Selaa lähdekoodia

LibWeb: Make MediaFeature a top-level class and add factory methods

Web::CSS::MediaQuery::MediaFeature::Type was getting a bit ridiculous!
Also, this moves the detection of "min-" and "max-" media-features into
the MediaFeature itself, since this is an implementation detail, not
part of the spec.
Sam Atkins 3 vuotta sitten
vanhempi
commit
ae4f0000c8

+ 22 - 22
Userland/Libraries/LibWeb/CSS/MediaQuery.cpp

@@ -59,30 +59,30 @@ bool MediaFeatureValue::equals(MediaFeatureValue const& other) const
     VERIFY_NOT_REACHED();
 }
 
-String MediaQuery::MediaFeature::to_string() const
+String MediaFeature::to_string() const
 {
-    switch (type) {
+    switch (m_type) {
     case Type::IsTrue:
-        return name;
+        return m_name;
     case Type::ExactValue:
-        return String::formatted("{}:{}", name, value->to_string());
+        return String::formatted("{}:{}", m_name, m_value->to_string());
     case Type::MinValue:
-        return String::formatted("min-{}:{}", name, value->to_string());
+        return String::formatted("min-{}:{}", m_name, m_value->to_string());
     case Type::MaxValue:
-        return String::formatted("max-{}:{}", name, value->to_string());
+        return String::formatted("max-{}:{}", m_name, m_value->to_string());
     }
 
     VERIFY_NOT_REACHED();
 }
 
-bool MediaQuery::MediaFeature::evaluate(DOM::Window const& window) const
+bool MediaFeature::evaluate(DOM::Window const& window) const
 {
-    auto maybe_queried_value = window.query_media_feature(name);
+    auto maybe_queried_value = window.query_media_feature(m_name);
     if (!maybe_queried_value.has_value())
         return false;
     auto queried_value = maybe_queried_value.release_value();
 
-    switch (type) {
+    switch (m_type) {
     case Type::IsTrue:
         if (queried_value.is_number())
             return queried_value.number() != 0;
@@ -93,18 +93,18 @@ bool MediaQuery::MediaFeature::evaluate(DOM::Window const& window) const
         return false;
 
     case Type::ExactValue:
-        return queried_value.equals(*value);
+        return queried_value.equals(*m_value);
 
     case Type::MinValue:
-        if (!value->is_same_type(queried_value))
+        if (!m_value->is_same_type(queried_value))
             return false;
 
-        if (value->is_number())
-            return queried_value.number() >= value->number();
+        if (m_value->is_number())
+            return queried_value.number() >= m_value->number();
 
-        if (value->is_length()) {
+        if (m_value->is_length()) {
             auto& queried_length = queried_value.length();
-            auto& value_length = value->length();
+            auto& value_length = m_value->length();
             // FIXME: Handle relative lengths. https://www.w3.org/TR/mediaqueries-4/#ref-for-relative-length
             if (!value_length.is_absolute()) {
                 dbgln("Media feature was given a non-absolute length! {}", value_length.to_string());
@@ -116,15 +116,15 @@ bool MediaQuery::MediaFeature::evaluate(DOM::Window const& window) const
         return false;
 
     case Type::MaxValue:
-        if (!value->is_same_type(queried_value))
+        if (!m_value->is_same_type(queried_value))
             return false;
 
-        if (value->is_number())
-            return queried_value.number() <= value->number();
+        if (m_value->is_number())
+            return queried_value.number() <= m_value->number();
 
-        if (value->is_length()) {
+        if (m_value->is_length()) {
             auto& queried_length = queried_value.length();
-            auto& value_length = value->length();
+            auto& value_length = m_value->length();
             // FIXME: Handle relative lengths. https://www.w3.org/TR/mediaqueries-4/#ref-for-relative-length
             if (!value_length.is_absolute()) {
                 dbgln("Media feature was given a non-absolute length! {}", value_length.to_string());
@@ -145,7 +145,7 @@ String MediaQuery::MediaCondition::to_string() const
     builder.append('(');
     switch (type) {
     case Type::Single:
-        builder.append(feature.to_string());
+        builder.append(feature->to_string());
         break;
     case Type::Not:
         builder.append("not ");
@@ -169,7 +169,7 @@ MatchResult MediaQuery::MediaCondition::evaluate(DOM::Window const& window) cons
 {
     switch (type) {
     case Type::Single:
-        return as_match_result(feature.evaluate(window));
+        return as_match_result(feature->evaluate(window));
     case Type::Not:
         return negate(conditions.first().evaluate(window));
     case Type::And:

+ 46 - 21
Userland/Libraries/LibWeb/CSS/MediaQuery.h

@@ -69,6 +69,49 @@ private:
     Variant<String, Length, double> m_value;
 };
 
+// https://www.w3.org/TR/mediaqueries-4/#mq-features
+class MediaFeature {
+public:
+    // Corresponds to `<mf-boolean>` grammar
+    static MediaFeature boolean(String const& name)
+    {
+        return MediaFeature(Type::IsTrue, name);
+    }
+
+    // Corresponds to `<mf-plain>` grammar
+    static MediaFeature plain(String const& name, MediaFeatureValue value)
+    {
+        if (name.starts_with("min-", CaseSensitivity::CaseInsensitive))
+            return MediaFeature(Type::MinValue, name.substring_view(4), move(value));
+        if (name.starts_with("max-", CaseSensitivity::CaseInsensitive))
+            return MediaFeature(Type::MaxValue, name.substring_view(4), move(value));
+        return MediaFeature(Type::ExactValue, move(name), move(value));
+    }
+
+    bool evaluate(DOM::Window const&) const;
+    String to_string() const;
+
+private:
+    // FIXME: Implement range syntax: https://www.w3.org/TR/mediaqueries-4/#mq-ranges
+    enum class Type {
+        IsTrue,
+        ExactValue,
+        MinValue,
+        MaxValue,
+    };
+
+    MediaFeature(Type type, FlyString name, Optional<MediaFeatureValue> value = {})
+        : m_type(type)
+        , m_name(move(name))
+        , m_value(move(value))
+    {
+    }
+
+    Type m_type;
+    FlyString m_name;
+    Optional<MediaFeatureValue> m_value {};
+};
+
 class MediaQuery : public RefCounted<MediaQuery> {
     friend class Parser;
 
@@ -92,24 +135,6 @@ public:
         Speech,
     };
 
-    // https://www.w3.org/TR/mediaqueries-4/#mq-features
-    struct MediaFeature {
-        // FIXME: Implement range syntax: https://www.w3.org/TR/mediaqueries-4/#mq-ranges
-        enum class Type {
-            IsTrue,
-            ExactValue,
-            MinValue,
-            MaxValue,
-        };
-
-        Type type;
-        FlyString name;
-        Optional<MediaFeatureValue> value {};
-
-        bool evaluate(DOM::Window const&) const;
-        String to_string() const;
-    };
-
     // https://www.w3.org/TR/mediaqueries-4/#media-conditions
     struct MediaCondition {
         enum class Type {
@@ -121,7 +146,7 @@ public:
         };
 
         Type type;
-        MediaFeature feature;
+        Optional<MediaFeature> feature;
         NonnullOwnPtrVector<MediaCondition> conditions;
         Optional<GeneralEnclosed> general_enclosed;
 
@@ -155,8 +180,8 @@ String serialize_a_media_query_list(NonnullRefPtrVector<MediaQuery> const&);
 namespace AK {
 
 template<>
-struct Formatter<Web::CSS::MediaQuery::MediaFeature> : Formatter<StringView> {
-    ErrorOr<void> format(FormatBuilder& builder, Web::CSS::MediaQuery::MediaFeature const& media_feature)
+struct Formatter<Web::CSS::MediaFeature> : Formatter<StringView> {
+    ErrorOr<void> format(FormatBuilder& builder, Web::CSS::MediaFeature const& media_feature)
     {
         return Formatter<StringView>::format(builder, media_feature.to_string());
     }

+ 5 - 27
Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp

@@ -860,11 +860,11 @@ OwnPtr<MediaQuery::MediaCondition> Parser::consume_media_condition(TokenStream<S
     return {};
 }
 
-Optional<MediaQuery::MediaFeature> Parser::consume_media_feature(TokenStream<StyleComponentValueRule>& outer_tokens)
+Optional<MediaFeature> Parser::consume_media_feature(TokenStream<StyleComponentValueRule>& outer_tokens)
 {
     outer_tokens.skip_whitespace();
 
-    auto invalid_feature = [&]() -> Optional<MediaQuery::MediaFeature> {
+    auto invalid_feature = [&]() -> Optional<MediaFeature> {
         outer_tokens.reconsume_current_input_token();
         return {};
     };
@@ -884,12 +884,8 @@ Optional<MediaQuery::MediaFeature> Parser::consume_media_feature(TokenStream<Sty
         auto feature_name = name_token.token().ident();
         tokens.skip_whitespace();
 
-        if (!tokens.has_next_token()) {
-            return MediaQuery::MediaFeature {
-                .type = MediaQuery::MediaFeature::Type::IsTrue,
-                .name = feature_name,
-            };
-        }
+        if (!tokens.has_next_token())
+            return MediaFeature::boolean(feature_name);
 
         if (!tokens.next_token().is(Token::Type::Colon))
             return invalid_feature();
@@ -902,25 +898,7 @@ Optional<MediaQuery::MediaFeature> Parser::consume_media_feature(TokenStream<Sty
         if (tokens.has_next_token())
             return invalid_feature();
 
-        if (feature_name.starts_with("min-", CaseSensitivity::CaseInsensitive)) {
-            return MediaQuery::MediaFeature {
-                .type = MediaQuery::MediaFeature::Type::MinValue,
-                .name = feature_name.substring_view(4),
-                .value = value.release_value(),
-            };
-        } else if (feature_name.starts_with("max-", CaseSensitivity::CaseInsensitive)) {
-            return MediaQuery::MediaFeature {
-                .type = MediaQuery::MediaFeature::Type::MaxValue,
-                .name = feature_name.substring_view(4),
-                .value = value.release_value(),
-            };
-        }
-
-        return MediaQuery::MediaFeature {
-            .type = MediaQuery::MediaFeature::Type::ExactValue,
-            .name = feature_name,
-            .value = value.release_value(),
-        };
+        return MediaFeature::plain(feature_name, value.release_value());
     }
 
     return invalid_feature();

+ 1 - 1
Userland/Libraries/LibWeb/CSS/Parser/Parser.h

@@ -236,7 +236,7 @@ private:
 
     NonnullRefPtr<MediaQuery> parse_media_query(TokenStream<StyleComponentValueRule>&);
     OwnPtr<MediaQuery::MediaCondition> consume_media_condition(TokenStream<StyleComponentValueRule>&);
-    Optional<MediaQuery::MediaFeature> consume_media_feature(TokenStream<StyleComponentValueRule>&);
+    Optional<MediaFeature> consume_media_feature(TokenStream<StyleComponentValueRule>&);
     Optional<MediaQuery::MediaType> consume_media_type(TokenStream<StyleComponentValueRule>&);
     Optional<MediaFeatureValue> parse_media_feature_value(TokenStream<StyleComponentValueRule>&);