1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
6 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
7 * (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 */
31
32 #include "config.h"
33 #include "EventTarget.h"
34
35 #include "Event.h"
36 #include "EventException.h"
37 #include <wtf/StdLibExtras.h>
38
39 using namespace WTF;
40
41 namespace WebCore {
42
43 #ifndef NDEBUG
44 static int gEventDispatchForbidden = 0;
45
forbidEventDispatch()46 void forbidEventDispatch()
47 {
48 if (!isMainThread())
49 return;
50 ++gEventDispatchForbidden;
51 }
52
allowEventDispatch()53 void allowEventDispatch()
54 {
55 if (!isMainThread())
56 return;
57 if (gEventDispatchForbidden > 0)
58 --gEventDispatchForbidden;
59 }
60
eventDispatchForbidden()61 bool eventDispatchForbidden()
62 {
63 if (!isMainThread())
64 return false;
65 return gEventDispatchForbidden > 0;
66 }
67 #endif // NDEBUG
68
EventTargetData()69 EventTargetData::EventTargetData()
70 {
71 }
72
~EventTargetData()73 EventTargetData::~EventTargetData()
74 {
75 deleteAllValues(eventListenerMap);
76 }
77
~EventTarget()78 EventTarget::~EventTarget()
79 {
80 }
81
toEventSource()82 EventSource* EventTarget::toEventSource()
83 {
84 return 0;
85 }
86
toNode()87 Node* EventTarget::toNode()
88 {
89 return 0;
90 }
91
toDOMWindow()92 DOMWindow* EventTarget::toDOMWindow()
93 {
94 return 0;
95 }
96
toXMLHttpRequest()97 XMLHttpRequest* EventTarget::toXMLHttpRequest()
98 {
99 return 0;
100 }
101
toXMLHttpRequestUpload()102 XMLHttpRequestUpload* EventTarget::toXMLHttpRequestUpload()
103 {
104 return 0;
105 }
106
107 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
toDOMApplicationCache()108 DOMApplicationCache* EventTarget::toDOMApplicationCache()
109 {
110 return 0;
111 }
112 #endif
113
114 #if ENABLE(SVG)
toSVGElementInstance()115 SVGElementInstance* EventTarget::toSVGElementInstance()
116 {
117 return 0;
118 }
119 #endif
120
121 #if ENABLE(WEB_AUDIO)
toAudioContext()122 AudioContext* EventTarget::toAudioContext()
123 {
124 return 0;
125 }
126
toJavaScriptAudioNode()127 JavaScriptAudioNode* EventTarget::toJavaScriptAudioNode()
128 {
129 return 0;
130 }
131 #endif
132
133 #if ENABLE(WEB_SOCKETS)
toWebSocket()134 WebSocket* EventTarget::toWebSocket()
135 {
136 return 0;
137 }
138 #endif
139
toMessagePort()140 MessagePort* EventTarget::toMessagePort()
141 {
142 return 0;
143 }
144
145 #if ENABLE(WORKERS)
toWorker()146 Worker* EventTarget::toWorker()
147 {
148 return 0;
149 }
150
toDedicatedWorkerContext()151 DedicatedWorkerContext* EventTarget::toDedicatedWorkerContext()
152 {
153 return 0;
154 }
155 #endif
156
157 #if ENABLE(SHARED_WORKERS)
toSharedWorker()158 SharedWorker* EventTarget::toSharedWorker()
159 {
160 return 0;
161 }
toSharedWorkerContext()162 SharedWorkerContext* EventTarget::toSharedWorkerContext()
163 {
164 return 0;
165 }
166 #endif
167
168 #if ENABLE(NOTIFICATIONS)
toNotification()169 Notification* EventTarget::toNotification()
170 {
171 return 0;
172 }
173 #endif
174
175 #if ENABLE(BLOB)
toFileReader()176 FileReader* EventTarget::toFileReader()
177 {
178 return 0;
179 }
180 #endif
181 #if ENABLE(FILE_SYSTEM)
toFileWriter()182 FileWriter* EventTarget::toFileWriter()
183 {
184 return 0;
185 }
186 #endif
187
188 #if ENABLE(INDEXED_DATABASE)
toIDBDatabase()189 IDBDatabase* EventTarget::toIDBDatabase()
190 {
191 return 0;
192 }
toIDBRequest()193 IDBRequest* EventTarget::toIDBRequest()
194 {
195 return 0;
196 }
toIDBTransaction()197 IDBTransaction* EventTarget::toIDBTransaction()
198 {
199 return 0;
200 }
toIDBVersionChangeRequest()201 IDBVersionChangeRequest* EventTarget::toIDBVersionChangeRequest()
202 {
203 return 0;
204 }
205 #endif
206
addEventListener(const AtomicString & eventType,PassRefPtr<EventListener> listener,bool useCapture)207 bool EventTarget::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
208 {
209 EventTargetData* d = ensureEventTargetData();
210
211 pair<EventListenerMap::iterator, bool> result = d->eventListenerMap.add(eventType, 0);
212 EventListenerVector*& entry = result.first->second;
213 const bool isNewEntry = result.second;
214 if (isNewEntry)
215 entry = new EventListenerVector();
216
217 RegisteredEventListener registeredListener(listener, useCapture);
218 if (!isNewEntry) {
219 if (entry->find(registeredListener) != notFound) // duplicate listener
220 return false;
221 }
222
223 entry->append(registeredListener);
224 return true;
225 }
226
removeEventListener(const AtomicString & eventType,EventListener * listener,bool useCapture)227 bool EventTarget::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
228 {
229 EventTargetData* d = eventTargetData();
230 if (!d)
231 return false;
232
233 EventListenerMap::iterator result = d->eventListenerMap.find(eventType);
234 if (result == d->eventListenerMap.end())
235 return false;
236 EventListenerVector* entry = result->second;
237
238 RegisteredEventListener registeredListener(listener, useCapture);
239 size_t index = entry->find(registeredListener);
240 if (index == notFound)
241 return false;
242
243 entry->remove(index);
244 if (entry->isEmpty()) {
245 delete entry;
246 d->eventListenerMap.remove(result);
247 }
248
249 // Notify firing events planning to invoke the listener at 'index' that
250 // they have one less listener to invoke.
251 for (size_t i = 0; i < d->firingEventIterators.size(); ++i) {
252 if (eventType != d->firingEventIterators[i].eventType)
253 continue;
254
255 if (index >= d->firingEventIterators[i].end)
256 continue;
257
258 --d->firingEventIterators[i].end;
259 if (index <= d->firingEventIterators[i].iterator)
260 --d->firingEventIterators[i].iterator;
261 }
262
263 return true;
264 }
265
setAttributeEventListener(const AtomicString & eventType,PassRefPtr<EventListener> listener)266 bool EventTarget::setAttributeEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener)
267 {
268 clearAttributeEventListener(eventType);
269 if (!listener)
270 return false;
271 return addEventListener(eventType, listener, false);
272 }
273
getAttributeEventListener(const AtomicString & eventType)274 EventListener* EventTarget::getAttributeEventListener(const AtomicString& eventType)
275 {
276 const EventListenerVector& entry = getEventListeners(eventType);
277 for (size_t i = 0; i < entry.size(); ++i) {
278 if (entry[i].listener->isAttribute())
279 return entry[i].listener.get();
280 }
281 return 0;
282 }
283
clearAttributeEventListener(const AtomicString & eventType)284 bool EventTarget::clearAttributeEventListener(const AtomicString& eventType)
285 {
286 EventListener* listener = getAttributeEventListener(eventType);
287 if (!listener)
288 return false;
289 return removeEventListener(eventType, listener, false);
290 }
291
dispatchEvent(PassRefPtr<Event> event,ExceptionCode & ec)292 bool EventTarget::dispatchEvent(PassRefPtr<Event> event, ExceptionCode& ec)
293 {
294 if (!event || event->type().isEmpty()) {
295 ec = EventException::UNSPECIFIED_EVENT_TYPE_ERR;
296 return false;
297 }
298
299 if (!scriptExecutionContext())
300 return false;
301
302 return dispatchEvent(event);
303 }
304
dispatchEvent(PassRefPtr<Event> event)305 bool EventTarget::dispatchEvent(PassRefPtr<Event> event)
306 {
307 event->setTarget(this);
308 event->setCurrentTarget(this);
309 event->setEventPhase(Event::AT_TARGET);
310 return fireEventListeners(event.get());
311 }
312
uncaughtExceptionInEventHandler()313 void EventTarget::uncaughtExceptionInEventHandler()
314 {
315 }
316
fireEventListeners(Event * event)317 bool EventTarget::fireEventListeners(Event* event)
318 {
319 ASSERT(!eventDispatchForbidden());
320 ASSERT(event && !event->type().isEmpty());
321
322 EventTargetData* d = eventTargetData();
323 if (!d)
324 return true;
325
326 EventListenerMap::iterator result = d->eventListenerMap.find(event->type());
327 if (result != d->eventListenerMap.end())
328 fireEventListeners(event, d, *result->second);
329
330 #if ENABLE(TOUCH_EVENTS) && PLATFORM(ANDROID)
331 if (event->isTouchEvent() && !event->hitTouchHandler()) {
332 // Check for touchmove or touchend to see if we can skip
333 // the rest of the stream (we always get touchstart, don't need to check that)
334 if (d->eventListenerMap.contains(eventNames().touchmoveEvent)
335 || d->eventListenerMap.contains(eventNames().touchendEvent))
336 event->setHitTouchHandler();
337 }
338 #endif
339
340 return !event->defaultPrevented();
341 }
342
fireEventListeners(Event * event,EventTargetData * d,EventListenerVector & entry)343 void EventTarget::fireEventListeners(Event* event, EventTargetData* d, EventListenerVector& entry)
344 {
345 RefPtr<EventTarget> protect = this;
346
347 #if ENABLE(TOUCH_EVENTS) && PLATFORM(ANDROID)
348 if (event->isTouchEvent())
349 event->setHitTouchHandler();
350 #endif
351
352 // Fire all listeners registered for this event. Don't fire listeners removed
353 // during event dispatch. Also, don't fire event listeners added during event
354 // dispatch. Conveniently, all new event listeners will be added after 'end',
355 // so iterating to 'end' naturally excludes new event listeners.
356
357 size_t i = 0;
358 size_t end = entry.size();
359 d->firingEventIterators.append(FiringEventIterator(event->type(), i, end));
360 for ( ; i < end; ++i) {
361 RegisteredEventListener& registeredListener = entry[i];
362 if (event->eventPhase() == Event::CAPTURING_PHASE && !registeredListener.useCapture)
363 continue;
364 if (event->eventPhase() == Event::BUBBLING_PHASE && registeredListener.useCapture)
365 continue;
366
367 // If stopImmediatePropagation has been called, we just break out immediately, without
368 // handling any more events on this target.
369 if (event->immediatePropagationStopped())
370 break;
371
372 // To match Mozilla, the AT_TARGET phase fires both capturing and bubbling
373 // event listeners, even though that violates some versions of the DOM spec.
374 registeredListener.listener->handleEvent(scriptExecutionContext(), event);
375 }
376 d->firingEventIterators.removeLast();
377 }
378
getEventListeners(const AtomicString & eventType)379 const EventListenerVector& EventTarget::getEventListeners(const AtomicString& eventType)
380 {
381 DEFINE_STATIC_LOCAL(EventListenerVector, emptyVector, ());
382
383 EventTargetData* d = eventTargetData();
384 if (!d)
385 return emptyVector;
386 EventListenerMap::iterator it = d->eventListenerMap.find(eventType);
387 if (it == d->eventListenerMap.end())
388 return emptyVector;
389 return *it->second;
390 }
391
removeAllEventListeners()392 void EventTarget::removeAllEventListeners()
393 {
394 EventTargetData* d = eventTargetData();
395 if (!d)
396 return;
397 deleteAllValues(d->eventListenerMap);
398 d->eventListenerMap.clear();
399
400 // Notify firing events planning to invoke the listener at 'index' that
401 // they have one less listener to invoke.
402 for (size_t i = 0; i < d->firingEventIterators.size(); ++i) {
403 d->firingEventIterators[i].iterator = 0;
404 d->firingEventIterators[i].end = 0;
405 }
406 }
407
408 } // namespace WebCore
409