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>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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.
33 #include "core/events/EventTarget.h"
35 #include "RuntimeEnabledFeatures.h"
36 #include "bindings/v8/ExceptionState.h"
37 #include "core/events/Event.h"
38 #include "core/dom/ExceptionCode.h"
39 #include "core/inspector/InspectorInstrumentation.h"
40 #include "core/frame/DOMWindow.h"
41 #include "platform/UserGestureIndicator.h"
42 #include "wtf/StdLibExtras.h"
43 #include "wtf/Vector.h"
49 EventTargetData::EventTargetData()
53 EventTargetData::~EventTargetData()
57 EventTarget::~EventTarget()
61 Node* EventTarget::toNode()
66 DOMWindow* EventTarget::toDOMWindow()
71 MessagePort* EventTarget::toMessagePort()
76 inline DOMWindow* EventTarget::executingWindow()
78 if (ExecutionContext* context = executionContext())
79 return context->executingWindow();
83 bool EventTarget::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
85 EventListener* eventListener = listener.get();
86 if (ensureEventTargetData().eventListenerMap.add(eventType, listener, useCapture)) {
87 InspectorInstrumentation::didAddEventListener(this, eventType, eventListener, useCapture);
93 bool EventTarget::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
95 EventTargetData* d = eventTargetData();
99 size_t indexOfRemovedListener;
101 if (!d->eventListenerMap.remove(eventType, listener, useCapture, indexOfRemovedListener))
103 InspectorInstrumentation::didRemoveEventListener(this, eventType, listener, useCapture);
105 // Notify firing events planning to invoke the listener at 'index' that
106 // they have one less listener to invoke.
107 if (!d->firingEventIterators)
109 for (size_t i = 0; i < d->firingEventIterators->size(); ++i) {
110 FiringEventIterator& firingIterator = d->firingEventIterators->at(i);
111 if (eventType != firingIterator.eventType)
114 if (indexOfRemovedListener >= firingIterator.end)
117 --firingIterator.end;
118 if (indexOfRemovedListener <= firingIterator.iterator)
119 --firingIterator.iterator;
125 bool EventTarget::setAttributeEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener)
127 clearAttributeEventListener(eventType);
130 return addEventListener(eventType, listener, false);
133 EventListener* EventTarget::getAttributeEventListener(const AtomicString& eventType)
135 const EventListenerVector& entry = getEventListeners(eventType);
136 for (size_t i = 0; i < entry.size(); ++i) {
137 EventListener* listener = entry[i].listener.get();
138 if (listener->isAttribute() && listener->belongsToTheCurrentWorld())
144 bool EventTarget::clearAttributeEventListener(const AtomicString& eventType)
146 EventListener* listener = getAttributeEventListener(eventType);
149 return removeEventListener(eventType, listener, false);
152 bool EventTarget::dispatchEvent(PassRefPtr<Event> event, ExceptionState& exceptionState)
155 exceptionState.throwDOMException(InvalidStateError, "The event provided is null.");
158 if (event->type().isEmpty()) {
159 exceptionState.throwDOMException(InvalidStateError, "The event provided is uninitialized.");
162 if (event->isBeingDispatched()) {
163 exceptionState.throwDOMException(InvalidStateError, "The event is already being dispatched.");
167 if (!executionContext())
170 return dispatchEvent(event);
173 bool EventTarget::dispatchEvent(PassRefPtr<Event> event)
175 event->setTarget(this);
176 event->setCurrentTarget(this);
177 event->setEventPhase(Event::AT_TARGET);
178 bool defaultPrevented = fireEventListeners(event.get());
179 event->setEventPhase(0);
180 return defaultPrevented;
183 void EventTarget::uncaughtExceptionInEventHandler()
187 static const AtomicString& legacyType(const Event* event)
189 if (event->type() == EventTypeNames::transitionend)
190 return EventTypeNames::webkitTransitionEnd;
192 if (event->type() == EventTypeNames::animationstart)
193 return EventTypeNames::webkitAnimationStart;
195 if (event->type() == EventTypeNames::animationend)
196 return EventTypeNames::webkitAnimationEnd;
198 if (event->type() == EventTypeNames::animationiteration)
199 return EventTypeNames::webkitAnimationIteration;
201 if (event->type() == EventTypeNames::wheel)
202 return EventTypeNames::mousewheel;
207 void EventTarget::countLegacyEvents(const AtomicString& legacyTypeName, EventListenerVector* listenersVector, EventListenerVector* legacyListenersVector)
209 UseCounter::Feature unprefixedFeature;
210 UseCounter::Feature prefixedFeature;
211 UseCounter::Feature prefixedAndUnprefixedFeature;
212 bool shouldCount = false;
214 if (legacyTypeName == EventTypeNames::webkitTransitionEnd) {
215 prefixedFeature = UseCounter::PrefixedTransitionEndEvent;
216 unprefixedFeature = UseCounter::UnprefixedTransitionEndEvent;
217 prefixedAndUnprefixedFeature = UseCounter::PrefixedAndUnprefixedTransitionEndEvent;
219 } else if (legacyTypeName == EventTypeNames::webkitAnimationEnd) {
220 prefixedFeature = UseCounter::PrefixedAnimationEndEvent;
221 unprefixedFeature = UseCounter::UnprefixedAnimationEndEvent;
222 prefixedAndUnprefixedFeature = UseCounter::PrefixedAndUnprefixedAnimationEndEvent;
224 } else if (legacyTypeName == EventTypeNames::webkitAnimationStart) {
225 prefixedFeature = UseCounter::PrefixedAnimationStartEvent;
226 unprefixedFeature = UseCounter::UnprefixedAnimationStartEvent;
227 prefixedAndUnprefixedFeature = UseCounter::PrefixedAndUnprefixedAnimationStartEvent;
229 } else if (legacyTypeName == EventTypeNames::webkitAnimationIteration) {
230 prefixedFeature = UseCounter::PrefixedAnimationIterationEvent;
231 unprefixedFeature = UseCounter::UnprefixedAnimationIterationEvent;
232 prefixedAndUnprefixedFeature = UseCounter::PrefixedAndUnprefixedAnimationIterationEvent;
237 if (DOMWindow* executingWindow = this->executingWindow()) {
238 if (legacyListenersVector) {
240 UseCounter::count(executingWindow->document(), prefixedAndUnprefixedFeature);
242 UseCounter::count(executingWindow->document(), prefixedFeature);
243 } else if (listenersVector) {
244 UseCounter::count(executingWindow->document(), unprefixedFeature);
250 bool EventTarget::fireEventListeners(Event* event)
252 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
253 ASSERT(event && !event->type().isEmpty());
255 EventTargetData* d = eventTargetData();
259 EventListenerVector* legacyListenersVector = 0;
260 AtomicString legacyTypeName = legacyType(event);
261 if (!legacyTypeName.isEmpty())
262 legacyListenersVector = d->eventListenerMap.find(legacyTypeName);
264 EventListenerVector* listenersVector = d->eventListenerMap.find(event->type());
265 if (!RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled() && (event->type() == EventTypeNames::animationiteration || event->type() == EventTypeNames::animationend
266 || event->type() == EventTypeNames::animationstart))
269 if (listenersVector) {
270 fireEventListeners(event, d, *listenersVector);
271 } else if (legacyListenersVector) {
272 AtomicString unprefixedTypeName = event->type();
273 event->setType(legacyTypeName);
274 fireEventListeners(event, d, *legacyListenersVector);
275 event->setType(unprefixedTypeName);
278 countLegacyEvents(legacyTypeName, listenersVector, legacyListenersVector);
279 return !event->defaultPrevented();
282 void EventTarget::fireEventListeners(Event* event, EventTargetData* d, EventListenerVector& entry)
284 RefPtr<EventTarget> protect = this;
286 // Fire all listeners registered for this event. Don't fire listeners removed
287 // during event dispatch. Also, don't fire event listeners added during event
288 // dispatch. Conveniently, all new event listeners will be added after or at
289 // index |size|, so iterating up to (but not including) |size| naturally excludes
290 // new event listeners.
292 if (event->type() == EventTypeNames::beforeunload) {
293 if (DOMWindow* executingWindow = this->executingWindow()) {
294 if (executingWindow->top())
295 UseCounter::count(executingWindow->document(), UseCounter::SubFrameBeforeUnloadFired);
296 UseCounter::count(executingWindow->document(), UseCounter::DocumentBeforeUnloadFired);
298 } else if (event->type() == EventTypeNames::unload) {
299 if (DOMWindow* executingWindow = this->executingWindow())
300 UseCounter::count(executingWindow->document(), UseCounter::DocumentUnloadFired);
303 bool userEventWasHandled = false;
305 size_t size = entry.size();
306 if (!d->firingEventIterators)
307 d->firingEventIterators = adoptPtr(new FiringEventIteratorVector);
308 d->firingEventIterators->append(FiringEventIterator(event->type(), i, size));
309 for ( ; i < size; ++i) {
310 RegisteredEventListener& registeredListener = entry[i];
311 if (event->eventPhase() == Event::CAPTURING_PHASE && !registeredListener.useCapture)
313 if (event->eventPhase() == Event::BUBBLING_PHASE && registeredListener.useCapture)
316 // If stopImmediatePropagation has been called, we just break out immediately, without
317 // handling any more events on this target.
318 if (event->immediatePropagationStopped())
321 ExecutionContext* context = executionContext();
325 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willHandleEvent(this, event->type(), registeredListener.listener.get(), registeredListener.useCapture);
326 // To match Mozilla, the AT_TARGET phase fires both capturing and bubbling
327 // event listeners, even though that violates some versions of the DOM spec.
328 registeredListener.listener->handleEvent(context, event);
329 if (!userEventWasHandled && UserGestureIndicator::processingUserGesture())
330 userEventWasHandled = true;
331 InspectorInstrumentation::didHandleEvent(cookie);
333 d->firingEventIterators->removeLast();
334 if (userEventWasHandled) {
335 if (ExecutionContext* context = executionContext())
336 context->userEventWasHandled();
340 const EventListenerVector& EventTarget::getEventListeners(const AtomicString& eventType)
342 DEFINE_STATIC_LOCAL(EventListenerVector, emptyVector, ());
344 EventTargetData* d = eventTargetData();
348 EventListenerVector* listenerVector = d->eventListenerMap.find(eventType);
352 return *listenerVector;
355 Vector<AtomicString> EventTarget::eventTypes()
357 EventTargetData* d = eventTargetData();
358 return d ? d->eventListenerMap.eventTypes() : Vector<AtomicString>();
361 void EventTarget::removeAllEventListeners()
363 EventTargetData* d = eventTargetData();
366 d->eventListenerMap.clear();
367 InspectorInstrumentation::didRemoveAllEventListeners(this);
369 // Notify firing events planning to invoke the listener at 'index' that
370 // they have one less listener to invoke.
371 if (d->firingEventIterators) {
372 for (size_t i = 0; i < d->firingEventIterators->size(); ++i) {
373 d->firingEventIterators->at(i).iterator = 0;
374 d->firingEventIterators->at(i).end = 0;
379 } // namespace WebCore