mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 15:42:44 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									d470e7e817
								
							
						
					
					
						commit
						ae4f0000c8
					
				
					 4 changed files with 74 additions and 71 deletions
				
			
		|  | @ -59,30 +59,30 @@ bool MediaFeatureValue::equals(MediaFeatureValue const& other) const | ||||||
|     VERIFY_NOT_REACHED(); |     VERIFY_NOT_REACHED(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| String MediaQuery::MediaFeature::to_string() const | String MediaFeature::to_string() const | ||||||
| { | { | ||||||
|     switch (type) { |     switch (m_type) { | ||||||
|     case Type::IsTrue: |     case Type::IsTrue: | ||||||
|         return name; |         return m_name; | ||||||
|     case Type::ExactValue: |     case Type::ExactValue: | ||||||
|         return String::formatted("{}:{}", name, value->to_string()); |         return String::formatted("{}:{}", m_name, m_value->to_string()); | ||||||
|     case Type::MinValue: |     case Type::MinValue: | ||||||
|         return String::formatted("min-{}:{}", name, value->to_string()); |         return String::formatted("min-{}:{}", m_name, m_value->to_string()); | ||||||
|     case Type::MaxValue: |     case Type::MaxValue: | ||||||
|         return String::formatted("max-{}:{}", name, value->to_string()); |         return String::formatted("max-{}:{}", m_name, m_value->to_string()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     VERIFY_NOT_REACHED(); |     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()) |     if (!maybe_queried_value.has_value()) | ||||||
|         return false; |         return false; | ||||||
|     auto queried_value = maybe_queried_value.release_value(); |     auto queried_value = maybe_queried_value.release_value(); | ||||||
| 
 | 
 | ||||||
|     switch (type) { |     switch (m_type) { | ||||||
|     case Type::IsTrue: |     case Type::IsTrue: | ||||||
|         if (queried_value.is_number()) |         if (queried_value.is_number()) | ||||||
|             return queried_value.number() != 0; |             return queried_value.number() != 0; | ||||||
|  | @ -93,18 +93,18 @@ bool MediaQuery::MediaFeature::evaluate(DOM::Window const& window) const | ||||||
|         return false; |         return false; | ||||||
| 
 | 
 | ||||||
|     case Type::ExactValue: |     case Type::ExactValue: | ||||||
|         return queried_value.equals(*value); |         return queried_value.equals(*m_value); | ||||||
| 
 | 
 | ||||||
|     case Type::MinValue: |     case Type::MinValue: | ||||||
|         if (!value->is_same_type(queried_value)) |         if (!m_value->is_same_type(queried_value)) | ||||||
|             return false; |             return false; | ||||||
| 
 | 
 | ||||||
|         if (value->is_number()) |         if (m_value->is_number()) | ||||||
|             return queried_value.number() >= value->number(); |             return queried_value.number() >= m_value->number(); | ||||||
| 
 | 
 | ||||||
|         if (value->is_length()) { |         if (m_value->is_length()) { | ||||||
|             auto& queried_length = queried_value.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
 |             // FIXME: Handle relative lengths. https://www.w3.org/TR/mediaqueries-4/#ref-for-relative-length
 | ||||||
|             if (!value_length.is_absolute()) { |             if (!value_length.is_absolute()) { | ||||||
|                 dbgln("Media feature was given a non-absolute length! {}", value_length.to_string()); |                 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; |         return false; | ||||||
| 
 | 
 | ||||||
|     case Type::MaxValue: |     case Type::MaxValue: | ||||||
|         if (!value->is_same_type(queried_value)) |         if (!m_value->is_same_type(queried_value)) | ||||||
|             return false; |             return false; | ||||||
| 
 | 
 | ||||||
|         if (value->is_number()) |         if (m_value->is_number()) | ||||||
|             return queried_value.number() <= value->number(); |             return queried_value.number() <= m_value->number(); | ||||||
| 
 | 
 | ||||||
|         if (value->is_length()) { |         if (m_value->is_length()) { | ||||||
|             auto& queried_length = queried_value.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
 |             // FIXME: Handle relative lengths. https://www.w3.org/TR/mediaqueries-4/#ref-for-relative-length
 | ||||||
|             if (!value_length.is_absolute()) { |             if (!value_length.is_absolute()) { | ||||||
|                 dbgln("Media feature was given a non-absolute length! {}", value_length.to_string()); |                 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('('); |     builder.append('('); | ||||||
|     switch (type) { |     switch (type) { | ||||||
|     case Type::Single: |     case Type::Single: | ||||||
|         builder.append(feature.to_string()); |         builder.append(feature->to_string()); | ||||||
|         break; |         break; | ||||||
|     case Type::Not: |     case Type::Not: | ||||||
|         builder.append("not "); |         builder.append("not "); | ||||||
|  | @ -169,7 +169,7 @@ MatchResult MediaQuery::MediaCondition::evaluate(DOM::Window const& window) cons | ||||||
| { | { | ||||||
|     switch (type) { |     switch (type) { | ||||||
|     case Type::Single: |     case Type::Single: | ||||||
|         return as_match_result(feature.evaluate(window)); |         return as_match_result(feature->evaluate(window)); | ||||||
|     case Type::Not: |     case Type::Not: | ||||||
|         return negate(conditions.first().evaluate(window)); |         return negate(conditions.first().evaluate(window)); | ||||||
|     case Type::And: |     case Type::And: | ||||||
|  |  | ||||||
|  | @ -69,6 +69,49 @@ private: | ||||||
|     Variant<String, Length, double> m_value; |     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> { | class MediaQuery : public RefCounted<MediaQuery> { | ||||||
|     friend class Parser; |     friend class Parser; | ||||||
| 
 | 
 | ||||||
|  | @ -92,24 +135,6 @@ public: | ||||||
|         Speech, |         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
 |     // https://www.w3.org/TR/mediaqueries-4/#media-conditions
 | ||||||
|     struct MediaCondition { |     struct MediaCondition { | ||||||
|         enum class Type { |         enum class Type { | ||||||
|  | @ -121,7 +146,7 @@ public: | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         Type type; |         Type type; | ||||||
|         MediaFeature feature; |         Optional<MediaFeature> feature; | ||||||
|         NonnullOwnPtrVector<MediaCondition> conditions; |         NonnullOwnPtrVector<MediaCondition> conditions; | ||||||
|         Optional<GeneralEnclosed> general_enclosed; |         Optional<GeneralEnclosed> general_enclosed; | ||||||
| 
 | 
 | ||||||
|  | @ -155,8 +180,8 @@ String serialize_a_media_query_list(NonnullRefPtrVector<MediaQuery> const&); | ||||||
| namespace AK { | namespace AK { | ||||||
| 
 | 
 | ||||||
| template<> | template<> | ||||||
| struct Formatter<Web::CSS::MediaQuery::MediaFeature> : Formatter<StringView> { | struct Formatter<Web::CSS::MediaFeature> : Formatter<StringView> { | ||||||
|     ErrorOr<void> format(FormatBuilder& builder, Web::CSS::MediaQuery::MediaFeature const& media_feature) |     ErrorOr<void> format(FormatBuilder& builder, Web::CSS::MediaFeature const& media_feature) | ||||||
|     { |     { | ||||||
|         return Formatter<StringView>::format(builder, media_feature.to_string()); |         return Formatter<StringView>::format(builder, media_feature.to_string()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -860,11 +860,11 @@ OwnPtr<MediaQuery::MediaCondition> Parser::consume_media_condition(TokenStream<S | ||||||
|     return {}; |     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(); |     outer_tokens.skip_whitespace(); | ||||||
| 
 | 
 | ||||||
|     auto invalid_feature = [&]() -> Optional<MediaQuery::MediaFeature> { |     auto invalid_feature = [&]() -> Optional<MediaFeature> { | ||||||
|         outer_tokens.reconsume_current_input_token(); |         outer_tokens.reconsume_current_input_token(); | ||||||
|         return {}; |         return {}; | ||||||
|     }; |     }; | ||||||
|  | @ -884,12 +884,8 @@ Optional<MediaQuery::MediaFeature> Parser::consume_media_feature(TokenStream<Sty | ||||||
|         auto feature_name = name_token.token().ident(); |         auto feature_name = name_token.token().ident(); | ||||||
|         tokens.skip_whitespace(); |         tokens.skip_whitespace(); | ||||||
| 
 | 
 | ||||||
|         if (!tokens.has_next_token()) { |         if (!tokens.has_next_token()) | ||||||
|             return MediaQuery::MediaFeature { |             return MediaFeature::boolean(feature_name); | ||||||
|                 .type = MediaQuery::MediaFeature::Type::IsTrue, |  | ||||||
|                 .name = feature_name, |  | ||||||
|             }; |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         if (!tokens.next_token().is(Token::Type::Colon)) |         if (!tokens.next_token().is(Token::Type::Colon)) | ||||||
|             return invalid_feature(); |             return invalid_feature(); | ||||||
|  | @ -902,25 +898,7 @@ Optional<MediaQuery::MediaFeature> Parser::consume_media_feature(TokenStream<Sty | ||||||
|         if (tokens.has_next_token()) |         if (tokens.has_next_token()) | ||||||
|             return invalid_feature(); |             return invalid_feature(); | ||||||
| 
 | 
 | ||||||
|         if (feature_name.starts_with("min-", CaseSensitivity::CaseInsensitive)) { |         return MediaFeature::plain(feature_name, value.release_value()); | ||||||
|             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 invalid_feature(); |     return invalid_feature(); | ||||||
|  |  | ||||||
|  | @ -236,7 +236,7 @@ private: | ||||||
| 
 | 
 | ||||||
|     NonnullRefPtr<MediaQuery> parse_media_query(TokenStream<StyleComponentValueRule>&); |     NonnullRefPtr<MediaQuery> parse_media_query(TokenStream<StyleComponentValueRule>&); | ||||||
|     OwnPtr<MediaQuery::MediaCondition> consume_media_condition(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<MediaQuery::MediaType> consume_media_type(TokenStream<StyleComponentValueRule>&); | ||||||
|     Optional<MediaFeatureValue> parse_media_feature_value(TokenStream<StyleComponentValueRule>&); |     Optional<MediaFeatureValue> parse_media_feature_value(TokenStream<StyleComponentValueRule>&); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Sam Atkins
						Sam Atkins