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