LibWeb: Partially implement MediaQuery class :^)

The main thing that's missing is the actual matching, but this is enough
to get started.
This commit is contained in:
Sam Atkins 2021-09-27 17:12:33 +01:00 committed by Andreas Kling
parent b90cc1148a
commit 0a4d9c6d31
Notes: sideshowbarker 2024-07-18 03:15:12 +09:00
4 changed files with 233 additions and 0 deletions

View file

@ -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

View file

@ -0,0 +1,113 @@
/*
* Copyright (c) 2021, Sam Atkins <atkinssj@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/CSS/MediaQuery.h>
namespace Web::CSS {
NonnullRefPtr<MediaQuery> 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();
}
}

View file

@ -0,0 +1,117 @@
/*
* Copyright (c) 2021, Sam Atkins <atkinssj@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/FlyString.h>
#include <AK/NonnullOwnPtrVector.h>
#include <AK/NonnullRefPtr.h>
#include <AK/Optional.h>
#include <AK/OwnPtr.h>
#include <AK/RefCounted.h>
#include <LibWeb/CSS/StyleValue.h>
namespace Web::CSS {
class MediaQuery : public RefCounted<MediaQuery> {
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<StyleValue> 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<MediaCondition> conditions;
String to_string() const;
};
static NonnullRefPtr<MediaQuery> create_not_all();
static NonnullRefPtr<MediaQuery> 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<MediaCondition> m_media_condition { nullptr };
};
}
namespace AK {
template<>
struct Formatter<Web::CSS::MediaQuery::MediaFeature> : Formatter<StringView> {
void format(FormatBuilder& builder, Web::CSS::MediaQuery::MediaFeature const& media_feature)
{
Formatter<StringView>::format(builder, media_feature.to_string());
}
};
template<>
struct Formatter<Web::CSS::MediaQuery::MediaCondition> : Formatter<StringView> {
void format(FormatBuilder& builder, Web::CSS::MediaQuery::MediaCondition const& media_condition)
{
Formatter<StringView>::format(builder, media_condition.to_string());
}
};
template<>
struct Formatter<Web::CSS::MediaQuery> : Formatter<StringView> {
void format(FormatBuilder& builder, Web::CSS::MediaQuery const& media_query)
{
Formatter<StringView>::format(builder, media_query.to_string());
}
};
}

View file

@ -26,6 +26,8 @@ class CSSStyleRule;
class CSSStyleSheet;
class ElementInlineCSSStyleDeclaration;
class Length;
class MediaQuery;
class MediaQueryList;
class PropertyOwningCSSStyleDeclaration;
class Screen;
class Selector;