AnimationEffect.cpp 24 KB

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