From ffdc2d8add1c8b156899f736293751e3044e56d7 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Thu, 23 Nov 2023 12:22:23 -0500 Subject: [PATCH] LibWeb+LibWebView+WebContent: Add an Inspector IDL object to the Window This is an internal object that must be explicitly enabled by the chrome before it is added to the Window. The Inspector object will be used by a special WebView that will replace all chrome-specific inspector windows. The IDL defines methods that this WebView will need to inform the chrome of various events, such as the user clicking a DOM node. --- .../Libraries/LibWeb/Internals/BUILD.gn | 5 +- .../Userland/Libraries/LibWeb/idl_files.gni | 1 + Userland/Libraries/LibWeb/CMakeLists.txt | 1 + Userland/Libraries/LibWeb/Forward.h | 1 + Userland/Libraries/LibWeb/HTML/Window.cpp | 9 ++++ Userland/Libraries/LibWeb/HTML/Window.h | 1 + .../Libraries/LibWeb/Internals/Inspector.cpp | 50 +++++++++++++++++++ .../Libraries/LibWeb/Internals/Inspector.h | 30 +++++++++++ .../Libraries/LibWeb/Internals/Inspector.idl | 6 +++ Userland/Libraries/LibWeb/Page/Page.h | 4 ++ Userland/Libraries/LibWeb/idl_files.cmake | 1 + .../LibWebView/ViewImplementation.cpp | 5 ++ .../Libraries/LibWebView/ViewImplementation.h | 4 ++ .../Libraries/LibWebView/WebContentClient.cpp | 12 +++++ .../Libraries/LibWebView/WebContentClient.h | 2 + .../WebContent/ConnectionFromClient.cpp | 5 ++ .../WebContent/ConnectionFromClient.h | 2 + Userland/Services/WebContent/PageHost.cpp | 10 ++++ Userland/Services/WebContent/PageHost.h | 2 + .../Services/WebContent/WebContentClient.ipc | 4 ++ .../Services/WebContent/WebContentServer.ipc | 2 + 21 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 Userland/Libraries/LibWeb/Internals/Inspector.cpp create mode 100644 Userland/Libraries/LibWeb/Internals/Inspector.h create mode 100644 Userland/Libraries/LibWeb/Internals/Inspector.idl diff --git a/Meta/gn/secondary/Userland/Libraries/LibWeb/Internals/BUILD.gn b/Meta/gn/secondary/Userland/Libraries/LibWeb/Internals/BUILD.gn index b68609ef1f6..c97eb62c99a 100644 --- a/Meta/gn/secondary/Userland/Libraries/LibWeb/Internals/BUILD.gn +++ b/Meta/gn/secondary/Userland/Libraries/LibWeb/Internals/BUILD.gn @@ -1,5 +1,8 @@ source_set("Internals") { configs += [ "//Userland/Libraries/LibWeb:configs" ] deps = [ "//Userland/Libraries/LibWeb:all_generated" ] - sources = [ "Internals.cpp" ] + sources = [ + "Inspector.cpp", + "Internals.cpp", + ] } diff --git a/Meta/gn/secondary/Userland/Libraries/LibWeb/idl_files.gni b/Meta/gn/secondary/Userland/Libraries/LibWeb/idl_files.gni index ca189489076..6ca47050da1 100644 --- a/Meta/gn/secondary/Userland/Libraries/LibWeb/idl_files.gni +++ b/Meta/gn/secondary/Userland/Libraries/LibWeb/idl_files.gni @@ -216,6 +216,7 @@ standard_idl_files = [ "//Userland/Libraries/LibWeb/HTML/WorkerLocation.idl", "//Userland/Libraries/LibWeb/HTML/WorkerNavigator.idl", "//Userland/Libraries/LibWeb/HighResolutionTime/Performance.idl", + "//Userland/Libraries/LibWeb/Internals/Inspector.idl", "//Userland/Libraries/LibWeb/Internals/Internals.idl", "//Userland/Libraries/LibWeb/IntersectionObserver/IntersectionObserver.idl", "//Userland/Libraries/LibWeb/IntersectionObserver/IntersectionObserverEntry.idl", diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 70cbf5dedad..94c64697dd1 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -415,6 +415,7 @@ set(SOURCES Infra/ByteSequences.cpp Infra/JSON.cpp Infra/Strings.cpp + Internals/Inspector.cpp Internals/Internals.cpp IntersectionObserver/IntersectionObserver.cpp IntersectionObserver/IntersectionObserverEntry.cpp diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index 9f75d878672..688b7d43652 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -482,6 +482,7 @@ class Performance; } namespace Web::Internals { +class Inspector; class Internals; } diff --git a/Userland/Libraries/LibWeb/HTML/Window.cpp b/Userland/Libraries/LibWeb/HTML/Window.cpp index 49c34b89d42..0b368c0ea65 100644 --- a/Userland/Libraries/LibWeb/HTML/Window.cpp +++ b/Userland/Libraries/LibWeb/HTML/Window.cpp @@ -60,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -781,8 +782,14 @@ WebIDL::ExceptionOr> Window::byte_length_ return JS::NonnullGCPtr { *m_byte_length_queuing_strategy_size_function }; } +static bool s_inspector_object_exposed = false; static bool s_internals_object_exposed = false; +void Window::set_inspector_object_exposed(bool exposed) +{ + s_inspector_object_exposed = exposed; +} + void Window::set_internals_object_exposed(bool exposed) { s_internals_object_exposed = exposed; @@ -798,6 +805,8 @@ WebIDL::ExceptionOr Window::initialize_web_interfaces(Badge(realm, realm), JS::default_attributes); if (s_internals_object_exposed) define_direct_property("internals", heap().allocate(realm, realm), JS::default_attributes); diff --git a/Userland/Libraries/LibWeb/HTML/Window.h b/Userland/Libraries/LibWeb/HTML/Window.h index c386af80f44..ddf20b0c125 100644 --- a/Userland/Libraries/LibWeb/HTML/Window.h +++ b/Userland/Libraries/LibWeb/HTML/Window.h @@ -196,6 +196,7 @@ public: HighResolutionTime::DOMHighResTimeStamp get_last_activation_timestamp() const { return m_last_activation_timestamp; } void set_last_activation_timestamp(HighResolutionTime::DOMHighResTimeStamp timestamp) { m_last_activation_timestamp = timestamp; } + static void set_inspector_object_exposed(bool); static void set_internals_object_exposed(bool); [[nodiscard]] OrderedHashMap> document_tree_child_navigable_target_name_property_set(); diff --git a/Userland/Libraries/LibWeb/Internals/Inspector.cpp b/Userland/Libraries/LibWeb/Internals/Inspector.cpp new file mode 100644 index 00000000000..12783c3e9f2 --- /dev/null +++ b/Userland/Libraries/LibWeb/Internals/Inspector.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2023, Tim Flynn + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Web::Internals { + +JS_DEFINE_ALLOCATOR(Inspector); + +Inspector::Inspector(JS::Realm& realm) + : Bindings::PlatformObject(realm) +{ +} + +Inspector::~Inspector() = default; + +void Inspector::initialize(JS::Realm& realm) +{ + Base::initialize(realm); + Object::set_prototype(&Bindings::ensure_web_prototype(realm, "Inspector")); +} + +void Inspector::inspector_loaded() +{ + if (auto* page = global_object().browsing_context()->page()) + page->client().inspector_did_load(); +} + +void Inspector::inspect_dom_node(i32 node_id, Optional const& pseudo_element) +{ + if (auto* page = global_object().browsing_context()->page()) { + page->client().inspector_did_select_dom_node(node_id, pseudo_element.map([](auto value) { + VERIFY(value < to_underlying(Web::CSS::Selector::PseudoElement::PseudoElementCount)); + return static_cast(value); + })); + } +} + +} diff --git a/Userland/Libraries/LibWeb/Internals/Inspector.h b/Userland/Libraries/LibWeb/Internals/Inspector.h new file mode 100644 index 00000000000..86d053c7ed3 --- /dev/null +++ b/Userland/Libraries/LibWeb/Internals/Inspector.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023, Tim Flynn + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace Web::Internals { + +class Inspector final : public Bindings::PlatformObject { + WEB_PLATFORM_OBJECT(Inspector, Bindings::PlatformObject); + JS_DECLARE_ALLOCATOR(Inspector); + +public: + virtual ~Inspector() override; + + void inspector_loaded(); + void inspect_dom_node(i32 node_id, Optional const& pseudo_element); + +private: + explicit Inspector(JS::Realm&); + + virtual void initialize(JS::Realm&) override; +}; + +} diff --git a/Userland/Libraries/LibWeb/Internals/Inspector.idl b/Userland/Libraries/LibWeb/Internals/Inspector.idl new file mode 100644 index 00000000000..e5149874566 --- /dev/null +++ b/Userland/Libraries/LibWeb/Internals/Inspector.idl @@ -0,0 +1,6 @@ +[Exposed=Nobody] interface Inspector { + + undefined inspectorLoaded(); + undefined inspectDOMNode(long nodeID, optional long pseudoElement); + +}; diff --git a/Userland/Libraries/LibWeb/Page/Page.h b/Userland/Libraries/LibWeb/Page/Page.h index a68c7a5c778..003bf234ebd 100644 --- a/Userland/Libraries/LibWeb/Page/Page.h +++ b/Userland/Libraries/LibWeb/Page/Page.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -260,6 +261,9 @@ public: virtual void page_did_insert_clipboard_entry([[maybe_unused]] String data, [[maybe_unused]] String presentation_style, [[maybe_unused]] String mime_type) { } + virtual void inspector_did_load() { } + virtual void inspector_did_select_dom_node([[maybe_unused]] i32 node_id, [[maybe_unused]] Optional const& pseudo_element) { } + protected: virtual ~PageClient() = default; }; diff --git a/Userland/Libraries/LibWeb/idl_files.cmake b/Userland/Libraries/LibWeb/idl_files.cmake index 87b044973be..1cf11d88ef4 100644 --- a/Userland/Libraries/LibWeb/idl_files.cmake +++ b/Userland/Libraries/LibWeb/idl_files.cmake @@ -202,6 +202,7 @@ libweb_js_bindings(HTML/WorkerGlobalScope) libweb_js_bindings(HTML/WorkerLocation) libweb_js_bindings(HTML/WorkerNavigator) libweb_js_bindings(HighResolutionTime/Performance) +libweb_js_bindings(Internals/Inspector) libweb_js_bindings(Internals/Internals) libweb_js_bindings(IntersectionObserver/IntersectionObserver) libweb_js_bindings(IntersectionObserver/IntersectionObserverEntry) diff --git a/Userland/Libraries/LibWebView/ViewImplementation.cpp b/Userland/Libraries/LibWebView/ViewImplementation.cpp index 26cd98a4585..2df40f3af8f 100644 --- a/Userland/Libraries/LibWebView/ViewImplementation.cpp +++ b/Userland/Libraries/LibWebView/ViewImplementation.cpp @@ -383,4 +383,9 @@ void ViewImplementation::use_native_user_style_sheet() set_user_style_sheet(MUST(String::from_utf8(native_stylesheet_source))); } +void ViewImplementation::enable_inspector_prototype() +{ + client().async_enable_inspector_prototype(); +} + } diff --git a/Userland/Libraries/LibWebView/ViewImplementation.h b/Userland/Libraries/LibWebView/ViewImplementation.h index 6c8bb14d52e..5bdabd99cb8 100644 --- a/Userland/Libraries/LibWebView/ViewImplementation.h +++ b/Userland/Libraries/LibWebView/ViewImplementation.h @@ -106,6 +106,8 @@ public: // native GUI widgets as possible. void use_native_user_style_sheet(); + void enable_inspector_prototype(); + Function on_did_layout; Function on_ready_to_paint; Function on_new_tab; @@ -161,6 +163,8 @@ public: Function on_text_test_finish; Function on_theme_color_change; Function on_insert_clipboard_entry; + Function on_inspector_loaded; + Function const&)> on_inspector_selected_dom_node; virtual Gfx::IntRect viewport_rect() const = 0; virtual Gfx::IntPoint to_content_position(Gfx::IntPoint widget_position) const = 0; diff --git a/Userland/Libraries/LibWebView/WebContentClient.cpp b/Userland/Libraries/LibWebView/WebContentClient.cpp index 1033fd36972..5a1ece2f392 100644 --- a/Userland/Libraries/LibWebView/WebContentClient.cpp +++ b/Userland/Libraries/LibWebView/WebContentClient.cpp @@ -402,4 +402,16 @@ void WebContentClient::did_insert_clipboard_entry(String const& data, String con m_view.on_insert_clipboard_entry(data, presentation_style, mime_type); } +void WebContentClient::inspector_did_load() +{ + if (m_view.on_inspector_loaded) + m_view.on_inspector_loaded(); +} + +void WebContentClient::inspector_did_select_dom_node(i32 node_id, Optional const& pseudo_element) +{ + if (m_view.on_inspector_selected_dom_node) + m_view.on_inspector_selected_dom_node(node_id, pseudo_element); +} + } diff --git a/Userland/Libraries/LibWebView/WebContentClient.h b/Userland/Libraries/LibWebView/WebContentClient.h index 41e21e563a7..194d1682f89 100644 --- a/Userland/Libraries/LibWebView/WebContentClient.h +++ b/Userland/Libraries/LibWebView/WebContentClient.h @@ -86,6 +86,8 @@ private: virtual void did_finish_text_test() override; virtual void did_change_theme_color(Gfx::Color color) override; virtual void did_insert_clipboard_entry(String const& data, String const& presentation_style, String const& mime_type) override; + virtual void inspector_did_load() override; + virtual void inspector_did_select_dom_node(i32 node_id, Optional const& pseudo_element) override; ViewImplementation& m_view; }; diff --git a/Userland/Services/WebContent/ConnectionFromClient.cpp b/Userland/Services/WebContent/ConnectionFromClient.cpp index 3af096a0680..0e8ec1a8756 100644 --- a/Userland/Services/WebContent/ConnectionFromClient.cpp +++ b/Userland/Services/WebContent/ConnectionFromClient.cpp @@ -929,4 +929,9 @@ void ConnectionFromClient::inspect_accessibility_tree() } } +void ConnectionFromClient::enable_inspector_prototype() +{ + Web::HTML::Window::set_inspector_object_exposed(true); +} + } diff --git a/Userland/Services/WebContent/ConnectionFromClient.h b/Userland/Services/WebContent/ConnectionFromClient.h index b989f5c8818..d3aa1981a05 100644 --- a/Userland/Services/WebContent/ConnectionFromClient.h +++ b/Userland/Services/WebContent/ConnectionFromClient.h @@ -106,6 +106,8 @@ private: virtual void set_user_style(String const&) override; + virtual void enable_inspector_prototype() override; + virtual Messages::WebContentServer::TakeDocumentScreenshotResponse take_document_screenshot() override; virtual Messages::WebContentServer::GetLocalStorageEntriesResponse get_local_storage_entries() override; diff --git a/Userland/Services/WebContent/PageHost.cpp b/Userland/Services/WebContent/PageHost.cpp index d8078a71b48..e58bd402e2e 100644 --- a/Userland/Services/WebContent/PageHost.cpp +++ b/Userland/Services/WebContent/PageHost.cpp @@ -503,4 +503,14 @@ void PageHost::page_did_insert_clipboard_entry(String data, String presentation_ m_client.async_did_insert_clipboard_entry(move(data), move(presentation_style), move(mime_type)); } +void PageHost::inspector_did_load() +{ + m_client.async_inspector_did_load(); +} + +void PageHost::inspector_did_select_dom_node(i32 node_id, Optional const& pseudo_element) +{ + m_client.async_inspector_did_select_dom_node(node_id, pseudo_element); +} + } diff --git a/Userland/Services/WebContent/PageHost.h b/Userland/Services/WebContent/PageHost.h index b47ee99ab56..9425f473e6b 100644 --- a/Userland/Services/WebContent/PageHost.h +++ b/Userland/Services/WebContent/PageHost.h @@ -121,6 +121,8 @@ private: virtual void page_did_finish_text_test() override; virtual void page_did_change_theme_color(Gfx::Color color) override; virtual void page_did_insert_clipboard_entry(String data, String presentation_style, String mime_type) override; + virtual void inspector_did_load() override; + virtual void inspector_did_select_dom_node(i32 node_id, Optional const& pseudo_element) override; explicit PageHost(ConnectionFromClient&); diff --git a/Userland/Services/WebContent/WebContentClient.ipc b/Userland/Services/WebContent/WebContentClient.ipc index 1f44c60ad3b..c35fc5ef068 100644 --- a/Userland/Services/WebContent/WebContentClient.ipc +++ b/Userland/Services/WebContent/WebContentClient.ipc @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -69,4 +70,7 @@ endpoint WebContentClient did_finish_text_test() =| + inspector_did_load() =| + inspector_did_select_dom_node(i32 node_id, Optional pseudo_element) =| + } diff --git a/Userland/Services/WebContent/WebContentServer.ipc b/Userland/Services/WebContent/WebContentServer.ipc index 72a23fbb38c..bee54d22df4 100644 --- a/Userland/Services/WebContent/WebContentServer.ipc +++ b/Userland/Services/WebContent/WebContentServer.ipc @@ -86,4 +86,6 @@ endpoint WebContentServer toggle_media_controls_state() =| set_user_style(String source) =| + + enable_inspector_prototype() =| }