ladybird/Libraries/LibDevTools/Actors/InspectorActor.cpp
Sam Atkins 64e0aa8c26 LibWeb+LibDevTools: Link style rules to CSS sources
Resolve applied-rule stylesheet identities through StyleSheetsActor and
include Firefox parentStyleSheet, line, and column fields on rule forms.
Firefox can then show matched rules as stylesheet rules and open the
corresponding CSS source location from the Rules panel.
2026-06-04 20:54:33 +01:00

149 lines
4.7 KiB
C++

/*
* Copyright (c) 2025, Tim Flynn <trflynn89@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Debug.h>
#include <AK/JsonObject.h>
#include <LibDevTools/Actors/HighlighterActor.h>
#include <LibDevTools/Actors/InspectorActor.h>
#include <LibDevTools/Actors/PageStyleActor.h>
#include <LibDevTools/Actors/StyleSheetsActor.h>
#include <LibDevTools/Actors/TabActor.h>
#include <LibDevTools/Actors/WalkerActor.h>
#include <LibDevTools/DevToolsDelegate.h>
#include <LibDevTools/DevToolsServer.h>
namespace DevTools {
NonnullRefPtr<InspectorActor> InspectorActor::create(DevToolsServer& devtools, String name, WeakPtr<TabActor> tab, WeakPtr<StyleSheetsActor> style_sheets)
{
return adopt_ref(*new InspectorActor(devtools, move(name), move(tab), move(style_sheets)));
}
InspectorActor::InspectorActor(DevToolsServer& devtools, String name, WeakPtr<TabActor> tab, WeakPtr<StyleSheetsActor> style_sheets)
: Actor(devtools, move(name))
, m_tab(move(tab))
, m_style_sheets(move(style_sheets))
{
}
InspectorActor::~InspectorActor() = default;
void InspectorActor::handle_message(Message const& message)
{
JsonObject response;
if (message.type == "getPageStyle"sv) {
if (!m_page_style)
m_page_style = devtools().register_actor<PageStyleActor>(*this);
response.set("pageStyle"sv, m_page_style->serialize_style());
send_response(message, move(response));
return;
}
if (message.type == "getHighlighterByType"sv) {
auto type_name = get_required_parameter<String>(message, "typeName"sv);
if (!type_name.has_value())
return;
auto& highlighter = devtools().register_actor<HighlighterActor>(*this, *type_name);
response.set("highlighter"sv, highlighter.serialize_highlighter());
send_response(message, move(response));
return;
}
if (message.type == "getWalker"sv) {
if (auto tab = m_tab.strong_ref()) {
devtools().delegate().inspect_tab(tab->description(),
async_handler<InspectorActor>(message, [](auto& self, auto dom_tree, auto& response) {
if (!WalkerActor::is_suitable_for_dom_inspection(dom_tree)) {
dbgln_if(DEVTOOLS_DEBUG, "Did not receive a suitable DOM tree: {}", dom_tree);
return;
}
self.received_dom_tree(response, move(dom_tree.as_object()));
}));
}
return;
}
if (message.type == "supportsHighlighters"sv) {
response.set("value"sv, true);
send_response(message, move(response));
return;
}
send_unrecognized_packet_type_error(message);
}
void InspectorActor::received_dom_tree(JsonObject& response, JsonObject dom_tree)
{
auto& walker_actor = devtools().register_actor<WalkerActor>(m_tab, move(dom_tree));
m_walker = walker_actor;
JsonObject walker;
walker.set("actor"sv, walker_actor.name());
walker.set("root"sv, walker_actor.serialize_root());
response.set("walker"sv, move(walker));
}
void InspectorActor::on_navigation_started()
{
if (auto walker = m_walker.strong_ref())
walker->document_unloaded();
if (auto tab = m_tab.strong_ref())
tab->reset_selected_node();
}
void InspectorActor::on_navigation_finished()
{
auto walker = m_walker.strong_ref();
auto tab = m_tab.strong_ref();
if (!walker || !tab)
return;
devtools().delegate().inspect_tab(tab->description(),
weak_callback(*this, [walker](auto&, auto dom_tree) {
if (dom_tree.is_error()) {
dbgln_if(DEVTOOLS_DEBUG, "Error inspecting tab after navigation: {}", dom_tree.error());
return;
}
auto value = dom_tree.release_value();
if (!WalkerActor::is_suitable_for_dom_inspection(value)) {
dbgln_if(DEVTOOLS_DEBUG, "Did not receive a suitable DOM tree: {}", value);
return;
}
walker->replace_dom_tree(move(value.as_object()));
}));
}
RefPtr<TabActor> InspectorActor::tab_for(WeakPtr<InspectorActor> const& weak_inspector)
{
if (auto inspector = weak_inspector.strong_ref())
return inspector->m_tab.strong_ref();
return {};
}
RefPtr<WalkerActor> InspectorActor::walker_for(WeakPtr<InspectorActor> const& weak_inspector)
{
if (auto inspector = weak_inspector.strong_ref())
return inspector->m_walker.strong_ref();
return {};
}
RefPtr<StyleSheetsActor> InspectorActor::style_sheets_for(WeakPtr<InspectorActor> const& weak_inspector)
{
if (auto inspector = weak_inspector.strong_ref())
return inspector->m_style_sheets.strong_ref();
return {};
}
}