Line data Source code
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 : #ifndef mozilla_AsyncEventDispatcher_h_
8 : #define mozilla_AsyncEventDispatcher_h_
9 :
10 : #include "mozilla/Attributes.h"
11 : #include "nsCOMPtr.h"
12 : #include "nsIDocument.h"
13 : #include "nsIDOMEvent.h"
14 : #include "nsString.h"
15 : #include "nsThreadUtils.h"
16 :
17 : class nsINode;
18 :
19 : namespace mozilla {
20 :
21 : /**
22 : * Use AsyncEventDispatcher to fire a DOM event that requires safe a stable DOM.
23 : * For example, you may need to fire an event from within layout, but
24 : * want to ensure that the event handler doesn't mutate the DOM at
25 : * the wrong time, in order to avoid resulting instability.
26 : */
27 :
28 357 : class AsyncEventDispatcher : public CancelableRunnable
29 : {
30 : public:
31 : /**
32 : * If aOnlyChromeDispatch is true, the event is dispatched to only
33 : * chrome node. In that case, if aTarget is already a chrome node,
34 : * the event is dispatched to it, otherwise the dispatch path starts
35 : * at the first chrome ancestor of that target.
36 : */
37 117 : AsyncEventDispatcher(nsINode* aTarget,
38 : const nsAString& aEventType,
39 : bool aBubbles,
40 : bool aOnlyChromeDispatch)
41 117 : : CancelableRunnable("AsyncEventDispatcher")
42 : , mTarget(aTarget)
43 : , mEventType(aEventType)
44 : , mEventMessage(eUnidentifiedEvent)
45 : , mBubbles(aBubbles)
46 117 : , mOnlyChromeDispatch(aOnlyChromeDispatch)
47 : {
48 117 : }
49 :
50 : /**
51 : * If aOnlyChromeDispatch is true, the event is dispatched to only
52 : * chrome node. In that case, if aTarget is already a chrome node,
53 : * the event is dispatched to it, otherwise the dispatch path starts
54 : * at the first chrome ancestor of that target.
55 : */
56 : AsyncEventDispatcher(nsINode* aTarget,
57 : mozilla::EventMessage aEventMessage,
58 : bool aBubbles, bool aOnlyChromeDispatch)
59 : : CancelableRunnable("AsyncEventDispatcher")
60 : , mTarget(aTarget)
61 : , mEventMessage(aEventMessage)
62 : , mBubbles(aBubbles)
63 : , mOnlyChromeDispatch(aOnlyChromeDispatch)
64 : {
65 : mEventType.SetIsVoid(true);
66 : MOZ_ASSERT(mEventMessage != eUnidentifiedEvent);
67 : }
68 :
69 4 : AsyncEventDispatcher(dom::EventTarget* aTarget, const nsAString& aEventType,
70 : bool aBubbles)
71 4 : : CancelableRunnable("AsyncEventDispatcher")
72 : , mTarget(aTarget)
73 : , mEventType(aEventType)
74 : , mEventMessage(eUnidentifiedEvent)
75 4 : , mBubbles(aBubbles)
76 : {
77 4 : }
78 :
79 4 : AsyncEventDispatcher(dom::EventTarget* aTarget,
80 : mozilla::EventMessage aEventMessage,
81 : bool aBubbles)
82 4 : : CancelableRunnable("AsyncEventDispatcher")
83 : , mTarget(aTarget)
84 : , mEventMessage(aEventMessage)
85 4 : , mBubbles(aBubbles)
86 : {
87 4 : mEventType.SetIsVoid(true);
88 4 : MOZ_ASSERT(mEventMessage != eUnidentifiedEvent);
89 4 : }
90 :
91 2 : AsyncEventDispatcher(dom::EventTarget* aTarget, nsIDOMEvent* aEvent)
92 2 : : CancelableRunnable("AsyncEventDispatcher")
93 : , mTarget(aTarget)
94 : , mEvent(aEvent)
95 2 : , mEventMessage(eUnidentifiedEvent)
96 : {
97 2 : }
98 :
99 : AsyncEventDispatcher(dom::EventTarget* aTarget, WidgetEvent& aEvent);
100 :
101 : NS_IMETHOD Run() override;
102 : nsresult Cancel() override;
103 : nsresult PostDOMEvent();
104 : void RunDOMEventWhenSafe();
105 :
106 : // Calling this causes the Run() method to check that
107 : // mTarget->IsInComposedDoc(). mTarget must be an nsINode or else we'll
108 : // assert.
109 : void RequireNodeInDocument();
110 :
111 : nsCOMPtr<dom::EventTarget> mTarget;
112 : nsCOMPtr<nsIDOMEvent> mEvent;
113 : // If mEventType is set, mEventMessage will be eUnidentifiedEvent.
114 : // If mEventMessage is set, mEventType will be void.
115 : // They can never both be set at the same time.
116 : nsString mEventType;
117 : mozilla::EventMessage mEventMessage;
118 : bool mBubbles = false;
119 : bool mOnlyChromeDispatch = false;
120 : bool mCanceled = false;
121 : bool mCheckStillInDoc = false;
122 : };
123 :
124 : class LoadBlockingAsyncEventDispatcher final : public AsyncEventDispatcher
125 : {
126 : public:
127 12 : LoadBlockingAsyncEventDispatcher(nsINode* aEventNode,
128 : const nsAString& aEventType,
129 : bool aBubbles, bool aDispatchChromeOnly)
130 12 : : AsyncEventDispatcher(aEventNode, aEventType,
131 : aBubbles, aDispatchChromeOnly)
132 12 : , mBlockedDoc(aEventNode->OwnerDoc())
133 : {
134 12 : if (mBlockedDoc) {
135 12 : mBlockedDoc->BlockOnload();
136 : }
137 12 : }
138 :
139 : LoadBlockingAsyncEventDispatcher(nsINode* aEventNode, nsIDOMEvent* aEvent)
140 : : AsyncEventDispatcher(aEventNode, aEvent)
141 : , mBlockedDoc(aEventNode->OwnerDoc())
142 : {
143 : if (mBlockedDoc) {
144 : mBlockedDoc->BlockOnload();
145 : }
146 : }
147 :
148 : ~LoadBlockingAsyncEventDispatcher();
149 :
150 : private:
151 : nsCOMPtr<nsIDocument> mBlockedDoc;
152 : };
153 :
154 : } // namespace mozilla
155 :
156 : #endif // mozilla_AsyncEventDispatcher_h_
|