1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 4 * (C) 2001 Dirk Mueller (mueller (at) kde.org) 5 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. 6 * Copyright (C) 2006 Alexey Proskuryakov (ap (at) webkit.org) 7 * (C) 2007, 2008 Nikolas Zimmermann <zimmermann (at) 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 "core/events/EventTarget.h" 34 35 #include "bindings/v8/ExceptionState.h" 36 #include "core/dom/ExceptionCode.h" 37 #include "core/dom/NoEventDispatchAssertion.h" 38 #include "core/editing/Editor.h" 39 #include "core/events/Event.h" 40 #include "core/inspector/InspectorInstrumentation.h" 41 #include "core/frame/LocalDOMWindow.h" 42 #include "platform/RuntimeEnabledFeatures.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 LocalDOMWindow* EventTarget::toDOMWindow() 68 { 69 return 0; 70 } 71 72 MessagePort* EventTarget::toMessagePort() 73 { 74 return 0; 75 } 76 77 inline LocalDOMWindow* EventTarget::executingWindow() 78 { 79 if (ExecutionContext* context = executionContext()) 80 return context->executingWindow(); 81 return 0; 82 } 83 84 bool EventTarget::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture) 85 { 86 // FIXME: listener null check should throw TypeError (and be done in 87 // generated bindings), but breaks legacy content. http://crbug.com/249598 88 if (!listener) 89 return false; 90 return ensureEventTargetData().eventListenerMap.add(eventType, listener, useCapture); 91 } 92 93 bool EventTarget::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture) 94 { 95 EventTargetData* d = eventTargetData(); 96 if (!d) 97 return false; 98 99 size_t indexOfRemovedListener; 100 101 if (!d->eventListenerMap.remove(eventType, listener, useCapture, indexOfRemovedListener)) 102 return false; 103 104 // Notify firing events planning to invoke the listener at 'index' that 105 // they have one less listener to invoke. 106 if (!d->firingEventIterators) 107 return true; 108 for (size_t i = 0; i < d->firingEventIterators->size(); ++i) { 109 FiringEventIterator& firingIterator = d->firingEventIterators->at(i); 110 if (eventType != firingIterator.eventType) 111 continue; 112 113 if (indexOfRemovedListener >= firingIterator.end) 114 continue; 115 116 --firingIterator.end; 117 if (indexOfRemovedListener <= firingIterator.iterator) 118 --firingIterator.iterator; 119 } 120 121 return true; 122 } 123 124 bool EventTarget::setAttributeEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener) 125 { 126 clearAttributeEventListener(eventType); 127 if (!listener) 128 return false; 129 return addEventListener(eventType, listener, false); 130 } 131 132 EventListener* EventTarget::getAttributeEventListener(const AtomicString& eventType) 133 { 134 const EventListenerVector& entry = getEventListeners(eventType); 135 for (size_t i = 0; i < entry.size(); ++i) { 136 EventListener* listener = entry[i].listener.get(); 137 if (listener->isAttribute() && listener->belongsToTheCurrentWorld()) 138 return listener; 139 } 140 return 0; 141 } 142 143 bool EventTarget::clearAttributeEventListener(const AtomicString& eventType) 144 { 145 EventListener* listener = getAttributeEventListener(eventType); 146 if (!listener) 147 return false; 148 return removeEventListener(eventType, listener, false); 149 } 150 151 bool EventTarget::dispatchEvent(PassRefPtrWillBeRawPtr<Event> event, ExceptionState& exceptionState) 152 { 153 if (!event) { 154 exceptionState.throwDOMException(InvalidStateError, "The event provided is null."); 155 return false; 156 } 157 if (event->type().isEmpty()) { 158 exceptionState.throwDOMException(InvalidStateError, "The event provided is uninitialized."); 159 return false; 160 } 161 if (event->isBeingDispatched()) { 162 exceptionState.throwDOMException(InvalidStateError, "The event is already being dispatched."); 163 return false; 164 } 165 166 if (!executionContext()) 167 return false; 168 169 return dispatchEvent(event); 170 } 171 172 bool EventTarget::dispatchEvent(PassRefPtrWillBeRawPtr<Event> event) 173 { 174 event->setTarget(this); 175 event->setCurrentTarget(this); 176 event->setEventPhase(Event::AT_TARGET); 177 bool defaultPrevented = fireEventListeners(event.get()); 178 event->setEventPhase(0); 179 return defaultPrevented; 180 } 181 182 void EventTarget::uncaughtExceptionInEventHandler() 183 { 184 } 185 186 static const AtomicString& legacyType(const Event* event) 187 { 188 if (event->type() == EventTypeNames::transitionend) 189 return EventTypeNames::webkitTransitionEnd; 190 191 if (event->type() == EventTypeNames::animationstart) 192 return EventTypeNames::webkitAnimationStart; 193 194 if (event->type() == EventTypeNames::animationend) 195 return EventTypeNames::webkitAnimationEnd; 196 197 if (event->type() == EventTypeNames::animationiteration) 198 return EventTypeNames::webkitAnimationIteration; 199 200 if (event->type() == EventTypeNames::wheel) 201 return EventTypeNames::mousewheel; 202 203 return emptyAtom; 204 } 205 206 void EventTarget::countLegacyEvents(const AtomicString& legacyTypeName, EventListenerVector* listenersVector, EventListenerVector* legacyListenersVector) 207 { 208 UseCounter::Feature unprefixedFeature; 209 UseCounter::Feature prefixedFeature; 210 UseCounter::Feature prefixedAndUnprefixedFeature; 211 bool shouldCount = false; 212 213 if (legacyTypeName == EventTypeNames::webkitTransitionEnd) { 214 prefixedFeature = UseCounter::PrefixedTransitionEndEvent; 215 unprefixedFeature = UseCounter::UnprefixedTransitionEndEvent; 216 prefixedAndUnprefixedFeature = UseCounter::PrefixedAndUnprefixedTransitionEndEvent; 217 shouldCount = true; 218 } else if (legacyTypeName == EventTypeNames::webkitAnimationEnd) { 219 prefixedFeature = UseCounter::PrefixedAnimationEndEvent; 220 unprefixedFeature = UseCounter::UnprefixedAnimationEndEvent; 221 prefixedAndUnprefixedFeature = UseCounter::PrefixedAndUnprefixedAnimationEndEvent; 222 shouldCount = true; 223 } else if (legacyTypeName == EventTypeNames::webkitAnimationStart) { 224 prefixedFeature = UseCounter::PrefixedAnimationStartEvent; 225 unprefixedFeature = UseCounter::UnprefixedAnimationStartEvent; 226 prefixedAndUnprefixedFeature = UseCounter::PrefixedAndUnprefixedAnimationStartEvent; 227 shouldCount = true; 228 } else if (legacyTypeName == EventTypeNames::webkitAnimationIteration) { 229 prefixedFeature = UseCounter::PrefixedAnimationIterationEvent; 230 unprefixedFeature = UseCounter::UnprefixedAnimationIterationEvent; 231 prefixedAndUnprefixedFeature = UseCounter::PrefixedAndUnprefixedAnimationIterationEvent; 232 shouldCount = true; 233 } 234 235 if (shouldCount) { 236 if (LocalDOMWindow* executingWindow = this->executingWindow()) { 237 if (legacyListenersVector) { 238 if (listenersVector) 239 UseCounter::count(executingWindow->document(), prefixedAndUnprefixedFeature); 240 else 241 UseCounter::count(executingWindow->document(), prefixedFeature); 242 } else if (listenersVector) { 243 UseCounter::count(executingWindow->document(), unprefixedFeature); 244 } 245 } 246 } 247 } 248 249 bool EventTarget::fireEventListeners(Event* event) 250 { 251 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden()); 252 ASSERT(event && !event->type().isEmpty()); 253 254 EventTargetData* d = eventTargetData(); 255 if (!d) 256 return true; 257 258 EventListenerVector* legacyListenersVector = 0; 259 AtomicString legacyTypeName = legacyType(event); 260 if (!legacyTypeName.isEmpty()) 261 legacyListenersVector = d->eventListenerMap.find(legacyTypeName); 262 263 EventListenerVector* listenersVector = d->eventListenerMap.find(event->type()); 264 if (!RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled() && (event->type() == EventTypeNames::animationiteration || event->type() == EventTypeNames::animationend 265 || event->type() == EventTypeNames::animationstart) 266 // Some code out-there uses custom events to dispatch unprefixed animation events manually, 267 // we can safely remove all this block when cssAnimationUnprefixedEnabled is always on, this 268 // is really a special case. DO NOT ADD MORE EVENTS HERE. 269 && event->interfaceName() != EventNames::CustomEvent) 270 listenersVector = 0; 271 272 if (listenersVector) { 273 fireEventListeners(event, d, *listenersVector); 274 } else if (legacyListenersVector) { 275 AtomicString unprefixedTypeName = event->type(); 276 event->setType(legacyTypeName); 277 fireEventListeners(event, d, *legacyListenersVector); 278 event->setType(unprefixedTypeName); 279 } 280 281 Editor::countEvent(executionContext(), event); 282 countLegacyEvents(legacyTypeName, listenersVector, legacyListenersVector); 283 return !event->defaultPrevented(); 284 } 285 286 void EventTarget::fireEventListeners(Event* event, EventTargetData* d, EventListenerVector& entry) 287 { 288 RefPtrWillBeRawPtr<EventTarget> protect(this); 289 290 // Fire all listeners registered for this event. Don't fire listeners removed 291 // during event dispatch. Also, don't fire event listeners added during event 292 // dispatch. Conveniently, all new event listeners will be added after or at 293 // index |size|, so iterating up to (but not including) |size| naturally excludes 294 // new event listeners. 295 296 if (event->type() == EventTypeNames::beforeunload) { 297 if (LocalDOMWindow* executingWindow = this->executingWindow()) { 298 if (executingWindow->top()) 299 UseCounter::count(executingWindow->document(), UseCounter::SubFrameBeforeUnloadFired); 300 UseCounter::count(executingWindow->document(), UseCounter::DocumentBeforeUnloadFired); 301 } 302 } else if (event->type() == EventTypeNames::unload) { 303 if (LocalDOMWindow* executingWindow = this->executingWindow()) 304 UseCounter::count(executingWindow->document(), UseCounter::DocumentUnloadFired); 305 } else if (event->type() == EventTypeNames::DOMFocusIn || event->type() == EventTypeNames::DOMFocusOut) { 306 if (LocalDOMWindow* executingWindow = this->executingWindow()) 307 UseCounter::count(executingWindow->document(), UseCounter::DOMFocusInOutEvent); 308 } else if (event->type() == EventTypeNames::focusin || event->type() == EventTypeNames::focusout) { 309 if (LocalDOMWindow* executingWindow = this->executingWindow()) 310 UseCounter::count(executingWindow->document(), UseCounter::FocusInOutEvent); 311 } 312 313 size_t i = 0; 314 size_t size = entry.size(); 315 if (!d->firingEventIterators) 316 d->firingEventIterators = adoptPtr(new FiringEventIteratorVector); 317 d->firingEventIterators->append(FiringEventIterator(event->type(), i, size)); 318 for ( ; i < size; ++i) { 319 RegisteredEventListener& registeredListener = entry[i]; 320 if (event->eventPhase() == Event::CAPTURING_PHASE && !registeredListener.useCapture) 321 continue; 322 if (event->eventPhase() == Event::BUBBLING_PHASE && registeredListener.useCapture) 323 continue; 324 325 // If stopImmediatePropagation has been called, we just break out immediately, without 326 // handling any more events on this target. 327 if (event->immediatePropagationStopped()) 328 break; 329 330 ExecutionContext* context = executionContext(); 331 if (!context) 332 break; 333 334 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willHandleEvent(this, event, registeredListener.listener.get(), registeredListener.useCapture); 335 // To match Mozilla, the AT_TARGET phase fires both capturing and bubbling 336 // event listeners, even though that violates some versions of the DOM spec. 337 registeredListener.listener->handleEvent(context, event); 338 InspectorInstrumentation::didHandleEvent(cookie); 339 } 340 d->firingEventIterators->removeLast(); 341 } 342 343 const EventListenerVector& EventTarget::getEventListeners(const AtomicString& eventType) 344 { 345 DEFINE_STATIC_LOCAL(EventListenerVector, emptyVector, ()); 346 347 EventTargetData* d = eventTargetData(); 348 if (!d) 349 return emptyVector; 350 351 EventListenerVector* listenerVector = d->eventListenerMap.find(eventType); 352 if (!listenerVector) 353 return emptyVector; 354 355 return *listenerVector; 356 } 357 358 Vector<AtomicString> EventTarget::eventTypes() 359 { 360 EventTargetData* d = eventTargetData(); 361 return d ? d->eventListenerMap.eventTypes() : Vector<AtomicString>(); 362 } 363 364 void EventTarget::removeAllEventListeners() 365 { 366 EventTargetData* d = eventTargetData(); 367 if (!d) 368 return; 369 d->eventListenerMap.clear(); 370 371 // Notify firing events planning to invoke the listener at 'index' that 372 // they have one less listener to invoke. 373 if (d->firingEventIterators) { 374 for (size_t i = 0; i < d->firingEventIterators->size(); ++i) { 375 d->firingEventIterators->at(i).iterator = 0; 376 d->firingEventIterators->at(i).end = 0; 377 } 378 } 379 } 380 381 } // namespace WebCore 382