LibWebView+WebContent: Make the DOM node inspection IPC async

This commit is contained in:
Timothy Flynn 2023-12-30 09:30:27 -05:00 committed by Andreas Kling
parent 4c3bff264e
commit 760ba5932b
Notes: sideshowbarker 2024-07-18 00:41:35 +09:00
9 changed files with 80 additions and 53 deletions

View file

@ -49,6 +49,32 @@ InspectorClient::InspectorClient(ViewImplementation& content_web_view, ViewImple
select_default_node(); select_default_node();
}; };
m_content_web_view.on_received_dom_node_properties = [this](auto const& inspected_node_properties) {
StringBuilder builder;
// FIXME: Support box model metrics and ARIA properties.
auto generate_property_script = [&](auto const& computed_style, auto const& resolved_style, auto const& custom_properties) {
builder.append("inspector.createPropertyTables(\""sv);
builder.append_escaped_for_json(computed_style);
builder.append("\", \""sv);
builder.append_escaped_for_json(resolved_style);
builder.append("\", \""sv);
builder.append_escaped_for_json(custom_properties);
builder.append("\");"sv);
};
if (inspected_node_properties.has_value()) {
generate_property_script(
inspected_node_properties->computed_style_json,
inspected_node_properties->resolved_style_json,
inspected_node_properties->custom_properties_json);
} else {
generate_property_script("{}"sv, "{}"sv, "{}"sv);
}
m_inspector_web_view.run_javascript(builder.string_view());
};
m_content_web_view.on_received_accessibility_tree = [this](auto const& accessibility_tree) { m_content_web_view.on_received_accessibility_tree = [this](auto const& accessibility_tree) {
auto result = parse_json_tree(accessibility_tree); auto result = parse_json_tree(accessibility_tree);
if (result.is_error()) { if (result.is_error()) {
@ -101,31 +127,7 @@ InspectorClient::InspectorClient(ViewImplementation& content_web_view, ViewImple
}; };
m_inspector_web_view.on_inspector_selected_dom_node = [this](auto node_id, auto const& pseudo_element) { m_inspector_web_view.on_inspector_selected_dom_node = [this](auto node_id, auto const& pseudo_element) {
auto inspected_node_properties = m_content_web_view.inspect_dom_node(node_id, pseudo_element); m_content_web_view.inspect_dom_node(node_id, pseudo_element);
StringBuilder builder;
// FIXME: Support box model metrics and ARIA properties.
auto generate_property_script = [&](auto const& computed_style, auto const& resolved_style, auto const& custom_properties) {
builder.append("inspector.createPropertyTables(\""sv);
builder.append_escaped_for_json(computed_style);
builder.append("\", \""sv);
builder.append_escaped_for_json(resolved_style);
builder.append("\", \""sv);
builder.append_escaped_for_json(custom_properties);
builder.append("\");"sv);
};
if (inspected_node_properties.is_error()) {
generate_property_script("{}"sv, "{}"sv, "{}"sv);
} else {
generate_property_script(
inspected_node_properties.value().computed_style_json,
inspected_node_properties.value().resolved_style_json,
inspected_node_properties.value().custom_properties_json);
}
m_inspector_web_view.run_javascript(builder.string_view());
}; };
m_inspector_web_view.on_inspector_set_dom_node_text = [this](auto node_id, auto const& text) { m_inspector_web_view.on_inspector_set_dom_node_text = [this](auto node_id, auto const& text) {

View file

@ -131,28 +131,19 @@ void ViewImplementation::inspect_dom_tree()
client().async_inspect_dom_tree(); client().async_inspect_dom_tree();
} }
void ViewImplementation::inspect_dom_node(i32 node_id, Optional<Web::CSS::Selector::PseudoElement::Type> pseudo_element)
{
client().async_inspect_dom_node(node_id, move(pseudo_element));
}
void ViewImplementation::inspect_accessibility_tree() void ViewImplementation::inspect_accessibility_tree()
{ {
client().async_inspect_accessibility_tree(); client().async_inspect_accessibility_tree();
} }
ErrorOr<ViewImplementation::DOMNodeProperties> ViewImplementation::inspect_dom_node(i32 node_id, Optional<Web::CSS::Selector::PseudoElement::Type> pseudo_element)
{
auto response = client().inspect_dom_node(node_id, pseudo_element);
if (!response.has_style())
return Error::from_string_view("Inspected node returned no style"sv);
return DOMNodeProperties {
.computed_style_json = TRY(String::from_byte_string(response.take_computed_style())),
.resolved_style_json = TRY(String::from_byte_string(response.take_resolved_style())),
.custom_properties_json = TRY(String::from_byte_string(response.take_custom_properties())),
.node_box_sizing_json = TRY(String::from_byte_string(response.take_node_box_sizing())),
.aria_properties_state_json = TRY(String::from_byte_string(response.take_aria_properties_state())),
};
}
void ViewImplementation::clear_inspected_dom_node() void ViewImplementation::clear_inspected_dom_node()
{ {
client().inspect_dom_node(0, {}); inspect_dom_node(0, {});
} }
i32 ViewImplementation::get_hovered_node_id() i32 ViewImplementation::get_hovered_node_id()

View file

@ -59,8 +59,8 @@ public:
void get_source(); void get_source();
void inspect_dom_tree(); void inspect_dom_tree();
void inspect_dom_node(i32 node_id, Optional<Web::CSS::Selector::PseudoElement::Type> pseudo_element);
void inspect_accessibility_tree(); void inspect_accessibility_tree();
ErrorOr<DOMNodeProperties> inspect_dom_node(i32 node_id, Optional<Web::CSS::Selector::PseudoElement::Type> pseudo_element);
void clear_inspected_dom_node(); void clear_inspected_dom_node();
i32 get_hovered_node_id(); i32 get_hovered_node_id();
@ -141,6 +141,7 @@ public:
Function<void()> on_request_dismiss_dialog; Function<void()> on_request_dismiss_dialog;
Function<void(const AK::URL&, ByteString const&)> on_received_source; Function<void(const AK::URL&, ByteString const&)> on_received_source;
Function<void(ByteString const&)> on_received_dom_tree; Function<void(ByteString const&)> on_received_dom_tree;
Function<void(Optional<DOMNodeProperties>)> on_received_dom_node_properties;
Function<void(ByteString const&)> on_received_accessibility_tree; Function<void(ByteString const&)> on_received_accessibility_tree;
Function<void(i32 message_id)> on_received_console_message; Function<void(i32 message_id)> on_received_console_message;
Function<void(i32 start_index, Vector<ByteString> const& message_types, Vector<ByteString> const& messages)> on_received_console_messages; Function<void(i32 start_index, Vector<ByteString> const& message_types, Vector<ByteString> const& messages)> on_received_console_messages;

View file

@ -187,6 +187,26 @@ void WebContentClient::did_inspect_dom_tree(ByteString const& dom_tree)
m_view.on_received_dom_tree(dom_tree); m_view.on_received_dom_tree(dom_tree);
} }
void WebContentClient::did_inspect_dom_node(bool has_style, ByteString const& computed_style, ByteString const& resolved_style, ByteString const& custom_properties, ByteString const& node_box_sizing, ByteString const& aria_properties_state)
{
if (!m_view.on_received_dom_node_properties)
return;
Optional<ViewImplementation::DOMNodeProperties> properties;
if (has_style) {
properties = ViewImplementation::DOMNodeProperties {
.computed_style_json = MUST(String::from_byte_string(computed_style)),
.resolved_style_json = MUST(String::from_byte_string(resolved_style)),
.custom_properties_json = MUST(String::from_byte_string(custom_properties)),
.node_box_sizing_json = MUST(String::from_byte_string(node_box_sizing)),
.aria_properties_state_json = MUST(String::from_byte_string(aria_properties_state)),
};
}
m_view.on_received_dom_node_properties(move(properties));
}
void WebContentClient::did_inspect_accessibility_tree(ByteString const& accessibility_tree) void WebContentClient::did_inspect_accessibility_tree(ByteString const& accessibility_tree)
{ {
if (m_view.on_received_accessibility_tree) if (m_view.on_received_accessibility_tree)

View file

@ -53,6 +53,7 @@ private:
virtual void did_request_media_context_menu(Gfx::IntPoint, ByteString const&, unsigned, Web::Page::MediaContextMenu const&) override; virtual void did_request_media_context_menu(Gfx::IntPoint, ByteString const&, unsigned, Web::Page::MediaContextMenu const&) override;
virtual void did_get_source(AK::URL const&, ByteString const&) override; virtual void did_get_source(AK::URL const&, ByteString const&) override;
virtual void did_inspect_dom_tree(ByteString const&) override; virtual void did_inspect_dom_tree(ByteString const&) override;
virtual void did_inspect_dom_node(bool has_style, ByteString const& computed_style, ByteString const& resolved_style, ByteString const& custom_properties, ByteString const& node_box_sizing, ByteString const& aria_properties_state) override;
virtual void did_inspect_accessibility_tree(ByteString const&) override; virtual void did_inspect_accessibility_tree(ByteString const&) override;
virtual void did_output_js_console_message(i32 message_index) override; virtual void did_output_js_console_message(i32 message_index) override;
virtual void did_get_js_console_messages(i32 start_index, Vector<ByteString> const& message_types, Vector<ByteString> const& messages) override; virtual void did_get_js_console_messages(i32 start_index, Vector<ByteString> const& message_types, Vector<ByteString> const& messages) override;

View file

@ -474,7 +474,7 @@ void ConnectionFromClient::inspect_dom_tree()
} }
} }
Messages::WebContentServer::InspectDomNodeResponse ConnectionFromClient::inspect_dom_node(i32 node_id, Optional<Web::CSS::Selector::PseudoElement::Type> const& pseudo_element) void ConnectionFromClient::inspect_dom_node(i32 node_id, Optional<Web::CSS::Selector::PseudoElement::Type> const& pseudo_element)
{ {
auto& top_context = page().page().top_level_browsing_context(); auto& top_context = page().page().top_level_browsing_context();
@ -488,15 +488,18 @@ Messages::WebContentServer::InspectDomNodeResponse ConnectionFromClient::inspect
Web::DOM::Node* node = Web::DOM::Node::from_unique_id(node_id); Web::DOM::Node* node = Web::DOM::Node::from_unique_id(node_id);
// Note: Nodes without layout (aka non-visible nodes, don't have style computed) // Note: Nodes without layout (aka non-visible nodes, don't have style computed)
if (!node || !node->layout_node()) { if (!node || !node->layout_node()) {
return { false, "", "", "", "", "" }; async_did_inspect_dom_node(false, {}, {}, {}, {}, {});
return;
} }
node->document().set_inspected_node(node, pseudo_element); node->document().set_inspected_node(node, pseudo_element);
if (node->is_element()) { if (node->is_element()) {
auto& element = verify_cast<Web::DOM::Element>(*node); auto& element = verify_cast<Web::DOM::Element>(*node);
if (!element.computed_css_values()) if (!element.computed_css_values()) {
return { false, "", "", "", "", "" }; async_did_inspect_dom_node(false, {}, {}, {}, {}, {});
return;
}
auto serialize_json = [](Web::CSS::StyleProperties const& properties) -> ByteString { auto serialize_json = [](Web::CSS::StyleProperties const& properties) -> ByteString {
StringBuilder builder; StringBuilder builder;
@ -580,8 +583,10 @@ Messages::WebContentServer::InspectDomNodeResponse ConnectionFromClient::inspect
if (pseudo_element.has_value()) { if (pseudo_element.has_value()) {
auto pseudo_element_node = element.get_pseudo_element_node(pseudo_element.value()); auto pseudo_element_node = element.get_pseudo_element_node(pseudo_element.value());
if (!pseudo_element_node) if (!pseudo_element_node) {
return { false, "", "", "", "", "" }; async_did_inspect_dom_node(false, {}, {}, {}, {}, {});
return;
}
// FIXME: Pseudo-elements only exist as Layout::Nodes, which don't have style information // FIXME: Pseudo-elements only exist as Layout::Nodes, which don't have style information
// in a format we can use. So, we run the StyleComputer again to get the specified // in a format we can use. So, we run the StyleComputer again to get the specified
@ -591,18 +596,22 @@ Messages::WebContentServer::InspectDomNodeResponse ConnectionFromClient::inspect
ByteString resolved_values = "{}"; ByteString resolved_values = "{}";
ByteString custom_properties_json = serialize_custom_properties_json(element, pseudo_element); ByteString custom_properties_json = serialize_custom_properties_json(element, pseudo_element);
ByteString node_box_sizing_json = serialize_node_box_sizing_json(pseudo_element_node.ptr()); ByteString node_box_sizing_json = serialize_node_box_sizing_json(pseudo_element_node.ptr());
return { true, computed_values, resolved_values, custom_properties_json, node_box_sizing_json, "" };
async_did_inspect_dom_node(true, move(computed_values), move(resolved_values), move(custom_properties_json), move(node_box_sizing_json), {});
return;
} }
ByteString computed_values = serialize_json(*element.computed_css_values()); ByteString computed_values = serialize_json(*element.computed_css_values());
ByteString resolved_values_json = serialize_json(element.resolved_css_values()); ByteString resolved_values = serialize_json(element.resolved_css_values());
ByteString custom_properties_json = serialize_custom_properties_json(element, {}); ByteString custom_properties_json = serialize_custom_properties_json(element, {});
ByteString node_box_sizing_json = serialize_node_box_sizing_json(element.layout_node()); ByteString node_box_sizing_json = serialize_node_box_sizing_json(element.layout_node());
ByteString aria_properties_state_json = serialize_aria_properties_state_json(element); ByteString aria_properties_state_json = serialize_aria_properties_state_json(element);
return { true, computed_values, resolved_values_json, custom_properties_json, node_box_sizing_json, aria_properties_state_json };
async_did_inspect_dom_node(true, move(computed_values), move(resolved_values), move(custom_properties_json), move(node_box_sizing_json), move(aria_properties_state_json));
return;
} }
return { false, "", "", "", "", "" }; async_did_inspect_dom_node(false, {}, {}, {}, {}, {});
} }
void ConnectionFromClient::inspect_accessibility_tree() void ConnectionFromClient::inspect_accessibility_tree()

View file

@ -72,7 +72,7 @@ private:
virtual void debug_request(ByteString const&, ByteString const&) override; virtual void debug_request(ByteString const&, ByteString const&) override;
virtual void get_source() override; virtual void get_source() override;
virtual void inspect_dom_tree() override; virtual void inspect_dom_tree() override;
virtual Messages::WebContentServer::InspectDomNodeResponse inspect_dom_node(i32 node_id, Optional<Web::CSS::Selector::PseudoElement::Type> const& pseudo_element) override; virtual void inspect_dom_node(i32 node_id, Optional<Web::CSS::Selector::PseudoElement::Type> const& pseudo_element) override;
virtual void inspect_accessibility_tree() override; virtual void inspect_accessibility_tree() override;
virtual Messages::WebContentServer::GetHoveredNodeIdResponse get_hovered_node_id() override; virtual Messages::WebContentServer::GetHoveredNodeIdResponse get_hovered_node_id() override;

View file

@ -40,8 +40,11 @@ endpoint WebContentClient
did_request_accept_dialog() =| did_request_accept_dialog() =|
did_request_dismiss_dialog() =| did_request_dismiss_dialog() =|
did_get_source(URL url, ByteString source) =| did_get_source(URL url, ByteString source) =|
did_inspect_dom_tree(ByteString dom_tree) =| did_inspect_dom_tree(ByteString dom_tree) =|
did_inspect_dom_node(bool has_style, ByteString computed_style, ByteString resolved_style, ByteString custom_properties, ByteString node_box_sizing, ByteString aria_properties_state) =|
did_inspect_accessibility_tree(ByteString accessibility_tree) =| did_inspect_accessibility_tree(ByteString accessibility_tree) =|
did_change_favicon(Gfx::ShareableBitmap favicon) =| did_change_favicon(Gfx::ShareableBitmap favicon) =|
did_request_all_cookies(URL url) => (Vector<Web::Cookie::Cookie> cookies) did_request_all_cookies(URL url) => (Vector<Web::Cookie::Cookie> cookies)
did_request_named_cookie(URL url, ByteString name) => (Optional<Web::Cookie::Cookie> cookie) did_request_named_cookie(URL url, ByteString name) => (Optional<Web::Cookie::Cookie> cookie)

View file

@ -38,7 +38,7 @@ endpoint WebContentServer
debug_request(ByteString request, ByteString argument) =| debug_request(ByteString request, ByteString argument) =|
get_source() =| get_source() =|
inspect_dom_tree() =| inspect_dom_tree() =|
inspect_dom_node(i32 node_id, Optional<Web::CSS::Selector::PseudoElement::Type> pseudo_element) => (bool has_style, ByteString computed_style, ByteString resolved_style, ByteString custom_properties, ByteString node_box_sizing, ByteString aria_properties_state) inspect_dom_node(i32 node_id, Optional<Web::CSS::Selector::PseudoElement::Type> pseudo_element) =|
inspect_accessibility_tree() =| inspect_accessibility_tree() =|
get_hovered_node_id() => (i32 node_id) get_hovered_node_id() => (i32 node_id)
js_console_input(ByteString js_source) =| js_console_input(ByteString js_source) =|