diff --git a/Libraries/LibWebView/Application.cpp b/Libraries/LibWebView/Application.cpp index 576d8622a86..c6c79cddc59 100644 --- a/Libraries/LibWebView/Application.cpp +++ b/Libraries/LibWebView/Application.cpp @@ -433,4 +433,34 @@ void Application::evaluate_javascript(DevTools::TabDescription const& descriptio view->js_console_input(move(script)); } +void Application::listen_for_console_messages(DevTools::TabDescription const& description, OnConsoleMessageAvailable on_console_message_available, OnReceivedConsoleMessages on_received_console_output) const +{ + auto view = ViewImplementation::find_view_by_id(description.id); + if (!view.has_value()) + return; + + view->on_console_message_available = move(on_console_message_available); + view->on_received_unstyled_console_messages = move(on_received_console_output); + view->js_console_request_messages(0); +} + +void Application::stop_listening_for_console_messages(DevTools::TabDescription const& description) const +{ + auto view = ViewImplementation::find_view_by_id(description.id); + if (!view.has_value()) + return; + + view->on_console_message_available = nullptr; + view->on_received_unstyled_console_messages = nullptr; +} + +void Application::request_console_messages(DevTools::TabDescription const& description, i32 start_index) const +{ + auto view = ViewImplementation::find_view_by_id(description.id); + if (!view.has_value()) + return; + + view->js_console_request_messages(start_index); +} + } diff --git a/Libraries/LibWebView/Application.h b/Libraries/LibWebView/Application.h index c7972db5da1..dc14e19bcc8 100644 --- a/Libraries/LibWebView/Application.h +++ b/Libraries/LibWebView/Application.h @@ -97,6 +97,9 @@ private: 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; + virtual void listen_for_console_messages(DevTools::TabDescription const&, OnConsoleMessageAvailable, OnReceivedConsoleMessages) const override; + virtual void stop_listening_for_console_messages(DevTools::TabDescription const&) const override; + virtual void request_console_messages(DevTools::TabDescription const&, i32) const override; static Application* s_the; diff --git a/Libraries/LibWebView/CMakeLists.txt b/Libraries/LibWebView/CMakeLists.txt index edab69343fa..4e7773c08a6 100644 --- a/Libraries/LibWebView/CMakeLists.txt +++ b/Libraries/LibWebView/CMakeLists.txt @@ -4,6 +4,7 @@ set(SOURCES Application.cpp Attribute.cpp ChromeProcess.cpp + ConsoleOutput.cpp CookieJar.cpp Database.cpp HelperProcess.cpp diff --git a/Libraries/LibWebView/ConsoleOutput.cpp b/Libraries/LibWebView/ConsoleOutput.cpp new file mode 100644 index 00000000000..1bdbe9f7131 --- /dev/null +++ b/Libraries/LibWebView/ConsoleOutput.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025, Tim Flynn + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +template<> +ErrorOr IPC::encode(Encoder& encoder, WebView::ConsoleOutput const& console_output) +{ + TRY(encoder.encode(console_output.level)); + TRY(encoder.encode(console_output.timestamp)); + TRY(encoder.encode(console_output.arguments)); + + return {}; +} + +template<> +ErrorOr IPC::decode(Decoder& decoder) +{ + auto level = TRY(decoder.decode()); + auto timestamp = TRY(decoder.decode()); + auto arguments = TRY(decoder.decode>()); + + return WebView::ConsoleOutput { level, timestamp, move(arguments) }; +} diff --git a/Libraries/LibWebView/ConsoleOutput.h b/Libraries/LibWebView/ConsoleOutput.h index bba5d30e60f..28d8b0d6a09 100644 --- a/Libraries/LibWebView/ConsoleOutput.h +++ b/Libraries/LibWebView/ConsoleOutput.h @@ -9,6 +9,7 @@ #include #include #include +#include #include namespace WebView { @@ -20,3 +21,13 @@ struct ConsoleOutput { }; } + +namespace IPC { + +template<> +ErrorOr encode(Encoder&, WebView::ConsoleOutput const&); + +template<> +ErrorOr decode(Decoder&); + +} diff --git a/Libraries/LibWebView/ViewImplementation.h b/Libraries/LibWebView/ViewImplementation.h index 831189894c2..2c3b6c1d32b 100644 --- a/Libraries/LibWebView/ViewImplementation.h +++ b/Libraries/LibWebView/ViewImplementation.h @@ -218,6 +218,7 @@ public: Function on_received_js_console_result; Function on_console_message_available; Function const& message_types, Vector const& messages)> on_received_styled_console_messages; + Function)> on_received_unstyled_console_messages; Function on_resource_status_change; Function on_restore_window; Function on_reposition_window; diff --git a/Libraries/LibWebView/WebContentClient.cpp b/Libraries/LibWebView/WebContentClient.cpp index 0ae57f351ac..d94842b5f0b 100644 --- a/Libraries/LibWebView/WebContentClient.cpp +++ b/Libraries/LibWebView/WebContentClient.cpp @@ -385,6 +385,14 @@ void WebContentClient::did_get_styled_js_console_messages(u64 page_id, i32 start } } +void WebContentClient::did_get_unstyled_js_console_messages(u64 page_id, i32 start_index, Vector const& console_output) +{ + if (auto view = view_for_page_id(page_id); view.has_value()) { + if (view->on_received_unstyled_console_messages) + view->on_received_unstyled_console_messages(start_index, move(const_cast&>(console_output))); + } +} + void WebContentClient::did_request_alert(u64 page_id, String const& message) { 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 5f8266ff241..3dfb0d2dc9a 100644 --- a/Libraries/LibWebView/WebContentClient.h +++ b/Libraries/LibWebView/WebContentClient.h @@ -82,6 +82,7 @@ private: 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_styled_js_console_messages(u64 page_id, i32 start_index, Vector const& message_types, Vector const& messages) override; + virtual void did_get_unstyled_js_console_messages(u64 page_id, i32 start_index, Vector const&) override; virtual void did_change_favicon(u64 page_id, Gfx::ShareableBitmap const&) override; virtual void did_request_alert(u64 page_id, String const&) override; virtual void did_request_confirm(u64 page_id, String const&) override; diff --git a/Services/WebContent/DevToolsConsoleClient.cpp b/Services/WebContent/DevToolsConsoleClient.cpp index 7bf1bf9c7e5..99327e654a9 100644 --- a/Services/WebContent/DevToolsConsoleClient.cpp +++ b/Services/WebContent/DevToolsConsoleClient.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include @@ -106,14 +107,39 @@ void DevToolsConsoleClient::report_exception(JS::Error const& exception, bool in void DevToolsConsoleClient::send_messages(i32 start_index) { - (void)start_index; + if (m_console_output.size() - start_index < 1) { + // When the console is first created, it requests any messages that happened before then, by requesting with + // start_index=0. If we don't have any messages at all, that is still a valid request, and we can just ignore it. + if (start_index != 0) + m_client->console_peer_did_misbehave("Requested non-existent console message index"); + return; + } + + Vector messages { m_console_output.span().slice(start_index) }; + m_client->did_get_unstyled_js_console_messages(start_index, move(messages)); } // 2.3. Printer(logLevel, args[, options]), https://console.spec.whatwg.org/#printer JS::ThrowCompletionOr DevToolsConsoleClient::printer(JS::Console::LogLevel log_level, PrinterArguments arguments) { - (void)log_level; - (void)arguments; + // FIXME: Implement these. + if (first_is_one_of(log_level, JS::Console::LogLevel::Table, JS::Console::LogLevel::Trace, JS::Console::LogLevel::Group, JS::Console::LogLevel::GroupCollapsed)) + return JS::js_undefined(); + + auto const& argument_values = arguments.get>(); + + auto output = TRY(generically_format_values(argument_values)); + m_console->output_debug_message(log_level, output); + + Vector serialized_arguments; + serialized_arguments.ensure_capacity(argument_values.size()); + + for (auto value : argument_values) + serialized_arguments.unchecked_append(serialize_js_value(m_console->realm(), value)); + + m_console_output.empend(log_level, UnixDateTime::now(), move(serialized_arguments)); + m_client->did_output_js_console_message(m_console_output.size() - 1); + return JS::js_undefined(); } diff --git a/Services/WebContent/DevToolsConsoleClient.h b/Services/WebContent/DevToolsConsoleClient.h index 59e87bd574e..fdc7d0bd0f3 100644 --- a/Services/WebContent/DevToolsConsoleClient.h +++ b/Services/WebContent/DevToolsConsoleClient.h @@ -6,9 +6,12 @@ #pragma once +#include +#include #include #include #include +#include #include #include @@ -32,6 +35,8 @@ private: virtual void send_messages(i32 start_index) override; virtual JS::ThrowCompletionOr printer(JS::Console::LogLevel, PrinterArguments) override; + + Vector m_console_output; }; } diff --git a/Services/WebContent/PageClient.cpp b/Services/WebContent/PageClient.cpp index d9cfe7a0b89..e3006f80e3f 100644 --- a/Services/WebContent/PageClient.cpp +++ b/Services/WebContent/PageClient.cpp @@ -810,6 +810,11 @@ void PageClient::did_get_styled_js_console_messages(i32 start_index, Vector console_output) +{ + client().async_did_get_unstyled_js_console_messages(m_id, start_index, move(console_output)); +} + static void gather_style_sheets(Vector& results, Web::CSS::CSSStyleSheet& sheet) { Web::CSS::StyleSheetIdentifier identifier {}; diff --git a/Services/WebContent/PageClient.h b/Services/WebContent/PageClient.h index c099b940242..689db3bedcb 100644 --- a/Services/WebContent/PageClient.h +++ b/Services/WebContent/PageClient.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -91,6 +92,7 @@ public: void did_output_js_console_message(i32 message_index); void console_peer_did_misbehave(char const* reason); void did_get_styled_js_console_messages(i32 start_index, Vector message_types, Vector messages); + void did_get_unstyled_js_console_messages(i32 start_index, Vector console_output); Vector list_style_sheets() const; diff --git a/Services/WebContent/WebContentClient.ipc b/Services/WebContent/WebContentClient.ipc index dd200db4c05..3e315bd2fee 100644 --- a/Services/WebContent/WebContentClient.ipc +++ b/Services/WebContent/WebContentClient.ipc @@ -16,8 +16,9 @@ #include #include #include -#include +#include #include +#include endpoint WebContentClient { @@ -95,6 +96,7 @@ endpoint WebContentClient did_execute_js_console_input(u64 page_id, JsonValue result) =| did_output_js_console_message(u64 page_id, i32 message_index) =| did_get_styled_js_console_messages(u64 page_id, i32 start_index, Vector message_types, Vector messages) =| + did_get_unstyled_js_console_messages(u64 page_id, i32 start_index, Vector console_output) =| did_finish_text_test(u64 page_id, String text) =| did_set_test_timeout(u64 page_id, double milliseconds) =|