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/dom/EventTarget.h" 34 35 #include "bindings/v8/DOMWrapperWorld.h" 36 #include "bindings/v8/ExceptionState.h" 37 #include "bindings/v8/ScriptController.h" 38 #include "core/dom/Event.h" 39 #include "core/dom/ExceptionCode.h" 40 #include "core/inspector/InspectorInstrumentation.h" 41 #include "core/page/DOMWindow.h" 42 #include "wtf/StdLibExtras.h" 43 #include "wtf/Vector.h" 44 45 using namespace WTF; 46 47 namespace WebCore { 48 49 EventTargetData::EventTargetData() 50 { 51 } 52 53 EventTargetData::~EventTargetData() 54 { 55 } 56 57 EventTarget::~EventTarget() 58 { 59 } 60 61 Node* EventTarget::toNode() 62 { 63 return 0; 64 } 65 66 DOMWindow* EventTarget::toDOMWindow() 67 { 68 return 0; 69 } 70 71 inline DOMWindow* EventTarget::executingWindow() 72 { 73 if (ScriptExecutionContext* context = scriptExecutionContext()) 74 return context->executingWindow(); 75 return 0; 76 } 77 78 bool EventTarget::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture) 79 { 80 EventTargetData* d = ensureEventTargetData(); 81 return d->eventListenerMap.add(eventType, listener, useCapture); 82 } 83 84 bool EventTarget::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture) 85 { 86 EventTargetData* d = eventTargetData(); 87 if (!d) 88 return false; 89 90 size_t indexOfRemovedListener; 91 92 if (!d->eventListenerMap.remove(eventType, listener, useCapture, indexOfRemovedListener)) 93 return false; 94 95 // Notify firing events planning to invoke the listener at 'index' that 96 // they have one less listener to invoke. 97 if (!d->firingEventIterators) 98 return true; 99 for (size_t i = 0; i < d->firingEventIterators->size(); ++i) { 100 FiringEventIterator& firingIterator = d->firingEventIterators->at(i); 101 if (eventType != firingIterator.eventType) 102 continue; 103 104 if (indexOfRemovedListener >= firingIterator.end) 105 continue; 106 107 --firingIterator.end; 108 if (indexOfRemovedListener <= firingIterator.iterator) 109 --firingIterator.iterator; 110 } 111 112 return true; 113 } 114 115 bool EventTarget::setAttributeEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, DOMWrapperWorld* isolatedWorld) 116 { 117 clearAttributeEventListener(eventType, isolatedWorld); 118 if (!listener) 119 return false; 120 return addEventListener(eventType, listener, false); 121 } 122 123 EventListener* EventTarget::getAttributeEventListener(const AtomicString& eventType, DOMWrapperWorld* isolatedWorld) 124 { 125 const EventListenerVector& entry = getEventListeners(eventType); 126 for (size_t i = 0; i < entry.size(); ++i) { 127 EventListener* listener = entry[i].listener.get(); 128 if (listener->isAttribute()) { 129 DOMWrapperWorld* listenerWorld = listener->world(); 130 // Worker listener 131 if (!listenerWorld) { 132 ASSERT(!isolatedWorld); 133 return listener; 134 } 135 if (listenerWorld->isMainWorld() && !isolatedWorld) 136 return listener; 137 if (listenerWorld == isolatedWorld) 138 return listener; 139 } 140 } 141 return 0; 142 } 143 144 bool EventTarget::clearAttributeEventListener(const AtomicString& eventType, DOMWrapperWorld* isolatedWorld) 145 { 146 EventListener* listener = getAttributeEventListener(eventType, isolatedWorld); 147 if (!listener) 148 return false; 149 return removeEventListener(eventType, listener, false); 150 } 151 152 bool EventTarget::dispatchEvent(PassRefPtr<Event> event, ExceptionState& es) 153 { 154 if (!event || event->type().isEmpty() || event->isBeingDispatched()) { 155 es.throwDOMException(InvalidStateError); 156 return false; 157 } 158 159 if (!scriptExecutionContext()) 160 return false; 161 162 return dispatchEvent(event); 163 } 164 165 bool EventTarget::dispatchEvent(PassRefPtr<Event> event) 166 { 167 event->setTarget(this); 168 event->setCurrentTarget(this); 169 event->setEventPhase(Event::AT_TARGET); 170 bool defaultPrevented = fireEventListeners(event.get()); 171 event->setEventPhase(0); 172 return defaultPrevented; 173 } 174 175 void EventTarget::uncaughtExceptionInEventHandler() 176 { 177 } 178 179 static AtomicString prefixedType(const Event* event) 180 { 181 if (event->type() == eventNames().transitionendEvent) 182 return eventNames().webkitTransitionEndEvent; 183 184 return emptyString(); 185 } 186 187 bool EventTarget::fireEventListeners(Event* event) 188 { 189 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden()); 190 ASSERT(event && !event->type().isEmpty()); 191 192 EventTargetData* d = eventTargetData(); 193 if (!d) 194 return true; 195 196 EventListenerVector* listenerPrefixedVector = 0; 197 AtomicString prefixedTypeName = prefixedType(event); 198 if (!prefixedTypeName.isEmpty()) 199 listenerPrefixedVector = d->eventListenerMap.find(prefixedTypeName); 200 201 EventListenerVector* listenerUnprefixedVector = d->eventListenerMap.find(event->type()); 202 203 if (listenerUnprefixedVector) 204 fireEventListeners(event, d, *listenerUnprefixedVector); 205 else if (listenerPrefixedVector) { 206 AtomicString unprefixedTypeName = event->type(); 207 event->setType(prefixedTypeName); 208 fireEventListeners(event, d, *listenerPrefixedVector); 209 event->setType(unprefixedTypeName); 210 } 211 212 if (!prefixedTypeName.isEmpty()) { 213 if (DOMWindow* executingWindow = this->executingWindow()) { 214 if (listenerPrefixedVector) { 215 if (listenerUnprefixedVector) 216 UseCounter::count(executingWindow, UseCounter::PrefixedAndUnprefixedTransitionEndEvent); 217 else 218 UseCounter::count(executingWindow, UseCounter::PrefixedTransitionEndEvent); 219 } else if (listenerUnprefixedVector) { 220 UseCounter::count(executingWindow, UseCounter::UnprefixedTransitionEndEvent); 221 } 222 } 223 } 224 225 return !event->defaultPrevented(); 226 } 227 228 void EventTarget::fireEventListeners(Event* event, EventTargetData* d, EventListenerVector& entry) 229 { 230 RefPtr<EventTarget> protect = this; 231 232 // Fire all listeners registered for this event. Don't fire listeners removed 233 // during event dispatch. Also, don't fire event listeners added during event 234 // dispatch. Conveniently, all new event listeners will be added after or at 235 // index |size|, so iterating up to (but not including) |size| naturally excludes 236 // new event listeners. 237 238 if (event->type() == eventNames().beforeunloadEvent) { 239 if (DOMWindow* executingWindow = this->executingWindow()) { 240 if (executingWindow->top()) 241 UseCounter::count(executingWindow, UseCounter::SubFrameBeforeUnloadFired); 242 } 243 } 244 245 bool userEventWasHandled = false; 246 size_t i = 0; 247 size_t size = entry.size(); 248 if (!d->firingEventIterators) 249 d->firingEventIterators = adoptPtr(new FiringEventIteratorVector); 250 d->firingEventIterators->append(FiringEventIterator(event->type(), i, size)); 251 for ( ; i < size; ++i) { 252 RegisteredEventListener& registeredListener = entry[i]; 253 if (event->eventPhase() == Event::CAPTURING_PHASE && !registeredListener.useCapture) 254 continue; 255 if (event->eventPhase() == Event::BUBBLING_PHASE && registeredListener.useCapture) 256 continue; 257 258 // If stopImmediatePropagation has been called, we just break out immediately, without 259 // handling any more events on this target. 260 if (event->immediatePropagationStopped()) 261 break; 262 263 ScriptExecutionContext* context = scriptExecutionContext(); 264 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willHandleEvent(context, event); 265 // To match Mozilla, the AT_TARGET phase fires both capturing and bubbling 266 // event listeners, even though that violates some versions of the DOM spec. 267 registeredListener.listener->handleEvent(context, event); 268 if (!userEventWasHandled && ScriptController::processingUserGesture()) 269 userEventWasHandled = true; 270 InspectorInstrumentation::didHandleEvent(cookie); 271 } 272 d->firingEventIterators->removeLast(); 273 if (userEventWasHandled) { 274 if (ScriptExecutionContext* context = scriptExecutionContext()) 275 context->userEventWasHandled(); 276 } 277 } 278 279 const EventListenerVector& EventTarget::getEventListeners(const AtomicString& eventType) 280 { 281 DEFINE_STATIC_LOCAL(EventListenerVector, emptyVector, ()); 282 283 EventTargetData* d = eventTargetData(); 284 if (!d) 285 return emptyVector; 286 287 EventListenerVector* listenerVector = d->eventListenerMap.find(eventType); 288 if (!listenerVector) 289 return emptyVector; 290 291 return *listenerVector; 292 } 293 294 void EventTarget::removeAllEventListeners() 295 { 296 EventTargetData* d = eventTargetData(); 297 if (!d) 298 return; 299 d->eventListenerMap.clear(); 300 301 // Notify firing events planning to invoke the listener at 'index' that 302 // they have one less listener to invoke. 303 if (d->firingEventIterators) { 304 for (size_t i = 0; i < d->firingEventIterators->size(); ++i) { 305 d->firingEventIterators->at(i).iterator = 0; 306 d->firingEventIterators->at(i).end = 0; 307 } 308 } 309 } 310 311 } // namespace WebCore 312