Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
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 "nsPresContext.h"
8 #include "nsContentUtils.h"
9 #include "nsError.h"
10 #include <new>
11 #include "nsIContent.h"
12 #include "nsIDocument.h"
13 #include "nsINode.h"
14 #include "nsPIDOMWindow.h"
15 #include "GeckoProfiler.h"
16 #include "GeneratedEvents.h"
17 #include "mozilla/ContentEvents.h"
18 #include "mozilla/dom/EventTarget.h"
19 #include "mozilla/dom/TouchEvent.h"
20 #include "mozilla/EventDispatcher.h"
21 #include "mozilla/EventListenerManager.h"
22 #include "mozilla/InternalMutationEvent.h"
23 #include "mozilla/MiscEvents.h"
24 #include "mozilla/MouseEvents.h"
25 #include "mozilla/TextEvents.h"
26 #include "mozilla/TouchEvents.h"
27 #include "mozilla/unused.h"
29 namespace mozilla {
31 using namespace dom;
33 class ELMCreationDetector
34 {
35 public:
36 ELMCreationDetector()
37 // We can do this optimization only in the main thread.
38 : mNonMainThread(!NS_IsMainThread())
39 , mInitialCount(mNonMainThread ?
40 0 : EventListenerManager::sMainThreadCreatedCount)
41 {
42 }
44 bool MayHaveNewListenerManager()
45 {
46 return mNonMainThread ||
47 mInitialCount != EventListenerManager::sMainThreadCreatedCount;
48 }
50 bool IsMainThread()
51 {
52 return !mNonMainThread;
53 }
55 private:
56 bool mNonMainThread;
57 uint32_t mInitialCount;
58 };
60 #define NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH (1 << 0)
61 #define NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT (1 << 1)
62 #define NS_TARGET_CHAIN_MAY_HAVE_MANAGER (1 << 2)
64 // EventTargetChainItem represents a single item in the event target chain.
65 class EventTargetChainItem
66 {
67 private:
68 EventTargetChainItem(EventTarget* aTarget);
69 public:
70 EventTargetChainItem()
71 : mFlags(0)
72 , mItemFlags(0)
73 {
74 }
76 static EventTargetChainItem* Create(nsTArray<EventTargetChainItem>& aChain,
77 EventTarget* aTarget,
78 EventTargetChainItem* aChild = nullptr)
79 {
80 MOZ_ASSERT(!aChild || &aChain.ElementAt(aChain.Length() - 1) == aChild);
81 return new (aChain.AppendElement()) EventTargetChainItem(aTarget);
82 }
84 static void DestroyLast(nsTArray<EventTargetChainItem>& aChain,
85 EventTargetChainItem* aItem)
86 {
87 uint32_t lastIndex = aChain.Length() - 1;
88 MOZ_ASSERT(&aChain[lastIndex] == aItem);
89 aChain.RemoveElementAt(lastIndex);
90 }
92 bool IsValid()
93 {
94 NS_WARN_IF_FALSE(!!(mTarget), "Event target is not valid!");
95 return !!(mTarget);
96 }
98 EventTarget* GetNewTarget()
99 {
100 return mNewTarget;
101 }
103 void SetNewTarget(EventTarget* aNewTarget)
104 {
105 mNewTarget = aNewTarget;
106 }
108 void SetForceContentDispatch(bool aForce)
109 {
110 if (aForce) {
111 mFlags |= NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH;
112 } else {
113 mFlags &= ~NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH;
114 }
115 }
117 bool ForceContentDispatch()
118 {
119 return !!(mFlags & NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH);
120 }
122 void SetWantsWillHandleEvent(bool aWants)
123 {
124 if (aWants) {
125 mFlags |= NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT;
126 } else {
127 mFlags &= ~NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT;
128 }
129 }
131 bool WantsWillHandleEvent()
132 {
133 return !!(mFlags & NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT);
134 }
136 void SetMayHaveListenerManager(bool aMayHave)
137 {
138 if (aMayHave) {
139 mFlags |= NS_TARGET_CHAIN_MAY_HAVE_MANAGER;
140 } else {
141 mFlags &= ~NS_TARGET_CHAIN_MAY_HAVE_MANAGER;
142 }
143 }
145 bool MayHaveListenerManager()
146 {
147 return !!(mFlags & NS_TARGET_CHAIN_MAY_HAVE_MANAGER);
148 }
150 EventTarget* CurrentTarget()
151 {
152 return mTarget;
153 }
155 /**
156 * Dispatches event through the event target chain.
157 * Handles capture, target and bubble phases both in default
158 * and system event group and calls also PostHandleEvent for each
159 * item in the chain.
160 */
161 static void HandleEventTargetChain(nsTArray<EventTargetChainItem>& aChain,
162 EventChainPostVisitor& aVisitor,
163 EventDispatchingCallback* aCallback,
164 ELMCreationDetector& aCd);
166 /**
167 * Resets aVisitor object and calls PreHandleEvent.
168 * Copies mItemFlags and mItemData to the current EventTargetChainItem.
169 */
170 void PreHandleEvent(EventChainPreVisitor& aVisitor);
172 /**
173 * If the current item in the event target chain has an event listener
174 * manager, this method calls EventListenerManager::HandleEvent().
175 */
176 void HandleEvent(EventChainPostVisitor& aVisitor,
177 ELMCreationDetector& aCd)
178 {
179 if (WantsWillHandleEvent()) {
180 mTarget->WillHandleEvent(aVisitor);
181 }
182 if (aVisitor.mEvent->mFlags.mPropagationStopped) {
183 return;
184 }
185 if (!mManager) {
186 if (!MayHaveListenerManager() && !aCd.MayHaveNewListenerManager()) {
187 return;
188 }
189 mManager = mTarget->GetExistingListenerManager();
190 }
191 if (mManager) {
192 NS_ASSERTION(aVisitor.mEvent->currentTarget == nullptr,
193 "CurrentTarget should be null!");
194 mManager->HandleEvent(aVisitor.mPresContext, aVisitor.mEvent,
195 &aVisitor.mDOMEvent,
196 CurrentTarget(),
197 &aVisitor.mEventStatus);
198 NS_ASSERTION(aVisitor.mEvent->currentTarget == nullptr,
199 "CurrentTarget should be null!");
200 }
201 }
203 /**
204 * Copies mItemFlags and mItemData to aVisitor and calls PostHandleEvent.
205 */
206 void PostHandleEvent(EventChainPostVisitor& aVisitor);
208 nsCOMPtr<EventTarget> mTarget;
209 uint16_t mFlags;
210 uint16_t mItemFlags;
211 nsCOMPtr<nsISupports> mItemData;
212 // Event retargeting must happen whenever mNewTarget is non-null.
213 nsCOMPtr<EventTarget> mNewTarget;
214 // Cache mTarget's event listener manager.
215 nsRefPtr<EventListenerManager> mManager;
216 };
218 EventTargetChainItem::EventTargetChainItem(EventTarget* aTarget)
219 : mTarget(aTarget)
220 , mFlags(0)
221 , mItemFlags(0)
222 {
223 MOZ_ASSERT(!aTarget || mTarget == aTarget->GetTargetForEventTargetChain());
224 }
226 void
227 EventTargetChainItem::PreHandleEvent(EventChainPreVisitor& aVisitor)
228 {
229 aVisitor.Reset();
230 unused << mTarget->PreHandleEvent(aVisitor);
231 SetForceContentDispatch(aVisitor.mForceContentDispatch);
232 SetWantsWillHandleEvent(aVisitor.mWantsWillHandleEvent);
233 SetMayHaveListenerManager(aVisitor.mMayHaveListenerManager);
234 mItemFlags = aVisitor.mItemFlags;
235 mItemData = aVisitor.mItemData;
236 }
238 void
239 EventTargetChainItem::PostHandleEvent(EventChainPostVisitor& aVisitor)
240 {
241 aVisitor.mItemFlags = mItemFlags;
242 aVisitor.mItemData = mItemData;
243 mTarget->PostHandleEvent(aVisitor);
244 }
246 void
247 EventTargetChainItem::HandleEventTargetChain(
248 nsTArray<EventTargetChainItem>& aChain,
249 EventChainPostVisitor& aVisitor,
250 EventDispatchingCallback* aCallback,
251 ELMCreationDetector& aCd)
252 {
253 // Save the target so that it can be restored later.
254 nsCOMPtr<EventTarget> firstTarget = aVisitor.mEvent->target;
255 uint32_t chainLength = aChain.Length();
257 // Capture
258 aVisitor.mEvent->mFlags.mInCapturePhase = true;
259 aVisitor.mEvent->mFlags.mInBubblingPhase = false;
260 for (uint32_t i = chainLength - 1; i > 0; --i) {
261 EventTargetChainItem& item = aChain[i];
262 if ((!aVisitor.mEvent->mFlags.mNoContentDispatch ||
263 item.ForceContentDispatch()) &&
264 !aVisitor.mEvent->mFlags.mPropagationStopped) {
265 item.HandleEvent(aVisitor, aCd);
266 }
268 if (item.GetNewTarget()) {
269 // item is at anonymous boundary. Need to retarget for the child items.
270 for (uint32_t j = i; j > 0; --j) {
271 uint32_t childIndex = j - 1;
272 EventTarget* newTarget = aChain[childIndex].GetNewTarget();
273 if (newTarget) {
274 aVisitor.mEvent->target = newTarget;
275 break;
276 }
277 }
278 }
279 }
281 // Target
282 aVisitor.mEvent->mFlags.mInBubblingPhase = true;
283 EventTargetChainItem& targetItem = aChain[0];
284 if (!aVisitor.mEvent->mFlags.mPropagationStopped &&
285 (!aVisitor.mEvent->mFlags.mNoContentDispatch ||
286 targetItem.ForceContentDispatch())) {
287 targetItem.HandleEvent(aVisitor, aCd);
288 }
289 if (aVisitor.mEvent->mFlags.mInSystemGroup) {
290 targetItem.PostHandleEvent(aVisitor);
291 }
293 // Bubble
294 aVisitor.mEvent->mFlags.mInCapturePhase = false;
295 for (uint32_t i = 1; i < chainLength; ++i) {
296 EventTargetChainItem& item = aChain[i];
297 EventTarget* newTarget = item.GetNewTarget();
298 if (newTarget) {
299 // Item is at anonymous boundary. Need to retarget for the current item
300 // and for parent items.
301 aVisitor.mEvent->target = newTarget;
302 }
304 if (aVisitor.mEvent->mFlags.mBubbles || newTarget) {
305 if ((!aVisitor.mEvent->mFlags.mNoContentDispatch ||
306 item.ForceContentDispatch()) &&
307 !aVisitor.mEvent->mFlags.mPropagationStopped) {
308 item.HandleEvent(aVisitor, aCd);
309 }
310 if (aVisitor.mEvent->mFlags.mInSystemGroup) {
311 item.PostHandleEvent(aVisitor);
312 }
313 }
314 }
315 aVisitor.mEvent->mFlags.mInBubblingPhase = false;
317 if (!aVisitor.mEvent->mFlags.mInSystemGroup) {
318 // Dispatch to the system event group. Make sure to clear the
319 // STOP_DISPATCH flag since this resets for each event group.
320 aVisitor.mEvent->mFlags.mPropagationStopped = false;
321 aVisitor.mEvent->mFlags.mImmediatePropagationStopped = false;
323 // Setting back the original target of the event.
324 aVisitor.mEvent->target = aVisitor.mEvent->originalTarget;
326 // Special handling if PresShell (or some other caller)
327 // used a callback object.
328 if (aCallback) {
329 aCallback->HandleEvent(aVisitor);
330 }
332 // Retarget for system event group (which does the default handling too).
333 // Setting back the target which was used also for default event group.
334 aVisitor.mEvent->target = firstTarget;
335 aVisitor.mEvent->mFlags.mInSystemGroup = true;
336 HandleEventTargetChain(aChain,
337 aVisitor,
338 aCallback,
339 aCd);
340 aVisitor.mEvent->mFlags.mInSystemGroup = false;
342 // After dispatch, clear all the propagation flags so that
343 // system group listeners don't affect to the event.
344 aVisitor.mEvent->mFlags.mPropagationStopped = false;
345 aVisitor.mEvent->mFlags.mImmediatePropagationStopped = false;
346 }
347 }
349 static nsTArray<EventTargetChainItem>* sCachedMainThreadChain = nullptr;
351 /* static */ void
352 EventDispatcher::Shutdown()
353 {
354 delete sCachedMainThreadChain;
355 sCachedMainThreadChain = nullptr;
356 }
358 EventTargetChainItem*
359 EventTargetChainItemForChromeTarget(nsTArray<EventTargetChainItem>& aChain,
360 nsINode* aNode,
361 EventTargetChainItem* aChild = nullptr)
362 {
363 if (!aNode->IsInDoc()) {
364 return nullptr;
365 }
366 nsPIDOMWindow* win = aNode->OwnerDoc()->GetInnerWindow();
367 EventTarget* piTarget = win ? win->GetParentTarget() : nullptr;
368 NS_ENSURE_TRUE(piTarget, nullptr);
370 EventTargetChainItem* etci =
371 EventTargetChainItem::Create(aChain,
372 piTarget->GetTargetForEventTargetChain(),
373 aChild);
374 if (!etci->IsValid()) {
375 EventTargetChainItem::DestroyLast(aChain, etci);
376 return nullptr;
377 }
378 return etci;
379 }
381 /* static */ nsresult
382 EventDispatcher::Dispatch(nsISupports* aTarget,
383 nsPresContext* aPresContext,
384 WidgetEvent* aEvent,
385 nsIDOMEvent* aDOMEvent,
386 nsEventStatus* aEventStatus,
387 EventDispatchingCallback* aCallback,
388 nsCOMArray<EventTarget>* aTargets)
389 {
390 PROFILER_LABEL("EventDispatcher", "Dispatch");
391 NS_ASSERTION(aEvent, "Trying to dispatch without WidgetEvent!");
392 NS_ENSURE_TRUE(!aEvent->mFlags.mIsBeingDispatched,
393 NS_ERROR_DOM_INVALID_STATE_ERR);
394 NS_ASSERTION(!aTargets || !aEvent->message, "Wrong parameters!");
396 // If we're dispatching an already created DOMEvent object, make
397 // sure it is initialized!
398 // If aTargets is non-null, the event isn't going to be dispatched.
399 NS_ENSURE_TRUE(aEvent->message || !aDOMEvent || aTargets,
400 NS_ERROR_DOM_INVALID_STATE_ERR);
402 nsCOMPtr<EventTarget> target = do_QueryInterface(aTarget);
404 bool retargeted = false;
406 if (aEvent->mFlags.mRetargetToNonNativeAnonymous) {
407 nsCOMPtr<nsIContent> content = do_QueryInterface(target);
408 if (content && content->IsInNativeAnonymousSubtree()) {
409 nsCOMPtr<EventTarget> newTarget =
410 do_QueryInterface(content->FindFirstNonChromeOnlyAccessContent());
411 NS_ENSURE_STATE(newTarget);
413 aEvent->originalTarget = target;
414 target = newTarget;
415 retargeted = true;
416 }
417 }
419 if (aEvent->mFlags.mOnlyChromeDispatch) {
420 nsCOMPtr<nsINode> node = do_QueryInterface(aTarget);
421 if (!node) {
422 nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aTarget);
423 if (win) {
424 node = win->GetExtantDoc();
425 }
426 }
428 NS_ENSURE_STATE(node);
429 nsIDocument* doc = node->OwnerDoc();
430 if (!nsContentUtils::IsChromeDoc(doc)) {
431 nsPIDOMWindow* win = doc ? doc->GetInnerWindow() : nullptr;
432 // If we can't dispatch the event to chrome, do nothing.
433 EventTarget* piTarget = win ? win->GetParentTarget() : nullptr;
434 NS_ENSURE_TRUE(piTarget, NS_OK);
436 // Set the target to be the original dispatch target,
437 aEvent->target = target;
438 // but use chrome event handler or TabChildGlobal for event target chain.
439 target = piTarget;
440 }
441 }
443 #ifdef DEBUG
444 if (!nsContentUtils::IsSafeToRunScript()) {
445 nsresult rv = NS_ERROR_FAILURE;
446 if (target->GetContextForEventHandlers(&rv) ||
447 NS_FAILED(rv)) {
448 nsCOMPtr<nsINode> node = do_QueryInterface(target);
449 if (node && nsContentUtils::IsChromeDoc(node->OwnerDoc())) {
450 NS_WARNING("Fix the caller!");
451 } else {
452 NS_ERROR("This is unsafe! Fix the caller!");
453 }
454 }
455 }
457 if (aDOMEvent) {
458 WidgetEvent* innerEvent = aDOMEvent->GetInternalNSEvent();
459 NS_ASSERTION(innerEvent == aEvent,
460 "The inner event of aDOMEvent is not the same as aEvent!");
461 }
462 #endif
464 nsresult rv = NS_OK;
465 bool externalDOMEvent = !!(aDOMEvent);
467 // If we have a PresContext, make sure it doesn't die before
468 // event dispatching is finished.
469 nsRefPtr<nsPresContext> kungFuDeathGrip(aPresContext);
471 ELMCreationDetector cd;
472 nsTArray<EventTargetChainItem> chain;
473 if (cd.IsMainThread()) {
474 if (!sCachedMainThreadChain) {
475 sCachedMainThreadChain = new nsTArray<EventTargetChainItem>();
476 }
477 chain.SwapElements(*sCachedMainThreadChain);
478 chain.SetCapacity(128);
479 }
481 // Create the event target chain item for the event target.
482 EventTargetChainItem* targetEtci =
483 EventTargetChainItem::Create(chain, target->GetTargetForEventTargetChain());
484 MOZ_ASSERT(&chain[0] == targetEtci);
485 if (!targetEtci->IsValid()) {
486 EventTargetChainItem::DestroyLast(chain, targetEtci);
487 return NS_ERROR_FAILURE;
488 }
490 // Make sure that nsIDOMEvent::target and nsIDOMEvent::originalTarget
491 // point to the last item in the chain.
492 if (!aEvent->target) {
493 // Note, CurrentTarget() points always to the object returned by
494 // GetTargetForEventTargetChain().
495 aEvent->target = targetEtci->CurrentTarget();
496 } else {
497 // XXX But if the target is already set, use that. This is a hack
498 // for the 'load', 'beforeunload' and 'unload' events,
499 // which are dispatched to |window| but have document as their target.
500 //
501 // Make sure that the event target points to the right object.
502 aEvent->target = aEvent->target->GetTargetForEventTargetChain();
503 NS_ENSURE_STATE(aEvent->target);
504 }
506 if (retargeted) {
507 aEvent->originalTarget =
508 aEvent->originalTarget->GetTargetForEventTargetChain();
509 NS_ENSURE_STATE(aEvent->originalTarget);
510 }
511 else {
512 aEvent->originalTarget = aEvent->target;
513 }
515 nsCOMPtr<nsIContent> content = do_QueryInterface(aEvent->originalTarget);
516 bool isInAnon = (content && content->IsInAnonymousSubtree());
518 aEvent->mFlags.mIsBeingDispatched = true;
520 // Create visitor object and start event dispatching.
521 // PreHandleEvent for the original target.
522 nsEventStatus status = aEventStatus ? *aEventStatus : nsEventStatus_eIgnore;
523 EventChainPreVisitor preVisitor(aPresContext, aEvent, aDOMEvent, status,
524 isInAnon);
525 targetEtci->PreHandleEvent(preVisitor);
527 if (!preVisitor.mCanHandle && preVisitor.mAutomaticChromeDispatch && content) {
528 // Event target couldn't handle the event. Try to propagate to chrome.
529 EventTargetChainItem::DestroyLast(chain, targetEtci);
530 targetEtci = EventTargetChainItemForChromeTarget(chain, content);
531 NS_ENSURE_STATE(targetEtci);
532 MOZ_ASSERT(&chain[0] == targetEtci);
533 targetEtci->PreHandleEvent(preVisitor);
534 }
535 if (preVisitor.mCanHandle) {
536 // At least the original target can handle the event.
537 // Setting the retarget to the |target| simplifies retargeting code.
538 nsCOMPtr<EventTarget> t = do_QueryInterface(aEvent->target);
539 targetEtci->SetNewTarget(t);
540 EventTargetChainItem* topEtci = targetEtci;
541 targetEtci = nullptr;
542 while (preVisitor.mParentTarget) {
543 EventTarget* parentTarget = preVisitor.mParentTarget;
544 EventTargetChainItem* parentEtci =
545 EventTargetChainItem::Create(chain, preVisitor.mParentTarget, topEtci);
546 if (!parentEtci->IsValid()) {
547 EventTargetChainItem::DestroyLast(chain, parentEtci);
548 rv = NS_ERROR_FAILURE;
549 break;
550 }
552 // Item needs event retargetting.
553 if (preVisitor.mEventTargetAtParent) {
554 // Need to set the target of the event
555 // so that also the next retargeting works.
556 preVisitor.mEvent->target = preVisitor.mEventTargetAtParent;
557 parentEtci->SetNewTarget(preVisitor.mEventTargetAtParent);
558 }
560 parentEtci->PreHandleEvent(preVisitor);
561 if (preVisitor.mCanHandle) {
562 topEtci = parentEtci;
563 } else {
564 EventTargetChainItem::DestroyLast(chain, parentEtci);
565 parentEtci = nullptr;
566 if (preVisitor.mAutomaticChromeDispatch && content) {
567 // Even if the current target can't handle the event, try to
568 // propagate to chrome.
569 nsCOMPtr<nsINode> disabledTarget = do_QueryInterface(parentTarget);
570 if (disabledTarget) {
571 parentEtci = EventTargetChainItemForChromeTarget(chain,
572 disabledTarget,
573 topEtci);
574 if (parentEtci) {
575 parentEtci->PreHandleEvent(preVisitor);
576 if (preVisitor.mCanHandle) {
577 chain[0].SetNewTarget(parentTarget);
578 topEtci = parentEtci;
579 continue;
580 }
581 }
582 }
583 }
584 break;
585 }
586 }
587 if (NS_SUCCEEDED(rv)) {
588 if (aTargets) {
589 aTargets->Clear();
590 aTargets->SetCapacity(chain.Length());
591 for (uint32_t i = 0; i < chain.Length(); ++i) {
592 aTargets->AppendObject(chain[i].CurrentTarget()->GetTargetForDOMEvent());
593 }
594 } else {
595 // Event target chain is created. Handle the chain.
596 EventChainPostVisitor postVisitor(preVisitor);
597 EventTargetChainItem::HandleEventTargetChain(chain, postVisitor,
598 aCallback, cd);
600 preVisitor.mEventStatus = postVisitor.mEventStatus;
601 // If the DOM event was created during event flow.
602 if (!preVisitor.mDOMEvent && postVisitor.mDOMEvent) {
603 preVisitor.mDOMEvent = postVisitor.mDOMEvent;
604 }
605 }
606 }
607 }
609 // Note, EventTargetChainItem objects are deleted when the chain goes out of
610 // the scope.
612 aEvent->mFlags.mIsBeingDispatched = false;
613 aEvent->mFlags.mDispatchedAtLeastOnce = true;
615 if (!externalDOMEvent && preVisitor.mDOMEvent) {
616 // An dom::Event was created while dispatching the event.
617 // Duplicate private data if someone holds a pointer to it.
618 nsrefcnt rc = 0;
619 NS_RELEASE2(preVisitor.mDOMEvent, rc);
620 if (preVisitor.mDOMEvent) {
621 preVisitor.mDOMEvent->DuplicatePrivateData();
622 }
623 }
625 if (aEventStatus) {
626 *aEventStatus = preVisitor.mEventStatus;
627 }
629 if (cd.IsMainThread() && chain.Capacity() == 128 && sCachedMainThreadChain) {
630 chain.ClearAndRetainStorage();
631 chain.SwapElements(*sCachedMainThreadChain);
632 }
634 return rv;
635 }
637 /* static */ nsresult
638 EventDispatcher::DispatchDOMEvent(nsISupports* aTarget,
639 WidgetEvent* aEvent,
640 nsIDOMEvent* aDOMEvent,
641 nsPresContext* aPresContext,
642 nsEventStatus* aEventStatus)
643 {
644 if (aDOMEvent) {
645 WidgetEvent* innerEvent = aDOMEvent->GetInternalNSEvent();
646 NS_ENSURE_TRUE(innerEvent, NS_ERROR_ILLEGAL_VALUE);
648 bool dontResetTrusted = false;
649 if (innerEvent->mFlags.mDispatchedAtLeastOnce) {
650 innerEvent->target = nullptr;
651 innerEvent->originalTarget = nullptr;
652 } else {
653 aDOMEvent->GetIsTrusted(&dontResetTrusted);
654 }
656 if (!dontResetTrusted) {
657 //Check security state to determine if dispatcher is trusted
658 aDOMEvent->SetTrusted(nsContentUtils::ThreadsafeIsCallerChrome());
659 }
661 return EventDispatcher::Dispatch(aTarget, aPresContext, innerEvent,
662 aDOMEvent, aEventStatus);
663 } else if (aEvent) {
664 return EventDispatcher::Dispatch(aTarget, aPresContext, aEvent,
665 aDOMEvent, aEventStatus);
666 }
667 return NS_ERROR_ILLEGAL_VALUE;
668 }
670 /* static */ nsresult
671 EventDispatcher::CreateEvent(EventTarget* aOwner,
672 nsPresContext* aPresContext,
673 WidgetEvent* aEvent,
674 const nsAString& aEventType,
675 nsIDOMEvent** aDOMEvent)
676 {
677 *aDOMEvent = nullptr;
679 if (aEvent) {
680 switch(aEvent->eventStructType) {
681 case NS_MUTATION_EVENT:
682 return NS_NewDOMMutationEvent(aDOMEvent, aOwner, aPresContext,
683 aEvent->AsMutationEvent());
684 case NS_GUI_EVENT:
685 case NS_SCROLLPORT_EVENT:
686 case NS_UI_EVENT:
687 return NS_NewDOMUIEvent(aDOMEvent, aOwner, aPresContext,
688 aEvent->AsGUIEvent());
689 case NS_SCROLLAREA_EVENT:
690 return NS_NewDOMScrollAreaEvent(aDOMEvent, aOwner, aPresContext,
691 aEvent->AsScrollAreaEvent());
692 case NS_KEY_EVENT:
693 return NS_NewDOMKeyboardEvent(aDOMEvent, aOwner, aPresContext,
694 aEvent->AsKeyboardEvent());
695 case NS_COMPOSITION_EVENT:
696 return NS_NewDOMCompositionEvent(aDOMEvent, aOwner, aPresContext,
697 aEvent->AsCompositionEvent());
698 case NS_MOUSE_EVENT:
699 return NS_NewDOMMouseEvent(aDOMEvent, aOwner, aPresContext,
700 aEvent->AsMouseEvent());
701 case NS_FOCUS_EVENT:
702 return NS_NewDOMFocusEvent(aDOMEvent, aOwner, aPresContext,
703 aEvent->AsFocusEvent());
704 case NS_MOUSE_SCROLL_EVENT:
705 return NS_NewDOMMouseScrollEvent(aDOMEvent, aOwner, aPresContext,
706 aEvent->AsMouseScrollEvent());
707 case NS_WHEEL_EVENT:
708 return NS_NewDOMWheelEvent(aDOMEvent, aOwner, aPresContext,
709 aEvent->AsWheelEvent());
710 case NS_EDITOR_INPUT_EVENT:
711 return NS_NewDOMInputEvent(aDOMEvent, aOwner, aPresContext,
712 aEvent->AsEditorInputEvent());
713 case NS_DRAG_EVENT:
714 return NS_NewDOMDragEvent(aDOMEvent, aOwner, aPresContext,
715 aEvent->AsDragEvent());
716 case NS_TEXT_EVENT:
717 return NS_NewDOMUIEvent(aDOMEvent, aOwner, aPresContext,
718 aEvent->AsTextEvent());
719 case NS_CLIPBOARD_EVENT:
720 return NS_NewDOMClipboardEvent(aDOMEvent, aOwner, aPresContext,
721 aEvent->AsClipboardEvent());
722 case NS_SVGZOOM_EVENT:
723 return NS_NewDOMSVGZoomEvent(aDOMEvent, aOwner, aPresContext,
724 aEvent->AsGUIEvent());
725 case NS_SMIL_TIME_EVENT:
726 return NS_NewDOMTimeEvent(aDOMEvent, aOwner, aPresContext, aEvent);
728 case NS_COMMAND_EVENT:
729 return NS_NewDOMCommandEvent(aDOMEvent, aOwner, aPresContext,
730 aEvent->AsCommandEvent());
731 case NS_SIMPLE_GESTURE_EVENT:
732 return NS_NewDOMSimpleGestureEvent(aDOMEvent, aOwner, aPresContext,
733 aEvent->AsSimpleGestureEvent());
734 case NS_POINTER_EVENT:
735 return NS_NewDOMPointerEvent(aDOMEvent, aOwner, aPresContext,
736 aEvent->AsPointerEvent());
737 case NS_TOUCH_EVENT:
738 return NS_NewDOMTouchEvent(aDOMEvent, aOwner, aPresContext,
739 aEvent->AsTouchEvent());
740 case NS_TRANSITION_EVENT:
741 return NS_NewDOMTransitionEvent(aDOMEvent, aOwner, aPresContext,
742 aEvent->AsTransitionEvent());
743 case NS_ANIMATION_EVENT:
744 return NS_NewDOMAnimationEvent(aDOMEvent, aOwner, aPresContext,
745 aEvent->AsAnimationEvent());
746 default:
747 // For all other types of events, create a vanilla event object.
748 return NS_NewDOMEvent(aDOMEvent, aOwner, aPresContext, aEvent);
749 }
750 }
752 // And if we didn't get an event, check the type argument.
754 if (aEventType.LowerCaseEqualsLiteral("mouseevent") ||
755 aEventType.LowerCaseEqualsLiteral("mouseevents") ||
756 aEventType.LowerCaseEqualsLiteral("popupevents"))
757 return NS_NewDOMMouseEvent(aDOMEvent, aOwner, aPresContext, nullptr);
758 if (aEventType.LowerCaseEqualsLiteral("mousescrollevents"))
759 return NS_NewDOMMouseScrollEvent(aDOMEvent, aOwner, aPresContext, nullptr);
760 if (aEventType.LowerCaseEqualsLiteral("dragevent") ||
761 aEventType.LowerCaseEqualsLiteral("dragevents"))
762 return NS_NewDOMDragEvent(aDOMEvent, aOwner, aPresContext, nullptr);
763 if (aEventType.LowerCaseEqualsLiteral("keyboardevent") ||
764 aEventType.LowerCaseEqualsLiteral("keyevents"))
765 return NS_NewDOMKeyboardEvent(aDOMEvent, aOwner, aPresContext, nullptr);
766 if (aEventType.LowerCaseEqualsLiteral("compositionevent"))
767 return NS_NewDOMCompositionEvent(aDOMEvent, aOwner, aPresContext, nullptr);
768 if (aEventType.LowerCaseEqualsLiteral("mutationevent") ||
769 aEventType.LowerCaseEqualsLiteral("mutationevents"))
770 return NS_NewDOMMutationEvent(aDOMEvent, aOwner, aPresContext, nullptr);
771 if (aEventType.LowerCaseEqualsLiteral("textevent") ||
772 aEventType.LowerCaseEqualsLiteral("textevents"))
773 return NS_NewDOMUIEvent(aDOMEvent, aOwner, aPresContext, nullptr);
774 if (aEventType.LowerCaseEqualsLiteral("popupblockedevents"))
775 return NS_NewDOMPopupBlockedEvent(aDOMEvent, aOwner, aPresContext, nullptr);
776 if (aEventType.LowerCaseEqualsLiteral("deviceorientationevent"))
777 return NS_NewDOMDeviceOrientationEvent(aDOMEvent, aOwner, aPresContext, nullptr);
778 if (aEventType.LowerCaseEqualsLiteral("devicemotionevent"))
779 return NS_NewDOMDeviceMotionEvent(aDOMEvent, aOwner, aPresContext, nullptr);
780 if (aEventType.LowerCaseEqualsLiteral("uievent") ||
781 aEventType.LowerCaseEqualsLiteral("uievents"))
782 return NS_NewDOMUIEvent(aDOMEvent, aOwner, aPresContext, nullptr);
783 if (aEventType.LowerCaseEqualsLiteral("event") ||
784 aEventType.LowerCaseEqualsLiteral("events") ||
785 aEventType.LowerCaseEqualsLiteral("htmlevents") ||
786 aEventType.LowerCaseEqualsLiteral("svgevent") ||
787 aEventType.LowerCaseEqualsLiteral("svgevents"))
788 return NS_NewDOMEvent(aDOMEvent, aOwner, aPresContext, nullptr);
789 if (aEventType.LowerCaseEqualsLiteral("svgzoomevent") ||
790 aEventType.LowerCaseEqualsLiteral("svgzoomevents"))
791 return NS_NewDOMSVGZoomEvent(aDOMEvent, aOwner, aPresContext, nullptr);
792 if (aEventType.LowerCaseEqualsLiteral("timeevent") ||
793 aEventType.LowerCaseEqualsLiteral("timeevents"))
794 return NS_NewDOMTimeEvent(aDOMEvent, aOwner, aPresContext, nullptr);
795 if (aEventType.LowerCaseEqualsLiteral("xulcommandevent") ||
796 aEventType.LowerCaseEqualsLiteral("xulcommandevents"))
797 return NS_NewDOMXULCommandEvent(aDOMEvent, aOwner, aPresContext, nullptr);
798 if (aEventType.LowerCaseEqualsLiteral("commandevent") ||
799 aEventType.LowerCaseEqualsLiteral("commandevents"))
800 return NS_NewDOMCommandEvent(aDOMEvent, aOwner, aPresContext, nullptr);
801 if (aEventType.LowerCaseEqualsLiteral("elementreplace"))
802 return NS_NewDOMElementReplaceEvent(aDOMEvent, aOwner, aPresContext, nullptr);
803 if (aEventType.LowerCaseEqualsLiteral("datacontainerevent") ||
804 aEventType.LowerCaseEqualsLiteral("datacontainerevents"))
805 return NS_NewDOMDataContainerEvent(aDOMEvent, aOwner, aPresContext, nullptr);
806 if (aEventType.LowerCaseEqualsLiteral("messageevent"))
807 return NS_NewDOMMessageEvent(aDOMEvent, aOwner, aPresContext, nullptr);
808 if (aEventType.LowerCaseEqualsLiteral("notifypaintevent"))
809 return NS_NewDOMNotifyPaintEvent(aDOMEvent, aOwner, aPresContext, nullptr);
810 if (aEventType.LowerCaseEqualsLiteral("simplegestureevent"))
811 return NS_NewDOMSimpleGestureEvent(aDOMEvent, aOwner, aPresContext, nullptr);
812 if (aEventType.LowerCaseEqualsLiteral("beforeunloadevent"))
813 return NS_NewDOMBeforeUnloadEvent(aDOMEvent, aOwner, aPresContext, nullptr);
814 if (aEventType.LowerCaseEqualsLiteral("pagetransition"))
815 return NS_NewDOMPageTransitionEvent(aDOMEvent, aOwner, aPresContext, nullptr);
816 if (aEventType.LowerCaseEqualsLiteral("domtransaction"))
817 return NS_NewDOMDOMTransactionEvent(aDOMEvent, aOwner, aPresContext, nullptr);
818 if (aEventType.LowerCaseEqualsLiteral("scrollareaevent"))
819 return NS_NewDOMScrollAreaEvent(aDOMEvent, aOwner, aPresContext, nullptr);
820 if (aEventType.LowerCaseEqualsLiteral("popstateevent"))
821 return NS_NewDOMPopStateEvent(aDOMEvent, aOwner, aPresContext, nullptr);
822 if (aEventType.LowerCaseEqualsLiteral("closeevent"))
823 return NS_NewDOMCloseEvent(aDOMEvent, aOwner, aPresContext, nullptr);
824 if (aEventType.LowerCaseEqualsLiteral("touchevent") &&
825 TouchEvent::PrefEnabled())
826 return NS_NewDOMTouchEvent(aDOMEvent, aOwner, aPresContext, nullptr);
827 if (aEventType.LowerCaseEqualsLiteral("hashchangeevent"))
828 return NS_NewDOMHashChangeEvent(aDOMEvent, aOwner, aPresContext, nullptr);
829 if (aEventType.LowerCaseEqualsLiteral("customevent"))
830 return NS_NewDOMCustomEvent(aDOMEvent, aOwner, aPresContext, nullptr);
831 if (aEventType.LowerCaseEqualsLiteral("mozsmsevent"))
832 return NS_NewDOMMozSmsEvent(aDOMEvent, aOwner, aPresContext, nullptr);
833 if (aEventType.LowerCaseEqualsLiteral("mozmmsevent"))
834 return NS_NewDOMMozMmsEvent(aDOMEvent, aOwner, aPresContext, nullptr);
835 if (aEventType.LowerCaseEqualsLiteral("storageevent")) {
836 return NS_NewDOMStorageEvent(aDOMEvent, aOwner, aPresContext, nullptr);
837 }
838 // NEW EVENT TYPES SHOULD NOT BE ADDED HERE; THEY SHOULD USE ONLY EVENT
839 // CONSTRUCTORS
841 return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
842 }
844 } // namespace mozilla