1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 14:27:35 +00:00

LibWeb: Make DOM::Event and all its subclasses GC-allocated

This commit is contained in:
Andreas Kling 2022-08-08 22:29:40 +02:00
parent a4ddb0ef87
commit 7c3db526b0
76 changed files with 892 additions and 565 deletions

View file

@ -60,7 +60,7 @@ void AbortSignal::signal_abort(JS::Value reason)
m_abort_algorithms.clear();
// 5. Fire an event named abort at signal.
dispatch_event(Event::create(HTML::EventNames::abort));
dispatch_event(*Event::create(verify_cast<Bindings::WindowObject>(wrapper()->global_object()), HTML::EventNames::abort));
}
void AbortSignal::set_onabort(Bindings::CallbackType* event_handler)

View file

@ -1,15 +1,44 @@
/*
* Copyright (c) 2021, Luke Wilde <lukew@serenityos.org>
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Bindings/CustomEventPrototype.h>
#include <LibWeb/Bindings/WindowObject.h>
#include <LibWeb/DOM/CustomEvent.h>
namespace Web::DOM {
CustomEvent* CustomEvent::create(Bindings::WindowObject& window_object, FlyString const& event_name, CustomEventInit const& event_init)
{
return window_object.heap().allocate<CustomEvent>(window_object.realm(), window_object, event_name, event_init);
}
CustomEvent* CustomEvent::create_with_global_object(Bindings::WindowObject& window_object, FlyString const& event_name, CustomEventInit const& event_init)
{
return create(window_object, event_name, event_init);
}
CustomEvent::CustomEvent(Bindings::WindowObject& window_object, FlyString const& event_name)
: Event(window_object, event_name)
{
set_prototype(&window_object.ensure_web_prototype<Bindings::CustomEventPrototype>("CustomEvent"));
}
CustomEvent::CustomEvent(Bindings::WindowObject& window_object, FlyString const& event_name, CustomEventInit const& event_init)
: Event(window_object, event_name, event_init)
, m_detail(event_init.detail)
{
set_prototype(&window_object.ensure_web_prototype<Bindings::CustomEventPrototype>("CustomEvent"));
}
CustomEvent::~CustomEvent() = default;
void CustomEvent::visit_edges(JS::Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_detail);
}
@ -21,7 +50,7 @@ void CustomEvent::init_custom_event(String const& type, bool bubbles, bool cance
return;
// 2. Initialize this with type, bubbles, and cancelable.
initialize(type, bubbles, cancelable);
initialize_event(type, bubbles, cancelable);
// 3. Set thiss detail attribute to detail.
m_detail = detail;

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2021, Luke Wilde <lukew@serenityos.org>
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -16,41 +17,34 @@ struct CustomEventInit : public EventInit {
// https://dom.spec.whatwg.org/#customevent
class CustomEvent : public Event {
JS_OBJECT(CustomEvent, Event);
public:
using WrapperType = Bindings::CustomEventWrapper;
static CustomEvent* create(Bindings::WindowObject&, FlyString const& event_name, CustomEventInit const& event_init = {});
static CustomEvent* create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, CustomEventInit const& event_init);
static NonnullRefPtr<CustomEvent> create(FlyString const& event_name, CustomEventInit const& event_init = {})
{
return adopt_ref(*new CustomEvent(event_name, event_init));
}
static NonnullRefPtr<CustomEvent> create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, CustomEventInit const& event_init)
{
return CustomEvent::create(event_name, event_init);
}
CustomEvent(Bindings::WindowObject&, FlyString const& event_name);
CustomEvent(Bindings::WindowObject&, FlyString const& event_name, CustomEventInit const& event_init);
virtual ~CustomEvent() override = default;
virtual ~CustomEvent() override;
CustomEvent& impl() { return *this; }
// https://dom.spec.whatwg.org/#dom-customevent-detail
JS::Value detail() const { return m_detail; }
void visit_edges(JS::Cell::Visitor&);
virtual void visit_edges(JS::Cell::Visitor&) override;
void init_custom_event(String const& type, bool bubbles, bool cancelable, JS::Value detail);
private:
explicit CustomEvent(FlyString const& event_name)
: Event(event_name)
{
}
CustomEvent(FlyString const& event_name, CustomEventInit const& event_init)
: Event(event_name, event_init)
, m_detail(event_init.detail)
{
}
// https://dom.spec.whatwg.org/#dom-customevent-initcustomevent-type-bubbles-cancelable-detail-detail
JS::Value m_detail { JS::js_null() };
};
}
namespace Web::Bindings {
inline JS::Object* wrap(JS::Realm&, Web::DOM::CustomEvent& object) { return &object; }
using CustomEventWrapper = Web::DOM::CustomEvent;
}

View file

@ -1,6 +1,6 @@
#import <DOM/Event.idl>
[Exposed=(Window,Worker), CustomVisit]
[Exposed=(Window,Worker), NoInstanceWrapper]
interface CustomEvent : Event {
constructor(DOMString type, optional CustomEventInit eventInitDict = {});

View file

@ -1160,51 +1160,53 @@ NonnullRefPtr<Range> Document::create_range()
}
// https://dom.spec.whatwg.org/#dom-document-createevent
DOM::ExceptionOr<NonnullRefPtr<Event>> Document::create_event(String const& interface)
DOM::ExceptionOr<JS::NonnullGCPtr<Event>> Document::create_event(String const& interface)
{
auto& window_object = preferred_window_object();
// NOTE: This is named event here, since we do step 5 and 6 as soon as possible for each case.
// 1. Let constructor be null.
RefPtr<Event> event;
JS::GCPtr<Event> event;
// 2. If interface is an ASCII case-insensitive match for any of the strings in the first column in the following table,
// then set constructor to the interface in the second column on the same row as the matching string:
auto interface_lowercase = interface.to_lowercase();
if (interface_lowercase == "beforeunloadevent") {
event = Event::create(""); // FIXME: Create BeforeUnloadEvent
event = Event::create(window_object, ""); // FIXME: Create BeforeUnloadEvent
} else if (interface_lowercase == "compositionevent") {
event = Event::create(""); // FIXME: Create CompositionEvent
event = Event::create(window_object, ""); // FIXME: Create CompositionEvent
} else if (interface_lowercase == "customevent") {
event = CustomEvent::create("");
event = CustomEvent::create(window_object, "");
} else if (interface_lowercase == "devicemotionevent") {
event = Event::create(""); // FIXME: Create DeviceMotionEvent
event = Event::create(window_object, ""); // FIXME: Create DeviceMotionEvent
} else if (interface_lowercase == "deviceorientationevent") {
event = Event::create(""); // FIXME: Create DeviceOrientationEvent
event = Event::create(window_object, ""); // FIXME: Create DeviceOrientationEvent
} else if (interface_lowercase == "dragevent") {
event = Event::create(""); // FIXME: Create DragEvent
event = Event::create(window_object, ""); // FIXME: Create DragEvent
} else if (interface_lowercase.is_one_of("event", "events")) {
event = Event::create("");
event = Event::create(window_object, "");
} else if (interface_lowercase == "focusevent") {
event = UIEvents::FocusEvent::create("");
event = UIEvents::FocusEvent::create(window_object, "");
} else if (interface_lowercase == "hashchangeevent") {
event = Event::create(""); // FIXME: Create HashChangeEvent
event = Event::create(window_object, ""); // FIXME: Create HashChangeEvent
} else if (interface_lowercase == "htmlevents") {
event = Event::create("");
event = Event::create(window_object, "");
} else if (interface_lowercase == "keyboardevent") {
event = UIEvents::KeyboardEvent::create("");
event = UIEvents::KeyboardEvent::create(window_object, "");
} else if (interface_lowercase == "messageevent") {
event = HTML::MessageEvent::create("");
event = HTML::MessageEvent::create(window_object, "");
} else if (interface_lowercase.is_one_of("mouseevent", "mouseevents")) {
event = UIEvents::MouseEvent::create("");
event = UIEvents::MouseEvent::create(window_object, "");
} else if (interface_lowercase == "storageevent") {
event = Event::create(""); // FIXME: Create StorageEvent
event = Event::create(window_object, ""); // FIXME: Create StorageEvent
} else if (interface_lowercase == "svgevents") {
event = Event::create("");
event = Event::create(window_object, "");
} else if (interface_lowercase == "textevent") {
event = Event::create(""); // FIXME: Create CompositionEvent
event = Event::create(window_object, ""); // FIXME: Create CompositionEvent
} else if (interface_lowercase == "touchevent") {
event = Event::create(""); // FIXME: Create TouchEvent
event = Event::create(window_object, ""); // FIXME: Create TouchEvent
} else if (interface_lowercase.is_one_of("uievent", "uievents")) {
event = UIEvents::UIEvent::create("");
event = UIEvents::UIEvent::create(window_object, "");
}
// 3. If constructor is null, then throw a "NotSupportedError" DOMException.
@ -1228,7 +1230,7 @@ DOM::ExceptionOr<NonnullRefPtr<Event>> Document::create_event(String const& inte
event->set_initialized(false);
// 10. Return event.
return event.release_nonnull();
return JS::NonnullGCPtr(*event);
}
void Document::set_pending_parsing_blocking_script(Badge<HTML::HTMLScriptElement>, HTML::HTMLScriptElement* script)
@ -1408,7 +1410,7 @@ void Document::update_readiness(HTML::DocumentReadyState readiness_value)
// FIXME: 3. Otherwise, if readinessValue is "interactive", and document's load timing info's DOM interactive time is 0, then set document's load timing info's DOM interactive time to now.
// 3. Fire an event named readystatechange at document.
dispatch_event(Event::create(HTML::EventNames::readystatechange));
dispatch_event(*Event::create(preferred_window_object(), HTML::EventNames::readystatechange));
}
Page* Document::page()
@ -1448,8 +1450,8 @@ void Document::completely_finish_loading()
}
// Otherwise, if container is non-null, then queue an element task on the DOM manipulation task source given container to fire an event named load at container.
else if (container) {
container->queue_an_element_task(HTML::Task::Source::DOMManipulation, [container]() mutable {
container->dispatch_event(DOM::Event::create(HTML::EventNames::load));
container->queue_an_element_task(HTML::Task::Source::DOMManipulation, [container, this]() mutable {
container->dispatch_event(*DOM::Event::create(preferred_window_object(), HTML::EventNames::load));
});
}
}
@ -1560,7 +1562,7 @@ void Document::run_the_resize_steps()
return;
m_last_viewport_size = viewport_size;
window().dispatch_event(DOM::Event::create(UIEvents::EventNames::resize));
window().dispatch_event(*DOM::Event::create(preferred_window_object(), UIEvents::EventNames::resize));
update_layout();
}
@ -1596,9 +1598,9 @@ void Document::evaluate_media_queries_and_report_changes()
CSS::MediaQueryListEventInit init;
init.media = media_query_list->media();
init.matches = now_matches;
auto event = CSS::MediaQueryListEvent::create(HTML::EventNames::change, init);
auto event = CSS::MediaQueryListEvent::create(preferred_window_object(), HTML::EventNames::change, init);
event->set_is_trusted(true);
media_query_list->dispatch_event(event);
media_query_list->dispatch_event(*event);
}
}

View file

@ -204,7 +204,7 @@ public:
NonnullRefPtr<Text> create_text_node(String const& data);
NonnullRefPtr<Comment> create_comment(String const& data);
NonnullRefPtr<Range> create_range();
ExceptionOr<NonnullRefPtr<Event>> create_event(String const& interface);
ExceptionOr<JS::NonnullGCPtr<Event>> create_event(String const& interface);
void set_pending_parsing_blocking_script(Badge<HTML::HTMLScriptElement>, HTML::HTMLScriptElement*);
HTML::HTMLScriptElement* pending_parsing_blocking_script() { return m_pending_parsing_blocking_script; }

View file

@ -1,17 +1,47 @@
/*
* Copyright (c) 2020, the SerenityOS developers.
* Copyright (c) 2021, Luke Wilde <lukew@serenityos.org>
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TypeCasts.h>
#include <LibWeb/Bindings/EventPrototype.h>
#include <LibWeb/Bindings/WindowObject.h>
#include <LibWeb/DOM/Event.h>
#include <LibWeb/DOM/Node.h>
#include <LibWeb/DOM/ShadowRoot.h>
namespace Web::DOM {
JS::NonnullGCPtr<Event> Event::create(Bindings::WindowObject& window_object, FlyString const& event_name, EventInit const& event_init)
{
return *window_object.heap().allocate<Event>(window_object.realm(), window_object, event_name, event_init);
}
JS::NonnullGCPtr<Event> Event::create_with_global_object(Bindings::WindowObject& window_object, FlyString const& event_name, EventInit const& event_init)
{
return create(window_object, event_name, event_init);
}
Event::Event(Bindings::WindowObject& window_object, FlyString const& type)
: PlatformObject(window_object.ensure_web_prototype<Bindings::EventPrototype>("Event"))
, m_type(type)
, m_initialized(true)
{
}
Event::Event(Bindings::WindowObject& window_object, FlyString const& type, EventInit const& event_init)
: PlatformObject(window_object.ensure_web_prototype<Bindings::EventPrototype>("Event"))
, m_type(type)
, m_bubbles(event_init.bubbles)
, m_cancelable(event_init.cancelable)
, m_composed(event_init.composed)
, m_initialized(true)
{
}
// https://dom.spec.whatwg.org/#concept-event-path-append
void Event::append_to_path(EventTarget& invocation_target, RefPtr<EventTarget> shadow_adjusted_target, RefPtr<EventTarget> related_target, TouchTargetList& touch_targets, bool slot_in_closed_tree)
{
@ -46,7 +76,7 @@ void Event::set_cancelled_flag()
}
// https://dom.spec.whatwg.org/#concept-event-initialize
void Event::initialize(String const& type, bool bubbles, bool cancelable)
void Event::initialize_event(String const& type, bool bubbles, bool cancelable)
{
// 1. Set events initialized flag.
m_initialized = true;
@ -80,7 +110,7 @@ void Event::init_event(String const& type, bool bubbles, bool cancelable)
return;
// 2. Initialize this with type, bubbles, and cancelable.
initialize(type, bubbles, cancelable);
initialize_event(type, bubbles, cancelable);
}
// https://dom.spec.whatwg.org/#dom-event-timestamp

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2020-2022, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -7,8 +7,8 @@
#pragma once
#include <AK/FlyString.h>
#include <LibWeb/Bindings/PlatformObject.h>
#include <LibWeb/Bindings/WindowObject.h>
#include <LibWeb/Bindings/Wrappable.h>
#include <LibWeb/DOM/EventTarget.h>
namespace Web::DOM {
@ -19,12 +19,10 @@ struct EventInit {
bool composed { false };
};
class Event
: public RefCounted<Event>
, public Bindings::Wrappable {
public:
using WrapperType = Bindings::EventWrapper;
class Event : public Bindings::PlatformObject {
JS_OBJECT(Event, Bindings::PlatformObject);
public:
enum Phase : u16 {
None = 0,
CapturingPhase = 1,
@ -47,17 +45,16 @@ public:
using Path = Vector<PathEntry>;
static NonnullRefPtr<Event> create(FlyString const& event_name, EventInit const& event_init = {})
{
return adopt_ref(*new Event(event_name, event_init));
}
static NonnullRefPtr<Event> create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, EventInit const& event_init)
{
return Event::create(event_name, event_init);
}
static JS::NonnullGCPtr<Event> create(Bindings::WindowObject&, FlyString const& event_name, EventInit const& event_init = {});
static JS::NonnullGCPtr<Event> create_with_global_object(Bindings::WindowObject&, FlyString const& event_name, EventInit const& event_init);
Event(Bindings::WindowObject&, FlyString const& type);
Event(Bindings::WindowObject&, FlyString const& type, EventInit const& event_init);
virtual ~Event() = default;
Event& impl() { return *this; }
double time_stamp() const;
FlyString const& type() const { return m_type; }
@ -149,21 +146,7 @@ public:
NonnullRefPtrVector<EventTarget> composed_path() const;
protected:
explicit Event(FlyString const& type)
: m_type(type)
, m_initialized(true)
{
}
Event(FlyString const& type, EventInit const& event_init)
: m_type(type)
, m_bubbles(event_init.bubbles)
, m_cancelable(event_init.cancelable)
, m_composed(event_init.composed)
, m_initialized(true)
{
}
void initialize(String const&, bool, bool);
void initialize_event(String const&, bool, bool);
private:
FlyString m_type;
@ -195,3 +178,8 @@ private:
};
}
namespace Web::Bindings {
inline JS::Object* wrap(JS::Realm&, Web::DOM::Event& object) { return &object; }
using EventWrapper = Web::DOM::Event;
}

View file

@ -1,5 +1,6 @@
#import <DOM/EventTarget.idl>
[NoInstanceWrapper]
interface Event {
constructor(DOMString type, optional EventInit eventInitDict = {});

View file

@ -10,8 +10,6 @@
#include <LibJS/Runtime/FunctionObject.h>
#include <LibWeb/Bindings/EventTargetWrapper.h>
#include <LibWeb/Bindings/EventTargetWrapperFactory.h>
#include <LibWeb/Bindings/EventWrapper.h>
#include <LibWeb/Bindings/EventWrapperFactory.h>
#include <LibWeb/Bindings/IDLAbstractOperations.h>
#include <LibWeb/Bindings/WindowObject.h>
#include <LibWeb/DOM/AbortSignal.h>
@ -92,7 +90,7 @@ bool EventDispatcher::inner_invoke(Event& event, Vector<JS::Handle<DOM::DOMEvent
auto& global = realm.global_object();
// 7. Let currentEvent be undefined.
RefPtr<Event> current_event;
Event* current_event = nullptr;
// 8. If global is a Window object, then:
if (is<Bindings::WindowObject>(global)) {
@ -207,10 +205,10 @@ void EventDispatcher::invoke(Event::PathEntry& struct_, Event& event, Event::Pha
}
// https://dom.spec.whatwg.org/#concept-event-dispatch
bool EventDispatcher::dispatch(NonnullRefPtr<EventTarget> target, NonnullRefPtr<Event> event, bool legacy_target_override)
bool EventDispatcher::dispatch(NonnullRefPtr<EventTarget> target, Event& event, bool legacy_target_override)
{
// 1. Set events dispatch flag.
event->set_dispatched(true);
event.set_dispatched(true);
// 2. Let targetOverride be target, if legacy target override flag is not given, and targets associated Document otherwise. [HTML]
// NOTE: legacy target override flag is only used by HTML and only when target is a Window object.
@ -225,24 +223,24 @@ bool EventDispatcher::dispatch(NonnullRefPtr<EventTarget> target, NonnullRefPtr<
RefPtr<EventTarget> activation_target;
// 4. Let relatedTarget be the result of retargeting events relatedTarget against target.
RefPtr<EventTarget> related_target = retarget(event->related_target(), target);
RefPtr<EventTarget> related_target = retarget(event.related_target(), target);
bool clear_targets = false;
// 5. If target is not relatedTarget or target is events relatedTarget, then:
if (related_target != target || event->related_target() == target) {
if (related_target != target || event.related_target() == target) {
// 1. Let touchTargets be a new list.
Event::TouchTargetList touch_targets;
// 2. For each touchTarget of events touch target list, append the result of retargeting touchTarget against target to touchTargets.
for (auto& touch_target : event->touch_target_list()) {
for (auto& touch_target : event.touch_target_list()) {
touch_targets.append(retarget(touch_target, target));
}
// 3. Append to an event path with event, target, targetOverride, relatedTarget, touchTargets, and false.
event->append_to_path(*target, target_override, related_target, touch_targets, false);
event.append_to_path(*target, target_override, related_target, touch_targets, false);
// 4. Let isActivationEvent be true, if event is a MouseEvent object and events type attribute is "click"; otherwise false.
bool is_activation_event = is<UIEvents::MouseEvent>(*event) && event->type() == HTML::EventNames::click;
bool is_activation_event = is<UIEvents::MouseEvent>(event) && event.type() == HTML::EventNames::click;
// 5. If isActivationEvent is true and target has activation behavior, then set activationTarget to target.
if (is_activation_event && target->activation_behavior)
@ -265,13 +263,13 @@ bool EventDispatcher::dispatch(NonnullRefPtr<EventTarget> target, NonnullRefPtr<
// FIXME: 2. If parent is a slottable and is assigned, then set slottable to parent.
// 3. Let relatedTarget be the result of retargeting events relatedTarget against parent.
related_target = retarget(event->related_target(), parent);
related_target = retarget(event.related_target(), parent);
// 4. Let touchTargets be a new list.
touch_targets.clear();
// 5. For each touchTarget of events touch target list, append the result of retargeting touchTarget against parent to touchTargets.
for (auto& touch_target : event->touch_target_list()) {
for (auto& touch_target : event.touch_target_list()) {
touch_targets.append(retarget(touch_target, parent));
}
@ -279,11 +277,11 @@ bool EventDispatcher::dispatch(NonnullRefPtr<EventTarget> target, NonnullRefPtr<
if (is<HTML::Window>(parent)
|| (is<Node>(parent) && verify_cast<Node>(*target).root().is_shadow_including_inclusive_ancestor_of(verify_cast<Node>(*parent)))) {
// 1. If isActivationEvent is true, events bubbles attribute is true, activationTarget is null, and parent has activation behavior, then set activationTarget to parent.
if (is_activation_event && event->bubbles() && !activation_target && parent->activation_behavior)
if (is_activation_event && event.bubbles() && !activation_target && parent->activation_behavior)
activation_target = parent;
// 2. Append to an event path with event, parent, null, relatedTarget, touchTargets, and slot-in-closed-tree.
event->append_to_path(*parent, nullptr, related_target, touch_targets, slot_in_closed_tree);
event.append_to_path(*parent, nullptr, related_target, touch_targets, slot_in_closed_tree);
}
// 7. Otherwise, if parent is relatedTarget, then set parent to null.
@ -299,7 +297,7 @@ bool EventDispatcher::dispatch(NonnullRefPtr<EventTarget> target, NonnullRefPtr<
activation_target = target;
// 2. Append to an event path with event, parent, target, relatedTarget, touchTargets, and slot-in-closed-tree.
event->append_to_path(*parent, target, related_target, touch_targets, slot_in_closed_tree);
event.append_to_path(*parent, target, related_target, touch_targets, slot_in_closed_tree);
}
// 9. If parent is non-null, then set parent to the result of invoking parents get the parent with event.
@ -312,7 +310,7 @@ bool EventDispatcher::dispatch(NonnullRefPtr<EventTarget> target, NonnullRefPtr<
}
// 10. Let clearTargetsStruct be the last struct in events path whose shadow-adjusted target is non-null.
auto clear_targets_struct = event->path().last_matching([](auto& entry) {
auto clear_targets_struct = event.path().last_matching([](auto& entry) {
return !entry.shadow_adjusted_target.is_null();
});
@ -349,32 +347,32 @@ bool EventDispatcher::dispatch(NonnullRefPtr<EventTarget> target, NonnullRefPtr<
activation_target->legacy_pre_activation_behavior();
// 13. For each struct in events path, in reverse order:
for (auto& entry : event->path().in_reverse()) {
for (auto& entry : event.path().in_reverse()) {
// 1. If structs shadow-adjusted target is non-null, then set events eventPhase attribute to AT_TARGET.
if (entry.shadow_adjusted_target)
event->set_phase(Event::Phase::AtTarget);
event.set_phase(Event::Phase::AtTarget);
// 2. Otherwise, set events eventPhase attribute to CAPTURING_PHASE.
else
event->set_phase(Event::Phase::CapturingPhase);
event.set_phase(Event::Phase::CapturingPhase);
// 3. Invoke with struct, event, "capturing", and legacyOutputDidListenersThrowFlag if given.
invoke(entry, event, Event::Phase::CapturingPhase);
}
// 14. For each struct in events path:
for (auto& entry : event->path()) {
for (auto& entry : event.path()) {
// 1. If structs shadow-adjusted target is non-null, then set events eventPhase attribute to AT_TARGET.
if (entry.shadow_adjusted_target) {
event->set_phase(Event::Phase::AtTarget);
event.set_phase(Event::Phase::AtTarget);
}
// 2. Otherwise:
else {
// 1. If events bubbles attribute is false, then continue.
if (!event->bubbles())
if (!event.bubbles())
continue;
// 2. Set events eventPhase attribute to BUBBLING_PHASE.
event->set_phase(Event::Phase::BubblingPhase);
event.set_phase(Event::Phase::BubblingPhase);
}
// 3. Invoke with struct, event, "bubbling", and legacyOutputDidListenersThrowFlag if given.
@ -383,35 +381,35 @@ bool EventDispatcher::dispatch(NonnullRefPtr<EventTarget> target, NonnullRefPtr<
}
// 6. Set events eventPhase attribute to NONE.
event->set_phase(Event::Phase::None);
event.set_phase(Event::Phase::None);
// 7. Set events currentTarget attribute to null.
event->set_current_target(nullptr);
event.set_current_target(nullptr);
// 8. Set events path to the empty list.
event->clear_path();
event.clear_path();
// 9. Unset events dispatch flag, stop propagation flag, and stop immediate propagation flag.
event->set_dispatched(false);
event->set_stop_propagation(false);
event->set_stop_immediate_propagation(false);
event.set_dispatched(false);
event.set_stop_propagation(false);
event.set_stop_immediate_propagation(false);
// 10. If clearTargets, then:
if (clear_targets) {
// 1. Set events target to null.
event->set_target(nullptr);
event.set_target(nullptr);
// 2. Set events relatedTarget to null.
event->set_related_target(nullptr);
event.set_related_target(nullptr);
// 3. Set events touch target list to the empty list.
event->clear_touch_target_list();
event.clear_touch_target_list();
}
// 11. If activationTarget is non-null, then:
if (activation_target) {
// 1. If events canceled flag is unset, then run activationTargets activation behavior with event.
if (!event->cancelled()) {
if (!event.cancelled()) {
activation_target->activation_behavior(event);
activation_target->legacy_cancelled_activation_behavior_was_not_called();
}
@ -422,7 +420,7 @@ bool EventDispatcher::dispatch(NonnullRefPtr<EventTarget> target, NonnullRefPtr<
}
// 12. Return false if events canceled flag is set; otherwise true.
return !event->cancelled();
return !event.cancelled();
}
}

View file

@ -14,7 +14,7 @@ namespace Web::DOM {
class EventDispatcher {
public:
static bool dispatch(NonnullRefPtr<EventTarget>, NonnullRefPtr<Event>, bool legacy_target_override = false);
static bool dispatch(NonnullRefPtr<EventTarget>, Event&, bool legacy_target_override = false);
private:
static void invoke(Event::PathEntry&, Event&, Event::Phase);

View file

@ -15,8 +15,6 @@
#include <LibJS/Runtime/VM.h>
#include <LibWeb/Bindings/DocumentWrapper.h>
#include <LibWeb/Bindings/EventTargetWrapperFactory.h>
#include <LibWeb/Bindings/EventWrapper.h>
#include <LibWeb/Bindings/EventWrapperFactory.h>
#include <LibWeb/Bindings/IDLAbstractOperations.h>
#include <LibWeb/Bindings/MainThreadVM.h>
#include <LibWeb/DOM/AbortSignal.h>
@ -204,17 +202,17 @@ void EventTarget::remove_from_event_listener_list(DOMEventListener& listener)
}
// https://dom.spec.whatwg.org/#dom-eventtarget-dispatchevent
ExceptionOr<bool> EventTarget::dispatch_event_binding(NonnullRefPtr<Event> event)
ExceptionOr<bool> EventTarget::dispatch_event_binding(Event& event)
{
// 1. If events dispatch flag is set, or if its initialized flag is not set, then throw an "InvalidStateError" DOMException.
if (event->dispatched())
if (event.dispatched())
return DOM::InvalidStateError::create("The event is already being dispatched.");
if (!event->initialized())
if (!event.initialized())
return DOM::InvalidStateError::create("Cannot dispatch an uninitialized event.");
// 2. Initialize events isTrusted attribute to false.
event->set_is_trusted(false);
event.set_is_trusted(false);
// 3. Return the result of dispatching event to this.
return dispatch_event(event);
@ -736,9 +734,9 @@ void EventTarget::element_event_handler_attribute_changed(FlyString const& local
event_target->activate_event_handler(local_name, *event_handler);
}
bool EventTarget::dispatch_event(NonnullRefPtr<Event> event)
bool EventTarget::dispatch_event(Event& event)
{
return EventDispatcher::dispatch(*this, move(event));
return EventDispatcher::dispatch(*this, event);
}
}

View file

@ -36,8 +36,8 @@ public:
void add_event_listener_without_options(FlyString const& type, IDLEventListener& callback);
void remove_event_listener_without_options(FlyString const& type, IDLEventListener& callback);
virtual bool dispatch_event(NonnullRefPtr<Event>);
ExceptionOr<bool> dispatch_event_binding(NonnullRefPtr<Event>);
virtual bool dispatch_event(Event&);
ExceptionOr<bool> dispatch_event_binding(Event&);
virtual JS::Object* create_wrapper(JS::Realm&) = 0;

View file

@ -10,7 +10,6 @@
#include <AK/StringBuilder.h>
#include <LibJS/AST.h>
#include <LibJS/Runtime/FunctionObject.h>
#include <LibWeb/Bindings/EventWrapper.h>
#include <LibWeb/Bindings/MainThreadVM.h>
#include <LibWeb/Bindings/NodeWrapper.h>
#include <LibWeb/Bindings/NodeWrapperFactory.h>