LibWeb: Add the AnimationEffect IDL object
This commit is contained in:
parent
e03e710d1b
commit
0df06ce273
Notes:
sideshowbarker
2024-07-17 09:49:33 +09:00
Author: https://github.com/mattco98 Commit: https://github.com/SerenityOS/serenity/commit/0df06ce273 Pull-request: https://github.com/SerenityOS/serenity/pull/21831
7 changed files with 336 additions and 1 deletions
|
@ -27,6 +27,8 @@ static bool is_platform_object(Type const& type)
|
|||
// might simply need to add another type here.
|
||||
static constexpr Array types = {
|
||||
"AbortSignal"sv,
|
||||
"AnimationEffect"sv,
|
||||
"AnimationTimeline"sv,
|
||||
"Attr"sv,
|
||||
"AudioTrack"sv,
|
||||
"Blob"sv,
|
||||
|
@ -3499,7 +3501,9 @@ void generate_constructor_implementation(IDL::Interface const& interface, String
|
|||
#include <LibWeb/Bindings/@prototype_class@.h>
|
||||
#include <LibWeb/Bindings/ExceptionOrUtils.h>
|
||||
#include <LibWeb/Bindings/Intrinsics.h>
|
||||
#if __has_include(<LibWeb/Crypto/@name@.h>)
|
||||
#if __has_include(<LibWeb/Animations/@name@.h>)
|
||||
# include <LibWeb/Animations/@name@.h>
|
||||
#elif __has_include(<LibWeb/Crypto/@name@.h>)
|
||||
# include <LibWeb/Crypto/@name@.h>
|
||||
#elif __has_include(<LibWeb/CSS/@name@.h>)
|
||||
# include <LibWeb/CSS/@name@.h>
|
||||
|
|
165
Userland/Libraries/LibWeb/Animations/AnimationEffect.cpp
Normal file
165
Userland/Libraries/LibWeb/Animations/AnimationEffect.cpp
Normal file
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Matthew Olsson <mattco@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Runtime/VM.h>
|
||||
#include <LibWeb/Animations/AnimationEffect.h>
|
||||
#include <LibWeb/Bindings/Intrinsics.h>
|
||||
#include <LibWeb/WebIDL/ExceptionOr.h>
|
||||
|
||||
namespace Web::Animations {
|
||||
|
||||
JS::NonnullGCPtr<AnimationEffect> AnimationEffect::create(JS::Realm& realm)
|
||||
{
|
||||
return realm.heap().allocate<AnimationEffect>(realm, realm);
|
||||
}
|
||||
|
||||
OptionalEffectTiming EffectTiming::to_optional_effect_timing() const
|
||||
{
|
||||
return {
|
||||
.delay = delay,
|
||||
.end_delay = end_delay,
|
||||
.fill = fill,
|
||||
.iteration_start = iteration_start,
|
||||
.iterations = iterations,
|
||||
.duration = duration,
|
||||
.direction = direction,
|
||||
.easing = easing,
|
||||
};
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#dom-animationeffect-gettiming
|
||||
EffectTiming AnimationEffect::get_timing() const
|
||||
{
|
||||
// 1. Returns the specified timing properties for this animation effect.
|
||||
return {
|
||||
.delay = m_start_delay,
|
||||
.end_delay = m_end_delay,
|
||||
.fill = m_fill_mode,
|
||||
.iteration_start = m_iteration_start,
|
||||
.iterations = m_iteration_count,
|
||||
.duration = m_iteration_duration,
|
||||
.direction = m_playback_direction,
|
||||
.easing = m_easing_function,
|
||||
};
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#dom-animationeffect-getcomputedtiming
|
||||
ComputedEffectTiming AnimationEffect::get_computed_timing() const
|
||||
{
|
||||
// 1. Returns the calculated timing properties for this animation effect.
|
||||
|
||||
// Note: Although some of the attributes of the object returned by getTiming() and getComputedTiming() are common,
|
||||
// their values may differ in the following ways:
|
||||
|
||||
// - duration: while getTiming() may return the string auto, getComputedTiming() must return a number
|
||||
// corresponding to the calculated value of the iteration duration as defined in the description of the
|
||||
// duration member of the EffectTiming interface.
|
||||
//
|
||||
// In this level of the specification, that simply means that an auto value is replaced by zero.
|
||||
auto duration = m_iteration_duration.has<String>() ? 0.0 : m_iteration_duration.get<double>();
|
||||
|
||||
// - fill: likewise, while getTiming() may return the string auto, getComputedTiming() must return the specific
|
||||
// FillMode used for timing calculations as defined in the description of the fill member of the EffectTiming
|
||||
// interface.
|
||||
//
|
||||
// In this level of the specification, that simply means that an auto value is replaced by the none FillMode.
|
||||
auto fill = m_fill_mode == Bindings::FillMode::Auto ? Bindings::FillMode::None : m_fill_mode;
|
||||
|
||||
return {
|
||||
{
|
||||
.delay = m_start_delay,
|
||||
.end_delay = m_end_delay,
|
||||
.fill = fill,
|
||||
.iteration_start = m_iteration_start,
|
||||
.iterations = m_iteration_count,
|
||||
.duration = duration,
|
||||
.direction = m_playback_direction,
|
||||
.easing = m_easing_function,
|
||||
},
|
||||
|
||||
// FIXME:
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
};
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#dom-animationeffect-updatetiming
|
||||
// https://www.w3.org/TR/web-animations-1/#update-the-timing-properties-of-an-animation-effect
|
||||
WebIDL::ExceptionOr<void> AnimationEffect::update_timing(OptionalEffectTiming timing)
|
||||
{
|
||||
// 1. If the iterationStart member of input exists and is less than zero, throw a TypeError and abort this
|
||||
// procedure.
|
||||
if (timing.iteration_start.has_value() && timing.iteration_start.value() < 0.0)
|
||||
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Invalid iteration start value"sv };
|
||||
|
||||
// 2. If the iterations member of input exists, and is less than zero or is the value NaN, throw a TypeError and
|
||||
// abort this procedure.
|
||||
if (timing.iterations.has_value() && (timing.iterations.value() < 0.0 || isnan(timing.iterations.value())))
|
||||
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Invalid iteration count value"sv };
|
||||
|
||||
// 3. If the duration member of input exists, and is less than zero or is the value NaN, throw a TypeError and
|
||||
// abort this procedure.
|
||||
// Note: "auto", the only valid string value, is treated as 0.
|
||||
auto& duration = timing.duration;
|
||||
if (duration.has_value() && duration->has<double>() && (duration->get<double>() < 0.0 || isnan(duration->get<double>())))
|
||||
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Invalid duration value"sv };
|
||||
|
||||
// FIXME:
|
||||
// 4. If the easing member of input exists but cannot be parsed using the <easing-function> production
|
||||
// [CSS-EASING-1], throw a TypeError and abort this procedure.
|
||||
|
||||
// 5. Assign each member that exists in input to the corresponding timing property of effect as follows:
|
||||
|
||||
// - delay → start delay
|
||||
if (timing.delay.has_value())
|
||||
m_start_delay = timing.delay.value();
|
||||
|
||||
// - endDelay → end delay
|
||||
if (timing.end_delay.has_value())
|
||||
m_end_delay = timing.end_delay.value();
|
||||
|
||||
// - fill → fill mode
|
||||
if (timing.fill.has_value())
|
||||
m_fill_mode = timing.fill.value();
|
||||
|
||||
// - iterationStart → iteration start
|
||||
if (timing.iteration_start.has_value())
|
||||
m_iteration_start = timing.iteration_start.value();
|
||||
|
||||
// - iterations → iteration count
|
||||
if (timing.iterations.has_value())
|
||||
m_iteration_count = timing.iterations.value();
|
||||
|
||||
// - duration → iteration duration
|
||||
if (timing.duration.has_value())
|
||||
m_iteration_duration = timing.duration.value();
|
||||
|
||||
// - direction → playback direction
|
||||
if (timing.direction.has_value())
|
||||
m_playback_direction = timing.direction.value();
|
||||
|
||||
// - easing → timing function
|
||||
if (timing.easing.has_value())
|
||||
m_easing_function = timing.easing.value();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
AnimationEffect::AnimationEffect(JS::Realm& realm)
|
||||
: Bindings::PlatformObject(realm)
|
||||
{
|
||||
}
|
||||
|
||||
void AnimationEffect::initialize(JS::Realm& realm)
|
||||
{
|
||||
Base::initialize(realm);
|
||||
set_prototype(&Bindings::ensure_web_prototype<Bindings::AnimationEffectPrototype>(realm, "AnimationEffect"));
|
||||
}
|
||||
|
||||
}
|
117
Userland/Libraries/LibWeb/Animations/AnimationEffect.h
Normal file
117
Userland/Libraries/LibWeb/Animations/AnimationEffect.h
Normal file
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Matthew Olsson <mattco@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/Variant.h>
|
||||
#include <LibWeb/Bindings/AnimationEffectPrototype.h>
|
||||
#include <LibWeb/Bindings/PlatformObject.h>
|
||||
|
||||
namespace Web::Animations {
|
||||
|
||||
// // https://www.w3.org/TR/web-animations-1/#the-effecttiming-dictionaries
|
||||
struct OptionalEffectTiming {
|
||||
Optional<double> delay {};
|
||||
Optional<double> end_delay {};
|
||||
Optional<Bindings::FillMode> fill {};
|
||||
Optional<double> iteration_start {};
|
||||
Optional<double> iterations {};
|
||||
Optional<Variant<double, String>> duration;
|
||||
Optional<Bindings::PlaybackDirection> direction {};
|
||||
Optional<String> easing {};
|
||||
};
|
||||
|
||||
// // https://www.w3.org/TR/web-animations-1/#the-effecttiming-dictionaries
|
||||
struct EffectTiming {
|
||||
double delay { 0 };
|
||||
double end_delay { 0 };
|
||||
Bindings::FillMode fill { Bindings::FillMode::Auto };
|
||||
double iteration_start { 0.0 };
|
||||
double iterations { 1.0 };
|
||||
Variant<double, String> duration { "auto"_string };
|
||||
Bindings::PlaybackDirection direction { Bindings::PlaybackDirection::Normal };
|
||||
String easing { "linear"_string };
|
||||
|
||||
OptionalEffectTiming to_optional_effect_timing() const;
|
||||
};
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#the-computedeffecttiming-dictionary
|
||||
struct ComputedEffectTiming : public EffectTiming {
|
||||
double end_time;
|
||||
double active_duration;
|
||||
Optional<double> local_time;
|
||||
Optional<double> progress;
|
||||
Optional<double> current_iteration;
|
||||
};
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#the-animationeffect-interface
|
||||
class AnimationEffect : public Bindings::PlatformObject {
|
||||
WEB_PLATFORM_OBJECT(AnimationEffect, Bindings::PlatformObject);
|
||||
|
||||
public:
|
||||
static JS::NonnullGCPtr<AnimationEffect> create(JS::Realm&);
|
||||
|
||||
EffectTiming get_timing() const;
|
||||
ComputedEffectTiming get_computed_timing() const;
|
||||
WebIDL::ExceptionOr<void> update_timing(OptionalEffectTiming timing = {});
|
||||
|
||||
double start_delay() const { return m_start_delay; }
|
||||
void set_start_delay(double start_delay) { m_start_delay = start_delay; }
|
||||
|
||||
double end_delay() const { return m_end_delay; }
|
||||
void set_end_delay(double end_delay) { m_end_delay = end_delay; }
|
||||
|
||||
Bindings::FillMode fill_mode() const { return m_fill_mode; }
|
||||
void set_fill_mode(Bindings::FillMode fill_mode) { m_fill_mode = fill_mode; }
|
||||
|
||||
double iteration_start() const { return m_iteration_start; }
|
||||
void set_iteration_start(double iteration_start) { m_iteration_start = iteration_start; }
|
||||
|
||||
double iteration_count() const { return m_iteration_count; }
|
||||
void set_iteration_count(double iteration_count) { m_iteration_count = iteration_count; }
|
||||
|
||||
Variant<double, String> const& iteration_duration() const { return m_iteration_duration; }
|
||||
void set_iteration_duration(Variant<double, String> iteration_duration) { m_iteration_duration = move(iteration_duration); }
|
||||
|
||||
Bindings::PlaybackDirection playback_direction() const { return m_playback_direction; }
|
||||
void set_playback_direction(Bindings::PlaybackDirection playback_direction) { m_playback_direction = playback_direction; }
|
||||
|
||||
String const& easing_function() const { return m_easing_function; }
|
||||
void set_easing_function(String easing_function) { m_easing_function = move(easing_function); }
|
||||
|
||||
protected:
|
||||
AnimationEffect(JS::Realm&);
|
||||
|
||||
virtual void initialize(JS::Realm&) override;
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#start-delay
|
||||
double m_start_delay { 0.0 };
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#end-delay
|
||||
double m_end_delay { 0.0 };
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#fill-mode
|
||||
Bindings::FillMode m_fill_mode { Bindings::FillMode::Auto };
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#iteration-start
|
||||
double m_iteration_start { 0.0 };
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#iteration-count
|
||||
double m_iteration_count { 1.0 };
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#iteration-duration
|
||||
Variant<double, String> m_iteration_duration { 0.0 };
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#playback-direction
|
||||
Bindings::PlaybackDirection m_playback_direction { Bindings::PlaybackDirection::Normal };
|
||||
|
||||
// https://www.w3.org/TR/css-easing-1/#easing-function
|
||||
String m_easing_function { "linear"_string };
|
||||
};
|
||||
|
||||
}
|
46
Userland/Libraries/LibWeb/Animations/AnimationEffect.idl
Normal file
46
Userland/Libraries/LibWeb/Animations/AnimationEffect.idl
Normal file
|
@ -0,0 +1,46 @@
|
|||
// https://www.w3.org/TR/web-animations-1/#the-effecttiming-dictionaries
|
||||
dictionary EffectTiming {
|
||||
double delay = 0;
|
||||
double endDelay = 0;
|
||||
FillMode fill = "auto";
|
||||
double iterationStart = 0.0;
|
||||
unrestricted double iterations = 1.0;
|
||||
(unrestricted double or DOMString) duration = "auto";
|
||||
PlaybackDirection direction = "normal";
|
||||
DOMString easing = "linear";
|
||||
};
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#dictdef-optionaleffecttiming
|
||||
dictionary OptionalEffectTiming {
|
||||
double delay;
|
||||
double endDelay;
|
||||
FillMode fill;
|
||||
double iterationStart;
|
||||
unrestricted double iterations;
|
||||
(unrestricted double or DOMString) duration;
|
||||
PlaybackDirection direction;
|
||||
DOMString easing;
|
||||
};
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#the-fillmode-enumeration
|
||||
enum FillMode { "none", "forwards", "backwards", "both", "auto" };
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#the-playbackdirection-enumeration
|
||||
enum PlaybackDirection { "normal", "reverse", "alternate", "alternate-reverse" };
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#the-computedeffecttiming-dictionary
|
||||
dictionary ComputedEffectTiming : EffectTiming {
|
||||
unrestricted double endTime;
|
||||
unrestricted double activeDuration;
|
||||
double? localTime;
|
||||
double? progress;
|
||||
unrestricted double? currentIteration;
|
||||
};
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#the-animationeffect-interface
|
||||
[Exposed=Window]
|
||||
interface AnimationEffect {
|
||||
EffectTiming getTiming();
|
||||
ComputedEffectTiming getComputedTiming();
|
||||
undefined updateTiming(optional OptionalEffectTiming timing = {});
|
||||
};
|
|
@ -2,6 +2,7 @@ include(libweb_generators)
|
|||
include(accelerated_graphics)
|
||||
|
||||
set(SOURCES
|
||||
Animations/AnimationEffect.cpp
|
||||
Animations/AnimationTimeline.cpp
|
||||
Animations/DocumentTimeline.cpp
|
||||
ARIA/AriaData.cpp
|
||||
|
|
|
@ -27,6 +27,7 @@ class RecordingPainter;
|
|||
}
|
||||
|
||||
namespace Web::Animations {
|
||||
class AnimationEffect;
|
||||
class AnimationTimeline;
|
||||
class DocumentTimeline;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# This file is included from "Meta/CMake/libweb_data.cmake"
|
||||
# It is defined here so that there is no need to go to the Meta directory when adding new idl files
|
||||
|
||||
libweb_js_bindings(Animations/AnimationEffect)
|
||||
libweb_js_bindings(Animations/AnimationTimeline)
|
||||
libweb_js_bindings(Animations/DocumentTimeline)
|
||||
libweb_js_bindings(Crypto/Crypto)
|
||||
|
|
Loading…
Add table
Reference in a new issue