From 3c9c134d71f652bf577c3e58ab7a4e318501595f Mon Sep 17 00:00:00 2001 From: Matthew Olsson Date: Mon, 12 Feb 2024 13:51:36 +0000 Subject: [PATCH] LibWeb: Implement KeyframeEffect::{get,set}_keyframes --- .../LibJS/Runtime/CommonPropertyNames.h | 3 ++ .../LibWeb/Animations/KeyframeEffect.cpp | 53 ++++++++++++++++--- .../LibWeb/Animations/KeyframeEffect.h | 5 +- 3 files changed, 54 insertions(+), 7 deletions(-) diff --git a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h index 6f38f7f9c47..3a6deb06c84 100644 --- a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h +++ b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h @@ -110,6 +110,8 @@ namespace JS { P(compactDisplay) \ P(compareExchange) \ P(compile) \ + P(composite) \ + P(computedOffset) \ P(concat) \ P(configurable) \ P(console) \ @@ -157,6 +159,7 @@ namespace JS { P(done) \ P(dotAll) \ P(drop) \ + P(easing) \ P(encodeURI) \ P(encodeURIComponent) \ P(endsWith) \ diff --git a/Userland/Libraries/LibWeb/Animations/KeyframeEffect.cpp b/Userland/Libraries/LibWeb/Animations/KeyframeEffect.cpp index 0ca7c1031b6..03a3a13cfc3 100644 --- a/Userland/Libraries/LibWeb/Animations/KeyframeEffect.cpp +++ b/Userland/Libraries/LibWeb/Animations/KeyframeEffect.cpp @@ -281,7 +281,7 @@ static bool is_loosely_sorted_by_offset(Vector const& keyframes) } // https://www.w3.org/TR/web-animations-1/#process-a-keyframes-argument -[[maybe_unused]] static WebIDL::ExceptionOr> process_a_keyframes_argument(JS::Realm& realm, JS::GCPtr object) +static WebIDL::ExceptionOr> process_a_keyframes_argument(JS::Realm& realm, JS::GCPtr object) { auto& vm = realm.vm(); @@ -688,16 +688,55 @@ void KeyframeEffect::set_pseudo_element(Optional pseudo_element) } // https://www.w3.org/TR/web-animations-1/#dom-keyframeeffect-getkeyframes -WebIDL::ExceptionOr> KeyframeEffect::get_keyframes() const +WebIDL::ExceptionOr> KeyframeEffect::get_keyframes() { - // FIXME: Implement this - return Vector {}; + if (m_keyframe_objects.size() != m_keyframes.size()) { + auto& vm = this->vm(); + auto& realm = this->realm(); + + // Recalculate the keyframe objects + VERIFY(m_keyframe_objects.size() == 0); + + for (auto& keyframe : m_keyframes) { + auto object = JS::Object::create(realm, realm.intrinsics().object_prototype()); + TRY(object->set(vm.names.offset, keyframe.offset.has_value() ? JS::Value(keyframe.offset.value()) : JS::js_null(), ShouldThrowExceptions::Yes)); + TRY(object->set(vm.names.computedOffset, JS::Value(keyframe.computed_offset.value()), ShouldThrowExceptions::Yes)); + auto easing_value = keyframe.easing.get>(); + TRY(object->set(vm.names.easing, JS::PrimitiveString::create(vm, easing_value->to_string()), ShouldThrowExceptions::Yes)); + + if (keyframe.composite == Bindings::CompositeOperationOrAuto::Replace) { + TRY(object->set(vm.names.composite, JS::PrimitiveString::create(vm, "replace"sv), ShouldThrowExceptions::Yes)); + } else if (keyframe.composite == Bindings::CompositeOperationOrAuto::Add) { + TRY(object->set(vm.names.composite, JS::PrimitiveString::create(vm, "add"sv), ShouldThrowExceptions::Yes)); + } else if (keyframe.composite == Bindings::CompositeOperationOrAuto::Accumulate) { + TRY(object->set(vm.names.composite, JS::PrimitiveString::create(vm, "accumulate"sv), ShouldThrowExceptions::Yes)); + } else { + TRY(object->set(vm.names.composite, JS::PrimitiveString::create(vm, "auto"sv), ShouldThrowExceptions::Yes)); + } + + for (auto const& [id, value] : keyframe.parsed_properties()) { + auto value_string = JS::PrimitiveString::create(vm, value->to_string()); + TRY(object->set(JS::PropertyKey(DeprecatedFlyString(CSS::string_from_property_id(id))), value_string, ShouldThrowExceptions::Yes)); + } + + m_keyframe_objects.append(object); + } + } + + return m_keyframe_objects; } // https://www.w3.org/TR/web-animations-1/#dom-keyframeeffect-setkeyframes -WebIDL::ExceptionOr KeyframeEffect::set_keyframes(Optional> const&) +WebIDL::ExceptionOr KeyframeEffect::set_keyframes(Optional> const& keyframe_object) { - // FIXME: Implement this + m_keyframe_objects.clear(); + m_keyframes = TRY(process_a_keyframes_argument(realm(), keyframe_object.has_value() ? JS::GCPtr { keyframe_object->ptr() } : JS::GCPtr {})); + // FIXME: After processing the keyframe argument, we need to turn the set of keyframes into a set of computed + // keyframes using the procedure outlined in the second half of + // https://www.w3.org/TR/web-animations-1/#calculating-computed-keyframes. For now, just compute the + // missing keyframe offsets + compute_missing_keyframe_offsets(m_keyframes); + return {}; } @@ -716,6 +755,8 @@ void KeyframeEffect::visit_edges(Cell::Visitor& visitor) { Base::visit_edges(visitor); visitor.visit(m_target_element); + for (auto const& keyframe : m_keyframe_objects) + visitor.visit(keyframe); } } diff --git a/Userland/Libraries/LibWeb/Animations/KeyframeEffect.h b/Userland/Libraries/LibWeb/Animations/KeyframeEffect.h index a0d73257810..e39ad72ba43 100644 --- a/Userland/Libraries/LibWeb/Animations/KeyframeEffect.h +++ b/Userland/Libraries/LibWeb/Animations/KeyframeEffect.h @@ -77,7 +77,7 @@ public: Bindings::CompositeOperation composite() const { return m_composite; } void set_composite(Bindings::CompositeOperation value) { m_composite = value; } - WebIDL::ExceptionOr> get_keyframes() const; + WebIDL::ExceptionOr> get_keyframes(); WebIDL::ExceptionOr set_keyframes(Optional> const&); private: @@ -97,6 +97,9 @@ private: // https://www.w3.org/TR/web-animations-1/#keyframe Vector m_keyframes {}; + + // A cached version of m_keyframes suitable for returning from get_keyframes() + Vector m_keyframe_objects {}; }; }