2021-09-02 02:12:49 +01:00
/*
* Copyright ( c ) 2021 , Luke Wilde < lukew @ serenityos . org >
2024-09-08 21:10:52 +01:00
* Copyright ( c ) 2024 , Tim Ledbetter < tim . ledbetter @ ladybird . org >
2021-09-02 02:12:49 +01:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2024-04-27 12:09:58 +12:00
# include <LibWeb/Bindings/AbortSignalPrototype.h>
2022-09-25 16:15:49 -06:00
# include <LibWeb/Bindings/Intrinsics.h>
2021-09-02 02:12:49 +01:00
# include <LibWeb/DOM/AbortSignal.h>
# include <LibWeb/DOM/Document.h>
# include <LibWeb/DOM/EventDispatcher.h>
2021-10-01 01:09:11 +01:00
# include <LibWeb/HTML/EventHandler.h>
2024-02-26 17:52:32 +00:00
# include <LibWeb/HTML/Window.h>
# include <LibWeb/HTML/WindowOrWorkerGlobalScope.h>
2021-09-02 02:12:49 +01:00
namespace Web : : DOM {
2024-11-15 04:01:23 +13:00
GC_DEFINE_ALLOCATOR ( AbortSignal ) ;
2023-11-19 19:47:52 +01:00
2024-11-15 04:01:23 +13:00
WebIDL : : ExceptionOr < GC : : Ref < AbortSignal > > AbortSignal : : construct_impl ( JS : : Realm & realm )
2021-09-02 02:12:49 +01:00
{
2024-11-14 05:50:17 +13:00
return realm . create < AbortSignal > ( realm ) ;
2022-09-25 16:15:49 -06:00
}
AbortSignal : : AbortSignal ( JS : : Realm & realm )
: EventTarget ( realm )
{
2023-01-10 06:28:20 -05:00
}
2023-08-07 08:41:28 +02:00
void AbortSignal : : initialize ( JS : : Realm & realm )
2023-01-10 06:28:20 -05:00
{
2023-08-07 08:41:28 +02:00
Base : : initialize ( realm ) ;
2024-03-16 13:13:08 +01:00
WEB_SET_PROTOTYPE_FOR_INTERFACE ( AbortSignal ) ;
2021-09-02 02:12:49 +01:00
}
// https://dom.spec.whatwg.org/#abortsignal-add
2023-09-25 18:45:20 +02:00
void AbortSignal : : add_abort_algorithm ( Function < void ( ) > abort_algorithm )
2021-09-02 02:12:49 +01:00
{
2021-12-10 20:05:12 +00:00
// 1. If signal is aborted, then return.
if ( aborted ( ) )
2021-09-02 02:12:49 +01:00
return ;
2021-12-10 20:05:12 +00:00
// 2. Append algorithm to signal’ s abort algorithms.
2024-11-15 04:01:23 +13:00
m_abort_algorithms . append ( GC : : create_function ( vm ( ) . heap ( ) , move ( abort_algorithm ) ) ) ;
2021-09-02 02:12:49 +01:00
}
// https://dom.spec.whatwg.org/#abortsignal-signal-abort
2021-12-10 20:05:12 +00:00
void AbortSignal : : signal_abort ( JS : : Value reason )
2021-09-02 02:12:49 +01:00
{
2021-12-10 20:05:12 +00:00
// 1. If signal is aborted, then return.
if ( aborted ( ) )
2021-09-02 02:12:49 +01:00
return ;
2021-12-10 20:05:12 +00:00
// 2. Set signal’ s abort reason to reason if it is given; otherwise to a new "AbortError" DOMException.
if ( ! reason . is_undefined ( ) )
m_abort_reason = reason ;
else
2024-10-12 20:56:21 +02:00
m_abort_reason = WebIDL : : AbortError : : create ( realm ( ) , " Aborted without reason " _string ) . ptr ( ) ;
2021-09-02 02:12:49 +01:00
2024-09-08 21:10:52 +01:00
// 3. Let dependentSignalsToAbort be a new list.
2024-11-15 04:01:23 +13:00
Vector < GC : : Root < AbortSignal > > dependent_signals_to_abort ;
2024-09-08 21:10:52 +01:00
// 4. For each dependentSignal of signal’ s dependent signals:
for ( auto const & dependent_signal : m_dependent_signals ) {
// 1. If dependentSignal is not aborted, then:
if ( ! dependent_signal - > aborted ( ) ) {
// 1. Set dependentSignal’ s abort reason to signal’ s abort reason.
dependent_signal - > set_reason ( m_abort_reason ) ;
// 2. Append dependentSignal to dependentSignalsToAbort.
dependent_signals_to_abort . append ( * dependent_signal ) ;
}
}
// https://dom.spec.whatwg.org/#run-the-abort-steps
auto run_the_abort_steps = [ ] ( auto & signal ) {
// 1. For each algorithm in signal’ s abort algorithms: run algorithm.
for ( auto & algorithm : signal . m_abort_algorithms )
algorithm - > function ( ) ( ) ;
// 2. Empty signal’ s abort algorithms.
signal . m_abort_algorithms . clear ( ) ;
// 3. Fire an event named abort at signal.
auto abort_event = Event : : create ( signal . realm ( ) , HTML : : EventNames : : abort ) ;
abort_event - > set_is_trusted ( true ) ;
signal . dispatch_event ( abort_event ) ;
} ;
// 5. Run the abort steps for signal.
run_the_abort_steps ( * this ) ;
// 6. For each dependentSignal of dependentSignalsToAbort, run the abort steps for dependentSignal.
for ( auto const & dependent_signal : dependent_signals_to_abort )
run_the_abort_steps ( * dependent_signal ) ;
2021-09-02 02:12:49 +01:00
}
2022-09-24 16:02:41 +01:00
void AbortSignal : : set_onabort ( WebIDL : : CallbackType * event_handler )
2021-10-01 01:09:11 +01:00
{
2022-08-08 14:12:01 +02:00
set_event_handler_attribute ( HTML : : EventNames : : abort , event_handler ) ;
2021-10-01 01:09:11 +01:00
}
2022-09-24 16:02:41 +01:00
WebIDL : : CallbackType * AbortSignal : : onabort ( )
2021-10-01 01:09:11 +01:00
{
return event_handler_attribute ( HTML : : EventNames : : abort ) ;
}
2021-12-10 19:48:51 +00:00
// https://dom.spec.whatwg.org/#dom-abortsignal-throwifaborted
JS : : ThrowCompletionOr < void > AbortSignal : : throw_if_aborted ( ) const
{
// The throwIfAborted() method steps are to throw this’ s abort reason, if this is aborted.
if ( ! aborted ( ) )
return { } ;
return JS : : throw_completion ( m_abort_reason ) ;
}
2021-12-10 20:05:12 +00:00
void AbortSignal : : visit_edges ( JS : : Cell : : Visitor & visitor )
{
2022-08-28 13:42:07 +02:00
Base : : visit_edges ( visitor ) ;
2021-12-10 20:05:12 +00:00
visitor . visit ( m_abort_reason ) ;
2024-04-15 13:58:21 +02:00
visitor . visit ( m_abort_algorithms ) ;
visitor . visit ( m_source_signals ) ;
visitor . visit ( m_dependent_signals ) ;
2021-12-10 20:05:12 +00:00
}
2024-02-20 20:51:29 +00:00
// https://dom.spec.whatwg.org/#dom-abortsignal-abort
2024-11-15 04:01:23 +13:00
WebIDL : : ExceptionOr < GC : : Ref < AbortSignal > > AbortSignal : : abort ( JS : : VM & vm , JS : : Value reason )
2024-02-20 20:51:29 +00:00
{
// 1. Let signal be a new AbortSignal object.
auto signal = TRY ( construct_impl ( * vm . current_realm ( ) ) ) ;
// 2. Set signal’ s abort reason to reason if it is given; otherwise to a new "AbortError" DOMException.
if ( reason . is_undefined ( ) )
2024-10-12 20:56:21 +02:00
reason = WebIDL : : AbortError : : create ( * vm . current_realm ( ) , " Aborted without reason " _string ) . ptr ( ) ;
2024-02-20 20:51:29 +00:00
signal - > set_reason ( reason ) ;
// 3. Return signal.
return signal ;
}
2024-02-26 17:52:32 +00:00
// https://dom.spec.whatwg.org/#dom-abortsignal-timeout
2024-11-15 04:01:23 +13:00
WebIDL : : ExceptionOr < GC : : Ref < AbortSignal > > AbortSignal : : timeout ( JS : : VM & vm , WebIDL : : UnsignedLongLong milliseconds )
2024-02-26 17:52:32 +00:00
{
auto & realm = * vm . current_realm ( ) ;
// 1. Let signal be a new AbortSignal object.
auto signal = TRY ( construct_impl ( realm ) ) ;
// 2. Let global be signal’ s relevant global object.
auto & global = HTML : : relevant_global_object ( signal ) ;
auto * window_or_worker = dynamic_cast < HTML : : WindowOrWorkerGlobalScopeMixin * > ( & global ) ;
VERIFY ( window_or_worker ) ;
// 3. Run steps after a timeout given global, "AbortSignal-timeout", milliseconds, and the following step:
2024-04-03 12:50:39 +02:00
window_or_worker - > run_steps_after_a_timeout ( milliseconds , [ & realm , & global , signal ] ( ) {
2024-02-26 17:52:32 +00:00
// 1. Queue a global task on the timer task source given global to signal abort given signal and a new "TimeoutError" DOMException.
2024-11-15 04:01:23 +13:00
HTML : : queue_global_task ( HTML : : Task : : Source : : TimerTask , global , GC : : create_function ( realm . heap ( ) , [ & realm , signal ] ( ) mutable {
2024-10-12 20:56:21 +02:00
auto reason = WebIDL : : TimeoutError : : create ( realm , " Signal timed out " _string ) ;
2024-04-03 12:50:39 +02:00
signal - > signal_abort ( reason ) ;
2024-04-16 22:04:01 +02:00
} ) ) ;
2024-02-26 17:52:32 +00:00
} ) ;
// 4. Return signal.
return signal ;
}
2024-03-10 18:50:30 +00:00
// https://dom.spec.whatwg.org/#dom-abortsignal-any
2024-11-15 04:01:23 +13:00
WebIDL : : ExceptionOr < GC : : Ref < AbortSignal > > AbortSignal : : any ( JS : : VM & vm , Vector < GC : : Root < AbortSignal > > const & signals )
2024-03-10 18:50:30 +00:00
{
// The static any(signals) method steps are to return the result of creating a dependent abort signal from signals using AbortSignal and the current realm.
2024-05-13 18:52:46 +01:00
return create_dependent_abort_signal ( * vm . current_realm ( ) , signals ) ;
2024-03-10 18:50:30 +00:00
}
// https://dom.spec.whatwg.org/#create-a-dependent-abort-signal
2024-11-15 04:01:23 +13:00
WebIDL : : ExceptionOr < GC : : Ref < AbortSignal > > AbortSignal : : create_dependent_abort_signal ( JS : : Realm & realm , Vector < GC : : Root < AbortSignal > > const & signals )
2024-03-10 18:50:30 +00:00
{
// 1. Let resultSignal be a new object implementing signalInterface using realm.
auto result_signal = TRY ( construct_impl ( realm ) ) ;
// 2. For each signal of signals: if signal is aborted, then set resultSignal’ s abort reason to signal’ s abort reason and return resultSignal.
for ( auto const & signal : signals ) {
if ( signal - > aborted ( ) ) {
result_signal - > set_reason ( signal - > reason ( ) ) ;
return result_signal ;
}
}
// 3. Set resultSignal’ s dependent to true.
result_signal - > set_dependent ( true ) ;
// 4. For each signal of signals:
for ( auto const & signal : signals ) {
// 1. If signal’ s dependent is false, then:
if ( ! signal - > dependent ( ) ) {
// 1. Append signal to resultSignal’ s source signals.
result_signal - > append_source_signal ( { signal } ) ;
// 2. Append resultSignal to signal’ s dependent signals.
signal - > append_dependent_signal ( result_signal ) ;
}
// 2. Otherwise, for each sourceSignal of signal’ s source signals:
else {
for ( auto const & source_signal : signal - > source_signals ( ) ) {
// 1. Assert: sourceSignal is not aborted and not dependent.
VERIFY ( source_signal ) ;
VERIFY ( ! source_signal - > aborted ( ) ) ;
VERIFY ( ! source_signal - > dependent ( ) ) ;
// 2. Append sourceSignal to resultSignal’ s source signals.
result_signal - > append_source_signal ( source_signal ) ;
// 3. Append resultSignal to sourceSignal’ s dependent signals.
source_signal - > append_dependent_signal ( result_signal ) ;
}
}
}
// 5. Return resultSignal
return result_signal ;
}
2021-09-02 02:12:49 +01:00
}