• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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