diff --git a/Userland/Libraries/LibWeb/CSS/MediaQuery.cpp b/Userland/Libraries/LibWeb/CSS/MediaQuery.cpp index b273a7a39c..53e286adcd 100644 --- a/Userland/Libraries/LibWeb/CSS/MediaQuery.cpp +++ b/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: diff --git a/Userland/Libraries/LibWeb/CSS/MediaQuery.h b/Userland/Libraries/LibWeb/CSS/MediaQuery.h index b7ef4079b1..14e7b92b77 100644 --- a/Userland/Libraries/LibWeb/CSS/MediaQuery.h +++ b/Userland/Libraries/LibWeb/CSS/MediaQuery.h @@ -69,6 +69,49 @@ private: Variant m_value; }; +// https://www.w3.org/TR/mediaqueries-4/#mq-features +class MediaFeature { +public: + // Corresponds to `` grammar + static MediaFeature boolean(String const& name) + { + return MediaFeature(Type::IsTrue, name); + } + + // Corresponds to `` 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 value = {}) + : m_type(type) + , m_name(move(name)) + , m_value(move(value)) + { + } + + Type m_type; + FlyString m_name; + Optional m_value {}; +}; + class MediaQuery : public RefCounted { 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 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 feature; NonnullOwnPtrVector conditions; Optional general_enclosed; @@ -155,8 +180,8 @@ String serialize_a_media_query_list(NonnullRefPtrVector const&); namespace AK { template<> -struct Formatter : Formatter { - ErrorOr format(FormatBuilder& builder, Web::CSS::MediaQuery::MediaFeature const& media_feature) +struct Formatter : Formatter { + ErrorOr format(FormatBuilder& builder, Web::CSS::MediaFeature const& media_feature) { return Formatter::format(builder, media_feature.to_string()); } diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index 972116b29b..b016f9b9f4 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -860,11 +860,11 @@ OwnPtr Parser::consume_media_condition(TokenStream Parser::consume_media_feature(TokenStream& outer_tokens) +Optional Parser::consume_media_feature(TokenStream& outer_tokens) { outer_tokens.skip_whitespace(); - auto invalid_feature = [&]() -> Optional { + auto invalid_feature = [&]() -> Optional { outer_tokens.reconsume_current_input_token(); return {}; }; @@ -884,12 +884,8 @@ Optional Parser::consume_media_feature(TokenStream Parser::consume_media_feature(TokenStream parse_media_query(TokenStream&); OwnPtr consume_media_condition(TokenStream&); - Optional consume_media_feature(TokenStream&); + Optional consume_media_feature(TokenStream&); Optional consume_media_type(TokenStream&); Optional parse_media_feature_value(TokenStream&);