diff --git a/Userland/Libraries/LibWeb/CSS/MediaQuery.cpp b/Userland/Libraries/LibWeb/CSS/MediaQuery.cpp index 73c9827927..b16c4fa335 100644 --- a/Userland/Libraries/LibWeb/CSS/MediaQuery.cpp +++ b/Userland/Libraries/LibWeb/CSS/MediaQuery.cpp @@ -25,6 +25,7 @@ String MediaFeatureValue::to_string() const return m_value.visit( [](String const& ident) { return serialize_an_identifier(ident); }, [](Length const& length) { return length.to_string(); }, + [](Ratio const& ratio) { return ratio.to_string(); }, [](Resolution const& resolution) { return resolution.to_string(); }, [](double number) { return String::number(number); }); } @@ -34,6 +35,7 @@ bool MediaFeatureValue::is_same_type(MediaFeatureValue const& other) const return m_value.visit( [&](String const&) { return other.is_ident(); }, [&](Length const&) { return other.is_length(); }, + [&](Ratio const&) { return other.is_ratio(); }, [&](Resolution const&) { return other.is_resolution(); }, [&](double) { return other.is_number(); }); } @@ -88,6 +90,9 @@ bool MediaFeature::evaluate(DOM::Window const& window) const return queried_value.number() != 0; if (queried_value.is_length()) return queried_value.length().raw_value() != 0; + // FIXME: I couldn't figure out from the spec how ratios should be evaluated in a boolean context. + if (queried_value.is_ratio()) + return !queried_value.ratio().is_degenerate(); if (queried_value.is_resolution()) return queried_value.resolution().to_dots_per_pixel() != 0; if (queried_value.is_ident()) @@ -181,6 +186,25 @@ bool MediaFeature::compare(DOM::Window const& window, MediaFeatureValue left, Co VERIFY_NOT_REACHED(); } + if (left.is_ratio()) { + auto left_decimal = left.ratio().value(); + auto right_decimal = right.ratio().value(); + + switch (comparison) { + case Comparison::Equal: + return left_decimal == right_decimal; + case Comparison::LessThan: + return left_decimal < right_decimal; + case Comparison::LessThanOrEqual: + return left_decimal <= right_decimal; + case Comparison::GreaterThan: + return left_decimal > right_decimal; + case Comparison::GreaterThanOrEqual: + return left_decimal >= right_decimal; + } + VERIFY_NOT_REACHED(); + } + if (left.is_resolution()) { auto left_dppx = left.resolution().to_dots_per_pixel(); auto right_dppx = right.resolution().to_dots_per_pixel(); diff --git a/Userland/Libraries/LibWeb/CSS/MediaQuery.h b/Userland/Libraries/LibWeb/CSS/MediaQuery.h index 93392e31c5..60871335d2 100644 --- a/Userland/Libraries/LibWeb/CSS/MediaQuery.h +++ b/Userland/Libraries/LibWeb/CSS/MediaQuery.h @@ -13,6 +13,7 @@ #include #include #include +#include #include namespace Web::CSS { @@ -30,6 +31,11 @@ public: { } + explicit MediaFeatureValue(Ratio ratio) + : m_value(move(ratio)) + { + } + explicit MediaFeatureValue(Resolution resolution) : m_value(move(resolution)) { @@ -45,6 +51,7 @@ public: bool is_ident() const { return m_value.has(); } bool is_length() const { return m_value.has(); } bool is_number() const { return m_value.has(); } + bool is_ratio() const { return m_value.has(); } bool is_resolution() const { return m_value.has(); } bool is_same_type(MediaFeatureValue const& other) const; @@ -60,6 +67,12 @@ public: return m_value.get(); } + Ratio const& ratio() const + { + VERIFY(is_ratio()); + return m_value.get(); + } + Resolution const& resolution() const { VERIFY(is_resolution()); @@ -73,8 +86,7 @@ public: } private: - // TODO: Support once we have that. - Variant m_value; + Variant m_value; }; // https://www.w3.org/TR/mediaqueries-4/#mq-features diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index e6e171b5fc..8fa6a84ecc 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -1153,13 +1153,14 @@ Optional Parser::parse_media_feature_value(TokenStream` - if (first.is(Token::Type::Number)) + if (first.is(Token::Type::Number) && !tokens.has_next_token()) return MediaFeatureValue(first.token().number_value()); // `` - if (auto dimension = parse_dimension(first); dimension.has_value()) { + if (auto dimension = parse_dimension(first); dimension.has_value() && !tokens.has_next_token()) { if (dimension->is_length()) return MediaFeatureValue(dimension->length()); if (dimension->is_resolution()) @@ -1167,10 +1168,15 @@ Optional Parser::parse_media_feature_value(TokenStream` - if (first.is(Token::Type::Ident)) + if (first.is(Token::Type::Ident) && !tokens.has_next_token()) return MediaFeatureValue(first.token().ident()); - // FIXME: ``, once we have ratios. + // `` + // Note that a single is a valid , but it gets parsed above as a . + // This will get solved with directed parsing of values based on the media-feature. + tokens.rewind_to_position(position); + if (auto ratio = parse_ratio(tokens); ratio.has_value() && !tokens.has_next_token()) + return MediaFeatureValue(ratio.release_value()); tokens.rewind_to_position(position); return {}; diff --git a/Userland/Libraries/LibWeb/DOM/Window.cpp b/Userland/Libraries/LibWeb/DOM/Window.cpp index a5dd1c9c65..bf181124f0 100644 --- a/Userland/Libraries/LibWeb/DOM/Window.cpp +++ b/Userland/Libraries/LibWeb/DOM/Window.cpp @@ -381,7 +381,8 @@ Optional Window::query_media_feature(FlyString const& na return CSS::MediaFeatureValue("hover"); if (name.equals_ignoring_case("any-pointer"sv)) return CSS::MediaFeatureValue("fine"); - // FIXME: aspect-ratio + if (name.equals_ignoring_case("aspect-ratio"sv)) + return CSS::MediaFeatureValue(CSS::Ratio(inner_width(), inner_height())); if (name.equals_ignoring_case("color"sv)) return CSS::MediaFeatureValue(8); if (name.equals_ignoring_case("color-gamut"sv))