diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp index ce8a00644622..dc2089fab105 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp @@ -2441,7 +2441,7 @@ static void generate_html_constructor(SourceGenerator& generator, IDL::Construct } constructor_generator.append(R"~~~( - auto& window = verify_cast(HTML::current_global_object()); + auto& window = verify_cast(HTML::current_principal_global_object()); // 1. Let registry be the current global object's CustomElementRegistry object. auto registry = TRY(throw_dom_exception_if_needed(vm, [&] { return window.custom_elements(); })); diff --git a/Userland/Libraries/LibJS/Runtime/Realm.h b/Userland/Libraries/LibJS/Runtime/Realm.h index ff492777380e..2ea3728e30d7 100644 --- a/Userland/Libraries/LibJS/Runtime/Realm.h +++ b/Userland/Libraries/LibJS/Runtime/Realm.h @@ -48,6 +48,8 @@ class Realm final : public Cell { } HostDefined* host_defined() { return m_host_defined; } + HostDefined const* host_defined() const { return m_host_defined; } + void set_host_defined(OwnPtr host_defined) { m_host_defined = move(host_defined); } void define_builtin(Bytecode::Builtin builtin, NonnullGCPtr value) diff --git a/Userland/Libraries/LibWeb/Animations/Animation.cpp b/Userland/Libraries/LibWeb/Animations/Animation.cpp index 9ef693c7b17c..a5e54790b3bb 100644 --- a/Userland/Libraries/LibWeb/Animations/Animation.cpp +++ b/Userland/Libraries/LibWeb/Animations/Animation.cpp @@ -34,7 +34,7 @@ JS::NonnullGCPtr Animation::create(JS::Realm& realm, JS::GCPtr(HTML::current_global_object()); + auto& window = verify_cast(HTML::current_principal_global_object()); timeline = window.associated_document().timeline(); } animation->set_timeline(timeline.release_value()); diff --git a/Userland/Libraries/LibWeb/Bindings/AudioConstructor.cpp b/Userland/Libraries/LibWeb/Bindings/AudioConstructor.cpp index b16a46ec4177..a5fda03f2378 100644 --- a/Userland/Libraries/LibWeb/Bindings/AudioConstructor.cpp +++ b/Userland/Libraries/LibWeb/Bindings/AudioConstructor.cpp @@ -41,7 +41,7 @@ JS::ThrowCompletionOr> AudioConstructor::construct( auto& vm = this->vm(); // 1. Let document be the current global object's associated Document. - auto& window = verify_cast(HTML::current_global_object()); + auto& window = verify_cast(HTML::current_principal_global_object()); auto& document = window.associated_document(); // 2. Let audio be the result of creating an element given document, audio, and the HTML namespace. diff --git a/Userland/Libraries/LibWeb/Bindings/HostDefined.h b/Userland/Libraries/LibWeb/Bindings/HostDefined.h index 54f49ffe4ce2..911df1b09c48 100644 --- a/Userland/Libraries/LibWeb/Bindings/HostDefined.h +++ b/Userland/Libraries/LibWeb/Bindings/HostDefined.h @@ -33,6 +33,11 @@ struct HostDefined : public JS::Realm::HostDefined { return *verify_cast(realm.host_defined())->environment_settings_object; } +[[nodiscard]] inline HTML::EnvironmentSettingsObject const& host_defined_environment_settings_object(JS::Realm const& realm) +{ + return *verify_cast(realm.host_defined())->environment_settings_object; +} + [[nodiscard]] inline Page& host_defined_page(JS::Realm& realm) { return *verify_cast(realm.host_defined())->page; diff --git a/Userland/Libraries/LibWeb/Bindings/ImageConstructor.cpp b/Userland/Libraries/LibWeb/Bindings/ImageConstructor.cpp index 7bb9ae757a0b..594fc880fcda 100644 --- a/Userland/Libraries/LibWeb/Bindings/ImageConstructor.cpp +++ b/Userland/Libraries/LibWeb/Bindings/ImageConstructor.cpp @@ -36,12 +36,13 @@ JS::ThrowCompletionOr ImageConstructor::call() } // https://html.spec.whatwg.org/multipage/embedded-content.html#dom-image +// https://whatpr.org/html/9893/embedded-content.html#dom-image JS::ThrowCompletionOr> ImageConstructor::construct(FunctionObject&) { auto& vm = this->vm(); - // 1. Let document be the current global object's associated Document. - auto& window = verify_cast(HTML::current_global_object()); + // 1. Let document be the current principal global object's associated Document. + auto& window = verify_cast(HTML::current_principal_global_object()); auto& document = window.associated_document(); // 2. Let img be the result of creating an element given document, img, and the HTML namespace. diff --git a/Userland/Libraries/LibWeb/Bindings/MainThreadVM.cpp b/Userland/Libraries/LibWeb/Bindings/MainThreadVM.cpp index 8e50e57a0d1e..ddf574918983 100644 --- a/Userland/Libraries/LibWeb/Bindings/MainThreadVM.cpp +++ b/Userland/Libraries/LibWeb/Bindings/MainThreadVM.cpp @@ -124,6 +124,7 @@ ErrorOr initialize_main_thread_vm(HTML::EventLoop::Type type) // 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 + // https://whatpr.org/html/9893/webappapis.html#the-hostpromiserejectiontracker-implementation s_main_thread_vm->host_promise_rejection_tracker = [](JS::Promise& promise, JS::Promise::RejectionOperation operation) { // 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. @@ -147,8 +148,8 @@ ErrorOr initialize_main_thread_vm(HTML::EventLoop::Type type) } // 3. Let settings object be the current settings object. - // 4. If script is not null, then set settings object to script's settings object. - auto& settings_object = script ? script->settings_object() : HTML::current_settings_object(); + // 4. If script is not null, then set settings object to script's principal settings object. + auto& settings_object = script ? script->settings_object() : HTML::current_principal_settings_object(); // 5. Let global be settingsObject's global object. auto* global_mixin = dynamic_cast(&settings_object.global_object()); @@ -198,14 +199,15 @@ ErrorOr initialize_main_thread_vm(HTML::EventLoop::Type type) }; // 8.1.5.4.1 HostCallJobCallback(callback, V, argumentsList), https://html.spec.whatwg.org/multipage/webappapis.html#hostcalljobcallback + // https://whatpr.org/html/9893/webappapis.html#hostcalljobcallback s_main_thread_vm->host_call_job_callback = [](JS::JobCallback& callback, JS::Value this_value, ReadonlySpan arguments_list) { auto& callback_host_defined = verify_cast(*callback.custom_data()); - // 1. Let incumbent settings be callback.[[HostDefined]].[[IncumbentSettings]]. (NOTE: Not necessary) + // 1. Let incumbent realm be callback.[[HostDefined]].[[IncumbentRealm]]. (NOTE: Not necessary) // 2. Let script execution context be callback.[[HostDefined]].[[ActiveScriptContext]]. (NOTE: Not necessary) - // 3. Prepare to run a callback with incumbent settings. - callback_host_defined.incumbent_settings->prepare_to_run_callback(); + // 3. Prepare to run a callback with incumbent realm. + HTML::prepare_to_run_callback(callback_host_defined.incumbent_settings->realm()); // 4. If script execution context is not null, then push script execution context onto the JavaScript execution context stack. if (callback_host_defined.active_script_context) @@ -220,8 +222,8 @@ ErrorOr initialize_main_thread_vm(HTML::EventLoop::Type type) s_main_thread_vm->pop_execution_context(); } - // 7. Clean up after running a callback with incumbent settings. - callback_host_defined.incumbent_settings->clean_up_after_running_callback(); + // 7. Clean up after running a callback with incumbent realm. + HTML::clean_up_after_running_callback(callback_host_defined.incumbent_settings->realm()); // 8. Return result. return result; @@ -234,25 +236,25 @@ ErrorOr initialize_main_thread_vm(HTML::EventLoop::Type type) // 2. Queue a global task on the JavaScript engine task source given global to perform the following steps: HTML::queue_global_task(HTML::Task::Source::JavaScriptEngine, global, JS::create_heap_function(s_main_thread_vm->heap(), [&finalization_registry] { - // 1. Let entry be finalizationRegistry.[[CleanupCallback]].[[Callback]].[[Realm]]'s environment settings object. - auto& entry = host_defined_environment_settings_object(*finalization_registry.cleanup_callback().callback().realm()); + // 1. Let entry be finalizationRegistry.[[CleanupCallback]].[[Callback]].[[Realm]]. + auto& entry = *finalization_registry.cleanup_callback().callback().realm(); // 2. Check if we can run script with entry. If this returns "do not run", then return. - if (entry.can_run_script() == HTML::RunScriptDecision::DoNotRun) + if (HTML::can_run_script(entry) == HTML::RunScriptDecision::DoNotRun) return; // 3. Prepare to run script with entry. - entry.prepare_to_run_script(); + HTML::prepare_to_run_script(entry); // 4. Let result be the result of performing CleanupFinalizationRegistry(finalizationRegistry). auto result = finalization_registry.cleanup(); // 5. Clean up after running script with entry. - entry.clean_up_after_running_script(); + HTML::clean_up_after_running_script(entry); // 6. If result is an abrupt completion, then report the exception given by result.[[Value]]. if (result.is_error()) - HTML::report_exception(result, finalization_registry.realm()); + HTML::report_exception(result, entry); })); }; @@ -275,22 +277,22 @@ ErrorOr initialize_main_thread_vm(HTML::EventLoop::Type type) auto& heap = realm ? realm->heap() : s_main_thread_vm->heap(); // NOTE: This keeps job_settings alive by keeping realm alive, which is holding onto job_settings. - HTML::queue_a_microtask(script ? script->settings_object().responsible_document().ptr() : nullptr, JS::create_heap_function(heap, [job_settings, job = move(job), script_or_module = move(script_or_module)] { + HTML::queue_a_microtask(script ? script->settings_object().responsible_document().ptr() : nullptr, JS::create_heap_function(heap, [realm, job_settings, job = move(job), script_or_module = move(script_or_module)] { // The dummy execution context has to be kept up here to keep it alive for the duration of the function. OwnPtr dummy_execution_context; - if (job_settings) { - // 1. If job settings is not null, then check if we can run script with job settings. If this returns "do not run" then return. - if (job_settings->can_run_script() == HTML::RunScriptDecision::DoNotRun) + 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) return; - // 2. If job settings is not null, then prepare to run script with job settings. - job_settings->prepare_to_run_script(); + // 2. If realm is not null, then prepare to run script with realm. + HTML::prepare_to_run_script(*realm); // 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. - job_settings->prepare_to_run_callback(); + HTML::prepare_to_run_callback(*realm); // 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. @@ -307,15 +309,15 @@ ErrorOr initialize_main_thread_vm(HTML::EventLoop::Type type) // 3. Let result be job(). auto result = job->function()(); - // 4. If job settings is not null, then clean up after running script with job settings. - if (job_settings) { + // 4. If realm is not null, then clean up after running script with job settings. + if (realm) { // IMPLEMENTATION DEFINED: Disassociate the realm execution context from the script or module. job_settings->realm_execution_context().script_or_module = Empty {}; // IMPLEMENTATION DEFINED: See comment above, we need to clean up the non-standard prepare_to_run_callback() call. - job_settings->clean_up_after_running_callback(); + HTML::clean_up_after_running_callback(*realm); - job_settings->clean_up_after_running_script(); + HTML::clean_up_after_running_script(*realm); } else { // Pop off the dummy execution context. See the above FIXME block about why this is done. s_main_thread_vm->pop_execution_context(); @@ -414,12 +416,13 @@ ErrorOr initialize_main_thread_vm(HTML::EventLoop::Type type) }; // 8.1.6.7.3 HostLoadImportedModule(referrer, moduleRequest, loadState, payload), https://html.spec.whatwg.org/multipage/webappapis.html#hostloadimportedmodule + // https://whatpr.org/html/9893/webappapis.html#hostloadimportedmodule s_main_thread_vm->host_load_imported_module = [](JS::ImportedModuleReferrer referrer, JS::ModuleRequest const& module_request, JS::GCPtr load_state, JS::ImportedModulePayload payload) -> void { auto& vm = *s_main_thread_vm; auto& realm = *vm.current_realm(); - // 1. Let settingsObject be the current settings object. - Optional settings_object = HTML::current_settings_object(); + // 1. Let settingsObject be the current principal settings object. + Optional settings_object = HTML::current_principal_settings_object(); // FIXME: 2. If settingsObject's global object implements WorkletGlobalScope or ServiceWorkerGlobalScope and loadState is undefined, then: diff --git a/Userland/Libraries/LibWeb/Bindings/OptionConstructor.cpp b/Userland/Libraries/LibWeb/Bindings/OptionConstructor.cpp index 4e19d3f8a334..3777674811cd 100644 --- a/Userland/Libraries/LibWeb/Bindings/OptionConstructor.cpp +++ b/Userland/Libraries/LibWeb/Bindings/OptionConstructor.cpp @@ -39,13 +39,14 @@ JS::ThrowCompletionOr OptionConstructor::call() } // https://html.spec.whatwg.org/multipage/form-elements.html#dom-option +// https://whatpr.org/html/9893/form-elements.html#dom-option JS::ThrowCompletionOr> OptionConstructor::construct(FunctionObject&) { auto& vm = this->vm(); auto& realm = *vm.current_realm(); - // 1. Let document be the current global object's associated Document. - auto& window = verify_cast(HTML::current_global_object()); + // 1. Let document be the current principal global object's associated Document. + auto& window = verify_cast(HTML::current_principal_global_object()); auto& document = window.associated_document(); // 2. Let option be the result of creating an element given document, option, and the HTML namespace. diff --git a/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.cpp b/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.cpp index 278ef39a84ad..334962c38390 100644 --- a/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.cpp +++ b/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.cpp @@ -34,8 +34,8 @@ WebIDL::ExceptionOr> CSSStyleSheet::construct_im // 1. Construct a new CSSStyleSheet object sheet. auto sheet = create(realm, CSSRuleList::create_empty(realm), CSS::MediaList::create(realm, {}), {}); - // 2. Set sheet’s location to the base URL of the associated Document for the current global object. - auto associated_document = verify_cast(HTML::current_global_object()).document(); + // 2. Set sheet’s location to the base URL of the associated Document for the current principal global object. + auto associated_document = verify_cast(HTML::current_principal_global_object()).document(); sheet->set_location(MUST(associated_document->base_url().to_string())); // 3. Set sheet’s stylesheet base URL to the baseURL attribute value from options. diff --git a/Userland/Libraries/LibWeb/DOM/Node.cpp b/Userland/Libraries/LibWeb/DOM/Node.cpp index bc8031c2089b..7740144e8938 100644 --- a/Userland/Libraries/LibWeb/DOM/Node.cpp +++ b/Userland/Libraries/LibWeb/DOM/Node.cpp @@ -1450,16 +1450,18 @@ void Node::serialize_tree_as_json(JsonObjectSerializer& object) c } // https://html.spec.whatwg.org/multipage/webappapis.html#concept-n-script +// https://whatpr.org/html/9893/webappapis.html#concept-n-script bool Node::is_scripting_enabled() const { - // Scripting is enabled for a node node if node's node document's browsing context is non-null, and scripting is enabled for node's relevant settings object. - return document().browsing_context() && const_cast(document()).relevant_settings_object().is_scripting_enabled(); + // Scripting is enabled for a node node if node's node document's browsing context is non-null, and scripting is enabled for node's relevant realm. + return document().browsing_context() && HTML::is_scripting_enabled(HTML::relevant_realm(*this)); } // https://html.spec.whatwg.org/multipage/webappapis.html#concept-n-noscript +// https://whatpr.org/html/9893/webappapis.html#concept-n-script bool Node::is_scripting_disabled() const { - // Scripting is disabled for a node when scripting is not enabled, i.e., when its node document's browsing context is null or when scripting is disabled for its relevant settings object. + // Scripting is disabled for a node when scripting is not enabled, i.e., when its node document's browsing context is null or when scripting is disabled for its relevant realm. return !is_scripting_enabled(); } diff --git a/Userland/Libraries/LibWeb/DOM/Text.cpp b/Userland/Libraries/LibWeb/DOM/Text.cpp index 0eea95fee59b..1f3895c08613 100644 --- a/Userland/Libraries/LibWeb/DOM/Text.cpp +++ b/Userland/Libraries/LibWeb/DOM/Text.cpp @@ -44,7 +44,7 @@ void Text::visit_edges(Cell::Visitor& visitor) WebIDL::ExceptionOr> Text::construct_impl(JS::Realm& realm, String const& data) { // The new Text(data) constructor steps are to set this’s data to data and this’s node document to current global object’s associated Document. - auto& window = verify_cast(HTML::current_global_object()); + auto& window = verify_cast(HTML::current_principal_global_object()); return realm.heap().allocate(realm, window.associated_document(), data); } diff --git a/Userland/Libraries/LibWeb/DOMURL/DOMURL.cpp b/Userland/Libraries/LibWeb/DOMURL/DOMURL.cpp index 2b6bede35f3f..5fdc33836a9a 100644 --- a/Userland/Libraries/LibWeb/DOMURL/DOMURL.cpp +++ b/Userland/Libraries/LibWeb/DOMURL/DOMURL.cpp @@ -144,7 +144,7 @@ WebIDL::ExceptionOr DOMURL::revoke_object_url(JS::VM& vm, StringView url) auto origin = url_record.origin(); // 4. Let settings be the current settings object. - auto& settings = HTML::current_settings_object(); + auto& settings = HTML::current_principal_settings_object(); // 5. If origin is not same origin with settings’s origin, return. if (!origin.is_same_origin(settings.origin())) diff --git a/Userland/Libraries/LibWeb/Fetch/Response.cpp b/Userland/Libraries/LibWeb/Fetch/Response.cpp index 4acc5c24b877..1f74a9a41fae 100644 --- a/Userland/Libraries/LibWeb/Fetch/Response.cpp +++ b/Userland/Libraries/LibWeb/Fetch/Response.cpp @@ -168,7 +168,7 @@ WebIDL::ExceptionOr> Response::redirect(JS::VM& vm, S auto& realm = *vm.current_realm(); // 1. Let parsedURL be the result of parsing url with current settings object’s API base URL. - auto api_base_url = HTML::current_settings_object().api_base_url(); + auto api_base_url = HTML::current_principal_settings_object().api_base_url(); auto parsed_url = DOMURL::parse(url, api_base_url); // 2. If parsedURL is failure, then throw a TypeError. diff --git a/Userland/Libraries/LibWeb/FileAPI/Blob.cpp b/Userland/Libraries/LibWeb/FileAPI/Blob.cpp index e9fd67127acd..aa9880c74108 100644 --- a/Userland/Libraries/LibWeb/FileAPI/Blob.cpp +++ b/Userland/Libraries/LibWeb/FileAPI/Blob.cpp @@ -335,17 +335,17 @@ JS::NonnullGCPtr Blob::get_stream() // 2. Queue a global task on the file reading task source given blob’s relevant global object to perform the following steps: HTML::queue_global_task(HTML::Task::Source::FileReading, realm.global_object(), JS::create_heap_function(heap(), [stream, bytes = move(bytes)]() { - // NOTE: Using an TemporaryExecutionContext here results in a crash in the method HTML::incumbent_settings_object() + // NOTE: Using an TemporaryExecutionContext here results in a crash in the method HTML::incumbent_realm() // since we end up in a state where we have no execution context + an event loop with an empty incumbent - // settings object stack. We still need an execution context therefore we push the realm's execution context - // onto the realm's VM, and we need an incumbent settings object which is pushed onto the incumbent settings - // object stack by EnvironmentSettings::prepare_to_run_callback(). + // realm stack. We still need an execution context therefore we push the realm's execution context + // onto the realm's VM, and we need an incumbent realm which is pushed onto the incumbent realm stack + // by HTML::prepare_to_run_callback(). auto& realm = stream->realm(); auto& environment_settings = Bindings::host_defined_environment_settings_object(realm); realm.vm().push_execution_context(environment_settings.realm_execution_context()); - environment_settings.prepare_to_run_callback(); - ScopeGuard const guard = [&environment_settings, &realm] { - environment_settings.clean_up_after_running_callback(); + HTML::prepare_to_run_callback(realm); + ScopeGuard const guard = [&realm] { + HTML::clean_up_after_running_callback(realm); realm.vm().pop_execution_context(); }; diff --git a/Userland/Libraries/LibWeb/FileAPI/BlobURLStore.cpp b/Userland/Libraries/LibWeb/FileAPI/BlobURLStore.cpp index 9b2648aaaa0a..41b7132faf55 100644 --- a/Userland/Libraries/LibWeb/FileAPI/BlobURLStore.cpp +++ b/Userland/Libraries/LibWeb/FileAPI/BlobURLStore.cpp @@ -33,7 +33,7 @@ ErrorOr generate_new_blob_url() TRY(result.try_append("blob:"sv)); // 3. Let settings be the current settings object - auto& settings = HTML::current_settings_object(); + auto& settings = HTML::current_principal_settings_object(); // 4. Let origin be settings’s origin. auto origin = settings.origin(); @@ -69,7 +69,7 @@ ErrorOr add_entry_to_blob_url_store(JS::NonnullGCPtr object) auto url = TRY(generate_new_blob_url()); // 3. Let entry be a new blob URL entry consisting of object and the current settings object. - BlobURLEntry entry { object, HTML::current_settings_object() }; + BlobURLEntry entry { object, HTML::current_principal_settings_object() }; // 4. Set store[url] to entry. TRY(store.try_set(url, move(entry))); diff --git a/Userland/Libraries/LibWeb/HTML/CrossOrigin/AbstractOperations.cpp b/Userland/Libraries/LibWeb/HTML/CrossOrigin/AbstractOperations.cpp index e53ba2e649d7..795c2d9f59f9 100644 --- a/Userland/Libraries/LibWeb/HTML/CrossOrigin/AbstractOperations.cpp +++ b/Userland/Libraries/LibWeb/HTML/CrossOrigin/AbstractOperations.cpp @@ -81,23 +81,25 @@ JS::ThrowCompletionOr cross_origin_property_fallback(JS: return throw_completion(WebIDL::SecurityError::create(*vm.current_realm(), MUST(String::formatted("Can't access property '{}' on cross-origin object", property_key)))); } -// 7.2.3.3 IsPlatformObjectSameOrigin ( O ), https://html.spec.whatwg.org/multipage/browsers.html#isplatformobjectsameorigin-(-o-) +// 7.2.3.3 IsPlatformObjectSameOrigin ( O ), https://html.spec.whatwg.org/multipage/nav-history-apis.html#isplatformobjectsameorigin-(-o-) +// https://whatpr.org/html/9893/nav-history-apis.html#isplatformobjectsameorigin-(-o-) bool is_platform_object_same_origin(JS::Object const& object) { - // 1. Return true if the current settings object's origin is same origin-domain with O's relevant settings object's origin, and false otherwise. - return HTML::current_settings_object().origin().is_same_origin_domain(HTML::relevant_settings_object(object).origin()); + // 1. Return true if the current principal settings object's origin is same origin-domain with O's relevant settings object's origin, and false otherwise. + return HTML::current_principal_settings_object().origin().is_same_origin_domain(HTML::relevant_settings_object(object).origin()); } -// 7.2.3.4 CrossOriginGetOwnPropertyHelper ( O, P ), https://html.spec.whatwg.org/multipage/browsers.html#crossorigingetownpropertyhelper-(-o,-p-) +// 7.2.3.4 CrossOriginGetOwnPropertyHelper ( O, P ), https://html.spec.whatwg.org/multipage/nav-history-apis.html#crossorigingetownpropertyhelper-(-o,-p-) +// https://whatpr.org/html/9893/nav-history-apis.html#crossorigingetownpropertyhelper-(-o,-p-) Optional cross_origin_get_own_property_helper(Variant const& object, JS::PropertyKey const& property_key) { auto& realm = *Bindings::main_thread_vm().current_realm(); auto const* object_ptr = object.visit([](auto* o) { return static_cast(o); }); auto const object_const_variant = object.visit([](auto* o) { return Variant { o }; }); - // 1. Let crossOriginKey be a tuple consisting of the current settings object, O's relevant settings object, and P. + // 1. Let crossOriginKey be a tuple consisting of the current principal settings object, O's relevant settings object, and P. auto cross_origin_key = CrossOriginKey { - .current_settings_object = (FlatPtr)&HTML::current_settings_object(), + .current_principal_settings_object = (FlatPtr)&HTML::current_principal_settings_object(), .relevant_settings_object = (FlatPtr)&HTML::relevant_settings_object(*object_ptr), .property_key = property_key, }; diff --git a/Userland/Libraries/LibWeb/HTML/CrossOrigin/CrossOriginPropertyDescriptorMap.h b/Userland/Libraries/LibWeb/HTML/CrossOrigin/CrossOriginPropertyDescriptorMap.h index 5b44062c0afe..9a735c2fe76d 100644 --- a/Userland/Libraries/LibWeb/HTML/CrossOrigin/CrossOriginPropertyDescriptorMap.h +++ b/Userland/Libraries/LibWeb/HTML/CrossOrigin/CrossOriginPropertyDescriptorMap.h @@ -22,7 +22,7 @@ struct CrossOriginProperty { }; struct CrossOriginKey { - FlatPtr current_settings_object; + FlatPtr current_principal_settings_object; FlatPtr relevant_settings_object; JS::PropertyKey property_key; }; @@ -39,12 +39,12 @@ struct Traits : public DefaultTraits::hash(key.property_key), - pair_int_hash(ptr_hash(key.current_settings_object), ptr_hash(key.relevant_settings_object))); + pair_int_hash(ptr_hash(key.current_principal_settings_object), ptr_hash(key.relevant_settings_object))); } static bool equals(Web::HTML::CrossOriginKey const& a, Web::HTML::CrossOriginKey const& b) { - return a.current_settings_object == b.current_settings_object + return a.current_principal_settings_object == b.current_principal_settings_object && a.relevant_settings_object == b.relevant_settings_object && Traits::equals(a.property_key, b.property_key); } diff --git a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp index 45f6954f36fb..3dd72c05bfab 100644 --- a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp +++ b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp @@ -46,7 +46,7 @@ void EventLoop::visit_edges(Visitor& visitor) visitor.visit(m_task_queue); visitor.visit(m_microtask_queue); visitor.visit(m_currently_running_task); - visitor.visit(m_backup_incumbent_settings_object_stack); + visitor.visit(m_backup_incumbent_realm_stack); visitor.visit(m_rendering_task_function); visitor.visit(m_system_event_loop_timer); } @@ -538,19 +538,19 @@ void EventLoop::unregister_document(Badge, DOM::Document& documen VERIFY(did_remove); } -void EventLoop::push_onto_backup_incumbent_settings_object_stack(Badge, EnvironmentSettingsObject& environment_settings_object) +void EventLoop::push_onto_backup_incumbent_realm_stack(JS::Realm& realm) { - m_backup_incumbent_settings_object_stack.append(environment_settings_object); + m_backup_incumbent_realm_stack.append(realm); } -void EventLoop::pop_backup_incumbent_settings_object_stack(Badge) +void EventLoop::pop_backup_incumbent_realm_stack() { - m_backup_incumbent_settings_object_stack.take_last(); + m_backup_incumbent_realm_stack.take_last(); } -EnvironmentSettingsObject& EventLoop::top_of_backup_incumbent_settings_object_stack() +JS::Realm& EventLoop::top_of_backup_incumbent_realm_stack() { - return m_backup_incumbent_settings_object_stack.last(); + return m_backup_incumbent_realm_stack.last(); } void EventLoop::register_environment_settings_object(Badge, EnvironmentSettingsObject& environment_settings_object) diff --git a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.h b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.h index e197c9b9801d..b743ab6ab40b 100644 --- a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.h +++ b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.h @@ -61,10 +61,10 @@ class EventLoop : public JS::Cell { Vector> same_loop_windows() const; - void push_onto_backup_incumbent_settings_object_stack(Badge, EnvironmentSettingsObject& environment_settings_object); - void pop_backup_incumbent_settings_object_stack(Badge); - EnvironmentSettingsObject& top_of_backup_incumbent_settings_object_stack(); - bool is_backup_incumbent_settings_object_stack_empty() const { return m_backup_incumbent_settings_object_stack.is_empty(); } + void push_onto_backup_incumbent_realm_stack(JS::Realm&); + void pop_backup_incumbent_realm_stack(); + JS::Realm& top_of_backup_incumbent_realm_stack(); + bool is_backup_incumbent_realm_stack_empty() const { return m_backup_incumbent_realm_stack.is_empty(); } void register_environment_settings_object(Badge, EnvironmentSettingsObject&); void unregister_environment_settings_object(Badge, EnvironmentSettingsObject&); @@ -107,7 +107,8 @@ class EventLoop : public JS::Cell { Vector> m_related_environment_settings_objects; // https://html.spec.whatwg.org/multipage/webappapis.html#backup-incumbent-settings-object-stack - Vector> m_backup_incumbent_settings_object_stack; + // https://whatpr.org/html/9893/webappapis.html#backup-incumbent-realm-stack + Vector> m_backup_incumbent_realm_stack; // https://html.spec.whatwg.org/multipage/browsing-the-web.html#termination-nesting-level size_t m_termination_nesting_level { 0 }; diff --git a/Userland/Libraries/LibWeb/HTML/Location.cpp b/Userland/Libraries/LibWeb/HTML/Location.cpp index 86350eabcd23..d0998b3236af 100644 --- a/Userland/Libraries/LibWeb/HTML/Location.cpp +++ b/Userland/Libraries/LibWeb/HTML/Location.cpp @@ -110,7 +110,7 @@ WebIDL::ExceptionOr Location::href() const WebIDL::ExceptionOr Location::set_href(String const& new_href) { auto& realm = this->realm(); - auto& window = verify_cast(HTML::current_global_object()); + auto& window = verify_cast(HTML::current_principal_global_object()); // 1. If this's relevant Document is null, then return. auto const relevant_document = this->relevant_document(); diff --git a/Userland/Libraries/LibWeb/HTML/Navigation.cpp b/Userland/Libraries/LibWeb/HTML/Navigation.cpp index 68719f53dd2b..4e8aa8b0789d 100644 --- a/Userland/Libraries/LibWeb/HTML/Navigation.cpp +++ b/Userland/Libraries/LibWeb/HTML/Navigation.cpp @@ -1402,6 +1402,7 @@ void Navigation::initialize_the_navigation_api_entries_for_a_new_document(Vector } // https://html.spec.whatwg.org/multipage/nav-history-apis.html#update-the-navigation-api-entries-for-a-same-document-navigation +// https://whatpr.org/html/9893/nav-history-apis.html#update-the-navigation-api-entries-for-a-same-document-navigation void Navigation::update_the_navigation_api_entries_for_a_same_document_navigation(JS::NonnullGCPtr destination_she, Bindings::NavigationType navigation_type) { auto& realm = relevant_realm(*this); @@ -1482,8 +1483,8 @@ void Navigation::update_the_navigation_api_entries_for_a_same_document_navigatio if (m_ongoing_api_method_tracker != nullptr) notify_about_the_committed_to_entry(*m_ongoing_api_method_tracker, *current_entry()); - // 9. Prepare to run script given navigation's relevant settings object. - relevant_settings_object(*this).prepare_to_run_script(); + // 9. Prepare to run script given navigation's relevant realm. + prepare_to_run_script(realm); // 10. Fire an event named currententrychange at navigation using NavigationCurrentEntryChangeEvent, // with its navigationType attribute initialized to navigationType and its from initialized to oldCurrentNHE. @@ -1498,8 +1499,8 @@ void Navigation::update_the_navigation_api_entries_for_a_same_document_navigatio disposed_nhe->dispatch_event(DOM::Event::create(realm, EventNames::dispose, {})); } - // 12. Clean up after running script given navigation's relevant settings object. - relevant_settings_object(*this).clean_up_after_running_script(); + // 12. Clean up after running script given navigation's relevant realm. + clean_up_after_running_script(relevant_realm(*this)); } } diff --git a/Userland/Libraries/LibWeb/HTML/Navigator.cpp b/Userland/Libraries/LibWeb/HTML/Navigator.cpp index dba3531ef4bc..83953ab59f6b 100644 --- a/Userland/Libraries/LibWeb/HTML/Navigator.cpp +++ b/Userland/Libraries/LibWeb/HTML/Navigator.cpp @@ -45,7 +45,7 @@ bool Navigator::pdf_viewer_enabled() const { // The NavigatorPlugins mixin's pdfViewerEnabled getter steps are to return the user agent's PDF viewer supported. // NOTE: The NavigatorPlugins mixin should only be exposed on the Window object. - auto const& window = verify_cast(HTML::current_global_object()); + auto const& window = verify_cast(HTML::current_principal_global_object()); return window.page().pdf_viewer_supported(); } @@ -55,7 +55,7 @@ bool Navigator::webdriver() const // Returns true if webdriver-active flag is set, false otherwise. // NOTE: The NavigatorAutomationInformation interface should not be exposed on WorkerNavigator. - auto const& window = verify_cast(HTML::current_global_object()); + auto const& window = verify_cast(HTML::current_principal_global_object()); return window.page().is_webdriver_active(); } diff --git a/Userland/Libraries/LibWeb/HTML/Scripting/ClassicScript.cpp b/Userland/Libraries/LibWeb/HTML/Scripting/ClassicScript.cpp index 198501aa3521..cd8994e97c16 100644 --- a/Userland/Libraries/LibWeb/HTML/Scripting/ClassicScript.cpp +++ b/Userland/Libraries/LibWeb/HTML/Scripting/ClassicScript.cpp @@ -19,39 +19,41 @@ namespace Web::HTML { JS_DEFINE_ALLOCATOR(ClassicScript); // https://html.spec.whatwg.org/multipage/webappapis.html#creating-a-classic-script +// https://whatpr.org/html/9893/webappapis.html#creating-a-classic-script JS::NonnullGCPtr ClassicScript::create(ByteString filename, StringView source, EnvironmentSettingsObject& environment_settings_object, URL::URL base_url, size_t source_line_number, MutedErrors muted_errors) { - auto& vm = environment_settings_object.realm().vm(); + auto& realm = environment_settings_object.realm(); + auto& vm = realm.vm(); - // 1. If muted errors was not provided, let it be false. (NOTE: This is taken care of by the default argument.) - - // 2. If muted errors is true, then set baseURL to about:blank. + // 1. If muted errors is true, then set baseURL to about:blank. if (muted_errors == MutedErrors::Yes) base_url = "about:blank"sv; - // 3. If scripting is disabled for settings, then set source to the empty string. - if (environment_settings_object.is_scripting_disabled()) + // 2. If scripting is disabled for realm, then set source to the empty string. + if (is_scripting_disabled(realm)) source = ""sv; - // 4. Let script be a new classic script that this algorithm will subsequently initialize. + // 3. Let script be a new classic script that this algorithm will subsequently initialize. auto script = vm.heap().allocate_without_realm(move(base_url), move(filename), environment_settings_object); - // 5. Set script's settings object to settings. (NOTE: This was already done when constructing.) + // FIXME: 4. Set script's realm to realm. (NOTE: This was already done when constructing.) - // 6. Set script's base URL to baseURL. (NOTE: This was already done when constructing.) + // 5. Set script's base URL to baseURL. (NOTE: This was already done when constructing.) - // FIXME: 7. Set script's fetch options to options. + // FIXME: 6. Set script's fetch options to options. - // 8. Set script's muted errors to muted errors. + // 7. Set script's muted errors to muted errors. script->m_muted_errors = muted_errors; - // 9. Set script's parse error and error to rethrow to null. + // 8. Set script's parse error and error to rethrow to null. script->set_parse_error(JS::js_null()); script->set_error_to_rethrow(JS::js_null()); - // 10. Let result be ParseScript(source, settings's Realm, script). + // FIXME: 9. Record classic script creation time given script and sourceURLForWindowScripts . + + // 10. Let result be ParseScript(source, realm, script). auto parse_timer = Core::ElapsedTimer::start_new(); - auto result = JS::Script::parse(source, environment_settings_object.realm(), script->filename(), script, source_line_number); + auto result = JS::Script::parse(source, realm, script->filename(), script, source_line_number); dbgln_if(HTML_SCRIPT_DEBUG, "ClassicScript: Parsed {} in {}ms", script->filename(), parse_timer.elapsed()); // 11. If result is a list of errors, then: @@ -60,7 +62,7 @@ JS::NonnullGCPtr ClassicScript::create(ByteString filename, Strin dbgln_if(HTML_SCRIPT_DEBUG, "ClassicScript: Failed to parse: {}", parse_error.to_string()); // 1. Set script's parse error and its error to rethrow to result[0]. - script->set_parse_error(JS::SyntaxError::create(environment_settings_object.realm(), parse_error.to_string())); + script->set_parse_error(JS::SyntaxError::create(realm, parse_error.to_string())); script->set_error_to_rethrow(script->parse_error()); // 2. Return script. @@ -75,17 +77,19 @@ JS::NonnullGCPtr ClassicScript::create(ByteString filename, Strin } // https://html.spec.whatwg.org/multipage/webappapis.html#run-a-classic-script +// https://whatpr.org/html/9893/webappapis.html#run-a-classic-script JS::Completion ClassicScript::run(RethrowErrors rethrow_errors) { // 1. Let settings be the settings object of script. auto& settings = settings_object(); + auto& realm = settings.realm(); // 2. Check if we can run script with settings. If this returns "do not run" then return NormalCompletion(empty). - if (settings.can_run_script() == RunScriptDecision::DoNotRun) + if (can_run_script(realm) == RunScriptDecision::DoNotRun) return JS::normal_completion({}); - // 3. Prepare to run script given settings. - settings.prepare_to_run_script(); + // 3. Prepare to run script given realm. + prepare_to_run_script(realm); // 4. Let evaluationStatus be null. JS::Completion evaluation_status; @@ -108,8 +112,8 @@ JS::Completion ClassicScript::run(RethrowErrors rethrow_errors) if (evaluation_status.is_abrupt()) { // 1. If rethrow errors is true and script's muted errors is false, then: if (rethrow_errors == RethrowErrors::Yes && m_muted_errors == MutedErrors::No) { - // 1. Clean up after running script with settings. - settings.clean_up_after_running_script(); + // 1. Clean up after running script with realm. + clean_up_after_running_script(realm); // 2. Rethrow evaluationStatus.[[Value]]. return JS::throw_completion(*evaluation_status.value()); @@ -117,11 +121,11 @@ JS::Completion ClassicScript::run(RethrowErrors rethrow_errors) // 2. If rethrow errors is true and script's muted errors is true, then: if (rethrow_errors == RethrowErrors::Yes && m_muted_errors == MutedErrors::Yes) { - // 1. Clean up after running script with settings. - settings.clean_up_after_running_script(); + // 1. Clean up after running script with realm. + clean_up_after_running_script(realm); // 2. Throw a "NetworkError" DOMException. - return throw_completion(WebIDL::NetworkError::create(settings.realm(), "Script error."_string)); + return throw_completion(WebIDL::NetworkError::create(realm, "Script error."_string)); } // 3. Otherwise, rethrow errors is false. Perform the following steps: @@ -132,15 +136,15 @@ JS::Completion ClassicScript::run(RethrowErrors rethrow_errors) VERIFY(window_or_worker); window_or_worker->report_an_exception(*evaluation_status.value()); - // 2. Clean up after running script with settings. - settings.clean_up_after_running_script(); + // 2. Clean up after running script with realm. + clean_up_after_running_script(realm); // 3. Return evaluationStatus. return evaluation_status; } - // 8. Clean up after running script with settings. - settings.clean_up_after_running_script(); + // 8. Clean up after running script with realm. + clean_up_after_running_script(realm); // 9. If evaluationStatus is a normal completion, then return evaluationStatus. VERIFY(!evaluation_status.is_abrupt()); diff --git a/Userland/Libraries/LibWeb/HTML/Scripting/Environments.cpp b/Userland/Libraries/LibWeb/HTML/Scripting/Environments.cpp index 7becdf0d7d6c..119bb183424d 100644 --- a/Userland/Libraries/LibWeb/HTML/Scripting/Environments.cpp +++ b/Userland/Libraries/LibWeb/HTML/Scripting/Environments.cpp @@ -2,6 +2,7 @@ * Copyright (c) 2021, Luke Wilde * Copyright (c) 2022, Linus Groh * Copyright (c) 2022, networkException + * Copyright (c) 2024, Shannon Booth * * SPDX-License-Identifier: BSD-2-Clause */ @@ -65,6 +66,12 @@ JS::ExecutionContext& EnvironmentSettingsObject::realm_execution_context() return *m_realm_execution_context; } +JS::ExecutionContext const& EnvironmentSettingsObject::realm_execution_context() const +{ + // NOTE: All environment settings objects are created with a realm execution context, so it's stored and returned here in the base class. + return *m_realm_execution_context; +} + ModuleMap& EnvironmentSettingsObject::module_map() { return *m_module_map; @@ -100,14 +107,15 @@ EventLoop& EnvironmentSettingsObject::responsible_event_loop() } // https://html.spec.whatwg.org/multipage/webappapis.html#check-if-we-can-run-script -RunScriptDecision EnvironmentSettingsObject::can_run_script() +// https://whatpr.org/html/9893/webappapis.html#check-if-we-can-run-script +RunScriptDecision can_run_script(JS::Realm const& realm) { - // 1. If the global object specified by settings is a Window object whose Document object is not fully active, then return "do not run". - if (is(global_object()) && !verify_cast(global_object()).associated_document().is_fully_active()) + // 1. If the global object specified by realm is a Window object whose Document object is not fully active, then return "do not run". + if (is(realm.global_object()) && !verify_cast(realm.global_object()).associated_document().is_fully_active()) return RunScriptDecision::DoNotRun; - // 2. If scripting is disabled for settings, then return "do not run". - if (is_scripting_disabled()) + // 2. If scripting is disabled for realm, then return "do not run". + if (is_scripting_disabled(realm)) return RunScriptDecision::DoNotRun; // 3. Return "run". @@ -115,28 +123,41 @@ RunScriptDecision EnvironmentSettingsObject::can_run_script() } // https://html.spec.whatwg.org/multipage/webappapis.html#prepare-to-run-script -void EnvironmentSettingsObject::prepare_to_run_script() +// https://whatpr.org/html/9893/b8ea975...df5706b/webappapis.html#prepare-to-run-script +void prepare_to_run_script(JS::Realm& realm) { - // 1. Push settings's realm execution context onto the JavaScript execution context stack; it is now the running JavaScript execution context. - global_object().vm().push_execution_context(realm_execution_context()); + // 1. Push realms's execution context onto the JavaScript execution context stack; it is now the running JavaScript execution context. + realm.global_object().vm().push_execution_context(execution_context_of_realm(realm)); + + // FIXME: 2. If realm is a principal realm, then: + // FIXME: 2.1 Let settings be realm's settings object. + // FIXME: 2.2 Add settings to the currently running task's script evaluation environment settings object set. +} - // FIXME: 2. Add settings to the currently running task's script evaluation environment settings object set. +// https://whatpr.org/html/9893/b8ea975...df5706b/webappapis.html#concept-realm-execution-context +JS::ExecutionContext const& execution_context_of_realm(JS::Realm const& realm) +{ + // FIXME: 1. If realm is a principal realm, then return the realm execution context of the environment settings object of realm. + // FIXME: 2. Assert: realm is a synthetic realm. + // FIXME: 3. Return the execution context of the synthetic realm settings object of realm. + return Bindings::host_defined_environment_settings_object(realm).realm_execution_context(); } // https://html.spec.whatwg.org/multipage/webappapis.html#clean-up-after-running-script -void EnvironmentSettingsObject::clean_up_after_running_script() +// https://whatpr.org/html/9893/webappapis.html#clean-up-after-running-script +void clean_up_after_running_script(JS::Realm const& realm) { - auto& vm = global_object().vm(); + auto& vm = realm.global_object().vm(); - // 1. Assert: settings's realm execution context is the running JavaScript execution context. - VERIFY(&realm_execution_context() == &vm.running_execution_context()); + // 1. Assert: realm's execution context is the running JavaScript execution context. + VERIFY(&execution_context_of_realm(realm) == &vm.running_execution_context()); - // 2. Remove settings's realm execution context from the JavaScript execution context stack. + // 2. Remove realm's execution context from the JavaScript execution context stack. vm.pop_execution_context(); // 3. If the JavaScript execution context stack is now empty, perform a microtask checkpoint. (If this runs scripts, these algorithms will be invoked reentrantly.) if (vm.execution_context_stack().is_empty()) - responsible_event_loop().perform_a_microtask_checkpoint(); + main_thread_event_loop().perform_a_microtask_checkpoint(); } static JS::ExecutionContext* top_most_script_having_execution_context(JS::VM& vm) @@ -154,14 +175,14 @@ static JS::ExecutionContext* top_most_script_having_execution_context(JS::VM& vm } // https://html.spec.whatwg.org/multipage/webappapis.html#prepare-to-run-a-callback -void EnvironmentSettingsObject::prepare_to_run_callback() +void prepare_to_run_callback(JS::Realm& realm) { - auto& vm = global_object().vm(); + auto& vm = realm.global_object().vm(); - // 1. Push settings onto the backup incumbent settings object stack. + // 1. Push realm onto the backup incumbent settings object stack. // NOTE: The spec doesn't say which event loop's stack to put this on. However, all the examples of the incumbent settings object use iframes and cross browsing context communication to demonstrate the concept. // This means that it must rely on some global state that can be accessed by all browsing contexts, which is the main thread event loop. - HTML::main_thread_event_loop().push_onto_backup_incumbent_settings_object_stack({}, *this); + HTML::main_thread_event_loop().push_onto_backup_incumbent_realm_stack(realm); // 2. Let context be the topmost script-having execution context. auto* context = top_most_script_having_execution_context(vm); @@ -188,9 +209,10 @@ URL::URL EnvironmentSettingsObject::parse_url(StringView url) } // https://html.spec.whatwg.org/multipage/webappapis.html#clean-up-after-running-a-callback -void EnvironmentSettingsObject::clean_up_after_running_callback() +// https://whatpr.org/html/9893/b8ea975...df5706b/webappapis.html#clean-up-after-running-a-callback +void clean_up_after_running_callback(JS::Realm const& realm) { - auto& vm = global_object().vm(); + auto& vm = realm.global_object().vm(); // 1. Let context be the topmost script-having execution context. auto* context = top_most_script_having_execution_context(vm); @@ -199,29 +221,29 @@ void EnvironmentSettingsObject::clean_up_after_running_callback() if (context) context->skip_when_determining_incumbent_counter--; - // 3. Assert: the topmost entry of the backup incumbent settings object stack is settings. + // 3. Assert: the topmost entry of the backup incumbent realm stack is realm. auto& event_loop = HTML::main_thread_event_loop(); - VERIFY(&event_loop.top_of_backup_incumbent_settings_object_stack() == this); + VERIFY(&event_loop.top_of_backup_incumbent_realm_stack() == &realm); - // 4. Remove settings from the backup incumbent settings object stack. - event_loop.pop_backup_incumbent_settings_object_stack({}); + // 4. Remove realm from the backup incumbent realm stack. + event_loop.pop_backup_incumbent_realm_stack(); } // https://html.spec.whatwg.org/multipage/webappapis.html#concept-environment-script -bool EnvironmentSettingsObject::is_scripting_enabled() const +// https://whatpr.org/html/9893/webappapis.html#concept-environment-script +bool is_scripting_enabled(JS::Realm const& realm) { - // Scripting is enabled for an environment settings object settings when all of the following conditions are true: + // Scripting is enabled for a realm realm when all of the following conditions are true: // The user agent supports scripting. // NOTE: This is always true in LibWeb :^) // FIXME: Do the right thing for workers. - if (!is(m_realm_execution_context->realm->global_object())) + if (!is(realm.global_object())) return true; - // The user has not disabled scripting for settings at this time. (User agents may provide users with the option to disable scripting globally, or in a finer-grained manner, e.g., on a per-origin basis, down to the level of individual environment settings objects.) - auto document = const_cast(*this).responsible_document(); - VERIFY(document); - if (!document->page().is_scripting_enabled()) + // The user has not disabled scripting for realm at this time. (User agents may provide users with the option to disable scripting globally, or in a finer-grained manner, e.g., on a per-origin basis, down to the level of individual realms.) + auto const& document = verify_cast(realm.global_object()).associated_document(); + if (!document.page().is_scripting_enabled()) return false; // FIXME: Either settings's global object is not a Window object, or settings's global object's associated Document's active sandboxing flag set does not have its sandboxed scripts browsing context flag set. @@ -230,10 +252,11 @@ bool EnvironmentSettingsObject::is_scripting_enabled() const } // https://html.spec.whatwg.org/multipage/webappapis.html#concept-environment-noscript -bool EnvironmentSettingsObject::is_scripting_disabled() const +// https://whatpr.org/html/9893/webappapis.html#concept-environment-noscript +bool is_scripting_disabled(JS::Realm const& realm) { - // Scripting is disabled for an environment settings object when scripting is not enabled for it, i.e., when any of the above conditions are false. - return !is_scripting_enabled(); + // Scripting is disabled for a realm when scripting is not enabled for it, i.e., when any of the above conditions are false. + return !is_scripting_enabled(realm); } // https://html.spec.whatwg.org/multipage/webappapis.html#module-type-allowed @@ -263,8 +286,9 @@ void EnvironmentSettingsObject::disallow_further_import_maps() verify_cast(global).set_import_maps_allowed(false); } -// https://html.spec.whatwg.org/multipage/webappapis.html#incumbent-settings-object -EnvironmentSettingsObject& incumbent_settings_object() +// https://html.spec.whatwg.org/multipage/webappapis.html#concept-incumbent-realm +// https://whatpr.org/html/9893/b8ea975...df5706b/webappapis.html#concept-incumbent-realm +JS::Realm& incumbent_realm() { auto& event_loop = HTML::main_thread_event_loop(); auto& vm = event_loop.vm(); @@ -275,22 +299,24 @@ EnvironmentSettingsObject& incumbent_settings_object() // 2. If context is null, or if context's skip-when-determining-incumbent counter is greater than zero, then: if (!context || context->skip_when_determining_incumbent_counter > 0) { // 1. Assert: the backup incumbent settings object stack is not empty. - // NOTE: If this assertion fails, it's because the incumbent settings object was used with no involvement of JavaScript. - VERIFY(!event_loop.is_backup_incumbent_settings_object_stack_empty()); + // 1. Assert: the backup incumbent realm stack is not empty. + // NOTE: If this assertion fails, it's because the incumbent realm was used with no involvement of JavaScript. + VERIFY(!event_loop.is_backup_incumbent_realm_stack_empty()); - // 2. Return the topmost entry of the backup incumbent settings object stack. - return event_loop.top_of_backup_incumbent_settings_object_stack(); + // 2. Return the topmost entry of the backup incumbent realm stack. + return event_loop.top_of_backup_incumbent_realm_stack(); } - // 3. Return context's Realm component's settings object. - return Bindings::host_defined_environment_settings_object(*context->realm); + // 3. Return context's Realm component. + return *context->realm; } -// https://html.spec.whatwg.org/multipage/webappapis.html#concept-incumbent-realm -JS::Realm& incumbent_realm() +// https://html.spec.whatwg.org/multipage/webappapis.html#incumbent-settings-object +// https://whatpr.org/html/9893/b8ea975...df5706b/webappapis.html#incumbent-settings-object +EnvironmentSettingsObject& incumbent_settings_object() { - // Then, the incumbent Realm is the Realm of the incumbent settings object. - return incumbent_settings_object().realm(); + // FIXME: Then, the incumbent settings object is the incumbent realm's principal realm settings object. + return Bindings::host_defined_environment_settings_object(incumbent_realm()); } // https://html.spec.whatwg.org/multipage/webappapis.html#concept-incumbent-global @@ -300,24 +326,30 @@ JS::Object& incumbent_global_object() return incumbent_settings_object().global_object(); } -// https://html.spec.whatwg.org/multipage/webappapis.html#current-settings-object -EnvironmentSettingsObject& current_settings_object() +// https://whatpr.org/html/9893/webappapis.html#current-principal-realm +JS::Realm& current_principal_realm() { + // FIXME: The current principal realm is the principal realm of the current realm. auto& event_loop = HTML::main_thread_event_loop(); auto& vm = event_loop.vm(); - // Then, the current settings object is the environment settings object of the current Realm Record. - return Bindings::host_defined_environment_settings_object(*vm.current_realm()); + return *vm.current_realm(); } -// https://html.spec.whatwg.org/multipage/webappapis.html#current-global-object -JS::Object& current_global_object() +// https://html.spec.whatwg.org/multipage/webappapis.html#current-settings-object +// https://whatpr.org/html/9893/webappapis.html#current-principal-settings-object +EnvironmentSettingsObject& current_principal_settings_object() { - auto& event_loop = HTML::main_thread_event_loop(); - auto& vm = event_loop.vm(); + // Then, the current principal settings object is the environment settings object of the current principal realm. + return Bindings::host_defined_environment_settings_object(current_principal_realm()); +} - // Similarly, the current global object is the global object of the current Realm Record. - return vm.current_realm()->global_object(); +// https://html.spec.whatwg.org/multipage/webappapis.html#current-global-object +// https://whatpr.org/html/9893/webappapis.html#current-principal-global-object +JS::Object& current_principal_global_object() +{ + // Similarly, the current principal global object is the global object of the current principal realm. + return current_principal_realm().global_object(); } // https://html.spec.whatwg.org/multipage/webappapis.html#concept-relevant-realm diff --git a/Userland/Libraries/LibWeb/HTML/Scripting/Environments.h b/Userland/Libraries/LibWeb/HTML/Scripting/Environments.h index d2ef0104945f..ec8b611dbba8 100644 --- a/Userland/Libraries/LibWeb/HTML/Scripting/Environments.h +++ b/Userland/Libraries/LibWeb/HTML/Scripting/Environments.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2021, Luke Wilde * Copyright (c) 2022, Linus Groh + * Copyright (c) 2024, Shannon Booth * * SPDX-License-Identifier: BSD-2-Clause */ @@ -63,6 +64,7 @@ struct EnvironmentSettingsObject : public Environment { // https://html.spec.whatwg.org/multipage/webappapis.html#concept-environment-target-browsing-context JS::ExecutionContext& realm_execution_context(); + JS::ExecutionContext const& realm_execution_context() const; // https://html.spec.whatwg.org/multipage/webappapis.html#concept-settings-object-module-map ModuleMap& module_map(); @@ -94,16 +96,6 @@ struct EnvironmentSettingsObject : public Environment { // https://fetch.spec.whatwg.org/#concept-fetch-group Vector>& fetch_group() { return m_fetch_group; } - RunScriptDecision can_run_script(); - void prepare_to_run_script(); - void clean_up_after_running_script(); - - void prepare_to_run_callback(); - void clean_up_after_running_callback(); - - bool is_scripting_enabled() const; - bool is_scripting_disabled() const; - bool module_type_allowed(StringView module_type) const; void disallow_further_import_maps(); @@ -139,11 +131,25 @@ struct EnvironmentSettingsObject : public Environment { bool m_discarded { false }; }; +JS::ExecutionContext const& execution_context_of_realm(JS::Realm const&); +inline JS::ExecutionContext& execution_context_of_realm(JS::Realm& realm) { return const_cast(execution_context_of_realm(const_cast(realm))); } + +RunScriptDecision can_run_script(JS::Realm const&); +bool is_scripting_enabled(JS::Realm const&); +bool is_scripting_disabled(JS::Realm const&); +void prepare_to_run_script(JS::Realm&); +void clean_up_after_running_script(JS::Realm const&); +void prepare_to_run_callback(JS::Realm&); +void clean_up_after_running_callback(JS::Realm const&); + EnvironmentSettingsObject& incumbent_settings_object(); JS::Realm& incumbent_realm(); JS::Object& incumbent_global_object(); -EnvironmentSettingsObject& current_settings_object(); -JS::Object& current_global_object(); + +JS::Realm& current_principal_realm(); +EnvironmentSettingsObject& current_principal_settings_object(); + +JS::Object& current_principal_global_object(); JS::Realm& relevant_realm(JS::Object const&); EnvironmentSettingsObject& relevant_settings_object(JS::Object const&); EnvironmentSettingsObject& relevant_settings_object(DOM::Node const&); diff --git a/Userland/Libraries/LibWeb/HTML/Scripting/Fetching.cpp b/Userland/Libraries/LibWeb/HTML/Scripting/Fetching.cpp index ea09c7631a1f..f2f2f7652649 100644 --- a/Userland/Libraries/LibWeb/HTML/Scripting/Fetching.cpp +++ b/Userland/Libraries/LibWeb/HTML/Scripting/Fetching.cpp @@ -81,6 +81,7 @@ ByteString module_type_from_module_request(JS::ModuleRequest const& module_reque } // https://html.spec.whatwg.org/multipage/webappapis.html#resolve-a-module-specifier +// https://whatpr.org/html/9893/webappapis.html#resolve-a-module-specifier WebIDL::ExceptionOr resolve_module_specifier(Optional referring_script, ByteString const& specifier) { // 1. Let settingsObject and baseURL be null. @@ -97,11 +98,11 @@ WebIDL::ExceptionOr resolve_module_specifier(Optional referri } // 3. Otherwise: else { - // 1. Assert: there is a current settings object. - // NOTE: This is handled by the current_settings_object() accessor. + // 1. Assert: there is a current principal settings object. + // NOTE: This is handled by the current_principal_settings_object() accessor. - // 2. Set settingsObject to the current settings object. - settings_object = current_settings_object(); + // 2. Set settingsObject to the current principal settings object. + settings_object = current_principal_settings_object(); // 3. Set baseURL to settingsObject's API base URL. base_url = settings_object->api_base_url(); @@ -957,7 +958,7 @@ void fetch_descendants_of_and_link_a_module_script(JS::Realm& realm, // resulting in the event loop hanging forever awaiting for the script to be ready for parser // execution. realm.vm().push_execution_context(fetch_client.realm_execution_context()); - fetch_client.prepare_to_run_callback(); + prepare_to_run_callback(realm); // 5. Let loadingPromise be record.LoadRequestedModules(state). auto& loading_promise = record->load_requested_modules(state); @@ -994,7 +995,8 @@ void fetch_descendants_of_and_link_a_module_script(JS::Realm& realm, return JS::js_undefined(); })); - fetch_client.clean_up_after_running_callback(); + clean_up_after_running_callback(realm); + realm.vm().pop_execution_context(); } diff --git a/Userland/Libraries/LibWeb/HTML/Scripting/ModuleScript.cpp b/Userland/Libraries/LibWeb/HTML/Scripting/ModuleScript.cpp index ea5f198c17e6..ebbdf984f6a5 100644 --- a/Userland/Libraries/LibWeb/HTML/Scripting/ModuleScript.cpp +++ b/Userland/Libraries/LibWeb/HTML/Scripting/ModuleScript.cpp @@ -30,18 +30,19 @@ JavaScriptModuleScript::JavaScriptModuleScript(URL::URL base_url, ByteString fil } // https://html.spec.whatwg.org/multipage/webappapis.html#creating-a-javascript-module-script +// https://whatpr.org/html/9893/webappapis.html#creating-a-javascript-module-script WebIDL::ExceptionOr> JavaScriptModuleScript::create(ByteString const& filename, StringView source, EnvironmentSettingsObject& settings_object, URL::URL base_url) { + auto& realm = settings_object.realm(); + // 1. If scripting is disabled for settings, then set source to the empty string. - if (settings_object.is_scripting_disabled()) + if (HTML::is_scripting_disabled(realm)) source = ""sv; - auto& realm = settings_object.realm(); - // 2. Let script be a new module script that this algorithm will subsequently initialize. auto script = realm.heap().allocate(realm, move(base_url), filename, settings_object); - // 3. Set script's settings object to settings. + // FIXME: 3. Set script's settings object to settings. // NOTE: This was already done when constructing. // 4. Set script's base URL to baseURL. @@ -53,8 +54,8 @@ WebIDL::ExceptionOr> JavaScriptModuleScript::c script->set_parse_error(JS::js_null()); script->set_error_to_rethrow(JS::js_null()); - // 7. Let result be ParseModule(source, settings's Realm, script). - auto result = JS::SourceTextModule::parse(source, settings_object.realm(), filename.view(), script); + // 7. Let result be ParseModule(source, realm, script). + auto result = JS::SourceTextModule::parse(source, realm, filename.view(), script); // 8. If result is a list of errors, then: if (result.is_error()) { @@ -62,7 +63,7 @@ WebIDL::ExceptionOr> JavaScriptModuleScript::c dbgln("JavaScriptModuleScript: Failed to parse: {}", parse_error.to_string()); // 1. Set script's parse error to result[0]. - script->set_parse_error(JS::SyntaxError::create(settings_object.realm(), parse_error.to_string())); + script->set_parse_error(JS::SyntaxError::create(realm, parse_error.to_string())); // 2. Return script. return script; @@ -75,7 +76,7 @@ WebIDL::ExceptionOr> JavaScriptModuleScript::c for (auto const& attribute : requested.attributes) { if (attribute.key != "type"sv) { // 1. Let error be a new SyntaxError exception. - auto error = JS::SyntaxError::create(settings_object.realm(), "Module request attributes must only contain a type attribute"_string); + auto error = JS::SyntaxError::create(realm, "Module request attributes must only contain a type attribute"_string); // 2. Set script's parse error to error. script->set_parse_error(error); @@ -118,27 +119,29 @@ WebIDL::ExceptionOr> JavaScriptModuleScript::c } // https://html.spec.whatwg.org/multipage/webappapis.html#run-a-module-script +// https://whatpr.org/html/9893/webappapis.html#run-a-module-script JS::Promise* JavaScriptModuleScript::run(PreventErrorReporting) { // 1. Let settings be the settings object of script. auto& settings = settings_object(); + auto& realm = settings.realm(); - // 2. Check if we can run script with settings. If this returns "do not run", then return a promise resolved with undefined. - if (settings.can_run_script() == RunScriptDecision::DoNotRun) { + // 2. Check if we can run script with realm. If this returns "do not run", then return a promise resolved with undefined. + if (can_run_script(realm) == RunScriptDecision::DoNotRun) { auto promise = JS::Promise::create(settings.realm()); promise->fulfill(JS::js_undefined()); return promise; } - // 3. Prepare to run script given settings. - settings.prepare_to_run_script(); + // 3. Prepare to run script given realm. + prepare_to_run_script(realm); // 4. Let evaluationPromise be null. JS::Promise* evaluation_promise = nullptr; // 5. If script's error to rethrow is not null, then set evaluationPromise to a promise rejected with script's error to rethrow. if (!error_to_rethrow().is_null()) { - evaluation_promise = JS::Promise::create(settings.realm()); + evaluation_promise = JS::Promise::create(realm); evaluation_promise->reject(error_to_rethrow()); } // 6. Otherwise: @@ -149,7 +152,7 @@ JS::Promise* JavaScriptModuleScript::run(PreventErrorReporting) // NON-STANDARD: To ensure that LibJS can find the module on the stack, we push a new execution context. auto module_execution_context = JS::ExecutionContext::create(); - module_execution_context->realm = &settings.realm(); + module_execution_context->realm = &realm; module_execution_context->script_or_module = JS::NonnullGCPtr { *record }; vm().push_execution_context(*module_execution_context); @@ -160,8 +163,8 @@ JS::Promise* JavaScriptModuleScript::run(PreventErrorReporting) // If Evaluate fails to complete as a result of the user agent aborting the running script, // then set evaluationPromise to a promise rejected with a new "QuotaExceededError" DOMException. if (elevation_promise_or_error.is_error()) { - auto promise = JS::Promise::create(settings_object().realm()); - promise->reject(WebIDL::QuotaExceededError::create(settings_object().realm(), "Failed to evaluate module script"_string).ptr()); + auto promise = JS::Promise::create(realm); + promise->reject(WebIDL::QuotaExceededError::create(realm, "Failed to evaluate module script"_string).ptr()); evaluation_promise = promise; } else { @@ -174,8 +177,8 @@ JS::Promise* JavaScriptModuleScript::run(PreventErrorReporting) // FIXME: 7. If preventErrorReporting is false, then upon rejection of evaluationPromise with reason, report the exception given by reason for script. - // 8. Clean up after running script with settings. - settings.clean_up_after_running_script(); + // 8. Clean up after running script with realm. + clean_up_after_running_script(realm); // 9. Return evaluationPromise. return evaluation_promise; diff --git a/Userland/Libraries/LibWeb/HTML/Scripting/TemporaryExecutionContext.cpp b/Userland/Libraries/LibWeb/HTML/Scripting/TemporaryExecutionContext.cpp index cf5ac9898db0..71e2f7121531 100644 --- a/Userland/Libraries/LibWeb/HTML/Scripting/TemporaryExecutionContext.cpp +++ b/Userland/Libraries/LibWeb/HTML/Scripting/TemporaryExecutionContext.cpp @@ -13,16 +13,16 @@ TemporaryExecutionContext::TemporaryExecutionContext(EnvironmentSettingsObject& : m_environment_settings(environment_settings) , m_callbacks_enabled(callbacks_enabled) { - m_environment_settings->prepare_to_run_script(); + prepare_to_run_script(m_environment_settings->realm()); if (m_callbacks_enabled == CallbacksEnabled::Yes) - m_environment_settings->prepare_to_run_callback(); + prepare_to_run_callback(m_environment_settings->realm()); } TemporaryExecutionContext::~TemporaryExecutionContext() { - m_environment_settings->clean_up_after_running_script(); + clean_up_after_running_script(m_environment_settings->realm()); if (m_callbacks_enabled == CallbacksEnabled::Yes) - m_environment_settings->clean_up_after_running_callback(); + clean_up_after_running_callback(m_environment_settings->realm()); } } diff --git a/Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp b/Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp index 010d0a0e8221..caf683547b9b 100644 --- a/Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp +++ b/Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp @@ -157,6 +157,7 @@ class Serializer { } // https://html.spec.whatwg.org/multipage/structured-data.html#structuredserializeinternal + // https://whatpr.org/html/9893/structured-data.html#structuredserializeinternal WebIDL::ExceptionOr serialize(JS::Value value) { // 2. If memory[value] exists, then return memory[value]. @@ -565,10 +566,10 @@ WebIDL::ExceptionOr serialize_array_buffer(JS::VM& vm, Vector& vector // FIXME: 1. If IsSharedArrayBuffer(value) is true, then: if (false) { - // 1. If the current settings object's cross-origin isolated capability is false, then throw a "DataCloneError" DOMException. + // 1. If the current principal settings object's cross-origin isolated capability is false, then throw a "DataCloneError" DOMException. // NOTE: This check is only needed when serializing (and not when deserializing) as the cross-origin isolated capability cannot change // over time and a SharedArrayBuffer cannot leave an agent cluster. - if (current_settings_object().cross_origin_isolated_capability() == CanUseCrossOriginIsolatedAPIs::No) + if (current_principal_settings_object().cross_origin_isolated_capability() == CanUseCrossOriginIsolatedAPIs::No) return WebIDL::DataCloneError::create(*vm.current_realm(), "Cannot serialize SharedArrayBuffer when cross-origin isolated"_string); // 2. If forStorage is true, then throw a "DataCloneError" DOMException. @@ -1304,12 +1305,11 @@ WebIDL::ExceptionOr structured_deserialize(JS::VM& vm, SerializationR memory = DeserializationMemory { vm.heap() }; // IMPLEMENTATION DEFINED: We need to make sure there's an execution context for target_realm on the stack before constructing these JS objects - auto& target_settings = Bindings::host_defined_environment_settings_object(target_realm); - target_settings.prepare_to_run_script(); + prepare_to_run_script(target_realm); auto result = TRY(structured_deserialize_internal(vm, serialized.span(), target_realm, *memory)); - target_settings.clean_up_after_running_script(); + clean_up_after_running_script(target_realm); VERIFY(result.value.has_value()); return *result.value; } diff --git a/Userland/Libraries/LibWeb/HTML/Window.cpp b/Userland/Libraries/LibWeb/HTML/Window.cpp index cb58fb65a935..daa10a7dc80d 100644 --- a/Userland/Libraries/LibWeb/HTML/Window.cpp +++ b/Userland/Libraries/LibWeb/HTML/Window.cpp @@ -994,6 +994,7 @@ JS::GCPtr Window::parent() const } // https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-frameelement +// https://whatpr.org/html/9893/nav-history-apis.html#dom-frameelement JS::GCPtr Window::frame_element() const { // 1. Let current be this's node navigable. @@ -1010,8 +1011,8 @@ JS::GCPtr Window::frame_element() const if (!container) return {}; - // 5. If container's node document's origin is not same origin-domain with the current settings object's origin, then return null. - if (!container->document().origin().is_same_origin_domain(current_settings_object().origin())) + // 5. If container's node document's origin is not same origin-domain with the current principal settings object's origin, then return null. + if (!container->document().origin().is_same_origin_domain(current_principal_settings_object().origin())) return {}; // 6. Return container. diff --git a/Userland/Libraries/LibWeb/HTML/WindowProxy.cpp b/Userland/Libraries/LibWeb/HTML/WindowProxy.cpp index 7d1f9f1035fc..a6c60d9eda38 100644 --- a/Userland/Libraries/LibWeb/HTML/WindowProxy.cpp +++ b/Userland/Libraries/LibWeb/HTML/WindowProxy.cpp @@ -152,15 +152,16 @@ JS::ThrowCompletionOr WindowProxy::internal_define_own_property(JS::Proper return throw_completion(WebIDL::SecurityError::create(m_window->realm(), MUST(String::formatted("Can't define property '{}' on cross-origin object", property_key)))); } -// 7.4.7 [[Get]] ( P, Receiver ), https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-get +// 7.4.7 [[Get]] ( P, Receiver ), https://html.spec.whatwg.org/multipage/nav-history-apis.html#windowproxy-get +// https://html.spec.whatwg.org/multipage/nav-history-apis.html#windowproxy-get JS::ThrowCompletionOr WindowProxy::internal_get(JS::PropertyKey const& property_key, JS::Value receiver, JS::CacheablePropertyMetadata*, PropertyLookupPhase) const { auto& vm = this->vm(); // 1. Let W be the value of the [[Window]] internal slot of this. - // 2. Check if an access between two browsing contexts should be reported, given the current global object's browsing context, W's browsing context, P, and the current settings object. - check_if_access_between_two_browsing_contexts_should_be_reported(*verify_cast(current_global_object()).browsing_context(), m_window->browsing_context(), property_key, current_settings_object()); + // 2. Check if an access between two browsing contexts should be reported, given the current principal global object's browsing context, W's browsing context, P, and the current principal settings object. + check_if_access_between_two_browsing_contexts_should_be_reported(*verify_cast(current_principal_global_object()).browsing_context(), m_window->browsing_context(), property_key, current_principal_settings_object()); // 3. If IsPlatformObjectSameOrigin(W) is true, then return ? OrdinaryGet(this, P, Receiver). // NOTE: this is passed rather than W as OrdinaryGet and CrossOriginGet will invoke the [[GetOwnProperty]] internal method. @@ -172,15 +173,16 @@ JS::ThrowCompletionOr WindowProxy::internal_get(JS::PropertyKey const return cross_origin_get(vm, *this, property_key, receiver); } -// 7.4.8 [[Set]] ( P, V, Receiver ), https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-set +// 7.4.8 [[Set]] ( P, V, Receiver ), https://html.spec.whatwg.org/multipage/nav-history-apis.html#windowproxy-set +// https://html.spec.whatwg.org/multipage/nav-history-apis.html#windowproxy-set JS::ThrowCompletionOr WindowProxy::internal_set(JS::PropertyKey const& property_key, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata*) { auto& vm = this->vm(); // 1. Let W be the value of the [[Window]] internal slot of this. - // 2. Check if an access between two browsing contexts should be reported, given the current global object's browsing context, W's browsing context, P, and the current settings object. - check_if_access_between_two_browsing_contexts_should_be_reported(*verify_cast(current_global_object()).browsing_context(), m_window->browsing_context(), property_key, current_settings_object()); + // 2. Check if an access between two browsing contexts should be reported, given the current principal global object's browsing context, W's browsing context, P, and the current principal settings object. + check_if_access_between_two_browsing_contexts_should_be_reported(*verify_cast(current_principal_global_object()).browsing_context(), m_window->browsing_context(), property_key, current_principal_settings_object()); // 3. If IsPlatformObjectSameOrigin(W) is true, then: if (is_platform_object_same_origin(*m_window)) { diff --git a/Userland/Libraries/LibWeb/HTML/Worker.cpp b/Userland/Libraries/LibWeb/HTML/Worker.cpp index f79ee851d11f..8f4ea71e2963 100644 --- a/Userland/Libraries/LibWeb/HTML/Worker.cpp +++ b/Userland/Libraries/LibWeb/HTML/Worker.cpp @@ -40,6 +40,7 @@ void Worker::visit_edges(Cell::Visitor& visitor) } // https://html.spec.whatwg.org/multipage/workers.html#dom-worker +// https://whatpr.org/html/9893/workers.html#dom-worker WebIDL::ExceptionOr> Worker::create(String const& script_url, WorkerOptions const& options, DOM::Document& document) { dbgln_if(WEB_WORKER_DEBUG, "WebWorker: Creating worker with script_url = {}", script_url); @@ -55,8 +56,8 @@ WebIDL::ExceptionOr> Worker::create(String const& scrip // a policy decision (e.g. if the user agent is configured to not allow the page to start dedicated workers). // Technically not a fixme if our policy is not to throw errors :^) - // 2. Let outside settings be the current settings object. - auto& outside_settings = current_settings_object(); + // 2. Let outside settings be the current principal settings object. + auto& outside_settings = current_principal_settings_object(); // 3. Parse the scriptURL argument relative to outside settings. auto url = document.parse_url(script_url); diff --git a/Userland/Libraries/LibWeb/HTML/WorkerGlobalScope.cpp b/Userland/Libraries/LibWeb/HTML/WorkerGlobalScope.cpp index 1e798c197831..088e24860360 100644 --- a/Userland/Libraries/LibWeb/HTML/WorkerGlobalScope.cpp +++ b/Userland/Libraries/LibWeb/HTML/WorkerGlobalScope.cpp @@ -79,6 +79,7 @@ void WorkerGlobalScope::close_a_worker() } // https://html.spec.whatwg.org/multipage/workers.html#importing-scripts-and-libraries +// https://whatpr.org/html/9893/workers.html#importing-scripts-and-libraries WebIDL::ExceptionOr WorkerGlobalScope::import_scripts(Vector const& urls, PerformTheFetchHook perform_fetch) { // The algorithm may optionally be customized by supplying custom perform the fetch hooks, @@ -87,8 +88,8 @@ WebIDL::ExceptionOr WorkerGlobalScope::import_scripts(Vector const // FIXME: 1. If worker global scope's type is "module", throw a TypeError exception. - // 2. Let settings object be the current settings object. - auto& settings_object = HTML::current_settings_object(); + // 2. Let settings object be the current principal settings object. + auto& settings_object = HTML::current_principal_settings_object(); // 3. If urls is empty, return. if (urls.is_empty()) diff --git a/Userland/Libraries/LibWeb/Page/Page.cpp b/Userland/Libraries/LibWeb/Page/Page.cpp index 60602a3c84e4..a94efcf11fd4 100644 --- a/Userland/Libraries/LibWeb/Page/Page.cpp +++ b/Userland/Libraries/LibWeb/Page/Page.cpp @@ -264,7 +264,7 @@ void Page::did_update_window_rect() template static ResponseType spin_event_loop_until_dialog_closed(PageClient& client, Optional& response, SourceLocation location = SourceLocation::current()) { - auto& event_loop = Web::HTML::current_settings_object().responsible_event_loop(); + auto& event_loop = Web::HTML::current_principal_settings_object().responsible_event_loop(); ScopeGuard guard { [&] { event_loop.set_execution_paused(false); } }; event_loop.set_execution_paused(true); diff --git a/Userland/Libraries/LibWeb/UserTiming/PerformanceMark.cpp b/Userland/Libraries/LibWeb/UserTiming/PerformanceMark.cpp index 6ec1f15a52c0..c2f374e3da8b 100644 --- a/Userland/Libraries/LibWeb/UserTiming/PerformanceMark.cpp +++ b/Userland/Libraries/LibWeb/UserTiming/PerformanceMark.cpp @@ -29,11 +29,11 @@ PerformanceMark::~PerformanceMark() = default; // https://w3c.github.io/user-timing/#dfn-performancemark-constructor WebIDL::ExceptionOr> PerformanceMark::construct_impl(JS::Realm& realm, String const& mark_name, Web::UserTiming::PerformanceMarkOptions const& mark_options) { - auto& current_global_object = realm.global_object(); + auto& current_principal_global_object = HTML::current_principal_global_object(); auto& vm = realm.vm(); // 1. If the current global object is a Window object and markName uses the same name as a read only attribute in the PerformanceTiming interface, throw a SyntaxError. - if (is(current_global_object)) { + if (is(current_principal_global_object)) { bool matched = false; #define __ENUMERATE_NAVIGATION_TIMING_ENTRY_NAME(name, _) \ diff --git a/Userland/Libraries/LibWeb/WebAudio/BaseAudioContext.cpp b/Userland/Libraries/LibWeb/WebAudio/BaseAudioContext.cpp index f1dc22884e79..9eda7e8ddcfb 100644 --- a/Userland/Libraries/LibWeb/WebAudio/BaseAudioContext.cpp +++ b/Userland/Libraries/LibWeb/WebAudio/BaseAudioContext.cpp @@ -123,7 +123,7 @@ WebIDL::ExceptionOr BaseAudioContext::verify_audio_options_inside_nominal_ void BaseAudioContext::queue_a_media_element_task(JS::NonnullGCPtr> steps) { - auto task = HTML::Task::create(vm(), m_media_element_event_task_source.source, HTML::current_settings_object().responsible_document(), steps); + auto task = HTML::Task::create(vm(), m_media_element_event_task_source.source, HTML::current_principal_settings_object().responsible_document(), steps); HTML::main_thread_event_loop().task_queue().add(task); } diff --git a/Userland/Libraries/LibWeb/WebDriver/ExecuteScript.cpp b/Userland/Libraries/LibWeb/WebDriver/ExecuteScript.cpp index e43beac90988..8adb98cc0a13 100644 --- a/Userland/Libraries/LibWeb/WebDriver/ExecuteScript.cpp +++ b/Userland/Libraries/LibWeb/WebDriver/ExecuteScript.cpp @@ -279,11 +279,11 @@ JS::ThrowCompletionOr execute_a_function_body(HTML::Window const& win // 5. If body begins with a directive prologue that contains a use strict directive then let strict be true, otherwise let strict be false. // NOTE: Handled in step 8 below. - // 6. Prepare to run a script with environment settings. - environment_settings.prepare_to_run_script(); + // 6. Prepare to run a script with realm. + HTML::prepare_to_run_script(realm); // 7. Prepare to run a callback with environment settings. - environment_settings.prepare_to_run_callback(); + HTML::prepare_to_run_callback(realm); // 8. Let function be the result of calling FunctionCreate, with arguments: // kind @@ -304,10 +304,10 @@ JS::ThrowCompletionOr execute_a_function_body(HTML::Window const& win auto completion = function->internal_call(&window, parameters); // 10. Clean up after running a callback with environment settings. - environment_settings.clean_up_after_running_callback(); + HTML::clean_up_after_running_callback(realm); - // 11. Clean up after running a script with environment settings. - environment_settings.clean_up_after_running_script(); + // 11. Clean up after running a script with realm. + HTML::clean_up_after_running_script(realm); // 12. Return completion. return completion; diff --git a/Userland/Libraries/LibWeb/WebIDL/AbstractOperations.cpp b/Userland/Libraries/LibWeb/WebIDL/AbstractOperations.cpp index 2ca54bfc47b5..4747bb0a5422 100644 --- a/Userland/Libraries/LibWeb/WebIDL/AbstractOperations.cpp +++ b/Userland/Libraries/LibWeb/WebIDL/AbstractOperations.cpp @@ -101,17 +101,16 @@ ErrorOr get_buffer_source_copy(JS::Object const& buffer_source) } // https://webidl.spec.whatwg.org/#call-user-object-operation-return -inline JS::Completion clean_up_on_return(HTML::EnvironmentSettingsObject& stored_settings, HTML::EnvironmentSettingsObject& relevant_settings, JS::Completion& completion, OperationReturnsPromise operation_returns_promise) +// https://whatpr.org/webidl/1437.html#call-user-object-operation-return +inline JS::Completion clean_up_on_return(JS::Realm& stored_realm, JS::Realm& relevant_realm, JS::Completion& completion, OperationReturnsPromise operation_returns_promise) { - auto& realm = stored_settings.realm(); - // Return: at this point completion will be set to an ECMAScript completion value. - // 1. Clean up after running a callback with stored settings. - stored_settings.clean_up_after_running_callback(); + // 1. Clean up after running a callback with stored realm. + HTML::clean_up_after_running_callback(stored_realm); - // 2. Clean up after running script with relevant settings. - relevant_settings.clean_up_after_running_script(); + // 2. Clean up after running script with relevant realm. + HTML::clean_up_after_running_script(relevant_realm); // 3. If completion is a normal completion, return completion. if (completion.type() == JS::Completion::Type::Normal) @@ -122,13 +121,15 @@ inline JS::Completion clean_up_on_return(HTML::EnvironmentSettingsObject& stored return completion; // 5. Let rejectedPromise be ! Call(%Promise.reject%, %Promise%, «completion.[[Value]]»). - auto rejected_promise = create_rejected_promise(realm, *completion.release_value()); + auto rejected_promise = create_rejected_promise(relevant_realm, *completion.release_value()); // 6. Return the result of converting rejectedPromise to the operation’s return type. // Note: The operation must return a promise, so no conversion is necessary return JS::Value { rejected_promise->promise() }; } +// https://webidl.spec.whatwg.org/#call-a-user-objects-operation +// https://whatpr.org/webidl/1437.html#call-a-user-objects-operation JS::Completion call_user_object_operation(WebIDL::CallbackType& callback, String const& operation_name, Optional this_argument, JS::MarkedVector args) { // 1. Let completion be an uninitialized variable. @@ -141,25 +142,23 @@ JS::Completion call_user_object_operation(WebIDL::CallbackType& callback, String // 3. Let O be the ECMAScript object corresponding to value. auto& object = callback.callback; - // 4. Let realm be O’s associated Realm. - auto& realm = object->shape().realm(); - - // 5. Let relevant settings be realm’s settings object. - auto& relevant_settings = Bindings::host_defined_environment_settings_object(realm); + // 4. Let relevant realm be O’s associated Realm. + auto& relevant_realm = object->shape().realm(); - // 6. Let stored settings be value’s callback context. - auto& stored_settings = callback.callback_context; + // FIXME: We should get the realm directly from the callback context. + // 5. Let stored realm be value’s callback context. + auto& stored_realm = callback.callback_context->realm(); - // 7. Prepare to run script with relevant settings. - relevant_settings.prepare_to_run_script(); + // 6. Prepare to run script with relevant realm. + HTML::prepare_to_run_script(relevant_realm); - // 8. Prepare to run a callback with stored settings. - stored_settings->prepare_to_run_callback(); + // 7. Prepare to run a callback with stored realm. + HTML::prepare_to_run_callback(stored_realm); - // 9. Let X be O. + // 8. Let X be O. auto actual_function_object = object; - // 10. If ! IsCallable(O) is false, then: + // 9. If ! IsCallable(O) is false, then: if (!object->is_function()) { // 1. Let getResult be Get(O, opName). auto get_result = object->get(operation_name.to_byte_string()); @@ -167,13 +166,13 @@ JS::Completion call_user_object_operation(WebIDL::CallbackType& callback, String // 2. If getResult is an abrupt completion, set completion to getResult and jump to the step labeled return. if (get_result.is_throw_completion()) { completion = get_result.throw_completion(); - return clean_up_on_return(stored_settings, relevant_settings, completion, callback.operation_returns_promise); + return clean_up_on_return(stored_realm, relevant_realm, completion, callback.operation_returns_promise); } // 4. If ! IsCallable(X) is false, then set completion to a new Completion{[[Type]]: throw, [[Value]]: a newly created TypeError object, [[Target]]: empty}, and jump to the step labeled return. if (!get_result.value().is_function()) { - completion = realm.vm().template throw_completion(JS::ErrorType::NotAFunction, get_result.value().to_string_without_side_effects()); - return clean_up_on_return(stored_settings, relevant_settings, completion, callback.operation_returns_promise); + completion = relevant_realm.vm().template throw_completion(JS::ErrorType::NotAFunction, get_result.value().to_string_without_side_effects()); + return clean_up_on_return(stored_realm, relevant_realm, completion, callback.operation_returns_promise); } // 3. Set X to getResult.[[Value]]. @@ -184,28 +183,29 @@ JS::Completion call_user_object_operation(WebIDL::CallbackType& callback, String this_argument = object; } - // FIXME: 11. Let esArgs be the result of converting args to an ECMAScript arguments list. If this throws an exception, set completion to the completion value representing the thrown exception and jump to the step labeled return. + // FIXME: 10. Let esArgs be the result of converting args to an ECMAScript arguments list. If this throws an exception, set completion to the completion value representing the thrown exception and jump to the step labeled return. // For simplicity, we currently make the caller do this. However, this means we can't throw exceptions at this point like the spec wants us to. - // 12. Let callResult be Call(X, thisArg, esArgs). + // 11. Let callResult be Call(X, thisArg, esArgs). VERIFY(actual_function_object); auto& vm = object->vm(); auto call_result = JS::call(vm, verify_cast(*actual_function_object), this_argument.value(), args.span()); - // 13. If callResult is an abrupt completion, set completion to callResult and jump to the step labeled return. + // 12. If callResult is an abrupt completion, set completion to callResult and jump to the step labeled return. if (call_result.is_throw_completion()) { completion = call_result.throw_completion(); - return clean_up_on_return(stored_settings, relevant_settings, completion, callback.operation_returns_promise); + return clean_up_on_return(stored_realm, relevant_realm, completion, callback.operation_returns_promise); } - // 14. Set completion to the result of converting callResult.[[Value]] to an IDL value of the same type as the operation’s return type. + // 13. Set completion to the result of converting callResult.[[Value]] to an IDL value of the same type as the operation’s return type. // FIXME: This does no conversion. completion = call_result.value(); - return clean_up_on_return(stored_settings, relevant_settings, completion, callback.operation_returns_promise); + return clean_up_on_return(stored_realm, relevant_realm, completion, callback.operation_returns_promise); } // https://webidl.spec.whatwg.org/#invoke-a-callback-function +// https://whatpr.org/webidl/1437.html#invoke-a-callback-function JS::Completion invoke_callback(WebIDL::CallbackType& callback, Optional this_argument, JS::MarkedVector args) { // 1. Let completion be an uninitialized variable. @@ -227,21 +227,18 @@ JS::Completion invoke_callback(WebIDL::CallbackType& callback, Optionalshape().realm(); - - // 6. Let relevant settings be realm’s settings object. - auto& relevant_settings = Bindings::host_defined_environment_settings_object(realm); + // 5. Let relevant realm be F’s associated Realm. + auto& relevant_realm = function_object->shape().realm(); - // 7. Let stored settings be value’s callback context. - auto& stored_settings = callback.callback_context; + // FIXME: We should get the realm directly from the callback context. + // 6. Let stored realm be value’s callback context. + auto& stored_realm = callback.callback_context->realm(); - // 8. Prepare to run script with relevant settings. - relevant_settings.prepare_to_run_script(); + // 8. Prepare to run script with relevant realm. + HTML::prepare_to_run_script(relevant_realm); - // 9. Prepare to run a callback with stored settings. - stored_settings->prepare_to_run_callback(); + // 9. Prepare to run a callback with stored realm. + HTML::prepare_to_run_callback(stored_realm); // FIXME: 10. Let esArgs be the result of converting args to an ECMAScript arguments list. If this throws an exception, set completion to the completion value representing the thrown exception and jump to the step labeled return. // For simplicity, we currently make the caller do this. However, this means we can't throw exceptions at this point like the spec wants us to. @@ -253,14 +250,14 @@ JS::Completion invoke_callback(WebIDL::CallbackType& callback, Optional args) @@ -271,49 +268,46 @@ JS::Completion construct(WebIDL::CallbackType& callback, JS::MarkedVectorshape().realm(); + // 4. Let relevant realm be F’s associated Realm. + auto& relevant_realm = function_object->shape().realm(); // 3. If IsConstructor(F) is false, throw a TypeError exception. if (!JS::Value(function_object).is_constructor()) - return realm.vm().template throw_completion(JS::ErrorType::NotAConstructor, JS::Value(function_object).to_string_without_side_effects()); + return relevant_realm.vm().template throw_completion(JS::ErrorType::NotAConstructor, JS::Value(function_object).to_string_without_side_effects()); - // 5. Let relevant settings be realm’s settings object. - auto& relevant_settings = Bindings::host_defined_environment_settings_object(realm); + // FIXME: We should get the realm directly from the callback context. + // 4. Let stored realm be callable’s callback context. + auto& stored_realm = callback.callback_context->realm(); - // 6. Let stored settings be callable’s callback context. - auto& stored_settings = callback.callback_context; + // 5. Prepare to run script with relevant realm. + HTML::prepare_to_run_script(relevant_realm); - // 7. Prepare to run script with relevant settings. - relevant_settings.prepare_to_run_script(); + // 6. Prepare to run a callback with stored realm. + HTML::prepare_to_run_callback(stored_realm); - // 8. Prepare to run a callback with stored settings. - stored_settings->prepare_to_run_callback(); - - // FIXME: 9. Let esArgs be the result of converting args to an ECMAScript arguments list. If this throws an exception, set completion to the completion value representing the thrown exception and jump to the step labeled return. + // FIXME: 7. Let esArgs be the result of converting args to an ECMAScript arguments list. If this throws an exception, set completion to the completion value representing the thrown exception and jump to the step labeled return. // For simplicity, we currently make the caller do this. However, this means we can't throw exceptions at this point like the spec wants us to. - // 10. Let callResult be Completion(Construct(F, esArgs)). + // 8. Let callResult be Completion(Construct(F, esArgs)). auto& vm = function_object->vm(); auto call_result = JS::construct(vm, verify_cast(*function_object), args.span()); - // 11. If callResult is an abrupt completion, set completion to callResult and jump to the step labeled return. + // 9. If callResult is an abrupt completion, set completion to callResult and jump to the step labeled return. if (call_result.is_throw_completion()) { completion = call_result.throw_completion(); } - - // 12. Set completion to the result of converting callResult.[[Value]] to an IDL value of the same type as the operation’s return type. + // 10. Set completion to the result of converting callResult.[[Value]] to an IDL value of the same type as the operation’s return type. else { // FIXME: This does no conversion. completion = JS::Value(call_result.value()); } - // 13. Return: at this point completion will be set to an ECMAScript completion value. - // 1. Clean up after running a callback with stored settings. - stored_settings->clean_up_after_running_callback(); + // 11. Return: at this point completion will be set to an ECMAScript completion value. + // 1. Clean up after running a callback with stored realm. + HTML::clean_up_after_running_callback(stored_realm); - // 2. Clean up after running script with relevant settings. - relevant_settings.clean_up_after_running_script(); + // 2. Clean up after running script with relevant realm. + HTML::clean_up_after_running_script(relevant_realm); // 3. Return completion. return completion; diff --git a/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.cpp b/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.cpp index 97d8c452e3f3..9f4d73448940 100644 --- a/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.cpp +++ b/Userland/Libraries/LibWeb/XHR/XMLHttpRequest.cpp @@ -159,7 +159,7 @@ WebIDL::ExceptionOr> XMLHttpRequest::response_xml() WebIDL::ExceptionOr XMLHttpRequest::set_response_type(Bindings::XMLHttpRequestResponseType response_type) { // 1. If the current global object is not a Window object and the given value is "document", then return. - if (!is(HTML::current_global_object()) && response_type == Bindings::XMLHttpRequestResponseType::Document) + if (!is(HTML::current_principal_global_object()) && response_type == Bindings::XMLHttpRequestResponseType::Document) return {}; // 2. If this’s state is loading or done, then throw an "InvalidStateError" DOMException. @@ -167,7 +167,7 @@ WebIDL::ExceptionOr XMLHttpRequest::set_response_type(Bindings::XMLHttpReq return WebIDL::InvalidStateError::create(realm(), "Can't readyState when XHR is loading or done"_string); // 3. If the current global object is a Window object and this’s synchronous flag is set, then throw an "InvalidAccessError" DOMException. - if (is(HTML::current_global_object()) && m_synchronous) + if (is(HTML::current_principal_global_object()) && m_synchronous) return WebIDL::InvalidAccessError::create(realm(), "Can't set readyState on synchronous XHR in Window environment"_string); // 4. Set this’s response type to the given value. @@ -506,7 +506,7 @@ WebIDL::ExceptionOr XMLHttpRequest::open(String const& method_string, Stri // 9. If async is false, the current global object is a Window object, and either this’s timeout is // not 0 or this’s response type is not the empty string, then throw an "InvalidAccessError" DOMException. if (!async - && is(HTML::current_global_object()) + && is(HTML::current_principal_global_object()) && (m_timeout != 0 || m_response_type != Bindings::XMLHttpRequestResponseType::Empty)) { return WebIDL::InvalidAccessError::create(realm(), "Synchronous XMLHttpRequests in a Window context do not support timeout or a non-empty responseType"_string); } @@ -1051,7 +1051,7 @@ WebIDL::ExceptionOr XMLHttpRequest::set_timeout(u32 timeout) { // 1. If the current global object is a Window object and this’s synchronous flag is set, // then throw an "InvalidAccessError" DOMException. - if (is(HTML::current_global_object()) && m_synchronous) + if (is(HTML::current_principal_global_object()) && m_synchronous) return WebIDL::InvalidAccessError::create(realm(), "Use of XMLHttpRequest's timeout attribute is not supported in the synchronous mode in window context."_string); // 2. Set this’s timeout to the given value.