LibWeb: Support custom descriptors
Some at-rules (i.e. `@function`) require us to support custom descriptors (e.g. `--foo`). We do this by adding `DescriptorID::Custom` and using a new `DescriptorNameAndID` class in a bunch of places where we previously just used `DescriptorID`
This commit is contained in:
parent
fc3dc8ac8c
commit
e7243f0090
16 changed files with 272 additions and 152 deletions
|
|
@ -173,10 +173,11 @@ The generated code provides:
|
|||
|
||||
Each at-rule object has the following fields. Both are required.
|
||||
|
||||
| Field | Description |
|
||||
|---------------|---------------------------------------------------------------------------------------------------|
|
||||
| `spec` | String. URL to the spec that defines this at-rule. |
|
||||
| `descriptors` | Object, with keys being descriptor names and values being objects of their properties. See below. |
|
||||
| Field | Description |
|
||||
|----------------------|----------------------------------------------------------------------------------------------------------------------|
|
||||
| `spec` | String. URL to the spec that defines this at-rule. |
|
||||
| `descriptors` | Object, with keys being descriptor names and values being objects of their properties. See below. |
|
||||
| `custom-descriptors` | Object, the configuration for custom descriptors (i.e. --foo). Omission means that custom descriptors are disallowed |
|
||||
|
||||
### Descriptor fields
|
||||
|
||||
|
|
@ -189,6 +190,15 @@ Each descriptor object can have the following fields:
|
|||
| `syntax` | Yes | Array of strings. Each string is one option, taken from the spec. |
|
||||
| `FIXME` or `NOTE` | No | Strings, for when you want to leave a note. |
|
||||
|
||||
### Custom descriptor fields
|
||||
|
||||
Each custom descriptor object has the following fields
|
||||
|
||||
| Field | Required | Description |
|
||||
|--------------------|----------|----------------------------------------------|
|
||||
| `syntax` | Yes | Array of strings. Each string is one option. |
|
||||
| `FIXME` or `NOTE` | No | Strings, for when you want to leave a note. |
|
||||
|
||||
## Keywords.json
|
||||
|
||||
This is a single JSON array of strings, each of which is a CSS keyword, for example `auto`, `none`, `medium`, or `currentcolor`.
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ void CSSCounterStyleRule::set_system(FlyString const& system)
|
|||
{
|
||||
// 1. parse the given value as the descriptor associated with the attribute.
|
||||
Parser::ParsingParams parsing_params { realm() };
|
||||
auto value = parse_css_descriptor(parsing_params, CSS::AtRuleID::CounterStyle, CSS::DescriptorID::System, system);
|
||||
auto value = parse_css_descriptor(parsing_params, CSS::AtRuleID::CounterStyle, DescriptorNameAndID::from_id(CSS::DescriptorID::System), system);
|
||||
|
||||
// 2. If the result is invalid according to the given descriptor’s grammar, or would cause the @counter-style rule
|
||||
// to not define a counter style, do nothing and abort these steps. (For example, some systems require the
|
||||
|
|
@ -169,7 +169,7 @@ void CSSCounterStyleRule::set_negative(FlyString const& negative)
|
|||
{
|
||||
Parser::ParsingParams parsing_params { realm() };
|
||||
|
||||
if (auto value = parse_css_descriptor(parsing_params, CSS::AtRuleID::CounterStyle, CSS::DescriptorID::Negative, negative))
|
||||
if (auto value = parse_css_descriptor(parsing_params, CSS::AtRuleID::CounterStyle, DescriptorNameAndID::from_id(CSS::DescriptorID::Negative), negative))
|
||||
m_negative = value;
|
||||
}
|
||||
|
||||
|
|
@ -185,7 +185,7 @@ void CSSCounterStyleRule::set_prefix(FlyString const& prefix)
|
|||
{
|
||||
Parser::ParsingParams parsing_params { realm() };
|
||||
|
||||
if (auto value = parse_css_descriptor(parsing_params, CSS::AtRuleID::CounterStyle, CSS::DescriptorID::Prefix, prefix))
|
||||
if (auto value = parse_css_descriptor(parsing_params, CSS::AtRuleID::CounterStyle, DescriptorNameAndID::from_id(CSS::DescriptorID::Prefix), prefix))
|
||||
m_prefix = value;
|
||||
}
|
||||
|
||||
|
|
@ -201,7 +201,7 @@ void CSSCounterStyleRule::set_suffix(FlyString const& suffix)
|
|||
{
|
||||
Parser::ParsingParams parsing_params { realm() };
|
||||
|
||||
if (auto value = parse_css_descriptor(parsing_params, CSS::AtRuleID::CounterStyle, CSS::DescriptorID::Suffix, suffix))
|
||||
if (auto value = parse_css_descriptor(parsing_params, CSS::AtRuleID::CounterStyle, DescriptorNameAndID::from_id(CSS::DescriptorID::Suffix), suffix))
|
||||
m_suffix = value;
|
||||
}
|
||||
|
||||
|
|
@ -217,7 +217,7 @@ void CSSCounterStyleRule::set_range(FlyString const& range)
|
|||
{
|
||||
Parser::ParsingParams parsing_params { realm() };
|
||||
|
||||
if (auto value = parse_css_descriptor(parsing_params, CSS::AtRuleID::CounterStyle, CSS::DescriptorID::Range, range))
|
||||
if (auto value = parse_css_descriptor(parsing_params, CSS::AtRuleID::CounterStyle, DescriptorNameAndID::from_id(CSS::DescriptorID::Range), range))
|
||||
m_range = value;
|
||||
}
|
||||
|
||||
|
|
@ -233,7 +233,7 @@ void CSSCounterStyleRule::set_pad(FlyString const& pad)
|
|||
{
|
||||
Parser::ParsingParams parsing_params { realm() };
|
||||
|
||||
if (auto value = parse_css_descriptor(parsing_params, CSS::AtRuleID::CounterStyle, CSS::DescriptorID::Pad, pad))
|
||||
if (auto value = parse_css_descriptor(parsing_params, CSS::AtRuleID::CounterStyle, DescriptorNameAndID::from_id(CSS::DescriptorID::Pad), pad))
|
||||
m_pad = value;
|
||||
}
|
||||
|
||||
|
|
@ -249,7 +249,7 @@ void CSSCounterStyleRule::set_fallback(FlyString const& fallback)
|
|||
{
|
||||
Parser::ParsingParams parsing_params { realm() };
|
||||
|
||||
if (auto value = parse_css_descriptor(parsing_params, CSS::AtRuleID::CounterStyle, CSS::DescriptorID::Fallback, fallback))
|
||||
if (auto value = parse_css_descriptor(parsing_params, CSS::AtRuleID::CounterStyle, DescriptorNameAndID::from_id(CSS::DescriptorID::Fallback), fallback))
|
||||
m_fallback = value;
|
||||
}
|
||||
|
||||
|
|
@ -269,7 +269,7 @@ void CSSCounterStyleRule::set_symbols(FlyString const& symbols)
|
|||
// 1. parse the given value as the descriptor associated with the attribute.
|
||||
Parser::ParsingParams parsing_params { realm() };
|
||||
|
||||
auto value = parse_css_descriptor(parsing_params, CSS::AtRuleID::CounterStyle, CSS::DescriptorID::Symbols, symbols);
|
||||
auto value = parse_css_descriptor(parsing_params, CSS::AtRuleID::CounterStyle, DescriptorNameAndID::from_id(CSS::DescriptorID::Symbols), symbols);
|
||||
|
||||
// 2. If the result is invalid according to the given descriptor’s grammar, or would cause the @counter-style rule
|
||||
// to not define a counter style, do nothing and abort these steps. (For example, some systems require the
|
||||
|
|
@ -300,7 +300,7 @@ void CSSCounterStyleRule::set_additive_symbols(FlyString const& additive_symbols
|
|||
// 1. parse the given value as the descriptor associated with the attribute.
|
||||
Parser::ParsingParams parsing_params { realm() };
|
||||
|
||||
auto value = parse_css_descriptor(parsing_params, CSS::AtRuleID::CounterStyle, CSS::DescriptorID::AdditiveSymbols, additive_symbols);
|
||||
auto value = parse_css_descriptor(parsing_params, CSS::AtRuleID::CounterStyle, DescriptorNameAndID::from_id(CSS::DescriptorID::AdditiveSymbols), additive_symbols);
|
||||
|
||||
// 2. If the result is invalid according to the given descriptor’s grammar, or would cause the @counter-style rule
|
||||
// to not define a counter style, do nothing and abort these steps. (For example, some systems require the
|
||||
|
|
@ -327,7 +327,7 @@ void CSSCounterStyleRule::set_speak_as(FlyString const& speak_as)
|
|||
{
|
||||
Parser::ParsingParams parsing_params { realm() };
|
||||
|
||||
if (auto value = parse_css_descriptor(parsing_params, CSS::AtRuleID::CounterStyle, CSS::DescriptorID::SpeakAs, speak_as))
|
||||
if (auto value = parse_css_descriptor(parsing_params, CSS::AtRuleID::CounterStyle, DescriptorNameAndID::from_id(CSS::DescriptorID::SpeakAs), speak_as))
|
||||
m_speak_as = value;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,16 +38,16 @@ String CSSDescriptors::item(size_t index) const
|
|||
if (index >= length())
|
||||
return {};
|
||||
|
||||
return to_string(m_descriptors[index].descriptor_id).to_string();
|
||||
return m_descriptors[index].descriptor_name_and_id.name().to_string();
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom/#set-a-css-declaration
|
||||
bool CSSDescriptors::set_a_css_declaration(DescriptorID descriptor_id, NonnullRefPtr<StyleValue const> value, Important)
|
||||
bool CSSDescriptors::set_a_css_declaration(DescriptorNameAndID const& descriptor_name_and_id, NonnullRefPtr<StyleValue const> value, Important)
|
||||
{
|
||||
VERIFY(!is_computed());
|
||||
|
||||
for (auto& descriptor : m_descriptors) {
|
||||
if (descriptor.descriptor_id == descriptor_id) {
|
||||
if (descriptor.descriptor_name_and_id == descriptor_name_and_id) {
|
||||
if (*descriptor.value == *value)
|
||||
return false;
|
||||
descriptor.value = move(value);
|
||||
|
|
@ -56,7 +56,7 @@ bool CSSDescriptors::set_a_css_declaration(DescriptorID descriptor_id, NonnullRe
|
|||
}
|
||||
|
||||
m_descriptors.append(Descriptor {
|
||||
.descriptor_id = descriptor_id,
|
||||
.descriptor_name_and_id = descriptor_name_and_id,
|
||||
.value = move(value),
|
||||
});
|
||||
return true;
|
||||
|
|
@ -70,12 +70,12 @@ WebIDL::ExceptionOr<void> CSSDescriptors::set_property(FlyString const& property
|
|||
return WebIDL::NoModificationAllowedError::create(realm(), "Cannot modify properties of readonly CSSStyleDeclaration"_utf16);
|
||||
|
||||
// 2. If property is not a custom property, follow these substeps:
|
||||
Optional<DescriptorID> descriptor_id;
|
||||
Optional<DescriptorNameAndID> descriptor_name_and_id;
|
||||
{
|
||||
// 1. Let property be property converted to ASCII lowercase.
|
||||
// 2. If property is not a case-sensitive match for a supported CSS property, then return.
|
||||
descriptor_id = descriptor_id_from_string(m_at_rule_id, property);
|
||||
if (!descriptor_id.has_value())
|
||||
descriptor_name_and_id = DescriptorNameAndID::from_name(m_at_rule_id, property);
|
||||
if (!descriptor_name_and_id.has_value())
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
@ -90,7 +90,7 @@ WebIDL::ExceptionOr<void> CSSDescriptors::set_property(FlyString const& property
|
|||
return {};
|
||||
|
||||
// 5. Let component value list be the result of parsing value for property property.
|
||||
RefPtr<StyleValue const> component_value_list = parse_css_descriptor(Parser::ParsingParams {}, m_at_rule_id, *descriptor_id, value);
|
||||
RefPtr<StyleValue const> component_value_list = parse_css_descriptor(Parser::ParsingParams {}, m_at_rule_id, *descriptor_name_and_id, value);
|
||||
|
||||
// 6. If component value list is null, then return.
|
||||
if (!component_value_list)
|
||||
|
|
@ -100,14 +100,14 @@ WebIDL::ExceptionOr<void> CSSDescriptors::set_property(FlyString const& property
|
|||
auto updated = false;
|
||||
|
||||
// 8. If property is a shorthand property, then for each longhand property longhand that property maps to, in canonical order, follow these substeps:
|
||||
if (is_shorthand(m_at_rule_id, *descriptor_id)) {
|
||||
for_each_expanded_longhand(m_at_rule_id, *descriptor_id, component_value_list, [this, &updated, priority](DescriptorID longhand_id, auto longhand_value) {
|
||||
if (is_shorthand(m_at_rule_id, *descriptor_name_and_id)) {
|
||||
for_each_expanded_longhand(m_at_rule_id, *descriptor_name_and_id, component_value_list, [this, &updated, priority](DescriptorNameAndID const& longhand_name_and_id, auto longhand_value) {
|
||||
VERIFY(longhand_value);
|
||||
|
||||
// 1. Let longhand result be the result of set the CSS declaration longhand with the appropriate value(s)
|
||||
// from component value list, with the important flag set if priority is not the empty string, and unset
|
||||
// otherwise, and with the list of declarations being the declarations.
|
||||
auto longhand_result = set_a_css_declaration(longhand_id, longhand_value.release_nonnull(), priority.is_empty() ? Important::No : Important::Yes);
|
||||
auto longhand_result = set_a_css_declaration(longhand_name_and_id, longhand_value.release_nonnull(), priority.is_empty() ? Important::No : Important::Yes);
|
||||
|
||||
// 2. If longhand result is true, let updated be true.
|
||||
if (longhand_result)
|
||||
|
|
@ -118,7 +118,7 @@ WebIDL::ExceptionOr<void> CSSDescriptors::set_property(FlyString const& property
|
|||
// with the important flag set if priority is not the empty string, and unset otherwise, and with the list of
|
||||
// declarations being the declarations.
|
||||
else {
|
||||
updated = set_a_css_declaration(*descriptor_id, *component_value_list, !priority.is_empty() ? Important::Yes : Important::No);
|
||||
updated = set_a_css_declaration(*descriptor_name_and_id, *component_value_list, !priority.is_empty() ? Important::Yes : Important::No);
|
||||
}
|
||||
|
||||
// 10. If updated is true, update style attribute for the CSS declaration block.
|
||||
|
|
@ -143,22 +143,22 @@ WebIDL::ExceptionOr<String> CSSDescriptors::remove_property(FlyString const& pro
|
|||
|
||||
// 4. Let removed be false.
|
||||
bool removed = false;
|
||||
auto descriptor_id = descriptor_id_from_string(m_at_rule_id, property);
|
||||
auto descriptor_name_and_id = DescriptorNameAndID::from_name(m_at_rule_id, property);
|
||||
|
||||
// 5. If property is a shorthand property, for each longhand property longhand that property maps to:
|
||||
if (descriptor_id.has_value() && is_shorthand(m_at_rule_id, *descriptor_id)) {
|
||||
for_each_expanded_longhand(m_at_rule_id, *descriptor_id, nullptr, [this, &removed](DescriptorID longhand_id, auto const&) {
|
||||
if (descriptor_name_and_id.has_value() && is_shorthand(m_at_rule_id, *descriptor_name_and_id)) {
|
||||
for_each_expanded_longhand(m_at_rule_id, *descriptor_name_and_id, nullptr, [this, &removed](DescriptorNameAndID const& longhand_name_and_id, auto const&) {
|
||||
// 1. If longhand is not a property name of a CSS declaration in the declarations, continue.
|
||||
// 2. Remove that CSS declaration and let removed be true.
|
||||
if (m_descriptors.remove_first_matching([longhand_id](auto& entry) { return entry.descriptor_id == longhand_id; })) {
|
||||
if (m_descriptors.remove_first_matching([longhand_name_and_id](Descriptor const& entry) { return entry.descriptor_name_and_id == longhand_name_and_id; })) {
|
||||
removed = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
// 6. Otherwise, if property is a case-sensitive match for a property name of a CSS declaration in the
|
||||
// declarations, remove that CSS declaration and let removed be true.
|
||||
else if (descriptor_id.has_value()) {
|
||||
removed = m_descriptors.remove_first_matching([descriptor_id](auto& entry) { return entry.descriptor_id == *descriptor_id; });
|
||||
else if (descriptor_name_and_id.has_value()) {
|
||||
removed = m_descriptors.remove_first_matching([descriptor_name_and_id](Descriptor const& entry) { return entry.descriptor_name_and_id == descriptor_name_and_id; });
|
||||
}
|
||||
|
||||
// 7. If removed is true, Update style attribute for the CSS declaration block.
|
||||
|
|
@ -177,9 +177,9 @@ String CSSDescriptors::get_property_value(FlyString const& property) const
|
|||
|
||||
// 2. If property is a case-sensitive match for a property name of a CSS declaration in the declarations, then
|
||||
// return the result of invoking serialize a CSS value of that declaration.
|
||||
auto descriptor_id = descriptor_id_from_string(m_at_rule_id, property);
|
||||
if (descriptor_id.has_value()) {
|
||||
auto match = m_descriptors.first_matching([descriptor_id](auto& entry) { return entry.descriptor_id == *descriptor_id; });
|
||||
auto descriptor_name_and_id = DescriptorNameAndID::from_name(m_at_rule_id, property);
|
||||
if (descriptor_name_and_id.has_value()) {
|
||||
auto match = m_descriptors.first_matching([descriptor_name_and_id](Descriptor const& entry) { return entry.descriptor_name_and_id == descriptor_name_and_id; });
|
||||
if (match.has_value())
|
||||
return match->value->to_string(SerializationMode::Normal);
|
||||
}
|
||||
|
|
@ -208,7 +208,7 @@ String CSSDescriptors::serialized() const
|
|||
// 3. Declaration loop: For each CSS declaration declaration in declaration block’s declarations, follow these substeps:
|
||||
for (auto const& descriptor : m_descriptors) {
|
||||
// 1. Let property be declaration’s property name.
|
||||
auto property = to_string(descriptor.descriptor_id);
|
||||
auto property = descriptor.descriptor_name_and_id.name();
|
||||
|
||||
// 2. If property is in already serialized, continue with the steps labeled declaration loop.
|
||||
// AD-HOC: Not needed as we don't have shorthands.
|
||||
|
|
@ -264,49 +264,49 @@ void CSSDescriptors::visit_edges(Visitor& visitor)
|
|||
}
|
||||
}
|
||||
|
||||
RefPtr<StyleValue const> CSSDescriptors::descriptor(DescriptorID descriptor_id) const
|
||||
RefPtr<StyleValue const> CSSDescriptors::descriptor(DescriptorNameAndID const& descriptor_name_and_id) const
|
||||
{
|
||||
auto match = m_descriptors.first_matching([descriptor_id](Descriptor const& descriptor) {
|
||||
return descriptor.descriptor_id == descriptor_id;
|
||||
auto match = m_descriptors.first_matching([descriptor_name_and_id](Descriptor const& descriptor) {
|
||||
return descriptor.descriptor_name_and_id == descriptor_name_and_id;
|
||||
});
|
||||
if (match.has_value())
|
||||
return match->value;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<StyleValue const> CSSDescriptors::descriptor_or_initial_value(DescriptorID descriptor_id) const
|
||||
RefPtr<StyleValue const> CSSDescriptors::descriptor_or_initial_value(DescriptorNameAndID const& descriptor_name_and_id) const
|
||||
{
|
||||
if (auto value = descriptor(descriptor_id))
|
||||
if (auto value = descriptor(descriptor_name_and_id))
|
||||
return value.release_nonnull();
|
||||
|
||||
return descriptor_initial_value(m_at_rule_id, descriptor_id);
|
||||
return descriptor_initial_value(m_at_rule_id, descriptor_name_and_id.id());
|
||||
}
|
||||
|
||||
bool is_shorthand(AtRuleID at_rule, DescriptorID descriptor)
|
||||
bool is_shorthand(AtRuleID at_rule, DescriptorNameAndID const& descriptor)
|
||||
{
|
||||
if (at_rule == AtRuleID::Page && descriptor == DescriptorID::Margin)
|
||||
if (at_rule == AtRuleID::Page && descriptor.id() == DescriptorID::Margin)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void for_each_expanded_longhand(AtRuleID at_rule, DescriptorID descriptor, RefPtr<StyleValue const> value, Function<void(DescriptorID, RefPtr<StyleValue const>)> callback)
|
||||
void for_each_expanded_longhand(AtRuleID at_rule, DescriptorNameAndID const& descriptor, RefPtr<StyleValue const> value, Function<void(DescriptorNameAndID const&, RefPtr<StyleValue const>)> callback)
|
||||
{
|
||||
if (at_rule == AtRuleID::Page && descriptor == DescriptorID::Margin) {
|
||||
if (at_rule == AtRuleID::Page && descriptor.id() == DescriptorID::Margin) {
|
||||
if (!value) {
|
||||
callback(DescriptorID::MarginTop, nullptr);
|
||||
callback(DescriptorID::MarginRight, nullptr);
|
||||
callback(DescriptorID::MarginBottom, nullptr);
|
||||
callback(DescriptorID::MarginLeft, nullptr);
|
||||
callback(DescriptorNameAndID::from_id(DescriptorID::MarginTop), nullptr);
|
||||
callback(DescriptorNameAndID::from_id(DescriptorID::MarginRight), nullptr);
|
||||
callback(DescriptorNameAndID::from_id(DescriptorID::MarginBottom), nullptr);
|
||||
callback(DescriptorNameAndID::from_id(DescriptorID::MarginLeft), nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
auto const& shorthand_value = value->as_shorthand();
|
||||
|
||||
callback(DescriptorID::MarginTop, shorthand_value.longhand(PropertyID::MarginTop));
|
||||
callback(DescriptorID::MarginRight, shorthand_value.longhand(PropertyID::MarginRight));
|
||||
callback(DescriptorID::MarginBottom, shorthand_value.longhand(PropertyID::MarginBottom));
|
||||
callback(DescriptorID::MarginLeft, shorthand_value.longhand(PropertyID::MarginLeft));
|
||||
callback(DescriptorNameAndID::from_id(DescriptorID::MarginTop), shorthand_value.longhand(PropertyID::MarginTop));
|
||||
callback(DescriptorNameAndID::from_id(DescriptorID::MarginRight), shorthand_value.longhand(PropertyID::MarginRight));
|
||||
callback(DescriptorNameAndID::from_id(DescriptorID::MarginBottom), shorthand_value.longhand(PropertyID::MarginBottom));
|
||||
callback(DescriptorNameAndID::from_id(DescriptorID::MarginLeft), shorthand_value.longhand(PropertyID::MarginLeft));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ public:
|
|||
virtual StringView get_property_priority(FlyString const& property) const override;
|
||||
|
||||
Vector<Descriptor> const& descriptors() const { return m_descriptors; }
|
||||
RefPtr<StyleValue const> descriptor(DescriptorID) const;
|
||||
RefPtr<StyleValue const> descriptor_or_initial_value(DescriptorID) const;
|
||||
RefPtr<StyleValue const> descriptor(DescriptorNameAndID const&) const;
|
||||
RefPtr<StyleValue const> descriptor_or_initial_value(DescriptorNameAndID const&) const;
|
||||
virtual String serialized() const override;
|
||||
|
||||
virtual WebIDL::ExceptionOr<void> set_css_text(StringView) override;
|
||||
|
|
@ -37,7 +37,7 @@ protected:
|
|||
CSSDescriptors(JS::Realm&, AtRuleID, Vector<Descriptor>);
|
||||
|
||||
private:
|
||||
bool set_a_css_declaration(DescriptorID, NonnullRefPtr<StyleValue const>, Important);
|
||||
bool set_a_css_declaration(DescriptorNameAndID const&, NonnullRefPtr<StyleValue const>, Important);
|
||||
|
||||
virtual void visit_edges(Visitor&) override;
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ private:
|
|||
Vector<Descriptor> m_descriptors;
|
||||
};
|
||||
|
||||
bool is_shorthand(AtRuleID, DescriptorID);
|
||||
void for_each_expanded_longhand(AtRuleID, DescriptorID, RefPtr<StyleValue const>, Function<void(DescriptorID, RefPtr<StyleValue const>)>);
|
||||
bool is_shorthand(AtRuleID, DescriptorNameAndID const&);
|
||||
void for_each_expanded_longhand(AtRuleID, DescriptorNameAndID const&, RefPtr<StyleValue const>, Function<void(DescriptorNameAndID const&, RefPtr<StyleValue const>)>);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@ bool CSSFontFaceRule::is_valid() const
|
|||
// @font-face rules require a font-family and src descriptor; if either of these are missing, the @font-face rule
|
||||
// must not be considered when performing the font matching algorithm.
|
||||
// https://drafts.csswg.org/css-fonts-4/#font-face-rule
|
||||
return !m_style->descriptor(DescriptorID::FontFamily).is_null()
|
||||
&& !m_style->descriptor(DescriptorID::Src).is_null();
|
||||
return !m_style->descriptor(DescriptorNameAndID::from_id(DescriptorID::FontFamily)).is_null()
|
||||
&& !m_style->descriptor(DescriptorNameAndID::from_id(DescriptorID::Src)).is_null();
|
||||
}
|
||||
|
||||
ParsedFontFace CSSFontFaceRule::font_face() const
|
||||
|
|
@ -69,21 +69,21 @@ String CSSFontFaceRule::serialized() const
|
|||
// AD-HOC: We don't necessary always have a font-family descriptor as the spec assumes,
|
||||
// see https://github.com/w3c/csswg-drafts/issues/13323
|
||||
|
||||
if (auto font_family = descriptors.descriptor(DescriptorID::FontFamily); !font_family.is_null()) {
|
||||
if (auto font_family = descriptors.descriptor(DescriptorNameAndID::from_id(DescriptorID::FontFamily)); !font_family.is_null()) {
|
||||
builder.append(' ');
|
||||
|
||||
// 2. The string "font-family:", followed by a single SPACE (U+0020).
|
||||
builder.append("font-family: "sv);
|
||||
|
||||
// 3. The result of performing serialize a string on the rule’s font family name.
|
||||
descriptors.descriptor(DescriptorID::FontFamily)->serialize(builder, SerializationMode::Normal);
|
||||
descriptors.descriptor(DescriptorNameAndID::from_id(DescriptorID::FontFamily))->serialize(builder, SerializationMode::Normal);
|
||||
|
||||
// 4. The string ";", i.e., SEMICOLON (U+003B).
|
||||
builder.append(';');
|
||||
}
|
||||
|
||||
// 5. If the rule’s associated source list is not empty, follow these substeps:
|
||||
if (auto sources = descriptors.descriptor(DescriptorID::Src)) {
|
||||
if (auto sources = descriptors.descriptor(DescriptorNameAndID::from_id(DescriptorID::Src))) {
|
||||
// 1. A single SPACE (U+0020), followed by the string "src:", followed by a single SPACE (U+0020).
|
||||
builder.append(" src: "sv);
|
||||
|
||||
|
|
@ -95,7 +95,7 @@ String CSSFontFaceRule::serialized() const
|
|||
}
|
||||
|
||||
// 6. If rule’s associated unicode-range descriptor is present, a single SPACE (U+0020), followed by the string "unicode-range:", followed by a single SPACE (U+0020), followed by the result of performing serialize a <'unicode-range'>, followed by the string ";", i.e., SEMICOLON (U+003B).
|
||||
if (auto unicode_range = descriptors.descriptor(DescriptorID::UnicodeRange)) {
|
||||
if (auto unicode_range = descriptors.descriptor(DescriptorNameAndID::from_id(DescriptorID::UnicodeRange))) {
|
||||
builder.append(" unicode-range: "sv);
|
||||
unicode_range->serialize(builder, SerializationMode::Normal);
|
||||
builder.append(';');
|
||||
|
|
@ -110,7 +110,7 @@ String CSSFontFaceRule::serialized() const
|
|||
// followed by the string "font-feature-settings:", followed by a single SPACE (U+0020),
|
||||
// followed by the result of performing serialize a <'font-feature-settings'>,
|
||||
// followed by the string ";", i.e., SEMICOLON (U+003B).
|
||||
if (auto font_feature_settings = descriptors.descriptor(DescriptorID::FontFeatureSettings)) {
|
||||
if (auto font_feature_settings = descriptors.descriptor(DescriptorNameAndID::from_id(DescriptorID::FontFeatureSettings))) {
|
||||
builder.append(" font-feature-settings: "sv);
|
||||
font_feature_settings->serialize(builder, SerializationMode::Normal);
|
||||
builder.append(";"sv);
|
||||
|
|
@ -121,7 +121,7 @@ String CSSFontFaceRule::serialized() const
|
|||
// followed by the result of performing serialize a <'font-stretch'>,
|
||||
// followed by the string ";", i.e., SEMICOLON (U+003B).
|
||||
// NOTE: font-stretch is now an alias for font-width, so we use that instead.
|
||||
if (auto font_width = descriptors.descriptor(DescriptorID::FontWidth)) {
|
||||
if (auto font_width = descriptors.descriptor(DescriptorNameAndID::from_id(DescriptorID::FontWidth))) {
|
||||
builder.append(" font-stretch: "sv);
|
||||
font_width->serialize(builder, SerializationMode::Normal);
|
||||
builder.append(";"sv);
|
||||
|
|
@ -131,7 +131,7 @@ String CSSFontFaceRule::serialized() const
|
|||
// followed by the string "font-weight:", followed by a single SPACE (U+0020),
|
||||
// followed by the result of performing serialize a <'font-weight'>,
|
||||
// followed by the string ";", i.e., SEMICOLON (U+003B).
|
||||
if (auto font_weight = descriptors.descriptor(DescriptorID::FontWeight)) {
|
||||
if (auto font_weight = descriptors.descriptor(DescriptorNameAndID::from_id(DescriptorID::FontWeight))) {
|
||||
builder.append(" font-weight: "sv);
|
||||
font_weight->serialize(builder, SerializationMode::Normal);
|
||||
builder.append(";"sv);
|
||||
|
|
@ -141,7 +141,7 @@ String CSSFontFaceRule::serialized() const
|
|||
// followed by the string "font-style:", followed by a single SPACE (U+0020),
|
||||
// followed by the result of performing serialize a <'font-style'>,
|
||||
// followed by the string ";", i.e., SEMICOLON (U+003B).
|
||||
if (auto font_style = descriptors.descriptor(DescriptorID::FontStyle)) {
|
||||
if (auto font_style = descriptors.descriptor(DescriptorNameAndID::from_id(DescriptorID::FontStyle))) {
|
||||
builder.append(" font-style: "sv);
|
||||
font_style->serialize(builder, SerializationMode::Normal);
|
||||
builder.append(";"sv);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/NonnullRefPtr.h>
|
||||
#include <LibWeb/CSS/DescriptorID.h>
|
||||
#include <LibWeb/CSS/DescriptorNameAndID.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
|
@ -15,7 +15,7 @@ namespace Web::CSS {
|
|||
struct Descriptor {
|
||||
~Descriptor();
|
||||
|
||||
DescriptorID descriptor_id;
|
||||
DescriptorNameAndID descriptor_name_and_id;
|
||||
NonnullRefPtr<StyleValue const> value;
|
||||
};
|
||||
|
||||
|
|
|
|||
72
Libraries/LibWeb/CSS/DescriptorNameAndID.h
Normal file
72
Libraries/LibWeb/CSS/DescriptorNameAndID.h
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2026, Callum Law <callumlaw1709@outlook.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/CSS/DescriptorID.h>
|
||||
#include <LibWeb/CSS/PropertyName.h>
|
||||
#include <LibWeb/CSS/Serialize.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
class DescriptorNameAndID {
|
||||
public:
|
||||
static Optional<DescriptorNameAndID> from_name(AtRuleID at_rule_id, FlyString name)
|
||||
{
|
||||
if (is_a_custom_property_name_string(name))
|
||||
return DescriptorNameAndID(move(name), DescriptorID::Custom);
|
||||
|
||||
if (auto descriptor_id = descriptor_id_from_string(at_rule_id, name); descriptor_id.has_value()) {
|
||||
// NB: We use the serialized ID as the name here instead of the input name to ensure that legacy alias
|
||||
// mapping is reflected
|
||||
return DescriptorNameAndID(CSS::to_string(descriptor_id.value()), descriptor_id.value());
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
static DescriptorNameAndID from_id(DescriptorID descriptor_id)
|
||||
{
|
||||
VERIFY(descriptor_id != DescriptorID::Custom);
|
||||
return DescriptorNameAndID(CSS::to_string(descriptor_id), descriptor_id);
|
||||
}
|
||||
|
||||
DescriptorID id() const { return m_id; }
|
||||
|
||||
FlyString const& name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
bool operator==(DescriptorNameAndID const& other) const
|
||||
{
|
||||
return m_id == other.m_id && m_name == other.m_name;
|
||||
}
|
||||
|
||||
private:
|
||||
DescriptorNameAndID(FlyString name, DescriptorID id)
|
||||
: m_name(move(name))
|
||||
, m_id(id)
|
||||
{
|
||||
}
|
||||
|
||||
FlyString m_name;
|
||||
DescriptorID m_id;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace AK {
|
||||
|
||||
template<>
|
||||
struct Traits<Web::CSS::DescriptorNameAndID> : public DefaultTraits<Web::CSS::DescriptorNameAndID> {
|
||||
static unsigned hash(Web::CSS::DescriptorNameAndID const& descriptor_name_and_id)
|
||||
{
|
||||
return pair_int_hash(to_underlying(descriptor_name_and_id.id()), descriptor_name_and_id.name().hash());
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -96,7 +96,7 @@ GC::Ref<FontFace> FontFace::construct_impl(JS::Realm& realm, String family, Font
|
|||
|
||||
Parser::ParsingParams parsing_params { realm };
|
||||
auto try_parse_descriptor = [&parsing_params, &font_face, &realm](DescriptorID descriptor_id, String const& string) -> String {
|
||||
auto result = parse_css_descriptor(parsing_params, AtRuleID::FontFace, descriptor_id, string);
|
||||
auto result = parse_css_descriptor(parsing_params, AtRuleID::FontFace, DescriptorNameAndID::from_id(descriptor_id), string);
|
||||
if (!result) {
|
||||
font_face->reject_status_promise(WebIDL::SyntaxError::create(realm, Utf16String::formatted("FontFace constructor: Invalid {}", to_string(descriptor_id))));
|
||||
return {};
|
||||
|
|
@ -120,7 +120,7 @@ GC::Ref<FontFace> FontFace::construct_impl(JS::Realm& realm, String family, Font
|
|||
font_face->m_line_gap_override = try_parse_descriptor(DescriptorID::LineGapOverride, descriptors.line_gap_override);
|
||||
RefPtr<StyleValue const> parsed_source;
|
||||
if (auto* source_string = source.get_pointer<String>()) {
|
||||
parsed_source = parse_css_descriptor(parsing_params, AtRuleID::FontFace, DescriptorID::Src, *source_string);
|
||||
parsed_source = parse_css_descriptor(parsing_params, AtRuleID::FontFace, DescriptorNameAndID::from_id(DescriptorID::Src), *source_string);
|
||||
if (!parsed_source) {
|
||||
font_face->reject_status_promise(WebIDL::SyntaxError::create(realm, Utf16String::formatted("FontFace constructor: Invalid {}", to_string(DescriptorID::Src))));
|
||||
}
|
||||
|
|
@ -238,7 +238,7 @@ GC::Ref<FontFace> FontFace::create_css_connected(JS::Realm& realm, CSSFontFaceRu
|
|||
font_face->m_css_font_face_rule = &rule;
|
||||
font_face->reparse_connected_css_font_face_rule_descriptors();
|
||||
|
||||
if (auto src_value = rule.descriptors()->descriptor(DescriptorID::Src)) {
|
||||
if (auto src_value = rule.descriptors()->descriptor(DescriptorNameAndID::from_id(DescriptorID::Src))) {
|
||||
font_face->m_urls = ParsedFontFace::sources_from_style_value(*src_value);
|
||||
font_face->m_urls.remove_all_matching(is_unsupported_source);
|
||||
}
|
||||
|
|
@ -252,17 +252,17 @@ void FontFace::reparse_connected_css_font_face_rule_descriptors()
|
|||
{
|
||||
auto const& descriptors = m_css_font_face_rule->descriptors();
|
||||
|
||||
set_family_impl(*descriptors->descriptor(DescriptorID::FontFamily));
|
||||
set_style_impl(*descriptors->descriptor_or_initial_value(DescriptorID::FontStyle));
|
||||
set_weight_impl(*descriptors->descriptor_or_initial_value(DescriptorID::FontWeight));
|
||||
set_stretch_impl(*descriptors->descriptor_or_initial_value(DescriptorID::FontWidth));
|
||||
set_unicode_range_impl(*descriptors->descriptor_or_initial_value(DescriptorID::UnicodeRange));
|
||||
set_feature_settings_impl(*descriptors->descriptor_or_initial_value(DescriptorID::FontFeatureSettings));
|
||||
set_variation_settings_impl(*descriptors->descriptor_or_initial_value(DescriptorID::FontVariationSettings));
|
||||
set_display_impl(*descriptors->descriptor_or_initial_value(DescriptorID::FontDisplay));
|
||||
set_ascent_override_impl(*descriptors->descriptor_or_initial_value(DescriptorID::AscentOverride));
|
||||
set_descent_override_impl(*descriptors->descriptor_or_initial_value(DescriptorID::DescentOverride));
|
||||
set_line_gap_override_impl(*descriptors->descriptor_or_initial_value(DescriptorID::LineGapOverride));
|
||||
set_family_impl(*descriptors->descriptor(DescriptorNameAndID::from_id(DescriptorID::FontFamily)));
|
||||
set_style_impl(*descriptors->descriptor_or_initial_value(DescriptorNameAndID::from_id(DescriptorID::FontStyle)));
|
||||
set_weight_impl(*descriptors->descriptor_or_initial_value(DescriptorNameAndID::from_id(DescriptorID::FontWeight)));
|
||||
set_stretch_impl(*descriptors->descriptor_or_initial_value(DescriptorNameAndID::from_id(DescriptorID::FontWidth)));
|
||||
set_unicode_range_impl(*descriptors->descriptor_or_initial_value(DescriptorNameAndID::from_id(DescriptorID::UnicodeRange)));
|
||||
set_feature_settings_impl(*descriptors->descriptor_or_initial_value(DescriptorNameAndID::from_id(DescriptorID::FontFeatureSettings)));
|
||||
set_variation_settings_impl(*descriptors->descriptor_or_initial_value(DescriptorNameAndID::from_id(DescriptorID::FontVariationSettings)));
|
||||
set_display_impl(*descriptors->descriptor_or_initial_value(DescriptorNameAndID::from_id(DescriptorID::FontDisplay)));
|
||||
set_ascent_override_impl(*descriptors->descriptor_or_initial_value(DescriptorNameAndID::from_id(DescriptorID::AscentOverride)));
|
||||
set_descent_override_impl(*descriptors->descriptor_or_initial_value(DescriptorNameAndID::from_id(DescriptorID::DescentOverride)));
|
||||
set_line_gap_override_impl(*descriptors->descriptor_or_initial_value(DescriptorNameAndID::from_id(DescriptorID::LineGapOverride)));
|
||||
}
|
||||
|
||||
ParsedFontFace FontFace::parsed_font_face() const
|
||||
|
|
@ -342,7 +342,7 @@ WebIDL::ExceptionOr<void> FontFace::set_family(String const& string)
|
|||
// If it does not match the grammar, throw a SyntaxError; otherwise, set the attribute to the serialization of the
|
||||
// parsed value.
|
||||
|
||||
auto property = parse_css_descriptor(Parser::ParsingParams(), AtRuleID::FontFace, DescriptorID::FontFamily, string);
|
||||
auto property = parse_css_descriptor(Parser::ParsingParams(), AtRuleID::FontFace, DescriptorNameAndID::from_id(DescriptorID::FontFamily), string);
|
||||
if (!property)
|
||||
return WebIDL::SyntaxError::create(realm(), "FontFace.family setter: Invalid descriptor value"_utf16);
|
||||
|
||||
|
|
@ -366,7 +366,7 @@ WebIDL::ExceptionOr<void> FontFace::set_style(String const& string)
|
|||
// If it does not match the grammar, throw a SyntaxError; otherwise, set the attribute to the serialization of the
|
||||
// parsed value.
|
||||
|
||||
auto property = parse_css_descriptor(Parser::ParsingParams(), AtRuleID::FontFace, DescriptorID::FontStyle, string);
|
||||
auto property = parse_css_descriptor(Parser::ParsingParams(), AtRuleID::FontFace, DescriptorNameAndID::from_id(DescriptorID::FontStyle), string);
|
||||
if (!property)
|
||||
return WebIDL::SyntaxError::create(realm(), "FontFace.style setter: Invalid descriptor value"_utf16);
|
||||
|
||||
|
|
@ -390,7 +390,7 @@ WebIDL::ExceptionOr<void> FontFace::set_weight(String const& string)
|
|||
// If it does not match the grammar, throw a SyntaxError; otherwise, set the attribute to the serialization of the
|
||||
// parsed value.
|
||||
|
||||
auto property = parse_css_descriptor(Parser::ParsingParams(), AtRuleID::FontFace, DescriptorID::FontWeight, string);
|
||||
auto property = parse_css_descriptor(Parser::ParsingParams(), AtRuleID::FontFace, DescriptorNameAndID::from_id(DescriptorID::FontWeight), string);
|
||||
if (!property)
|
||||
return WebIDL::SyntaxError::create(realm(), "FontFace.weight setter: Invalid descriptor value"_utf16);
|
||||
|
||||
|
|
@ -415,7 +415,7 @@ WebIDL::ExceptionOr<void> FontFace::set_stretch(String const& string)
|
|||
// parsed value.
|
||||
|
||||
// NOTE: font-stretch is now an alias for font-width
|
||||
auto property = parse_css_descriptor(Parser::ParsingParams(), AtRuleID::FontFace, DescriptorID::FontWidth, string);
|
||||
auto property = parse_css_descriptor(Parser::ParsingParams(), AtRuleID::FontFace, DescriptorNameAndID::from_id(DescriptorID::FontWidth), string);
|
||||
if (!property)
|
||||
return WebIDL::SyntaxError::create(realm(), "FontFace.stretch setter: Invalid descriptor value"_utf16);
|
||||
|
||||
|
|
@ -439,7 +439,7 @@ WebIDL::ExceptionOr<void> FontFace::set_unicode_range(String const& string)
|
|||
// If it does not match the grammar, throw a SyntaxError; otherwise, set the attribute to the serialization of the
|
||||
// parsed value.
|
||||
|
||||
auto property = parse_css_descriptor(Parser::ParsingParams(), AtRuleID::FontFace, DescriptorID::UnicodeRange, string);
|
||||
auto property = parse_css_descriptor(Parser::ParsingParams(), AtRuleID::FontFace, DescriptorNameAndID::from_id(DescriptorID::UnicodeRange), string);
|
||||
if (!property)
|
||||
return WebIDL::SyntaxError::create(realm(), "FontFace.unicodeRange setter: Invalid descriptor value"_utf16);
|
||||
|
||||
|
|
@ -463,7 +463,7 @@ WebIDL::ExceptionOr<void> FontFace::set_feature_settings(String const& string)
|
|||
// If it does not match the grammar, throw a SyntaxError; otherwise, set the attribute to the serialization of the
|
||||
// parsed value.
|
||||
|
||||
auto property = parse_css_descriptor(Parser::ParsingParams(), AtRuleID::FontFace, DescriptorID::FontFeatureSettings, string);
|
||||
auto property = parse_css_descriptor(Parser::ParsingParams(), AtRuleID::FontFace, DescriptorNameAndID::from_id(DescriptorID::FontFeatureSettings), string);
|
||||
if (!property)
|
||||
return WebIDL::SyntaxError::create(realm(), "FontFace.featureSettings setter: Invalid descriptor value"_utf16);
|
||||
|
||||
|
|
@ -487,7 +487,7 @@ WebIDL::ExceptionOr<void> FontFace::set_variation_settings(String const& string)
|
|||
// If it does not match the grammar, throw a SyntaxError; otherwise, set the attribute to the serialization of the
|
||||
// parsed value.
|
||||
|
||||
auto property = parse_css_descriptor(Parser::ParsingParams(), AtRuleID::FontFace, DescriptorID::FontVariationSettings, string);
|
||||
auto property = parse_css_descriptor(Parser::ParsingParams(), AtRuleID::FontFace, DescriptorNameAndID::from_id(DescriptorID::FontVariationSettings), string);
|
||||
if (!property)
|
||||
return WebIDL::SyntaxError::create(realm(), "FontFace.variationSettings setter: Invalid descriptor value"_utf16);
|
||||
|
||||
|
|
@ -511,7 +511,7 @@ WebIDL::ExceptionOr<void> FontFace::set_display(String const& string)
|
|||
// If it does not match the grammar, throw a SyntaxError; otherwise, set the attribute to the serialization of the
|
||||
// parsed value.
|
||||
|
||||
auto property = parse_css_descriptor(Parser::ParsingParams(), AtRuleID::FontFace, DescriptorID::FontDisplay, string);
|
||||
auto property = parse_css_descriptor(Parser::ParsingParams(), AtRuleID::FontFace, DescriptorNameAndID::from_id(DescriptorID::FontDisplay), string);
|
||||
if (!property)
|
||||
return WebIDL::SyntaxError::create(realm(), "FontFace.display setter: Invalid descriptor value"_utf16);
|
||||
|
||||
|
|
@ -535,7 +535,7 @@ WebIDL::ExceptionOr<void> FontFace::set_ascent_override(String const& string)
|
|||
// If it does not match the grammar, throw a SyntaxError; otherwise, set the attribute to the serialization of the
|
||||
// parsed value.
|
||||
|
||||
auto property = parse_css_descriptor(Parser::ParsingParams(), AtRuleID::FontFace, DescriptorID::AscentOverride, string);
|
||||
auto property = parse_css_descriptor(Parser::ParsingParams(), AtRuleID::FontFace, DescriptorNameAndID::from_id(DescriptorID::AscentOverride), string);
|
||||
if (!property)
|
||||
return WebIDL::SyntaxError::create(realm(), "FontFace.ascentOverride setter: Invalid descriptor value"_utf16);
|
||||
|
||||
|
|
@ -559,7 +559,7 @@ WebIDL::ExceptionOr<void> FontFace::set_descent_override(String const& string)
|
|||
// If it does not match the grammar, throw a SyntaxError; otherwise, set the attribute to the serialization of the
|
||||
// parsed value.
|
||||
|
||||
auto property = parse_css_descriptor(Parser::ParsingParams(), AtRuleID::FontFace, DescriptorID::DescentOverride, string);
|
||||
auto property = parse_css_descriptor(Parser::ParsingParams(), AtRuleID::FontFace, DescriptorNameAndID::from_id(DescriptorID::DescentOverride), string);
|
||||
if (!property)
|
||||
return WebIDL::SyntaxError::create(realm(), "FontFace.descentOverride setter: Invalid descriptor value"_utf16);
|
||||
|
||||
|
|
@ -583,7 +583,7 @@ WebIDL::ExceptionOr<void> FontFace::set_line_gap_override(String const& string)
|
|||
// If it does not match the grammar, throw a SyntaxError; otherwise, set the attribute to the serialization of the
|
||||
// parsed value.
|
||||
|
||||
auto property = parse_css_descriptor(Parser::ParsingParams(), AtRuleID::FontFace, DescriptorID::LineGapOverride, string);
|
||||
auto property = parse_css_descriptor(Parser::ParsingParams(), AtRuleID::FontFace, DescriptorNameAndID::from_id(DescriptorID::LineGapOverride), string);
|
||||
if (!property)
|
||||
return WebIDL::SyntaxError::create(realm(), "FontFace.lineGapOverride setter: Invalid descriptor value"_utf16);
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ ParsedFontFace ParsedFontFace::from_descriptors(CSSFontFaceDescriptors const& de
|
|||
};
|
||||
|
||||
FlyString font_family;
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::FontFamily))
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorNameAndID::from_id(DescriptorID::FontFamily)))
|
||||
font_family = string_from_style_value(*value);
|
||||
|
||||
ComputationContext computation_context {
|
||||
|
|
@ -73,7 +73,7 @@ ParsedFontFace ParsedFontFace::from_descriptors(CSSFontFaceDescriptors const& de
|
|||
};
|
||||
|
||||
Optional<FontWeightRange> weight;
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::FontWeight)) {
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorNameAndID::from_id(DescriptorID::FontWeight))) {
|
||||
// https://drafts.csswg.org/css-fonts-4/#font-prop-desc
|
||||
// The auto values for these three descriptors have the following effects:
|
||||
// - For font selection purposes, the font is selected as if the appropriate normal value (normal, normal or normal) is chosen
|
||||
|
|
@ -102,7 +102,7 @@ ParsedFontFace ParsedFontFace::from_descriptors(CSSFontFaceDescriptors const& de
|
|||
}
|
||||
|
||||
Optional<int> slope;
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::FontStyle)) {
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorNameAndID::from_id(DescriptorID::FontStyle))) {
|
||||
// https://drafts.csswg.org/css-fonts-4/#font-prop-desc
|
||||
// The auto values for these three descriptors have the following effects:
|
||||
// - For font selection purposes, the font is selected as if the appropriate normal value (normal, normal or normal) is chosen
|
||||
|
|
@ -115,7 +115,7 @@ ParsedFontFace ParsedFontFace::from_descriptors(CSSFontFaceDescriptors const& de
|
|||
}
|
||||
|
||||
Optional<int> width;
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::FontWidth)) {
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorNameAndID::from_id(DescriptorID::FontWidth))) {
|
||||
// https://drafts.csswg.org/css-fonts-4/#font-prop-desc
|
||||
// The auto values for these three descriptors have the following effects:
|
||||
// - For font selection purposes, the font is selected as if the appropriate normal value (normal, normal or normal) is chosen
|
||||
|
|
@ -128,45 +128,45 @@ ParsedFontFace ParsedFontFace::from_descriptors(CSSFontFaceDescriptors const& de
|
|||
}
|
||||
|
||||
Vector<Source> sources;
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::Src))
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorNameAndID::from_id(DescriptorID::Src)))
|
||||
sources = sources_from_style_value(*value);
|
||||
|
||||
Vector<Gfx::UnicodeRange> unicode_ranges;
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::UnicodeRange)) {
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorNameAndID::from_id(DescriptorID::UnicodeRange))) {
|
||||
for (auto const& range : value->as_value_list().values())
|
||||
unicode_ranges.append(range->as_unicode_range().unicode_range());
|
||||
}
|
||||
|
||||
Optional<Percentage> ascent_override;
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::AscentOverride))
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorNameAndID::from_id(DescriptorID::AscentOverride)))
|
||||
ascent_override = extract_percentage_or_normal(*value);
|
||||
|
||||
Optional<Percentage> descent_override;
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::DescentOverride))
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorNameAndID::from_id(DescriptorID::DescentOverride)))
|
||||
descent_override = extract_percentage_or_normal(*value);
|
||||
|
||||
Optional<Percentage> line_gap_override;
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::LineGapOverride))
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorNameAndID::from_id(DescriptorID::LineGapOverride)))
|
||||
line_gap_override = extract_percentage_or_normal(*value);
|
||||
|
||||
FontDisplay font_display;
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::FontDisplay))
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorNameAndID::from_id(DescriptorID::FontDisplay)))
|
||||
font_display = keyword_to_font_display(value->to_keyword()).value_or(FontDisplay::Auto);
|
||||
|
||||
Optional<FlyString> font_named_instance;
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::FontNamedInstance)) {
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorNameAndID::from_id(DescriptorID::FontNamedInstance))) {
|
||||
if (value->is_string())
|
||||
font_named_instance = value->as_string().string_value();
|
||||
}
|
||||
|
||||
Optional<FlyString> font_language_override;
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::FontLanguageOverride)) {
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorNameAndID::from_id(DescriptorID::FontLanguageOverride))) {
|
||||
if (value->is_string())
|
||||
font_language_override = value->as_string().string_value();
|
||||
}
|
||||
|
||||
Optional<OrderedHashMap<FlyString, i32>> font_feature_settings;
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::FontFeatureSettings)) {
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorNameAndID::from_id(DescriptorID::FontFeatureSettings))) {
|
||||
if (value->to_keyword() == Keyword::Normal) {
|
||||
font_feature_settings.clear();
|
||||
} else if (value->is_value_list()) {
|
||||
|
|
@ -184,7 +184,7 @@ ParsedFontFace ParsedFontFace::from_descriptors(CSSFontFaceDescriptors const& de
|
|||
}
|
||||
|
||||
Optional<OrderedHashMap<FlyString, double>> font_variation_settings;
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorID::FontVariationSettings)) {
|
||||
if (auto value = descriptors.descriptor_or_initial_value(DescriptorNameAndID::from_id(DescriptorID::FontVariationSettings))) {
|
||||
if (value->to_keyword() == Keyword::Normal) {
|
||||
font_variation_settings.clear();
|
||||
} else if (value->is_value_list()) {
|
||||
|
|
|
|||
|
|
@ -22,17 +22,17 @@
|
|||
|
||||
namespace Web::CSS::Parser {
|
||||
|
||||
Parser::ParseErrorOr<NonnullRefPtr<StyleValue const>> Parser::parse_descriptor_value(AtRuleID at_rule_id, DescriptorID descriptor_id, TokenStream<ComponentValue>& unprocessed_tokens)
|
||||
Parser::ParseErrorOr<NonnullRefPtr<StyleValue const>> Parser::parse_descriptor_value(AtRuleID at_rule_id, DescriptorNameAndID const& descriptor_name_and_id, TokenStream<ComponentValue>& unprocessed_tokens)
|
||||
{
|
||||
if (!at_rule_supports_descriptor(at_rule_id, descriptor_id)) {
|
||||
if (!at_rule_supports_descriptor(at_rule_id, descriptor_name_and_id.id())) {
|
||||
ErrorReporter::the().report(UnknownPropertyError {
|
||||
.rule_name = to_string(at_rule_id),
|
||||
.property_name = to_string(descriptor_id),
|
||||
.property_name = descriptor_name_and_id.name(),
|
||||
});
|
||||
return ParseError::SyntaxError;
|
||||
}
|
||||
|
||||
auto context_guard = push_temporary_value_parsing_context(DescriptorContext { at_rule_id, descriptor_id });
|
||||
auto context_guard = push_temporary_value_parsing_context(DescriptorContext { at_rule_id, descriptor_name_and_id.id() });
|
||||
|
||||
Vector<ComponentValue> component_values;
|
||||
while (unprocessed_tokens.has_next_token()) {
|
||||
|
|
@ -48,7 +48,7 @@ Parser::ParseErrorOr<NonnullRefPtr<StyleValue const>> Parser::parse_descriptor_v
|
|||
: Optional<ComputationContext> {};
|
||||
|
||||
TokenStream tokens { component_values };
|
||||
auto metadata = get_descriptor_metadata(at_rule_id, descriptor_id);
|
||||
auto metadata = get_descriptor_metadata(at_rule_id, descriptor_name_and_id.id());
|
||||
for (auto const& option : metadata.syntax) {
|
||||
auto transaction = tokens.begin_transaction();
|
||||
auto parsed_style_value = option.visit(
|
||||
|
|
@ -415,7 +415,7 @@ Parser::ParseErrorOr<NonnullRefPtr<StyleValue const>> Parser::parse_descriptor_v
|
|||
|
||||
ErrorReporter::the().report(InvalidPropertyError {
|
||||
.rule_name = to_string(at_rule_id),
|
||||
.property_name = to_string(descriptor_id),
|
||||
.property_name = descriptor_name_and_id.name(),
|
||||
.value_string = tokens.dump_string(),
|
||||
.description = "Failed to parse."_string,
|
||||
});
|
||||
|
|
@ -425,16 +425,16 @@ Parser::ParseErrorOr<NonnullRefPtr<StyleValue const>> Parser::parse_descriptor_v
|
|||
|
||||
Optional<Descriptor> Parser::convert_to_descriptor(AtRuleID at_rule_id, Declaration const& declaration)
|
||||
{
|
||||
auto descriptor_id = descriptor_id_from_string(at_rule_id, declaration.name);
|
||||
if (!descriptor_id.has_value())
|
||||
auto descriptor_name_and_id = DescriptorNameAndID::from_name(at_rule_id, declaration.name);
|
||||
if (!descriptor_name_and_id.has_value())
|
||||
return {};
|
||||
|
||||
auto value_token_stream = TokenStream(declaration.value);
|
||||
auto value = parse_descriptor_value(at_rule_id, descriptor_id.value(), value_token_stream);
|
||||
auto value = parse_descriptor_value(at_rule_id, descriptor_name_and_id.value(), value_token_stream);
|
||||
if (value.is_error())
|
||||
return {};
|
||||
|
||||
return Descriptor { *descriptor_id, value.release_value() };
|
||||
return Descriptor { descriptor_name_and_id.value(), value.release_value() };
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,11 +89,11 @@ RefPtr<CSS::StyleValue const> parse_css_type(CSS::Parser::ParsingParams const& c
|
|||
return CSS::Parser::Parser::create(context, string).parse_as_type(value_type);
|
||||
}
|
||||
|
||||
RefPtr<CSS::StyleValue const> parse_css_descriptor(CSS::Parser::ParsingParams const& parsing_params, CSS::AtRuleID at_rule_id, CSS::DescriptorID descriptor_id, StringView string)
|
||||
RefPtr<CSS::StyleValue const> parse_css_descriptor(CSS::Parser::ParsingParams const& parsing_params, CSS::AtRuleID at_rule_id, CSS::DescriptorNameAndID const& descriptor_name_and_id, StringView string)
|
||||
{
|
||||
if (string.is_empty())
|
||||
return nullptr;
|
||||
return CSS::Parser::Parser::create(parsing_params, string).parse_as_descriptor_value(at_rule_id, descriptor_id);
|
||||
return CSS::Parser::Parser::create(parsing_params, string).parse_as_descriptor_value(at_rule_id, descriptor_name_and_id);
|
||||
}
|
||||
|
||||
CSS::CSSRule* parse_css_rule(CSS::Parser::ParsingParams const& context, StringView css_text)
|
||||
|
|
|
|||
|
|
@ -1807,11 +1807,11 @@ RefPtr<StyleValue const> Parser::parse_as_css_value(PropertyID property_id)
|
|||
return parsed_value.release_value();
|
||||
}
|
||||
|
||||
RefPtr<StyleValue const> Parser::parse_as_descriptor_value(AtRuleID at_rule_id, DescriptorID descriptor_id)
|
||||
RefPtr<StyleValue const> Parser::parse_as_descriptor_value(AtRuleID at_rule_id, DescriptorNameAndID const& descriptor_name_and_id)
|
||||
{
|
||||
auto component_values = parse_a_list_of_component_values(m_token_stream);
|
||||
auto tokens = TokenStream(component_values);
|
||||
auto parsed_value = parse_descriptor_value(at_rule_id, descriptor_id, tokens);
|
||||
auto parsed_value = parse_descriptor_value(at_rule_id, descriptor_name_and_id, tokens);
|
||||
if (parsed_value.is_error())
|
||||
return nullptr;
|
||||
return parsed_value.release_value();
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ public:
|
|||
RefPtr<Supports> parse_as_supports();
|
||||
|
||||
RefPtr<StyleValue const> parse_as_css_value(PropertyID);
|
||||
RefPtr<StyleValue const> parse_as_descriptor_value(AtRuleID, DescriptorID);
|
||||
RefPtr<StyleValue const> parse_as_descriptor_value(AtRuleID, DescriptorNameAndID const&);
|
||||
RefPtr<StyleValue const> parse_as_type(ValueType);
|
||||
|
||||
Optional<ComponentValue> parse_as_component_value();
|
||||
|
|
@ -382,7 +382,7 @@ private:
|
|||
RefPtr<RadialGradientStyleValue const> parse_radial_gradient_function(TokenStream<ComponentValue>&);
|
||||
|
||||
ParseErrorOr<NonnullRefPtr<StyleValue const>> parse_css_value(PropertyID, TokenStream<ComponentValue>&, Optional<String> original_source_text = {});
|
||||
ParseErrorOr<NonnullRefPtr<StyleValue const>> parse_descriptor_value(AtRuleID, DescriptorID, TokenStream<ComponentValue>&);
|
||||
ParseErrorOr<NonnullRefPtr<StyleValue const>> parse_descriptor_value(AtRuleID, DescriptorNameAndID const&, TokenStream<ComponentValue>&);
|
||||
RefPtr<StyleValue const> parse_positional_value_list_shorthand(PropertyID, TokenStream<ComponentValue>&);
|
||||
RefPtr<StyleValue const> parse_css_value_for_property(PropertyID, TokenStream<ComponentValue>&);
|
||||
struct PropertyAndValue {
|
||||
|
|
@ -645,7 +645,7 @@ CSS::Parser::Parser::PropertiesAndCustomProperties parse_css_property_declaratio
|
|||
Vector<CSS::Descriptor> parse_css_descriptor_declaration_block(CSS::Parser::ParsingParams const&, CSS::AtRuleID, StringView);
|
||||
RefPtr<CSS::StyleValue const> parse_css_value(CSS::Parser::ParsingParams const&, StringView, CSS::PropertyID);
|
||||
RefPtr<CSS::StyleValue const> parse_css_type(CSS::Parser::ParsingParams const&, StringView, CSS::ValueType);
|
||||
RefPtr<CSS::StyleValue const> parse_css_descriptor(CSS::Parser::ParsingParams const&, CSS::AtRuleID, CSS::DescriptorID, StringView);
|
||||
RefPtr<CSS::StyleValue const> parse_css_descriptor(CSS::Parser::ParsingParams const&, CSS::AtRuleID, CSS::DescriptorNameAndID const&, StringView);
|
||||
Optional<CSS::SelectorList> parse_selector(CSS::Parser::ParsingParams const&, StringView);
|
||||
Optional<CSS::SelectorList> parse_selector_for_nested_style_rule(CSS::Parser::ParsingParams const&, StringView);
|
||||
Optional<CSS::PageSelectorList> parse_page_selector_list(CSS::Parser::ParsingParams const&, StringView);
|
||||
|
|
|
|||
|
|
@ -56,8 +56,8 @@ public:
|
|||
|
||||
void append(Descriptor&& descriptor)
|
||||
{
|
||||
if (is_shorthand(m_at_rule, descriptor.descriptor_id)) {
|
||||
for_each_expanded_longhand(m_at_rule, descriptor.descriptor_id, descriptor.value, [this](auto longhand_id, auto longhand_value) {
|
||||
if (is_shorthand(m_at_rule, descriptor.descriptor_name_and_id)) {
|
||||
for_each_expanded_longhand(m_at_rule, descriptor.descriptor_name_and_id, descriptor.value, [this](auto longhand_id, auto longhand_value) {
|
||||
append_internal(Descriptor { longhand_id, longhand_value.release_nonnull() });
|
||||
});
|
||||
return;
|
||||
|
|
@ -74,19 +74,19 @@ public:
|
|||
private:
|
||||
void append_internal(Descriptor&& descriptor)
|
||||
{
|
||||
if (m_seen_descriptor_ids.contains(descriptor.descriptor_id)) {
|
||||
if (m_seen_descriptor_ids.contains(descriptor.descriptor_name_and_id)) {
|
||||
m_descriptors.remove_first_matching([&descriptor](Descriptor const& existing) {
|
||||
return existing.descriptor_id == descriptor.descriptor_id;
|
||||
return existing.descriptor_name_and_id == descriptor.descriptor_name_and_id;
|
||||
});
|
||||
} else {
|
||||
m_seen_descriptor_ids.set(descriptor.descriptor_id);
|
||||
m_seen_descriptor_ids.set(descriptor.descriptor_name_and_id);
|
||||
}
|
||||
m_descriptors.append(move(descriptor));
|
||||
}
|
||||
|
||||
AtRuleID m_at_rule;
|
||||
Vector<Descriptor> m_descriptors;
|
||||
HashTable<DescriptorID> m_seen_descriptor_ids;
|
||||
HashTable<DescriptorNameAndID> m_seen_descriptor_ids;
|
||||
};
|
||||
|
||||
GC::Ptr<CSSRule> Parser::convert_to_rule(Rule const& rule, Nested nested)
|
||||
|
|
@ -756,12 +756,12 @@ GC::Ptr<CSSPropertyRule> Parser::convert_to_property_rule(AtRule const& rule)
|
|||
|
||||
rule.for_each_as_declaration_list([&](auto& declaration) {
|
||||
if (auto descriptor = convert_to_descriptor(AtRuleID::Property, declaration); descriptor.has_value()) {
|
||||
if (descriptor->descriptor_id == DescriptorID::Syntax) {
|
||||
if (descriptor->descriptor_name_and_id.id() == DescriptorID::Syntax) {
|
||||
if (descriptor->value->is_string())
|
||||
syntax_maybe = descriptor->value->as_string().string_value();
|
||||
return;
|
||||
}
|
||||
if (descriptor->descriptor_id == DescriptorID::Inherits) {
|
||||
if (descriptor->descriptor_name_and_id.id() == DescriptorID::Inherits) {
|
||||
switch (descriptor->value->to_keyword()) {
|
||||
case Keyword::True:
|
||||
inherits_maybe = true;
|
||||
|
|
@ -774,7 +774,7 @@ GC::Ptr<CSSPropertyRule> Parser::convert_to_property_rule(AtRule const& rule)
|
|||
}
|
||||
return;
|
||||
}
|
||||
if (descriptor->descriptor_id == DescriptorID::InitialValue) {
|
||||
if (descriptor->descriptor_name_and_id.id() == DescriptorID::InitialValue) {
|
||||
initial_value_maybe = *descriptor->value;
|
||||
return;
|
||||
}
|
||||
|
|
@ -893,7 +893,7 @@ GC::Ptr<CSSCounterStyleRule> Parser::convert_to_counter_style_rule(AtRule const&
|
|||
if (!descriptor.has_value())
|
||||
return;
|
||||
|
||||
switch (descriptor->descriptor_id) {
|
||||
switch (descriptor->descriptor_name_and_id.id()) {
|
||||
case DescriptorID::System:
|
||||
system = descriptor->value;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -685,7 +685,7 @@ void dump_descriptors(StringBuilder& builder, CSS::CSSDescriptors const& descrip
|
|||
builder.appendff("Declarations ({}):\n", descriptors.length());
|
||||
for (auto const& descriptor : descriptors.descriptors()) {
|
||||
dump_indent(builder, indent_levels);
|
||||
builder.appendff(" {}: '{}'", CSS::to_string(descriptor.descriptor_id), descriptor.value->to_string(CSS::SerializationMode::Normal));
|
||||
builder.appendff(" {}: '{}'", descriptor.descriptor_name_and_id.name(), descriptor.value->to_string(CSS::SerializationMode::Normal));
|
||||
builder.append('\n');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ enum class DescriptorID : @descriptor_id_underlying_type@ {
|
|||
member_generator.appendln(" @name:titlecase@,");
|
||||
}
|
||||
generator.append(R"~~~(
|
||||
Custom,
|
||||
};
|
||||
|
||||
Optional<DescriptorID> descriptor_id_from_string(AtRuleID, StringView);
|
||||
|
|
@ -197,6 +198,13 @@ Optional<DescriptorID> descriptor_id_from_string(AtRuleID at_rule_id, StringView
|
|||
case AtRuleID::@at_rule:titlecase@:
|
||||
)~~~");
|
||||
|
||||
if (at_rule.has_object("custom-descriptors"sv)) {
|
||||
at_rule_generator.append(R"~~~(
|
||||
if (is_a_custom_property_name_string(string))
|
||||
return DescriptorID::Custom;
|
||||
)~~~");
|
||||
}
|
||||
|
||||
auto const& descriptors = at_rule.get_object("descriptors"sv).value();
|
||||
|
||||
descriptors.for_each_member([&](auto const& descriptor_name, JsonValue const& descriptor_value) {
|
||||
|
|
@ -242,6 +250,8 @@ FlyString to_string(DescriptorID descriptor_id)
|
|||
}
|
||||
|
||||
generator.append(R"~~~(
|
||||
case DescriptorID::Custom:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
|
@ -271,6 +281,12 @@ bool at_rule_supports_descriptor(AtRuleID at_rule_id, DescriptorID descriptor_id
|
|||
descriptor_generator.appendln(" case DescriptorID::@descriptor:titlecase@:");
|
||||
});
|
||||
|
||||
if (at_rule.has_object("custom-descriptors"sv)) {
|
||||
at_rule_generator.append(R"~~~(
|
||||
case DescriptorID::Custom:
|
||||
)~~~");
|
||||
}
|
||||
|
||||
at_rule_generator.append(R"~~~(
|
||||
return true;
|
||||
default:
|
||||
|
|
@ -323,7 +339,7 @@ RefPtr<StyleValue const> descriptor_initial_value(AtRuleID at_rule_id, Descripto
|
|||
descriptor_generator.set("initial_value_string", initial_value.value());
|
||||
descriptor_generator.append(R"~~~(
|
||||
case DescriptorID::@descriptor:titlecase@: {
|
||||
auto parsed_value = parse_css_descriptor(parsing_params, AtRuleID::@at_rule:titlecase@, DescriptorID::@descriptor:titlecase@, "@initial_value_string@"sv);
|
||||
auto parsed_value = parse_css_descriptor(parsing_params, AtRuleID::@at_rule:titlecase@, DescriptorNameAndID::from_id(DescriptorID::@descriptor:titlecase@), "@initial_value_string@"sv);
|
||||
VERIFY(!parsed_value.is_null());
|
||||
auto initial_value = parsed_value.release_nonnull();
|
||||
initial_values[to_underlying(at_rule_id)][to_underlying(descriptor_id)] = initial_value;
|
||||
|
|
@ -365,19 +381,7 @@ DescriptorMetadata get_descriptor_metadata(AtRuleID at_rule_id, DescriptorID des
|
|||
switch (descriptor_id) {
|
||||
)~~~");
|
||||
|
||||
auto const& descriptors = at_rule.get_object("descriptors"sv).value();
|
||||
descriptors.for_each_member([&](auto const& descriptor_name, JsonValue const& descriptor_value) {
|
||||
auto const& descriptor = descriptor_value.as_object();
|
||||
if (is_legacy_alias(descriptor))
|
||||
return;
|
||||
|
||||
auto descriptor_generator = at_rule_generator.fork();
|
||||
descriptor_generator.set("descriptor:titlecase", title_casify(descriptor_name));
|
||||
descriptor_generator.append(R"~~~(
|
||||
case DescriptorID::@descriptor:titlecase@: {
|
||||
DescriptorMetadata metadata;
|
||||
)~~~");
|
||||
auto const& syntax = descriptor.get_array("syntax"sv).value();
|
||||
auto const generate_syntax_list = [&](SourceGenerator& descriptor_generator, JsonArray const& syntax) {
|
||||
for (auto const& entry : syntax.values()) {
|
||||
auto option_generator = descriptor_generator.fork();
|
||||
auto const& syntax_string = entry.as_string();
|
||||
|
|
@ -446,12 +450,46 @@ DescriptorMetadata get_descriptor_metadata(AtRuleID at_rule_id, DescriptorID des
|
|||
)~~~");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
auto const& descriptors = at_rule.get_object("descriptors"sv).value();
|
||||
descriptors.for_each_member([&](auto const& descriptor_name, JsonValue const& descriptor_value) {
|
||||
auto const& descriptor = descriptor_value.as_object();
|
||||
if (is_legacy_alias(descriptor))
|
||||
return;
|
||||
|
||||
auto descriptor_generator = at_rule_generator.fork();
|
||||
descriptor_generator.set("descriptor:titlecase", title_casify(descriptor_name));
|
||||
descriptor_generator.append(R"~~~(
|
||||
case DescriptorID::@descriptor:titlecase@: {
|
||||
DescriptorMetadata metadata;
|
||||
)~~~");
|
||||
auto const& syntax = descriptor.get_array("syntax"sv).value();
|
||||
|
||||
generate_syntax_list(descriptor_generator, syntax);
|
||||
|
||||
descriptor_generator.append(R"~~~(
|
||||
return metadata;
|
||||
}
|
||||
)~~~");
|
||||
});
|
||||
|
||||
if (at_rule.has_object("custom-descriptors"sv)) {
|
||||
auto const& custom_descriptors = at_rule.get_object("custom-descriptors"sv).value();
|
||||
|
||||
auto custom_descriptor_generator = at_rule_generator.fork();
|
||||
custom_descriptor_generator.append(R"~~~(
|
||||
case DescriptorID::Custom: {
|
||||
DescriptorMetadata metadata;
|
||||
)~~~");
|
||||
auto const& syntax = custom_descriptors.get_array("syntax"sv).value();
|
||||
generate_syntax_list(custom_descriptor_generator, syntax);
|
||||
custom_descriptor_generator.append(R"~~~(
|
||||
return metadata;
|
||||
}
|
||||
)~~~");
|
||||
}
|
||||
|
||||
at_rule_generator.append(R"~~~(
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
|
|
|
|||
Loading…
Reference in a new issue