LibWeb: Generate property_accepts_value() function :^)

Previously, we have not been validating the values for CSS declarations
inside the Parser. This causes issues, since we should be discarding
invalid style declarations, so that previous ones are used instead. For
example, in this code:

```css
.foo {
  width: 2em;
  width: orange;
}
```

... the `width: orange` declaration overwrites the `width: 2em` one,
even though it is invalid. According to the spec, `width: orange` should
be rejected at parse time, and discarded, leaving `width: 2em` as the
resulting value.

Many properties (mostly shorthands) are parsed specially, and so they
are already rejected if they are invalid. But for simple properties, we
currently accept any value. With `property_accepts_value()`, we can
check if the value is valid in `parse_css_value()`, and reject it if it
is not.
This commit is contained in:
Sam Atkins 2021-09-22 20:11:15 +01:00 committed by Andreas Kling
parent 633ede5c6c
commit 11d3098f40
Notes: sideshowbarker 2024-07-18 03:32:41 +09:00
2 changed files with 104 additions and 0 deletions

View file

@ -252,6 +252,109 @@ bool property_has_quirk(PropertyID property_id, Quirk quirk)
}
}
bool property_accepts_value(PropertyID property_id, StyleValue& style_value)
{
if (style_value.is_builtin() || style_value.is_custom_property())
return true;
switch (property_id) {
)~~~");
properties.for_each_member([&](auto& name, auto& value) {
VERIFY(value.is_object());
auto& object = value.as_object();
bool has_valid_types = object.has("valid-types");
auto has_valid_identifiers = object.has("valid-identifiers");
if (has_valid_types || has_valid_identifiers) {
auto property_generator = generator.fork();
property_generator.set("name:titlecase", title_casify(name));
property_generator.append(R"~~~(
case PropertyID::@name:titlecase@: {
)~~~");
if (has_valid_types) {
auto valid_types_value = object.get("valid-types");
VERIFY(valid_types_value.is_array());
auto valid_types = valid_types_value.as_array();
if (!valid_types.is_empty()) {
for (auto& type : valid_types.values()) {
VERIFY(type.is_string());
auto type_name = type.as_string();
if (type_name == "color") {
property_generator.append(R"~~~(
if (style_value.is_color())
return true;
)~~~");
} else if (type_name == "image") {
property_generator.append(R"~~~(
if (style_value.is_image())
return true;
)~~~");
} else if (type_name == "length" || type_name == "percentage") {
// FIXME: Handle lengths and percentages separately
property_generator.append(R"~~~(
if (style_value.is_length() || style_value.is_calculated())
return true;
)~~~");
} else if (type_name == "number" || type_name == "integer") {
// FIXME: Handle integers separately
property_generator.append(R"~~~(
if (style_value.is_numeric())
return true;
)~~~");
} else if (type_name == "string") {
property_generator.append(R"~~~(
if (style_value.is_string())
return true;
)~~~");
} else if (type_name == "url") {
// FIXME: Handle urls!
} else {
warnln("Unrecognized valid-type name: '{}'", type_name);
VERIFY_NOT_REACHED();
}
}
}
}
if (has_valid_identifiers) {
auto valid_identifiers_value = object.get("valid-identifiers");
VERIFY(valid_identifiers_value.is_array());
auto valid_identifiers = valid_identifiers_value.as_array();
if (!valid_identifiers.is_empty()) {
property_generator.append(R"~~~(
switch (style_value.to_identifier()) {
)~~~");
for (auto& identifier : valid_identifiers.values()) {
VERIFY(identifier.is_string());
auto identifier_generator = generator.fork();
identifier_generator.set("identifier:titlecase", title_casify(identifier.as_string()));
identifier_generator.append(R"~~~(
case ValueID::@identifier:titlecase@:
)~~~");
}
property_generator.append(R"~~~(
return true;
default:
break;
}
)~~~");
}
}
generator.append(R"~~~(
return false;
}
)~~~");
}
});
generator.append(R"~~~(
default:
return true;
}
}
size_t property_maximum_value_count(PropertyID property_id)
{
switch (property_id) {

View file

@ -106,6 +106,7 @@ bool is_inherited_property(PropertyID);
bool is_pseudo_property(PropertyID);
RefPtr<StyleValue> property_initial_value(PropertyID);
bool property_accepts_value(PropertyID, StyleValue&);
size_t property_maximum_value_count(PropertyID);
constexpr PropertyID first_property_id = PropertyID::@first_property_id@;