From 0a4d9c6d313a8fd5e0799dda4c64d2edd8dd1252 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Mon, 27 Sep 2021 17:12:33 +0100 Subject: [PATCH] LibWeb: Partially implement MediaQuery class :^) The main thing that's missing is the actual matching, but this is enough to get started. --- Userland/Libraries/LibWeb/CMakeLists.txt | 1 + Userland/Libraries/LibWeb/CSS/MediaQuery.cpp | 113 ++++++++++++++++++ Userland/Libraries/LibWeb/CSS/MediaQuery.h | 117 +++++++++++++++++++ Userland/Libraries/LibWeb/Forward.h | 2 + 4 files changed, 233 insertions(+) create mode 100644 Userland/Libraries/LibWeb/CSS/MediaQuery.cpp create mode 100644 Userland/Libraries/LibWeb/CSS/MediaQuery.h diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index a2f0517ea04..911e28bd835 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -25,6 +25,7 @@ set(SOURCES CSS/ResolvedCSSStyleDeclaration.cpp CSS/DefaultStyleSheetSource.cpp CSS/Length.cpp + CSS/MediaQuery.cpp CSS/MediaQueryList.cpp CSS/Parser/Parser.cpp CSS/Parser/StyleRules.cpp diff --git a/Userland/Libraries/LibWeb/CSS/MediaQuery.cpp b/Userland/Libraries/LibWeb/CSS/MediaQuery.cpp new file mode 100644 index 00000000000..507d28a48a4 --- /dev/null +++ b/Userland/Libraries/LibWeb/CSS/MediaQuery.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2021, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +namespace Web::CSS { + +NonnullRefPtr MediaQuery::create_not_all() +{ + auto media_query = new MediaQuery; + media_query->m_negated = true; + media_query->m_media_type = MediaType::All; + + return adopt_ref(*media_query); +} + +String MediaQuery::MediaFeature::to_string() const +{ + switch (type) { + case Type::IsTrue: + return name; + case Type::ExactValue: + return String::formatted("{}:{}", name, value->to_string()); + case Type::MinValue: + return String::formatted("min-{}:{}", name, value->to_string()); + case Type::MaxValue: + return String::formatted("max-{}:{}", name, value->to_string()); + } + + VERIFY_NOT_REACHED(); +} + +String MediaQuery::MediaCondition::to_string() const +{ + StringBuilder builder; + builder.append('('); + switch (type) { + case Type::Single: + builder.append(feature.to_string()); + break; + case Type::Not: + builder.append("not "); + builder.append(conditions.first().to_string()); + break; + case Type::And: + builder.join(" and ", conditions); + break; + case Type::Or: + builder.join(" or ", conditions); + break; + } + builder.append(')'); + return builder.to_string(); +} + +String MediaQuery::to_string() const +{ + StringBuilder builder; + + if (m_negated) + builder.append("not "); + + if (m_negated || m_media_type != MediaType::All || !m_media_condition) { + switch (m_media_type) { + case MediaType::All: + builder.append("all"); + break; + case MediaType::Aural: + builder.append("aural"); + break; + case MediaType::Braille: + builder.append("braille"); + break; + case MediaType::Embossed: + builder.append("embossed"); + break; + case MediaType::Handheld: + builder.append("handheld"); + break; + case MediaType::Print: + builder.append("print"); + break; + case MediaType::Projection: + builder.append("projection"); + break; + case MediaType::Screen: + builder.append("screen"); + break; + case MediaType::Speech: + builder.append("speech"); + break; + case MediaType::TTY: + builder.append("tty"); + break; + case MediaType::TV: + builder.append("tv"); + break; + } + if (m_media_condition) + builder.append(" and "); + } + + if (m_media_condition) { + builder.append(m_media_condition->to_string()); + } + + return builder.to_string(); +} + +} diff --git a/Userland/Libraries/LibWeb/CSS/MediaQuery.h b/Userland/Libraries/LibWeb/CSS/MediaQuery.h new file mode 100644 index 00000000000..97775333c38 --- /dev/null +++ b/Userland/Libraries/LibWeb/CSS/MediaQuery.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2021, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace Web::CSS { + +class MediaQuery : public RefCounted { + friend class Parser; + +public: + ~MediaQuery() { } + + // https://www.w3.org/TR/mediaqueries-4/#media-types + enum class MediaType { + All, + Print, + Screen, + + // Deprecated, must never match: + TTY, + TV, + Projection, + Handheld, + Braille, + Embossed, + Aural, + 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; + RefPtr value { nullptr }; + + String to_string() const; + }; + + // https://www.w3.org/TR/mediaqueries-4/#media-conditions + struct MediaCondition { + enum class Type { + Single, + And, + Or, + Not, + }; + + Type type; + MediaFeature feature; + NonnullOwnPtrVector conditions; + + String to_string() const; + }; + + static NonnullRefPtr create_not_all(); + static NonnullRefPtr create() { return adopt_ref(*new MediaQuery); } + + String to_string() const; + +private: + MediaQuery() { } + + // https://www.w3.org/TR/mediaqueries-4/#mq-not + bool m_negated { false }; + MediaType m_media_type { MediaType::All }; + OwnPtr m_media_condition { nullptr }; +}; + +} + +namespace AK { + +template<> +struct Formatter : Formatter { + void format(FormatBuilder& builder, Web::CSS::MediaQuery::MediaFeature const& media_feature) + { + Formatter::format(builder, media_feature.to_string()); + } +}; + +template<> +struct Formatter : Formatter { + void format(FormatBuilder& builder, Web::CSS::MediaQuery::MediaCondition const& media_condition) + { + Formatter::format(builder, media_condition.to_string()); + } +}; + +template<> +struct Formatter : Formatter { + void format(FormatBuilder& builder, Web::CSS::MediaQuery const& media_query) + { + Formatter::format(builder, media_query.to_string()); + } +}; + +} diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index 66f27a3e005..a456b8bae04 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -26,6 +26,8 @@ class CSSStyleRule; class CSSStyleSheet; class ElementInlineCSSStyleDeclaration; class Length; +class MediaQuery; +class MediaQueryList; class PropertyOwningCSSStyleDeclaration; class Screen; class Selector;