ladybird/Libraries/LibWeb/CSS/Parser/ComponentValue.cpp
Sam Atkins ee24561ab4 LibWeb/CSS: Store source positions on CSS rules
DevTools needs rule-level source positions to link applied style
rules back to their source sheets. The parser already tracks token
line and column information, so carry that through qualified rules
and nested declarations when creating CSSRule objects.
2026-06-04 20:54:33 +01:00

148 lines
4.1 KiB
C++

/*
* Copyright (c) 2020-2021, the SerenityOS developers.
* Copyright (c) 2021-2026, Sam Atkins <sam@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/CSS/Parser/ComponentValue.h>
namespace Web::CSS::Parser {
ComponentValue::ComponentValue(Token token)
: m_value(move(token))
{
}
ComponentValue::ComponentValue(Function&& function)
: m_value(move(function))
{
}
ComponentValue::ComponentValue(SimpleBlock&& block)
: m_value(move(block))
{
}
ComponentValue::ComponentValue(GuaranteedInvalidValue&& invalid)
: m_value(move(invalid))
{
}
ComponentValue::~ComponentValue() = default;
bool ComponentValue::is_function(StringView name) const
{
return is_function() && function().name.equals_ignoring_ascii_case(name);
}
bool ComponentValue::is_delim(u32 delim) const
{
switch (delim) {
// All of these have their own separate token types, and so passing them to is_delim() is incorrect and will never match.
case ':':
case ';':
case ',':
case '[':
case ']':
case '{':
case '}':
case '(':
case ')':
dbgln("Calling is_delim() with a punctuation mark ({}) that has its own token type!", static_cast<char>(delim));
VERIFY_NOT_REACHED();
default:
return is(Token::Type::Delim) && token().delim() == delim;
}
}
bool ComponentValue::is_ident(StringView ident) const
{
return is(Token::Type::Ident) && token().ident().equals_ignoring_ascii_case(ident);
}
String ComponentValue::to_string() const
{
return m_value.visit([](auto const& it) { return it.to_string(); });
}
String ComponentValue::to_debug_string() const
{
return m_value.visit(
[](Token const& token) {
return MUST(String::formatted("Token: {}", token.to_debug_string()));
},
[](SimpleBlock const& block) {
return MUST(String::formatted("Block: {}", block.to_string()));
},
[](Function const& function) {
return MUST(String::formatted("Function: {}", function.to_string()));
},
[](GuaranteedInvalidValue const&) {
return "Guaranteed-invalid value"_string;
});
}
String ComponentValue::original_source_text() const
{
return m_value.visit([](auto const& it) { return it.original_source_text(); });
}
Optional<SourcePosition> ComponentValue::start_position() const
{
return m_value.visit(
[](Token const& token) -> Optional<SourcePosition> {
return token.start_position();
},
[](SimpleBlock const& block) -> Optional<SourcePosition> {
return block.token.start_position();
},
[](Function const& function) -> Optional<SourcePosition> {
return function.name_token.start_position();
},
[](auto const&) -> Optional<SourcePosition> { return {}; });
}
bool ComponentValue::contains_guaranteed_invalid_value() const
{
return m_value.visit(
[](Token const&) {
return false;
},
[](SimpleBlock const& block) {
return block.value
.first_matching([](auto const& it) { return it.contains_guaranteed_invalid_value(); })
.has_value();
},
[](Function const& function) {
return function.value
.first_matching([](auto const& it) { return it.contains_guaranteed_invalid_value(); })
.has_value();
},
[](GuaranteedInvalidValue const&) {
return true;
});
}
bool ComponentValue::contains_attr_tainted_value() const
{
if (m_attr_tainted)
return true;
return m_value.visit(
[](Token const&) {
return false;
},
[](SimpleBlock const& block) {
return block.value
.first_matching([](auto const& it) { return it.contains_attr_tainted_value(); })
.has_value();
},
[](Function const& function) {
return function.value
.first_matching([](auto const& it) { return it.contains_attr_tainted_value(); })
.has_value();
},
[](GuaranteedInvalidValue const&) {
return false;
});
}
}