diff options
author | Andreas Kling <kling@serenityos.org> | 2022-12-09 18:48:25 +0100 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2022-12-09 18:51:03 +0000 |
commit | fbf9cb338728bdae160655a1e1527f5ce0e1871a (patch) | |
tree | 6cc659f9f431338e9a8977b341f98fd1f85a7c22 | |
parent | 23b07b3408728f5ea184c6fa928729e11b0c4957 (diff) | |
download | serenity-fbf9cb338728bdae160655a1e1527f5ce0e1871a.zip |
WebContent+LibWeb+LibJS: Simplify injection of JS console globals
Instead of creating a new global object and proxying everything through
it, we now evaluate console inputs inside a `with` environment.
This seems to match the behavior of WebKit and Gecko in my basic
testing, and removes the ConsoleGlobalObject which has been a source of
confusion and invalid downcasts.
The globals now live in a class called ConsoleGlobalObjectExtensions
(renamed from ConsoleGlobalObject since it's no longer a global object).
To make this possible, I had to add a way to override the initial
lexical environment when calling JS::Interpreter::run(). This is plumbed
via Web::HTML::ClassicScript::run().
12 files changed, 187 insertions, 292 deletions
diff --git a/Userland/Libraries/LibJS/Interpreter.cpp b/Userland/Libraries/LibJS/Interpreter.cpp index 20bdc1bc86..2dc3be1e19 100644 --- a/Userland/Libraries/LibJS/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Interpreter.cpp @@ -35,7 +35,7 @@ Interpreter::Interpreter(VM& vm) } // 16.1.6 ScriptEvaluation ( scriptRecord ), https://tc39.es/ecma262/#sec-runtime-semantics-scriptevaluation -ThrowCompletionOr<Value> Interpreter::run(Script& script_record) +ThrowCompletionOr<Value> Interpreter::run(Script& script_record, JS::GCPtr<Environment> lexical_environment_override) { auto& vm = this->vm(); @@ -62,6 +62,10 @@ ThrowCompletionOr<Value> Interpreter::run(Script& script_record) // 7. Set the LexicalEnvironment of scriptContext to globalEnv. script_context.lexical_environment = &global_environment; + // Non-standard: Override the lexical environment if requested. + if (lexical_environment_override) + script_context.lexical_environment = lexical_environment_override; + // 8. Set the PrivateEnvironment of scriptContext to null. // NOTE: This isn't in the spec, but we require it. diff --git a/Userland/Libraries/LibJS/Interpreter.h b/Userland/Libraries/LibJS/Interpreter.h index e5937c86bc..d84e93ff3b 100644 --- a/Userland/Libraries/LibJS/Interpreter.h +++ b/Userland/Libraries/LibJS/Interpreter.h @@ -66,7 +66,7 @@ public: ~Interpreter() = default; - ThrowCompletionOr<Value> run(Script&); + ThrowCompletionOr<Value> run(Script&, JS::GCPtr<Environment> lexical_environment_override = {}); ThrowCompletionOr<Value> run(SourceTextModule&); Realm& realm(); diff --git a/Userland/Libraries/LibWeb/HTML/Scripting/ClassicScript.cpp b/Userland/Libraries/LibWeb/HTML/Scripting/ClassicScript.cpp index 2fdc908821..d4dedf47a5 100644 --- a/Userland/Libraries/LibWeb/HTML/Scripting/ClassicScript.cpp +++ b/Userland/Libraries/LibWeb/HTML/Scripting/ClassicScript.cpp @@ -71,7 +71,7 @@ JS::NonnullGCPtr<ClassicScript> ClassicScript::create(DeprecatedString filename, } // https://html.spec.whatwg.org/multipage/webappapis.html#run-a-classic-script -JS::Completion ClassicScript::run(RethrowErrors rethrow_errors) +JS::Completion ClassicScript::run(RethrowErrors rethrow_errors, JS::GCPtr<JS::Environment> lexical_environment_override) { auto& vm = settings_object().realm().vm(); @@ -97,7 +97,7 @@ JS::Completion ClassicScript::run(RethrowErrors rethrow_errors) // 6. Otherwise, set evaluationStatus to ScriptEvaluation(script's record). auto interpreter = JS::Interpreter::create_with_existing_realm(m_script_record->realm()); - evaluation_status = interpreter->run(*m_script_record); + evaluation_status = interpreter->run(*m_script_record, lexical_environment_override); // FIXME: If ScriptEvaluation does not complete because the user agent has aborted the running script, leave evaluationStatus as null. diff --git a/Userland/Libraries/LibWeb/HTML/Scripting/ClassicScript.h b/Userland/Libraries/LibWeb/HTML/Scripting/ClassicScript.h index 9f1ef9c2ab..3d602f1d66 100644 --- a/Userland/Libraries/LibWeb/HTML/Scripting/ClassicScript.h +++ b/Userland/Libraries/LibWeb/HTML/Scripting/ClassicScript.h @@ -32,7 +32,7 @@ public: No, Yes, }; - JS::Completion run(RethrowErrors = RethrowErrors::No); + JS::Completion run(RethrowErrors = RethrowErrors::No, JS::GCPtr<JS::Environment> lexical_environment_override = {}); MutedErrors muted_errors() const { return m_muted_errors; } diff --git a/Userland/Services/WebContent/CMakeLists.txt b/Userland/Services/WebContent/CMakeLists.txt index 3ea9a981eb..c5c0e30247 100644 --- a/Userland/Services/WebContent/CMakeLists.txt +++ b/Userland/Services/WebContent/CMakeLists.txt @@ -12,7 +12,7 @@ compile_ipc(WebDriverServer.ipc WebDriverServerEndpoint.h) set(SOURCES ConnectionFromClient.cpp - ConsoleGlobalObject.cpp + ConsoleGlobalEnvironmentExtensions.cpp ImageCodecPluginSerenity.cpp PageHost.cpp WebContentConsoleClient.cpp diff --git a/Userland/Services/WebContent/ConsoleGlobalEnvironmentExtensions.cpp b/Userland/Services/WebContent/ConsoleGlobalEnvironmentExtensions.cpp new file mode 100644 index 0000000000..3377b1a4fe --- /dev/null +++ b/Userland/Services/WebContent/ConsoleGlobalEnvironmentExtensions.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2021-2022, Sam Atkins <atkinssj@serenityos.org> + * Copyright (c) 2022, Andreas Kling <kling@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "ConsoleGlobalEnvironmentExtensions.h" +#include <LibJS/Runtime/Array.h> +#include <LibJS/Runtime/Completion.h> +#include <LibWeb/Bindings/ExceptionOrUtils.h> +#include <LibWeb/DOM/Document.h> +#include <LibWeb/DOM/NodeList.h> +#include <LibWeb/HTML/Window.h> + +namespace WebContent { + +ConsoleGlobalEnvironmentExtensions::ConsoleGlobalEnvironmentExtensions(JS::Realm& realm, Web::HTML::Window& window) + : Object(realm, nullptr) + , m_window_object(window) +{ +} + +void ConsoleGlobalEnvironmentExtensions::initialize(JS::Realm& realm) +{ + Base::initialize(realm); + + define_native_accessor(realm, "$0", $0_getter, nullptr, 0); + define_native_accessor(realm, "$_", $__getter, nullptr, 0); + define_native_function(realm, "$", $_function, 2, JS::default_attributes); + define_native_function(realm, "$$", $$_function, 2, JS::default_attributes); +} + +void ConsoleGlobalEnvironmentExtensions::visit_edges(Visitor& visitor) +{ + Base::visit_edges(visitor); + visitor.visit(m_window_object); +} + +static JS::ThrowCompletionOr<ConsoleGlobalEnvironmentExtensions*> get_console(JS::VM& vm) +{ + auto this_value = vm.this_value(); + if (!this_value.is_object() || !is<ConsoleGlobalEnvironmentExtensions>(this_value.as_object())) + return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "ConsoleGlobalEnvironmentExtensions"); + + return &static_cast<ConsoleGlobalEnvironmentExtensions&>(this_value.as_object()); +} + +JS_DEFINE_NATIVE_FUNCTION(ConsoleGlobalEnvironmentExtensions::$0_getter) +{ + auto* console_global_object = TRY(get_console(vm)); + auto& window = *console_global_object->m_window_object; + auto* inspected_node = window.associated_document().inspected_node(); + if (!inspected_node) + return JS::js_undefined(); + + return inspected_node; +} + +JS_DEFINE_NATIVE_FUNCTION(ConsoleGlobalEnvironmentExtensions::$__getter) +{ + auto* console_global_object = TRY(get_console(vm)); + return console_global_object->m_most_recent_result; +} + +JS_DEFINE_NATIVE_FUNCTION(ConsoleGlobalEnvironmentExtensions::$_function) +{ + auto* console_global_object = TRY(get_console(vm)); + auto& window = *console_global_object->m_window_object; + + auto selector = TRY(vm.argument(0).to_string(vm)); + + if (vm.argument_count() > 1) { + auto element_value = vm.argument(1); + if (!(element_value.is_object() && is<Web::DOM::ParentNode>(element_value.as_object()))) { + return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "Node"); + } + + auto& element = static_cast<Web::DOM::ParentNode&>(element_value.as_object()); + return TRY(Web::Bindings::throw_dom_exception_if_needed(vm, [&]() { + return element.query_selector(selector); + })); + } + + return TRY(Web::Bindings::throw_dom_exception_if_needed(vm, [&]() { + return window.associated_document().query_selector(selector); + })); +} + +JS_DEFINE_NATIVE_FUNCTION(ConsoleGlobalEnvironmentExtensions::$$_function) +{ + auto* console_global_object = TRY(get_console(vm)); + auto& window = *console_global_object->m_window_object; + + auto selector = TRY(vm.argument(0).to_string(vm)); + + Web::DOM::ParentNode* element = &window.associated_document(); + + if (vm.argument_count() > 1) { + auto element_value = vm.argument(1); + if (!(element_value.is_object() && is<Web::DOM::ParentNode>(element_value.as_object()))) { + return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "Node"); + } + + element = static_cast<Web::DOM::ParentNode*>(&element_value.as_object()); + } + + auto node_list = TRY(Web::Bindings::throw_dom_exception_if_needed(vm, [&]() { + return element->query_selector_all(selector); + })); + + auto* array = TRY(JS::Array::create(*vm.current_realm(), node_list->length())); + for (auto i = 0u; i < node_list->length(); ++i) { + TRY(array->create_data_property_or_throw(i, node_list->item_value(i))); + } + + return array; +} + +} diff --git a/Userland/Services/WebContent/ConsoleGlobalEnvironmentExtensions.h b/Userland/Services/WebContent/ConsoleGlobalEnvironmentExtensions.h new file mode 100644 index 0000000000..476000ad85 --- /dev/null +++ b/Userland/Services/WebContent/ConsoleGlobalEnvironmentExtensions.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021-2022, Sam Atkins <atkinssj@serenityos.org> + * Copyright (c) 2022, Andreas Kling <kling@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <LibJS/Forward.h> +#include <LibJS/Runtime/Completion.h> +#include <LibWeb/HTML/Window.h> + +namespace WebContent { + +class ConsoleGlobalEnvironmentExtensions final : public JS::Object { + JS_OBJECT(ConsoleGlobalEnvironmentExtensions, JS::Object); + +public: + ConsoleGlobalEnvironmentExtensions(JS::Realm&, Web::HTML::Window&); + virtual void initialize(JS::Realm&) override; + virtual ~ConsoleGlobalEnvironmentExtensions() override = default; + + void set_most_recent_result(JS::Value result) { m_most_recent_result = move(result); } + +private: + virtual void visit_edges(Visitor&) override; + + // $0, the DOM node currently selected in the inspector + JS_DECLARE_NATIVE_FUNCTION($0_getter); + // $_, the value of the most recent expression entered into the console + JS_DECLARE_NATIVE_FUNCTION($__getter); + // $(selector, element), equivalent to `(element || document).querySelector(selector)` + JS_DECLARE_NATIVE_FUNCTION($_function); + // $$(selector, element), equivalent to `(element || document).querySelectorAll(selector)` + JS_DECLARE_NATIVE_FUNCTION($$_function); + + JS::NonnullGCPtr<Web::HTML::Window> m_window_object; + JS::Value m_most_recent_result { JS::js_undefined() }; +}; + +} diff --git a/Userland/Services/WebContent/ConsoleGlobalObject.cpp b/Userland/Services/WebContent/ConsoleGlobalObject.cpp deleted file mode 100644 index 8082698fa7..0000000000 --- a/Userland/Services/WebContent/ConsoleGlobalObject.cpp +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (c) 2021-2022, Sam Atkins <atkinssj@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "ConsoleGlobalObject.h" -#include <LibJS/Runtime/Array.h> -#include <LibJS/Runtime/Completion.h> -#include <LibWeb/Bindings/ExceptionOrUtils.h> -#include <LibWeb/DOM/Document.h> -#include <LibWeb/DOM/NodeList.h> -#include <LibWeb/HTML/Window.h> - -namespace WebContent { - -ConsoleGlobalObject::ConsoleGlobalObject(JS::Realm& realm, Web::HTML::Window& parent_object) - : GlobalObject(realm) - , m_window_object(&parent_object) -{ -} - -void ConsoleGlobalObject::initialize(JS::Realm& realm) -{ - Base::initialize(realm); - - define_native_accessor(realm, "$0", $0_getter, nullptr, 0); - define_native_accessor(realm, "$_", $__getter, nullptr, 0); - define_native_function(realm, "$", $_function, 2, JS::default_attributes); - define_native_function(realm, "$$", $$_function, 2, JS::default_attributes); -} - -void ConsoleGlobalObject::visit_edges(Visitor& visitor) -{ - Base::visit_edges(visitor); - visitor.visit(m_window_object); -} - -JS::ThrowCompletionOr<JS::Object*> ConsoleGlobalObject::internal_get_prototype_of() const -{ - return m_window_object->internal_get_prototype_of(); -} - -JS::ThrowCompletionOr<bool> ConsoleGlobalObject::internal_set_prototype_of(JS::Object* prototype) -{ - return m_window_object->internal_set_prototype_of(prototype); -} - -JS::ThrowCompletionOr<bool> ConsoleGlobalObject::internal_is_extensible() const -{ - return m_window_object->internal_is_extensible(); -} - -JS::ThrowCompletionOr<bool> ConsoleGlobalObject::internal_prevent_extensions() -{ - return m_window_object->internal_prevent_extensions(); -} - -JS::ThrowCompletionOr<Optional<JS::PropertyDescriptor>> ConsoleGlobalObject::internal_get_own_property(JS::PropertyKey const& property_name) const -{ - if (auto result = TRY(m_window_object->internal_get_own_property(property_name)); result.has_value()) - return result; - - return Base::internal_get_own_property(property_name); -} - -JS::ThrowCompletionOr<bool> ConsoleGlobalObject::internal_define_own_property(JS::PropertyKey const& property_name, JS::PropertyDescriptor const& descriptor) -{ - return m_window_object->internal_define_own_property(property_name, descriptor); -} - -JS::ThrowCompletionOr<bool> ConsoleGlobalObject::internal_has_property(JS::PropertyKey const& property_name) const -{ - return TRY(Object::internal_has_property(property_name)) || TRY(m_window_object->internal_has_property(property_name)); -} - -JS::ThrowCompletionOr<JS::Value> ConsoleGlobalObject::internal_get(JS::PropertyKey const& property_name, JS::Value receiver) const -{ - if (TRY(m_window_object->has_own_property(property_name))) - return m_window_object->internal_get(property_name, (receiver == this) ? m_window_object : receiver); - - return Base::internal_get(property_name, receiver); -} - -JS::ThrowCompletionOr<bool> ConsoleGlobalObject::internal_set(JS::PropertyKey const& property_name, JS::Value value, JS::Value receiver) -{ - return m_window_object->internal_set(property_name, value, (receiver == this) ? m_window_object : receiver); -} - -JS::ThrowCompletionOr<bool> ConsoleGlobalObject::internal_delete(JS::PropertyKey const& property_name) -{ - return m_window_object->internal_delete(property_name); -} - -JS::ThrowCompletionOr<JS::MarkedVector<JS::Value>> ConsoleGlobalObject::internal_own_property_keys() const -{ - return m_window_object->internal_own_property_keys(); -} - -static JS::ThrowCompletionOr<ConsoleGlobalObject*> get_console(JS::VM& vm) -{ - if (!is<ConsoleGlobalObject>(vm.get_global_object())) - return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "ConsoleGlobalObject"); - - return static_cast<ConsoleGlobalObject*>(&vm.get_global_object()); -} - -JS_DEFINE_NATIVE_FUNCTION(ConsoleGlobalObject::$0_getter) -{ - auto* console_global_object = TRY(get_console(vm)); - auto& window = *console_global_object->m_window_object; - auto* inspected_node = window.associated_document().inspected_node(); - if (!inspected_node) - return JS::js_undefined(); - - return inspected_node; -} - -JS_DEFINE_NATIVE_FUNCTION(ConsoleGlobalObject::$__getter) -{ - auto* console_global_object = TRY(get_console(vm)); - return console_global_object->m_most_recent_result; -} - -JS_DEFINE_NATIVE_FUNCTION(ConsoleGlobalObject::$_function) -{ - auto* console_global_object = TRY(get_console(vm)); - auto& window = *console_global_object->m_window_object; - - auto selector = TRY(vm.argument(0).to_string(vm)); - - if (vm.argument_count() > 1) { - auto element_value = vm.argument(1); - if (!(element_value.is_object() && is<Web::DOM::ParentNode>(element_value.as_object()))) { - return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "Node"); - } - - auto& element = static_cast<Web::DOM::ParentNode&>(element_value.as_object()); - return TRY(Web::Bindings::throw_dom_exception_if_needed(vm, [&]() { - return element.query_selector(selector); - })); - } - - return TRY(Web::Bindings::throw_dom_exception_if_needed(vm, [&]() { - return window.associated_document().query_selector(selector); - })); -} - -JS_DEFINE_NATIVE_FUNCTION(ConsoleGlobalObject::$$_function) -{ - auto* console_global_object = TRY(get_console(vm)); - auto& window = *console_global_object->m_window_object; - - auto selector = TRY(vm.argument(0).to_string(vm)); - - Web::DOM::ParentNode* element = &window.associated_document(); - - if (vm.argument_count() > 1) { - auto element_value = vm.argument(1); - if (!(element_value.is_object() && is<Web::DOM::ParentNode>(element_value.as_object()))) { - return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "Node"); - } - - element = static_cast<Web::DOM::ParentNode*>(&element_value.as_object()); - } - - auto node_list = TRY(Web::Bindings::throw_dom_exception_if_needed(vm, [&]() { - return element->query_selector_all(selector); - })); - - auto* array = TRY(JS::Array::create(*vm.current_realm(), node_list->length())); - for (auto i = 0u; i < node_list->length(); ++i) { - TRY(array->create_data_property_or_throw(i, node_list->item_value(i))); - } - - return array; -} - -} diff --git a/Userland/Services/WebContent/ConsoleGlobalObject.h b/Userland/Services/WebContent/ConsoleGlobalObject.h deleted file mode 100644 index 75d13ad4c5..0000000000 --- a/Userland/Services/WebContent/ConsoleGlobalObject.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2021-2022, Sam Atkins <atkinssj@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include <LibJS/Forward.h> -#include <LibJS/Runtime/Completion.h> -#include <LibJS/Runtime/GlobalObject.h> -#include <LibWeb/HTML/Window.h> - -namespace WebContent { - -class ConsoleGlobalObject final : public JS::GlobalObject { - JS_OBJECT(ConsoleGlobalObject, JS::GlobalObject); - -public: - ConsoleGlobalObject(JS::Realm&, Web::HTML::Window&); - virtual void initialize(JS::Realm&) override; - virtual ~ConsoleGlobalObject() override = default; - - virtual JS::ThrowCompletionOr<Object*> internal_get_prototype_of() const override; - virtual JS::ThrowCompletionOr<bool> internal_set_prototype_of(Object* prototype) override; - virtual JS::ThrowCompletionOr<bool> internal_is_extensible() const override; - virtual JS::ThrowCompletionOr<bool> internal_prevent_extensions() override; - virtual JS::ThrowCompletionOr<Optional<JS::PropertyDescriptor>> internal_get_own_property(JS::PropertyKey const& name) const override; - virtual JS::ThrowCompletionOr<bool> internal_define_own_property(JS::PropertyKey const& name, JS::PropertyDescriptor const& descriptor) override; - virtual JS::ThrowCompletionOr<bool> internal_has_property(JS::PropertyKey const& name) const override; - virtual JS::ThrowCompletionOr<JS::Value> internal_get(JS::PropertyKey const&, JS::Value) const override; - virtual JS::ThrowCompletionOr<bool> internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver) override; - virtual JS::ThrowCompletionOr<bool> internal_delete(JS::PropertyKey const& name) override; - virtual JS::ThrowCompletionOr<JS::MarkedVector<JS::Value>> internal_own_property_keys() const override; - - void set_most_recent_result(JS::Value result) { m_most_recent_result = move(result); } - -private: - virtual void visit_edges(Visitor&) override; - - // $0, the DOM node currently selected in the inspector - JS_DECLARE_NATIVE_FUNCTION($0_getter); - // $_, the value of the most recent expression entered into the console - JS_DECLARE_NATIVE_FUNCTION($__getter); - // $(selector, element), equivalent to `(element || document).querySelector(selector)` - JS_DECLARE_NATIVE_FUNCTION($_function); - // $$(selector, element), equivalent to `(element || document).querySelectorAll(selector)` - JS_DECLARE_NATIVE_FUNCTION($$_function); - - Web::HTML::Window* m_window_object; - JS::Value m_most_recent_result { JS::js_undefined() }; -}; - -} diff --git a/Userland/Services/WebContent/Forward.h b/Userland/Services/WebContent/Forward.h index b5fedefa07..160588a103 100644 --- a/Userland/Services/WebContent/Forward.h +++ b/Userland/Services/WebContent/Forward.h @@ -9,7 +9,7 @@ namespace WebContent { class ConnectionFromClient; -class ConsoleGlobalObject; +class ConsoleGlobalEnvironmentExtensions; class PageHost; class WebContentConsoleClient; class WebDriverConnection; diff --git a/Userland/Services/WebContent/WebContentConsoleClient.cpp b/Userland/Services/WebContent/WebContentConsoleClient.cpp index 649cbeceab..0afd762d69 100644 --- a/Userland/Services/WebContent/WebContentConsoleClient.cpp +++ b/Userland/Services/WebContent/WebContentConsoleClient.cpp @@ -7,78 +7,42 @@ */ #include "WebContentConsoleClient.h" +#include <AK/TemporaryChange.h> #include <LibJS/Interpreter.h> #include <LibJS/MarkupGenerator.h> +#include <LibJS/Runtime/AbstractOperations.h> +#include <LibJS/Runtime/ObjectEnvironment.h> #include <LibWeb/HTML/PolicyContainers.h> #include <LibWeb/HTML/Scripting/ClassicScript.h> #include <LibWeb/HTML/Scripting/Environments.h> #include <LibWeb/HTML/Window.h> -#include <WebContent/ConsoleGlobalObject.h> +#include <WebContent/ConsoleGlobalEnvironmentExtensions.h> namespace WebContent { -class ConsoleEnvironmentSettingsObject final : public Web::HTML::EnvironmentSettingsObject { - JS_CELL(ConsoleEnvironmentSettingsObject, EnvironmentSettingsObject); - -public: - ConsoleEnvironmentSettingsObject(NonnullOwnPtr<JS::ExecutionContext> execution_context) - : Web::HTML::EnvironmentSettingsObject(move(execution_context)) - { - } - - virtual ~ConsoleEnvironmentSettingsObject() override = default; - - JS::GCPtr<Web::DOM::Document> responsible_document() override { return nullptr; } - DeprecatedString api_url_character_encoding() override { return m_api_url_character_encoding; } - AK::URL api_base_url() override { return m_url; } - Web::HTML::Origin origin() override { return m_origin; } - Web::HTML::PolicyContainer policy_container() override { return m_policy_container; } - Web::HTML::CanUseCrossOriginIsolatedAPIs cross_origin_isolated_capability() override { return Web::HTML::CanUseCrossOriginIsolatedAPIs::Yes; } - -private: - DeprecatedString m_api_url_character_encoding; - AK::URL m_url; - Web::HTML::Origin m_origin; - Web::HTML::PolicyContainer m_policy_container; -}; - WebContentConsoleClient::WebContentConsoleClient(JS::Console& console, JS::Realm& realm, ConnectionFromClient& client) : ConsoleClient(console) , m_client(client) - , m_realm(realm) { - JS::DeferGC defer_gc(realm.heap()); - - auto& vm = realm.vm(); - auto& window = static_cast<Web::HTML::Window&>(realm.global_object()); - - auto console_execution_context = MUST(JS::Realm::initialize_host_defined_realm( - vm, [&](JS::Realm& realm) { - m_console_global_object = vm.heap().allocate_without_realm<ConsoleGlobalObject>(realm, window); - return m_console_global_object; - }, - nullptr)); - - auto* console_realm = console_execution_context->realm; - m_console_settings = vm.heap().allocate<ConsoleEnvironmentSettingsObject>(*console_realm, move(console_execution_context)); - auto* intrinsics = vm.heap().allocate<Web::Bindings::Intrinsics>(*console_realm, *console_realm); - auto host_defined = make<Web::Bindings::HostDefined>(*m_console_settings, *intrinsics); - console_realm->set_host_defined(move(host_defined)); + auto& window = verify_cast<Web::HTML::Window>(realm.global_object()); + m_console_global_environment_extensions = realm.heap().allocate<ConsoleGlobalEnvironmentExtensions>(realm, realm, window); } void WebContentConsoleClient::handle_input(DeprecatedString const& js_source) { - if (!m_realm) + if (!m_console_global_environment_extensions) return; - auto script = Web::HTML::ClassicScript::create("(console)", js_source, *m_console_settings, m_console_settings->api_base_url()); + auto& settings = Web::HTML::relevant_settings_object(*m_console_global_environment_extensions); + auto script = Web::HTML::ClassicScript::create("(console)", js_source, settings, settings.api_base_url()); - // FIXME: Add parse error printouts back once ClassicScript can report parse errors. + JS::Environment* with_scope = JS::new_object_environment(*m_console_global_environment_extensions, true, &settings.realm().global_environment()); - auto result = script->run(); + // FIXME: Add parse error printouts back once ClassicScript can report parse errors. + auto result = script->run(Web::HTML::ClassicScript::RethrowErrors::No, with_scope); if (result.value().has_value()) { - m_console_global_object->set_most_recent_result(result.value().value()); + m_console_global_environment_extensions->set_most_recent_result(result.value().value()); print_html(JS::MarkupGenerator::html_from_value(*result.value()).release_value_but_fixme_should_propagate_errors().to_deprecated_string()); } } diff --git a/Userland/Services/WebContent/WebContentConsoleClient.h b/Userland/Services/WebContent/WebContentConsoleClient.h index 9ab581d222..208e8a5399 100644 --- a/Userland/Services/WebContent/WebContentConsoleClient.h +++ b/Userland/Services/WebContent/WebContentConsoleClient.h @@ -35,9 +35,7 @@ private: } ConnectionFromClient& m_client; - WeakPtr<JS::Realm> m_realm; - JS::GCPtr<class ConsoleEnvironmentSettingsObject> m_console_settings; - JS::Handle<ConsoleGlobalObject> m_console_global_object; + JS::Handle<ConsoleGlobalEnvironmentExtensions> m_console_global_environment_extensions; void clear_output(); void print_html(DeprecatedString const& line); |