1
0
Fork 0
mirror of https://github.com/LadybirdBrowser/ladybird.git synced 2025-06-09 17:44:56 +09:00

LibWeb: Correctly implement event listeners default passive attribute

This commit implements the default value of the passive attribute of
event listeners according to the spec.
This commit is contained in:
Glenn Skrzypczak 2024-12-24 17:52:52 +01:00 committed by Tim Ledbetter
parent 4c7cd05078
commit 08589741f5
Notes: github-actions[bot] 2024-12-25 14:58:22 +00:00
6 changed files with 82 additions and 49 deletions

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2022, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2024, Glenn Skrzypczak <glenn.skrzypczak@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -35,8 +36,8 @@ public:
// capture (a boolean, initially false)
bool capture { false };
// passive (a boolean, initially false)
bool passive { false };
// passive (null or a boolean, initially null)
Optional<bool> passive;
// once (a boolean, initially false)
bool once { false };

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2020-2022, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2024, Glenn Skrzypczak <glenn.skrzypczak@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -81,7 +82,7 @@ bool EventDispatcher::inner_invoke(Event& event, Vector<GC::Root<DOM::DOMEventLi
}
// 9. If listeners passive is true, then set events in passive listener flag.
if (listener->passive)
if (listener->passive == true)
event.set_in_passive_listener(true);
// FIXME: 10. If global is a Window object, then record timing info for event listener given event and listener.

View file

@ -1,6 +1,7 @@
/*
* Copyright (c) 2020-2022, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2022, Luke Wilde <lukew@serenityos.org>
* Copyright (c) 2024, Glenn Skrzypczak <glenn.skrzypczak@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -110,7 +111,7 @@ static bool flatten_event_listener_options(Variant<AddEventListenerOptions, bool
struct FlattenedAddEventListenerOptions {
bool capture { false };
bool passive { false };
Optional<bool> passive;
bool once { false };
GC::Ptr<AbortSignal> signal;
};
@ -121,22 +122,25 @@ static FlattenedAddEventListenerOptions flatten_add_event_listener_options(Varia
// 1. Let capture be the result of flattening options.
bool capture = flatten_event_listener_options(options);
// 2. Let once and passive be false.
// 2. Let once be false.
bool once = false;
bool passive = false;
// 3. Let signal be null.
// 3. Let passive and signal be null.
Optional<bool> passive;
GC::Ptr<AbortSignal> signal;
// 4. If options is a dictionary, then:
if (options.has<AddEventListenerOptions>()) {
auto& add_event_listener_options = options.get<AddEventListenerOptions>();
auto const& add_event_listener_options = options.get<AddEventListenerOptions>();
// 1. Set passive to options["passive"] and once to options["once"].
passive = add_event_listener_options.passive;
// 1. Set once to options["once"].
once = add_event_listener_options.once;
// 2. If options["signal"] exists, then set signal to options["signal"].
// 2. If options["passive"] exists, then set passive to options["passive"].
if (add_event_listener_options.passive.has_value())
passive = add_event_listener_options.passive;
// 3. If options["signal"] exists, then set signal to options["signal"].
if (add_event_listener_options.signal)
signal = add_event_listener_options.signal;
}
@ -145,6 +149,28 @@ static FlattenedAddEventListenerOptions flatten_add_event_listener_options(Varia
return FlattenedAddEventListenerOptions { .capture = capture, .passive = passive, .once = once, .signal = signal.ptr() };
}
// https://dom.spec.whatwg.org/#default-passive-value
static bool default_passive_value(FlyString const& type, EventTarget* event_target)
{
// 1. Return true if all of the following are true:
// - type is one of "touchstart", "touchmove", "wheel", or "mousewheel".
// - eventTarget is a Window object, or is a node whose node document is eventTarget, or is a node whose node documents document element is eventTarget,
// or is a node whose node documents body element is eventTarget.
if (AK::first_is_one_of(type, "touchstart"sv, "touchmove"sv, "wheel"sv, "mousewheel"sv)) {
if (is<HTML::Window>(event_target))
return true;
if (is<Node>(event_target)) {
auto* node = verify_cast<Node>(event_target);
if (&node->document() == event_target || node->document().document_element() == event_target || node->document().body() == event_target)
return true;
}
}
// 2. Return false.
return false;
}
// https://dom.spec.whatwg.org/#dom-eventtarget-addeventlistener
void EventTarget::add_event_listener(FlyString const& type, IDLEventListener* callback, Variant<AddEventListenerOptions, bool> const& options)
{
@ -186,7 +212,12 @@ void EventTarget::add_an_event_listener(DOMEventListener& listener)
if (!listener.callback)
return;
// 4. If eventTargets event listener list does not contain an event listener whose type is listeners type, callback is listeners callback,
// 4. If listeners passive is null, then set it to the default passive value given listeners type and eventTarget.
if (!listener.passive.has_value()) {
listener.passive = default_passive_value(listener.type, this);
}
// 5. If eventTargets event listener list does not contain an event listener whose type is listeners type, callback is listeners callback,
// and capture is listeners capture, then append listener to eventTargets event listener list.
auto it = event_listener_list.find_if([&](auto& entry) {
return entry->type == listener.type
@ -196,7 +227,7 @@ void EventTarget::add_an_event_listener(DOMEventListener& listener)
if (it == event_listener_list.end())
event_listener_list.append(listener);
// 5. If listeners signal is not null, then add the following abort steps to it:
// 6. If listeners signal is not null, then add the following abort steps to it:
if (listener.signal) {
// NOTE: `this` and `listener` are protected by AbortSignal using GC::HeapFunction.
listener.signal->add_abort_algorithm([this, &listener] {

View file

@ -20,7 +20,7 @@ dictionary EventListenerOptions {
};
dictionary AddEventListenerOptions : EventListenerOptions {
boolean passive = false;
boolean passive;
boolean once = false;
AbortSignal signal;
};

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2020-2022, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2024, Glenn Skrzypczak <glenn.skrzypczak@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -19,7 +20,7 @@ struct EventListenerOptions {
};
struct AddEventListenerOptions : public EventListenerOptions {
bool passive { false };
Optional<bool> passive;
bool once { false };
GC::Ptr<AbortSignal> signal;
};

View file

@ -2,82 +2,81 @@ Harness status: OK
Found 100 tests
68 Pass
32 Fail
Fail touchstart listener is passive by default for Window
Fail touchstart listener is passive with {passive:undefined} for Window
100 Pass
Pass touchstart listener is passive by default for Window
Pass touchstart listener is passive with {passive:undefined} for Window
Pass touchstart listener is non-passive with {passive:false} for Window
Pass touchstart listener is passive with {passive:true} for Window
Fail touchstart listener is passive by default for HTMLDocument
Fail touchstart listener is passive with {passive:undefined} for HTMLDocument
Pass touchstart listener is passive by default for HTMLDocument
Pass touchstart listener is passive with {passive:undefined} for HTMLDocument
Pass touchstart listener is non-passive with {passive:false} for HTMLDocument
Pass touchstart listener is passive with {passive:true} for HTMLDocument
Fail touchstart listener is passive by default for HTMLHtmlElement
Fail touchstart listener is passive with {passive:undefined} for HTMLHtmlElement
Pass touchstart listener is passive by default for HTMLHtmlElement
Pass touchstart listener is passive with {passive:undefined} for HTMLHtmlElement
Pass touchstart listener is non-passive with {passive:false} for HTMLHtmlElement
Pass touchstart listener is passive with {passive:true} for HTMLHtmlElement
Fail touchstart listener is passive by default for HTMLBodyElement
Fail touchstart listener is passive with {passive:undefined} for HTMLBodyElement
Pass touchstart listener is passive by default for HTMLBodyElement
Pass touchstart listener is passive with {passive:undefined} for HTMLBodyElement
Pass touchstart listener is non-passive with {passive:false} for HTMLBodyElement
Pass touchstart listener is passive with {passive:true} for HTMLBodyElement
Pass touchstart listener is non-passive by default for HTMLDivElement
Pass touchstart listener is non-passive with {passive:undefined} for HTMLDivElement
Pass touchstart listener is non-passive with {passive:false} for HTMLDivElement
Pass touchstart listener is passive with {passive:true} for HTMLDivElement
Fail touchmove listener is passive by default for Window
Fail touchmove listener is passive with {passive:undefined} for Window
Pass touchmove listener is passive by default for Window
Pass touchmove listener is passive with {passive:undefined} for Window
Pass touchmove listener is non-passive with {passive:false} for Window
Pass touchmove listener is passive with {passive:true} for Window
Fail touchmove listener is passive by default for HTMLDocument
Fail touchmove listener is passive with {passive:undefined} for HTMLDocument
Pass touchmove listener is passive by default for HTMLDocument
Pass touchmove listener is passive with {passive:undefined} for HTMLDocument
Pass touchmove listener is non-passive with {passive:false} for HTMLDocument
Pass touchmove listener is passive with {passive:true} for HTMLDocument
Fail touchmove listener is passive by default for HTMLHtmlElement
Fail touchmove listener is passive with {passive:undefined} for HTMLHtmlElement
Pass touchmove listener is passive by default for HTMLHtmlElement
Pass touchmove listener is passive with {passive:undefined} for HTMLHtmlElement
Pass touchmove listener is non-passive with {passive:false} for HTMLHtmlElement
Pass touchmove listener is passive with {passive:true} for HTMLHtmlElement
Fail touchmove listener is passive by default for HTMLBodyElement
Fail touchmove listener is passive with {passive:undefined} for HTMLBodyElement
Pass touchmove listener is passive by default for HTMLBodyElement
Pass touchmove listener is passive with {passive:undefined} for HTMLBodyElement
Pass touchmove listener is non-passive with {passive:false} for HTMLBodyElement
Pass touchmove listener is passive with {passive:true} for HTMLBodyElement
Pass touchmove listener is non-passive by default for HTMLDivElement
Pass touchmove listener is non-passive with {passive:undefined} for HTMLDivElement
Pass touchmove listener is non-passive with {passive:false} for HTMLDivElement
Pass touchmove listener is passive with {passive:true} for HTMLDivElement
Fail wheel listener is passive by default for Window
Fail wheel listener is passive with {passive:undefined} for Window
Pass wheel listener is passive by default for Window
Pass wheel listener is passive with {passive:undefined} for Window
Pass wheel listener is non-passive with {passive:false} for Window
Pass wheel listener is passive with {passive:true} for Window
Fail wheel listener is passive by default for HTMLDocument
Fail wheel listener is passive with {passive:undefined} for HTMLDocument
Pass wheel listener is passive by default for HTMLDocument
Pass wheel listener is passive with {passive:undefined} for HTMLDocument
Pass wheel listener is non-passive with {passive:false} for HTMLDocument
Pass wheel listener is passive with {passive:true} for HTMLDocument
Fail wheel listener is passive by default for HTMLHtmlElement
Fail wheel listener is passive with {passive:undefined} for HTMLHtmlElement
Pass wheel listener is passive by default for HTMLHtmlElement
Pass wheel listener is passive with {passive:undefined} for HTMLHtmlElement
Pass wheel listener is non-passive with {passive:false} for HTMLHtmlElement
Pass wheel listener is passive with {passive:true} for HTMLHtmlElement
Fail wheel listener is passive by default for HTMLBodyElement
Fail wheel listener is passive with {passive:undefined} for HTMLBodyElement
Pass wheel listener is passive by default for HTMLBodyElement
Pass wheel listener is passive with {passive:undefined} for HTMLBodyElement
Pass wheel listener is non-passive with {passive:false} for HTMLBodyElement
Pass wheel listener is passive with {passive:true} for HTMLBodyElement
Pass wheel listener is non-passive by default for HTMLDivElement
Pass wheel listener is non-passive with {passive:undefined} for HTMLDivElement
Pass wheel listener is non-passive with {passive:false} for HTMLDivElement
Pass wheel listener is passive with {passive:true} for HTMLDivElement
Fail mousewheel listener is passive by default for Window
Fail mousewheel listener is passive with {passive:undefined} for Window
Pass mousewheel listener is passive by default for Window
Pass mousewheel listener is passive with {passive:undefined} for Window
Pass mousewheel listener is non-passive with {passive:false} for Window
Pass mousewheel listener is passive with {passive:true} for Window
Fail mousewheel listener is passive by default for HTMLDocument
Fail mousewheel listener is passive with {passive:undefined} for HTMLDocument
Pass mousewheel listener is passive by default for HTMLDocument
Pass mousewheel listener is passive with {passive:undefined} for HTMLDocument
Pass mousewheel listener is non-passive with {passive:false} for HTMLDocument
Pass mousewheel listener is passive with {passive:true} for HTMLDocument
Fail mousewheel listener is passive by default for HTMLHtmlElement
Fail mousewheel listener is passive with {passive:undefined} for HTMLHtmlElement
Pass mousewheel listener is passive by default for HTMLHtmlElement
Pass mousewheel listener is passive with {passive:undefined} for HTMLHtmlElement
Pass mousewheel listener is non-passive with {passive:false} for HTMLHtmlElement
Pass mousewheel listener is passive with {passive:true} for HTMLHtmlElement
Fail mousewheel listener is passive by default for HTMLBodyElement
Fail mousewheel listener is passive with {passive:undefined} for HTMLBodyElement
Pass mousewheel listener is passive by default for HTMLBodyElement
Pass mousewheel listener is passive with {passive:undefined} for HTMLBodyElement
Pass mousewheel listener is non-passive with {passive:false} for HTMLBodyElement
Pass mousewheel listener is passive with {passive:true} for HTMLBodyElement
Pass mousewheel listener is non-passive by default for HTMLDivElement