Browse Source

LibWeb: Use StyleComponentValueRules for StyleBlockRule's values

Noticed while doing this that attribute selectors have two different
ways of saying "starts with", and so AttributeMatchType::StartsWith
needs a better name. But I'll change that when I add the missing
types.

These class names are a mouthful to fit in a commit message. :^)
Sam Atkins 4 years ago
parent
commit
29d78bba4b

+ 51 - 13
Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp

@@ -152,31 +152,69 @@ Vector<CSS::Selector::ComplexSelector> Parser::parse_selectors(Vector<StyleCompo
         // FIXME: Attribute selectors want to be their own Selector::SimpleSelector::Type according to the spec.
         // FIXME: Attribute selectors want to be their own Selector::SimpleSelector::Type according to the spec.
         if (current_value.is_block() && current_value.block().is_square()) {
         if (current_value.is_block() && current_value.block().is_square()) {
 
 
-            Vector<String> attribute_parts = current_value.block().values();
+            Vector<StyleComponentValueRule> const& attribute_parts = current_value.block().values();
+
+            // FIXME: Handle namespace prefix for attribute name.
+            auto& attribute_part = attribute_parts.first();
+            if (!attribute_part.is(Token::TokenType::Ident)) {
+                dbgln("Expected ident for attribute name, got: '{}'", attribute_part.to_string());
+                return {};
+            }
 
 
             simple_selector.attribute_match_type = CSS::Selector::SimpleSelector::AttributeMatchType::HasAttribute;
             simple_selector.attribute_match_type = CSS::Selector::SimpleSelector::AttributeMatchType::HasAttribute;
-            simple_selector.attribute_name = attribute_parts.first();
+            simple_selector.attribute_name = attribute_part.token().ident();
 
 
             size_t attribute_index = 1;
             size_t attribute_index = 1;
-            if (attribute_index >= attribute_parts.size())
-                return simple_selector;
+            while (attribute_parts.at(attribute_index).is(Token::TokenType::Whitespace)) {
+                attribute_index++;
+                if (attribute_index >= attribute_parts.size())
+                    return simple_selector;
+            }
 
 
-            if (attribute_parts.at(attribute_index) == " =") {
+            auto& delim_part = attribute_parts.at(attribute_index);
+            if (!delim_part.is(Token::TokenType::Delim)) {
+                dbgln("Expected a delim for attribute comparison, got: '{}'", delim_part.to_string());
+                return {};
+            }
+
+            if (delim_part.token().delim() == "=") {
                 simple_selector.attribute_match_type = CSS::Selector::SimpleSelector::AttributeMatchType::ExactValueMatch;
                 simple_selector.attribute_match_type = CSS::Selector::SimpleSelector::AttributeMatchType::ExactValueMatch;
                 attribute_index++;
                 attribute_index++;
+            } else {
+                attribute_index++;
+                auto& delim_second_part = attribute_parts.at(attribute_index);
+                if (!(delim_part.is(Token::TokenType::Delim) && delim_part.token().delim() == "=")) {
+                    dbgln("Expected a double delim for attribute comparison, got: '{}{}'", delim_part.to_string(), delim_second_part.to_string());
+                    return {};
+                }
+
+                if (delim_part.token().delim() == "~") {
+                    simple_selector.attribute_match_type = CSS::Selector::SimpleSelector::AttributeMatchType::Contains;
+                    attribute_index++;
+                }
+
+                if (delim_part.token().delim() == "|") {
+                    simple_selector.attribute_match_type = CSS::Selector::SimpleSelector::AttributeMatchType::StartsWith;
+                    attribute_index++;
+                }
             }
             }
 
 
-            if (attribute_parts.at(attribute_index) == " ~") {
-                simple_selector.attribute_match_type = CSS::Selector::SimpleSelector::AttributeMatchType::Contains;
-                attribute_index += 2;
+            while (attribute_parts.at(attribute_index).is(Token::TokenType::Whitespace)) {
+                attribute_index++;
+                if (attribute_index >= attribute_parts.size()) {
+                    dbgln("Attribute selector ended without a value to match.");
+                    return {};
+                }
             }
             }
 
 
-            if (attribute_parts.at(attribute_index) == " |") {
-                simple_selector.attribute_match_type = CSS::Selector::SimpleSelector::AttributeMatchType::StartsWith;
-                attribute_index += 2;
+            auto& value_part = attribute_parts.at(attribute_index);
+            if (!value_part.is(Token::TokenType::Ident) && !value_part.is(Token::TokenType::String)) {
+                dbgln("Expected a string or ident for the value to match attribute against, got: '{}'", value_part.to_string());
+                return {};
             }
             }
+            simple_selector.attribute_value = value_part.token().is_ident() ? value_part.token().ident() : value_part.token().string();
 
 
-            simple_selector.attribute_value = attribute_parts.at(attribute_index);
+            // FIXME: Handle case-sensitivity suffixes. https://www.w3.org/TR/selectors-4/#attribute-case
             return simple_selector;
             return simple_selector;
         }
         }
 
 
@@ -495,7 +533,7 @@ NonnullRefPtr<StyleBlockRule> Parser::consume_a_simple_block()
                 continue;
                 continue;
             }
             }
         }
         }
-        block->m_values.append(value.to_string());
+        block->m_values.append(value);
     }
     }
 }
 }
 
 

+ 3 - 2
Userland/Libraries/LibWeb/CSS/Parser/StyleBlockRule.h

@@ -9,6 +9,7 @@
 
 
 #include <AK/RefCounted.h>
 #include <AK/RefCounted.h>
 #include <AK/Vector.h>
 #include <AK/Vector.h>
+#include <LibWeb/CSS/Parser/StyleComponentValueRule.h>
 #include <LibWeb/CSS/Parser/Token.h>
 #include <LibWeb/CSS/Parser/Token.h>
 
 
 namespace Web::CSS {
 namespace Web::CSS {
@@ -24,12 +25,12 @@ public:
     bool is_paren() const { return m_token.is_open_paren(); }
     bool is_paren() const { return m_token.is_open_paren(); }
     bool is_square() const { return m_token.is_open_square(); }
     bool is_square() const { return m_token.is_open_square(); }
 
 
-    Vector<String> const& values() const { return m_values; }
+    Vector<StyleComponentValueRule> const& values() const { return m_values; }
 
 
     String to_string() const;
     String to_string() const;
 
 
 private:
 private:
     Token m_token;
     Token m_token;
-    Vector<String> m_values;
+    Vector<StyleComponentValueRule> m_values;
 };
 };
 }
 }

+ 1 - 1
Userland/Libraries/LibWeb/CSS/Parser/StyleRules.cpp

@@ -119,7 +119,7 @@ String StyleBlockRule::to_string() const
     StringBuilder builder;
     StringBuilder builder;
 
 
     builder.append(m_token.bracket_string());
     builder.append(m_token.bracket_string());
-    append_raw(builder, ", ", m_values);
+    append_with_to_string(builder, ", ", m_values);
     builder.append(m_token.bracket_mirror_string());
     builder.append(m_token.bracket_mirror_string());
 
 
     return builder.to_string();
     return builder.to_string();