mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-28 19:59:17 +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();
|
||||
}
|
||||
|
||||
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();
|
||||
token_stream.discard_whitespace();
|
||||
if (maybe_condition && !token_stream.has_next_token())
|
||||
return Supports::create(realm(), maybe_condition.release_nonnull());
|
||||
return Supports::create(maybe_condition.release_nonnull());
|
||||
|
||||
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()) {
|
||||
transaction.commit();
|
||||
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)
|
||||
builder.append(item.to_string());
|
||||
transaction.commit();
|
||||
TokenStream selector_tokens { first_token.function().value };
|
||||
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);
|
||||
Vector<NonnullRefPtr<CSS::MediaQuery>> parse_media_query_list(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
|
||||
*/
|
||||
|
||||
#include <LibJS/Runtime/Realm.h>
|
||||
#include <LibWeb/CSS/Parser/Parser.h>
|
||||
#include <LibWeb/CSS/Supports.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
@ -16,26 +15,26 @@ static void indent(StringBuilder& builder, int levels)
|
|||
builder.append(" "sv);
|
||||
}
|
||||
|
||||
Supports::Supports(JS::Realm& realm, NonnullOwnPtr<Condition>&& condition)
|
||||
Supports::Supports(NonnullOwnPtr<Condition>&& 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) {
|
||||
case Type::Not:
|
||||
return !children.first().evaluate(realm);
|
||||
return !children.first().evaluate();
|
||||
case Type::And:
|
||||
for (auto& child : children) {
|
||||
if (!child.evaluate(realm))
|
||||
if (!child.evaluate())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
case Type::Or:
|
||||
for (auto& child : children) {
|
||||
if (child.evaluate(realm))
|
||||
if (child.evaluate())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -43,40 +42,28 @@ bool Supports::Condition::evaluate(JS::Realm& realm) const
|
|||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
bool Supports::InParens::evaluate(JS::Realm& realm) const
|
||||
bool Supports::InParens::evaluate() const
|
||||
{
|
||||
return value.visit(
|
||||
[&](NonnullOwnPtr<Condition> const& condition) {
|
||||
return condition->evaluate(realm);
|
||||
return condition->evaluate();
|
||||
},
|
||||
[&](Feature const& feature) {
|
||||
return feature.evaluate(realm);
|
||||
return feature.evaluate();
|
||||
},
|
||||
[&](GeneralEnclosed const&) {
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
bool Supports::Declaration::evaluate(JS::Realm& realm) 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
|
||||
bool Supports::Feature::evaluate() const
|
||||
{
|
||||
return value.visit(
|
||||
[&](Declaration const& declaration) {
|
||||
return declaration.evaluate(realm);
|
||||
return declaration.evaluate();
|
||||
},
|
||||
[&](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
|
||||
*/
|
||||
|
@ -17,26 +17,26 @@ namespace Web::CSS {
|
|||
|
||||
// https://www.w3.org/TR/css-conditional-3/#at-supports
|
||||
class Supports final : public RefCounted<Supports> {
|
||||
friend class Parser::Parser;
|
||||
|
||||
public:
|
||||
struct Declaration {
|
||||
String declaration;
|
||||
[[nodiscard]] bool evaluate(JS::Realm&) const;
|
||||
bool matches;
|
||||
[[nodiscard]] bool evaluate() const { return matches; }
|
||||
String to_string() const;
|
||||
void dump(StringBuilder&, int indent_levels = 0) const;
|
||||
};
|
||||
|
||||
struct Selector {
|
||||
String selector;
|
||||
[[nodiscard]] bool evaluate(JS::Realm&) const;
|
||||
bool matches;
|
||||
[[nodiscard]] bool evaluate() const { return matches; }
|
||||
String to_string() const;
|
||||
void dump(StringBuilder&, int indent_levels = 0) const;
|
||||
};
|
||||
|
||||
struct Feature {
|
||||
Variant<Declaration, Selector> value;
|
||||
[[nodiscard]] bool evaluate(JS::Realm&) const;
|
||||
[[nodiscard]] bool evaluate() const;
|
||||
String to_string() const;
|
||||
void dump(StringBuilder&, int indent_levels = 0) const;
|
||||
};
|
||||
|
@ -45,7 +45,7 @@ public:
|
|||
struct InParens {
|
||||
Variant<NonnullOwnPtr<Condition>, Feature, GeneralEnclosed> value;
|
||||
|
||||
[[nodiscard]] bool evaluate(JS::Realm&) const;
|
||||
[[nodiscard]] bool evaluate() const;
|
||||
String to_string() const;
|
||||
void dump(StringBuilder&, int indent_levels = 0) const;
|
||||
};
|
||||
|
@ -59,14 +59,14 @@ public:
|
|||
Type type;
|
||||
Vector<InParens> children;
|
||||
|
||||
[[nodiscard]] bool evaluate(JS::Realm&) const;
|
||||
[[nodiscard]] bool evaluate() const;
|
||||
String to_string() 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; }
|
||||
|
@ -75,7 +75,7 @@ public:
|
|||
void dump(StringBuilder&, int indent_levels = 0) const;
|
||||
|
||||
private:
|
||||
Supports(JS::Realm&, NonnullOwnPtr<Condition>&&);
|
||||
Supports(NonnullOwnPtr<Condition>&&);
|
||||
|
||||
NonnullOwnPtr<Condition> m_condition;
|
||||
bool m_matches { false };
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue