Explorar o código

LibWebView+WebContent: Add APIs to manipulate DOM nodes

This adds APIs to allow Ispector clients to:
* Change a DOM text or comment node's text data.
* Add, replace, or remove a DOM element's attribute.
* Change a DOM element's tag.
Timothy Flynn hai 1 ano
pai
achega
4cfeb41c4b

+ 1 - 0
Meta/gn/secondary/Userland/Libraries/LibWebView/BUILD.gn

@@ -116,6 +116,7 @@ shared_library("LibWebView") {
     "//Userland/Libraries/LibWeb",
   ]
   sources = [
+    "Attribute.cpp",
     "CookieJar.cpp",
     "Database.cpp",
     "History.cpp",

+ 26 - 0
Userland/Libraries/LibWebView/Attribute.cpp

@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibIPC/Decoder.h>
+#include <LibIPC/Encoder.h>
+#include <LibWebView/Attribute.h>
+
+template<>
+ErrorOr<void> IPC::encode(Encoder& encoder, WebView::Attribute const& attribute)
+{
+    TRY(encoder.encode(attribute.name));
+    TRY(encoder.encode(attribute.value));
+    return {};
+}
+
+template<>
+ErrorOr<WebView::Attribute> IPC::decode(Decoder& decoder)
+{
+    auto name = TRY(decoder.decode<String>());
+    auto value = TRY(decoder.decode<String>());
+
+    return WebView::Attribute { move(name), move(value) };
+}

+ 29 - 0
Userland/Libraries/LibWebView/Attribute.h

@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/String.h>
+#include <LibIPC/Forward.h>
+
+namespace WebView {
+
+struct Attribute {
+    String name;
+    String value;
+};
+
+}
+
+namespace IPC {
+
+template<>
+ErrorOr<void> encode(Encoder&, WebView::Attribute const&);
+
+template<>
+ErrorOr<WebView::Attribute> decode(Decoder&);
+
+}

+ 1 - 0
Userland/Libraries/LibWebView/CMakeLists.txt

@@ -1,6 +1,7 @@
 include(${SerenityOS_SOURCE_DIR}/Meta/CMake/public_suffix.cmake)
 
 set(SOURCES
+    Attribute.cpp
     CookieJar.cpp
     Database.cpp
     History.cpp

+ 1 - 0
Userland/Libraries/LibWebView/Forward.h

@@ -18,6 +18,7 @@ class OutOfProcessWebView;
 class ViewImplementation;
 class WebContentClient;
 
+struct Attribute;
 struct CookieStorageKey;
 struct SearchEngine;
 

+ 15 - 0
Userland/Libraries/LibWebView/ViewImplementation.cpp

@@ -181,6 +181,21 @@ i32 ViewImplementation::get_hovered_node_id()
     return client().get_hovered_node_id();
 }
 
+void ViewImplementation::set_dom_node_text(i32 node_id, String text)
+{
+    client().async_set_dom_node_text(node_id, move(text));
+}
+
+Optional<i32> ViewImplementation::set_dom_node_tag(i32 node_id, String name)
+{
+    return client().set_dom_node_tag(node_id, move(name));
+}
+
+void ViewImplementation::replace_dom_node_attribute(i32 node_id, String name, Vector<Attribute> replacement_attributes)
+{
+    client().async_replace_dom_node_attribute(node_id, move(name), move(replacement_attributes));
+}
+
 void ViewImplementation::debug_request(DeprecatedString const& request, DeprecatedString const& argument)
 {
     client().async_debug_request(request, argument);

+ 4 - 0
Userland/Libraries/LibWebView/ViewImplementation.h

@@ -63,6 +63,10 @@ public:
     void clear_inspected_dom_node();
     i32 get_hovered_node_id();
 
+    void set_dom_node_text(i32 node_id, String text);
+    Optional<i32> set_dom_node_tag(i32 node_id, String name);
+    void replace_dom_node_attribute(i32 node_id, String name, Vector<Attribute> replacement_attributes);
+
     void debug_request(DeprecatedString const& request, DeprecatedString const& argument = {});
 
     void run_javascript(StringView);

+ 50 - 0
Userland/Services/WebContent/ConnectionFromClient.cpp

@@ -22,7 +22,11 @@
 #include <LibWeb/ARIA/RoleType.h>
 #include <LibWeb/Bindings/MainThreadVM.h>
 #include <LibWeb/CSS/StyleComputer.h>
+#include <LibWeb/DOM/Attr.h>
+#include <LibWeb/DOM/CharacterData.h>
 #include <LibWeb/DOM/Document.h>
+#include <LibWeb/DOM/Element.h>
+#include <LibWeb/DOM/ElementFactory.h>
 #include <LibWeb/Dump.h>
 #include <LibWeb/HTML/BrowsingContext.h>
 #include <LibWeb/HTML/Scripting/ClassicScript.h>
@@ -37,6 +41,7 @@
 #include <LibWeb/Painting/ViewportPaintable.h>
 #include <LibWeb/PermissionsPolicy/AutoplayAllowlist.h>
 #include <LibWeb/Platform/EventLoopPlugin.h>
+#include <LibWebView/Attribute.h>
 #include <WebContent/ConnectionFromClient.h>
 #include <WebContent/PageClient.h>
 #include <WebContent/PageHost.h>
@@ -649,6 +654,51 @@ Messages::WebContentServer::GetHoveredNodeIdResponse ConnectionFromClient::get_h
     return (i32)0;
 }
 
+void ConnectionFromClient::set_dom_node_text(i32 node_id, String const& text)
+{
+    auto* dom_node = Web::DOM::Node::from_unique_id(node_id);
+    if (!dom_node || (!dom_node->is_text() && !dom_node->is_comment()))
+        return;
+
+    auto& character_data = static_cast<Web::DOM::CharacterData&>(*dom_node);
+    character_data.set_data(text);
+}
+
+Messages::WebContentServer::SetDomNodeTagResponse ConnectionFromClient::set_dom_node_tag(i32 node_id, String const& name)
+{
+    auto* dom_node = Web::DOM::Node::from_unique_id(node_id);
+    if (!dom_node || !dom_node->is_element() || !dom_node->parent())
+        return OptionalNone {};
+
+    auto& element = static_cast<Web::DOM::Element&>(*dom_node);
+    auto new_element = Web::DOM::create_element(element.document(), name, element.namespace_uri(), element.prefix(), element.is_value()).release_value_but_fixme_should_propagate_errors();
+
+    element.for_each_attribute([&](auto const& attribute) {
+        new_element->set_attribute_value(attribute.local_name(), attribute.value().to_deprecated_string(), attribute.prefix(), attribute.namespace_uri());
+    });
+
+    while (auto* child_node = element.first_child()) {
+        MUST(element.remove_child(*child_node));
+        MUST(new_element->append_child(*child_node));
+    }
+
+    element.parent()->replace_child(*new_element, element).release_value_but_fixme_should_propagate_errors();
+    return new_element->unique_id();
+}
+
+void ConnectionFromClient::replace_dom_node_attribute(i32 node_id, String const& name, Vector<WebView::Attribute> const& replacement_attributes)
+{
+    auto* dom_node = Web::DOM::Node::from_unique_id(node_id);
+    if (!dom_node || !dom_node->is_element())
+        return;
+
+    auto& element = static_cast<Web::DOM::Element&>(*dom_node);
+    element.remove_attribute(name);
+
+    for (auto const& attribute : replacement_attributes)
+        element.set_attribute(attribute.name, attribute.value).release_value_but_fixme_should_propagate_errors();
+}
+
 void ConnectionFromClient::initialize_js_console(Badge<PageClient>, Web::DOM::Document& document)
 {
     auto& realm = document.realm();

+ 6 - 0
Userland/Services/WebContent/ConnectionFromClient.h

@@ -17,6 +17,7 @@
 #include <LibWeb/Forward.h>
 #include <LibWeb/Loader/FileRequest.h>
 #include <LibWeb/Platform/Timer.h>
+#include <LibWebView/Forward.h>
 #include <WebContent/Forward.h>
 #include <WebContent/WebContentClientEndpoint.h>
 #include <WebContent/WebContentConsoleClient.h>
@@ -74,6 +75,11 @@ private:
     virtual Messages::WebContentServer::InspectDomNodeResponse inspect_dom_node(i32 node_id, Optional<Web::CSS::Selector::PseudoElement> const& pseudo_element) override;
     virtual void inspect_accessibility_tree() override;
     virtual Messages::WebContentServer::GetHoveredNodeIdResponse get_hovered_node_id() override;
+
+    virtual void set_dom_node_text(i32 node_id, String const& text) override;
+    virtual Messages::WebContentServer::SetDomNodeTagResponse set_dom_node_tag(i32 node_id, String const& name) override;
+    virtual void replace_dom_node_attribute(i32 node_id, String const& name, Vector<WebView::Attribute> const& replacement_attributes) override;
+
     virtual Messages::WebContentServer::DumpLayoutTreeResponse dump_layout_tree() override;
     virtual Messages::WebContentServer::DumpPaintTreeResponse dump_paint_tree() override;
     virtual Messages::WebContentServer::DumpTextResponse dump_text() override;

+ 5 - 0
Userland/Services/WebContent/WebContentServer.ipc

@@ -6,6 +6,7 @@
 #include <LibWeb/CSS/PreferredColorScheme.h>
 #include <LibWeb/CSS/Selector.h>
 #include <LibWeb/WebDriver/ExecuteScript.h>
+#include <LibWebView/Attribute.h>
 
 endpoint WebContentServer
 {
@@ -45,6 +46,10 @@ endpoint WebContentServer
     js_console_input(DeprecatedString js_source) =|
     js_console_request_messages(i32 start_index) =|
 
+    set_dom_node_text(i32 node_id, String text) =|
+    set_dom_node_tag(i32 node_id, String name) => (Optional<i32> node_id)
+    replace_dom_node_attribute(i32 node_id, String name, Vector<WebView::Attribute> replacement_attributes) =|
+
     take_document_screenshot() => (Gfx::ShareableBitmap data)
 
     run_javascript(DeprecatedString js_source) =|