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