Remove all uses of PassRefPtr in WebCore/svg
[WebKit-https.git] / Source / WebCore / dom / EventTarget.cpp
index 7c058c2..8b9cd41 100644 (file)
  *    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
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE 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
 #include "config.h"
 #include "EventTarget.h"
 
-#include "Event.h"
 #include "EventException.h"
+#include "InspectorInstrumentation.h"
+#include "ScriptController.h"
+#include "WebKitAnimationEvent.h"
+#include "WebKitTransitionEvent.h"
+#include <wtf/MainThread.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/Ref.h>
 #include <wtf/StdLibExtras.h>
 #include <wtf/Vector.h>
 
@@ -41,50 +47,18 @@ 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;
@@ -95,134 +69,14 @@ 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()
+bool EventTarget::isMessagePort() const
 {
-    return 0;
+    return false;
 }
-#endif
 
-#if ENABLE(WEB_AUDIO)
-AudioContext* EventTarget::toAudioContext()
+bool EventTarget::addEventListener(const AtomicString& eventType, RefPtr<EventListener>&& listener, bool useCapture)
 {
-    return 0;
-}
-
-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)
-IDBDatabase* EventTarget::toIDBDatabase()
-{
-    return 0;
-}
-IDBRequest* EventTarget::toIDBRequest()
-{
-    return 0;
-}
-IDBTransaction* EventTarget::toIDBTransaction()
-{
-    return 0;
-}
-IDBVersionChangeRequest* EventTarget::toIDBVersionChangeRequest()
-{
-    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;
+    return ensureEventTargetData().eventListenerMap.add(eventType, WTF::move(listener), useCapture);
 }
 
 bool EventTarget::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
@@ -231,34 +85,26 @@ bool EventTarget::removeEventListener(const AtomicString& eventType, EventListen
     if (!d)
         return false;
 
-    EventListenerMap::iterator result = d->eventListenerMap.find(eventType);
-    if (result == d->eventListenerMap.end())
-        return false;
-    EventListenerVector* entry = result->second;
+    size_t indexOfRemovedListener;
 
-    RegisteredEventListener registeredListener(listener, useCapture);
-    size_t index = entry->find(registeredListener);
-    if (index == notFound)
+    if (!d->eventListenerMap.remove(eventType, listener, useCapture, indexOfRemovedListener))
         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)
+    if (!d->firingEventIterators)
+        return true;
+    for (size_t i = 0; i < d->firingEventIterators->size(); ++i) {
+        FiringEventIterator& firingIterator = d->firingEventIterators->at(i);
+        if (eventType != firingIterator.eventType)
             continue;
 
-        if (index >= d->firingEventIterators[i].end)
+        if (indexOfRemovedListener >= firingIterator.size)
             continue;
 
-        --d->firingEventIterators[i].end;
-        if (index <= d->firingEventIterators[i].iterator)
-            --d->firingEventIterators[i].iterator;
+        --firingIterator.size;
+        if (indexOfRemovedListener <= firingIterator.iterator)
+            --firingIterator.iterator;
     }
 
     return true;
@@ -292,8 +138,13 @@ bool EventTarget::clearAttributeEventListener(const AtomicString& eventType)
 
 bool EventTarget::dispatchEvent(PassRefPtr<Event> event, ExceptionCode& ec)
 {
-    if (!event || event->type().isEmpty()) {
-        ec = EventException::UNSPECIFIED_EVENT_TYPE_ERR;
+    if (!event) {
+        ec = TypeError;
+        return false;
+    }
+
+    if (!event->isInitialized() || event->isBeingDispatched()) {
+        ec = INVALID_STATE_ERR;
         return false;
     }
 
@@ -308,42 +159,86 @@ bool EventTarget::dispatchEvent(PassRefPtr<Event> event)
     event->setTarget(this);
     event->setCurrentTarget(this);
     event->setEventPhase(Event::AT_TARGET);
-    return fireEventListeners(event.get());
+    bool defaultPrevented = fireEventListeners(event.get());
+    event->setEventPhase(0);
+    return defaultPrevented;
 }
 
 void EventTarget::uncaughtExceptionInEventHandler()
 {
 }
 
+static const AtomicString& legacyType(const Event* event)
+{
+    if (event->type() == eventNames().animationendEvent)
+        return eventNames().webkitAnimationEndEvent;
+
+    if (event->type() == eventNames().animationstartEvent)
+        return eventNames().webkitAnimationStartEvent;
+
+    if (event->type() == eventNames().animationiterationEvent)
+        return eventNames().webkitAnimationIterationEvent;
+
+    if (event->type() == eventNames().transitionendEvent)
+        return eventNames().webkitTransitionEndEvent;
+
+    if (event->type() == eventNames().wheelEvent)
+        return eventNames().mousewheelEvent;
+
+    return emptyAtom;
+}
+
 bool EventTarget::fireEventListeners(Event* event)
 {
-    ASSERT(!eventDispatchForbidden());
-    ASSERT(event && !event->type().isEmpty());
+    ASSERT_WITH_SECURITY_IMPLICATION(!NoEventDispatchAssertion::isEventDispatchForbidden());
+    ASSERT(event && event->isInitialized());
 
     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);
-    
+    EventListenerVector* legacyListenersVector = 0;
+    const AtomicString& legacyTypeName = legacyType(event);
+    if (!legacyTypeName.isEmpty())
+        legacyListenersVector = d->eventListenerMap.find(legacyTypeName);
+
+    EventListenerVector* listenersVector = d->eventListenerMap.find(event->type());
+
+    if (listenersVector)
+        fireEventListeners(event, d, *listenersVector);
+    else if (legacyListenersVector) {
+        AtomicString typeName = event->type();
+        event->setType(legacyTypeName);
+        fireEventListeners(event, d, *legacyListenersVector);
+        event->setType(typeName);
+    }
+
     return !event->defaultPrevented();
 }
         
 void EventTarget::fireEventListeners(Event* event, EventTargetData* d, EventListenerVector& entry)
 {
-    RefPtr<EventTarget> protect = this;
+    Ref<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.
+    // 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 or at index |size|, so iterating up to (but not including) |size| 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) {
+    size_t size = entry.size();
+    if (!d->firingEventIterators)
+        d->firingEventIterators = std::make_unique<FiringEventIteratorVector>();
+    d->firingEventIterators->append(FiringEventIterator(event->type(), i, size));
+
+    ScriptExecutionContext* context = scriptExecutionContext();
+    Document* document = nullptr;
+    InspectorInstrumentationCookie willDispatchEventCookie;
+    if (is<Document>(context)) {
+        document = downcast<Document>(context);
+        willDispatchEventCookie = InspectorInstrumentation::willDispatchEvent(*document, *event, size > 0);
+    }
+
+    for (; i < size; ++i) {
         RegisteredEventListener& registeredListener = entry[i];
         if (event->eventPhase() == Event::CAPTURING_PHASE && !registeredListener.useCapture)
             continue;
@@ -355,24 +250,24 @@ void EventTarget::fireEventListeners(Event* event, EventTargetData* d, EventList
         if (event->immediatePropagationStopped())
             break;
 
+        InspectorInstrumentationCookie cookie = InspectorInstrumentation::willHandleEvent(context, *event);
         // 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);
+        registeredListener.listener->handleEvent(context, event);
+        InspectorInstrumentation::didHandleEvent(cookie);
     }
-    d->firingEventIterators.removeLast();
+    d->firingEventIterators->removeLast();
+
+    if (document)
+        InspectorInstrumentation::didDispatchEvent(willDispatchEventCookie);
 }
 
 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;
+    auto* data = eventTargetData();
+    auto* listenerVector = data ? data->eventListenerMap.find(eventType) : nullptr;
+    static NeverDestroyed<EventListenerVector> emptyVector;
+    return listenerVector ? *listenerVector : emptyVector.get();
 }
 
 void EventTarget::removeAllEventListeners()
@@ -380,41 +275,16 @@ 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;
+    if (d->firingEventIterators) {
+        for (size_t i = 0; i < d->firingEventIterators->size(); ++i) {
+            d->firingEventIterators->at(i).iterator = 0;
+            d->firingEventIterators->at(i).size = 0;
+        }
     }
 }
 
-EventListenerIterator::EventListenerIterator()
-    : m_index(0)
-{
-}
-
-EventListenerIterator::EventListenerIterator(EventTarget* target)
-    : m_index(0)
-{
-    EventTargetData* data = target->eventTargetData();
-    if (!data)
-        return;
-    m_mapIterator = data->eventListenerMap.begin();
-    m_mapEnd = data->eventListenerMap.end();
-}
-
-EventListener* EventListenerIterator::nextListener()
-{
-    for (; m_mapIterator != m_mapEnd; ++m_mapIterator) {
-        EventListenerVector& listeners = *m_mapIterator->second;
-        if (m_index < listeners.size())
-            return listeners[m_index++].listener.get();
-        m_index = 0;
-    }
-    return 0;
-}
-
 } // namespace WebCore