mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-28 19:59:17 +00:00
LibWeb/CSS: Make media-type more permissive
The current spec defines this simply as `<ident>`, but does apparently serialize as lowercase. Because of this change, we no longer need to care about the deprecated media types, as they all behave the same as unknown ones. We still keep an enum around for KnownMediaType, to avoid repeated string comparisons when evaluating it. Gets us 2 WPT passes.
This commit is contained in:
parent
bb035fbfe0
commit
38aca62ef5
Notes:
github-actions[bot]
2025-05-23 09:19:52 +00:00
Author: https://github.com/AtkinsSJ
Commit: 38aca62ef5
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4817
4 changed files with 52 additions and 89 deletions
|
@ -17,7 +17,10 @@ NonnullRefPtr<MediaQuery> MediaQuery::create_not_all()
|
|||
{
|
||||
auto media_query = new MediaQuery;
|
||||
media_query->m_negated = true;
|
||||
media_query->m_media_type = MediaType::All;
|
||||
media_query->m_media_type = {
|
||||
.name = "all"_fly_string,
|
||||
.known_type = KnownMediaType::All,
|
||||
};
|
||||
|
||||
return adopt_ref(*media_query);
|
||||
}
|
||||
|
@ -265,8 +268,12 @@ String MediaQuery::to_string() const
|
|||
if (m_negated)
|
||||
builder.append("not "sv);
|
||||
|
||||
if (m_negated || m_media_type != MediaType::All || !m_media_condition) {
|
||||
builder.append(CSS::to_string(m_media_type));
|
||||
if (m_negated || m_media_type.known_type != KnownMediaType::All || !m_media_condition) {
|
||||
if (m_media_type.known_type.has_value()) {
|
||||
builder.append(CSS::to_string(m_media_type.known_type.value()));
|
||||
} else {
|
||||
builder.append(serialize_an_identifier(m_media_type.name.to_ascii_lowercase()));
|
||||
}
|
||||
if (m_media_condition)
|
||||
builder.append(" and "sv);
|
||||
}
|
||||
|
@ -280,28 +287,18 @@ String MediaQuery::to_string() const
|
|||
|
||||
bool MediaQuery::evaluate(HTML::Window const& window)
|
||||
{
|
||||
auto matches_media = [](MediaType media) -> MatchResult {
|
||||
switch (media) {
|
||||
case MediaType::All:
|
||||
auto matches_media = [](MediaType const& media) -> MatchResult {
|
||||
if (!media.known_type.has_value())
|
||||
return MatchResult::False;
|
||||
switch (media.known_type.value()) {
|
||||
case KnownMediaType::All:
|
||||
return MatchResult::True;
|
||||
case MediaType::Print:
|
||||
case KnownMediaType::Print:
|
||||
// FIXME: Enable for printing, when we have printing!
|
||||
return MatchResult::False;
|
||||
case MediaType::Screen:
|
||||
case KnownMediaType::Screen:
|
||||
// FIXME: Disable for printing, when we have printing!
|
||||
return MatchResult::True;
|
||||
case MediaType::Unknown:
|
||||
return MatchResult::False;
|
||||
// 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 MatchResult::False;
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
};
|
||||
|
@ -330,60 +327,26 @@ String serialize_a_media_query_list(Vector<NonnullRefPtr<MediaQuery>> const& med
|
|||
return MUST(String::join(", "sv, media_queries));
|
||||
}
|
||||
|
||||
MediaQuery::MediaType media_type_from_string(StringView name)
|
||||
Optional<MediaQuery::KnownMediaType> media_type_from_string(StringView name)
|
||||
{
|
||||
if (name.equals_ignoring_ascii_case("all"sv))
|
||||
return MediaQuery::MediaType::All;
|
||||
if (name.equals_ignoring_ascii_case("aural"sv))
|
||||
return MediaQuery::MediaType::Aural;
|
||||
if (name.equals_ignoring_ascii_case("braille"sv))
|
||||
return MediaQuery::MediaType::Braille;
|
||||
if (name.equals_ignoring_ascii_case("embossed"sv))
|
||||
return MediaQuery::MediaType::Embossed;
|
||||
if (name.equals_ignoring_ascii_case("handheld"sv))
|
||||
return MediaQuery::MediaType::Handheld;
|
||||
return MediaQuery::KnownMediaType::All;
|
||||
if (name.equals_ignoring_ascii_case("print"sv))
|
||||
return MediaQuery::MediaType::Print;
|
||||
if (name.equals_ignoring_ascii_case("projection"sv))
|
||||
return MediaQuery::MediaType::Projection;
|
||||
return MediaQuery::KnownMediaType::Print;
|
||||
if (name.equals_ignoring_ascii_case("screen"sv))
|
||||
return MediaQuery::MediaType::Screen;
|
||||
if (name.equals_ignoring_ascii_case("speech"sv))
|
||||
return MediaQuery::MediaType::Speech;
|
||||
if (name.equals_ignoring_ascii_case("tty"sv))
|
||||
return MediaQuery::MediaType::TTY;
|
||||
if (name.equals_ignoring_ascii_case("tv"sv))
|
||||
return MediaQuery::MediaType::TV;
|
||||
return MediaQuery::MediaType::Unknown;
|
||||
return MediaQuery::KnownMediaType::Screen;
|
||||
return {};
|
||||
}
|
||||
|
||||
StringView to_string(MediaQuery::MediaType media_type)
|
||||
StringView to_string(MediaQuery::KnownMediaType media_type)
|
||||
{
|
||||
switch (media_type) {
|
||||
case MediaQuery::MediaType::All:
|
||||
case MediaQuery::KnownMediaType::All:
|
||||
return "all"sv;
|
||||
case MediaQuery::MediaType::Aural:
|
||||
return "aural"sv;
|
||||
case MediaQuery::MediaType::Braille:
|
||||
return "braille"sv;
|
||||
case MediaQuery::MediaType::Embossed:
|
||||
return "embossed"sv;
|
||||
case MediaQuery::MediaType::Handheld:
|
||||
return "handheld"sv;
|
||||
case MediaQuery::MediaType::Print:
|
||||
case MediaQuery::KnownMediaType::Print:
|
||||
return "print"sv;
|
||||
case MediaQuery::MediaType::Projection:
|
||||
return "projection"sv;
|
||||
case MediaQuery::MediaType::Screen:
|
||||
case MediaQuery::KnownMediaType::Screen:
|
||||
return "screen"sv;
|
||||
case MediaQuery::MediaType::Speech:
|
||||
return "speech"sv;
|
||||
case MediaQuery::MediaType::TTY:
|
||||
return "tty"sv;
|
||||
case MediaQuery::MediaType::TV:
|
||||
return "tv"sv;
|
||||
case MediaQuery::MediaType::Unknown:
|
||||
return "unknown"sv;
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/FlyString.h>
|
||||
#include <AK/NonnullRefPtr.h>
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/OwnPtr.h>
|
||||
|
@ -189,21 +190,14 @@ public:
|
|||
~MediaQuery() = default;
|
||||
|
||||
// https://www.w3.org/TR/mediaqueries-4/#media-types
|
||||
enum class MediaType {
|
||||
enum class KnownMediaType : u8 {
|
||||
All,
|
||||
Print,
|
||||
Screen,
|
||||
Unknown,
|
||||
|
||||
// Deprecated, must never match:
|
||||
TTY,
|
||||
TV,
|
||||
Projection,
|
||||
Handheld,
|
||||
Braille,
|
||||
Embossed,
|
||||
Aural,
|
||||
Speech,
|
||||
};
|
||||
struct MediaType {
|
||||
FlyString name;
|
||||
Optional<KnownMediaType> known_type;
|
||||
};
|
||||
|
||||
static NonnullRefPtr<MediaQuery> create_not_all();
|
||||
|
@ -218,7 +212,7 @@ private:
|
|||
|
||||
// https://www.w3.org/TR/mediaqueries-4/#mq-not
|
||||
bool m_negated { false };
|
||||
MediaType m_media_type { MediaType::All };
|
||||
MediaType m_media_type { .name = "all"_fly_string, .known_type = KnownMediaType::All };
|
||||
OwnPtr<BooleanExpression> m_media_condition { nullptr };
|
||||
|
||||
// Cached value, updated by evaluate()
|
||||
|
@ -227,8 +221,8 @@ private:
|
|||
|
||||
String serialize_a_media_query_list(Vector<NonnullRefPtr<MediaQuery>> const&);
|
||||
|
||||
MediaQuery::MediaType media_type_from_string(StringView);
|
||||
StringView to_string(MediaQuery::MediaType);
|
||||
Optional<MediaQuery::KnownMediaType> media_type_from_string(StringView);
|
||||
StringView to_string(MediaQuery::KnownMediaType);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -112,13 +112,11 @@ NonnullRefPtr<MediaQuery> Parser::parse_media_query(TokenStream<ComponentValue>&
|
|||
|
||||
// `<media-type>`
|
||||
if (auto media_type = parse_media_type(tokens); media_type.has_value()) {
|
||||
// https://drafts.csswg.org/mediaqueries-4/#error-handling
|
||||
// An unknown <media-type> must be treated as not matching.
|
||||
if (media_type.value() == MediaQuery::MediaType::Unknown)
|
||||
return invalid_media_query();
|
||||
media_query->m_media_type = media_type.value();
|
||||
media_query->m_media_type = media_type.release_value();
|
||||
tokens.discard_whitespace();
|
||||
} else {
|
||||
// https://drafts.csswg.org/mediaqueries-4/#error-handling
|
||||
// A media query that does not match the grammar in the previous section must be replaced by not all during parsing.
|
||||
return invalid_media_query();
|
||||
}
|
||||
|
||||
|
@ -415,10 +413,19 @@ Optional<MediaQuery::MediaType> Parser::parse_media_type(TokenStream<ComponentVa
|
|||
if (!token.is(Token::Type::Ident))
|
||||
return {};
|
||||
|
||||
// https://drafts.csswg.org/mediaqueries-3/#error-handling
|
||||
// "However, an exception is made for media types ‘layer’, ‘not’, ‘and’, ‘only’, and ‘or’. Even though they do match
|
||||
// the IDENT production, they must not be treated as unknown media types, but rather trigger the malformed query clause."
|
||||
if (token.is_ident("layer"sv) || token.is_ident("not"sv) || token.is_ident("and"sv) || token.is_ident("only"sv) || token.is_ident("or"sv))
|
||||
return {};
|
||||
|
||||
transaction.commit();
|
||||
|
||||
auto ident = token.token().ident();
|
||||
return media_type_from_string(ident);
|
||||
auto const& ident = token.token().ident();
|
||||
return MediaQuery::MediaType {
|
||||
.name = ident,
|
||||
.known_type = media_type_from_string(ident),
|
||||
};
|
||||
}
|
||||
|
||||
// `<mf-value>`, https://www.w3.org/TR/mediaqueries-4/#typedef-mf-value
|
||||
|
|
|
@ -2,8 +2,7 @@ Harness status: OK
|
|||
|
||||
Found 34 tests
|
||||
|
||||
32 Pass
|
||||
2 Fail
|
||||
34 Pass
|
||||
Pass Test parsing '' with matchMedia
|
||||
Pass Test parsing ' ' with matchMedia
|
||||
Pass Test parsing 'all' with matchMedia
|
||||
|
@ -19,12 +18,12 @@ Pass Test parsing ' ( color ' with matchMedia
|
|||
Pass Test parsing 'color)' with matchMedia
|
||||
Pass Test parsing ' color)' with matchMedia
|
||||
Pass Test parsing ' color ), ( color' with matchMedia
|
||||
Fail Test parsing ' foo ' with matchMedia
|
||||
Pass Test parsing ' foo ' with matchMedia
|
||||
Pass Test parsing ',' with matchMedia
|
||||
Pass Test parsing ' , ' with matchMedia
|
||||
Pass Test parsing ',,' with matchMedia
|
||||
Pass Test parsing ' , , ' with matchMedia
|
||||
Fail Test parsing ' foo,' with matchMedia
|
||||
Pass Test parsing ' foo,' with matchMedia
|
||||
Pass Test parsing '(min-resolution: 1x)' with matchMedia
|
||||
Pass Test parsing '(min-resolution: calc(1x))' with matchMedia
|
||||
Pass Test parsing '(resolution: 2x)' with matchMedia
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue