1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 06:37:44 +00:00

LibWeb: Implement @supports rule :^)

The main thing missing is that we don't serialize the supports clause,
but for actually using a `@supports (something: cool) {}` rule in CSS,
it works!
This commit is contained in:
Sam Atkins 2021-10-08 17:48:14 +01:00 committed by Andreas Kling
parent 439d978ea5
commit 57a25139a5
9 changed files with 129 additions and 0 deletions

View file

@ -26,6 +26,7 @@ public:
Style,
Import,
Media,
Supports,
__Count,
};

View file

@ -8,6 +8,7 @@
#include <LibWeb/CSS/CSSImportRule.h>
#include <LibWeb/CSS/CSSMediaRule.h>
#include <LibWeb/CSS/CSSRuleList.h>
#include <LibWeb/CSS/CSSSupportsRule.h>
#include <LibWeb/DOM/ExceptionOr.h>
namespace Web::CSS {
@ -93,6 +94,9 @@ void CSSRuleList::for_each_effective_style_rule(Function<void(CSSStyleRule const
case CSSRule::Type::Media:
verify_cast<CSSMediaRule>(rule).for_each_effective_style_rule(callback);
break;
case CSSRule::Type::Supports:
verify_cast<CSSSupportsRule>(rule).for_each_effective_style_rule(callback);
break;
case CSSRule::Type::__Count:
VERIFY_NOT_REACHED();
}
@ -114,6 +118,8 @@ bool CSSRuleList::for_first_not_loaded_import_rule(Function<void(CSSImportRule&)
}
} else if (rule.type() == CSSRule::Type::Media) {
return verify_cast<CSSMediaRule>(rule).for_first_not_loaded_import_rule(callback);
} else if (rule.type() == CSSRule::Type::Supports) {
return verify_cast<CSSSupportsRule>(rule).for_first_not_loaded_import_rule(callback);
}
}

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2021, Sam Atkins <atkinssj@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/CSS/CSSSupportsRule.h>
#include <LibWeb/CSS/Parser/Parser.h>
namespace Web::CSS {
CSSSupportsRule::CSSSupportsRule(NonnullRefPtr<Supports>&& supports, NonnullRefPtrVector<CSSRule>&& rules)
: CSSConditionRule(move(rules))
, m_supports(move(supports))
{
}
CSSSupportsRule::~CSSSupportsRule()
{
}
String CSSSupportsRule::condition_text() const
{
// FIXME: Serializing supports rules!
return "<supports-condition>";
}
void CSSSupportsRule::set_condition_text(String text)
{
if (auto new_supports = parse_css_supports({}, text))
m_supports = new_supports.release_nonnull();
}
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2021, Sam Atkins <atkinssj@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/NonnullRefPtr.h>
#include <AK/NonnullRefPtrVector.h>
#include <LibWeb/CSS/CSSConditionRule.h>
#include <LibWeb/CSS/CSSRule.h>
#include <LibWeb/CSS/Supports.h>
#include <LibWeb/Forward.h>
namespace Web::CSS {
// https://www.w3.org/TR/css-conditional-3/#the-csssupportsrule-interface
class CSSSupportsRule final : public CSSConditionRule {
AK_MAKE_NONCOPYABLE(CSSSupportsRule);
AK_MAKE_NONMOVABLE(CSSSupportsRule);
public:
static NonnullRefPtr<CSSSupportsRule> create(NonnullRefPtr<Supports>&& supports, NonnullRefPtrVector<CSSRule>&& rules)
{
return adopt_ref(*new CSSSupportsRule(move(supports), move(rules)));
}
~CSSSupportsRule();
virtual StringView class_name() const override { return "CSSSupportsRule"; };
virtual Type type() const override { return Type::Supports; };
String condition_text() const override;
void set_condition_text(String) override;
virtual bool condition_matches() const override { return m_supports->matches(); }
private:
explicit CSSSupportsRule(NonnullRefPtr<Supports>&&, NonnullRefPtrVector<CSSRule>&&);
NonnullRefPtr<Supports> m_supports;
};
template<>
inline bool CSSRule::fast_is<CSSSupportsRule>() const { return type() == CSSRule::Type::Supports; }
}

View file

@ -16,6 +16,7 @@
#include <LibWeb/CSS/CSSStyleDeclaration.h>
#include <LibWeb/CSS/CSSStyleRule.h>
#include <LibWeb/CSS/CSSStyleSheet.h>
#include <LibWeb/CSS/CSSSupportsRule.h>
#include <LibWeb/CSS/Parser/DeclarationOrAtRule.h>
#include <LibWeb/CSS/Parser/Parser.h>
#include <LibWeb/CSS/Parser/StyleBlockRule.h>
@ -1735,6 +1736,29 @@ RefPtr<CSSRule> Parser::convert_to_rule(NonnullRefPtr<StyleRule> rule)
return CSSImportRule::create(url.value());
else
dbgln("Unable to parse url from @import rule");
} else if (rule->m_name.equals_ignoring_case("supports"sv)) {
auto supports_tokens = TokenStream { rule->prelude() };
auto supports = parse_a_supports(supports_tokens);
if (!supports) {
if constexpr (CSS_PARSER_DEBUG) {
dbgln("CSSParser: @supports rule invalid; discarding.");
supports_tokens.dump_all_tokens();
}
return {};
}
auto child_tokens = TokenStream { rule->block().values() };
auto parser_rules = consume_a_list_of_rules(child_tokens, false);
NonnullRefPtrVector<CSSRule> child_rules;
for (auto& raw_rule : parser_rules) {
if (auto child_rule = convert_to_rule(raw_rule))
child_rules.append(*child_rule);
}
return CSSSupportsRule::create(supports.release_nonnull(), move(child_rules));
} else {
dbgln("Unrecognized CSS at-rule: @{}", rule->m_name);
}