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