mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-31 13:19:05 +00:00
LibWeb/CSS: Evaluate Supports query components during parsing
Instead of parsing the parts of a `@supports` query, then only evaluating them when constructing the Supports itself, we can instead evaluate them as we parse them. This simplifies things as we no longer need to pass a Realm around, and don't have to re-parse the conditions again with a new Parser instance.
This commit is contained in:
parent
95730c66aa
commit
84a695c958
Notes:
github-actions[bot]
2025-03-17 10:01:49 +00:00
Author: https://github.com/AtkinsSJ
Commit: 84a695c958
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3941
5 changed files with 32 additions and 48 deletions
|
@ -87,11 +87,4 @@ RefPtr<CSS::Supports> parse_css_supports(CSS::Parser::ParsingParams const& conte
|
||||||
return CSS::Parser::Parser::create(context, string).parse_as_supports();
|
return CSS::Parser::Parser::create(context, string).parse_as_supports();
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<CSS::StyleProperty> parse_css_supports_condition(CSS::Parser::ParsingParams const& context, StringView string)
|
|
||||||
{
|
|
||||||
if (string.is_empty())
|
|
||||||
return {};
|
|
||||||
return CSS::Parser::Parser::create(context, string).parse_as_supports_condition();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,7 +154,7 @@ RefPtr<Supports> Parser::parse_a_supports(TokenStream<T>& tokens)
|
||||||
m_rule_context.take_last();
|
m_rule_context.take_last();
|
||||||
token_stream.discard_whitespace();
|
token_stream.discard_whitespace();
|
||||||
if (maybe_condition && !token_stream.has_next_token())
|
if (maybe_condition && !token_stream.has_next_token())
|
||||||
return Supports::create(realm(), maybe_condition.release_nonnull());
|
return Supports::create(maybe_condition.release_nonnull());
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -279,7 +279,9 @@ Optional<Supports::Feature> Parser::parse_supports_feature(TokenStream<Component
|
||||||
if (auto declaration = consume_a_declaration(block_tokens); declaration.has_value()) {
|
if (auto declaration = consume_a_declaration(block_tokens); declaration.has_value()) {
|
||||||
transaction.commit();
|
transaction.commit();
|
||||||
return Supports::Feature {
|
return Supports::Feature {
|
||||||
Supports::Declaration { declaration->to_string() }
|
Supports::Declaration {
|
||||||
|
declaration->to_string(),
|
||||||
|
convert_to_style_property(*declaration).has_value() }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -291,8 +293,11 @@ Optional<Supports::Feature> Parser::parse_supports_feature(TokenStream<Component
|
||||||
for (auto const& item : first_token.function().value)
|
for (auto const& item : first_token.function().value)
|
||||||
builder.append(item.to_string());
|
builder.append(item.to_string());
|
||||||
transaction.commit();
|
transaction.commit();
|
||||||
|
TokenStream selector_tokens { first_token.function().value };
|
||||||
return Supports::Feature {
|
return Supports::Feature {
|
||||||
Supports::Selector { builder.to_string().release_value_but_fixme_should_propagate_errors() }
|
Supports::Selector {
|
||||||
|
builder.to_string_without_validation(),
|
||||||
|
!parse_a_selector_list(selector_tokens, SelectorType::Standalone).is_error() }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -518,6 +518,5 @@ CSS::CSSRule* parse_css_rule(CSS::Parser::ParsingParams const&, StringView);
|
||||||
RefPtr<CSS::MediaQuery> parse_media_query(CSS::Parser::ParsingParams const&, StringView);
|
RefPtr<CSS::MediaQuery> parse_media_query(CSS::Parser::ParsingParams const&, StringView);
|
||||||
Vector<NonnullRefPtr<CSS::MediaQuery>> parse_media_query_list(CSS::Parser::ParsingParams const&, StringView);
|
Vector<NonnullRefPtr<CSS::MediaQuery>> parse_media_query_list(CSS::Parser::ParsingParams const&, StringView);
|
||||||
RefPtr<CSS::Supports> parse_css_supports(CSS::Parser::ParsingParams const&, StringView);
|
RefPtr<CSS::Supports> parse_css_supports(CSS::Parser::ParsingParams const&, StringView);
|
||||||
Optional<CSS::StyleProperty> parse_css_supports_condition(CSS::Parser::ParsingParams const&, StringView);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2021-2023, Sam Atkins <atkinssj@serenityos.org>
|
* Copyright (c) 2021-2025, Sam Atkins <sam@ladybird.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <LibJS/Runtime/Realm.h>
|
#include <LibJS/Runtime/Realm.h>
|
||||||
#include <LibWeb/CSS/Parser/Parser.h>
|
|
||||||
#include <LibWeb/CSS/Supports.h>
|
#include <LibWeb/CSS/Supports.h>
|
||||||
|
|
||||||
namespace Web::CSS {
|
namespace Web::CSS {
|
||||||
|
@ -16,26 +15,26 @@ static void indent(StringBuilder& builder, int levels)
|
||||||
builder.append(" "sv);
|
builder.append(" "sv);
|
||||||
}
|
}
|
||||||
|
|
||||||
Supports::Supports(JS::Realm& realm, NonnullOwnPtr<Condition>&& condition)
|
Supports::Supports(NonnullOwnPtr<Condition>&& condition)
|
||||||
: m_condition(move(condition))
|
: m_condition(move(condition))
|
||||||
{
|
{
|
||||||
m_matches = m_condition->evaluate(realm);
|
m_matches = m_condition->evaluate();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Supports::Condition::evaluate(JS::Realm& realm) const
|
bool Supports::Condition::evaluate() const
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Type::Not:
|
case Type::Not:
|
||||||
return !children.first().evaluate(realm);
|
return !children.first().evaluate();
|
||||||
case Type::And:
|
case Type::And:
|
||||||
for (auto& child : children) {
|
for (auto& child : children) {
|
||||||
if (!child.evaluate(realm))
|
if (!child.evaluate())
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
case Type::Or:
|
case Type::Or:
|
||||||
for (auto& child : children) {
|
for (auto& child : children) {
|
||||||
if (child.evaluate(realm))
|
if (child.evaluate())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -43,40 +42,28 @@ bool Supports::Condition::evaluate(JS::Realm& realm) const
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Supports::InParens::evaluate(JS::Realm& realm) const
|
bool Supports::InParens::evaluate() const
|
||||||
{
|
{
|
||||||
return value.visit(
|
return value.visit(
|
||||||
[&](NonnullOwnPtr<Condition> const& condition) {
|
[&](NonnullOwnPtr<Condition> const& condition) {
|
||||||
return condition->evaluate(realm);
|
return condition->evaluate();
|
||||||
},
|
},
|
||||||
[&](Feature const& feature) {
|
[&](Feature const& feature) {
|
||||||
return feature.evaluate(realm);
|
return feature.evaluate();
|
||||||
},
|
},
|
||||||
[&](GeneralEnclosed const&) {
|
[&](GeneralEnclosed const&) {
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Supports::Declaration::evaluate(JS::Realm& realm) const
|
bool Supports::Feature::evaluate() const
|
||||||
{
|
|
||||||
auto style_property = parse_css_supports_condition(Parser::ParsingParams { realm }, declaration);
|
|
||||||
return style_property.has_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Supports::Selector::evaluate(JS::Realm& realm) const
|
|
||||||
{
|
|
||||||
auto style_property = parse_selector(Parser::ParsingParams { realm }, selector);
|
|
||||||
return style_property.has_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Supports::Feature::evaluate(JS::Realm& realm) const
|
|
||||||
{
|
{
|
||||||
return value.visit(
|
return value.visit(
|
||||||
[&](Declaration const& declaration) {
|
[&](Declaration const& declaration) {
|
||||||
return declaration.evaluate(realm);
|
return declaration.evaluate();
|
||||||
},
|
},
|
||||||
[&](Selector const& selector) {
|
[&](Selector const& selector) {
|
||||||
return selector.evaluate(realm);
|
return selector.evaluate();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2021-2023, Sam Atkins <atkinssj@serenityos.org>
|
* Copyright (c) 2021-2025, Sam Atkins <sam@ladybird.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -17,26 +17,26 @@ namespace Web::CSS {
|
||||||
|
|
||||||
// https://www.w3.org/TR/css-conditional-3/#at-supports
|
// https://www.w3.org/TR/css-conditional-3/#at-supports
|
||||||
class Supports final : public RefCounted<Supports> {
|
class Supports final : public RefCounted<Supports> {
|
||||||
friend class Parser::Parser;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct Declaration {
|
struct Declaration {
|
||||||
String declaration;
|
String declaration;
|
||||||
[[nodiscard]] bool evaluate(JS::Realm&) const;
|
bool matches;
|
||||||
|
[[nodiscard]] bool evaluate() const { return matches; }
|
||||||
String to_string() const;
|
String to_string() const;
|
||||||
void dump(StringBuilder&, int indent_levels = 0) const;
|
void dump(StringBuilder&, int indent_levels = 0) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Selector {
|
struct Selector {
|
||||||
String selector;
|
String selector;
|
||||||
[[nodiscard]] bool evaluate(JS::Realm&) const;
|
bool matches;
|
||||||
|
[[nodiscard]] bool evaluate() const { return matches; }
|
||||||
String to_string() const;
|
String to_string() const;
|
||||||
void dump(StringBuilder&, int indent_levels = 0) const;
|
void dump(StringBuilder&, int indent_levels = 0) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Feature {
|
struct Feature {
|
||||||
Variant<Declaration, Selector> value;
|
Variant<Declaration, Selector> value;
|
||||||
[[nodiscard]] bool evaluate(JS::Realm&) const;
|
[[nodiscard]] bool evaluate() const;
|
||||||
String to_string() const;
|
String to_string() const;
|
||||||
void dump(StringBuilder&, int indent_levels = 0) const;
|
void dump(StringBuilder&, int indent_levels = 0) const;
|
||||||
};
|
};
|
||||||
|
@ -45,7 +45,7 @@ public:
|
||||||
struct InParens {
|
struct InParens {
|
||||||
Variant<NonnullOwnPtr<Condition>, Feature, GeneralEnclosed> value;
|
Variant<NonnullOwnPtr<Condition>, Feature, GeneralEnclosed> value;
|
||||||
|
|
||||||
[[nodiscard]] bool evaluate(JS::Realm&) const;
|
[[nodiscard]] bool evaluate() const;
|
||||||
String to_string() const;
|
String to_string() const;
|
||||||
void dump(StringBuilder&, int indent_levels = 0) const;
|
void dump(StringBuilder&, int indent_levels = 0) const;
|
||||||
};
|
};
|
||||||
|
@ -59,14 +59,14 @@ public:
|
||||||
Type type;
|
Type type;
|
||||||
Vector<InParens> children;
|
Vector<InParens> children;
|
||||||
|
|
||||||
[[nodiscard]] bool evaluate(JS::Realm&) const;
|
[[nodiscard]] bool evaluate() const;
|
||||||
String to_string() const;
|
String to_string() const;
|
||||||
void dump(StringBuilder&, int indent_levels = 0) const;
|
void dump(StringBuilder&, int indent_levels = 0) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
static NonnullRefPtr<Supports> create(JS::Realm& realm, NonnullOwnPtr<Condition>&& condition)
|
static NonnullRefPtr<Supports> create(NonnullOwnPtr<Condition>&& condition)
|
||||||
{
|
{
|
||||||
return adopt_ref(*new Supports(realm, move(condition)));
|
return adopt_ref(*new Supports(move(condition)));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool matches() const { return m_matches; }
|
bool matches() const { return m_matches; }
|
||||||
|
@ -75,7 +75,7 @@ public:
|
||||||
void dump(StringBuilder&, int indent_levels = 0) const;
|
void dump(StringBuilder&, int indent_levels = 0) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Supports(JS::Realm&, NonnullOwnPtr<Condition>&&);
|
Supports(NonnullOwnPtr<Condition>&&);
|
||||||
|
|
||||||
NonnullOwnPtr<Condition> m_condition;
|
NonnullOwnPtr<Condition> m_condition;
|
||||||
bool m_matches { false };
|
bool m_matches { false };
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue