|
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 #ifndef mozilla_DOMEventTargetHelper_h_ |
|
7 #define mozilla_DOMEventTargetHelper_h_ |
|
8 |
|
9 #include "nsCOMPtr.h" |
|
10 #include "nsGkAtoms.h" |
|
11 #include "nsCycleCollectionParticipant.h" |
|
12 #include "nsPIDOMWindow.h" |
|
13 #include "nsIScriptGlobalObject.h" |
|
14 #include "nsIScriptContext.h" |
|
15 #include "MainThreadUtils.h" |
|
16 #include "mozilla/Attributes.h" |
|
17 #include "mozilla/EventListenerManager.h" |
|
18 #include "mozilla/dom/EventTarget.h" |
|
19 |
|
20 class JSCompartment; |
|
21 |
|
22 namespace mozilla { |
|
23 |
|
24 class ErrorResult; |
|
25 |
|
26 #define NS_DOMEVENTTARGETHELPER_IID \ |
|
27 { 0xa28385c6, 0x9451, 0x4d7e, \ |
|
28 { 0xa3, 0xdd, 0xf4, 0xb6, 0x87, 0x2f, 0xa4, 0x76 } } |
|
29 |
|
30 class DOMEventTargetHelper : public dom::EventTarget |
|
31 { |
|
32 public: |
|
33 DOMEventTargetHelper() |
|
34 : mParentObject(nullptr) |
|
35 , mOwnerWindow(nullptr) |
|
36 , mHasOrHasHadOwnerWindow(false) |
|
37 { |
|
38 } |
|
39 DOMEventTargetHelper(nsPIDOMWindow* aWindow) |
|
40 : mParentObject(nullptr) |
|
41 , mOwnerWindow(nullptr) |
|
42 , mHasOrHasHadOwnerWindow(false) |
|
43 { |
|
44 BindToOwner(aWindow); |
|
45 // All objects coming through here are WebIDL objects |
|
46 SetIsDOMBinding(); |
|
47 } |
|
48 DOMEventTargetHelper(DOMEventTargetHelper* aOther) |
|
49 : mParentObject(nullptr) |
|
50 , mOwnerWindow(nullptr) |
|
51 , mHasOrHasHadOwnerWindow(false) |
|
52 { |
|
53 BindToOwner(aOther); |
|
54 // All objects coming through here are WebIDL objects |
|
55 SetIsDOMBinding(); |
|
56 } |
|
57 |
|
58 virtual ~DOMEventTargetHelper(); |
|
59 NS_DECL_CYCLE_COLLECTING_ISUPPORTS |
|
60 NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(DOMEventTargetHelper) |
|
61 |
|
62 NS_DECL_NSIDOMEVENTTARGET |
|
63 |
|
64 virtual EventListenerManager* GetExistingListenerManager() const MOZ_OVERRIDE; |
|
65 virtual EventListenerManager* GetOrCreateListenerManager() MOZ_OVERRIDE; |
|
66 |
|
67 using dom::EventTarget::RemoveEventListener; |
|
68 virtual void AddEventListener(const nsAString& aType, |
|
69 dom::EventListener* aListener, |
|
70 bool aCapture, |
|
71 const dom::Nullable<bool>& aWantsUntrusted, |
|
72 ErrorResult& aRv) MOZ_OVERRIDE; |
|
73 |
|
74 NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOMEVENTTARGETHELPER_IID) |
|
75 |
|
76 void GetParentObject(nsIScriptGlobalObject **aParentObject) |
|
77 { |
|
78 if (mParentObject) { |
|
79 CallQueryInterface(mParentObject, aParentObject); |
|
80 } else { |
|
81 *aParentObject = nullptr; |
|
82 } |
|
83 } |
|
84 |
|
85 static DOMEventTargetHelper* FromSupports(nsISupports* aSupports) |
|
86 { |
|
87 dom::EventTarget* target = static_cast<dom::EventTarget*>(aSupports); |
|
88 #ifdef DEBUG |
|
89 { |
|
90 nsCOMPtr<dom::EventTarget> target_qi = do_QueryInterface(aSupports); |
|
91 |
|
92 // If this assertion fires the QI implementation for the object in |
|
93 // question doesn't use the EventTarget pointer as the |
|
94 // nsISupports pointer. That must be fixed, or we'll crash... |
|
95 NS_ASSERTION(target_qi == target, "Uh, fix QI!"); |
|
96 } |
|
97 #endif |
|
98 |
|
99 return static_cast<DOMEventTargetHelper*>(target); |
|
100 } |
|
101 |
|
102 bool HasListenersFor(nsIAtom* aTypeWithOn) |
|
103 { |
|
104 return mListenerManager && mListenerManager->HasListenersFor(aTypeWithOn); |
|
105 } |
|
106 |
|
107 nsresult SetEventHandler(nsIAtom* aType, |
|
108 JSContext* aCx, |
|
109 const JS::Value& aValue); |
|
110 using dom::EventTarget::SetEventHandler; |
|
111 void GetEventHandler(nsIAtom* aType, |
|
112 JSContext* aCx, |
|
113 JS::Value* aValue); |
|
114 using dom::EventTarget::GetEventHandler; |
|
115 virtual nsIDOMWindow* GetOwnerGlobal() MOZ_OVERRIDE |
|
116 { |
|
117 return nsPIDOMWindow::GetOuterFromCurrentInner(GetOwner()); |
|
118 } |
|
119 |
|
120 nsresult CheckInnerWindowCorrectness() |
|
121 { |
|
122 NS_ENSURE_STATE(!mHasOrHasHadOwnerWindow || mOwnerWindow); |
|
123 if (mOwnerWindow) { |
|
124 NS_ASSERTION(mOwnerWindow->IsInnerWindow(), "Should have inner window here!\n"); |
|
125 nsPIDOMWindow* outer = mOwnerWindow->GetOuterWindow(); |
|
126 if (!outer || outer->GetCurrentInnerWindow() != mOwnerWindow) { |
|
127 return NS_ERROR_FAILURE; |
|
128 } |
|
129 } |
|
130 return NS_OK; |
|
131 } |
|
132 |
|
133 nsPIDOMWindow* GetOwner() const { return mOwnerWindow; } |
|
134 void BindToOwner(nsIGlobalObject* aOwner); |
|
135 void BindToOwner(nsPIDOMWindow* aOwner); |
|
136 void BindToOwner(DOMEventTargetHelper* aOther); |
|
137 virtual void DisconnectFromOwner(); |
|
138 nsIGlobalObject* GetParentObject() const { return mParentObject; } |
|
139 bool HasOrHasHadOwner() { return mHasOrHasHadOwnerWindow; } |
|
140 |
|
141 virtual void EventListenerAdded(nsIAtom* aType) MOZ_OVERRIDE; |
|
142 virtual void EventListenerRemoved(nsIAtom* aType) MOZ_OVERRIDE; |
|
143 virtual void EventListenerWasAdded(const nsAString& aType, |
|
144 ErrorResult& aRv, |
|
145 JSCompartment* aCompartment = nullptr) {} |
|
146 virtual void EventListenerWasRemoved(const nsAString& aType, |
|
147 ErrorResult& aRv, |
|
148 JSCompartment* aCompartment = nullptr) {} |
|
149 protected: |
|
150 nsresult WantsUntrusted(bool* aRetVal); |
|
151 |
|
152 nsRefPtr<EventListenerManager> mListenerManager; |
|
153 // Dispatch a trusted, non-cancellable and non-bubbling event to |this|. |
|
154 nsresult DispatchTrustedEvent(const nsAString& aEventName); |
|
155 // Make |event| trusted and dispatch |aEvent| to |this|. |
|
156 nsresult DispatchTrustedEvent(nsIDOMEvent* aEvent); |
|
157 |
|
158 virtual void LastRelease() {} |
|
159 private: |
|
160 // Inner window or sandbox. |
|
161 nsIGlobalObject* mParentObject; |
|
162 // mParentObject pre QI-ed and cached |
|
163 // (it is needed for off main thread access) |
|
164 nsPIDOMWindow* mOwnerWindow; |
|
165 bool mHasOrHasHadOwnerWindow; |
|
166 }; |
|
167 |
|
168 NS_DEFINE_STATIC_IID_ACCESSOR(DOMEventTargetHelper, |
|
169 NS_DOMEVENTTARGETHELPER_IID) |
|
170 |
|
171 } // namespace mozilla |
|
172 |
|
173 // XPIDL event handlers |
|
174 #define NS_IMPL_EVENT_HANDLER(_class, _event) \ |
|
175 NS_IMETHODIMP _class::GetOn##_event(JSContext* aCx, \ |
|
176 JS::MutableHandle<JS::Value> aValue) \ |
|
177 { \ |
|
178 GetEventHandler(nsGkAtoms::on##_event, aCx, aValue.address()); \ |
|
179 return NS_OK; \ |
|
180 } \ |
|
181 NS_IMETHODIMP _class::SetOn##_event(JSContext* aCx, \ |
|
182 JS::Handle<JS::Value> aValue) \ |
|
183 { \ |
|
184 return SetEventHandler(nsGkAtoms::on##_event, aCx, aValue); \ |
|
185 } |
|
186 |
|
187 #define NS_IMPL_FORWARD_EVENT_HANDLER(_class, _event, _baseclass) \ |
|
188 NS_IMETHODIMP _class::GetOn##_event(JSContext* aCx, \ |
|
189 JS::MutableHandle<JS::Value> aValue) \ |
|
190 { \ |
|
191 return _baseclass::GetOn##_event(aCx, aValue); \ |
|
192 } \ |
|
193 NS_IMETHODIMP _class::SetOn##_event(JSContext* aCx, \ |
|
194 JS::Handle<JS::Value> aValue) \ |
|
195 { \ |
|
196 return _baseclass::SetOn##_event(aCx, aValue); \ |
|
197 } |
|
198 |
|
199 // WebIDL event handlers |
|
200 #define IMPL_EVENT_HANDLER(_event) \ |
|
201 inline mozilla::dom::EventHandlerNonNull* GetOn##_event() \ |
|
202 { \ |
|
203 if (NS_IsMainThread()) { \ |
|
204 return GetEventHandler(nsGkAtoms::on##_event, EmptyString()); \ |
|
205 } \ |
|
206 return GetEventHandler(nullptr, NS_LITERAL_STRING(#_event)); \ |
|
207 } \ |
|
208 inline void SetOn##_event(mozilla::dom::EventHandlerNonNull* aCallback) \ |
|
209 { \ |
|
210 if (NS_IsMainThread()) { \ |
|
211 SetEventHandler(nsGkAtoms::on##_event, EmptyString(), aCallback); \ |
|
212 } else { \ |
|
213 SetEventHandler(nullptr, NS_LITERAL_STRING(#_event), aCallback); \ |
|
214 } \ |
|
215 } |
|
216 |
|
217 /* Use this macro to declare functions that forward the behavior of this |
|
218 * interface to another object. |
|
219 * This macro doesn't forward PreHandleEvent because sometimes subclasses |
|
220 * want to override it. |
|
221 */ |
|
222 #define NS_FORWARD_NSIDOMEVENTTARGET_NOPREHANDLEEVENT(_to) \ |
|
223 NS_IMETHOD AddEventListener(const nsAString & type, nsIDOMEventListener *listener, bool useCapture, bool wantsUntrusted, uint8_t _argc) { \ |
|
224 return _to AddEventListener(type, listener, useCapture, wantsUntrusted, _argc); \ |
|
225 } \ |
|
226 NS_IMETHOD AddSystemEventListener(const nsAString & type, nsIDOMEventListener *listener, bool aUseCapture, bool aWantsUntrusted, uint8_t _argc) { \ |
|
227 return _to AddSystemEventListener(type, listener, aUseCapture, aWantsUntrusted, _argc); \ |
|
228 } \ |
|
229 NS_IMETHOD RemoveEventListener(const nsAString & type, nsIDOMEventListener *listener, bool useCapture) { \ |
|
230 return _to RemoveEventListener(type, listener, useCapture); \ |
|
231 } \ |
|
232 NS_IMETHOD RemoveSystemEventListener(const nsAString & type, nsIDOMEventListener *listener, bool aUseCapture) { \ |
|
233 return _to RemoveSystemEventListener(type, listener, aUseCapture); \ |
|
234 } \ |
|
235 NS_IMETHOD DispatchEvent(nsIDOMEvent *evt, bool *_retval) { \ |
|
236 return _to DispatchEvent(evt, _retval); \ |
|
237 } \ |
|
238 virtual mozilla::dom::EventTarget* GetTargetForDOMEvent() { \ |
|
239 return _to GetTargetForDOMEvent(); \ |
|
240 } \ |
|
241 virtual mozilla::dom::EventTarget* GetTargetForEventTargetChain() { \ |
|
242 return _to GetTargetForEventTargetChain(); \ |
|
243 } \ |
|
244 virtual nsresult WillHandleEvent( \ |
|
245 mozilla::EventChainPostVisitor & aVisitor) { \ |
|
246 return _to WillHandleEvent(aVisitor); \ |
|
247 } \ |
|
248 virtual nsresult PostHandleEvent( \ |
|
249 mozilla::EventChainPostVisitor & aVisitor) { \ |
|
250 return _to PostHandleEvent(aVisitor); \ |
|
251 } \ |
|
252 virtual nsresult DispatchDOMEvent(mozilla::WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent, nsPresContext* aPresContext, nsEventStatus* aEventStatus) { \ |
|
253 return _to DispatchDOMEvent(aEvent, aDOMEvent, aPresContext, aEventStatus); \ |
|
254 } \ |
|
255 virtual mozilla::EventListenerManager* GetOrCreateListenerManager() { \ |
|
256 return _to GetOrCreateListenerManager(); \ |
|
257 } \ |
|
258 virtual mozilla::EventListenerManager* GetExistingListenerManager() const { \ |
|
259 return _to GetExistingListenerManager(); \ |
|
260 } \ |
|
261 virtual nsIScriptContext * GetContextForEventHandlers(nsresult *aRv) { \ |
|
262 return _to GetContextForEventHandlers(aRv); \ |
|
263 } \ |
|
264 virtual JSContext * GetJSContextForEventHandlers(void) { \ |
|
265 return _to GetJSContextForEventHandlers(); \ |
|
266 } |
|
267 |
|
268 #define NS_REALLY_FORWARD_NSIDOMEVENTTARGET(_class) \ |
|
269 using _class::AddEventListener; \ |
|
270 using _class::RemoveEventListener; \ |
|
271 NS_FORWARD_NSIDOMEVENTTARGET(_class::) \ |
|
272 virtual mozilla::EventListenerManager* \ |
|
273 GetOrCreateListenerManager() { \ |
|
274 return _class::GetOrCreateListenerManager(); \ |
|
275 } \ |
|
276 virtual mozilla::EventListenerManager* \ |
|
277 GetExistingListenerManager() const { \ |
|
278 return _class::GetExistingListenerManager(); \ |
|
279 } |
|
280 |
|
281 #endif // mozilla_DOMEventTargetHelper_h_ |