ladybird/Libraries/LibDevTools/Actors/StyleSheetsActor.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

99 lines
3.2 KiB
C++

/*
* Copyright (c) 2025, Tim Flynn <trflynn89@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/JsonObject.h>
#include <LibDevTools/Actors/InspectorActor.h>
#include <LibDevTools/Actors/StyleSheetsActor.h>
#include <LibDevTools/Actors/TabActor.h>
#include <LibDevTools/DevToolsDelegate.h>
#include <LibDevTools/DevToolsServer.h>
namespace DevTools {
NonnullRefPtr<StyleSheetsActor> StyleSheetsActor::create(DevToolsServer& devtools, String name, WeakPtr<TabActor> tab)
{
return adopt_ref(*new StyleSheetsActor(devtools, move(name), move(tab)));
}
StyleSheetsActor::StyleSheetsActor(DevToolsServer& devtools, String name, WeakPtr<TabActor> tab)
: Actor(devtools, move(name))
, m_tab(move(tab))
{
if (auto tab = m_tab.strong_ref()) {
devtools.delegate().listen_for_style_sheet_sources(
tab->description(),
weak_callback(*this, [](auto& self, Web::CSS::StyleSheetIdentifier const& style_sheet, String source) {
self.style_sheet_source_received(style_sheet, move(source));
}));
}
}
StyleSheetsActor::~StyleSheetsActor()
{
if (auto tab = m_tab.strong_ref())
devtools().delegate().stop_listening_for_style_sheet_sources(tab->description());
}
String StyleSheetsActor::resource_id_for_index(StringView actor_name, size_t index)
{
return MUST(String::formatted("{}-stylesheet:{}", actor_name, index));
}
void StyleSheetsActor::handle_message(Message const& message)
{
if (message.type == "getText"sv) {
auto resource_id = get_required_parameter<String>(message, "resourceId"sv);
if (!resource_id.has_value())
return;
auto index = resource_id->bytes_as_string_view().find_last_split_view(':').to_number<size_t>();
if (!index.has_value() || *index >= m_style_sheets.size()) {
send_unknown_actor_error(message, *resource_id);
return;
}
if (auto tab = m_tab.strong_ref()) {
devtools().delegate().retrieve_style_sheet_source(tab->description(), m_style_sheets[*index]);
m_pending_style_sheet_source_requests.set(*index, { .id = message.id });
}
return;
}
send_unrecognized_packet_type_error(message);
}
void StyleSheetsActor::set_style_sheets(Vector<Web::CSS::StyleSheetIdentifier> style_sheets)
{
m_style_sheets = move(style_sheets);
}
Optional<String> StyleSheetsActor::resource_id_for(Web::CSS::StyleSheetIdentifier const& style_sheet) const
{
auto index = m_style_sheets.find_first_index(style_sheet);
if (!index.has_value())
return {};
return resource_id_for_index(name(), *index);
}
void StyleSheetsActor::style_sheet_source_received(Web::CSS::StyleSheetIdentifier const& style_sheet, String source)
{
auto index = m_style_sheets.find_first_index(style_sheet);
if (!index.has_value())
return;
auto pending_message = m_pending_style_sheet_source_requests.take(*index);
if (!pending_message.has_value())
return;
// FIXME: Support the `longString` message type so that we don't have to send the entire style sheet
// source at once for large sheets.
JsonObject response;
response.set("text"sv, move(source));
send_response(*pending_message, move(response));
}
}