2021-02-03 10:41:07 +01:00
/*
2024-10-04 13:19:50 +02:00
* Copyright ( c ) 2021 - 2022 , Andreas Kling < andreas @ ladybird . org >
2023-03-29 23:46:18 +01:00
* Copyright ( c ) 2021 - 2023 , Luke Wilde < lukew @ serenityos . org >
2023-10-29 02:53:53 +01:00
* Copyright ( c ) 2022 - 2023 , networkException < networkexception @ serenityos . org >
2023-01-18 17:41:12 +00:00
* Copyright ( c ) 2022 - 2023 , Linus Groh < linusg @ serenityos . org >
2024-12-01 00:02:58 +13:00
* Copyright ( c ) 2024 , Shannon Booth < shannon @ serenityos . org >
2021-02-03 10:41:07 +01:00
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2021-02-03 10:41:07 +01:00
*/
2024-11-15 04:01:23 +13:00
# include <LibGC/DeferGC.h>
2023-10-29 02:53:53 +01:00
# include <LibJS/AST.h>
2022-01-18 19:14:25 +01:00
# include <LibJS/Module.h>
2022-07-11 16:37:51 +01:00
# include <LibJS/Runtime/Array.h>
2022-02-07 18:51:58 +01:00
# include <LibJS/Runtime/Environment.h>
2022-02-06 03:32:26 +00:00
# include <LibJS/Runtime/FinalizationRegistry.h>
2024-10-26 22:07:09 +13:00
# include <LibJS/Runtime/GlobalEnvironment.h>
2022-11-23 14:18:38 +01:00
# include <LibJS/Runtime/ModuleRequest.h>
2022-02-06 03:32:26 +00:00
# include <LibJS/Runtime/NativeFunction.h>
2024-10-26 22:07:09 +13:00
# include <LibJS/Runtime/ShadowRealm.h>
2021-02-03 10:41:07 +01:00
# include <LibJS/Runtime/VM.h>
2023-07-17 21:26:59 -04:00
# include <LibJS/SourceTextModule.h>
# include <LibWeb/Bindings/ExceptionOrUtils.h>
2022-09-24 15:39:23 -06:00
# include <LibWeb/Bindings/Intrinsics.h>
2021-02-03 10:41:07 +01:00
# include <LibWeb/Bindings/MainThreadVM.h>
2024-10-26 22:07:09 +13:00
# include <LibWeb/Bindings/SyntheticHostDefined.h>
2022-10-17 10:38:21 +02:00
# include <LibWeb/Bindings/WindowExposedInterfaces.h>
2022-02-06 03:32:26 +00:00
# include <LibWeb/DOM/Document.h>
2023-03-29 23:46:18 +01:00
# include <LibWeb/HTML/CustomElements/CustomElementDefinition.h>
2023-03-18 10:39:37 -04:00
# include <LibWeb/HTML/EventNames.h>
2023-01-18 17:41:12 +00:00
# include <LibWeb/HTML/Location.h>
2022-02-06 03:32:26 +00:00
# include <LibWeb/HTML/PromiseRejectionEvent.h>
2025-01-04 23:12:55 +13:00
# include <LibWeb/HTML/Scripting/Agent.h>
2022-02-06 03:32:26 +00:00
# include <LibWeb/HTML/Scripting/ClassicScript.h>
# include <LibWeb/HTML/Scripting/Environments.h>
# include <LibWeb/HTML/Scripting/ExceptionReporter.h>
2022-10-03 21:06:00 +02:00
# include <LibWeb/HTML/Scripting/Fetching.h>
2023-10-29 02:53:53 +01:00
# include <LibWeb/HTML/Scripting/ModuleScript.h>
2023-07-17 21:26:59 -04:00
# include <LibWeb/HTML/Scripting/Script.h>
2024-10-26 22:07:09 +13:00
# include <LibWeb/HTML/Scripting/SyntheticRealmSettings.h>
2023-12-03 15:12:09 +01:00
# include <LibWeb/HTML/Scripting/TemporaryExecutionContext.h>
2024-10-26 22:07:09 +13:00
# include <LibWeb/HTML/ShadowRealmGlobalScope.h>
2022-03-07 23:08:26 +01:00
# include <LibWeb/HTML/Window.h>
2022-09-24 16:24:41 +01:00
# include <LibWeb/HTML/WindowProxy.h>
2024-12-01 00:02:58 +13:00
# include <LibWeb/HTML/WorkletGlobalScope.h>
2022-09-08 00:13:39 +02:00
# include <LibWeb/Platform/EventLoopPlugin.h>
2024-12-01 00:02:58 +13:00
# include <LibWeb/ServiceWorker/ServiceWorkerGlobalScope.h>
2022-09-24 16:14:37 +01:00
# include <LibWeb/WebIDL/AbstractOperations.h>
2021-02-03 10:41:07 +01:00
namespace Web : : Bindings {
2023-03-17 10:56:59 -04:00
static RefPtr < JS : : VM > s_main_thread_vm ;
2022-02-06 03:32:26 +00:00
// https://html.spec.whatwg.org/multipage/webappapis.html#active-script
2022-10-24 19:39:35 +01:00
HTML : : Script * active_script ( )
2022-02-06 03:32:26 +00:00
{
// 1. Let record be GetActiveScriptOrModule().
auto record = main_thread_vm ( ) . get_active_script_or_module ( ) ;
// 2. If record is null, return null.
// 3. Return record.[[HostDefined]].
2022-10-24 19:39:35 +01:00
return record . visit (
2024-11-15 04:01:23 +13:00
[ ] ( GC : : Ref < JS : : Script > & js_script ) - > HTML : : Script * {
2025-01-21 09:12:05 -05:00
return as < HTML : : ClassicScript > ( js_script - > host_defined ( ) ) ;
2022-10-24 19:39:35 +01:00
} ,
2024-11-15 04:01:23 +13:00
[ ] ( GC : : Ref < JS : : Module > & js_module ) - > HTML : : Script * {
2025-01-21 09:12:05 -05:00
return as < HTML : : ModuleScript > ( js_module - > host_defined ( ) ) ;
2022-10-24 19:39:35 +01:00
} ,
[ ] ( Empty ) - > HTML : : Script * {
return nullptr ;
} ) ;
2022-02-06 03:32:26 +00:00
}
2024-07-09 02:59:25 -06:00
ErrorOr < void > initialize_main_thread_vm ( HTML : : EventLoop : : Type type )
2021-02-03 10:41:07 +01:00
{
2023-03-17 10:56:59 -04:00
VERIFY ( ! s_main_thread_vm ) ;
s_main_thread_vm = TRY ( JS : : VM : : create ( make < WebEngineCustomData > ( ) ) ) ;
2025-01-04 23:12:55 +13:00
2025-01-21 09:12:05 -05:00
auto & custom_data = as < WebEngineCustomData > ( * s_main_thread_vm - > custom_data ( ) ) ;
2025-01-04 23:12:55 +13:00
custom_data . agent . event_loop = s_main_thread_vm - > heap ( ) . allocate < HTML : : EventLoop > ( type ) ;
2024-06-11 07:20:22 +01:00
s_main_thread_vm - > on_unimplemented_property_access = [ ] ( auto const & object , auto const & property_key ) {
dbgln ( " FIXME: Unimplemented IDL interface: '{}.{}' " , object . class_name ( ) , property_key . to_string ( ) ) ;
} ;
2023-03-17 10:56:59 -04:00
// NOTE: We intentionally leak the main thread JavaScript VM.
// This avoids doing an exhaustive garbage collection on process exit.
s_main_thread_vm - > ref ( ) ;
// 8.1.5.1 HostEnsureCanAddPrivateElement(O), https://html.spec.whatwg.org/multipage/webappapis.html#the-hostensurecanaddprivateelement-implementation
s_main_thread_vm - > host_ensure_can_add_private_element = [ ] ( JS : : Object const & object ) - > JS : : ThrowCompletionOr < void > {
// 1. If O is a WindowProxy object, or implements Location, then return Completion { [[Type]]: throw, [[Value]]: a new TypeError }.
if ( is < HTML : : WindowProxy > ( object ) | | is < HTML : : Location > ( object ) )
return s_main_thread_vm - > throw_completion < JS : : TypeError > ( " Cannot add private elements to window or location object " sv ) ;
// 2. Return NormalCompletion(unused).
return { } ;
} ;
// FIXME: Implement 8.1.5.2 HostEnsureCanCompileStrings(callerRealm, calleeRealm), https://html.spec.whatwg.org/multipage/webappapis.html#hostensurecancompilestrings(callerrealm,-calleerealm)
// 8.1.5.3 HostPromiseRejectionTracker(promise, operation), https://html.spec.whatwg.org/multipage/webappapis.html#the-hostpromiserejectiontracker-implementation
2024-10-21 13:35:24 +13:00
// https://whatpr.org/html/9893/webappapis.html#the-hostpromiserejectiontracker-implementation
2023-03-17 10:56:59 -04:00
s_main_thread_vm - > host_promise_rejection_tracker = [ ] ( JS : : Promise & promise , JS : : Promise : : RejectionOperation operation ) {
2024-10-25 16:27:26 +13:00
auto & vm = * s_main_thread_vm ;
2023-03-17 10:56:59 -04:00
// 1. Let script be the running script.
// The running script is the script in the [[HostDefined]] field in the ScriptOrModule component of the running JavaScript execution context.
HTML : : Script * script { nullptr } ;
2024-10-25 16:27:26 +13:00
vm . running_execution_context ( ) . script_or_module . visit (
2024-11-15 04:01:23 +13:00
[ & script ] ( GC : : Ref < JS : : Script > & js_script ) {
2025-01-21 09:12:05 -05:00
script = as < HTML : : ClassicScript > ( js_script - > host_defined ( ) ) ;
2023-03-17 10:56:59 -04:00
} ,
2024-11-15 04:01:23 +13:00
[ & script ] ( GC : : Ref < JS : : Module > & js_module ) {
2025-01-21 09:12:05 -05:00
script = as < HTML : : ModuleScript > ( js_module - > host_defined ( ) ) ;
2023-03-17 10:56:59 -04:00
} ,
[ ] ( Empty ) {
} ) ;
2022-02-06 03:32:26 +00:00
2023-03-17 10:56:59 -04:00
// 2. If script is a classic script and script's muted errors is true, then return.
// NOTE: is<T>() returns false if nullptr is passed.
if ( is < HTML : : ClassicScript > ( script ) ) {
auto const & classic_script = static_cast < HTML : : ClassicScript const & > ( * script ) ;
if ( classic_script . muted_errors ( ) = = HTML : : ClassicScript : : MutedErrors : : Yes )
return ;
}
2024-10-25 16:27:26 +13:00
// 3. Let realm be the current realm.
// 4. If script is not null, then set settings object to script's realm.
auto & realm = script ? script - > realm ( ) : * vm . current_realm ( ) ;
2023-03-17 10:56:59 -04:00
2024-10-25 16:27:26 +13:00
// 5. Let global be realm's global object.
2024-11-28 04:06:02 +13:00
auto * global_mixin = dynamic_cast < HTML : : UniversalGlobalScopeMixin * > ( & realm . global_object ( ) ) ;
2024-10-23 18:59:19 +13:00
VERIFY ( global_mixin ) ;
auto & global = global_mixin - > this_impl ( ) ;
2023-03-17 10:56:59 -04:00
switch ( operation ) {
2024-10-23 18:59:19 +13:00
// 6. If operation is "reject",
2023-03-17 10:56:59 -04:00
case JS : : Promise : : RejectionOperation : : Reject :
2024-10-23 18:59:19 +13:00
// 1. Append promise to global's about-to-be-notified rejected promises list.
global_mixin - > push_onto_about_to_be_notified_rejected_promises_list ( promise ) ;
2023-03-17 10:56:59 -04:00
break ;
2024-10-23 18:59:19 +13:00
// 7. If operation is "handle",
2023-03-17 10:56:59 -04:00
case JS : : Promise : : RejectionOperation : : Handle : {
2024-10-23 18:59:19 +13:00
// 1. If global's about-to-be-notified rejected promises list contains promise, then remove promise from that list and return.
bool removed_about_to_be_notified_rejected_promise = global_mixin - > remove_from_about_to_be_notified_rejected_promises_list ( promise ) ;
2023-03-17 10:56:59 -04:00
if ( removed_about_to_be_notified_rejected_promise )
return ;
2024-10-23 18:59:19 +13:00
// 3. Remove promise from global's outstanding rejected promises weak set.
bool removed_outstanding_rejected_promise = global_mixin - > remove_from_outstanding_rejected_promises_weak_set ( & promise ) ;
2023-03-17 10:56:59 -04:00
2024-10-23 18:59:19 +13:00
// 2. If global's outstanding rejected promises weak set does not contain promise, then return.
2023-03-17 10:56:59 -04:00
// NOTE: This is done out of order because removed_outstanding_rejected_promise will be false if the promise wasn't in the set or true if it was and got removed.
if ( ! removed_outstanding_rejected_promise )
return ;
2024-10-23 18:59:19 +13:00
// 4. Queue a global task on the DOM manipulation task source given global to fire an event named rejectionhandled at global, using PromiseRejectionEvent,
2023-03-17 10:56:59 -04:00
// with the promise attribute initialized to promise, and the reason attribute initialized to the value of promise's [[PromiseResult]] internal slot.
2024-11-15 04:01:23 +13:00
HTML : : queue_global_task ( HTML : : Task : : Source : : DOMManipulation , global , GC : : create_function ( s_main_thread_vm - > heap ( ) , [ & global , & promise ] {
2023-03-17 10:56:59 -04:00
// FIXME: This currently assumes that global is a WindowObject.
2025-01-21 09:12:05 -05:00
auto & window = as < HTML : : Window > ( global ) ;
2023-03-17 10:56:59 -04:00
HTML : : PromiseRejectionEventInit event_init {
{ } , // Initialize the inherited DOM::EventInit
/* .promise = */ promise ,
/* .reason = */ promise . result ( ) ,
} ;
2023-08-13 13:05:26 +02:00
auto promise_rejection_event = HTML : : PromiseRejectionEvent : : create ( HTML : : relevant_realm ( global ) , HTML : : EventNames : : rejectionhandled , event_init ) ;
2023-03-17 10:56:59 -04:00
window . dispatch_event ( promise_rejection_event ) ;
2024-04-16 22:04:01 +02:00
} ) ) ;
2023-03-17 10:56:59 -04:00
break ;
}
default :
VERIFY_NOT_REACHED ( ) ;
}
} ;
2022-02-06 03:32:26 +00:00
2023-03-17 10:56:59 -04:00
// 8.1.5.4.1 HostCallJobCallback(callback, V, argumentsList), https://html.spec.whatwg.org/multipage/webappapis.html#hostcalljobcallback
2024-10-21 20:54:39 +13:00
// https://whatpr.org/html/9893/webappapis.html#hostcalljobcallback
2023-11-27 16:45:45 +01:00
s_main_thread_vm - > host_call_job_callback = [ ] ( JS : : JobCallback & callback , JS : : Value this_value , ReadonlySpan < JS : : Value > arguments_list ) {
2025-01-21 09:12:05 -05:00
auto & callback_host_defined = as < WebEngineCustomJobCallbackData > ( * callback . custom_data ( ) ) ;
2022-02-06 03:32:26 +00:00
2024-10-25 16:27:26 +13:00
// 1. Let incumbent realm be callback.[[HostDefined]].[[IncumbentRealm]].
auto & incumbent_realm = callback_host_defined . incumbent_realm ;
// 2. Let script execution context be callback.[[HostDefined]].[[ActiveScriptContext]].
auto * script_execution_context = callback_host_defined . active_script_context . ptr ( ) ;
2022-02-06 03:32:26 +00:00
2024-10-21 20:54:39 +13:00
// 3. Prepare to run a callback with incumbent realm.
2024-10-25 16:27:26 +13:00
HTML : : prepare_to_run_callback ( incumbent_realm ) ;
2022-02-06 03:32:26 +00:00
2023-03-17 10:56:59 -04:00
// 4. If script execution context is not null, then push script execution context onto the JavaScript execution context stack.
2024-10-25 16:27:26 +13:00
if ( script_execution_context )
s_main_thread_vm - > push_execution_context ( * script_execution_context ) ;
2022-02-06 03:32:26 +00:00
2023-03-17 10:56:59 -04:00
// 5. Let result be Call(callback.[[Callback]], V, argumentsList).
2024-03-12 03:49:13 +01:00
auto result = JS : : call ( * s_main_thread_vm , callback . callback ( ) , this_value , arguments_list ) ;
2022-02-06 03:32:26 +00:00
2023-03-17 10:56:59 -04:00
// 6. If script execution context is not null, then pop script execution context from the JavaScript execution context stack.
2024-10-25 16:27:26 +13:00
if ( script_execution_context ) {
VERIFY ( & s_main_thread_vm - > running_execution_context ( ) = = script_execution_context ) ;
2023-03-17 10:56:59 -04:00
s_main_thread_vm - > pop_execution_context ( ) ;
}
2022-02-06 03:32:26 +00:00
2024-10-21 20:54:39 +13:00
// 7. Clean up after running a callback with incumbent realm.
2024-10-25 16:27:26 +13:00
HTML : : clean_up_after_running_callback ( incumbent_realm ) ;
2022-02-06 03:32:26 +00:00
2023-03-17 10:56:59 -04:00
// 8. Return result.
return result ;
} ;
2022-02-06 03:32:26 +00:00
2023-03-17 10:56:59 -04:00
// 8.1.5.4.2 HostEnqueueFinalizationRegistryCleanupJob(finalizationRegistry), https://html.spec.whatwg.org/multipage/webappapis.html#hostenqueuefinalizationregistrycleanupjob
s_main_thread_vm - > host_enqueue_finalization_registry_cleanup_job = [ ] ( JS : : FinalizationRegistry & finalization_registry ) {
// 1. Let global be finalizationRegistry.[[Realm]]'s global object.
auto & global = finalization_registry . realm ( ) . global_object ( ) ;
2022-02-06 03:32:26 +00:00
2023-03-17 10:56:59 -04:00
// 2. Queue a global task on the JavaScript engine task source given global to perform the following steps:
2024-11-15 04:01:23 +13:00
HTML : : queue_global_task ( HTML : : Task : : Source : : JavaScriptEngine , global , GC : : create_function ( s_main_thread_vm - > heap ( ) , [ & finalization_registry ] {
2024-10-21 20:09:02 +13:00
// 1. Let entry be finalizationRegistry.[[CleanupCallback]].[[Callback]].[[Realm]].
auto & entry = * finalization_registry . cleanup_callback ( ) . callback ( ) . realm ( ) ;
2022-02-06 03:32:26 +00:00
2023-03-17 10:56:59 -04:00
// 2. Check if we can run script with entry. If this returns "do not run", then return.
2024-10-21 20:09:02 +13:00
if ( HTML : : can_run_script ( entry ) = = HTML : : RunScriptDecision : : DoNotRun )
2023-03-17 10:56:59 -04:00
return ;
2022-02-06 03:32:26 +00:00
2023-03-17 10:56:59 -04:00
// 3. Prepare to run script with entry.
2024-10-21 20:09:02 +13:00
HTML : : prepare_to_run_script ( entry ) ;
2022-02-06 03:32:26 +00:00
2023-03-17 10:56:59 -04:00
// 4. Let result be the result of performing CleanupFinalizationRegistry(finalizationRegistry).
auto result = finalization_registry . cleanup ( ) ;
2022-02-06 03:32:26 +00:00
2023-03-17 10:56:59 -04:00
// 5. Clean up after running script with entry.
2024-10-21 20:09:02 +13:00
HTML : : clean_up_after_running_script ( entry ) ;
2023-03-17 10:56:59 -04:00
// 6. If result is an abrupt completion, then report the exception given by result.[[Value]].
if ( result . is_error ( ) )
2024-10-21 20:09:02 +13:00
HTML : : report_exception ( result , entry ) ;
2024-04-16 22:04:01 +02:00
} ) ) ;
2023-03-17 10:56:59 -04:00
} ;
// 8.1.5.4.3 HostEnqueuePromiseJob(job, realm), https://html.spec.whatwg.org/multipage/webappapis.html#hostenqueuepromisejob
2024-10-25 16:27:26 +13:00
// // https://whatpr.org/html/9893/webappapis.html#hostenqueuepromisejob
2024-11-15 04:01:23 +13:00
s_main_thread_vm - > host_enqueue_promise_job = [ ] ( GC : : Ref < GC : : Function < JS : : ThrowCompletionOr < JS : : Value > ( ) > > job , JS : : Realm * realm ) {
2024-10-25 16:27:26 +13:00
auto & vm = * s_main_thread_vm ;
2023-03-17 10:56:59 -04:00
// IMPLEMENTATION DEFINED: The JS spec says we must take implementation defined steps to make the currently active script or module at the time of HostEnqueuePromiseJob being invoked
// also be the active script or module of the job at the time of its invocation.
// This means taking it here now and passing it through to the lambda.
2024-10-25 16:27:26 +13:00
auto script_or_module = vm . get_active_script_or_module ( ) ;
2023-03-17 10:56:59 -04:00
2024-10-25 16:27:26 +13:00
// 1. Queue a microtask to perform the following steps:
2023-03-17 10:56:59 -04:00
// This instance of "queue a microtask" uses the "implied document". The best fit for "implied document" here is "If the task is being queued by or for a script, then return the script's settings object's responsible document."
// Do note that "implied document" from the spec is handwavy and the spec authors are trying to get rid of it: https://github.com/whatwg/html/issues/4980
auto * script = active_script ( ) ;
2024-10-25 16:27:26 +13:00
auto & heap = realm ? realm - > heap ( ) : vm . heap ( ) ;
2024-11-15 04:01:23 +13:00
HTML : : queue_a_microtask ( script ? script - > settings_object ( ) . responsible_document ( ) . ptr ( ) : nullptr , GC : : create_function ( heap , [ & vm , realm , job = move ( job ) , script_or_module = move ( script_or_module ) ] {
2023-03-17 10:56:59 -04:00
// The dummy execution context has to be kept up here to keep it alive for the duration of the function.
2023-11-27 16:45:45 +01:00
OwnPtr < JS : : ExecutionContext > dummy_execution_context ;
2023-03-17 10:56:59 -04:00
2024-10-21 14:24:06 +13:00
if ( realm ) {
// 1. If realm is not null, then check if we can run script with realm. If this returns "do not run" then return.
if ( HTML : : can_run_script ( * realm ) = = HTML : : RunScriptDecision : : DoNotRun )
2022-02-06 03:32:26 +00:00
return ;
2024-10-21 20:09:02 +13:00
// 2. If realm is not null, then prepare to run script with realm.
HTML : : prepare_to_run_script ( * realm ) ;
2023-03-17 10:56:59 -04:00
// IMPLEMENTATION DEFINED: Additionally to preparing to run a script, we also prepare to run a callback here. This matches WebIDL's
// invoke_callback() / call_user_object_operation() functions, and prevents a crash in host_make_job_callback()
// when getting the incumbent settings object.
2024-10-21 20:54:39 +13:00
HTML : : prepare_to_run_callback ( * realm ) ;
2023-03-17 10:56:59 -04:00
// IMPLEMENTATION DEFINED: Per the previous "implementation defined" comment, we must now make the script or module the active script or module.
// Since the only active execution context currently is the realm execution context of job settings, lets attach it here.
2024-10-25 16:27:26 +13:00
HTML : : execution_context_of_realm ( * realm ) . script_or_module = script_or_module ;
2023-03-17 10:56:59 -04:00
} else {
// FIXME: We need to setup a dummy execution context in case a JS::NativeFunction is called when processing the job.
// This is because JS::NativeFunction::call excepts something to be on the execution context stack to be able to get the caller context to initialize the environment.
// Do note that the JS spec gives _no_ guarantee that the execution context stack has something on it if HostEnqueuePromiseJob was called with a null realm: https://tc39.es/ecma262/#job-preparedtoevaluatecode
2024-05-31 15:12:33 +02:00
dummy_execution_context = JS : : ExecutionContext : : create ( ) ;
2023-03-17 10:56:59 -04:00
dummy_execution_context - > script_or_module = script_or_module ;
2024-10-25 16:27:26 +13:00
vm . push_execution_context ( * dummy_execution_context ) ;
2023-03-17 10:56:59 -04:00
}
2022-02-06 03:32:26 +00:00
2023-03-17 10:56:59 -04:00
// 3. Let result be job().
2024-03-25 14:18:22 +01:00
auto result = job - > function ( ) ( ) ;
2022-02-06 03:32:26 +00:00
2024-10-21 16:18:25 +13:00
// 4. If realm is not null, then clean up after running script with job settings.
if ( realm ) {
2023-03-17 10:56:59 -04:00
// IMPLEMENTATION DEFINED: Disassociate the realm execution context from the script or module.
2024-10-25 16:27:26 +13:00
HTML : : execution_context_of_realm ( * realm ) . script_or_module = Empty { } ;
2022-02-06 03:32:26 +00:00
2023-03-17 10:56:59 -04:00
// IMPLEMENTATION DEFINED: See comment above, we need to clean up the non-standard prepare_to_run_callback() call.
2024-10-21 20:54:39 +13:00
HTML : : clean_up_after_running_callback ( * realm ) ;
2023-03-17 10:56:59 -04:00
2024-10-21 16:18:25 +13:00
HTML : : clean_up_after_running_script ( * realm ) ;
2023-03-17 10:56:59 -04:00
} else {
// Pop off the dummy execution context. See the above FIXME block about why this is done.
2024-10-25 16:27:26 +13:00
vm . pop_execution_context ( ) ;
2023-03-17 10:56:59 -04:00
}
2022-02-06 03:32:26 +00:00
2023-03-17 10:56:59 -04:00
// 5. If result is an abrupt completion, then report the exception given by result.[[Value]].
if ( result . is_error ( ) )
2024-10-25 16:27:26 +13:00
HTML : : report_exception ( result , * realm ) ;
2024-04-13 16:32:39 +02:00
} ) ) ;
2023-03-17 10:56:59 -04:00
} ;
2022-02-06 03:32:26 +00:00
2023-03-17 10:56:59 -04:00
// 8.1.5.4.4 HostMakeJobCallback(callable), https://html.spec.whatwg.org/multipage/webappapis.html#hostmakejobcallback
2024-10-25 16:27:26 +13:00
// https://whatpr.org/html/9893/webappapis.html#hostmakejobcallback
2024-11-15 04:01:23 +13:00
s_main_thread_vm - > host_make_job_callback = [ ] ( JS : : FunctionObject & callable ) - > GC : : Ref < JS : : JobCallback > {
2024-10-25 16:27:26 +13:00
// 1. Let incumbent realm be the incumbent realm.
auto & incumbent_realm = HTML : : incumbent_realm ( ) ;
2022-02-06 03:32:26 +00:00
2023-03-17 10:56:59 -04:00
// 2. Let active script be the active script.
auto * script = active_script ( ) ;
2022-10-04 21:00:08 +01:00
2023-03-17 10:56:59 -04:00
// 3. Let script execution context be null.
OwnPtr < JS : : ExecutionContext > script_execution_context ;
2022-02-06 03:32:26 +00:00
2023-03-17 10:56:59 -04:00
// 4. If active script is not null, set script execution context to a new JavaScript execution context, with its Function field set to null,
2024-10-25 16:27:26 +13:00
// its Realm field set to active script's realm, and its ScriptOrModule set to active script's record.
2023-03-17 10:56:59 -04:00
if ( script ) {
2024-05-31 15:12:33 +02:00
script_execution_context = JS : : ExecutionContext : : create ( ) ;
2023-03-17 10:56:59 -04:00
script_execution_context - > function = nullptr ;
2024-10-25 16:27:26 +13:00
script_execution_context - > realm = & script - > realm ( ) ;
2023-03-17 10:56:59 -04:00
if ( is < HTML : : ClassicScript > ( script ) ) {
2025-01-21 09:12:05 -05:00
script_execution_context - > script_or_module = GC : : Ref < JS : : Script > ( * as < HTML : : ClassicScript > ( script ) - > script_record ( ) ) ;
2023-03-17 10:56:59 -04:00
} else if ( is < HTML : : ModuleScript > ( script ) ) {
if ( is < HTML : : JavaScriptModuleScript > ( script ) ) {
2025-01-21 09:12:05 -05:00
script_execution_context - > script_or_module = GC : : Ref < JS : : Module > ( * as < HTML : : JavaScriptModuleScript > ( script ) - > record ( ) ) ;
2022-10-24 19:39:35 +01:00
} else {
2023-03-17 10:56:59 -04:00
// NOTE: Handle CSS and JSON module scripts once we have those.
2022-10-24 19:39:35 +01:00
VERIFY_NOT_REACHED ( ) ;
}
2023-03-17 10:56:59 -04:00
} else {
VERIFY_NOT_REACHED ( ) ;
2022-02-06 03:32:26 +00:00
}
2023-03-17 10:56:59 -04:00
}
2024-10-25 16:27:26 +13:00
// 5. Return the JobCallback Record { [[Callback]]: callable, [[HostDefined]]: { [[IncumbentRealm]]: incumbent realm, [[ActiveScriptContext]]: script execution context } }.
auto host_defined = adopt_own ( * new WebEngineCustomJobCallbackData ( incumbent_realm , move ( script_execution_context ) ) ) ;
2024-03-12 03:49:13 +01:00
return JS : : JobCallback : : create ( * s_main_thread_vm , callable , move ( host_defined ) ) ;
2023-03-17 10:56:59 -04:00
} ;
2024-12-01 13:09:45 +13:00
// 8.1.6.7.1 HostGetImportMetaProperties(moduleRecord), https://html.spec.whatwg.org/multipage/webappapis.html#hostgetimportmetaproperties
2023-07-17 21:26:59 -04:00
s_main_thread_vm - > host_get_import_meta_properties = [ ] ( JS : : SourceTextModule & module_record ) {
auto & realm = module_record . realm ( ) ;
auto & vm = realm . vm ( ) ;
// 1. Let moduleScript be moduleRecord.[[HostDefined]].
2025-01-21 09:12:05 -05:00
auto & module_script = * as < HTML : : Script > ( module_record . host_defined ( ) ) ;
2023-07-17 21:26:59 -04:00
// 2. Assert: moduleScript's base URL is not null, as moduleScript is a JavaScript module script.
VERIFY ( module_script . base_url ( ) . is_valid ( ) ) ;
// 3. Let urlString be moduleScript's base URL, serialized.
auto url_string = module_script . base_url ( ) . serialize ( ) ;
// 4. Let steps be the following steps, given the argument specifier:
2024-11-15 04:01:23 +13:00
auto steps = [ module_script = GC : : Ref { module_script } ] ( JS : : VM & vm ) - > JS : : ThrowCompletionOr < JS : : Value > {
2023-07-17 21:26:59 -04:00
auto specifier = vm . argument ( 0 ) ;
// 1. Set specifier to ? ToString(specifier).
auto specifier_string = TRY ( specifier . to_string ( vm ) ) ;
// 2. Let url be the result of resolving a module specifier given moduleScript and specifier.
auto url = TRY ( Bindings : : throw_dom_exception_if_needed ( vm , [ & ] {
2023-12-16 17:49:34 +03:30
return HTML : : resolve_module_specifier ( * module_script , specifier_string . to_byte_string ( ) ) ;
2023-07-17 21:26:59 -04:00
} ) ) ;
// 3. Return the serialization of url.
return JS : : PrimitiveString : : create ( vm , url . serialize ( ) ) ;
} ;
// 4. Let resolveFunction be ! CreateBuiltinFunction(steps, 1, "resolve", « »).
auto resolve_function = JS : : NativeFunction : : create ( realm , move ( steps ) , 1 , vm . names . resolve ) ;
// 5. Return « Record { [[Key]]: "url", [[Value]]: urlString }, Record { [[Key]]: "resolve", [[Value]]: resolveFunction } ».
HashMap < JS : : PropertyKey , JS : : Value > meta ;
meta . set ( " url " , JS : : PrimitiveString : : create ( vm , move ( url_string ) ) ) ;
meta . set ( " resolve " , resolve_function ) ;
return meta ;
} ;
2024-12-01 13:09:45 +13:00
// 8.1.6.7.2 HostGetSupportedImportAttributes(), https://html.spec.whatwg.org/multipage/webappapis.html#hostgetsupportedimportassertions
2023-12-16 17:49:34 +03:30
s_main_thread_vm - > host_get_supported_import_attributes = [ ] ( ) - > Vector < ByteString > {
2023-03-17 10:56:59 -04:00
// 1. Return « "type" ».
return { " type " sv } ;
} ;
2024-10-04 00:01:20 +01:00
// 8.1.6.7.3 HostLoadImportedModule(referrer, moduleRequest, loadState, payload), https://html.spec.whatwg.org/multipage/webappapis.html#hostloadimportedmodule
2024-10-21 13:35:24 +13:00
// https://whatpr.org/html/9893/webappapis.html#hostloadimportedmodule
2024-11-15 04:01:23 +13:00
s_main_thread_vm - > host_load_imported_module = [ ] ( JS : : ImportedModuleReferrer referrer , JS : : ModuleRequest const & module_request , GC : : Ptr < JS : : GraphLoadingState : : HostDefined > load_state , JS : : ImportedModulePayload payload ) - > void {
2023-12-02 22:56:47 +01:00
auto & vm = * s_main_thread_vm ;
2024-10-25 16:27:26 +13:00
// 1. Let moduleMapRealm be the current realm.
auto * module_map_realm = vm . current_realm ( ) ;
2023-10-29 02:53:53 +01:00
2024-12-01 00:02:58 +13:00
// 2. If moduleMapRealm's global object implements WorkletGlobalScope or ServiceWorkerGlobalScope and loadState is undefined, then:
if ( ( is < HTML : : WorkletGlobalScope > ( module_map_realm - > global_object ( ) ) | | is < ServiceWorker : : ServiceWorkerGlobalScope > ( module_map_realm - > global_object ( ) ) ) & & ! load_state ) {
// 1. Let completion be Completion Record { [[Type]]: throw, [[Value]]: a new TypeError, [[Target]]: empty }.
auto completion = JS : : throw_completion ( JS : : TypeError : : create ( * module_map_realm , " Dynamic Import not available for Worklets or ServiceWorkers " _string ) ) ;
// 2. Perform FinishLoadingImportedModule(referrer, moduleRequest, payload, completion).
JS : : finish_loading_imported_module ( referrer , module_request , payload , completion ) ;
// 3. Return.
return ;
}
2023-10-29 02:53:53 +01:00
// 3. Let referencingScript be null.
Optional < HTML : : Script & > referencing_script ;
2024-10-03 23:49:55 +01:00
// 4. Let originalFetchOptions be the default script fetch options.
auto original_fetch_options = HTML : : default_script_fetch_options ( ) ;
2023-10-29 02:53:53 +01:00
// 5. Let fetchReferrer be "client".
2024-06-01 11:25:58 +01:00
Fetch : : Infrastructure : : Request : : ReferrerType fetch_referrer = Fetch : : Infrastructure : : Request : : Referrer : : Client ;
2023-10-29 02:53:53 +01:00
2024-10-04 00:01:20 +01:00
// 6. If referrer is a Script Record or a Cyclic Module Record, then:
2024-11-15 04:01:23 +13:00
if ( referrer . has < GC : : Ref < JS : : Script > > ( ) | | referrer . has < GC : : Ref < JS : : CyclicModule > > ( ) ) {
2023-10-29 02:53:53 +01:00
// 1. Set referencingScript to referrer.[[HostDefined]].
2025-01-21 09:12:05 -05:00
referencing_script = as < HTML : : Script > ( referrer . has < GC : : Ref < JS : : Script > > ( ) ? * referrer . get < GC : : Ref < JS : : Script > > ( ) - > host_defined ( ) : * referrer . get < GC : : Ref < JS : : CyclicModule > > ( ) - > host_defined ( ) ) ;
2023-10-29 02:53:53 +01:00
2024-10-25 16:27:26 +13:00
// 2. Set fetchReferrer to referencingScript's base URL.
2024-06-01 11:25:58 +01:00
fetch_referrer = referencing_script - > base_url ( ) ;
2023-10-29 02:53:53 +01:00
2024-10-25 16:27:26 +13:00
// FIXME: 3. Set originalFetchOptions to referencingScript's fetch options.
// 4. Set moduleMapRealm to referencingScript's realm.
module_map_realm = & referencing_script - > realm ( ) ;
2023-10-29 02:53:53 +01:00
}
2024-12-01 13:03:26 +13:00
// 7. If referrer is a Cyclic Module Record and moduleRequest is equal to the first element of referrer.[[RequestedModules]], then:
2024-12-02 00:24:48 +13:00
if ( referrer . has < GC : : Ref < JS : : CyclicModule > > ( ) ) {
// FIXME: Why do we need to check requested modules is empty here?
if ( auto const & requested_modules = referrer . get < GC : : Ref < JS : : CyclicModule > > ( ) - > requested_modules ( ) ; ! requested_modules . is_empty ( ) & & module_request = = requested_modules . first ( ) ) {
// 1. For each ModuleRequest record requested of referrer.[[RequestedModules]]:
for ( auto const & module_request : referrer . get < GC : : Ref < JS : : CyclicModule > > ( ) - > requested_modules ( ) ) {
// 1. If moduleRequest.[[Attributes]] contains a Record entry such that entry.[[Key]] is not "type", then:
for ( auto const & attribute : module_request . attributes ) {
if ( attribute . key = = " type " sv )
continue ;
// 1. Let completion be Completion Record { [[Type]]: throw, [[Value]]: a new SyntaxError exception, [[Target]]: empty }.
auto completion = JS : : throw_completion ( JS : : SyntaxError : : create ( * module_map_realm , " Module request attributes must only contain a type attribute " _string ) ) ;
// 2. Perform FinishLoadingImportedModule(referrer, moduleRequest, payload, completion).
JS : : finish_loading_imported_module ( referrer , module_request , payload , completion ) ;
// 3. Return.
return ;
}
}
// 2. Resolve a module specifier given referencingScript and moduleRequest.[[Specifier]], catching any
// exceptions. If they throw an exception, let resolutionError be the thrown exception.
auto maybe_exception = HTML : : resolve_module_specifier ( referencing_script , module_request . module_specifier ) ;
2024-12-01 13:03:26 +13:00
2024-12-02 00:24:48 +13:00
// 3. If the previous step threw an exception, then:
if ( maybe_exception . is_exception ( ) ) {
// 1. Let completion be Completion Record { [[Type]]: throw, [[Value]]: resolutionError, [[Target]]: empty }.
2024-11-04 14:37:27 +01:00
auto completion = exception_to_throw_completion ( main_thread_vm ( ) , maybe_exception . exception ( ) ) ;
2024-12-01 13:03:26 +13:00
// 2. Perform FinishLoadingImportedModule(referrer, moduleRequest, payload, completion).
JS : : finish_loading_imported_module ( referrer , module_request , payload , completion ) ;
// 3. Return.
return ;
}
2024-12-02 00:24:48 +13:00
// 4. Let moduleType be the result of running the module type from module request steps given moduleRequest.
auto module_type = HTML : : module_type_from_module_request ( module_request ) ;
2024-12-01 13:03:26 +13:00
2024-12-02 00:24:48 +13:00
// 5. If the result of running the module type allowed steps given moduleType and moduleMapRealm is false, then:
if ( ! HTML : : module_type_allowed ( * module_map_realm , module_type ) ) {
// 1. Let completion be Completion Record { [[Type]]: throw, [[Value]]: a new TypeError exception, [[Target]]: empty }.
auto completion = JS : : throw_completion ( JS : : SyntaxError : : create ( * module_map_realm , MUST ( String : : formatted ( " Module type '{}' is not supported " , module_type ) ) ) ) ;
2024-12-01 13:03:26 +13:00
2024-12-02 00:24:48 +13:00
// 2. Perform FinishLoadingImportedModule(referrer, moduleRequest, payload, completion).
JS : : finish_loading_imported_module ( referrer , module_request , payload , completion ) ;
2024-12-01 13:03:26 +13:00
2024-12-02 00:24:48 +13:00
// 3. Return
return ;
}
2024-12-01 13:03:26 +13:00
2024-12-02 00:24:48 +13:00
// Spec-Note: This step is essentially validating all of the requested module specifiers and type attributes
// when the first call to HostLoadImportedModule for a static module dependency list is made, to
// avoid further loading operations in the case any one of the dependencies has a static error.
// We treat a module with unresolvable module specifiers or unsupported type attributes the same
// as one that cannot be parsed; in both cases, a syntactic issue makes it impossible to ever
// contemplate linking the module later.
2024-12-01 13:03:26 +13:00
}
}
2024-10-04 00:01:20 +01:00
2024-12-03 20:31:14 +13:00
// 8. Let url be the result of resolving a module specifier given referencingScript and moduleRequest.[[Specifier]],
2023-10-29 02:53:53 +01:00
// catching any exceptions. If they throw an exception, let resolutionError be the thrown exception.
auto url = HTML : : resolve_module_specifier ( referencing_script , module_request . module_specifier ) ;
2024-12-03 20:31:14 +13:00
// 9. If the previous step threw an exception, then:
2023-10-29 02:53:53 +01:00
if ( url . is_exception ( ) ) {
// 1. Let completion be Completion Record { [[Type]]: throw, [[Value]]: resolutionError, [[Target]]: empty }.
2024-11-04 14:37:27 +01:00
auto completion = exception_to_throw_completion ( main_thread_vm ( ) , url . exception ( ) ) ;
2023-10-29 02:53:53 +01:00
// 2. Perform FinishLoadingImportedModule(referrer, moduleRequest, payload, completion).
2024-10-25 16:27:26 +13:00
HTML : : TemporaryExecutionContext context { * module_map_realm } ;
2023-12-02 22:56:47 +01:00
JS : : finish_loading_imported_module ( referrer , module_request , payload , completion ) ;
2023-10-29 02:53:53 +01:00
// 3. Return.
return ;
}
2024-12-03 20:31:14 +13:00
// 10. Let settingsObject be moduleMapRealm's principal realm's settings object.
2024-10-25 16:27:26 +13:00
auto & settings_object = HTML : : principal_realm_settings_object ( HTML : : principal_realm ( * module_map_realm ) ) ;
2024-12-03 20:31:14 +13:00
// 11. Let fetchOptions be the result of getting the descendant script fetch options given originalFetchOptions, url, and settingsObject.
2024-12-03 18:03:50 +13:00
auto fetch_options = HTML : : get_descendant_script_fetch_options ( original_fetch_options , url . value ( ) , settings_object ) ;
2024-06-01 11:25:58 +01:00
2024-12-03 20:31:14 +13:00
// 12. Let destination be "script".
2023-10-29 02:53:53 +01:00
auto destination = Fetch : : Infrastructure : : Request : : Destination : : Script ;
2024-12-03 20:31:14 +13:00
// 13. Let fetchClient be moduleMapRealm's principal realm's settings object.
2024-11-15 04:01:23 +13:00
GC : : Ref fetch_client { HTML : : principal_realm_settings_object ( HTML : : principal_realm ( * module_map_realm ) ) } ;
2023-10-29 02:53:53 +01:00
2024-12-03 20:31:14 +13:00
// 15. If loadState is not undefined, then:
2024-03-05 09:48:10 -07:00
HTML : : PerformTheFetchHook perform_fetch ;
2023-11-17 12:14:18 +01:00
if ( load_state ) {
auto & fetch_context = static_cast < HTML : : FetchContext & > ( * load_state ) ;
2023-10-29 02:53:53 +01:00
// 1. Set destination to loadState.[[Destination]].
destination = fetch_context . destination ;
2024-10-04 00:01:20 +01:00
// 2. Set fetchClient to loadState.[[FetchClient]].
2023-10-29 02:53:53 +01:00
fetch_client = fetch_context . fetch_client ;
2024-03-05 09:48:10 -07:00
// For step 13
perform_fetch = fetch_context . perform_fetch ;
2023-10-29 02:53:53 +01:00
}
2024-11-15 04:01:23 +13:00
auto on_single_fetch_complete = HTML : : create_on_fetch_script_complete ( module_map_realm - > heap ( ) , [ referrer , module_map_realm , load_state , module_request , payload ] ( GC : : Ptr < HTML : : Script > const & module_script ) - > void {
2024-10-25 16:27:26 +13:00
auto & realm = * module_map_realm ;
2023-10-29 02:53:53 +01:00
// onSingleFetchComplete given moduleScript is the following algorithm:
// 1. Let completion be null.
// NOTE: Our JS::Completion does not support non JS::Value types for its [[Value]], a such we
// use JS::ThrowCompletionOr here.
2023-12-06 11:57:47 +01:00
auto & vm = realm . vm ( ) ;
2024-11-15 04:01:23 +13:00
GC : : Ptr < JS : : Module > module = nullptr ;
2023-12-06 11:57:47 +01:00
2024-11-15 04:01:23 +13:00
auto completion = [ & ] ( ) - > JS : : ThrowCompletionOr < GC : : Ref < JS : : Module > > {
2023-12-02 22:56:47 +01:00
// 2. If moduleScript is null, then set completion to Completion Record { [[Type]]: throw, [[Value]]: a new TypeError, [[Target]]: empty }.
if ( ! module_script ) {
2023-12-16 17:49:34 +03:30
return JS : : throw_completion ( JS : : TypeError : : create ( realm , ByteString : : formatted ( " Loading imported module '{}' failed. " , module_request . module_specifier ) ) ) ;
2023-12-02 22:56:47 +01:00
}
// 3. Otherwise, if moduleScript's parse error is not null, then:
2023-12-06 11:57:47 +01:00
else if ( ! module_script - > parse_error ( ) . is_null ( ) ) {
2023-12-02 22:56:47 +01:00
// 1. Let parseError be moduleScript's parse error.
auto parse_error = module_script - > parse_error ( ) ;
// 2. Set completion to Completion Record { [[Type]]: throw, [[Value]]: parseError, [[Target]]: empty }.
2023-12-06 11:57:47 +01:00
auto completion = JS : : throw_completion ( parse_error ) ;
2023-12-02 22:56:47 +01:00
// 3. If loadState is not undefined and loadState.[[ParseError]] is null, set loadState.[[ParseError]] to parseError.
if ( load_state ) {
auto & load_state_as_fetch_context = static_cast < HTML : : FetchContext & > ( * load_state ) ;
if ( load_state_as_fetch_context . parse_error . is_null ( ) ) {
load_state_as_fetch_context . parse_error = parse_error ;
}
2023-10-29 02:53:53 +01:00
}
2023-12-06 11:57:47 +01:00
return completion ;
2023-10-29 02:53:53 +01:00
}
2024-10-04 00:01:20 +01:00
// 4. Otherwise, set completion to Completion Record { [[Type]]: normal, [[Value]]: moduleScript's record, [[Target]]: empty }.
2023-12-02 22:56:47 +01:00
else {
2023-12-06 11:57:47 +01:00
module = static_cast < HTML : : JavaScriptModuleScript & > ( * module_script ) . record ( ) ;
2024-11-15 04:01:23 +13:00
return JS : : ThrowCompletionOr < GC : : Ref < JS : : Module > > ( * module ) ;
2023-12-02 22:56:47 +01:00
}
} ( ) ;
2023-10-29 02:53:53 +01:00
// 5. Perform FinishLoadingImportedModule(referrer, moduleRequest, payload, completion).
2023-12-06 11:57:47 +01:00
// NON-STANDARD: To ensure that LibJS can find the module on the stack, we push a new execution context.
2024-05-31 15:12:33 +02:00
auto module_execution_context = JS : : ExecutionContext : : create ( ) ;
2023-12-06 11:57:47 +01:00
module_execution_context - > realm = realm ;
if ( module )
2024-11-15 04:01:23 +13:00
module_execution_context - > script_or_module = GC : : Ref { * module } ;
2023-12-06 11:57:47 +01:00
vm . push_execution_context ( * module_execution_context ) ;
2023-12-02 22:56:47 +01:00
JS : : finish_loading_imported_module ( referrer , module_request , payload , completion ) ;
2023-12-06 11:57:47 +01:00
vm . pop_execution_context ( ) ;
2023-10-29 02:53:53 +01:00
} ) ;
2024-12-03 20:31:14 +13:00
// 16. Fetch a single imported module script given url, fetchClient, destination, fetchOptions, moduleMapRealm, fetchReferrer,
2023-10-29 02:53:53 +01:00
// moduleRequest, and onSingleFetchComplete as defined below.
2024-03-05 09:48:10 -07:00
// If loadState is not undefined and loadState.[[PerformFetch]] is not null, pass loadState.[[PerformFetch]] along as well.
2024-10-25 16:27:26 +13:00
HTML : : fetch_single_imported_module_script ( * module_map_realm , url . release_value ( ) , * fetch_client , destination , fetch_options , * module_map_realm , fetch_referrer , module_request , perform_fetch , on_single_fetch_complete ) ;
2023-10-29 02:53:53 +01:00
} ;
2024-10-26 22:07:09 +13:00
// https://whatpr.org/html/9893/webappapis.html#hostinitializeshadowrealm(realm,-context,-o)
// 8.1.6.8 HostInitializeShadowRealm(realm, context, O)
s_main_thread_vm - > host_initialize_shadow_realm = [ ] ( JS : : Realm & realm , NonnullOwnPtr < JS : : ExecutionContext > context , JS : : ShadowRealm & object ) - > JS : : ThrowCompletionOr < void > {
// FIXME: 1. Set realm's is global prototype chain mutable to true.
// 2. Let globalObject be a new ShadowRealmGlobalScope object with realm.
auto global_object = HTML : : ShadowRealmGlobalScope : : create ( realm ) ;
// 3. Let settings be a new synthetic realm settings object that this algorithm will subsequently initialize.
auto settings = HTML : : SyntheticRealmSettings {
// 4. Set settings's execution context to context.
. execution_context = move ( context ) ,
2024-11-28 05:10:30 +13:00
// 5. Set settings's principal realm to O's associated realm's principal realm
. principal_realm = HTML : : principal_realm ( object . shape ( ) . realm ( ) ) ,
2024-10-26 22:07:09 +13:00
2024-11-25 10:01:47 +13:00
// 6. Set settings's module map to a new module map, initially empty.
2024-11-14 05:50:17 +13:00
. module_map = realm . create < HTML : : ModuleMap > ( ) ,
2024-10-26 22:07:09 +13:00
} ;
2024-11-25 10:01:47 +13:00
// 7. Set realm.[[HostDefined]] to settings.
2024-11-14 05:50:17 +13:00
realm . set_host_defined ( make < Bindings : : SyntheticHostDefined > ( move ( settings ) , realm . create < Bindings : : Intrinsics > ( realm ) ) ) ;
2024-10-26 22:07:09 +13:00
2024-11-25 10:01:47 +13:00
// 8. Set realm.[[GlobalObject]] to globalObject.
2024-10-26 22:07:09 +13:00
realm . set_global_object ( global_object ) ;
2024-11-25 10:01:47 +13:00
// 9. Set realm.[[GlobalEnv]] to NewGlobalEnvironment(globalObject, globalObject).
2024-11-14 06:13:46 +13:00
realm . set_global_environment ( realm . heap ( ) . allocate < JS : : GlobalEnvironment > ( global_object , global_object ) ) ;
2024-10-26 22:07:09 +13:00
2024-11-25 10:01:47 +13:00
// 10. Perform ? SetDefaultGlobalBindings(realm).
2024-10-26 22:07:09 +13:00
set_default_global_bindings ( realm ) ;
2024-11-08 16:03:45 +13:00
// NOTE: This needs to be done after initialization so that the realm has an intrinsics in its [[HostDefined]]
global_object - > initialize_web_interfaces ( ) ;
2024-11-25 10:01:47 +13:00
// 11. Return NormalCompletion(unused).
2024-10-26 22:07:09 +13:00
return { } ;
} ;
2024-09-08 11:15:07 -04:00
s_main_thread_vm - > host_unrecognized_date_string = [ ] ( StringView date ) {
dbgln ( " Unable to parse date string: \" {} \" " , date ) ;
} ;
2023-03-17 10:56:59 -04:00
return { } ;
}
2022-02-06 03:32:26 +00:00
2023-03-17 10:56:59 -04:00
JS : : VM & main_thread_vm ( )
{
VERIFY ( s_main_thread_vm ) ;
return * s_main_thread_vm ;
2021-02-03 10:41:07 +01:00
}
2022-07-11 16:37:51 +01:00
// https://dom.spec.whatwg.org/#queue-a-mutation-observer-compound-microtask
2023-02-25 10:44:51 -07:00
void queue_mutation_observer_microtask ( DOM : : Document const & document )
2022-07-11 16:37:51 +01:00
{
auto & vm = main_thread_vm ( ) ;
2025-01-21 09:12:05 -05:00
auto & surrounding_agent = as < WebEngineCustomData > ( * vm . custom_data ( ) ) . agent ;
2022-07-11 16:37:51 +01:00
// 1. If the surrounding agent’ s mutation observer microtask queued is true, then return.
2025-01-04 23:12:55 +13:00
if ( surrounding_agent . mutation_observer_microtask_queued )
2022-07-11 16:37:51 +01:00
return ;
// 2. Set the surrounding agent’ s mutation observer microtask queued to true.
2025-01-04 23:12:55 +13:00
surrounding_agent . mutation_observer_microtask_queued = true ;
2022-07-11 16:37:51 +01:00
// 3. Queue a microtask to notify mutation observers.
// NOTE: This uses the implied document concept. In the case of mutation observers, it is always done in a node context, so document should be that node's document.
2025-01-04 23:12:55 +13:00
HTML : : queue_a_microtask ( & document , GC : : create_function ( vm . heap ( ) , [ & surrounding_agent , & heap = document . heap ( ) ] ( ) {
2022-07-11 16:37:51 +01:00
// 1. Set the surrounding agent’ s mutation observer microtask queued to false.
2025-01-04 23:12:55 +13:00
surrounding_agent . mutation_observer_microtask_queued = false ;
2022-07-11 16:37:51 +01:00
// 2. Let notifySet be a clone of the surrounding agent’ s mutation observers.
2024-12-26 14:32:52 +01:00
GC : : RootVector < DOM : : MutationObserver * > notify_set ( heap ) ;
2025-01-04 23:12:55 +13:00
for ( auto & observer : surrounding_agent . mutation_observers )
2024-03-13 08:41:24 +01:00
notify_set . append ( observer ) ;
2022-07-11 16:37:51 +01:00
// FIXME: 3. Let signalSet be a clone of the surrounding agent’ s signal slots.
// FIXME: 4. Empty the surrounding agent’ s signal slots.
// 5. For each mo of notifySet:
for ( auto & mutation_observer : notify_set ) {
// 1. Let records be a clone of mo’ s record queue.
// 2. Empty mo’ s record queue.
2022-09-01 17:59:48 +02:00
auto records = mutation_observer - > take_records ( ) ;
2022-07-11 16:37:51 +01:00
// 3. For each node of mo’ s node list, remove all transient registered observers whose observer is mo from node’ s registered observer list.
2022-09-01 17:59:48 +02:00
for ( auto & node : mutation_observer - > node_list ( ) ) {
2022-07-11 16:37:51 +01:00
// FIXME: Is this correct?
if ( node . is_null ( ) )
continue ;
2023-11-18 11:22:51 +01:00
if ( node - > registered_observer_list ( ) ) {
node - > registered_observer_list ( ) - > remove_all_matching ( [ & mutation_observer ] ( DOM : : RegisteredObserver & registered_observer ) {
2024-03-13 08:41:24 +01:00
return is < DOM : : TransientRegisteredObserver > ( registered_observer ) & & static_cast < DOM : : TransientRegisteredObserver & > ( registered_observer ) . observer ( ) . ptr ( ) = = mutation_observer ;
2023-11-18 11:22:51 +01:00
} ) ;
}
2022-07-11 16:37:51 +01:00
}
2024-12-05 09:43:27 +00:00
// 4. If records is not empty, then invoke mo’ s callback with « records, mo » and "report", and with callback this value mo.
2022-07-11 16:37:51 +01:00
if ( ! records . is_empty ( ) ) {
2022-09-01 17:59:48 +02:00
auto & callback = mutation_observer - > callback ( ) ;
2024-11-19 00:38:06 +13:00
auto & realm = callback . callback_context ;
2022-07-11 16:37:51 +01:00
2022-12-13 20:49:49 +00:00
auto wrapped_records = MUST ( JS : : Array : : create ( realm , 0 ) ) ;
2022-07-11 16:37:51 +01:00
for ( size_t i = 0 ; i < records . size ( ) ; + + i ) {
auto & record = records . at ( i ) ;
auto property_index = JS : : PropertyKey { i } ;
2022-09-01 17:13:18 +02:00
MUST ( wrapped_records - > create_data_property ( property_index , record . ptr ( ) ) ) ;
2022-07-11 16:37:51 +01:00
}
2024-12-05 09:43:27 +00:00
( void ) WebIDL : : invoke_callback ( callback , mutation_observer , WebIDL : : ExceptionBehavior : : Report , wrapped_records , mutation_observer ) ;
2022-07-11 16:37:51 +01:00
}
}
// FIXME: 6. For each slot of signalSet, fire an event named slotchange, with its bubbles attribute set to true, at slot.
2024-04-13 16:32:39 +02:00
} ) ) ;
2022-07-11 16:37:51 +01:00
}
2022-08-04 21:30:33 +02:00
// https://html.spec.whatwg.org/multipage/webappapis.html#creating-a-new-javascript-realm
2022-08-28 13:42:07 +02:00
NonnullOwnPtr < JS : : ExecutionContext > create_a_new_javascript_realm ( JS : : VM & vm , Function < JS : : Object * ( JS : : Realm & ) > create_global_object , Function < JS : : Object * ( JS : : Realm & ) > create_global_this_value )
2022-08-04 21:30:33 +02:00
{
// 1. Perform InitializeHostDefinedRealm() with the provided customizations for creating the global object and the global this binding.
// 2. Let realm execution context be the running JavaScript execution context.
auto realm_execution_context = MUST ( JS : : Realm : : initialize_host_defined_realm ( vm , move ( create_global_object ) , move ( create_global_this_value ) ) ) ;
// 3. Remove realm execution context from the JavaScript execution context stack.
2023-02-26 16:09:02 -07:00
vm . execution_context_stack ( ) . remove_first_matching ( [ & realm_execution_context ] ( auto execution_context ) {
2022-08-04 21:30:33 +02:00
return execution_context = = realm_execution_context . ptr ( ) ;
} ) ;
// NO-OP: 4. Let realm be realm execution context's Realm component.
// NO-OP: 5. Set realm's agent to agent.
// FIXME: 6. If agent's agent cluster's cross-origin isolation mode is "none", then:
// 1. Let global be realm's global object.
// 2. Let status be ! global.[[Delete]]("SharedArrayBuffer").
// 3. Assert: status is true.
// 7. Return realm execution context.
return realm_execution_context ;
}
2024-11-15 04:01:23 +13:00
void WebEngineCustomData : : spin_event_loop_until ( GC : : Root < GC : : Function < bool ( ) > > goal_condition )
2022-09-08 00:13:39 +02:00
{
Platform : : EventLoopPlugin : : the ( ) . spin_until ( move ( goal_condition ) ) ;
}
2023-03-29 23:46:18 +01:00
// https://html.spec.whatwg.org/multipage/custom-elements.html#invoke-custom-element-reactions
2024-11-15 04:01:23 +13:00
void invoke_custom_element_reactions ( Vector < GC : : Root < DOM : : Element > > & element_queue )
2023-03-29 23:46:18 +01:00
{
// 1. While queue is not empty:
while ( ! element_queue . is_empty ( ) ) {
// 1. Let element be the result of dequeuing from queue.
auto element = element_queue . take_first ( ) ;
// 2. Let reactions be element's custom element reaction queue.
2023-11-19 21:53:58 +01:00
auto * reactions = element - > custom_element_reaction_queue ( ) ;
2023-03-29 23:46:18 +01:00
// 3. Repeat until reactions is empty:
2023-11-19 21:53:58 +01:00
if ( ! reactions )
continue ;
while ( ! reactions - > is_empty ( ) ) {
2023-03-29 23:46:18 +01:00
// 1. Remove the first element of reactions, and let reaction be that element. Switch on reaction's type:
2023-11-19 21:53:58 +01:00
auto reaction = reactions - > take_first ( ) ;
2023-03-29 23:46:18 +01:00
2024-11-23 15:42:01 -07:00
reaction . visit (
[ & ] ( DOM : : CustomElementUpgradeReaction const & custom_element_upgrade_reaction ) - > void {
2023-03-29 23:46:18 +01:00
// -> upgrade reaction
// Upgrade element using reaction's custom element definition.
2024-11-23 15:42:01 -07:00
auto maybe_exception = element - > upgrade_element ( * custom_element_upgrade_reaction . custom_element_definition ) ;
// If this throws an exception, catch it, and report it for reaction's custom element definition's constructor's corresponding JavaScript object's associated realm's global object.
if ( maybe_exception . is_error ( ) ) {
// FIXME: Should it be easier to get to report an exception from an IDL callback?
auto & callback = custom_element_upgrade_reaction . custom_element_definition - > constructor ( ) ;
auto & realm = callback . callback - > shape ( ) . realm ( ) ;
auto & global = realm . global_object ( ) ;
2025-02-02 15:42:57 +00:00
auto & window_or_worker = as < HTML : : WindowOrWorkerGlobalScopeMixin > ( global ) ;
window_or_worker . report_an_exception ( maybe_exception . error_value ( ) ) ;
2024-11-23 15:42:01 -07:00
}
2023-03-29 23:46:18 +01:00
} ,
2024-11-23 15:42:01 -07:00
[ & ] ( DOM : : CustomElementCallbackReaction & custom_element_callback_reaction ) - > void {
2023-03-29 23:46:18 +01:00
// -> callback reaction
2024-12-05 09:49:08 +00:00
// Invoke reaction's callback function with reaction's arguments and "report", and callback this value set to element.
( void ) WebIDL : : invoke_callback ( * custom_element_callback_reaction . callback , element . ptr ( ) , WebIDL : : ExceptionBehavior : : Report , custom_element_callback_reaction . arguments ) ;
2023-03-29 23:46:18 +01:00
} ) ;
}
}
}
2021-02-03 10:41:07 +01:00
}