blob: 0239dfb8d4cedeb90d42a6e5da778e7f7c3b445e [file] [log] [blame]
/*
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
* Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
* Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
* Copyright (C) 2003, 2005, 2006, 2008 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/dom/events/event_dispatcher.h"
#include "third_party/blink/renderer/core/dom/events/event_path.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
#include "third_party/blink/renderer/core/dom/events/window_event_context.h"
#include "third_party/blink/renderer/core/dom/static_node_list.h"
#include "third_party/blink/renderer/core/events/focus_event.h"
#include "third_party/blink/renderer/core/events/mouse_event.h"
#include "third_party/blink/renderer/core/events/pointer_event.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/hosts_using_features.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/use_counter.h"
#include "third_party/blink/renderer/core/svg/svg_element.h"
#include "third_party/blink/renderer/core/timing/dom_window_performance.h"
#include "third_party/blink/renderer/core/timing/window_performance.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
namespace blink {
static bool IsEventTypeScopedInV0(const AtomicString& event_type) {
// WebKit never allowed selectstart event to cross the the shadow DOM
// boundary. Changing this breaks existing sites.
// See https://bugs.webkit.org/show_bug.cgi?id=52195 for details.
return event_type == EventTypeNames::abort ||
event_type == EventTypeNames::change ||
event_type == EventTypeNames::error ||
event_type == EventTypeNames::load ||
event_type == EventTypeNames::reset ||
event_type == EventTypeNames::resize ||
event_type == EventTypeNames::scroll ||
event_type == EventTypeNames::select ||
event_type == EventTypeNames::selectstart ||
event_type == EventTypeNames::slotchange;
}
Event::Event() : Event("", Bubbles::kNo, Cancelable::kNo) {
was_initialized_ = false;
}
Event::Event(const AtomicString& event_type,
Bubbles bubbles,
Cancelable cancelable,
TimeTicks platform_time_stamp)
: Event(event_type,
bubbles,
cancelable,
ComposedMode::kScoped,
platform_time_stamp) {}
Event::Event(const AtomicString& event_type,
Bubbles bubbles,
Cancelable cancelable,
ComposedMode composed_mode)
: Event(event_type,
bubbles,
cancelable,
composed_mode,
CurrentTimeTicks()) {}
Event::Event(const AtomicString& event_type,
Bubbles bubbles,
Cancelable cancelable,
ComposedMode composed_mode,
TimeTicks platform_time_stamp)
: type_(event_type),
bubbles_(bubbles == Bubbles::kYes),
cancelable_(cancelable == Cancelable::kYes),
composed_(composed_mode == ComposedMode::kComposed),
is_event_type_scoped_in_v0_(IsEventTypeScopedInV0(event_type)),
propagation_stopped_(false),
immediate_propagation_stopped_(false),
default_prevented_(false),
default_handled_(false),
was_initialized_(true),
is_trusted_(false),
executed_listener_or_default_action_(false),
prevent_default_called_on_uncancelable_event_(false),
legacy_did_listeners_throw_flag_(false),
fire_only_capture_listeners_at_target_(false),
fire_only_non_capture_listeners_at_target_(false),
handling_passive_(PassiveMode::kNotPassiveDefault),
event_phase_(0),
current_target_(nullptr),
platform_time_stamp_(platform_time_stamp) {}
Event::Event(const AtomicString& event_type,
const EventInit& initializer,
TimeTicks platform_time_stamp)
: Event(event_type,
initializer.bubbles() ? Bubbles::kYes : Bubbles::kNo,
initializer.cancelable() ? Cancelable::kYes : Cancelable::kNo,
initializer.composed() ? ComposedMode::kComposed
: ComposedMode::kScoped,
platform_time_stamp) {}
Event::~Event() = default;
bool Event::IsScopedInV0() const {
return isTrusted() && is_event_type_scoped_in_v0_;
}
void Event::initEvent(const AtomicString& event_type_arg,
bool bubbles_arg,
bool cancelable_arg) {
initEvent(event_type_arg, bubbles_arg, cancelable_arg, nullptr);
}
void Event::initEvent(const AtomicString& event_type_arg,
bool bubbles_arg,
bool cancelable_arg,
EventTarget* related_target) {
if (IsBeingDispatched())
return;
was_initialized_ = true;
propagation_stopped_ = false;
immediate_propagation_stopped_ = false;
default_prevented_ = false;
is_trusted_ = false;
prevent_default_called_on_uncancelable_event_ = false;
type_ = event_type_arg;
bubbles_ = bubbles_arg;
cancelable_ = cancelable_arg;
}
bool Event::legacyReturnValue(ScriptState* script_state) const {
bool return_value = !defaultPrevented();
if (return_value) {
UseCounter::Count(ExecutionContext::From(script_state),
WebFeature::kEventGetReturnValueTrue);
} else {
UseCounter::Count(ExecutionContext::From(script_state),
WebFeature::kEventGetReturnValueFalse);
}
return return_value;
}
void Event::setLegacyReturnValue(ScriptState* script_state, bool return_value) {
if (return_value) {
UseCounter::Count(ExecutionContext::From(script_state),
WebFeature::kEventSetReturnValueTrue);
} else {
UseCounter::Count(ExecutionContext::From(script_state),
WebFeature::kEventSetReturnValueFalse);
}
SetDefaultPrevented(!return_value);
}
const AtomicString& Event::InterfaceName() const {
return EventNames::Event;
}
bool Event::HasInterface(const AtomicString& name) const {
return InterfaceName() == name;
}
bool Event::IsUIEvent() const {
return false;
}
bool Event::IsMouseEvent() const {
return false;
}
bool Event::IsFocusEvent() const {
return false;
}
bool Event::IsKeyboardEvent() const {
return false;
}
bool Event::IsTouchEvent() const {
return false;
}
bool Event::IsGestureEvent() const {
return false;
}
bool Event::IsWheelEvent() const {
return false;
}
bool Event::IsPointerEvent() const {
return false;
}
bool Event::IsInputEvent() const {
return false;
}
bool Event::IsDragEvent() const {
return false;
}
bool Event::IsCompositionEvent() const {
return false;
}
bool Event::IsActivateInvisibleEvent() const {
return false;
}
bool Event::IsClipboardEvent() const {
return false;
}
bool Event::IsBeforeTextInsertedEvent() const {
return false;
}
bool Event::IsBeforeUnloadEvent() const {
return false;
}
bool Event::IsErrorEvent() const {
return false;
}
void Event::preventDefault() {
if (handling_passive_ != PassiveMode::kNotPassive &&
handling_passive_ != PassiveMode::kNotPassiveDefault) {
prevent_default_called_during_passive_ = true;
const LocalDOMWindow* window =
event_path_ ? event_path_->GetWindowEventContext().Window() : nullptr;
if (window && handling_passive_ == PassiveMode::kPassive) {
window->PrintErrorMessage(
"Unable to preventDefault inside passive event listener invocation.");
}
return;
}
if (cancelable_)
default_prevented_ = true;
else
prevent_default_called_on_uncancelable_event_ = true;
}
void Event::SetTarget(EventTarget* target) {
if (target_ == target)
return;
target_ = target;
if (target_)
ReceivedTarget();
}
void Event::DoneDispatchingEventAtCurrentTarget() {
SetExecutedListenerOrDefaultAction();
}
void Event::SetRelatedTargetIfExists(EventTarget* related_target) {
if (IsMouseEvent()) {
ToMouseEvent(this)->SetRelatedTarget(related_target);
} else if (IsPointerEvent()) {
ToPointerEvent(this)->SetRelatedTarget(related_target);
} else if (IsFocusEvent()) {
ToFocusEvent(this)->SetRelatedTarget(related_target);
}
}
void Event::ReceivedTarget() {}
void Event::SetUnderlyingEvent(Event* ue) {
// Prohibit creation of a cycle -- just do nothing in that case.
for (Event* e = ue; e; e = e->UnderlyingEvent())
if (e == this)
return;
underlying_event_ = ue;
}
void Event::InitEventPath(Node& node) {
if (!event_path_) {
event_path_ = new EventPath(node, this);
} else {
event_path_->InitializeWith(node, this);
}
}
ScriptValue Event::path(ScriptState* script_state) const {
return ScriptValue(
script_state,
ToV8(PathInternal(script_state, kNonEmptyAfterDispatch), script_state));
}
HeapVector<Member<EventTarget>> Event::composedPath(
ScriptState* script_state) const {
return PathInternal(script_state, kEmptyAfterDispatch);
}
void Event::SetHandlingPassive(PassiveMode mode) {
handling_passive_ = mode;
prevent_default_called_during_passive_ = false;
}
HeapVector<Member<EventTarget>> Event::PathInternal(ScriptState* script_state,
EventPathMode mode) const {
if (target_)
HostsUsingFeatures::CountHostOrIsolatedWorldHumanReadableName(
script_state, *target_, HostsUsingFeatures::Feature::kEventPath);
if (!current_target_) {
DCHECK_EQ(Event::kNone, event_phase_);
if (!event_path_) {
// Before dispatching the event
return HeapVector<Member<EventTarget>>();
}
DCHECK(!event_path_->IsEmpty());
// After dispatching the event
if (mode == kEmptyAfterDispatch)
return HeapVector<Member<EventTarget>>();
return event_path_->Last().GetTreeScopeEventContext().EnsureEventPath(
*event_path_);
}
if (Node* node = current_target_->ToNode()) {
DCHECK(event_path_);
for (auto& context : event_path_->NodeEventContexts()) {
if (node == context.GetNode())
return context.GetTreeScopeEventContext().EnsureEventPath(*event_path_);
}
NOTREACHED();
}
if (LocalDOMWindow* window = current_target_->ToLocalDOMWindow()) {
if (event_path_ && !event_path_->IsEmpty()) {
return event_path_->TopNodeEventContext()
.GetTreeScopeEventContext()
.EnsureEventPath(*event_path_);
}
return HeapVector<Member<EventTarget>>(1, window);
}
return HeapVector<Member<EventTarget>>();
}
EventTarget* Event::currentTarget() const {
if (!current_target_)
return nullptr;
Node* node = current_target_->ToNode();
if (node && node->IsSVGElement()) {
if (SVGElement* svg_element = ToSVGElement(node)->CorrespondingElement())
return svg_element;
}
return current_target_.Get();
}
double Event::timeStamp(ScriptState* script_state) const {
double time_stamp = 0;
if (script_state && LocalDOMWindow::From(script_state)) {
WindowPerformance* performance =
DOMWindowPerformance::performance(*LocalDOMWindow::From(script_state));
time_stamp =
performance->MonotonicTimeToDOMHighResTimeStamp(platform_time_stamp_);
}
return time_stamp;
}
void Event::setCancelBubble(ScriptState* script_state, bool cancel) {
if (cancel)
propagation_stopped_ = true;
}
DispatchEventResult Event::DispatchEvent(EventDispatcher& dispatcher) {
return dispatcher.Dispatch();
}
void Event::Trace(blink::Visitor* visitor) {
visitor->Trace(current_target_);
visitor->Trace(target_);
visitor->Trace(underlying_event_);
visitor->Trace(event_path_);
ScriptWrappable::Trace(visitor);
}
} // namespace blink