Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LibWeb: Shadow Realm integration - part 2 #1932

Merged
merged 10 commits into from
Nov 1, 2024
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -2441,7 +2441,7 @@ static void generate_html_constructor(SourceGenerator& generator, IDL::Construct
}

constructor_generator.append(R"~~~(
auto& window = verify_cast<HTML::Window>(HTML::current_global_object());
auto& window = verify_cast<HTML::Window>(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(); }));
Expand Down
2 changes: 2 additions & 0 deletions Userland/Libraries/LibJS/Runtime/Realm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<HostDefined> host_defined) { m_host_defined = move(host_defined); }

void define_builtin(Bytecode::Builtin builtin, NonnullGCPtr<NativeFunction> value)
Expand Down
2 changes: 1 addition & 1 deletion Userland/Libraries/LibWeb/Animations/Animation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ JS::NonnullGCPtr<Animation> Animation::create(JS::Realm& realm, JS::GCPtr<Animat
// a timeline argument is missing, passing the default document timeline of the Document associated with the
// Window that is the current global object.
if (!timeline.has_value()) {
auto& window = verify_cast<HTML::Window>(HTML::current_global_object());
auto& window = verify_cast<HTML::Window>(HTML::current_principal_global_object());
timeline = window.associated_document().timeline();
}
animation->set_timeline(timeline.release_value());
Expand Down
2 changes: 1 addition & 1 deletion Userland/Libraries/LibWeb/Bindings/AudioConstructor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ JS::ThrowCompletionOr<JS::NonnullGCPtr<JS::Object>> AudioConstructor::construct(
auto& vm = this->vm();

// 1. Let document be the current global object's associated Document.
auto& window = verify_cast<HTML::Window>(HTML::current_global_object());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the first commit you updated the copied spec text language to add "principal" for the ESO. Seems a miss here, and in Animations/Animation.cpp.

... and more. Perhaps best to leave that to a tracking issue in html/shadow realms

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, that is a miss on my end for this one. It is covered in the open merge request, see: https://whatpr.org/html/9893/b8ea975...32ad7a4/media.html#dom-audio

I did a scan over the spec folders for specs which have an open MR, but missed this one since it's in the Bindings folder. Will do a second scan over and adjust

auto& window = verify_cast<HTML::Window>(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.
Expand Down
5 changes: 5 additions & 0 deletions Userland/Libraries/LibWeb/Bindings/HostDefined.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ struct HostDefined : public JS::Realm::HostDefined {
return *verify_cast<HostDefined>(realm.host_defined())->environment_settings_object;
}

[[nodiscard]] inline HTML::EnvironmentSettingsObject const& host_defined_environment_settings_object(JS::Realm const& realm)
{
return *verify_cast<HostDefined>(realm.host_defined())->environment_settings_object;
}

[[nodiscard]] inline Page& host_defined_page(JS::Realm& realm)
{
return *verify_cast<HostDefined>(realm.host_defined())->page;
Expand Down
5 changes: 3 additions & 2 deletions Userland/Libraries/LibWeb/Bindings/ImageConstructor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,13 @@ JS::ThrowCompletionOr<JS::Value> 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<JS::NonnullGCPtr<JS::Object>> ImageConstructor::construct(FunctionObject&)
{
auto& vm = this->vm();

// 1. Let document be the current global object's associated Document.
auto& window = verify_cast<HTML::Window>(HTML::current_global_object());
// 1. Let document be the current principal global object's associated Document.
auto& window = verify_cast<HTML::Window>(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.
Expand Down
55 changes: 29 additions & 26 deletions Userland/Libraries/LibWeb/Bindings/MainThreadVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ ErrorOr<void> 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.
Expand All @@ -147,8 +148,8 @@ ErrorOr<void> 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();
ADKaster marked this conversation as resolved.
Show resolved Hide resolved
// 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<HTML::WindowOrWorkerGlobalScopeMixin*>(&settings_object.global_object());
Expand Down Expand Up @@ -198,14 +199,15 @@ ErrorOr<void> 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<JS::Value> arguments_list) {
auto& callback_host_defined = verify_cast<WebEngineCustomJobCallbackData>(*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)
Expand All @@ -220,8 +222,8 @@ ErrorOr<void> 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;
Expand All @@ -234,25 +236,25 @@ ErrorOr<void> 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);
}));
};

Expand All @@ -275,22 +277,22 @@ ErrorOr<void> 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<JS::ExecutionContext> 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.
Expand All @@ -307,15 +309,15 @@ ErrorOr<void> 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();
Expand Down Expand Up @@ -414,12 +416,13 @@ ErrorOr<void> 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<JS::GraphLoadingState::HostDefined> 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<HTML::EnvironmentSettingsObject&> settings_object = HTML::current_settings_object();
// 1. Let settingsObject be the current principal settings object.
Optional<HTML::EnvironmentSettingsObject&> settings_object = HTML::current_principal_settings_object();

// FIXME: 2. If settingsObject's global object implements WorkletGlobalScope or ServiceWorkerGlobalScope and loadState is undefined, then:

Expand Down
5 changes: 3 additions & 2 deletions Userland/Libraries/LibWeb/Bindings/OptionConstructor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,14 @@ JS::ThrowCompletionOr<JS::Value> 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<JS::NonnullGCPtr<JS::Object>> 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::Window>(HTML::current_global_object());
// 1. Let document be the current principal global object's associated Document.
auto& window = verify_cast<HTML::Window>(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.
Expand Down
4 changes: 2 additions & 2 deletions Userland/Libraries/LibWeb/CSS/CSSStyleSheet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<CSSStyleSheet>> 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::Window>(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::Window>(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.
Expand Down
8 changes: 5 additions & 3 deletions Userland/Libraries/LibWeb/DOM/Node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1450,16 +1450,18 @@ void Node::serialize_tree_as_json(JsonObjectSerializer<StringBuilder>& 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&>(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();
}

Expand Down
2 changes: 1 addition & 1 deletion Userland/Libraries/LibWeb/DOM/Text.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ void Text::visit_edges(Cell::Visitor& visitor)
WebIDL::ExceptionOr<JS::NonnullGCPtr<Text>> 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::Window>(HTML::current_global_object());
auto& window = verify_cast<HTML::Window>(HTML::current_principal_global_object());
return realm.heap().allocate<Text>(realm, window.associated_document(), data);
}

Expand Down
2 changes: 1 addition & 1 deletion Userland/Libraries/LibWeb/DOMURL/DOMURL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ WebIDL::ExceptionOr<void> 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()))
Expand Down
2 changes: 1 addition & 1 deletion Userland/Libraries/LibWeb/Fetch/Response.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Response>> 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.
Expand Down
Loading
Loading