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
39using namespace WTF;
40
41namespace WebCore {
42
43#ifndef NDEBUG
44static int gEventDispatchForbidden = 0;
45
46void forbidEventDispatch()
47{
48    if (!isMainThread())
49        return;
50    ++gEventDispatchForbidden;
51}
52
53void allowEventDispatch()
54{
55    if (!isMainThread())
56        return;
57    if (gEventDispatchForbidden > 0)
58        --gEventDispatchForbidden;
59}
60
61bool eventDispatchForbidden()
62{
63    if (!isMainThread())
64        return false;
65    return gEventDispatchForbidden > 0;
66}
67#endif // NDEBUG
68
69EventTargetData::EventTargetData()
70{
71}
72
73EventTargetData::~EventTargetData()
74{
75    deleteAllValues(eventListenerMap);
76}
77
78EventTarget::~EventTarget()
79{
80}
81
82EventSource* EventTarget::toEventSource()
83{
84    return 0;
85}
86
87Node* EventTarget::toNode()
88{
89    return 0;
90}
91
92DOMWindow* EventTarget::toDOMWindow()
93{
94    return 0;
95}
96
97XMLHttpRequest* EventTarget::toXMLHttpRequest()
98{
99    return 0;
100}
101
102XMLHttpRequestUpload* EventTarget::toXMLHttpRequestUpload()
103{
104    return 0;
105}
106
107#if ENABLE(OFFLINE_WEB_APPLICATIONS)
108DOMApplicationCache* EventTarget::toDOMApplicationCache()
109{
110    return 0;
111}
112#endif
113
114#if ENABLE(SVG)
115SVGElementInstance* EventTarget::toSVGElementInstance()
116{
117    return 0;
118}
119#endif
120
121#if ENABLE(WEB_AUDIO)
122AudioContext* EventTarget::toAudioContext()
123{
124    return 0;
125}
126
127JavaScriptAudioNode* EventTarget::toJavaScriptAudioNode()
128{
129    return 0;
130}
131#endif
132
133#if ENABLE(WEB_SOCKETS)
134WebSocket* EventTarget::toWebSocket()
135{
136    return 0;
137}
138#endif
139
140MessagePort* EventTarget::toMessagePort()
141{
142    return 0;
143}
144
145#if ENABLE(WORKERS)
146Worker* EventTarget::toWorker()
147{
148    return 0;
149}
150
151DedicatedWorkerContext* EventTarget::toDedicatedWorkerContext()
152{
153    return 0;
154}
155#endif
156
157#if ENABLE(SHARED_WORKERS)
158SharedWorker* EventTarget::toSharedWorker()
159{
160    return 0;
161}
162SharedWorkerContext* EventTarget::toSharedWorkerContext()
163{
164    return 0;
165}
166#endif
167
168#if ENABLE(NOTIFICATIONS)
169Notification* EventTarget::toNotification()
170{
171    return 0;
172}
173#endif
174
175#if ENABLE(BLOB)
176FileReader* EventTarget::toFileReader()
177{
178    return 0;
179}
180#endif
181#if ENABLE(FILE_SYSTEM)
182FileWriter* EventTarget::toFileWriter()
183{
184    return 0;
185}
186#endif
187
188#if ENABLE(INDEXED_DATABASE)
189IDBDatabase* EventTarget::toIDBDatabase()
190{
191    return 0;
192}
193IDBRequest* EventTarget::toIDBRequest()
194{
195    return 0;
196}
197IDBTransaction* EventTarget::toIDBTransaction()
198{
199    return 0;
200}
201IDBVersionChangeRequest* EventTarget::toIDBVersionChangeRequest()
202{
203    return 0;
204}
205#endif
206
207bool 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
227bool 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
266bool 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
274EventListener* 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
284bool 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
292bool 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
305bool 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
313void EventTarget::uncaughtExceptionInEventHandler()
314{
315}
316
317bool 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
343void 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
379const 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
392void 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