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 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 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 "EventException.h"
36#include "InspectorInstrumentation.h"
37#include "ScriptController.h"
38#include "WebKitTransitionEvent.h"
39#include <wtf/MainThread.h>
40#include <wtf/Ref.h>
41#include <wtf/StdLibExtras.h>
42#include <wtf/Vector.h>
43
44using namespace WTF;
45
46namespace WebCore {
47
48EventTargetData::EventTargetData()
49{
50}
51
52EventTargetData::~EventTargetData()
53{
54}
55
56EventTarget::~EventTarget()
57{
58}
59
60Node* EventTarget::toNode()
61{
62    return 0;
63}
64
65DOMWindow* EventTarget::toDOMWindow()
66{
67    return 0;
68}
69
70bool EventTarget::isMessagePort() const
71{
72    return false;
73}
74
75bool EventTarget::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
76{
77    return ensureEventTargetData().eventListenerMap.add(eventType, listener, useCapture);
78}
79
80bool EventTarget::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
81{
82    EventTargetData* d = eventTargetData();
83    if (!d)
84        return false;
85
86    size_t indexOfRemovedListener;
87
88    if (!d->eventListenerMap.remove(eventType, listener, useCapture, indexOfRemovedListener))
89        return false;
90
91    // Notify firing events planning to invoke the listener at 'index' that
92    // they have one less listener to invoke.
93    if (!d->firingEventIterators)
94        return true;
95    for (size_t i = 0; i < d->firingEventIterators->size(); ++i) {
96        FiringEventIterator& firingIterator = d->firingEventIterators->at(i);
97        if (eventType != firingIterator.eventType)
98            continue;
99
100        if (indexOfRemovedListener >= firingIterator.size)
101            continue;
102
103        --firingIterator.size;
104        if (indexOfRemovedListener <= firingIterator.iterator)
105            --firingIterator.iterator;
106    }
107
108    return true;
109}
110
111bool EventTarget::setAttributeEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener)
112{
113    clearAttributeEventListener(eventType);
114    if (!listener)
115        return false;
116    return addEventListener(eventType, listener, false);
117}
118
119EventListener* EventTarget::getAttributeEventListener(const AtomicString& eventType)
120{
121    const EventListenerVector& entry = getEventListeners(eventType);
122    for (size_t i = 0; i < entry.size(); ++i) {
123        if (entry[i].listener->isAttribute())
124            return entry[i].listener.get();
125    }
126    return 0;
127}
128
129bool EventTarget::clearAttributeEventListener(const AtomicString& eventType)
130{
131    EventListener* listener = getAttributeEventListener(eventType);
132    if (!listener)
133        return false;
134    return removeEventListener(eventType, listener, false);
135}
136
137bool EventTarget::dispatchEvent(PassRefPtr<Event> event, ExceptionCode& ec)
138{
139    if (!event || event->type().isEmpty()) {
140        ec = EventException::UNSPECIFIED_EVENT_TYPE_ERR;
141        return false;
142    }
143
144    if (event->isBeingDispatched()) {
145        ec = EventException::DISPATCH_REQUEST_ERR;
146        return false;
147    }
148
149    if (!scriptExecutionContext())
150        return false;
151
152    return dispatchEvent(event);
153}
154
155bool EventTarget::dispatchEvent(PassRefPtr<Event> event)
156{
157    event->setTarget(this);
158    event->setCurrentTarget(this);
159    event->setEventPhase(Event::AT_TARGET);
160    bool defaultPrevented = fireEventListeners(event.get());
161    event->setEventPhase(0);
162    return defaultPrevented;
163}
164
165void EventTarget::uncaughtExceptionInEventHandler()
166{
167}
168
169static const AtomicString& legacyType(const Event* event)
170{
171    if (event->type() == eventNames().transitionendEvent)
172        return eventNames().webkitTransitionEndEvent;
173
174    if (event->type() == eventNames().wheelEvent)
175        return eventNames().mousewheelEvent;
176
177    return emptyAtom;
178}
179
180bool EventTarget::fireEventListeners(Event* event)
181{
182    ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
183    ASSERT(event && !event->type().isEmpty());
184
185    EventTargetData* d = eventTargetData();
186    if (!d)
187        return true;
188
189    EventListenerVector* legacyListenersVector = 0;
190    const AtomicString& legacyTypeName = legacyType(event);
191    if (!legacyTypeName.isEmpty())
192        legacyListenersVector = d->eventListenerMap.find(legacyTypeName);
193
194    EventListenerVector* listenersVector = d->eventListenerMap.find(event->type());
195
196    if (listenersVector)
197        fireEventListeners(event, d, *listenersVector);
198    else if (legacyListenersVector) {
199        AtomicString typeName = event->type();
200        event->setType(legacyTypeName);
201        fireEventListeners(event, d, *legacyListenersVector);
202        event->setType(typeName);
203    }
204
205    return !event->defaultPrevented();
206}
207
208void EventTarget::fireEventListeners(Event* event, EventTargetData* d, EventListenerVector& entry)
209{
210    Ref<EventTarget> protect(*this);
211
212    // Fire all listeners registered for this event. Don't fire listeners removed during event dispatch.
213    // Also, don't fire event listeners added during event dispatch. Conveniently, all new event listeners will be added
214    // after or at index |size|, so iterating up to (but not including) |size| naturally excludes new event listeners.
215
216    bool userEventWasHandled = false;
217    size_t i = 0;
218    size_t size = entry.size();
219    if (!d->firingEventIterators)
220        d->firingEventIterators = std::make_unique<FiringEventIteratorVector>();
221    d->firingEventIterators->append(FiringEventIterator(event->type(), i, size));
222
223    ScriptExecutionContext* context = scriptExecutionContext();
224    Document* document = nullptr;
225    InspectorInstrumentationCookie willDispatchEventCookie;
226    if (context && context->isDocument()) {
227        document = toDocument(context);
228        willDispatchEventCookie = InspectorInstrumentation::willDispatchEvent(document, *event, size > 0);
229    }
230
231    for (; i < size; ++i) {
232        RegisteredEventListener& registeredListener = entry[i];
233        if (event->eventPhase() == Event::CAPTURING_PHASE && !registeredListener.useCapture)
234            continue;
235        if (event->eventPhase() == Event::BUBBLING_PHASE && registeredListener.useCapture)
236            continue;
237
238        // If stopImmediatePropagation has been called, we just break out immediately, without
239        // handling any more events on this target.
240        if (event->immediatePropagationStopped())
241            break;
242
243        InspectorInstrumentationCookie cookie = InspectorInstrumentation::willHandleEvent(context, event);
244        // To match Mozilla, the AT_TARGET phase fires both capturing and bubbling
245        // event listeners, even though that violates some versions of the DOM spec.
246        registeredListener.listener->handleEvent(context, event);
247        if (!userEventWasHandled && ScriptController::processingUserGesture())
248            userEventWasHandled = true;
249        InspectorInstrumentation::didHandleEvent(cookie);
250    }
251    d->firingEventIterators->removeLast();
252    if (userEventWasHandled && document)
253        document->resetLastHandledUserGestureTimestamp();
254
255    if (document)
256        InspectorInstrumentation::didDispatchEvent(willDispatchEventCookie);
257}
258
259const EventListenerVector& EventTarget::getEventListeners(const AtomicString& eventType)
260{
261    DEPRECATED_DEFINE_STATIC_LOCAL(EventListenerVector, emptyVector, ());
262
263    EventTargetData* d = eventTargetData();
264    if (!d)
265        return emptyVector;
266
267    EventListenerVector* listenerVector = d->eventListenerMap.find(eventType);
268    if (!listenerVector)
269        return emptyVector;
270
271    return *listenerVector;
272}
273
274void EventTarget::removeAllEventListeners()
275{
276    EventTargetData* d = eventTargetData();
277    if (!d)
278        return;
279    d->eventListenerMap.clear();
280
281    // Notify firing events planning to invoke the listener at 'index' that
282    // they have one less listener to invoke.
283    if (d->firingEventIterators) {
284        for (size_t i = 0; i < d->firingEventIterators->size(); ++i) {
285            d->firingEventIterators->at(i).iterator = 0;
286            d->firingEventIterators->at(i).size = 0;
287        }
288    }
289}
290
291} // namespace WebCore
292