Browse Source

LibHTML: Improve CSS parser's handling of values somewhat

Now we just skip over url() and rgb() instead of crashing on them.
Andreas Kling 5 năm trước cách đây
mục cha
commit
94bc46ee70
1 tập tin đã thay đổi với 69 bổ sung23 xóa
  1. 69 23
      Libraries/LibHTML/Parser/CSSParser.cpp

+ 69 - 23
Libraries/LibHTML/Parser/CSSParser.cpp

@@ -374,6 +374,72 @@ public:
         return ch && ch != '!' && ch != ';' && ch != '}';
     }
 
+    struct ValueAndImportant {
+        String value;
+        bool important { false };
+    };
+
+    ValueAndImportant consume_css_value()
+    {
+        buffer.clear();
+
+        int paren_nesting_level = 0;
+        bool important = false;
+
+        for (;;) {
+            char ch = peek();
+            if (ch == '(') {
+                ++paren_nesting_level;
+                buffer.append(consume_one());
+                continue;
+            }
+            if (ch == ')') {
+                PARSE_ASSERT(paren_nesting_level > 0);
+                --paren_nesting_level;
+                buffer.append(consume_one());
+                continue;
+            }
+            if (paren_nesting_level > 0) {
+                buffer.append(consume_one());
+                continue;
+            }
+            if (next_is("!important")) {
+                consume_specific('!');
+                consume_specific('i');
+                consume_specific('m');
+                consume_specific('p');
+                consume_specific('o');
+                consume_specific('r');
+                consume_specific('t');
+                consume_specific('a');
+                consume_specific('n');
+                consume_specific('t');
+                important = true;
+                continue;
+            }
+            if (next_is("/*")) {
+                consume_whitespace_or_comments();
+                continue;
+            }
+            if (!ch)
+                break;
+            if (ch == '}')
+                break;
+            if (ch == ';')
+                break;
+            buffer.append(consume_one());
+        }
+
+        // Remove trailing whitespace.
+        while (!buffer.is_empty() && isspace(buffer.last()))
+            buffer.take_last();
+
+        auto string = String::copy(buffer);
+        buffer.clear();
+
+        return { string, important };
+    }
+
     Optional<StyleProperty> parse_property()
     {
         consume_whitespace_or_comments();
@@ -391,36 +457,16 @@ public:
         consume_whitespace_or_comments();
         consume_specific(':');
         consume_whitespace_or_comments();
-        while (is_valid_property_value_char(peek()))
-            buffer.append(consume_one());
 
-        // Remove trailing whitespace.
-        while (!buffer.is_empty() && isspace(buffer.last()))
-            buffer.take_last();
+        auto [property_value, important] = consume_css_value();
 
-        auto property_value = String::copy(buffer);
-        buffer.clear();
         consume_whitespace_or_comments();
-        bool is_important = false;
-        if (peek() == '!') {
-            consume_specific('!');
-            consume_specific('i');
-            consume_specific('m');
-            consume_specific('p');
-            consume_specific('o');
-            consume_specific('r');
-            consume_specific('t');
-            consume_specific('a');
-            consume_specific('n');
-            consume_specific('t');
-            consume_whitespace_or_comments();
-            is_important = true;
-        }
+
         if (peek() && peek() != '}')
             consume_specific(';');
 
         auto property_id = CSS::property_id_from_string(property_name);
-        return StyleProperty { property_id, parse_css_value(property_value), is_important };
+        return StyleProperty { property_id, parse_css_value(property_value), important };
     }
 
     void parse_declaration()