Remove FeatureObserver.
[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 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 "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
44 using namespace WTF;
45
46 namespace WebCore {
47
48 EventTargetData::EventTargetData()
49 {
50 }
51
52 EventTargetData::~EventTargetData()
53 {
54 }
55
56 EventTarget::~EventTarget()
57 {
58 }
59
60 Node* EventTarget::toNode()
61 {
62     return 0;
63 }
64
65 DOMWindow* EventTarget::toDOMWindow()
66 {
67     return 0;
68 }
69
70 bool EventTarget::isMessagePort() const
71 {
72     return false;
73 }
74
75 bool EventTarget::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
76 {
77     return ensureEventTargetData().eventListenerMap.add(eventType, listener, useCapture);
78 }
79
80 bool 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
111 bool 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
119 EventListener* 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
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(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
155 bool 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
165 void EventTarget::uncaughtExceptionInEventHandler()
166 {
167 }
168
169 static 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
180 bool 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         
208 void 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
259 const EventListenerVector& EventTarget::getEventListeners(const AtomicString& eventType)
260 {
261     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
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 (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