diff --git a/Libraries/LibWebView/Application.cpp b/Libraries/LibWebView/Application.cpp index 83a0d8c4af5..576d8622a86 100644 --- a/Libraries/LibWebView/Application.cpp +++ b/Libraries/LibWebView/Application.cpp @@ -417,4 +417,20 @@ void Application::clear_highlighted_dom_node(DevTools::TabDescription const& des view->clear_highlighted_dom_node(); } +void Application::evaluate_javascript(DevTools::TabDescription const& description, String script, OnScriptEvaluationComplete on_complete) const +{ + auto view = ViewImplementation::find_view_by_id(description.id); + if (!view.has_value()) { + on_complete(Error::from_string_literal("Unable to locate tab")); + return; + } + + view->on_received_js_console_result = [&view = *view, on_complete = move(on_complete)](JsonValue result) { + view.on_received_js_console_result = nullptr; + on_complete(move(result)); + }; + + view->js_console_input(move(script)); +} + } diff --git a/Libraries/LibWebView/Application.h b/Libraries/LibWebView/Application.h index a9c3cb05f84..c7972db5da1 100644 --- a/Libraries/LibWebView/Application.h +++ b/Libraries/LibWebView/Application.h @@ -96,6 +96,7 @@ private: virtual void clear_inspected_dom_node(DevTools::TabDescription const&) const override; virtual void highlight_dom_node(DevTools::TabDescription const&, Web::UniqueNodeID, Optional) const override; virtual void clear_highlighted_dom_node(DevTools::TabDescription const&) const override; + virtual void evaluate_javascript(DevTools::TabDescription const&, String, OnScriptEvaluationComplete) const override; static Application* s_the; diff --git a/Libraries/LibWebView/ViewImplementation.h b/Libraries/LibWebView/ViewImplementation.h index 1f1ee94724a..8fb77e9b3d4 100644 --- a/Libraries/LibWebView/ViewImplementation.h +++ b/Libraries/LibWebView/ViewImplementation.h @@ -215,6 +215,7 @@ public: Function on_received_hovered_node_id; Function const& node_id)> on_finshed_editing_dom_node; Function on_received_dom_node_html; + Function on_received_js_console_result; Function on_received_console_message; Function const& message_types, Vector const& messages)> on_received_console_messages; Function on_resource_status_change; diff --git a/Libraries/LibWebView/WebContentClient.cpp b/Libraries/LibWebView/WebContentClient.cpp index 4bef200e246..96a811f4663 100644 --- a/Libraries/LibWebView/WebContentClient.cpp +++ b/Libraries/LibWebView/WebContentClient.cpp @@ -366,6 +366,14 @@ void WebContentClient::did_get_internal_page_info(u64 page_id, WebView::PageInfo view->did_receive_internal_page_info({}, type, info); } +void WebContentClient::did_execute_js_console_input(u64 page_id, JsonValue const& result) +{ + if (auto view = view_for_page_id(page_id); view.has_value()) { + if (view->on_received_js_console_result) + view->on_received_js_console_result(move(const_cast(result))); + } +} + void WebContentClient::did_output_js_console_message(u64 page_id, i32 message_index) { if (auto view = view_for_page_id(page_id); view.has_value()) { diff --git a/Libraries/LibWebView/WebContentClient.h b/Libraries/LibWebView/WebContentClient.h index e8971d02ec3..52d4b7e3b96 100644 --- a/Libraries/LibWebView/WebContentClient.h +++ b/Libraries/LibWebView/WebContentClient.h @@ -79,6 +79,7 @@ private: virtual void did_get_dom_node_html(u64 page_id, String const& html) override; virtual void did_take_screenshot(u64 page_id, Gfx::ShareableBitmap const& screenshot) override; virtual void did_get_internal_page_info(u64 page_id, PageInfoType, String const&) override; + virtual void did_execute_js_console_input(u64 page_id, JsonValue const&) override; virtual void did_output_js_console_message(u64 page_id, i32 message_index) override; virtual void did_get_js_console_messages(u64 page_id, i32 start_index, Vector const& message_types, Vector const& messages) override; virtual void did_change_favicon(u64 page_id, Gfx::ShareableBitmap const&) override; diff --git a/Services/WebContent/CMakeLists.txt b/Services/WebContent/CMakeLists.txt index 56ff5099031..9da574227e3 100644 --- a/Services/WebContent/CMakeLists.txt +++ b/Services/WebContent/CMakeLists.txt @@ -30,7 +30,7 @@ target_include_directories(webcontentservice PUBLIC $) target_include_directories(webcontentservice PUBLIC $) -target_link_libraries(webcontentservice PUBLIC LibCore LibFileSystem LibGfx LibIPC LibJS LibMain LibMedia LibWeb LibWebSocket LibRequests LibWebView LibImageDecoderClient LibGC) +target_link_libraries(webcontentservice PUBLIC LibCore LibCrypto LibFileSystem LibGfx LibIPC LibJS LibMain LibMedia LibWeb LibWebSocket LibRequests LibWebView LibImageDecoderClient LibGC) target_link_libraries(webcontentservice PRIVATE OpenSSL::Crypto OpenSSL::SSL) if (ENABLE_QT) diff --git a/Services/WebContent/DevToolsConsoleClient.cpp b/Services/WebContent/DevToolsConsoleClient.cpp index 64e15b33655..7bf1bf9c7e5 100644 --- a/Services/WebContent/DevToolsConsoleClient.cpp +++ b/Services/WebContent/DevToolsConsoleClient.cpp @@ -4,7 +4,13 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include +#include +#include +#include +#include #include +#include #include #include #include @@ -29,9 +35,67 @@ DevToolsConsoleClient::DevToolsConsoleClient(JS::Realm& realm, JS::Console& cons DevToolsConsoleClient::~DevToolsConsoleClient() = default; +// https://firefox-source-docs.mozilla.org/devtools/backend/protocol.html#grips +static JsonValue serialize_js_value(JS::Realm& realm, JS::Value value) +{ + auto& vm = realm.vm(); + + auto serialize_type = [](StringView type) { + JsonObject serialized; + serialized.set("type"sv, type); + return serialized; + }; + + if (value.is_undefined()) + return serialize_type("undefined"sv); + + if (value.is_null()) + return serialize_type("null"sv); + + if (value.is_boolean()) + return value.as_bool(); + + if (value.is_string()) + return value.as_string().utf8_string(); + + if (value.is_number()) { + if (value.is_nan()) + return serialize_type("NaN"sv); + if (value.is_positive_infinity()) + return serialize_type("Infinity"sv); + if (value.is_negative_infinity()) + return serialize_type("-Infinity"sv); + if (value.is_negative_zero()) + return serialize_type("-0"sv); + return value.as_double(); + } + + if (value.is_bigint()) { + auto serialized = serialize_type("BigInt"sv); + serialized.set("text"sv, MUST(value.as_bigint().big_integer().to_base(10))); + return serialized; + } + + if (value.is_symbol()) + return MUST(value.as_symbol().descriptive_string()); + + // FIXME: Handle serialization of object grips. For now, we stringify the object. + if (value.is_object()) { + Web::HTML::TemporaryExecutionContext execution_context { realm }; + AllocatingMemoryStream stream; + + JS::PrintContext context { vm, stream, true }; + MUST(JS::print(value, context)); + + return MUST(String::from_stream(stream, stream.used_buffer_size())); + } + + return {}; +} + void DevToolsConsoleClient::handle_result(JS::Value result) { - (void)result; + m_client->did_execute_js_console_input(serialize_js_value(m_realm, result)); } void DevToolsConsoleClient::report_exception(JS::Error const& exception, bool in_promise) diff --git a/Services/WebContent/PageClient.cpp b/Services/WebContent/PageClient.cpp index 1b07c89d235..d555a11442c 100644 --- a/Services/WebContent/PageClient.cpp +++ b/Services/WebContent/PageClient.cpp @@ -7,6 +7,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include @@ -750,6 +751,11 @@ void PageClient::initialize_js_console(Web::DOM::Document& document) document.set_console_client(console_client); } +void PageClient::did_execute_js_console_input(JsonValue result) +{ + client().async_did_execute_js_console_input(m_id, move(result)); +} + void PageClient::js_console_input(StringView js_source) { if (m_top_level_document_console_client) diff --git a/Services/WebContent/PageClient.h b/Services/WebContent/PageClient.h index 6e234060f3d..b6b201c5268 100644 --- a/Services/WebContent/PageClient.h +++ b/Services/WebContent/PageClient.h @@ -85,6 +85,7 @@ public: void initialize_js_console(Web::DOM::Document& document); void js_console_input(StringView js_source); + void did_execute_js_console_input(JsonValue); void run_javascript(StringView js_source); void js_console_request_messages(i32 start_index); void did_output_js_console_message(i32 message_index); diff --git a/Services/WebContent/WebContentClient.ipc b/Services/WebContent/WebContentClient.ipc index 9edb48a7ec3..d52fe567b66 100644 --- a/Services/WebContent/WebContentClient.ipc +++ b/Services/WebContent/WebContentClient.ipc @@ -91,6 +91,7 @@ endpoint WebContentClient did_change_audio_play_state(u64 page_id, Web::HTML::AudioPlayState play_state) =| + did_execute_js_console_input(u64 page_id, JsonValue result) =| did_output_js_console_message(u64 page_id, i32 message_index) =| did_get_js_console_messages(u64 page_id, i32 start_index, Vector message_types, Vector messages) =|