ladybird/Libraries/LibWeb/CSS/Parser/ComponentValue.h
Andreas Kling f47b6f3270 LibWeb: Reduce CSS parser token memory usage
Store CSS token payloads in a variant so each token only carries the
state needed by its type. Keep delimiter, number, hash, string, and
dimension data separate instead of storing every possible payload on
every token.

Use a smaller component-value token for function and block boundary
metadata. These component values only need token type, original source
text, and source positions, so avoid embedding full token payload
storage inside every Function and SimpleBlock.

Shrink CSS source positions to explicit 32-bit counters. Guard the C++
and Rust tokenizer paths against overflow. Add size assertions for the
hot Token and ComponentValue types so future growth is intentional.
2026-06-13 14:57:52 +02:00

73 lines
2.4 KiB
C++

/*
* Copyright (c) 2020-2021, the SerenityOS developers.
* Copyright (c) 2021-2026, Sam Atkins <sam@ladybird.org>
* Copyright (c) 2023, Andreas Kling <andreas@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/NonnullRefPtr.h>
#include <AK/RefPtr.h>
#include <LibWeb/CSS/Parser/Token.h>
#include <LibWeb/CSS/Parser/Types.h>
#include <LibWeb/Export.h>
namespace Web::CSS::Parser {
// https://drafts.csswg.org/css-syntax/#component-value
class WEB_API ComponentValue {
AK_MAKE_DEFAULT_COPYABLE(ComponentValue);
AK_MAKE_DEFAULT_MOVABLE(ComponentValue);
public:
ComponentValue(Token);
explicit ComponentValue(Function&&);
explicit ComponentValue(SimpleBlock&&);
explicit ComponentValue(GuaranteedInvalidValue&&);
~ComponentValue();
bool is_block() const { return m_value.has<SimpleBlock>(); }
SimpleBlock const& block() const { return m_value.get<SimpleBlock>(); }
bool is_function() const { return m_value.has<Function>(); }
bool is_function(StringView name) const;
Function const& function() const { return m_value.get<Function>(); }
bool is_token() const { return m_value.has<Token>(); }
bool is(Token::Type type) const { return is_token() && token().is(type); }
bool is_delim(u32 delim) const;
bool is_ident(StringView ident) const;
Token const& token() const { return m_value.get<Token>(); }
operator Token() const { return m_value.get<Token>(); }
bool is_guaranteed_invalid() const { return m_value.has<GuaranteedInvalidValue>(); }
bool contains_guaranteed_invalid_value() const;
bool contains_attr_tainted_value() const;
void set_attr_tainted() { m_attr_tainted = true; }
String to_string() const;
String to_debug_string() const;
String original_source_text() const;
Optional<SourcePosition> start_position() const;
bool operator==(ComponentValue const&) const = default;
private:
Variant<Token, Function, SimpleBlock, GuaranteedInvalidValue> m_value;
bool m_attr_tainted { false };
};
static_assert(sizeof(ComponentValue) <= 112, "Keep the size of CSS component values down!");
}
template<>
struct AK::Formatter<Web::CSS::Parser::ComponentValue> : Formatter<StringView> {
ErrorOr<void> format(FormatBuilder& builder, Web::CSS::Parser::ComponentValue const& component_value)
{
return Formatter<StringView>::format(builder, component_value.to_string());
}
};