/*
 * 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 "third_party/blink/renderer/core/dom/events/event_target.h"

#include <memory>

#include "base/format_macros.h"
#include "third_party/blink/public/web/web_settings.h"
#include "third_party/blink/renderer/bindings/core/v8/add_event_listener_options_or_boolean.h"
#include "third_party/blink/renderer/bindings/core/v8/event_listener_options_or_boolean.h"
#include "third_party/blink/renderer/bindings/core/v8/js_based_event_listener.h"
#include "third_party/blink/renderer/bindings/core/v8/js_event_listener.h"
#include "third_party/blink/renderer/bindings/core/v8/source_location.h"
#include "third_party/blink/renderer/core/dom/abort_signal.h"
#include "third_party/blink/renderer/core/dom/events/add_event_listener_options_resolved.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/dom/events/event_dispatch_forbidden_scope.h"
#include "third_party/blink/renderer/core/dom/events/event_target_impl.h"
#include "third_party/blink/renderer/core/editing/editor.h"
#include "third_party/blink/renderer/core/events/event_util.h"
#include "third_party/blink/renderer/core/events/pointer_event.h"
#include "third_party/blink/renderer/core/frame/frame_console.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/performance_monitor.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/v8_dom_activity_logger.h"
#include "third_party/blink/renderer/platform/instrumentation/histogram.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
#include "third_party/blink/renderer/platform/wtf/threading.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"

namespace blink {
namespace {

enum PassiveForcedListenerResultType {
  kPreventDefaultNotCalled,
  kDocumentLevelTouchPreventDefaultCalled,
  kPassiveForcedListenerResultTypeMax
};

Event::PassiveMode EventPassiveMode(
    const RegisteredEventListener& event_listener) {
  if (!event_listener.Passive()) {
    if (event_listener.PassiveSpecified())
      return Event::PassiveMode::kNotPassive;
    return Event::PassiveMode::kNotPassiveDefault;
  }
  if (event_listener.PassiveForcedForDocumentTarget())
    return Event::PassiveMode::kPassiveForcedDocumentLevel;
  if (event_listener.PassiveSpecified())
    return Event::PassiveMode::kPassive;
  return Event::PassiveMode::kPassiveDefault;
}

Settings* WindowSettings(LocalDOMWindow* executing_window) {
  if (executing_window) {
    if (LocalFrame* frame = executing_window->GetFrame()) {
      return frame->GetSettings();
    }
  }
  return nullptr;
}

bool IsTouchScrollBlockingEvent(const AtomicString& event_type) {
  return event_type == event_type_names::kTouchstart ||
         event_type == event_type_names::kTouchmove;
}

bool IsWheelScrollBlockingEvent(const AtomicString& event_type) {
  return event_type == event_type_names::kMousewheel ||
         event_type == event_type_names::kWheel;
}

bool IsScrollBlockingEvent(const AtomicString& event_type) {
  return IsTouchScrollBlockingEvent(event_type) ||
         IsWheelScrollBlockingEvent(event_type);
}

bool IsInstrumentedForAsyncStack(const AtomicString& event_type) {
  return event_type == event_type_names::kLoad ||
         event_type == event_type_names::kError;
}

base::TimeDelta BlockedEventsWarningThreshold(ExecutionContext* context,
                                              const Event& event) {
  if (!event.cancelable())
    return base::TimeDelta();
  if (!IsScrollBlockingEvent(event.type()))
    return base::TimeDelta();
  return PerformanceMonitor::Threshold(context,
                                       PerformanceMonitor::kBlockedEvent);
}

void ReportBlockedEvent(EventTarget& target,
                        const Event& event,
                        RegisteredEventListener* registered_listener,
                        base::TimeDelta delayed) {
  JSBasedEventListener* listener =
      DynamicTo<JSBasedEventListener>(registered_listener->Callback());
  if (!listener)
    return;

  String message_text = String::Format(
      "Handling of '%s' input event was delayed for %" PRId64
      " ms due to main thread being busy. "
      "Consider marking event handler as 'passive' to make the page more "
      "responsive.",
      event.type().GetString().Utf8().c_str(), delayed.InMilliseconds());
  PerformanceMonitor::ReportGenericViolation(
      target.GetExecutionContext(), PerformanceMonitor::kBlockedEvent,
      message_text, delayed, listener->GetSourceLocation(target));
  registered_listener->SetBlockedEventWarningEmitted();
}

// UseCounts the event if it has the specified type. Returns true iff the event
// type matches.
bool CheckTypeThenUseCount(const Event& event,
                           const AtomicString& event_type_to_count,
                           const WebFeature feature,
                           Document& document) {
  if (event.type() != event_type_to_count)
    return false;
  UseCounter::Count(document, feature);
  return true;
}

void CountFiringEventListeners(const Event& event,
                               const LocalDOMWindow* executing_window) {
  if (!executing_window)
    return;
  if (!executing_window->document())
    return;
  Document& document = *executing_window->document();

  if (event.type() == event_type_names::kToggle &&
      document.ToggleDuringParsing()) {
    UseCounter::Count(document, WebFeature::kToggleEventHandlerDuringParsing);
    return;
  }
  if (CheckTypeThenUseCount(event, event_type_names::kBeforeunload,
                            WebFeature::kDocumentBeforeUnloadFired, document)) {
    if (executing_window != executing_window->top())
      UseCounter::Count(document, WebFeature::kSubFrameBeforeUnloadFired);
    return;
  }
  if (CheckTypeThenUseCount(event, event_type_names::kPointerdown,
                            WebFeature::kPointerDownFired, document)) {
    if (IsA<PointerEvent>(event) &&
        static_cast<const PointerEvent&>(event).pointerType() == "touch") {
      UseCounter::Count(document, WebFeature::kPointerDownFiredForTouch);
    }
    return;
  }

  struct CountedEvent {
    const AtomicString& event_type;
    const WebFeature feature;
  };
  static const CountedEvent counted_events[] = {
      {event_type_names::kUnload, WebFeature::kDocumentUnloadFired},
      {event_type_names::kPagehide, WebFeature::kDocumentPageHideFired},
      {event_type_names::kPageshow, WebFeature::kDocumentPageShowFired},
      {event_type_names::kDOMFocusIn, WebFeature::kDOMFocusInOutEvent},
      {event_type_names::kDOMFocusOut, WebFeature::kDOMFocusInOutEvent},
      {event_type_names::kFocusin, WebFeature::kFocusInOutEvent},
      {event_type_names::kFocusout, WebFeature::kFocusInOutEvent},
      {event_type_names::kTextInput, WebFeature::kTextInputFired},
      {event_type_names::kTouchstart, WebFeature::kTouchStartFired},
      {event_type_names::kMousedown, WebFeature::kMouseDownFired},
      {event_type_names::kPointerenter, WebFeature::kPointerEnterLeaveFired},
      {event_type_names::kPointerleave, WebFeature::kPointerEnterLeaveFired},
      {event_type_names::kPointerover, WebFeature::kPointerOverOutFired},
      {event_type_names::kPointerout, WebFeature::kPointerOverOutFired},
      {event_type_names::kSearch, WebFeature::kSearchEventFired},
  };
  for (const auto& counted_event : counted_events) {
    if (CheckTypeThenUseCount(event, counted_event.event_type,
                              counted_event.feature, document))
      return;
  }
}

void RegisterWithScheduler(ExecutionContext* execution_context,
                           const AtomicString& event_type) {
  if (!execution_context || !execution_context->GetScheduler())
    return;
  // TODO(altimin): Ideally we would also support tracking unregistration of
  // event listeners, but we don't do this for performance reasons.
  base::Optional<SchedulingPolicy::Feature> feature_for_scheduler;
  if (event_type == event_type_names::kPageshow) {
    feature_for_scheduler = SchedulingPolicy::Feature::kPageShowEventListener;
  } else if (event_type == event_type_names::kPagehide) {
    feature_for_scheduler = SchedulingPolicy::Feature::kPageHideEventListener;
  } else if (event_type == event_type_names::kBeforeunload) {
    feature_for_scheduler =
        SchedulingPolicy::Feature::kBeforeUnloadEventListener;
  } else if (event_type == event_type_names::kUnload) {
    feature_for_scheduler = SchedulingPolicy::Feature::kUnloadEventListener;
  } else if (event_type == event_type_names::kFreeze) {
    feature_for_scheduler = SchedulingPolicy::Feature::kFreezeEventListener;
  } else if (event_type == event_type_names::kResume) {
    feature_for_scheduler = SchedulingPolicy::Feature::kResumeEventListener;
  }
  if (feature_for_scheduler) {
    execution_context->GetScheduler()->RegisterStickyFeature(
        feature_for_scheduler.value(),
        {SchedulingPolicy::DisableBackForwardCache()});
  }
}

}  // namespace

EventTargetData::EventTargetData() = default;

EventTargetData::~EventTargetData() = default;

void EventTargetData::Trace(Visitor* visitor) const {
  visitor->Trace(event_listener_map);
}

EventTarget::EventTarget() = default;

EventTarget::~EventTarget() = default;

Node* EventTarget::ToNode() {
  return nullptr;
}

const DOMWindow* EventTarget::ToDOMWindow() const {
  return nullptr;
}

const LocalDOMWindow* EventTarget::ToLocalDOMWindow() const {
  return nullptr;
}

LocalDOMWindow* EventTarget::ToLocalDOMWindow() {
  return nullptr;
}

MessagePort* EventTarget::ToMessagePort() {
  return nullptr;
}

ServiceWorker* EventTarget::ToServiceWorker() {
  return nullptr;
}

PortalHost* EventTarget::ToPortalHost() {
  return nullptr;
}

// An instance of EventTargetImpl is returned because EventTarget
// is an abstract class, and making it non-abstract is unfavorable
// because it will increase the size of EventTarget and all of its
// subclasses with code that are mostly unnecessary for them,
// resulting in a performance decrease.
// We also don't use ImplementedAs=EventTargetImpl in event_target.idl
// because it will result in some complications with classes that are
// currently derived from EventTarget.
// Spec: https://dom.spec.whatwg.org/#dom-eventtarget-eventtarget
EventTarget* EventTarget::Create(ScriptState* script_state) {
  return MakeGarbageCollected<EventTargetImpl>(script_state);
}

inline LocalDOMWindow* EventTarget::ExecutingWindow() {
  return DynamicTo<LocalDOMWindow>(GetExecutionContext());
}

bool EventTarget::IsTopLevelNode() {
  if (ToLocalDOMWindow())
    return true;

  Node* node = ToNode();
  if (!node)
    return false;

  if (node->IsDocumentNode() || node->GetDocument().documentElement() == node ||
      node->GetDocument().body() == node) {
    return true;
  }

  return false;
}

void EventTarget::SetDefaultAddEventListenerOptions(
    const AtomicString& event_type,
    EventListener* event_listener,
    AddEventListenerOptionsResolved* options) {
  options->SetPassiveSpecified(options->hasPassive());

  if (!IsScrollBlockingEvent(event_type)) {
    if (!options->hasPassive())
      options->setPassive(false);
    return;
  }

  LocalDOMWindow* executing_window = ExecutingWindow();
  if (executing_window) {
    if (options->hasPassive()) {
      UseCounter::Count(executing_window->document(),
                        options->passive()
                            ? WebFeature::kAddEventListenerPassiveTrue
                            : WebFeature::kAddEventListenerPassiveFalse);
    }
  }

  if (IsTouchScrollBlockingEvent(event_type)) {
    if (!options->hasPassive() && IsTopLevelNode()) {
      options->setPassive(true);
      options->SetPassiveForcedForDocumentTarget(true);
      return;
    }
  }

  if (IsWheelScrollBlockingEvent(event_type) && IsTopLevelNode()) {
    if (options->hasPassive()) {
      if (executing_window) {
        UseCounter::Count(
            executing_window->document(),
            options->passive()
                ? WebFeature::kAddDocumentLevelPassiveTrueWheelEventListener
                : WebFeature::kAddDocumentLevelPassiveFalseWheelEventListener);
      }
    } else {  // !options->hasPassive()
      if (executing_window) {
        UseCounter::Count(
            executing_window->document(),
            WebFeature::kAddDocumentLevelPassiveDefaultWheelEventListener);
      }
      options->setPassive(true);
      options->SetPassiveForcedForDocumentTarget(true);
      return;
    }
  }

  // For mousewheel event listeners that have the target as the window and
  // a bound function name of "ssc_wheel" treat and no passive value default
  // passive to true. See crbug.com/501568.
  if (event_type == event_type_names::kMousewheel && ToLocalDOMWindow() &&
      event_listener && !options->hasPassive()) {
    JSBasedEventListener* v8_listener =
        DynamicTo<JSBasedEventListener>(event_listener);
    if (!v8_listener)
      return;
    v8::Local<v8::Value> callback_object =
        v8_listener->GetListenerObject(*this);
    if (!callback_object.IsEmpty() && callback_object->IsFunction() &&
        strcmp(
            "ssc_wheel",
            *v8::String::Utf8Value(
                v8::Isolate::GetCurrent(),
                v8::Local<v8::Function>::Cast(callback_object)->GetName())) ==
            0) {
      options->setPassive(true);
      if (executing_window) {
        UseCounter::Count(executing_window->document(),
                          WebFeature::kSmoothScrollJSInterventionActivated);

        executing_window->GetFrame()->Console().AddMessage(
            MakeGarbageCollected<ConsoleMessage>(
                mojom::ConsoleMessageSource::kIntervention,
                mojom::ConsoleMessageLevel::kWarning,
                "Registering mousewheel event as passive due to "
                "smoothscroll.js usage. The smoothscroll.js library is "
                "buggy, no longer necessary and degrades performance. See "
                "https://www.chromestatus.com/feature/5749447073988608"));
      }
      return;
    }
  }

  if (Settings* settings = WindowSettings(ExecutingWindow())) {
    switch (settings->GetPassiveListenerDefault()) {
      case PassiveListenerDefault::kFalse:
        if (!options->hasPassive())
          options->setPassive(false);
        break;
      case PassiveListenerDefault::kTrue:
        if (!options->hasPassive())
          options->setPassive(true);
        break;
      case PassiveListenerDefault::kForceAllTrue:
        options->setPassive(true);
        break;
    }
  } else {
    if (!options->hasPassive())
      options->setPassive(false);
  }

  if (!options->passive() && !options->PassiveSpecified()) {
    String message_text = String::Format(
        "Added non-passive event listener to a scroll-blocking '%s' event. "
        "Consider marking event handler as 'passive' to make the page more "
        "responsive. See "
        "https://www.chromestatus.com/feature/5745543795965952",
        event_type.GetString().Utf8().c_str());

    PerformanceMonitor::ReportGenericViolation(
        GetExecutionContext(), PerformanceMonitor::kDiscouragedAPIUse,
        message_text, base::TimeDelta(), nullptr);
  }
}

bool EventTarget::addEventListener(const AtomicString& event_type,
                                   V8EventListener* listener) {
  EventListener* event_listener = JSEventListener::CreateOrNull(listener);
  return addEventListener(event_type, event_listener);
}

bool EventTarget::addEventListener(
    const AtomicString& event_type,
    V8EventListener* listener,
    const AddEventListenerOptionsOrBoolean& options_union) {
  EventListener* event_listener = JSEventListener::CreateOrNull(listener);

  if (options_union.IsBoolean()) {
    return addEventListener(event_type, event_listener,
                            options_union.GetAsBoolean());
  }

  if (options_union.IsAddEventListenerOptions()) {
    auto* resolved_options =
        MakeGarbageCollected<AddEventListenerOptionsResolved>();
    AddEventListenerOptions* options =
        options_union.GetAsAddEventListenerOptions();
    if (options->hasPassive())
      resolved_options->setPassive(options->passive());
    if (options->hasOnce())
      resolved_options->setOnce(options->once());
    if (options->hasCapture())
      resolved_options->setCapture(options->capture());
    if (options->hasSignal())
      resolved_options->setSignal(options->signal());
    return addEventListener(event_type, event_listener, resolved_options);
  }

  return addEventListener(event_type, event_listener);
}

bool EventTarget::addEventListener(const AtomicString& event_type,
                                   EventListener* listener,
                                   bool use_capture) {
  auto* options = MakeGarbageCollected<AddEventListenerOptionsResolved>();
  options->setCapture(use_capture);
  SetDefaultAddEventListenerOptions(event_type, listener, options);
  return AddEventListenerInternal(event_type, listener, options);
}

bool EventTarget::addEventListener(const AtomicString& event_type,
                                   EventListener* listener,
                                   AddEventListenerOptionsResolved* options) {
  SetDefaultAddEventListenerOptions(event_type, listener, options);
  return AddEventListenerInternal(event_type, listener, options);
}

bool EventTarget::AddEventListenerInternal(
    const AtomicString& event_type,
    EventListener* listener,
    const AddEventListenerOptionsResolved* options) {
  if (!listener)
    return false;

  if (options->hasSignal() && options->signal()->aborted())
    return false;

  if (event_type == event_type_names::kTouchcancel ||
      event_type == event_type_names::kTouchend ||
      event_type == event_type_names::kTouchmove ||
      event_type == event_type_names::kTouchstart) {
    if (const LocalDOMWindow* executing_window = ExecutingWindow()) {
      if (const Document* document = executing_window->document()) {
        document->CountUse(options->passive()
                               ? WebFeature::kPassiveTouchEventListener
                               : WebFeature::kNonPassiveTouchEventListener);
      }
    }
  }

  V8DOMActivityLogger* activity_logger =
      V8DOMActivityLogger::CurrentActivityLoggerIfIsolatedWorld();
  if (activity_logger) {
    Vector<String> argv;
    argv.push_back(ToNode() ? ToNode()->nodeName() : InterfaceName());
    argv.push_back(event_type);
    activity_logger->LogEvent("blinkAddEventListener", argv.size(),
                              argv.data());
  }

  RegisteredEventListener registered_listener;
  bool added = EnsureEventTargetData().event_listener_map.Add(
      event_type, listener, options, &registered_listener);
  if (added) {
    if (options->hasSignal()) {
      // Instead of passing the entire |options| here, which could create a
      // circular reference due to |options| holding a Member<AbortSignal>, just
      // pass the |options->capture()| boolean, which is the only thing
      // removeEventListener actually uses to find and remove the event
      // listener.
      options->signal()->AddAlgorithm(WTF::Bind(
          [](EventTarget* event_target, const AtomicString& event_type,
             const EventListener* listener, bool capture) {
            event_target->removeEventListener(event_type, listener, capture);
          },
          WrapWeakPersistent(this), event_type, WrapWeakPersistent(listener),
          options->capture()));
      if (const LocalDOMWindow* executing_window = ExecutingWindow()) {
        if (const Document* document = executing_window->document()) {
          document->CountUse(WebFeature::kAddEventListenerWithAbortSignal);
        }
      }
    }

    AddedEventListener(event_type, registered_listener);
    if (IsA<JSBasedEventListener>(listener) &&
        IsInstrumentedForAsyncStack(event_type)) {
      probe::AsyncTaskScheduled(GetExecutionContext(), event_type,
                                listener->async_task_id());
    }
  }
  return added;
}

void EventTarget::AddedEventListener(
    const AtomicString& event_type,
    RegisteredEventListener& registered_listener) {
  if (const LocalDOMWindow* executing_window = ExecutingWindow()) {
    if (Document* document = executing_window->document()) {
      if (event_type == event_type_names::kAuxclick) {
        UseCounter::Count(*document, WebFeature::kAuxclickAddListenerCount);
      } else if (event_type == event_type_names::kAppinstalled) {
        UseCounter::Count(*document, WebFeature::kAppInstalledEventAddListener);
      } else if (event_util::IsPointerEventType(event_type)) {
        UseCounter::Count(*document, WebFeature::kPointerEventAddListenerCount);
      } else if (event_type == event_type_names::kSlotchange) {
        UseCounter::Count(*document, WebFeature::kSlotChangeEventAddListener);
      } else if (event_type == event_type_names::kBeforematch) {
        UseCounter::Count(*document, WebFeature::kBeforematchHandlerRegistered);
      }
    }
  }

  RegisterWithScheduler(GetExecutionContext(), event_type);

  if (event_util::IsDOMMutationEventType(event_type)) {
    if (ExecutionContext* context = GetExecutionContext()) {
      String message_text = String::Format(
          "Added synchronous DOM mutation listener to a '%s' event. "
          "Consider using MutationObserver to make the page more responsive.",
          event_type.GetString().Utf8().c_str());
      PerformanceMonitor::ReportGenericViolation(
          context, PerformanceMonitor::kDiscouragedAPIUse, message_text,
          base::TimeDelta(), nullptr);
    }
  }
}

bool EventTarget::removeEventListener(const AtomicString& event_type,
                                      V8EventListener* listener) {
  EventListener* event_listener = JSEventListener::CreateOrNull(listener);
  return removeEventListener(event_type, event_listener);
}

bool EventTarget::removeEventListener(
    const AtomicString& event_type,
    V8EventListener* listener,
    const EventListenerOptionsOrBoolean& options_union) {
  EventListener* event_listener = JSEventListener::CreateOrNull(listener);

  if (options_union.IsBoolean()) {
    return removeEventListener(event_type, event_listener,
                               options_union.GetAsBoolean());
  }

  if (options_union.IsEventListenerOptions()) {
    EventListenerOptions* options = options_union.GetAsEventListenerOptions();
    return removeEventListener(event_type, event_listener, options);
  }

  return removeEventListener(event_type, event_listener);
}

bool EventTarget::removeEventListener(const AtomicString& event_type,
                                      const EventListener* listener,
                                      bool use_capture) {
  EventListenerOptions* options = EventListenerOptions::Create();
  options->setCapture(use_capture);
  return RemoveEventListenerInternal(event_type, listener, options);
}

bool EventTarget::removeEventListener(const AtomicString& event_type,
                                      const EventListener* listener,
                                      EventListenerOptions* options) {
  return RemoveEventListenerInternal(event_type, listener, options);
}

bool EventTarget::RemoveEventListenerInternal(
    const AtomicString& event_type,
    const EventListener* listener,
    const EventListenerOptions* options) {
  if (!listener)
    return false;

  EventTargetData* d = GetEventTargetData();
  if (!d)
    return false;

  wtf_size_t index_of_removed_listener;
  RegisteredEventListener registered_listener;

  if (!d->event_listener_map.Remove(event_type, listener, options,
                                    &index_of_removed_listener,
                                    &registered_listener))
    return false;

  // Notify firing events planning to invoke the listener at 'index' that
  // they have one less listener to invoke.
  if (d->firing_event_iterators) {
    for (const auto& firing_iterator : *d->firing_event_iterators) {
      if (event_type != firing_iterator.event_type)
        continue;

      if (index_of_removed_listener >= firing_iterator.end)
        continue;

      --firing_iterator.end;
      // Note that when firing an event listener,
      // firingIterator.iterator indicates the next event listener
      // that would fire, not the currently firing event
      // listener. See EventTarget::fireEventListeners.
      if (index_of_removed_listener < firing_iterator.iterator)
        --firing_iterator.iterator;
    }
  }
  RemovedEventListener(event_type, registered_listener);
  return true;
}

void EventTarget::RemovedEventListener(
    const AtomicString& event_type,
    const RegisteredEventListener& registered_listener) {}

RegisteredEventListener* EventTarget::GetAttributeRegisteredEventListener(
    const AtomicString& event_type) {
  EventListenerVector* listener_vector = GetEventListeners(event_type);
  if (!listener_vector)
    return nullptr;

  for (auto& event_listener : *listener_vector) {
    EventListener* listener = event_listener.Callback();
    if (GetExecutionContext() && listener->IsEventHandler() &&
        listener->BelongsToTheCurrentWorld(GetExecutionContext()))
      return &event_listener;
  }
  return nullptr;
}

bool EventTarget::SetAttributeEventListener(const AtomicString& event_type,
                                            EventListener* listener) {
  RegisteredEventListener* registered_listener =
      GetAttributeRegisteredEventListener(event_type);
  if (!listener) {
    if (registered_listener)
      removeEventListener(event_type, registered_listener->Callback(), false);
    return false;
  }
  if (registered_listener) {
    if (IsA<JSBasedEventListener>(listener) &&
        IsInstrumentedForAsyncStack(event_type)) {
      probe::AsyncTaskScheduled(GetExecutionContext(), event_type,
                                listener->async_task_id());
    }
    registered_listener->SetCallback(listener);
    return true;
  }
  return addEventListener(event_type, listener, false);
}

EventListener* EventTarget::GetAttributeEventListener(
    const AtomicString& event_type) {
  RegisteredEventListener* registered_listener =
      GetAttributeRegisteredEventListener(event_type);
  if (registered_listener)
    return registered_listener->Callback();
  return nullptr;
}

bool EventTarget::dispatchEventForBindings(Event* event,
                                           ExceptionState& exception_state) {
  if (!event->WasInitialized()) {
    exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
                                      "The event provided is uninitialized.");
    return false;
  }
  if (event->IsBeingDispatched()) {
    exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
                                      "The event is already being dispatched.");
    return false;
  }

  if (!GetExecutionContext())
    return false;

  event->SetTrusted(false);

  // Return whether the event was cancelled or not to JS not that it
  // might have actually been default handled; so check only against
  // CanceledByEventHandler.
  return DispatchEventInternal(*event) !=
         DispatchEventResult::kCanceledByEventHandler;
}

DispatchEventResult EventTarget::DispatchEvent(Event& event) {
  event.SetTrusted(true);
  return DispatchEventInternal(event);
}

DispatchEventResult EventTarget::DispatchEventInternal(Event& event) {
  event.SetTarget(this);
  event.SetCurrentTarget(this);
  event.SetEventPhase(Event::kAtTarget);
  DispatchEventResult dispatch_result = FireEventListeners(event);
  event.SetEventPhase(0);
  return dispatch_result;
}

static const AtomicString& LegacyType(const Event& event) {
  if (event.type() == event_type_names::kTransitionend)
    return event_type_names::kWebkitTransitionEnd;

  if (event.type() == event_type_names::kAnimationstart)
    return event_type_names::kWebkitAnimationStart;

  if (event.type() == event_type_names::kAnimationend)
    return event_type_names::kWebkitAnimationEnd;

  if (event.type() == event_type_names::kAnimationiteration)
    return event_type_names::kWebkitAnimationIteration;

  if (event.type() == event_type_names::kWheel)
    return event_type_names::kMousewheel;

  return g_empty_atom;
}

void EventTarget::CountLegacyEvents(
    const AtomicString& legacy_type_name,
    EventListenerVector* listeners_vector,
    EventListenerVector* legacy_listeners_vector) {
  WebFeature unprefixed_feature;
  WebFeature prefixed_feature;
  WebFeature prefixed_and_unprefixed_feature;
  if (legacy_type_name == event_type_names::kWebkitTransitionEnd) {
    prefixed_feature = WebFeature::kPrefixedTransitionEndEvent;
    unprefixed_feature = WebFeature::kUnprefixedTransitionEndEvent;
    prefixed_and_unprefixed_feature =
        WebFeature::kPrefixedAndUnprefixedTransitionEndEvent;
  } else if (legacy_type_name == event_type_names::kWebkitAnimationEnd) {
    prefixed_feature = WebFeature::kPrefixedAnimationEndEvent;
    unprefixed_feature = WebFeature::kUnprefixedAnimationEndEvent;
    prefixed_and_unprefixed_feature =
        WebFeature::kPrefixedAndUnprefixedAnimationEndEvent;
  } else if (legacy_type_name == event_type_names::kWebkitAnimationStart) {
    prefixed_feature = WebFeature::kPrefixedAnimationStartEvent;
    unprefixed_feature = WebFeature::kUnprefixedAnimationStartEvent;
    prefixed_and_unprefixed_feature =
        WebFeature::kPrefixedAndUnprefixedAnimationStartEvent;
  } else if (legacy_type_name == event_type_names::kWebkitAnimationIteration) {
    prefixed_feature = WebFeature::kPrefixedAnimationIterationEvent;
    unprefixed_feature = WebFeature::kUnprefixedAnimationIterationEvent;
    prefixed_and_unprefixed_feature =
        WebFeature::kPrefixedAndUnprefixedAnimationIterationEvent;
  } else if (legacy_type_name == event_type_names::kMousewheel) {
    prefixed_feature = WebFeature::kMouseWheelEvent;
    unprefixed_feature = WebFeature::kWheelEvent;
    prefixed_and_unprefixed_feature = WebFeature::kMouseWheelAndWheelEvent;
  } else {
    return;
  }

  if (const LocalDOMWindow* executing_window = ExecutingWindow()) {
    if (Document* document = executing_window->document()) {
      if (legacy_listeners_vector) {
        if (listeners_vector)
          UseCounter::Count(*document, prefixed_and_unprefixed_feature);
        else
          UseCounter::Count(*document, prefixed_feature);
      } else if (listeners_vector) {
        UseCounter::Count(*document, unprefixed_feature);
      }
    }
  }
}

DispatchEventResult EventTarget::FireEventListeners(Event& event) {
#if DCHECK_IS_ON()
  DCHECK(!EventDispatchForbiddenScope::IsEventDispatchForbidden());
#endif
  DCHECK(event.WasInitialized());

  EventTargetData* d = GetEventTargetData();
  if (!d)
    return DispatchEventResult::kNotCanceled;

  EventListenerVector* legacy_listeners_vector = nullptr;
  AtomicString legacy_type_name = LegacyType(event);
  if (!legacy_type_name.IsEmpty())
    legacy_listeners_vector = d->event_listener_map.Find(legacy_type_name);

  EventListenerVector* listeners_vector =
      d->event_listener_map.Find(event.type());

  bool fired_event_listeners = false;
  if (listeners_vector) {
    fired_event_listeners = FireEventListeners(event, d, *listeners_vector);
  } else if (event.isTrusted() && legacy_listeners_vector) {
    AtomicString unprefixed_type_name = event.type();
    event.SetType(legacy_type_name);
    fired_event_listeners =
        FireEventListeners(event, d, *legacy_listeners_vector);
    event.SetType(unprefixed_type_name);
  }

  // Only invoke the callback if event listeners were fired for this phase.
  if (fired_event_listeners) {
    event.DoneDispatchingEventAtCurrentTarget();

    // Only count uma metrics if we really fired an event listener.
    Editor::CountEvent(GetExecutionContext(), event);
    CountLegacyEvents(legacy_type_name, listeners_vector,
                      legacy_listeners_vector);
  }
  return GetDispatchEventResult(event);
}

bool EventTarget::FireEventListeners(Event& event,
                                     EventTargetData* d,
                                     EventListenerVector& entry) {
  // 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.

  ExecutionContext* context = GetExecutionContext();
  if (!context)
    return false;

  CountFiringEventListeners(event, ExecutingWindow());

  wtf_size_t i = 0;
  wtf_size_t size = entry.size();
  if (!d->firing_event_iterators)
    d->firing_event_iterators = std::make_unique<FiringEventIteratorVector>();
  d->firing_event_iterators->push_back(
      FiringEventIterator(event.type(), i, size));

  base::TimeDelta blocked_event_threshold =
      BlockedEventsWarningThreshold(context, event);
  base::TimeTicks now;
  bool should_report_blocked_event = false;
  if (!blocked_event_threshold.is_zero()) {
    now = base::TimeTicks::Now();
    should_report_blocked_event =
        now - event.PlatformTimeStamp() > blocked_event_threshold;
  }
  bool fired_listener = false;

  while (i < size) {
    // If stopImmediatePropagation has been called, we just break out
    // immediately, without handling any more events on this target.
    if (event.ImmediatePropagationStopped())
      break;

    RegisteredEventListener registered_listener = entry[i];

    // Move the iterator past this event listener. This must match
    // the handling of the FiringEventIterator::iterator in
    // EventTarget::removeEventListener.
    ++i;

    if (!registered_listener.ShouldFire(event))
      continue;

    EventListener* listener = registered_listener.Callback();
    // The listener will be retained by Member<EventListener> in the
    // registeredListener, i and size are updated with the firing event iterator
    // in case the listener is removed from the listener vector below.
    if (registered_listener.Once())
      removeEventListener(event.type(), listener,
                          registered_listener.Capture());

    event.SetHandlingPassive(EventPassiveMode(registered_listener));

    probe::UserCallback probe(context, nullptr, event.type(), false, this);
    probe::AsyncTask async_task(context, listener->async_task_id(), "event",
                                IsInstrumentedForAsyncStack(event.type()));

    // To match Mozilla, the AT_TARGET phase fires both capturing and bubbling
    // event listeners, even though that violates some versions of the DOM spec.
    listener->Invoke(context, &event);
    fired_listener = true;

    // If we're about to report this event listener as blocking, make sure it
    // wasn't removed while handling the event.
    if (should_report_blocked_event && i > 0 &&
        entry[i - 1].Callback() == listener && !entry[i - 1].Passive() &&
        !entry[i - 1].BlockedEventWarningEmitted() &&
        !event.defaultPrevented()) {
      ReportBlockedEvent(*this, event, &entry[i - 1],
                         now - event.PlatformTimeStamp());
    }

    event.SetHandlingPassive(Event::PassiveMode::kNotPassive);

    CHECK_LE(i, size);
  }
  d->firing_event_iterators->pop_back();
  return fired_listener;
}

DispatchEventResult EventTarget::GetDispatchEventResult(const Event& event) {
  if (event.defaultPrevented())
    return DispatchEventResult::kCanceledByEventHandler;
  if (event.DefaultHandled())
    return DispatchEventResult::kCanceledByDefaultEventHandler;
  return DispatchEventResult::kNotCanceled;
}

EventListenerVector* EventTarget::GetEventListeners(
    const AtomicString& event_type) {
  EventTargetData* data = GetEventTargetData();
  if (!data)
    return nullptr;
  return data->event_listener_map.Find(event_type);
}

int EventTarget::NumberOfEventListeners(const AtomicString& event_type) const {
  EventListenerVector* listeners =
      const_cast<EventTarget*>(this)->GetEventListeners(event_type);
  return listeners ? listeners->size() : 0;
}

Vector<AtomicString> EventTarget::EventTypes() {
  EventTargetData* d = GetEventTargetData();
  return d ? d->event_listener_map.EventTypes() : Vector<AtomicString>();
}

void EventTarget::RemoveAllEventListeners() {
  EventTargetData* d = GetEventTargetData();
  if (!d)
    return;
  d->event_listener_map.Clear();

  // Notify firing events planning to invoke the listener at 'index' that
  // they have one less listener to invoke.
  if (d->firing_event_iterators) {
    for (const auto& iterator : *d->firing_event_iterators) {
      iterator.iterator = 0;
      iterator.end = 0;
    }
  }
}

void EventTarget::EnqueueEvent(Event& event, TaskType task_type) {
  ExecutionContext* context = GetExecutionContext();
  if (!context)
    return;
  probe::AsyncTaskScheduled(context, event.type(), event.async_task_id());
  context->GetTaskRunner(task_type)->PostTask(
      FROM_HERE,
      WTF::Bind(&EventTarget::DispatchEnqueuedEvent, WrapPersistent(this),
                WrapPersistent(&event), WrapPersistent(context)));
}

void EventTarget::DispatchEnqueuedEvent(Event* event,
                                        ExecutionContext* context) {
  if (!GetExecutionContext()) {
    probe::AsyncTaskCanceled(context, event->async_task_id());
    return;
  }
  probe::AsyncTask async_task(context, event->async_task_id());
  DispatchEvent(*event);
}

STATIC_ASSERT_ENUM(WebSettings::PassiveEventListenerDefault::kFalse,
                   PassiveListenerDefault::kFalse);
STATIC_ASSERT_ENUM(WebSettings::PassiveEventListenerDefault::kTrue,
                   PassiveListenerDefault::kTrue);
STATIC_ASSERT_ENUM(WebSettings::PassiveEventListenerDefault::kForceAllTrue,
                   PassiveListenerDefault::kForceAllTrue);

}  // namespace blink
