1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #ifndef nsEventListenerManager_h__
39 : #define nsEventListenerManager_h__
40 :
41 : #include "nsEventListenerManager.h"
42 : #include "jsapi.h"
43 : #include "nsCOMPtr.h"
44 : #include "nsIDOMEventTarget.h"
45 : #include "nsIDOMEventListener.h"
46 : #include "nsAutoPtr.h"
47 : #include "nsCOMArray.h"
48 : #include "nsHashtable.h"
49 : #include "nsIScriptContext.h"
50 : #include "nsCycleCollectionParticipant.h"
51 : #include "nsTObserverArray.h"
52 : #include "nsGUIEvent.h"
53 : #include "nsIJSEventListener.h"
54 :
55 : class nsIDOMEvent;
56 : class nsIAtom;
57 : class nsIWidget;
58 : struct nsPoint;
59 : struct EventTypeData;
60 : class nsEventTargetChainItem;
61 : class nsPIDOMWindow;
62 : class nsCxPusher;
63 : class nsIEventListenerInfo;
64 : class nsIDocument;
65 :
66 : struct nsListenerStruct
67 4584 : {
68 : nsRefPtr<nsIDOMEventListener> mListener;
69 : PRUint32 mEventType;
70 : nsCOMPtr<nsIAtom> mTypeAtom;
71 : PRUint16 mFlags;
72 : bool mHandlerIsString;
73 : bool mWrappedJS;
74 :
75 374 : nsIJSEventListener* GetJSListener() const {
76 : return (mFlags & NS_PRIV_EVENT_FLAG_SCRIPT) ?
77 374 : static_cast<nsIJSEventListener *>(mListener.get()) : nsnull;
78 : }
79 :
80 4582 : ~nsListenerStruct()
81 4582 : {
82 4582 : if ((mFlags & NS_PRIV_EVENT_FLAG_SCRIPT) && mListener) {
83 0 : static_cast<nsIJSEventListener*>(mListener.get())->Disconnect();
84 : }
85 4582 : }
86 : };
87 :
88 : /*
89 : * Event listener manager
90 : */
91 :
92 : class nsEventListenerManager
93 : {
94 :
95 : public:
96 : nsEventListenerManager(nsISupports* aTarget);
97 : virtual ~nsEventListenerManager();
98 :
99 0 : NS_INLINE_DECL_REFCOUNTING(nsEventListenerManager)
100 :
101 1464 : NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsEventListenerManager)
102 :
103 : void AddEventListener(const nsAString& aType,
104 : nsIDOMEventListener* aListener,
105 : bool aUseCapture,
106 : bool aWantsUntrusted);
107 : void RemoveEventListener(const nsAString& aType,
108 : nsIDOMEventListener* aListener,
109 : bool aUseCapture);
110 :
111 : /**
112 : * Sets events listeners of all types.
113 : * @param an event listener
114 : */
115 : void AddEventListenerByType(nsIDOMEventListener *aListener,
116 : const nsAString& type,
117 : PRInt32 aFlags);
118 : void RemoveEventListenerByType(nsIDOMEventListener *aListener,
119 : const nsAString& type,
120 : PRInt32 aFlags);
121 :
122 : /**
123 : * Sets the current "inline" event listener for aName to be a
124 : * function compiled from aFunc if !aDeferCompilation. If
125 : * aDeferCompilation, then we assume that we can get the string from
126 : * mTarget later and compile lazily.
127 : */
128 : // XXXbz does that play correctly with nodes being adopted across
129 : // documents? Need to double-check the spec here.
130 : nsresult AddScriptEventListener(nsIAtom *aName,
131 : const nsAString& aFunc,
132 : PRUint32 aLanguage,
133 : bool aDeferCompilation,
134 : bool aPermitUntrustedEvents);
135 : /**
136 : * Remove the current "inline" event listener for aName.
137 : */
138 : void RemoveScriptEventListener(nsIAtom *aName);
139 :
140 20010 : void HandleEvent(nsPresContext* aPresContext,
141 : nsEvent* aEvent,
142 : nsIDOMEvent** aDOMEvent,
143 : nsIDOMEventTarget* aCurrentTarget,
144 : PRUint32 aFlags,
145 : nsEventStatus* aEventStatus,
146 : nsCxPusher* aPusher)
147 : {
148 20010 : if (mListeners.IsEmpty() || aEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH) {
149 2 : return;
150 : }
151 :
152 40004 : if (!mMayHaveCapturingListeners &&
153 19996 : !(aEvent->flags & NS_EVENT_FLAG_BUBBLE)) {
154 2394 : return;
155 : }
156 :
157 17614 : if (!mMayHaveSystemGroupListeners &&
158 : aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) {
159 8808 : return;
160 : }
161 :
162 : // Check if we already know that there is no event listener for the event.
163 12018 : if (mNoListenerForEvent == aEvent->message &&
164 : (mNoListenerForEvent != NS_USER_DEFINED_EVENT ||
165 3212 : mNoListenerForEventAtom == aEvent->userType)) {
166 574 : return;
167 : }
168 : HandleEventInternal(aPresContext, aEvent, aDOMEvent, aCurrentTarget,
169 8232 : aFlags, aEventStatus, aPusher);
170 : }
171 :
172 : void HandleEventInternal(nsPresContext* aPresContext,
173 : nsEvent* aEvent,
174 : nsIDOMEvent** aDOMEvent,
175 : nsIDOMEventTarget* aCurrentTarget,
176 : PRUint32 aFlags,
177 : nsEventStatus* aEventStatus,
178 : nsCxPusher* aPusher);
179 :
180 : /**
181 : * Tells the event listener manager that its target (which owns it) is
182 : * no longer using it (and could go away).
183 : */
184 : void Disconnect();
185 :
186 : /**
187 : * Allows us to quickly determine if we have mutation listeners registered.
188 : */
189 : bool HasMutationListeners();
190 :
191 : /**
192 : * Allows us to quickly determine whether we have unload or beforeunload
193 : * listeners registered.
194 : */
195 : bool HasUnloadListeners();
196 :
197 : /**
198 : * Returns the mutation bits depending on which mutation listeners are
199 : * registered to this listener manager.
200 : * @note If a listener is an nsIDOMMutationListener, all possible mutation
201 : * event bits are returned. All bits are also returned if one of the
202 : * event listeners is registered to handle DOMSubtreeModified events.
203 : */
204 : PRUint32 MutationListenerBits();
205 :
206 : /**
207 : * Returns true if there is at least one event listener for aEventName.
208 : */
209 : bool HasListenersFor(const nsAString& aEventName);
210 :
211 : /**
212 : * Returns true if there is at least one event listener.
213 : */
214 : bool HasListeners();
215 :
216 : /**
217 : * Sets aList to the list of nsIEventListenerInfo objects representing the
218 : * listeners managed by this listener manager.
219 : */
220 : nsresult GetListenerInfo(nsCOMArray<nsIEventListenerInfo>* aList);
221 :
222 : PRUint32 GetIdentifierForEvent(nsIAtom* aEvent);
223 :
224 : static void Shutdown();
225 :
226 : /**
227 : * Returns true if there may be a paint event listener registered,
228 : * false if there definitely isn't.
229 : */
230 0 : bool MayHavePaintEventListener() { return mMayHavePaintEventListener; }
231 :
232 : /**
233 : * Returns true if there may be a MozAudioAvailable event listener registered,
234 : * false if there definitely isn't.
235 : */
236 : bool MayHaveAudioAvailableEventListener() { return mMayHaveAudioAvailableEventListener; }
237 :
238 : /**
239 : * Returns true if there may be a touch event listener registered,
240 : * false if there definitely isn't.
241 : */
242 : bool MayHaveTouchEventListener() { return mMayHaveTouchEventListener; }
243 :
244 : bool MayHaveMouseEnterLeaveEventListener() { return mMayHaveMouseEnterLeaveEventListener; }
245 :
246 : size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
247 :
248 : void UnmarkGrayJSListeners();
249 :
250 : nsISupports* GetTarget() { return mTarget; }
251 : protected:
252 : nsresult HandleEventSubType(nsListenerStruct* aListenerStruct,
253 : nsIDOMEventListener* aListener,
254 : nsIDOMEvent* aDOMEvent,
255 : nsIDOMEventTarget* aCurrentTarget,
256 : PRUint32 aPhaseFlags,
257 : nsCxPusher* aPusher);
258 :
259 : /**
260 : * Compile the "inline" event listener for aListenerStruct. The
261 : * body of the listener can be provided in aBody; if this is null we
262 : * will look for it on mTarget.
263 : */
264 : nsresult CompileEventHandlerInternal(nsListenerStruct *aListenerStruct,
265 : bool aNeedsCxPush,
266 : const nsAString* aBody);
267 :
268 : /**
269 : * Find the nsListenerStruct for the "inline" event listener for aTypeAtom.
270 : */
271 : nsListenerStruct* FindJSEventListener(PRUint32 aEventType, nsIAtom* aTypeAtom);
272 :
273 : /**
274 : * Set the "inline" event listener for aName to aHandler. aHandler
275 : * may be null to indicate that we should lazily get and compile the
276 : * string for this listener. The nsListenerStruct that results, if
277 : * any, is returned in aListenerStruct.
278 : */
279 : nsresult SetJSEventListener(nsIScriptContext *aContext,
280 : JSObject* aScopeGlobal,
281 : nsIAtom* aName,
282 : JSObject *aHandler,
283 : bool aPermitUntrustedEvents,
284 : nsListenerStruct **aListenerStruct);
285 :
286 : public:
287 : /**
288 : * Set the "inline" event listener for aEventName to |v|. This
289 : * might actually remove the event listener, depending on the value
290 : * of |v|.
291 : */
292 : nsresult SetJSEventListenerToJsval(nsIAtom *aEventName, JSContext *cx,
293 : JSObject *aScope, const jsval &v);
294 : /**
295 : * Get the value of the "inline" event listener for aEventName.
296 : * This may cause lazy compilation if the listener is uncompiled.
297 : */
298 : void GetJSEventListener(nsIAtom *aEventName, jsval *vp);
299 :
300 : protected:
301 : void AddEventListener(nsIDOMEventListener *aListener,
302 : PRUint32 aType,
303 : nsIAtom* aTypeAtom,
304 : PRInt32 aFlags);
305 : void RemoveEventListener(nsIDOMEventListener *aListener,
306 : PRUint32 aType,
307 : nsIAtom* aUserType,
308 : PRInt32 aFlags);
309 : void RemoveAllListeners();
310 : const EventTypeData* GetTypeDataForIID(const nsIID& aIID);
311 : const EventTypeData* GetTypeDataForEventName(nsIAtom* aName);
312 : nsPIDOMWindow* GetInnerWindowForTarget();
313 :
314 : PRUint32 mMayHavePaintEventListener : 1;
315 : PRUint32 mMayHaveMutationListeners : 1;
316 : PRUint32 mMayHaveCapturingListeners : 1;
317 : PRUint32 mMayHaveSystemGroupListeners : 1;
318 : PRUint32 mMayHaveAudioAvailableEventListener : 1;
319 : PRUint32 mMayHaveTouchEventListener : 1;
320 : PRUint32 mMayHaveMouseEnterLeaveEventListener : 1;
321 : PRUint32 mNoListenerForEvent : 25;
322 :
323 : nsAutoTObserverArray<nsListenerStruct, 2> mListeners;
324 : nsISupports* mTarget; //WEAK
325 : nsCOMPtr<nsIAtom> mNoListenerForEventAtom;
326 :
327 : static PRUint32 mInstanceCount;
328 : static jsid sAddListenerID;
329 :
330 : friend class nsEventTargetChainItem;
331 : static PRUint32 sCreatedCount;
332 : };
333 :
334 : /**
335 : * NS_AddSystemEventListener() is a helper function for implementing
336 : * nsIDOMEventTarget::AddSystemEventListener().
337 : */
338 : inline nsresult
339 0 : NS_AddSystemEventListener(nsIDOMEventTarget* aTarget,
340 : const nsAString& aType,
341 : nsIDOMEventListener *aListener,
342 : bool aUseCapture,
343 : bool aWantsUntrusted)
344 : {
345 0 : nsEventListenerManager* listenerManager = aTarget->GetListenerManager(true);
346 0 : NS_ENSURE_STATE(listenerManager);
347 0 : PRUint32 flags = NS_EVENT_FLAG_SYSTEM_EVENT;
348 0 : flags |= aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
349 0 : if (aWantsUntrusted) {
350 0 : flags |= NS_PRIV_EVENT_UNTRUSTED_PERMITTED;
351 : }
352 0 : listenerManager->AddEventListenerByType(aListener, aType, flags);
353 0 : return NS_OK;
354 : }
355 :
356 : #endif // nsEventListenerManager_h__
|