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