diff --git a/Tests/LibWeb/Text/expected/css/keyframes-css-rules.txt b/Tests/LibWeb/Text/expected/css/keyframes-css-rules.txt
new file mode 100644
index 00000000000..3af11a131fc
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/css/keyframes-css-rules.txt
@@ -0,0 +1,5 @@
+fooRule: [object CSSKeyframesRule] ~ @keyframes "foo" { 0% { color: rgb(0, 0, 0); } 100% { color: rgb(255, 255, 255); } }
+fooRule.cssRules: [object CSSRuleList]
+fooRule.cssRules[0]: [object CSSKeyframeRule] ~ 0% { color: rgb(0, 0, 0); }
+fooRule.cssRules[0].style.parentRule: [object CSSKeyframeRule] ~ 0% { color: rgb(0, 0, 0); }
+fooRule.cssRules[0].style.parentRule === fooRule.cssRules[0]: true
diff --git a/Tests/LibWeb/Text/input/css/keyframes-css-rules.html b/Tests/LibWeb/Text/input/css/keyframes-css-rules.html
new file mode 100644
index 00000000000..249cace53fb
--- /dev/null
+++ b/Tests/LibWeb/Text/input/css/keyframes-css-rules.html
@@ -0,0 +1,17 @@
+
+
+
diff --git a/Userland/Libraries/LibWeb/CSS/CSSKeyframeRule.h b/Userland/Libraries/LibWeb/CSS/CSSKeyframeRule.h
index bac207ead9d..74958a9284b 100644
--- a/Userland/Libraries/LibWeb/CSS/CSSKeyframeRule.h
+++ b/Userland/Libraries/LibWeb/CSS/CSSKeyframeRule.h
@@ -29,6 +29,7 @@ public:
CSS::Percentage key() const { return m_key; }
JS::NonnullGCPtr style() const { return m_declarations; }
+ JS::NonnullGCPtr style_as_property_owning_style_declaration() const { return m_declarations; }
String key_text() const
{
diff --git a/Userland/Libraries/LibWeb/CSS/CSSKeyframesRule.cpp b/Userland/Libraries/LibWeb/CSS/CSSKeyframesRule.cpp
index 74ce66884f6..3fff7ffc8c8 100644
--- a/Userland/Libraries/LibWeb/CSS/CSSKeyframesRule.cpp
+++ b/Userland/Libraries/LibWeb/CSS/CSSKeyframesRule.cpp
@@ -1,26 +1,28 @@
/*
* Copyright (c) 2023, Ali Mohammad Pur
+ * Copyright (c) 2024, Andreas Kling
*
* SPDX-License-Identifier: BSD-2-Clause
*/
-#include "CSSKeyframesRule.h"
#include
#include
+#include
+#include
namespace Web::CSS {
JS_DEFINE_ALLOCATOR(CSSKeyframesRule);
-JS::NonnullGCPtr CSSKeyframesRule::create(JS::Realm& realm, FlyString name, JS::MarkedVector> keyframes)
+JS::NonnullGCPtr CSSKeyframesRule::create(JS::Realm& realm, FlyString name, JS::NonnullGCPtr css_rules)
{
- return realm.heap().allocate(realm, realm, move(name), move(keyframes));
+ return realm.heap().allocate(realm, realm, move(name), move(css_rules));
}
void CSSKeyframesRule::visit_edges(Visitor& visitor)
{
Base::visit_edges(visitor);
- visitor.visit(m_keyframes);
+ visitor.visit(m_rules);
}
void CSSKeyframesRule::initialize(JS::Realm& realm)
@@ -34,7 +36,7 @@ String CSSKeyframesRule::serialized() const
StringBuilder builder;
builder.appendff("@keyframes \"{}\"", name());
builder.append(" { "sv);
- for (auto const& keyframe : keyframes()) {
+ for (auto const& keyframe : *m_rules) {
builder.append(keyframe->css_text());
builder.append(' ');
}
@@ -42,4 +44,9 @@ String CSSKeyframesRule::serialized() const
return MUST(builder.to_string());
}
+WebIDL::UnsignedLong CSSKeyframesRule::length() const
+{
+ return m_rules->length();
+}
+
}
diff --git a/Userland/Libraries/LibWeb/CSS/CSSKeyframesRule.h b/Userland/Libraries/LibWeb/CSS/CSSKeyframesRule.h
index b95a53c5bbb..f1863d11549 100644
--- a/Userland/Libraries/LibWeb/CSS/CSSKeyframesRule.h
+++ b/Userland/Libraries/LibWeb/CSS/CSSKeyframesRule.h
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2023, Ali Mohammad Pur
+ * Copyright (c) 2024, Andreas Kling
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@@ -13,6 +14,7 @@
#include
#include
#include
+#include
namespace Web::CSS {
@@ -22,23 +24,23 @@ class CSSKeyframesRule final : public CSSRule {
JS_DECLARE_ALLOCATOR(CSSKeyframesRule);
public:
- [[nodiscard]] static JS::NonnullGCPtr create(JS::Realm&, FlyString name, JS::MarkedVector>);
+ [[nodiscard]] static JS::NonnullGCPtr create(JS::Realm&, FlyString name, JS::NonnullGCPtr);
virtual ~CSSKeyframesRule() = default;
virtual Type type() const override { return Type::Keyframes; }
- Vector> const& keyframes() const { return m_keyframes; }
+ auto const& css_rules() const { return m_rules; }
FlyString const& name() const { return m_name; }
- size_t length() { return m_keyframes.size(); }
+ [[nodiscard]] WebIDL::UnsignedLong length() const;
void set_name(String const& name) { m_name = name; }
private:
- CSSKeyframesRule(JS::Realm& realm, FlyString name, JS::MarkedVector> keyframes)
+ CSSKeyframesRule(JS::Realm& realm, FlyString name, JS::NonnullGCPtr keyframes)
: CSSRule(realm)
, m_name(move(name))
- , m_keyframes(move(keyframes))
+ , m_rules(move(keyframes))
{
}
@@ -48,7 +50,7 @@ private:
virtual String serialized() const override;
FlyString m_name;
- Vector> m_keyframes;
+ JS::NonnullGCPtr m_rules;
};
template<>
diff --git a/Userland/Libraries/LibWeb/CSS/CSSKeyframesRule.idl b/Userland/Libraries/LibWeb/CSS/CSSKeyframesRule.idl
index f1aab1c311b..c6aea702c96 100644
--- a/Userland/Libraries/LibWeb/CSS/CSSKeyframesRule.idl
+++ b/Userland/Libraries/LibWeb/CSS/CSSKeyframesRule.idl
@@ -5,7 +5,7 @@
[Exposed=Window]
interface CSSKeyframesRule : CSSRule {
attribute CSSOMString name;
- [FIXME] readonly attribute CSSRuleList cssRules;
+ readonly attribute CSSRuleList cssRules;
readonly attribute unsigned long length;
getter CSSKeyframeRule (unsigned long index);
diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp
index 71a256c25a2..04978565260 100644
--- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp
+++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp
@@ -1349,7 +1349,7 @@ CSSRule* Parser::convert_to_rule(NonnullRefPtr rule)
auto child_tokens = TokenStream { rule->block()->values() };
- JS::MarkedVector> keyframes(m_context.realm().heap());
+ JS::MarkedVector keyframes(m_context.realm().heap());
while (child_tokens.has_next_token()) {
child_tokens.skip_whitespace();
// keyframe-selector = |
@@ -1415,7 +1415,7 @@ CSSRule* Parser::convert_to_rule(NonnullRefPtr rule)
}
}
- return CSSKeyframesRule::create(m_context.realm(), name, move(keyframes));
+ return CSSKeyframesRule::create(m_context.realm(), name, CSSRuleList::create(m_context.realm(), move(keyframes)));
}
if (rule->at_rule_name().equals_ignoring_ascii_case("namespace"sv)) {
// https://drafts.csswg.org/css-namespaces/#syntax
diff --git a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp
index abba7c9506b..d0feffa7cdd 100644
--- a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp
+++ b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp
@@ -2553,16 +2553,12 @@ NonnullOwnPtr StyleComputer::make_rule_cache_for_casca
HashTable animated_properties;
// Forwards pass, resolve all the user-specified keyframe properties.
- for (auto const& keyframe : rule.keyframes()) {
+ for (auto const& keyframe_rule : *rule.css_rules()) {
+ auto const& keyframe = verify_cast(*keyframe_rule);
Animations::KeyframeEffect::KeyFrameSet::ResolvedKeyFrame resolved_keyframe;
- auto key = static_cast(keyframe->key().value() * Animations::KeyframeEffect::AnimationKeyFrameKeyScaleFactor);
- auto keyframe_rule = keyframe->style();
-
- if (!is(*keyframe_rule))
- continue;
-
- auto const& keyframe_style = static_cast(*keyframe_rule);
+ auto key = static_cast(keyframe.key().value() * Animations::KeyframeEffect::AnimationKeyFrameKeyScaleFactor);
+ auto const& keyframe_style = *keyframe.style_as_property_owning_style_declaration();
for (auto const& it : keyframe_style.properties()) {
// Unresolved properties will be resolved in collect_animation_into()
for_each_property_expanding_shorthands(it.property_id, it.value, AllowUnresolved::Yes, [&](PropertyID shorthand_id, StyleValue const& shorthand_value) {