ladybird/Libraries/LibWeb/CSS/StyleValues/CounterStyleStyleValue.cpp
Callum Law 64ccb9a015 LibWeb: Make @counter-style tree-scoped
This was a pretty straightforward change of storing registered counter
styles on the relevant `StyleScope`s and resolving by following the
process to dereference a global tree-scoped name, the only things of
note are:
 - We only define predefined counter styles (e.g. decimal) on the
   document's scope (since otherwise overrides in outer scopes would
   themselves be overriden).
 - When registering counter styles we don't have the full list of
   extendable styles so we defer fallback to "decimal" for undefined
   styles until `CounterStyle::from_counter_style_definition`.
2026-04-15 11:07:38 +01:00

86 lines
3.9 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2026, Callum Law <callumlaw1709@outlook.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "CounterStyleStyleValue.h"
#include <LibWeb/CSS/CounterStyle.h>
#include <LibWeb/CSS/Enums.h>
#include <LibWeb/CSS/Serialize.h>
#include <LibWeb/CSS/StyleScope.h>
namespace Web::CSS {
void CounterStyleStyleValue::serialize(StringBuilder& builder, SerializationMode) const
{
m_value.visit(
[&](FlyString const& name) {
builder.append(name);
},
[&](SymbolsFunction const& symbols_function) {
builder.append("symbols("sv);
if (symbols_function.type != SymbolsType::Symbolic)
builder.appendff("{} ", CSS::to_string(symbols_function.type));
for (size_t i = 0; i < symbols_function.symbols.size(); ++i) {
if (i > 0)
builder.append(' ');
serialize_a_string(builder, symbols_function.symbols[i]);
}
builder.append(')');
});
}
RefPtr<CounterStyle const> CounterStyleStyleValue::resolve_counter_style(StyleScope const& style_scope) const
{
return m_value.visit(
[&](FlyString const& name) -> RefPtr<CounterStyle const> {
return style_scope.get_registered_counter_style(name);
},
[&](SymbolsFunction const& symbols_function) -> RefPtr<CounterStyle const> {
// https://drafts.csswg.org/css-counter-styles-3/#symbols-function
auto algorithm = [&]() -> CounterStyleAlgorithm {
// The counter styles algorithm is constructed by consulting the previous chapter using the provided
// system — or symbolic if the system was omitted — and the provided <string>s and <image>s as the value
// of the symbols property. If the system is fixed, the first symbol value is 1.
switch (symbols_function.type) {
case SymbolsType::Cyclic:
return GenericCounterStyleAlgorithm { CounterStyleSystem::Cyclic, symbols_function.symbols };
case SymbolsType::Numeric:
return GenericCounterStyleAlgorithm { CounterStyleSystem::Numeric, symbols_function.symbols };
case SymbolsType::Alphabetic:
return GenericCounterStyleAlgorithm { CounterStyleSystem::Alphabetic, symbols_function.symbols };
case SymbolsType::Symbolic:
return GenericCounterStyleAlgorithm { CounterStyleSystem::Symbolic, symbols_function.symbols };
case SymbolsType::Fixed:
return FixedCounterStyleAlgorithm { .first_symbol = 1, .symbol_list = symbols_function.symbols };
}
VERIFY_NOT_REACHED();
}();
// The symbols() function defines an anonymous counter style with no name, a prefix of "" (empty string) and
// suffix of " " (U+0020 SPACE), a range of auto, a fallback of decimal, a negative of "\2D" ("-"
// hyphen-minus), a pad of 0 "", and a speak-as of auto.
// FIXME: Pass the correct speak-as value once we support that.
auto definition = CounterStyleDefinition::create(
// NB: We use empty string instead of no name for simplicity - this doesn't clash with
// <counter-style-name> since that is a <custom-ident> which can't be an empty string.
""_fly_string,
algorithm,
CounterStyleNegativeSign { "-"_fly_string, ""_fly_string },
""_fly_string,
" "_fly_string,
AutoRange {},
"decimal"_fly_string,
CounterStylePad { 0, ""_fly_string });
// NB: We don't need to pass registered counter styles here since we don't rely on extension.
return CounterStyle::from_counter_style_definition(definition, style_scope);
});
}
}