summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/dom/EventTarget.cpp
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-06 11:45:16 +0100
committerSteve Block <steveblock@google.com>2011-05-12 13:44:10 +0100
commitcad810f21b803229eb11403f9209855525a25d57 (patch)
tree29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/dom/EventTarget.cpp
parent121b0cf4517156d0ac5111caf9830c51b69bae8f (diff)
downloadexternal_webkit-cad810f21b803229eb11403f9209855525a25d57.zip
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/dom/EventTarget.cpp')
-rw-r--r--Source/WebCore/dom/EventTarget.cpp376
1 files changed, 376 insertions, 0 deletions
diff --git a/Source/WebCore/dom/EventTarget.cpp b/Source/WebCore/dom/EventTarget.cpp
new file mode 100644
index 0000000..5f2f8a7
--- /dev/null
+++ b/Source/WebCore/dom/EventTarget.cpp
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
+ * (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "config.h"
+#include "EventTarget.h"
+
+#include "Event.h"
+#include "EventException.h"
+#include <wtf/StdLibExtras.h>
+
+using namespace WTF;
+
+namespace WebCore {
+
+#ifndef NDEBUG
+static int gEventDispatchForbidden = 0;
+
+void forbidEventDispatch()
+{
+ if (!isMainThread())
+ return;
+ ++gEventDispatchForbidden;
+}
+
+void allowEventDispatch()
+{
+ if (!isMainThread())
+ return;
+ if (gEventDispatchForbidden > 0)
+ --gEventDispatchForbidden;
+}
+
+bool eventDispatchForbidden()
+{
+ if (!isMainThread())
+ return false;
+ return gEventDispatchForbidden > 0;
+}
+#endif // NDEBUG
+
+EventTargetData::EventTargetData()
+{
+}
+
+EventTargetData::~EventTargetData()
+{
+ deleteAllValues(eventListenerMap);
+}
+
+EventTarget::~EventTarget()
+{
+}
+
+EventSource* EventTarget::toEventSource()
+{
+ return 0;
+}
+
+Node* EventTarget::toNode()
+{
+ return 0;
+}
+
+DOMWindow* EventTarget::toDOMWindow()
+{
+ return 0;
+}
+
+XMLHttpRequest* EventTarget::toXMLHttpRequest()
+{
+ return 0;
+}
+
+XMLHttpRequestUpload* EventTarget::toXMLHttpRequestUpload()
+{
+ return 0;
+}
+
+#if ENABLE(OFFLINE_WEB_APPLICATIONS)
+DOMApplicationCache* EventTarget::toDOMApplicationCache()
+{
+ return 0;
+}
+#endif
+
+#if ENABLE(SVG)
+SVGElementInstance* EventTarget::toSVGElementInstance()
+{
+ return 0;
+}
+#endif
+
+#if ENABLE(WEB_AUDIO)
+JavaScriptAudioNode* EventTarget::toJavaScriptAudioNode()
+{
+ return 0;
+}
+#endif
+
+#if ENABLE(WEB_SOCKETS)
+WebSocket* EventTarget::toWebSocket()
+{
+ return 0;
+}
+#endif
+
+MessagePort* EventTarget::toMessagePort()
+{
+ return 0;
+}
+
+#if ENABLE(WORKERS)
+Worker* EventTarget::toWorker()
+{
+ return 0;
+}
+
+DedicatedWorkerContext* EventTarget::toDedicatedWorkerContext()
+{
+ return 0;
+}
+#endif
+
+#if ENABLE(SHARED_WORKERS)
+SharedWorker* EventTarget::toSharedWorker()
+{
+ return 0;
+}
+SharedWorkerContext* EventTarget::toSharedWorkerContext()
+{
+ return 0;
+}
+#endif
+
+#if ENABLE(NOTIFICATIONS)
+Notification* EventTarget::toNotification()
+{
+ return 0;
+}
+#endif
+
+#if ENABLE(BLOB)
+FileReader* EventTarget::toFileReader()
+{
+ return 0;
+}
+#endif
+#if ENABLE(FILE_SYSTEM)
+FileWriter* EventTarget::toFileWriter()
+{
+ return 0;
+}
+#endif
+
+#if ENABLE(INDEXED_DATABASE)
+IDBRequest* EventTarget::toIDBRequest()
+{
+ return 0;
+}
+IDBTransaction* EventTarget::toIDBTransaction()
+{
+ return 0;
+}
+#endif
+
+bool EventTarget::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
+{
+ EventTargetData* d = ensureEventTargetData();
+
+ pair<EventListenerMap::iterator, bool> result = d->eventListenerMap.add(eventType, 0);
+ EventListenerVector*& entry = result.first->second;
+ const bool isNewEntry = result.second;
+ if (isNewEntry)
+ entry = new EventListenerVector();
+
+ RegisteredEventListener registeredListener(listener, useCapture);
+ if (!isNewEntry) {
+ if (entry->find(registeredListener) != notFound) // duplicate listener
+ return false;
+ }
+
+ entry->append(registeredListener);
+ return true;
+}
+
+bool EventTarget::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
+{
+ EventTargetData* d = eventTargetData();
+ if (!d)
+ return false;
+
+ EventListenerMap::iterator result = d->eventListenerMap.find(eventType);
+ if (result == d->eventListenerMap.end())
+ return false;
+ EventListenerVector* entry = result->second;
+
+ RegisteredEventListener registeredListener(listener, useCapture);
+ size_t index = entry->find(registeredListener);
+ if (index == notFound)
+ return false;
+
+ entry->remove(index);
+ if (entry->isEmpty()) {
+ delete entry;
+ d->eventListenerMap.remove(result);
+ }
+
+ // Notify firing events planning to invoke the listener at 'index' that
+ // they have one less listener to invoke.
+ for (size_t i = 0; i < d->firingEventIterators.size(); ++i) {
+ if (eventType != d->firingEventIterators[i].eventType)
+ continue;
+
+ if (index >= d->firingEventIterators[i].end)
+ continue;
+
+ --d->firingEventIterators[i].end;
+ if (index <= d->firingEventIterators[i].iterator)
+ --d->firingEventIterators[i].iterator;
+ }
+
+ return true;
+}
+
+bool EventTarget::setAttributeEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener)
+{
+ clearAttributeEventListener(eventType);
+ if (!listener)
+ return false;
+ return addEventListener(eventType, listener, false);
+}
+
+EventListener* EventTarget::getAttributeEventListener(const AtomicString& eventType)
+{
+ const EventListenerVector& entry = getEventListeners(eventType);
+ for (size_t i = 0; i < entry.size(); ++i) {
+ if (entry[i].listener->isAttribute())
+ return entry[i].listener.get();
+ }
+ return 0;
+}
+
+bool EventTarget::clearAttributeEventListener(const AtomicString& eventType)
+{
+ EventListener* listener = getAttributeEventListener(eventType);
+ if (!listener)
+ return false;
+ return removeEventListener(eventType, listener, false);
+}
+
+bool EventTarget::dispatchEvent(PassRefPtr<Event> event, ExceptionCode& ec)
+{
+ if (!event || event->type().isEmpty()) {
+ ec = EventException::UNSPECIFIED_EVENT_TYPE_ERR;
+ return false;
+ }
+
+ if (!scriptExecutionContext())
+ return false;
+
+ return dispatchEvent(event);
+}
+
+bool EventTarget::dispatchEvent(PassRefPtr<Event> event)
+{
+ event->setTarget(this);
+ event->setCurrentTarget(this);
+ event->setEventPhase(Event::AT_TARGET);
+ return fireEventListeners(event.get());
+}
+
+bool EventTarget::fireEventListeners(Event* event)
+{
+ ASSERT(!eventDispatchForbidden());
+ ASSERT(event && !event->type().isEmpty());
+
+ EventTargetData* d = eventTargetData();
+ if (!d)
+ return true;
+
+ EventListenerMap::iterator result = d->eventListenerMap.find(event->type());
+ if (result != d->eventListenerMap.end())
+ fireEventListeners(event, d, *result->second);
+
+ return !event->defaultPrevented();
+}
+
+void EventTarget::fireEventListeners(Event* event, EventTargetData* d, EventListenerVector& entry)
+{
+ RefPtr<EventTarget> protect = this;
+
+ // Fire all listeners registered for this event. Don't fire listeners removed
+ // during event dispatch. Also, don't fire event listeners added during event
+ // dispatch. Conveniently, all new event listeners will be added after 'end',
+ // so iterating to 'end' naturally excludes new event listeners.
+
+ size_t i = 0;
+ size_t end = entry.size();
+ d->firingEventIterators.append(FiringEventIterator(event->type(), i, end));
+ for ( ; i < end; ++i) {
+ RegisteredEventListener& registeredListener = entry[i];
+ if (event->eventPhase() == Event::CAPTURING_PHASE && !registeredListener.useCapture)
+ continue;
+ if (event->eventPhase() == Event::BUBBLING_PHASE && registeredListener.useCapture)
+ continue;
+
+ // If stopImmediatePropagation has been called, we just break out immediately, without
+ // handling any more events on this target.
+ if (event->immediatePropagationStopped())
+ break;
+
+ // To match Mozilla, the AT_TARGET phase fires both capturing and bubbling
+ // event listeners, even though that violates some versions of the DOM spec.
+ registeredListener.listener->handleEvent(scriptExecutionContext(), event);
+ }
+ d->firingEventIterators.removeLast();
+}
+
+const EventListenerVector& EventTarget::getEventListeners(const AtomicString& eventType)
+{
+ DEFINE_STATIC_LOCAL(EventListenerVector, emptyVector, ());
+
+ EventTargetData* d = eventTargetData();
+ if (!d)
+ return emptyVector;
+ EventListenerMap::iterator it = d->eventListenerMap.find(eventType);
+ if (it == d->eventListenerMap.end())
+ return emptyVector;
+ return *it->second;
+}
+
+void EventTarget::removeAllEventListeners()
+{
+ EventTargetData* d = eventTargetData();
+ if (!d)
+ return;
+ deleteAllValues(d->eventListenerMap);
+ d->eventListenerMap.clear();
+
+ // Notify firing events planning to invoke the listener at 'index' that
+ // they have one less listener to invoke.
+ for (size_t i = 0; i < d->firingEventIterators.size(); ++i) {
+ d->firingEventIterators[i].iterator = 0;
+ d->firingEventIterators[i].end = 0;
+ }
+}
+
+} // namespace WebCore