diff --git a/Base/res/html/misc/supports.html b/Base/res/html/misc/supports.html index 0940b51c2d..0593f4b35f 100644 --- a/Base/res/html/misc/supports.html +++ b/Base/res/html/misc/supports.html @@ -25,6 +25,23 @@ } } + /* Selectors */ + @supports selector(.simple) { + .p5 { + background-color: lime; + } + } + @supports selector(a#more > .complicated.case:nth-child(42)) { + .p6 { + background-color: lime; + } + } + @supports selector(.easy) or selector(.....nope) { + .p7 { + background-color: lime; + } + } + .negative { background-color: red; } @@ -48,6 +65,21 @@ background-color: lime; } } + @supports selector(.....nope) { + .n5 { + background-color: lime; + } + } + @supports selector(::-webkit-input-placeholder) { + .n6 { + background-color: lime; + } + } + @supports selector(32) or selector(thing[foo??????bar]) { + .n7 { + background-color: lime; + } + } .success { background-color: lime; @@ -63,16 +95,24 @@

@supports (color: green) and (width: 50px)

@supports (color: green) or (flogwizzle: purple)

@supports (not (flogwizzle: purple))

+

@supports selector(.simple)

+

@supports selector(a#more > .complicated.case:nth-child(42))

+

@supports selector(.easy) or selector(.....nope)

These should all be red

@supports (not (color: green))

@supports (color: green) and (width: 50px) or (color: green)

@supports (width: yellow) or (height: green)

@supports (flogwizzle: purple)

+

@supports selector(.....nope)

+

@supports selector(::-webkit-input-placeholder)

+

@supports selector(32) or selector(thing[foo??????bar])

Testing CSS.supports(property, value)

+

These should all be green, meaning they returned true

+

These should all be red, meaning they returned false

@@ -118,7 +158,10 @@ "color: green", "(color: green) and (width: 50px)", "(color: green) or (flogwizzle: purple)", - "not (flogwizzle: purple)" + "not (flogwizzle: purple)", + "selector(.simple)", + "selector(a#more > .complicated.case:nth-child(42))", + "selector(.easy) or selector(.....nope)" ]; for (let text of should_succeed) { let success = CSS.supports(text); @@ -133,7 +176,10 @@ "not (color: green)", "(color: green) and (width: 50px) or (color: green)", "(width: yellow) or (height: green)", - "flogwizzle: purple" + "flogwizzle: purple", + "selector(.....nope)", + "selector(::-webkit-input-placeholder)", + "selector(32) or selector(thing[foo??????bar])" ]; for (let text of should_fail) { let success = CSS.supports(text); diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index e5ace9fa06..cc88ead5b0 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -1,7 +1,7 @@ /* * Copyright (c) 2018-2020, Andreas Kling * Copyright (c) 2020-2021, the SerenityOS developers. - * Copyright (c) 2021, Sam Atkins + * Copyright (c) 2021-2022, Sam Atkins * Copyright (c) 2021, Tobias Christiansen * * SPDX-License-Identifier: BSD-2-Clause @@ -1309,12 +1309,23 @@ Optional Parser::parse_supports_feature(TokenStream` if (first_token.is_block() && first_token.block().is_paren()) { TokenStream block_tokens { first_token.block().values() }; + // FIXME: Parsing and then converting back to a string is weird. if (auto declaration = consume_a_declaration(block_tokens); declaration.has_value()) { return Supports::Feature { - .declaration = declaration->to_string() + Supports::Declaration { declaration->to_string() } }; } } + // `` + if (first_token.is_function() && first_token.function().name().equals_ignoring_case("selector"sv)) { + // FIXME: Parsing and then converting back to a string is weird. + StringBuilder builder; + for (auto const& item : first_token.function().values()) + builder.append(item.to_string()); + return Supports::Feature { + Supports::Selector { builder.to_string() } + }; + } tokens.rewind_to_position(start_position); return {}; diff --git a/Userland/Libraries/LibWeb/CSS/Supports.cpp b/Userland/Libraries/LibWeb/CSS/Supports.cpp index de220a5598..45a6e4b9d6 100644 --- a/Userland/Libraries/LibWeb/CSS/Supports.cpp +++ b/Userland/Libraries/LibWeb/CSS/Supports.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Sam Atkins + * Copyright (c) 2021-2022, Sam Atkins * * SPDX-License-Identifier: BSD-2-Clause */ @@ -50,10 +50,27 @@ bool Supports::InParens::evaluate() const }); } -bool Supports::Feature::evaluate() const +bool Supports::Declaration::evaluate() const { auto style_property = Parser({}, declaration).parse_as_declaration(); return style_property.has_value(); } +bool Supports::Selector::evaluate() const +{ + auto style_property = Parser({}, selector).parse_as_selector(); + return style_property.has_value(); +} + +bool Supports::Feature::evaluate() const +{ + return value.visit( + [&](Declaration const& declaration) { + return declaration.evaluate(); + }, + [&](Selector const& selector) { + return selector.evaluate(); + }); +} + } diff --git a/Userland/Libraries/LibWeb/CSS/Supports.h b/Userland/Libraries/LibWeb/CSS/Supports.h index 2494f0488b..e7b6fa2264 100644 --- a/Userland/Libraries/LibWeb/CSS/Supports.h +++ b/Userland/Libraries/LibWeb/CSS/Supports.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Sam Atkins + * Copyright (c) 2021-2022, Sam Atkins * * SPDX-License-Identifier: BSD-2-Clause */ @@ -16,16 +16,26 @@ namespace Web::CSS { -// https://www.w3.org/TR/css-conditional-3/#at-supports +// https://www.w3.org/TR/css-conditional-4/#at-supports class Supports final : public RefCounted { friend class Parser; public: - struct Feature { + struct Declaration { String declaration; bool evaluate() const; }; + struct Selector { + String selector; + bool evaluate() const; + }; + + struct Feature { + Variant value; + bool evaluate() const; + }; + struct Condition; struct InParens { Variant, Feature, GeneralEnclosed> value;