diff --git a/Userland/Libraries/LibWeb/CSS/MediaList.cpp b/Userland/Libraries/LibWeb/CSS/MediaList.cpp index aa8097f256..b723800519 100644 --- a/Userland/Libraries/LibWeb/CSS/MediaList.cpp +++ b/Userland/Libraries/LibWeb/CSS/MediaList.cpp @@ -67,4 +67,21 @@ void MediaList::delete_medium(String medium) // FIXME: If nothing was removed, then throw a NotFoundError exception. } +bool MediaList::evaluate(DOM::Window const& window) +{ + for (auto& media : m_media) + media.evaluate(window); + + return matches(); +} + +bool MediaList::matches() const +{ + for (auto& media : m_media) { + if (media.matches()) + return true; + } + return false; +} + } diff --git a/Userland/Libraries/LibWeb/CSS/MediaList.h b/Userland/Libraries/LibWeb/CSS/MediaList.h index 4586f731bb..d264654316 100644 --- a/Userland/Libraries/LibWeb/CSS/MediaList.h +++ b/Userland/Libraries/LibWeb/CSS/MediaList.h @@ -29,6 +29,9 @@ public: void append_medium(String); void delete_medium(String); + bool evaluate(DOM::Window const&); + bool matches() const; + private: explicit MediaList(NonnullRefPtrVector&&); diff --git a/Userland/Libraries/LibWeb/CSS/MediaQuery.cpp b/Userland/Libraries/LibWeb/CSS/MediaQuery.cpp index 507d28a48a..83effe782f 100644 --- a/Userland/Libraries/LibWeb/CSS/MediaQuery.cpp +++ b/Userland/Libraries/LibWeb/CSS/MediaQuery.cpp @@ -5,6 +5,8 @@ */ #include +#include +#include namespace Web::CSS { @@ -33,6 +35,59 @@ String MediaQuery::MediaFeature::to_string() const VERIFY_NOT_REACHED(); } +bool MediaQuery::MediaFeature::evaluate(DOM::Window const& window) const +{ + auto queried_value = window.query_media_feature(name); + if (!queried_value) + return false; + + switch (type) { + case Type::IsTrue: + if (queried_value->has_number()) + return queried_value->to_number() != 0; + if (queried_value->has_length()) + return queried_value->to_length().raw_value() != 0; + if (queried_value->has_identifier()) + return queried_value->to_identifier() != ValueID::None; + return false; + + case Type::ExactValue: + return queried_value->equals(*value); + + case Type::MinValue: + if (queried_value->has_number() && value->has_number()) + return queried_value->to_number() >= value->to_number(); + if (queried_value->has_length() && value->has_length()) { + auto queried_length = queried_value->to_length(); + auto value_length = value->to_length(); + // FIXME: We should be checking that lengths are valid during parsing + if (!value_length.is_absolute()) { + dbgln("Media feature was given a non-absolute length, which is invalid! {}", value_length.to_string()); + return false; + } + return queried_length.absolute_length_to_px() >= value_length.absolute_length_to_px(); + } + return false; + + case Type::MaxValue: + if (queried_value->has_number() && value->has_number()) + return queried_value->to_number() <= value->to_number(); + if (queried_value->has_length() && value->has_length()) { + auto queried_length = queried_value->to_length(); + auto value_length = value->to_length(); + // FIXME: We should be checking that lengths are valid during parsing + if (!value_length.is_absolute()) { + dbgln("Media feature was given a non-absolute length, which is invalid! {}", value_length.to_string()); + return false; + } + return queried_length.absolute_length_to_px() <= value_length.absolute_length_to_px(); + } + return false; + } + + VERIFY_NOT_REACHED(); +} + String MediaQuery::MediaCondition::to_string() const { StringBuilder builder; @@ -56,6 +111,33 @@ String MediaQuery::MediaCondition::to_string() const return builder.to_string(); } +bool MediaQuery::MediaCondition::evaluate(DOM::Window const& window) const +{ + switch (type) { + case Type::Single: + return feature.evaluate(window); + + case Type::Not: + return !conditions.first().evaluate(window); + + case Type::And: + for (auto& child : conditions) { + if (!child.evaluate(window)) + return false; + } + return true; + + case Type::Or: + for (auto& child : conditions) { + if (child.evaluate(window)) + return true; + } + return false; + } + + VERIFY_NOT_REACHED(); +} + String MediaQuery::to_string() const { StringBuilder builder; @@ -110,4 +192,39 @@ String MediaQuery::to_string() const return builder.to_string(); } +bool MediaQuery::evaluate(DOM::Window const& window) +{ + auto matches_media = [](MediaType media) -> bool { + switch (media) { + case MediaType::All: + return true; + case MediaType::Print: + // FIXME: Enable for printing, when we have printing! + return false; + case MediaType::Screen: + // FIXME: Disable for printing, when we have printing! + return true; + // Deprecated, must never match: + case MediaType::TTY: + case MediaType::TV: + case MediaType::Projection: + case MediaType::Handheld: + case MediaType::Braille: + case MediaType::Embossed: + case MediaType::Aural: + case MediaType::Speech: + return false; + } + VERIFY_NOT_REACHED(); + }; + + bool result = matches_media(m_media_type); + + if (result && m_media_condition) + result = m_media_condition->evaluate(window); + + m_matches = m_negated ? !result : result; + return m_matches; +} + } diff --git a/Userland/Libraries/LibWeb/CSS/MediaQuery.h b/Userland/Libraries/LibWeb/CSS/MediaQuery.h index 97775333c3..9321525227 100644 --- a/Userland/Libraries/LibWeb/CSS/MediaQuery.h +++ b/Userland/Libraries/LibWeb/CSS/MediaQuery.h @@ -53,6 +53,7 @@ public: FlyString name; RefPtr value { nullptr }; + bool evaluate(DOM::Window const&) const; String to_string() const; }; @@ -69,12 +70,15 @@ public: MediaFeature feature; NonnullOwnPtrVector conditions; + bool evaluate(DOM::Window const&) const; String to_string() const; }; static NonnullRefPtr create_not_all(); static NonnullRefPtr create() { return adopt_ref(*new MediaQuery); } + bool matches() const { return m_matches; } + bool evaluate(DOM::Window const&); String to_string() const; private: @@ -84,6 +88,9 @@ private: bool m_negated { false }; MediaType m_media_type { MediaType::All }; OwnPtr m_media_condition { nullptr }; + + // Cached value, updated by evaluate() + bool m_matches { false }; }; } diff --git a/Userland/Libraries/LibWeb/CSS/MediaQueryList.cpp b/Userland/Libraries/LibWeb/CSS/MediaQueryList.cpp index d3295c3075..f581a96e96 100644 --- a/Userland/Libraries/LibWeb/CSS/MediaQueryList.cpp +++ b/Userland/Libraries/LibWeb/CSS/MediaQueryList.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2021, Linus Groh + * Copyright (c) 2021, Sam Atkins * * SPDX-License-Identifier: BSD-2-Clause */ @@ -18,6 +19,7 @@ MediaQueryList::MediaQueryList(DOM::Document& document, NonnullRefPtrVector #include +#include #include #include #include @@ -18,6 +19,7 @@ namespace Web::CSS { // 4.2. The MediaQueryList Interface, https://drafts.csswg.org/cssom-view/#the-mediaquerylist-interface class MediaQueryList final : public RefCounted + , public Weakable , public DOM::EventTarget , public Bindings::Wrappable { @@ -36,6 +38,7 @@ public: String media() const; bool matches() const; + bool evaluate(); // ^EventTarget virtual void ref_event_target() override { ref(); }