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