mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-29 12:19:54 +00:00
LibWebView: Parse inspector-related JSON strings sooner
We currently receive serialized JSON values over IPC and forward them to them WebView callbacks, leaving it to the implementations of those callbacks to parse the strings as JSON objects. This patch hoists that parsing up to WebContentClient as soon as the IPC message is received. This is to reduce the work needed for secondary implementations of these callbacks (i.e. our Firefox DevTools server).
This commit is contained in:
parent
5478f34992
commit
d4b7dd88b7
Notes:
github-actions[bot]
2025-02-24 17:07:18 +00:00
Author: https://github.com/trflynn89
Commit: d4b7dd88b7
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3666
Reviewed-by: https://github.com/AtkinsSJ
4 changed files with 63 additions and 70 deletions
|
@ -371,14 +371,9 @@ void Application::inspect_tab(DevTools::TabDescription const& description, DevTo
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
view->on_received_dom_tree = [&view = *view, on_complete = move(on_complete)](String const& dom_tree) {
|
view->on_received_dom_tree = [&view = *view, on_complete = move(on_complete)](JsonObject dom_tree) {
|
||||||
view.on_received_dom_tree = nullptr;
|
view.on_received_dom_tree = nullptr;
|
||||||
|
on_complete(move(dom_tree));
|
||||||
if (auto parsed_tree = JsonValue::from_string(dom_tree); parsed_tree.is_error()) {
|
|
||||||
on_complete(parsed_tree.release_error());
|
|
||||||
} else {
|
|
||||||
on_complete(parsed_tree.release_value());
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
view->inspect_dom_tree();
|
view->inspect_dom_tree();
|
||||||
|
|
|
@ -28,15 +28,6 @@ static constexpr auto INSPECTOR_HTML = "resource://ladybird/inspector.html"sv;
|
||||||
static constexpr auto INSPECTOR_CSS = "resource://ladybird/inspector.css"sv;
|
static constexpr auto INSPECTOR_CSS = "resource://ladybird/inspector.css"sv;
|
||||||
static constexpr auto INSPECTOR_JS = "resource://ladybird/inspector.js"sv;
|
static constexpr auto INSPECTOR_JS = "resource://ladybird/inspector.js"sv;
|
||||||
|
|
||||||
static ErrorOr<JsonValue> parse_json_tree(StringView json)
|
|
||||||
{
|
|
||||||
auto parsed_tree = TRY(JsonValue::from_string(json));
|
|
||||||
if (!parsed_tree.is_object())
|
|
||||||
return Error::from_string_literal("Expected tree to be a JSON object");
|
|
||||||
|
|
||||||
return parsed_tree;
|
|
||||||
}
|
|
||||||
|
|
||||||
static String style_sheet_identifier_to_json(Web::CSS::StyleSheetIdentifier const& identifier)
|
static String style_sheet_identifier_to_json(Web::CSS::StyleSheetIdentifier const& identifier)
|
||||||
{
|
{
|
||||||
return MUST(String::formatted("{{ type: '{}', domNodeId: {}, url: '{}' }}"sv,
|
return MUST(String::formatted("{{ type: '{}', domNodeId: {}, url: '{}' }}"sv,
|
||||||
|
@ -50,13 +41,7 @@ InspectorClient::InspectorClient(ViewImplementation& content_web_view, ViewImple
|
||||||
, m_inspector_web_view(inspector_web_view)
|
, m_inspector_web_view(inspector_web_view)
|
||||||
{
|
{
|
||||||
m_content_web_view.on_received_dom_tree = [this](auto const& dom_tree) {
|
m_content_web_view.on_received_dom_tree = [this](auto const& dom_tree) {
|
||||||
auto result = parse_json_tree(dom_tree);
|
auto dom_tree_html = generate_dom_tree(dom_tree);
|
||||||
if (result.is_error()) {
|
|
||||||
dbgln("Failed to load DOM tree: {}", result.error());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto dom_tree_html = generate_dom_tree(result.value().as_object());
|
|
||||||
auto dom_tree_base64 = MUST(encode_base64(dom_tree_html.bytes()));
|
auto dom_tree_base64 = MUST(encode_base64(dom_tree_html.bytes()));
|
||||||
|
|
||||||
auto script = MUST(String::formatted("inspector.loadDOMTree(\"{}\");", dom_tree_base64));
|
auto script = MUST(String::formatted("inspector.loadDOMTree(\"{}\");", dom_tree_base64));
|
||||||
|
@ -70,44 +55,27 @@ 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) {
|
m_content_web_view.on_received_dom_node_properties = [this](auto const& properties) {
|
||||||
StringBuilder builder;
|
StringBuilder builder;
|
||||||
|
|
||||||
// FIXME: Support box model metrics and ARIA properties.
|
// FIXME: Support box model metrics and ARIA properties.
|
||||||
auto generate_property_script = [&](auto const& computed_style, auto const& resolved_style, auto const& custom_properties, auto const& fonts) {
|
builder.append("inspector.createPropertyTables(\""sv);
|
||||||
builder.append("inspector.createPropertyTables(\""sv);
|
builder.append_escaped_for_json(properties.computed_style.serialized());
|
||||||
builder.append_escaped_for_json(computed_style);
|
builder.append("\", \""sv);
|
||||||
builder.append("\", \""sv);
|
builder.append_escaped_for_json(properties.resolved_style.serialized());
|
||||||
builder.append_escaped_for_json(resolved_style);
|
builder.append("\", \""sv);
|
||||||
builder.append("\", \""sv);
|
builder.append_escaped_for_json(properties.custom_properties.serialized());
|
||||||
builder.append_escaped_for_json(custom_properties);
|
builder.append("\");"sv);
|
||||||
builder.append("\");"sv);
|
|
||||||
builder.append("inspector.createFontList(\""sv);
|
|
||||||
builder.append_escaped_for_json(fonts);
|
|
||||||
builder.append("\");"sv);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (inspected_node_properties.has_value()) {
|
builder.append("inspector.createFontList(\""sv);
|
||||||
generate_property_script(
|
builder.append_escaped_for_json(properties.fonts.serialized());
|
||||||
inspected_node_properties->computed_style_json,
|
builder.append("\");"sv);
|
||||||
inspected_node_properties->resolved_style_json,
|
|
||||||
inspected_node_properties->custom_properties_json,
|
|
||||||
inspected_node_properties->fonts_json);
|
|
||||||
} else {
|
|
||||||
generate_property_script("{}"sv, "{}"sv, "{}"sv, "{}"sv);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_inspector_web_view.run_javascript(builder.string_view());
|
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 accessibility_tree_html = generate_accessibility_tree(accessibility_tree);
|
||||||
if (result.is_error()) {
|
|
||||||
dbgln("Failed to load accessibility tree: {}", result.error());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto accessibility_tree_html = generate_accessibility_tree(result.value().as_object());
|
|
||||||
auto accessibility_tree_base64 = MUST(encode_base64(accessibility_tree_html.bytes()));
|
auto accessibility_tree_base64 = MUST(encode_base64(accessibility_tree_html.bytes()));
|
||||||
|
|
||||||
auto script = MUST(String::formatted("inspector.loadAccessibilityTree(\"{}\");", accessibility_tree_base64));
|
auto script = MUST(String::formatted("inspector.loadAccessibilityTree(\"{}\");", accessibility_tree_base64));
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
|
|
||||||
#include <AK/Forward.h>
|
#include <AK/Forward.h>
|
||||||
#include <AK/Function.h>
|
#include <AK/Function.h>
|
||||||
|
#include <AK/JsonArray.h>
|
||||||
|
#include <AK/JsonObject.h>
|
||||||
#include <AK/LexicalPath.h>
|
#include <AK/LexicalPath.h>
|
||||||
#include <AK/Queue.h>
|
#include <AK/Queue.h>
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
|
@ -35,12 +37,12 @@ public:
|
||||||
virtual ~ViewImplementation();
|
virtual ~ViewImplementation();
|
||||||
|
|
||||||
struct DOMNodeProperties {
|
struct DOMNodeProperties {
|
||||||
String computed_style_json;
|
JsonObject computed_style;
|
||||||
String resolved_style_json;
|
JsonObject resolved_style;
|
||||||
String custom_properties_json;
|
JsonObject custom_properties;
|
||||||
String node_box_sizing_json;
|
JsonObject node_box_sizing;
|
||||||
String aria_properties_state_json;
|
JsonObject aria_properties_state;
|
||||||
String fonts_json;
|
JsonArray fonts;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void for_each_view(Function<IterationDecision(ViewImplementation&)>);
|
static void for_each_view(Function<IterationDecision(ViewImplementation&)>);
|
||||||
|
@ -200,9 +202,9 @@ public:
|
||||||
Function<void()> on_request_accept_dialog;
|
Function<void()> on_request_accept_dialog;
|
||||||
Function<void()> on_request_dismiss_dialog;
|
Function<void()> on_request_dismiss_dialog;
|
||||||
Function<void(URL::URL const&, URL::URL const&, String const&)> on_received_source;
|
Function<void(URL::URL const&, URL::URL const&, String const&)> on_received_source;
|
||||||
Function<void(String const&)> on_received_dom_tree;
|
Function<void(JsonObject)> on_received_dom_tree;
|
||||||
Function<void(Optional<DOMNodeProperties>)> on_received_dom_node_properties;
|
Function<void(DOMNodeProperties)> on_received_dom_node_properties;
|
||||||
Function<void(String const&)> on_received_accessibility_tree;
|
Function<void(JsonObject)> on_received_accessibility_tree;
|
||||||
Function<void(Vector<Web::CSS::StyleSheetIdentifier>)> on_received_style_sheet_list;
|
Function<void(Vector<Web::CSS::StyleSheetIdentifier>)> on_received_style_sheet_list;
|
||||||
Function<void(Web::CSS::StyleSheetIdentifier const&)> on_inspector_requested_style_sheet_source;
|
Function<void(Web::CSS::StyleSheetIdentifier const&)> on_inspector_requested_style_sheet_source;
|
||||||
Function<void(Web::CSS::StyleSheetIdentifier const&, URL::URL const&, String const&)> on_received_style_sheet_source;
|
Function<void(Web::CSS::StyleSheetIdentifier const&, URL::URL const&, String const&)> on_received_style_sheet_source;
|
||||||
|
|
|
@ -264,11 +264,39 @@ void WebContentClient::did_get_source(u64 page_id, URL::URL const& url, URL::URL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename JsonType = JsonObject>
|
||||||
|
static JsonType parse_json(StringView json, StringView name)
|
||||||
|
{
|
||||||
|
auto parsed_tree = JsonValue::from_string(json);
|
||||||
|
if (parsed_tree.is_error()) {
|
||||||
|
dbgln("Unable to parse {}: {}", name, parsed_tree.error());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (IsSame<JsonType, JsonObject>) {
|
||||||
|
if (!parsed_tree.value().is_object()) {
|
||||||
|
dbgln("Expected {} to be an object: {}", name, parsed_tree.value());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return move(parsed_tree.release_value().as_object());
|
||||||
|
} else if constexpr (IsSame<JsonType, JsonArray>) {
|
||||||
|
if (!parsed_tree.value().is_array()) {
|
||||||
|
dbgln("Expected {} to be an array: {}", name, parsed_tree.value());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return move(parsed_tree.release_value().as_array());
|
||||||
|
} else {
|
||||||
|
static_assert(DependentFalse<JsonType>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void WebContentClient::did_inspect_dom_tree(u64 page_id, String const& dom_tree)
|
void WebContentClient::did_inspect_dom_tree(u64 page_id, String const& dom_tree)
|
||||||
{
|
{
|
||||||
if (auto view = view_for_page_id(page_id); view.has_value()) {
|
if (auto view = view_for_page_id(page_id); view.has_value()) {
|
||||||
if (view->on_received_dom_tree)
|
if (view->on_received_dom_tree)
|
||||||
view->on_received_dom_tree(dom_tree);
|
view->on_received_dom_tree(parse_json(dom_tree, "DOM tree"sv));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,16 +306,16 @@ void WebContentClient::did_inspect_dom_node(u64 page_id, bool has_style, String
|
||||||
if (!view.has_value() || !view->on_received_dom_node_properties)
|
if (!view.has_value() || !view->on_received_dom_node_properties)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Optional<ViewImplementation::DOMNodeProperties> properties;
|
ViewImplementation::DOMNodeProperties properties;
|
||||||
|
|
||||||
if (has_style) {
|
if (has_style) {
|
||||||
properties = ViewImplementation::DOMNodeProperties {
|
properties = ViewImplementation::DOMNodeProperties {
|
||||||
.computed_style_json = computed_style,
|
.computed_style = parse_json(computed_style, "computed style"sv),
|
||||||
.resolved_style_json = resolved_style,
|
.resolved_style = parse_json(resolved_style, "resolved style"sv),
|
||||||
.custom_properties_json = custom_properties,
|
.custom_properties = parse_json(custom_properties, "custom properties"sv),
|
||||||
.node_box_sizing_json = node_box_sizing,
|
.node_box_sizing = parse_json(node_box_sizing, "node box sizing"sv),
|
||||||
.aria_properties_state_json = aria_properties_state,
|
.aria_properties_state = parse_json(aria_properties_state, "aria properties state"sv),
|
||||||
.fonts_json = fonts,
|
.fonts = parse_json<JsonArray>(fonts, "fonts"sv),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,7 +326,7 @@ void WebContentClient::did_inspect_accessibility_tree(u64 page_id, String const&
|
||||||
{
|
{
|
||||||
if (auto view = view_for_page_id(page_id); view.has_value()) {
|
if (auto view = view_for_page_id(page_id); view.has_value()) {
|
||||||
if (view->on_received_accessibility_tree)
|
if (view->on_received_accessibility_tree)
|
||||||
view->on_received_accessibility_tree(accessibility_tree);
|
view->on_received_accessibility_tree(parse_json(accessibility_tree, "accessibility tree"sv));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue