| OLD | NEW |
| (Empty) |
| 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 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 "bindings/v8/ScriptController.h" | |
| 39 #include "core/events/Event.h" | |
| 40 #include "core/dom/ExceptionCode.h" | |
| 41 #include "core/inspector/InspectorInstrumentation.h" | |
| 42 #include "core/page/DOMWindow.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 (ScriptExecutionContext* context = scriptExecutionContext()) | |
| 80 return context->executingWindow(); | |
| 81 return 0; | |
| 82 } | |
| 83 | |
| 84 bool EventTarget::addEventListener(const AtomicString& eventType, PassRefPtr<Eve
ntListener> listener, bool useCapture) | |
| 85 { | |
| 86 EventTargetData* d = ensureEventTargetData(); | |
| 87 return d->eventListenerMap.add(eventType, listener, useCapture); | |
| 88 } | |
| 89 | |
| 90 bool EventTarget::removeEventListener(const AtomicString& eventType, EventListen
er* listener, bool useCapture) | |
| 91 { | |
| 92 EventTargetData* d = eventTargetData(); | |
| 93 if (!d) | |
| 94 return false; | |
| 95 | |
| 96 size_t indexOfRemovedListener; | |
| 97 | |
| 98 if (!d->eventListenerMap.remove(eventType, listener, useCapture, indexOfRemo
vedListener)) | |
| 99 return false; | |
| 100 | |
| 101 // Notify firing events planning to invoke the listener at 'index' that | |
| 102 // they have one less listener to invoke. | |
| 103 if (!d->firingEventIterators) | |
| 104 return true; | |
| 105 for (size_t i = 0; i < d->firingEventIterators->size(); ++i) { | |
| 106 FiringEventIterator& firingIterator = d->firingEventIterators->at(i); | |
| 107 if (eventType != firingIterator.eventType) | |
| 108 continue; | |
| 109 | |
| 110 if (indexOfRemovedListener >= firingIterator.end) | |
| 111 continue; | |
| 112 | |
| 113 --firingIterator.end; | |
| 114 if (indexOfRemovedListener <= firingIterator.iterator) | |
| 115 --firingIterator.iterator; | |
| 116 } | |
| 117 | |
| 118 return true; | |
| 119 } | |
| 120 | |
| 121 bool EventTarget::setAttributeEventListener(const AtomicString& eventType, PassR
efPtr<EventListener> listener, DOMWrapperWorld* isolatedWorld) | |
| 122 { | |
| 123 clearAttributeEventListener(eventType, isolatedWorld); | |
| 124 if (!listener) | |
| 125 return false; | |
| 126 return addEventListener(eventType, listener, false); | |
| 127 } | |
| 128 | |
| 129 EventListener* EventTarget::getAttributeEventListener(const AtomicString& eventT
ype, DOMWrapperWorld* isolatedWorld) | |
| 130 { | |
| 131 const EventListenerVector& entry = getEventListeners(eventType); | |
| 132 for (size_t i = 0; i < entry.size(); ++i) { | |
| 133 EventListener* listener = entry[i].listener.get(); | |
| 134 if (listener->isAttribute()) { | |
| 135 DOMWrapperWorld* listenerWorld = listener->world(); | |
| 136 // Worker listener | |
| 137 if (!listenerWorld) { | |
| 138 ASSERT(!isolatedWorld); | |
| 139 return listener; | |
| 140 } | |
| 141 if (listenerWorld->isMainWorld() && !isolatedWorld) | |
| 142 return listener; | |
| 143 if (listenerWorld == isolatedWorld) | |
| 144 return listener; | |
| 145 } | |
| 146 } | |
| 147 return 0; | |
| 148 } | |
| 149 | |
| 150 bool EventTarget::clearAttributeEventListener(const AtomicString& eventType, DOM
WrapperWorld* isolatedWorld) | |
| 151 { | |
| 152 EventListener* listener = getAttributeEventListener(eventType, isolatedWorld
); | |
| 153 if (!listener) | |
| 154 return false; | |
| 155 return removeEventListener(eventType, listener, false); | |
| 156 } | |
| 157 | |
| 158 bool EventTarget::dispatchEvent(PassRefPtr<Event> event, ExceptionState& es) | |
| 159 { | |
| 160 if (!event || event->type().isEmpty() || event->isBeingDispatched()) { | |
| 161 es.throwDOMException(InvalidStateError); | |
| 162 return false; | |
| 163 } | |
| 164 | |
| 165 if (!scriptExecutionContext()) | |
| 166 return false; | |
| 167 | |
| 168 return dispatchEvent(event); | |
| 169 } | |
| 170 | |
| 171 bool EventTarget::dispatchEvent(PassRefPtr<Event> event) | |
| 172 { | |
| 173 event->setTarget(this); | |
| 174 event->setCurrentTarget(this); | |
| 175 event->setEventPhase(Event::AT_TARGET); | |
| 176 bool defaultPrevented = fireEventListeners(event.get()); | |
| 177 event->setEventPhase(0); | |
| 178 return defaultPrevented; | |
| 179 } | |
| 180 | |
| 181 void EventTarget::uncaughtExceptionInEventHandler() | |
| 182 { | |
| 183 } | |
| 184 | |
| 185 static AtomicString legacyType(const Event* event) | |
| 186 { | |
| 187 if (event->type() == eventNames().transitionendEvent) | |
| 188 return eventNames().webkitTransitionEndEvent; | |
| 189 | |
| 190 if (event->type() == eventNames().animationstartEvent) | |
| 191 return eventNames().webkitAnimationStartEvent; | |
| 192 | |
| 193 if (event->type() == eventNames().animationendEvent) | |
| 194 return eventNames().webkitAnimationEndEvent; | |
| 195 | |
| 196 if (event->type() == eventNames().animationiterationEvent) | |
| 197 return eventNames().webkitAnimationIterationEvent; | |
| 198 | |
| 199 if (event->type() == eventNames().wheelEvent) | |
| 200 return eventNames().mousewheelEvent; | |
| 201 | |
| 202 return emptyString(); | |
| 203 } | |
| 204 | |
| 205 void EventTarget::countLegacyEvents(const AtomicString& legacyTypeName, EventLis
tenerVector* listenersVector, EventListenerVector* legacyListenersVector) | |
| 206 { | |
| 207 UseCounter::Feature unprefixedFeature; | |
| 208 UseCounter::Feature prefixedFeature; | |
| 209 UseCounter::Feature prefixedAndUnprefixedFeature; | |
| 210 bool shouldCount = false; | |
| 211 | |
| 212 if (legacyTypeName == eventNames().webkitTransitionEndEvent) { | |
| 213 prefixedFeature = UseCounter::PrefixedTransitionEndEvent; | |
| 214 unprefixedFeature = UseCounter::UnprefixedTransitionEndEvent; | |
| 215 prefixedAndUnprefixedFeature = UseCounter::PrefixedAndUnprefixedTransiti
onEndEvent; | |
| 216 shouldCount = true; | |
| 217 } else if (legacyTypeName == eventNames().webkitAnimationEndEvent) { | |
| 218 prefixedFeature = UseCounter::PrefixedAnimationEndEvent; | |
| 219 unprefixedFeature = UseCounter::UnprefixedAnimationEndEvent; | |
| 220 prefixedAndUnprefixedFeature = UseCounter::PrefixedAndUnprefixedAnimatio
nEndEvent; | |
| 221 shouldCount = true; | |
| 222 } else if (legacyTypeName == eventNames().webkitAnimationStartEvent) { | |
| 223 prefixedFeature = UseCounter::PrefixedAnimationStartEvent; | |
| 224 unprefixedFeature = UseCounter::UnprefixedAnimationStartEvent; | |
| 225 prefixedAndUnprefixedFeature = UseCounter::PrefixedAndUnprefixedAnimatio
nStartEvent; | |
| 226 shouldCount = true; | |
| 227 } else if (legacyTypeName == eventNames().webkitAnimationIterationEvent) { | |
| 228 prefixedFeature = UseCounter::PrefixedAnimationIterationEvent; | |
| 229 unprefixedFeature = UseCounter::UnprefixedAnimationIterationEvent; | |
| 230 prefixedAndUnprefixedFeature = UseCounter::PrefixedAndUnprefixedAnimatio
nIterationEvent; | |
| 231 shouldCount = true; | |
| 232 } | |
| 233 | |
| 234 if (shouldCount) { | |
| 235 if (DOMWindow* executingWindow = this->executingWindow()) { | |
| 236 if (legacyListenersVector) { | |
| 237 if (listenersVector) | |
| 238 UseCounter::count(executingWindow, prefixedAndUnprefixedFeat
ure); | |
| 239 else | |
| 240 UseCounter::count(executingWindow, prefixedFeature); | |
| 241 } else if (listenersVector) { | |
| 242 UseCounter::count(executingWindow, unprefixedFeature); | |
| 243 } | |
| 244 } | |
| 245 } | |
| 246 } | |
| 247 | |
| 248 bool EventTarget::fireEventListeners(Event* event) | |
| 249 { | |
| 250 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden()); | |
| 251 ASSERT(event && !event->type().isEmpty()); | |
| 252 | |
| 253 EventTargetData* d = eventTargetData(); | |
| 254 if (!d) | |
| 255 return true; | |
| 256 | |
| 257 EventListenerVector* legacyListenersVector = 0; | |
| 258 AtomicString legacyTypeName = legacyType(event); | |
| 259 if (!legacyTypeName.isEmpty()) | |
| 260 legacyListenersVector = d->eventListenerMap.find(legacyTypeName); | |
| 261 | |
| 262 EventListenerVector* listenersVector = d->eventListenerMap.find(event->type(
)); | |
| 263 if (!RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled() && (event->type
() == eventNames().animationiterationEvent || event->type() == eventNames().anim
ationendEvent | |
| 264 || event->type() == eventNames().animationstartEvent)) | |
| 265 listenersVector = 0; | |
| 266 | |
| 267 if (listenersVector) { | |
| 268 fireEventListeners(event, d, *listenersVector); | |
| 269 } else if (legacyListenersVector) { | |
| 270 AtomicString unprefixedTypeName = event->type(); | |
| 271 event->setType(legacyTypeName); | |
| 272 fireEventListeners(event, d, *legacyListenersVector); | |
| 273 event->setType(unprefixedTypeName); | |
| 274 } | |
| 275 | |
| 276 countLegacyEvents(legacyTypeName, listenersVector, legacyListenersVector); | |
| 277 return !event->defaultPrevented(); | |
| 278 } | |
| 279 | |
| 280 void EventTarget::fireEventListeners(Event* event, EventTargetData* d, EventList
enerVector& entry) | |
| 281 { | |
| 282 RefPtr<EventTarget> protect = this; | |
| 283 | |
| 284 // Fire all listeners registered for this event. Don't fire listeners remove
d | |
| 285 // during event dispatch. Also, don't fire event listeners added during even
t | |
| 286 // dispatch. Conveniently, all new event listeners will be added after or at | |
| 287 // index |size|, so iterating up to (but not including) |size| naturally exc
ludes | |
| 288 // new event listeners. | |
| 289 | |
| 290 if (event->type() == eventNames().beforeunloadEvent) { | |
| 291 if (DOMWindow* executingWindow = this->executingWindow()) { | |
| 292 if (executingWindow->top()) | |
| 293 UseCounter::count(executingWindow, UseCounter::SubFrameBeforeUnl
oadFired); | |
| 294 } | |
| 295 } | |
| 296 | |
| 297 bool userEventWasHandled = false; | |
| 298 size_t i = 0; | |
| 299 size_t size = entry.size(); | |
| 300 if (!d->firingEventIterators) | |
| 301 d->firingEventIterators = adoptPtr(new FiringEventIteratorVector); | |
| 302 d->firingEventIterators->append(FiringEventIterator(event->type(), i, size))
; | |
| 303 for ( ; i < size; ++i) { | |
| 304 RegisteredEventListener& registeredListener = entry[i]; | |
| 305 if (event->eventPhase() == Event::CAPTURING_PHASE && !registeredListener
.useCapture) | |
| 306 continue; | |
| 307 if (event->eventPhase() == Event::BUBBLING_PHASE && registeredListener.u
seCapture) | |
| 308 continue; | |
| 309 | |
| 310 // If stopImmediatePropagation has been called, we just break out immedi
ately, without | |
| 311 // handling any more events on this target. | |
| 312 if (event->immediatePropagationStopped()) | |
| 313 break; | |
| 314 | |
| 315 ScriptExecutionContext* context = scriptExecutionContext(); | |
| 316 if (!context) | |
| 317 break; | |
| 318 | |
| 319 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willHa
ndleEvent(context, event); | |
| 320 // To match Mozilla, the AT_TARGET phase fires both capturing and bubbli
ng | |
| 321 // event listeners, even though that violates some versions of the DOM s
pec. | |
| 322 registeredListener.listener->handleEvent(context, event); | |
| 323 if (!userEventWasHandled && ScriptController::processingUserGesture()) | |
| 324 userEventWasHandled = true; | |
| 325 InspectorInstrumentation::didHandleEvent(cookie); | |
| 326 } | |
| 327 d->firingEventIterators->removeLast(); | |
| 328 if (userEventWasHandled) { | |
| 329 if (ScriptExecutionContext* context = scriptExecutionContext()) | |
| 330 context->userEventWasHandled(); | |
| 331 } | |
| 332 } | |
| 333 | |
| 334 const EventListenerVector& EventTarget::getEventListeners(const AtomicString& ev
entType) | |
| 335 { | |
| 336 DEFINE_STATIC_LOCAL(EventListenerVector, emptyVector, ()); | |
| 337 | |
| 338 EventTargetData* d = eventTargetData(); | |
| 339 if (!d) | |
| 340 return emptyVector; | |
| 341 | |
| 342 EventListenerVector* listenerVector = d->eventListenerMap.find(eventType); | |
| 343 if (!listenerVector) | |
| 344 return emptyVector; | |
| 345 | |
| 346 return *listenerVector; | |
| 347 } | |
| 348 | |
| 349 void EventTarget::removeAllEventListeners() | |
| 350 { | |
| 351 EventTargetData* d = eventTargetData(); | |
| 352 if (!d) | |
| 353 return; | |
| 354 d->eventListenerMap.clear(); | |
| 355 | |
| 356 // Notify firing events planning to invoke the listener at 'index' that | |
| 357 // they have one less listener to invoke. | |
| 358 if (d->firingEventIterators) { | |
| 359 for (size_t i = 0; i < d->firingEventIterators->size(); ++i) { | |
| 360 d->firingEventIterators->at(i).iterator = 0; | |
| 361 d->firingEventIterators->at(i).end = 0; | |
| 362 } | |
| 363 } | |
| 364 } | |
| 365 | |
| 366 } // namespace WebCore | |
| OLD | NEW |