Browse Source

LibWeb: Add range-checking to property_accepts_value()

For `number` and `integer` types, you can add a range afterwards to add
a range check, using similar syntax to that used in the CSS specs. For
example:

```json
"font-weight": {
  ...
  "valid-types": [
    "number [1,1000]"
  ],
  ...
}
```

This limits any numbers to the range `1 <= n <= 1000`.
Sam Atkins 3 years ago
parent
commit
b927972da7

+ 21 - 2
Meta/Lagom/Tools/CodeGenerators/LibWeb/Generate_CSS_PropertyID_cpp.cpp

@@ -279,7 +279,9 @@ bool property_accepts_value(PropertyID property_id, StyleValue& style_value)
                 if (!valid_types.is_empty()) {
                     for (auto& type : valid_types.values()) {
                         VERIFY(type.is_string());
-                        auto type_name = type.as_string();
+                        auto type_parts = type.as_string().split_view(' ');
+                        auto type_name = type_parts.first();
+                        auto type_args = type_parts.size() > 1 ? type_parts[1] : ""sv;
                         if (type_name == "color") {
                             property_generator.append(R"~~~(
         if (style_value.is_color())
@@ -298,8 +300,25 @@ bool property_accepts_value(PropertyID property_id, StyleValue& style_value)
 )~~~");
                         } else if (type_name == "number" || type_name == "integer") {
                             // FIXME: Handle integers separately
+                            StringView min_value;
+                            StringView max_value;
+                            if (!type_args.is_empty()) {
+                                VERIFY(type_args.starts_with('[') && type_args.ends_with(']'));
+                                auto comma_index = type_args.find(',').value();
+                                min_value = type_args.substring_view(1, comma_index - 1);
+                                max_value = type_args.substring_view(comma_index + 1, type_args.length() - comma_index - 2);
+                            }
                             property_generator.append(R"~~~(
-        if (style_value.is_numeric())
+        if (style_value.is_numeric())~~~");
+                            if (!min_value.is_empty()) {
+                                property_generator.set("minvalue", min_value);
+                                property_generator.append(" && (style_value.as_number() >= (float)@minvalue@)");
+                            }
+                            if (!max_value.is_empty()) {
+                                property_generator.set("maxvalue", max_value);
+                                property_generator.append(" && (style_value.as_number() <= (float)@maxvalue@)");
+                            }
+                            property_generator.append(R"~~~()
             return true;
 )~~~");
                         } else if (type_name == "string") {

+ 1 - 1
Userland/Libraries/LibWeb/CSS/Properties.json

@@ -668,7 +668,7 @@
     "inherited": true,
     "initial": "normal",
     "valid-types": [
-      "integer"
+      "number [1,1000]"
     ],
     "valid-identifiers": [
       "bold",

+ 6 - 0
Userland/Libraries/LibWeb/CSS/StyleValue.cpp

@@ -98,6 +98,12 @@ bool StyleValue::is_color() const
     return false;
 }
 
+float StyleValue::as_number() const
+{
+    VERIFY(is_numeric());
+    return static_cast<NumericStyleValue const&>(*this).value();
+}
+
 String IdentifierStyleValue::to_string() const
 {
     return CSS::string_from_value_id(m_id);

+ 3 - 0
Userland/Libraries/LibWeb/CSS/StyleValue.h

@@ -290,8 +290,11 @@ public:
         return is_builtin() || is_custom_property() || is_calculated();
     }
 
+    float as_number() const;
+
     virtual String to_string() const = 0;
     virtual Length to_length() const { return {}; }
+
     virtual Color to_color(Layout::NodeWithStyle const&) const { return {}; }
 
     CSS::ValueID to_identifier() const;