mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 04:27:44 +00:00
LibWeb: Add KeyframeEffect IDL objects
This commit is contained in:
parent
99bb5a1d08
commit
5824916f8c
8 changed files with 303 additions and 0 deletions
|
@ -44,6 +44,7 @@ static bool is_platform_object(Type const& type)
|
||||||
"ImageData"sv,
|
"ImageData"sv,
|
||||||
"Instance"sv,
|
"Instance"sv,
|
||||||
"IntersectionObserverEntry"sv,
|
"IntersectionObserverEntry"sv,
|
||||||
|
"KeyframeEffect"sv,
|
||||||
"Memory"sv,
|
"Memory"sv,
|
||||||
"MessagePort"sv,
|
"MessagePort"sv,
|
||||||
"Module"sv,
|
"Module"sv,
|
||||||
|
|
|
@ -127,6 +127,8 @@ public:
|
||||||
Optional<double> current_iteration() const;
|
Optional<double> current_iteration() const;
|
||||||
Optional<double> transformed_progress() const;
|
Optional<double> transformed_progress() const;
|
||||||
|
|
||||||
|
virtual DOM::Element* target() const { return {}; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
AnimationEffect(JS::Realm&);
|
AnimationEffect(JS::Realm&);
|
||||||
|
|
||||||
|
|
169
Userland/Libraries/LibWeb/Animations/KeyframeEffect.cpp
Normal file
169
Userland/Libraries/LibWeb/Animations/KeyframeEffect.cpp
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Matthew Olsson <mattco@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <LibWeb/Animations/KeyframeEffect.h>
|
||||||
|
#include <LibWeb/WebIDL/ExceptionOr.h>
|
||||||
|
|
||||||
|
namespace Web::Animations {
|
||||||
|
|
||||||
|
JS::NonnullGCPtr<KeyframeEffect> KeyframeEffect::create(JS::Realm& realm)
|
||||||
|
{
|
||||||
|
return realm.heap().allocate<KeyframeEffect>(realm, realm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/web-animations-1/#dom-keyframeeffect-keyframeeffect
|
||||||
|
WebIDL::ExceptionOr<JS::NonnullGCPtr<KeyframeEffect>> KeyframeEffect::construct_impl(
|
||||||
|
JS::Realm& realm,
|
||||||
|
JS::Handle<DOM::Element> const& target,
|
||||||
|
JS::Handle<JS::Object> const& keyframes,
|
||||||
|
Variant<double, KeyframeEffectOptions> options)
|
||||||
|
{
|
||||||
|
auto& vm = realm.vm();
|
||||||
|
|
||||||
|
// 1. Create a new KeyframeEffect object, effect.
|
||||||
|
auto effect = vm.heap().allocate<KeyframeEffect>(realm, realm);
|
||||||
|
|
||||||
|
// 2. Set the target element of effect to target.
|
||||||
|
effect->set_target(target);
|
||||||
|
|
||||||
|
// 3. Set the target pseudo-selector to the result corresponding to the first matching condition from below.
|
||||||
|
|
||||||
|
// If options is a KeyframeEffectOptions object with a pseudoElement property,
|
||||||
|
if (options.has<KeyframeEffectOptions>()) {
|
||||||
|
// Set the target pseudo-selector to the value of the pseudoElement property.
|
||||||
|
//
|
||||||
|
// When assigning this property, the error-handling defined for the pseudoElement setter on the interface is
|
||||||
|
// applied. If the setter requires an exception to be thrown, this procedure must throw the same exception and
|
||||||
|
// abort all further steps.
|
||||||
|
effect->set_pseudo_element(options.get<KeyframeEffectOptions>().pseudo_element);
|
||||||
|
}
|
||||||
|
// Otherwise,
|
||||||
|
else {
|
||||||
|
// Set the target pseudo-selector to null.
|
||||||
|
// Note: This is the default when constructed
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Let timing input be the result corresponding to the first matching condition from below.
|
||||||
|
EffectTiming timing_input;
|
||||||
|
|
||||||
|
// If options is a KeyframeEffectOptions object,
|
||||||
|
if (options.has<KeyframeEffectOptions>()) {
|
||||||
|
// Let timing input be options.
|
||||||
|
timing_input = options.get<KeyframeEffectOptions>();
|
||||||
|
}
|
||||||
|
// Otherwise (if options is a double),
|
||||||
|
else {
|
||||||
|
// Let timing input be a new EffectTiming object with all members set to their default values and duration set
|
||||||
|
// to options.
|
||||||
|
timing_input = { .duration = options.get<double>() };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Call the procedure to update the timing properties of an animation effect of effect from timing input.
|
||||||
|
// If that procedure causes an exception to be thrown, propagate the exception and abort this procedure.
|
||||||
|
TRY(effect->update_timing(timing_input.to_optional_effect_timing()));
|
||||||
|
|
||||||
|
// 6. If options is a KeyframeEffectOptions object, assign the composite property of effect to the corresponding
|
||||||
|
// value from options.
|
||||||
|
//
|
||||||
|
// When assigning this property, the error-handling defined for the corresponding setter on the KeyframeEffect
|
||||||
|
// interface is applied. If the setter requires an exception to be thrown for the value specified by options,
|
||||||
|
// this procedure must throw the same exception and abort all further steps.
|
||||||
|
if (options.has<KeyframeEffectOptions>())
|
||||||
|
effect->set_composite(options.get<KeyframeEffectOptions>().composite);
|
||||||
|
|
||||||
|
// 7. Initialize the set of keyframes by performing the procedure defined for setKeyframes() passing keyframes as
|
||||||
|
// the input.
|
||||||
|
TRY(effect->set_keyframes(keyframes));
|
||||||
|
|
||||||
|
return effect;
|
||||||
|
}
|
||||||
|
|
||||||
|
WebIDL::ExceptionOr<JS::NonnullGCPtr<KeyframeEffect>> KeyframeEffect::construct_impl(JS::Realm& realm, JS::NonnullGCPtr<KeyframeEffect> source)
|
||||||
|
{
|
||||||
|
auto& vm = realm.vm();
|
||||||
|
|
||||||
|
// 1. Create a new KeyframeEffect object, effect.
|
||||||
|
auto effect = vm.heap().allocate<KeyframeEffect>(realm, realm);
|
||||||
|
|
||||||
|
// 2. Set the following properties of effect using the corresponding values of source:
|
||||||
|
|
||||||
|
// - effect target,
|
||||||
|
effect->m_target_element = source->target();
|
||||||
|
|
||||||
|
// FIXME:
|
||||||
|
// - keyframes,
|
||||||
|
|
||||||
|
// - composite operation, and
|
||||||
|
effect->set_composite(source->composite());
|
||||||
|
|
||||||
|
// - all specified timing properties:
|
||||||
|
|
||||||
|
// - start delay,
|
||||||
|
effect->m_start_delay = source->m_start_delay;
|
||||||
|
|
||||||
|
// - end delay,
|
||||||
|
effect->m_end_delay = source->m_end_delay;
|
||||||
|
|
||||||
|
// - fill mode,
|
||||||
|
effect->m_fill_mode = source->m_fill_mode;
|
||||||
|
|
||||||
|
// - iteration start,
|
||||||
|
effect->m_iteration_start = source->m_iteration_start;
|
||||||
|
|
||||||
|
// - iteration count,
|
||||||
|
effect->m_iteration_count = source->m_iteration_count;
|
||||||
|
|
||||||
|
// - iteration duration,
|
||||||
|
effect->m_iteration_duration = source->m_iteration_duration;
|
||||||
|
|
||||||
|
// - playback direction, and
|
||||||
|
effect->m_playback_direction = source->m_playback_direction;
|
||||||
|
|
||||||
|
// - timing function.
|
||||||
|
effect->m_easing_function = source->m_easing_function;
|
||||||
|
|
||||||
|
return effect;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyframeEffect::set_pseudo_element(Optional<String> pseudo_element)
|
||||||
|
{
|
||||||
|
// FIXME: Implement this
|
||||||
|
(void)pseudo_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/web-animations-1/#dom-keyframeeffect-getkeyframes
|
||||||
|
WebIDL::ExceptionOr<Vector<JS::Object*>> KeyframeEffect::get_keyframes() const
|
||||||
|
{
|
||||||
|
// FIXME: Implement this
|
||||||
|
return Vector<JS::Object*> {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/web-animations-1/#dom-keyframeeffect-setkeyframes
|
||||||
|
WebIDL::ExceptionOr<void> KeyframeEffect::set_keyframes(JS::Object* keyframe_object)
|
||||||
|
{
|
||||||
|
// FIXME: Implement this
|
||||||
|
(void)keyframe_object;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyframeEffect::KeyframeEffect(JS::Realm& realm)
|
||||||
|
: AnimationEffect(realm)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyframeEffect::initialize(JS::Realm& realm)
|
||||||
|
{
|
||||||
|
Base::initialize(realm);
|
||||||
|
set_prototype(&Bindings::ensure_web_prototype<Bindings::KeyframeEffectPrototype>(realm, "KeyframeEffect"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyframeEffect::visit_edges(Cell::Visitor& visitor)
|
||||||
|
{
|
||||||
|
Base::visit_edges(visitor);
|
||||||
|
visitor.visit(m_target_element);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
85
Userland/Libraries/LibWeb/Animations/KeyframeEffect.h
Normal file
85
Userland/Libraries/LibWeb/Animations/KeyframeEffect.h
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Matthew Olsson <mattco@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Optional.h>
|
||||||
|
#include <LibWeb/Animations/AnimationEffect.h>
|
||||||
|
#include <LibWeb/Bindings/KeyframeEffectPrototype.h>
|
||||||
|
#include <LibWeb/Bindings/PlatformObject.h>
|
||||||
|
#include <LibWeb/DOM/Element.h>
|
||||||
|
|
||||||
|
namespace Web::Animations {
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/web-animations-1/#the-keyframeeffectoptions-dictionary
|
||||||
|
struct KeyframeEffectOptions : public EffectTiming {
|
||||||
|
Bindings::CompositeOperation composite { Bindings::CompositeOperation::Replace };
|
||||||
|
Optional<String> pseudo_element {};
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/web-animations-1/#dictdef-basepropertyindexedkeyframe
|
||||||
|
struct BasePropertyIndexedKeyframe {
|
||||||
|
Variant<Optional<double>, Vector<Optional<double>>> offset { Vector<Optional<double>> {} };
|
||||||
|
Variant<String, Vector<String>> easing { Vector<String> {} };
|
||||||
|
Variant<Bindings::CompositeOperationOrAuto, Vector<Bindings::CompositeOperationOrAuto>> composite { Vector<Bindings::CompositeOperationOrAuto> {} };
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/web-animations-1/#dictdef-basekeyframe
|
||||||
|
struct BaseKeyframe {
|
||||||
|
Optional<double> offset {};
|
||||||
|
String easing { "linear"_string };
|
||||||
|
Bindings::CompositeOperationOrAuto composite { Bindings::CompositeOperationOrAuto::Auto };
|
||||||
|
|
||||||
|
Optional<double> computed_offset {};
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/web-animations-1/#the-keyframeeffect-interface
|
||||||
|
class KeyframeEffect : public AnimationEffect {
|
||||||
|
WEB_PLATFORM_OBJECT(KeyframeEffect, AnimationEffect);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static JS::NonnullGCPtr<KeyframeEffect> create(JS::Realm&);
|
||||||
|
|
||||||
|
static WebIDL::ExceptionOr<JS::NonnullGCPtr<KeyframeEffect>> construct_impl(
|
||||||
|
JS::Realm&,
|
||||||
|
JS::Handle<DOM::Element> const& target,
|
||||||
|
JS::Handle<JS::Object> const& keyframes,
|
||||||
|
Variant<double, KeyframeEffectOptions> options = KeyframeEffectOptions {});
|
||||||
|
|
||||||
|
static WebIDL::ExceptionOr<JS::NonnullGCPtr<KeyframeEffect>> construct_impl(JS::Realm&, JS::NonnullGCPtr<KeyframeEffect> source);
|
||||||
|
|
||||||
|
DOM::Element* target() const override { return m_target_element; }
|
||||||
|
void set_target(DOM::Element* target) { m_target_element = target; }
|
||||||
|
|
||||||
|
Optional<String> pseudo_element() const { return m_target_pseudo_selector; }
|
||||||
|
void set_pseudo_element(Optional<String>);
|
||||||
|
|
||||||
|
Bindings::CompositeOperation composite() const { return m_composite; }
|
||||||
|
void set_composite(Bindings::CompositeOperation value) { m_composite = value; }
|
||||||
|
|
||||||
|
WebIDL::ExceptionOr<Vector<JS::Object*>> get_keyframes() const;
|
||||||
|
WebIDL::ExceptionOr<void> set_keyframes(JS::Object*);
|
||||||
|
|
||||||
|
private:
|
||||||
|
KeyframeEffect(JS::Realm&);
|
||||||
|
|
||||||
|
virtual void initialize(JS::Realm&) override;
|
||||||
|
virtual void visit_edges(Cell::Visitor&) override;
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/web-animations-1/#effect-target-target-element
|
||||||
|
JS::GCPtr<DOM::Element> m_target_element {};
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/web-animations-1/#dom-keyframeeffect-pseudoelement
|
||||||
|
Optional<String> m_target_pseudo_selector {};
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/web-animations-1/#dom-keyframeeffect-composite
|
||||||
|
Bindings::CompositeOperation m_composite { Bindings::CompositeOperation::Replace };
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/web-animations-1/#keyframe
|
||||||
|
Vector<BaseKeyframe> m_keyframes {};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
43
Userland/Libraries/LibWeb/Animations/KeyframeEffect.idl
Normal file
43
Userland/Libraries/LibWeb/Animations/KeyframeEffect.idl
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#import <Animations/AnimationEffect.idl>
|
||||||
|
#import <DOM/Element.idl>
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/web-animations-1/#the-compositeoperation-enumeration
|
||||||
|
enum CompositeOperation { "replace", "add", "accumulate" };
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/web-animations-1/#enumdef-compositeoperationorauto
|
||||||
|
enum CompositeOperationOrAuto { "replace", "add", "accumulate", "auto" };
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/web-animations-1/#the-keyframeeffectoptions-dictionary
|
||||||
|
dictionary KeyframeEffectOptions : EffectTiming {
|
||||||
|
CompositeOperation composite = "replace";
|
||||||
|
CSSOMString? pseudoElement = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/web-animations-1/#dictdef-basepropertyindexedkeyframe
|
||||||
|
dictionary BasePropertyIndexedKeyframe {
|
||||||
|
(double? or sequence<double?>) offset = [];
|
||||||
|
(DOMString or sequence<DOMString>) easing = [];
|
||||||
|
(CompositeOperationOrAuto or sequence<CompositeOperationOrAuto>) composite = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/web-animations-1/#dictdef-basekeyframe
|
||||||
|
dictionary BaseKeyframe {
|
||||||
|
double? offset = null;
|
||||||
|
DOMString easing = "linear";
|
||||||
|
CompositeOperationOrAuto composite = "auto";
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/web-animations-1/#the-keyframeeffect-interface
|
||||||
|
[Exposed=Window]
|
||||||
|
interface KeyframeEffect : AnimationEffect {
|
||||||
|
constructor(Element? target,
|
||||||
|
object? keyframes,
|
||||||
|
optional (unrestricted double or KeyframeEffectOptions) options = {});
|
||||||
|
constructor(KeyframeEffect source);
|
||||||
|
|
||||||
|
attribute Element? target;
|
||||||
|
attribute CSSOMString? pseudoElement;
|
||||||
|
attribute CompositeOperation composite;
|
||||||
|
sequence<object> getKeyframes();
|
||||||
|
undefined setKeyframes(object? keyframes);
|
||||||
|
};
|
|
@ -7,6 +7,7 @@ set(SOURCES
|
||||||
Animations/AnimationPlaybackEvent.cpp
|
Animations/AnimationPlaybackEvent.cpp
|
||||||
Animations/AnimationTimeline.cpp
|
Animations/AnimationTimeline.cpp
|
||||||
Animations/DocumentTimeline.cpp
|
Animations/DocumentTimeline.cpp
|
||||||
|
Animations/KeyframeEffect.cpp
|
||||||
Animations/TimingFunction.cpp
|
Animations/TimingFunction.cpp
|
||||||
ARIA/AriaData.cpp
|
ARIA/AriaData.cpp
|
||||||
ARIA/ARIAMixin.cpp
|
ARIA/ARIAMixin.cpp
|
||||||
|
|
|
@ -32,6 +32,7 @@ class AnimationEffect;
|
||||||
class AnimationPlaybackEvent;
|
class AnimationPlaybackEvent;
|
||||||
class AnimationTimeline;
|
class AnimationTimeline;
|
||||||
class DocumentTimeline;
|
class DocumentTimeline;
|
||||||
|
class KeyframeEffect;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Web::ARIA {
|
namespace Web::ARIA {
|
||||||
|
|
|
@ -6,6 +6,7 @@ libweb_js_bindings(Animations/AnimationEffect)
|
||||||
libweb_js_bindings(Animations/AnimationPlaybackEvent)
|
libweb_js_bindings(Animations/AnimationPlaybackEvent)
|
||||||
libweb_js_bindings(Animations/AnimationTimeline)
|
libweb_js_bindings(Animations/AnimationTimeline)
|
||||||
libweb_js_bindings(Animations/DocumentTimeline)
|
libweb_js_bindings(Animations/DocumentTimeline)
|
||||||
|
libweb_js_bindings(Animations/KeyframeEffect)
|
||||||
libweb_js_bindings(Clipboard/Clipboard)
|
libweb_js_bindings(Clipboard/Clipboard)
|
||||||
libweb_js_bindings(Crypto/Crypto)
|
libweb_js_bindings(Crypto/Crypto)
|
||||||
libweb_js_bindings(Crypto/SubtleCrypto)
|
libweb_js_bindings(Crypto/SubtleCrypto)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue