Просмотр исходного кода

LibWeb/DOM: Allow the animationiteration event to be fired

This event is fired while both the previous and the current phase are
active.

This prevents this test from timing out:
- css/css-animations/animationevent-types.txt
Lucas CHOLLET 6 месяцев назад
Родитель
Сommit
61b444d538
1 измененных файлов с 70 добавлено и 71 удалено
  1. 70 71
      Libraries/LibWeb/DOM/Document.cpp

+ 70 - 71
Libraries/LibWeb/DOM/Document.cpp

@@ -2360,85 +2360,84 @@ void Document::dispatch_events_for_animation_if_necessary(GC::Ref<Animations::An
     auto current_phase = effect->phase();
     auto current_iteration = effect->current_iteration().value_or(0.0);
 
-    if (previous_phase != current_phase) {
-        auto owning_element = css_animation.owning_element();
-
-        auto dispatch_event = [&](FlyString const& name, double elapsed_time) {
-            append_pending_animation_event({
-                .event = CSS::AnimationEvent::create(
-                    owning_element->realm(),
-                    name,
-                    {
-                        { .bubbles = true },
-                        css_animation.id(),
-                        elapsed_time,
-                    }),
-                .animation = css_animation,
-                .target = *target,
-                .scheduled_event_time = HighResolutionTime::unsafe_shared_current_time(),
-            });
-        };
+    auto owning_element = css_animation.owning_element();
 
-        // For calculating the elapsedTime of each event, the following definitions are used:
+    auto dispatch_event = [&](FlyString const& name, double elapsed_time) {
+        append_pending_animation_event({
+            .event = CSS::AnimationEvent::create(
+                owning_element->realm(),
+                name,
+                {
+                    { .bubbles = true },
+                    css_animation.id(),
+                    elapsed_time,
+                }),
+            .animation = css_animation,
+            .target = *target,
+            .scheduled_event_time = HighResolutionTime::unsafe_shared_current_time(),
+        });
+    };
 
-        // - interval start = max(min(-start delay, active duration), 0)
-        auto interval_start = max(min(-effect->start_delay(), effect->active_duration()), 0.0);
+    // For calculating the elapsedTime of each event, the following definitions are used:
 
-        // - interval end = max(min(associated effect end - start delay, active duration), 0)
-        auto interval_end = max(min(effect->end_time() - effect->start_delay(), effect->active_duration()), 0.0);
+    // - interval start = max(min(-start delay, active duration), 0)
+    auto interval_start = max(min(-effect->start_delay(), effect->active_duration()), 0.0);
 
-        switch (previous_phase) {
-        case Animations::AnimationEffect::Phase::Before:
-            [[fallthrough]];
-        case Animations::AnimationEffect::Phase::Idle:
-            if (current_phase == Animations::AnimationEffect::Phase::Active) {
-                dispatch_event(HTML::EventNames::animationstart, interval_start);
-            } else if (current_phase == Animations::AnimationEffect::Phase::After) {
-                dispatch_event(HTML::EventNames::animationstart, interval_start);
-                dispatch_event(HTML::EventNames::animationend, interval_end);
-            }
-            break;
-        case Animations::AnimationEffect::Phase::Active:
-            if (current_phase == Animations::AnimationEffect::Phase::Before) {
-                dispatch_event(HTML::EventNames::animationend, interval_start);
-            } else if (current_phase == Animations::AnimationEffect::Phase::Active) {
-                auto previous_current_iteration = effect->previous_current_iteration();
-                if (previous_current_iteration != current_iteration) {
-                    // The elapsed time for an animationiteration event is defined as follows:
-
-                    // 1. Let previous current iteration be the current iteration from the previous animation frame.
-
-                    // 2. If previous current iteration is greater than current iteration, let iteration boundary be current iteration + 1,
-                    //    otherwise let it be current iteration.
-                    auto iteration_boundary = previous_current_iteration > current_iteration ? current_iteration + 1 : current_iteration;
-
-                    // 3. The elapsed time is the result of evaluating (iteration boundary - iteration start) × iteration duration).
-                    auto iteration_duration_variant = effect->iteration_duration();
-                    auto iteration_duration = iteration_duration_variant.has<String>() ? 0.0 : iteration_duration_variant.get<double>();
-                    auto elapsed_time = (iteration_boundary - effect->iteration_start()) * iteration_duration;
-
-                    dispatch_event(HTML::EventNames::animationiteration, elapsed_time);
-                }
-            } else if (current_phase == Animations::AnimationEffect::Phase::After) {
-                dispatch_event(HTML::EventNames::animationend, interval_end);
-            }
-            break;
-        case Animations::AnimationEffect::Phase::After:
-            if (current_phase == Animations::AnimationEffect::Phase::Active) {
-                dispatch_event(HTML::EventNames::animationstart, interval_end);
-            } else if (current_phase == Animations::AnimationEffect::Phase::Before) {
-                dispatch_event(HTML::EventNames::animationstart, interval_end);
-                dispatch_event(HTML::EventNames::animationend, interval_start);
+    // - interval end = max(min(associated effect end - start delay, active duration), 0)
+    auto interval_end = max(min(effect->end_time() - effect->start_delay(), effect->active_duration()), 0.0);
+
+    switch (previous_phase) {
+    case Animations::AnimationEffect::Phase::Before:
+        [[fallthrough]];
+    case Animations::AnimationEffect::Phase::Idle:
+        if (current_phase == Animations::AnimationEffect::Phase::Active) {
+            dispatch_event(HTML::EventNames::animationstart, interval_start);
+        } else if (current_phase == Animations::AnimationEffect::Phase::After) {
+            dispatch_event(HTML::EventNames::animationstart, interval_start);
+            dispatch_event(HTML::EventNames::animationend, interval_end);
+        }
+        break;
+    case Animations::AnimationEffect::Phase::Active:
+        if (current_phase == Animations::AnimationEffect::Phase::Before) {
+            dispatch_event(HTML::EventNames::animationend, interval_start);
+        } else if (current_phase == Animations::AnimationEffect::Phase::Active) {
+            auto previous_current_iteration = effect->previous_current_iteration();
+            if (previous_current_iteration != current_iteration) {
+                // The elapsed time for an animationiteration event is defined as follows:
+
+                // 1. Let previous current iteration be the current iteration from the previous animation frame.
+
+                // 2. If previous current iteration is greater than current iteration, let iteration boundary be current iteration + 1,
+                //    otherwise let it be current iteration.
+                auto iteration_boundary = previous_current_iteration > current_iteration ? current_iteration + 1 : current_iteration;
+
+                // 3. The elapsed time is the result of evaluating (iteration boundary - iteration start) × iteration duration).
+                auto iteration_duration_variant = effect->iteration_duration();
+                auto iteration_duration = iteration_duration_variant.has<String>() ? 0.0 : iteration_duration_variant.get<double>();
+                auto elapsed_time = (iteration_boundary - effect->iteration_start()) * iteration_duration;
+
+                dispatch_event(HTML::EventNames::animationiteration, elapsed_time);
             }
-            break;
+        } else if (current_phase == Animations::AnimationEffect::Phase::After) {
+            dispatch_event(HTML::EventNames::animationend, interval_end);
         }
-
-        if (current_phase == Animations::AnimationEffect::Phase::Idle && previous_phase != Animations::AnimationEffect::Phase::Idle && previous_phase != Animations::AnimationEffect::Phase::After) {
-            // FIXME: Calculate a non-zero time when the animation is cancelled by means other than calling cancel()
-            auto cancel_time = animation->release_saved_cancel_time().value_or(0.0);
-            dispatch_event(HTML::EventNames::animationcancel, cancel_time);
+        break;
+    case Animations::AnimationEffect::Phase::After:
+        if (current_phase == Animations::AnimationEffect::Phase::Active) {
+            dispatch_event(HTML::EventNames::animationstart, interval_end);
+        } else if (current_phase == Animations::AnimationEffect::Phase::Before) {
+            dispatch_event(HTML::EventNames::animationstart, interval_end);
+            dispatch_event(HTML::EventNames::animationend, interval_start);
         }
+        break;
     }
+
+    if (current_phase == Animations::AnimationEffect::Phase::Idle && previous_phase != Animations::AnimationEffect::Phase::Idle && previous_phase != Animations::AnimationEffect::Phase::After) {
+        // FIXME: Calculate a non-zero time when the animation is cancelled by means other than calling cancel()
+        auto cancel_time = animation->release_saved_cancel_time().value_or(0.0);
+        dispatch_event(HTML::EventNames::animationcancel, cancel_time);
+    }
+
     effect->set_previous_phase(current_phase);
     effect->set_previous_current_iteration(current_iteration);
 }