AnimationEffect.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /*
  2. * Copyright (c) 2023, 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/Bindings/Intrinsics.h>
  10. #include <LibWeb/WebIDL/ExceptionOr.h>
  11. namespace Web::Animations {
  12. JS::NonnullGCPtr<AnimationEffect> AnimationEffect::create(JS::Realm& realm)
  13. {
  14. return realm.heap().allocate<AnimationEffect>(realm, realm);
  15. }
  16. OptionalEffectTiming EffectTiming::to_optional_effect_timing() const
  17. {
  18. return {
  19. .delay = delay,
  20. .end_delay = end_delay,
  21. .fill = fill,
  22. .iteration_start = iteration_start,
  23. .iterations = iterations,
  24. .duration = duration,
  25. .direction = direction,
  26. .easing = easing,
  27. };
  28. }
  29. // https://www.w3.org/TR/web-animations-1/#dom-animationeffect-gettiming
  30. EffectTiming AnimationEffect::get_timing() const
  31. {
  32. // 1. Returns the specified timing properties for this animation effect.
  33. return {
  34. .delay = m_start_delay,
  35. .end_delay = m_end_delay,
  36. .fill = m_fill_mode,
  37. .iteration_start = m_iteration_start,
  38. .iterations = m_iteration_count,
  39. .duration = m_iteration_duration,
  40. .direction = m_playback_direction,
  41. .easing = m_easing_function,
  42. };
  43. }
  44. // https://www.w3.org/TR/web-animations-1/#dom-animationeffect-getcomputedtiming
  45. ComputedEffectTiming AnimationEffect::get_computed_timing() const
  46. {
  47. // 1. Returns the calculated timing properties for this animation effect.
  48. // Note: Although some of the attributes of the object returned by getTiming() and getComputedTiming() are common,
  49. // their values may differ in the following ways:
  50. // - duration: while getTiming() may return the string auto, getComputedTiming() must return a number
  51. // corresponding to the calculated value of the iteration duration as defined in the description of the
  52. // duration member of the EffectTiming interface.
  53. //
  54. // In this level of the specification, that simply means that an auto value is replaced by zero.
  55. auto duration = m_iteration_duration.has<String>() ? 0.0 : m_iteration_duration.get<double>();
  56. // - fill: likewise, while getTiming() may return the string auto, getComputedTiming() must return the specific
  57. // FillMode used for timing calculations as defined in the description of the fill member of the EffectTiming
  58. // interface.
  59. //
  60. // In this level of the specification, that simply means that an auto value is replaced by the none FillMode.
  61. auto fill = m_fill_mode == Bindings::FillMode::Auto ? Bindings::FillMode::None : m_fill_mode;
  62. return {
  63. {
  64. .delay = m_start_delay,
  65. .end_delay = m_end_delay,
  66. .fill = fill,
  67. .iteration_start = m_iteration_start,
  68. .iterations = m_iteration_count,
  69. .duration = duration,
  70. .direction = m_playback_direction,
  71. .easing = m_easing_function,
  72. },
  73. // FIXME:
  74. 0.0,
  75. 0.0,
  76. 0.0,
  77. 0.0,
  78. 0.0,
  79. };
  80. }
  81. // https://www.w3.org/TR/web-animations-1/#dom-animationeffect-updatetiming
  82. // https://www.w3.org/TR/web-animations-1/#update-the-timing-properties-of-an-animation-effect
  83. WebIDL::ExceptionOr<void> AnimationEffect::update_timing(OptionalEffectTiming timing)
  84. {
  85. // 1. If the iterationStart member of input exists and is less than zero, throw a TypeError and abort this
  86. // procedure.
  87. if (timing.iteration_start.has_value() && timing.iteration_start.value() < 0.0)
  88. return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Invalid iteration start value"sv };
  89. // 2. If the iterations member of input exists, and is less than zero or is the value NaN, throw a TypeError and
  90. // abort this procedure.
  91. if (timing.iterations.has_value() && (timing.iterations.value() < 0.0 || isnan(timing.iterations.value())))
  92. return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Invalid iteration count value"sv };
  93. // 3. If the duration member of input exists, and is less than zero or is the value NaN, throw a TypeError and
  94. // abort this procedure.
  95. // Note: "auto", the only valid string value, is treated as 0.
  96. auto& duration = timing.duration;
  97. if (duration.has_value() && duration->has<double>() && (duration->get<double>() < 0.0 || isnan(duration->get<double>())))
  98. return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Invalid duration value"sv };
  99. // FIXME:
  100. // 4. If the easing member of input exists but cannot be parsed using the <easing-function> production
  101. // [CSS-EASING-1], throw a TypeError and abort this procedure.
  102. // 5. Assign each member that exists in input to the corresponding timing property of effect as follows:
  103. // - delay → start delay
  104. if (timing.delay.has_value())
  105. m_start_delay = timing.delay.value();
  106. // - endDelay → end delay
  107. if (timing.end_delay.has_value())
  108. m_end_delay = timing.end_delay.value();
  109. // - fill → fill mode
  110. if (timing.fill.has_value())
  111. m_fill_mode = timing.fill.value();
  112. // - iterationStart → iteration start
  113. if (timing.iteration_start.has_value())
  114. m_iteration_start = timing.iteration_start.value();
  115. // - iterations → iteration count
  116. if (timing.iterations.has_value())
  117. m_iteration_count = timing.iterations.value();
  118. // - duration → iteration duration
  119. if (timing.duration.has_value())
  120. m_iteration_duration = timing.duration.value();
  121. // - direction → playback direction
  122. if (timing.direction.has_value())
  123. m_playback_direction = timing.direction.value();
  124. // - easing → timing function
  125. if (timing.easing.has_value())
  126. m_easing_function = timing.easing.value();
  127. return {};
  128. }
  129. // https://www.w3.org/TR/web-animations-1/#animation-direction
  130. AnimationDirection AnimationEffect::animation_direction() const
  131. {
  132. // "backwards" if the effect is associated with an animation and the associated animation’s playback rate is less
  133. // than zero; in all other cases, the animation direction is "forwards".
  134. if (m_associated_animation && m_associated_animation->playback_rate() < 0.0)
  135. return AnimationDirection::Backwards;
  136. return AnimationDirection::Forwards;
  137. }
  138. AnimationEffect::AnimationEffect(JS::Realm& realm)
  139. : Bindings::PlatformObject(realm)
  140. {
  141. }
  142. void AnimationEffect::initialize(JS::Realm& realm)
  143. {
  144. Base::initialize(realm);
  145. set_prototype(&Bindings::ensure_web_prototype<Bindings::AnimationEffectPrototype>(realm, "AnimationEffect"));
  146. }
  147. }