AnimationEffect.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. /*
  2. * Copyright (c) 2023-2024, Matthew Olsson <mattco@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibJS/Runtime/VM.h>
  7. #include <LibWeb/Animations/Animation.h>
  8. #include <LibWeb/Animations/AnimationEffect.h>
  9. #include <LibWeb/Animations/AnimationTimeline.h>
  10. #include <LibWeb/Bindings/Intrinsics.h>
  11. #include <LibWeb/DOM/Element.h>
  12. #include <LibWeb/WebIDL/ExceptionOr.h>
  13. namespace Web::Animations {
  14. JS_DEFINE_ALLOCATOR(AnimationEffect);
  15. Bindings::FillMode css_fill_mode_to_bindings_fill_mode(CSS::AnimationFillMode mode)
  16. {
  17. switch (mode) {
  18. case CSS::AnimationFillMode::Backwards:
  19. return Bindings::FillMode::Backwards;
  20. case CSS::AnimationFillMode::Both:
  21. return Bindings::FillMode::Both;
  22. case CSS::AnimationFillMode::Forwards:
  23. return Bindings::FillMode::Forwards;
  24. case CSS::AnimationFillMode::None:
  25. return Bindings::FillMode::None;
  26. default:
  27. VERIFY_NOT_REACHED();
  28. }
  29. }
  30. Bindings::PlaybackDirection css_animation_direction_to_bindings_playback_direction(CSS::AnimationDirection direction)
  31. {
  32. switch (direction) {
  33. case CSS::AnimationDirection::Alternate:
  34. return Bindings::PlaybackDirection::Alternate;
  35. case CSS::AnimationDirection::AlternateReverse:
  36. return Bindings::PlaybackDirection::AlternateReverse;
  37. case CSS::AnimationDirection::Normal:
  38. return Bindings::PlaybackDirection::Normal;
  39. case CSS::AnimationDirection::Reverse:
  40. return Bindings::PlaybackDirection::Reverse;
  41. default:
  42. VERIFY_NOT_REACHED();
  43. }
  44. }
  45. JS::NonnullGCPtr<AnimationEffect> AnimationEffect::create(JS::Realm& realm)
  46. {
  47. return realm.heap().allocate<AnimationEffect>(realm, realm);
  48. }
  49. OptionalEffectTiming EffectTiming::to_optional_effect_timing() const
  50. {
  51. return {
  52. .delay = delay,
  53. .end_delay = end_delay,
  54. .fill = fill,
  55. .iteration_start = iteration_start,
  56. .iterations = iterations,
  57. .duration = duration,
  58. .direction = direction,
  59. .easing = easing,
  60. };
  61. }
  62. // https://www.w3.org/TR/web-animations-1/#dom-animationeffect-gettiming
  63. EffectTiming AnimationEffect::get_timing() const
  64. {
  65. // 1. Returns the specified timing properties for this animation effect.
  66. return {
  67. .delay = m_start_delay,
  68. .end_delay = m_end_delay,
  69. .fill = m_fill_mode,
  70. .iteration_start = m_iteration_start,
  71. .iterations = m_iteration_count,
  72. .duration = m_iteration_duration,
  73. .direction = m_playback_direction,
  74. .easing = m_easing_function,
  75. };
  76. }
  77. // https://www.w3.org/TR/web-animations-1/#dom-animationeffect-getcomputedtiming
  78. ComputedEffectTiming AnimationEffect::get_computed_timing() const
  79. {
  80. // 1. Returns the calculated timing properties for this animation effect.
  81. // Note: Although some of the attributes of the object returned by getTiming() and getComputedTiming() are common,
  82. // their values may differ in the following ways:
  83. // - duration: while getTiming() may return the string auto, getComputedTiming() must return a number
  84. // corresponding to the calculated value of the iteration duration as defined in the description of the
  85. // duration member of the EffectTiming interface.
  86. //
  87. // In this level of the specification, that simply means that an auto value is replaced by zero.
  88. auto duration = m_iteration_duration.has<String>() ? 0.0 : m_iteration_duration.get<double>();
  89. // - fill: likewise, while getTiming() may return the string auto, getComputedTiming() must return the specific
  90. // FillMode used for timing calculations as defined in the description of the fill member of the EffectTiming
  91. // interface.
  92. //
  93. // In this level of the specification, that simply means that an auto value is replaced by the none FillMode.
  94. auto fill = m_fill_mode == Bindings::FillMode::Auto ? Bindings::FillMode::None : m_fill_mode;
  95. return {
  96. {
  97. .delay = m_start_delay,
  98. .end_delay = m_end_delay,
  99. .fill = fill,
  100. .iteration_start = m_iteration_start,
  101. .iterations = m_iteration_count,
  102. .duration = duration,
  103. .direction = m_playback_direction,
  104. .easing = m_easing_function,
  105. },
  106. end_time(),
  107. active_duration(),
  108. local_time(),
  109. transformed_progress(),
  110. current_iteration(),
  111. };
  112. }
  113. // https://www.w3.org/TR/web-animations-1/#dom-animationeffect-updatetiming
  114. // https://www.w3.org/TR/web-animations-1/#update-the-timing-properties-of-an-animation-effect
  115. WebIDL::ExceptionOr<void> AnimationEffect::update_timing(OptionalEffectTiming timing)
  116. {
  117. // 1. If the iterationStart member of input exists and is less than zero, throw a TypeError and abort this
  118. // procedure.
  119. if (timing.iteration_start.has_value() && timing.iteration_start.value() < 0.0)
  120. return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Invalid iteration start value"sv };
  121. // 2. If the iterations member of input exists, and is less than zero or is the value NaN, throw a TypeError and
  122. // abort this procedure.
  123. if (timing.iterations.has_value() && (timing.iterations.value() < 0.0 || isnan(timing.iterations.value())))
  124. return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Invalid iteration count value"sv };
  125. // 3. If the duration member of input exists, and is less than zero or is the value NaN, throw a TypeError and
  126. // abort this procedure.
  127. // Note: "auto", the only valid string value, is treated as 0.
  128. auto& duration = timing.duration;
  129. if (duration.has_value() && duration->has<double>() && (duration->get<double>() < 0.0 || isnan(duration->get<double>())))
  130. return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Invalid duration value"sv };
  131. // FIXME:
  132. // 4. If the easing member of input exists but cannot be parsed using the <easing-function> production
  133. // [CSS-EASING-1], throw a TypeError and abort this procedure.
  134. // 5. Assign each member that exists in input to the corresponding timing property of effect as follows:
  135. // - delay → start delay
  136. if (timing.delay.has_value())
  137. m_start_delay = timing.delay.value();
  138. // - endDelay → end delay
  139. if (timing.end_delay.has_value())
  140. m_end_delay = timing.end_delay.value();
  141. // - fill → fill mode
  142. if (timing.fill.has_value())
  143. m_fill_mode = timing.fill.value();
  144. // - iterationStart → iteration start
  145. if (timing.iteration_start.has_value())
  146. m_iteration_start = timing.iteration_start.value();
  147. // - iterations → iteration count
  148. if (timing.iterations.has_value())
  149. m_iteration_count = timing.iterations.value();
  150. // - duration → iteration duration
  151. if (timing.duration.has_value())
  152. m_iteration_duration = timing.duration.value();
  153. // - direction → playback direction
  154. if (timing.direction.has_value())
  155. m_playback_direction = timing.direction.value();
  156. // - easing → timing function
  157. if (timing.easing.has_value())
  158. m_easing_function = timing.easing.value();
  159. if (auto animation = m_associated_animation)
  160. animation->effect_timing_changed({});
  161. return {};
  162. }
  163. void AnimationEffect::set_associated_animation(JS::GCPtr<Animation> value)
  164. {
  165. m_associated_animation = value;
  166. if (auto* target = this->target())
  167. target->invalidate_style();
  168. }
  169. // https://www.w3.org/TR/web-animations-1/#animation-direction
  170. AnimationDirection AnimationEffect::animation_direction() const
  171. {
  172. // "backwards" if the effect is associated with an animation and the associated animation’s playback rate is less
  173. // than zero; in all other cases, the animation direction is "forwards".
  174. if (m_associated_animation && m_associated_animation->playback_rate() < 0.0)
  175. return AnimationDirection::Backwards;
  176. return AnimationDirection::Forwards;
  177. }
  178. // https://www.w3.org/TR/web-animations-1/#end-time
  179. double AnimationEffect::end_time() const
  180. {
  181. // 1. The end time of an animation effect is the result of evaluating
  182. // max(start delay + active duration + end delay, 0).
  183. return max(m_start_delay + active_duration() + m_end_delay, 0.0);
  184. }
  185. // https://www.w3.org/TR/web-animations-1/#local-time
  186. Optional<double> AnimationEffect::local_time() const
  187. {
  188. // The local time of an animation effect at a given moment is based on the first matching condition from the
  189. // following:
  190. // -> If the animation effect is associated with an animation,
  191. if (m_associated_animation) {
  192. // the local time is the current time of the animation.
  193. return m_associated_animation->current_time();
  194. }
  195. // -> Otherwise,
  196. // the local time is unresolved.
  197. return {};
  198. }
  199. // https://www.w3.org/TR/web-animations-1/#active-duration
  200. double AnimationEffect::active_duration() const
  201. {
  202. // The active duration is calculated as follows:
  203. // active duration = iteration duration × iteration count
  204. // If either the iteration duration or iteration count are zero, the active duration is zero. This clarification is
  205. // needed since the result of infinity multiplied by zero is undefined according to IEEE 754-2008.
  206. if (m_iteration_duration.has<String>() || m_iteration_duration.get<double>() == 0.0 || m_iteration_count == 0.0)
  207. return 0.0;
  208. return m_iteration_duration.get<double>() * m_iteration_count;
  209. }
  210. Optional<double> AnimationEffect::active_time() const
  211. {
  212. return active_time_using_fill(m_fill_mode);
  213. }
  214. // https://www.w3.org/TR/web-animations-1/#calculating-the-active-time
  215. Optional<double> AnimationEffect::active_time_using_fill(Bindings::FillMode fill_mode) const
  216. {
  217. // The active time is based on the local time and start delay. However, it is only defined when the animation effect
  218. // should produce an output and hence depends on its fill mode and phase as follows,
  219. // -> If the animation effect is in the before phase,
  220. if (is_in_the_before_phase()) {
  221. // The result depends on the first matching condition from the following,
  222. // -> If the fill mode is backwards or both,
  223. if (fill_mode == Bindings::FillMode::Backwards || fill_mode == Bindings::FillMode::Both) {
  224. // Return the result of evaluating max(local time - start delay, 0).
  225. return max(local_time().value() - m_start_delay, 0.0);
  226. }
  227. // -> Otherwise,
  228. // Return an unresolved time value.
  229. return {};
  230. }
  231. // -> If the animation effect is in the active phase,
  232. if (is_in_the_active_phase()) {
  233. // Return the result of evaluating local time - start delay.
  234. return local_time().value() - m_start_delay;
  235. }
  236. // -> If the animation effect is in the after phase,
  237. if (is_in_the_after_phase()) {
  238. // The result depends on the first matching condition from the following,
  239. // -> If the fill mode is forwards or both,
  240. if (fill_mode == Bindings::FillMode::Forwards || fill_mode == Bindings::FillMode::Both) {
  241. // Return the result of evaluating max(min(local time - start delay, active duration), 0).
  242. return max(min(local_time().value() - m_start_delay, active_duration()), 0.0);
  243. }
  244. // -> Otherwise,
  245. // Return an unresolved time value.
  246. return {};
  247. }
  248. // -> Otherwise (the local time is unresolved),
  249. // Return an unresolved time value.
  250. return {};
  251. }
  252. // https://www.w3.org/TR/web-animations-1/#in-play
  253. bool AnimationEffect::is_in_play() const
  254. {
  255. // An animation effect is in play if all of the following conditions are met:
  256. // - the animation effect is in the active phase, and
  257. // - the animation effect is associated with an animation that is not finished.
  258. return is_in_the_active_phase() && m_associated_animation && !m_associated_animation->is_finished();
  259. }
  260. // https://www.w3.org/TR/web-animations-1/#current
  261. bool AnimationEffect::is_current() const
  262. {
  263. // An animation effect is current if any of the following conditions are true:
  264. // - the animation effect is in play, or
  265. if (is_in_play())
  266. return true;
  267. if (auto animation = m_associated_animation) {
  268. auto playback_rate = animation->playback_rate();
  269. // - the animation effect is associated with an animation with a playback rate > 0 and the animation effect is
  270. // in the before phase, or
  271. if (playback_rate > 0.0 && is_in_the_before_phase())
  272. return true;
  273. // - the animation effect is associated with an animation with a playback rate < 0 and the animation effect is
  274. // in the after phase, or
  275. if (playback_rate < 0.0 && is_in_the_after_phase())
  276. return true;
  277. // - the animation effect is associated with an animation not in the idle play state with a non-null associated
  278. // timeline that is not monotonically increasing.
  279. if (animation->play_state() != Bindings::AnimationPlayState::Idle && animation->timeline() && !animation->timeline()->is_monotonically_increasing())
  280. return true;
  281. }
  282. return false;
  283. }
  284. // https://www.w3.org/TR/web-animations-1/#in-effect
  285. bool AnimationEffect::is_in_effect() const
  286. {
  287. // An animation effect is in effect if its active time, as calculated according to the procedure in
  288. // §4.8.3.1 Calculating the active time, is not unresolved.
  289. return active_time().has_value();
  290. }
  291. // https://www.w3.org/TR/web-animations-1/#before-active-boundary-time
  292. double AnimationEffect::before_active_boundary_time() const
  293. {
  294. // max(min(start delay, end time), 0)
  295. return max(min(m_start_delay, end_time()), 0.0);
  296. }
  297. // https://www.w3.org/TR/web-animations-1/#active-after-boundary-time
  298. double AnimationEffect::after_active_boundary_time() const
  299. {
  300. // max(min(start delay + active duration, end time), 0)
  301. return max(min(m_start_delay + active_duration(), end_time()), 0.0);
  302. }
  303. // https://www.w3.org/TR/web-animations-1/#animation-effect-before-phase
  304. bool AnimationEffect::is_in_the_before_phase() const
  305. {
  306. // An animation effect is in the before phase if the animation effect’s local time is not unresolved and either of
  307. // the following conditions are met:
  308. auto local_time = this->local_time();
  309. if (!local_time.has_value())
  310. return false;
  311. // - the local time is less than the before-active boundary time, or
  312. auto before_active_boundary_time = this->before_active_boundary_time();
  313. if (local_time.value() < before_active_boundary_time)
  314. return true;
  315. // - the animation direction is "backwards" and the local time is equal to the before-active boundary time.
  316. return animation_direction() == AnimationDirection::Backwards && local_time.value() == before_active_boundary_time;
  317. }
  318. // https://www.w3.org/TR/web-animations-1/#animation-effect-after-phase
  319. bool AnimationEffect::is_in_the_after_phase() const
  320. {
  321. // An animation effect is in the after phase if the animation effect’s local time is not unresolved and either of
  322. // the following conditions are met:
  323. auto local_time = this->local_time();
  324. if (!local_time.has_value())
  325. return false;
  326. // - the local time is greater than the active-after boundary time, or
  327. auto after_active_boundary_time = this->after_active_boundary_time();
  328. if (local_time.value() > after_active_boundary_time)
  329. return true;
  330. // - the animation direction is "forwards" and the local time is equal to the active-after boundary time.
  331. return animation_direction() == AnimationDirection::Forwards && local_time.value() == after_active_boundary_time;
  332. }
  333. // https://www.w3.org/TR/web-animations-1/#animation-effect-active-phase
  334. bool AnimationEffect::is_in_the_active_phase() const
  335. {
  336. // An animation effect is in the active phase if the animation effect’s local time is not unresolved and it is not
  337. // in either the before phase nor the after phase.
  338. return local_time().has_value() && !is_in_the_before_phase() && !is_in_the_after_phase();
  339. }
  340. // https://www.w3.org/TR/web-animations-1/#animation-effect-idle-phase
  341. bool AnimationEffect::is_in_the_idle_phase() const
  342. {
  343. // It is often convenient to refer to the case when an animation effect is in none of the above phases as being in
  344. // the idle phase
  345. return !is_in_the_before_phase() && !is_in_the_active_phase() && !is_in_the_after_phase();
  346. }
  347. AnimationEffect::Phase AnimationEffect::phase() const
  348. {
  349. // This is a convenience method that returns the phase of the animation effect, to avoid having to call all of the
  350. // phase functions separately.
  351. // FIXME: There is a lot of duplicated condition checking here which can probably be inlined into this function
  352. if (is_in_the_before_phase())
  353. return Phase::Before;
  354. if (is_in_the_active_phase())
  355. return Phase::Active;
  356. if (is_in_the_after_phase())
  357. return Phase::After;
  358. return Phase::Idle;
  359. }
  360. // https://www.w3.org/TR/web-animations-1/#overall-progress
  361. Optional<double> AnimationEffect::overall_progress() const
  362. {
  363. // 1. If the active time is unresolved, return unresolved.
  364. auto active_time = this->active_time();
  365. if (!active_time.has_value())
  366. return {};
  367. // 2. Calculate an initial value for overall progress based on the first matching condition from below,
  368. double overall_progress;
  369. // -> If the iteration duration is zero,
  370. if (m_iteration_duration.has<String>() || m_iteration_duration.get<double>() == 0.0) {
  371. // If the animation effect is in the before phase, let overall progress be zero, otherwise, let it be equal to
  372. // the iteration count.
  373. if (is_in_the_before_phase())
  374. overall_progress = 0.0;
  375. else
  376. overall_progress = m_iteration_count;
  377. }
  378. // Otherwise,
  379. else {
  380. // Let overall progress be the result of calculating active time / iteration duration.
  381. overall_progress = active_time.value() / m_iteration_duration.get<double>();
  382. }
  383. // 3. Return the result of calculating overall progress + iteration start.
  384. return overall_progress + m_iteration_start;
  385. }
  386. // https://www.w3.org/TR/web-animations-1/#directed-progress
  387. Optional<double> AnimationEffect::directed_progress() const
  388. {
  389. // 1. If the simple iteration progress is unresolved, return unresolved.
  390. auto simple_iteration_progress = this->simple_iteration_progress();
  391. if (!simple_iteration_progress.has_value())
  392. return {};
  393. // 2. Calculate the current direction using the first matching condition from the following list:
  394. auto current_direction = this->current_direction();
  395. // 3. If the current direction is forwards then return the simple iteration progress.
  396. if (current_direction == AnimationDirection::Forwards)
  397. return simple_iteration_progress;
  398. // Otherwise, return 1.0 - simple iteration progress.
  399. return 1.0 - simple_iteration_progress.value();
  400. }
  401. // https://www.w3.org/TR/web-animations-1/#directed-progress
  402. AnimationDirection AnimationEffect::current_direction() const
  403. {
  404. // 2. Calculate the current direction using the first matching condition from the following list:
  405. // -> If playback direction is normal,
  406. if (m_playback_direction == Bindings::PlaybackDirection::Normal) {
  407. // Let the current direction be forwards.
  408. return AnimationDirection::Forwards;
  409. }
  410. // -> If playback direction is reverse,
  411. if (m_playback_direction == Bindings::PlaybackDirection::Reverse) {
  412. // Let the current direction be reverse.
  413. return AnimationDirection::Backwards;
  414. }
  415. // -> Otherwise,
  416. // 1. Let d be the current iteration.
  417. double d = current_iteration().value();
  418. // 2. If playback direction is alternate-reverse increment d by 1.
  419. if (m_playback_direction == Bindings::PlaybackDirection::AlternateReverse)
  420. d += 1.0;
  421. // 3. If d % 2 == 0, let the current direction be forwards, otherwise let the current direction be reverse. If d
  422. // is infinity, let the current direction be forwards.
  423. if (isinf(d))
  424. return AnimationDirection::Forwards;
  425. if (fmod(d, 2.0) == 0.0)
  426. return AnimationDirection::Forwards;
  427. return AnimationDirection::Backwards;
  428. }
  429. // https://www.w3.org/TR/web-animations-1/#simple-iteration-progress
  430. Optional<double> AnimationEffect::simple_iteration_progress() const
  431. {
  432. // 1. If the overall progress is unresolved, return unresolved.
  433. auto overall_progress = this->overall_progress();
  434. if (!overall_progress.has_value())
  435. return {};
  436. // 2. If overall progress is infinity, let the simple iteration progress be iteration start % 1.0, otherwise, let
  437. // the simple iteration progress be overall progress % 1.0.
  438. double simple_iteration_progress = isinf(overall_progress.value()) ? fmod(m_iteration_start, 1.0) : fmod(overall_progress.value(), 1.0);
  439. // 3. If all of the following conditions are true,
  440. // - the simple iteration progress calculated above is zero, and
  441. // - the animation effect is in the active phase or the after phase, and
  442. // - the active time is equal to the active duration, and
  443. // - the iteration count is not equal to zero.
  444. auto active_time = this->active_time();
  445. if (simple_iteration_progress == 0.0 && (is_in_the_active_phase() || is_in_the_after_phase()) && active_time.has_value() && active_time.value() == active_duration() && m_iteration_count != 0.0) {
  446. // let the simple iteration progress be 1.0.
  447. simple_iteration_progress = 1.0;
  448. }
  449. // 4. Return simple iteration progress.
  450. return simple_iteration_progress;
  451. }
  452. // https://www.w3.org/TR/web-animations-1/#current-iteration
  453. Optional<double> AnimationEffect::current_iteration() const
  454. {
  455. // 1. If the active time is unresolved, return unresolved.
  456. auto active_time = this->active_time();
  457. if (!active_time.has_value())
  458. return {};
  459. // 2. If the animation effect is in the after phase and the iteration count is infinity, return infinity.
  460. if (is_in_the_after_phase() && isinf(m_iteration_count))
  461. return m_iteration_count;
  462. // 3. If the simple iteration progress is 1.0, return floor(overall progress) - 1.
  463. auto simple_iteration_progress = this->simple_iteration_progress();
  464. if (simple_iteration_progress.has_value() && simple_iteration_progress.value() == 1.0)
  465. return floor(overall_progress().value()) - 1.0;
  466. // 4. Otherwise, return floor(overall progress).
  467. return floor(overall_progress().value());
  468. }
  469. // https://www.w3.org/TR/web-animations-1/#transformed-progress
  470. Optional<double> AnimationEffect::transformed_progress() const
  471. {
  472. // 1. If the directed progress is unresolved, return unresolved.
  473. auto directed_progress = this->directed_progress();
  474. if (!directed_progress.has_value())
  475. return {};
  476. // 2. Calculate the value of the before flag as follows:
  477. // 1. Determine the current direction using the procedure defined in §4.9.1 Calculating the directed progress.
  478. auto current_direction = this->current_direction();
  479. // 2. If the current direction is forwards, let going forwards be true, otherwise it is false.
  480. auto going_forwards = current_direction == AnimationDirection::Forwards;
  481. // 3. The before flag is set if the animation effect is in the before phase and going forwards is true; or if the animation effect
  482. // is in the after phase and going forwards is false.
  483. auto before_flag = (is_in_the_before_phase() && going_forwards) || (is_in_the_after_phase() && !going_forwards);
  484. // 3. Return the result of evaluating the animation effect’s timing function passing directed progress as the input progress value and
  485. // before flag as the before flag.
  486. return m_timing_function(directed_progress.value(), before_flag);
  487. }
  488. AnimationEffect::AnimationEffect(JS::Realm& realm)
  489. : Bindings::PlatformObject(realm)
  490. {
  491. }
  492. void AnimationEffect::initialize(JS::Realm& realm)
  493. {
  494. Base::initialize(realm);
  495. set_prototype(&Bindings::ensure_web_prototype<Bindings::AnimationEffectPrototype>(realm, "AnimationEffect"_fly_string));
  496. }
  497. }