Bug 1210795 - Part 7: Change setCurrentTimeAll behavior. r=pbro
authorDaisuke Akatsuka <daisuke@mozilla-japan.org>
Wed, 26 Oct 2016 16:37:20 +0900
changeset 319810 23f92954349863643543975a05ca8f229dfcbf23
parent 319809 2558ac9b4094371bbfbee82d4faf135cf7820a1f
child 319811 a18f7b70b8089682aca7b3ae319b205f1b14869b
push id20748
push userphilringnalda@gmail.com
push dateFri, 28 Oct 2016 03:39:55 +0000
treeherderfx-team@715360440695 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspbro
bugs1210795
milestone52.0a1
Bug 1210795 - Part 7: Change setCurrentTimeAll behavior. r=pbro MozReview-Commit-ID: 298b7TfBVXu
devtools/client/animationinspector/test/browser.ini
devtools/client/animationinspector/test/browser_animation_timeline_setCurrentTime.js
devtools/client/animationinspector/test/doc_timing_combination_animation.html
devtools/server/actors/animation.js
--- a/devtools/client/animationinspector/test/browser.ini
+++ b/devtools/client/animationinspector/test/browser.ini
@@ -7,16 +7,17 @@ support-files =
   doc_frame_script.js
   doc_keyframes.html
   doc_modify_playbackRate.html
   doc_negative_animation.html
   doc_pseudo_elements.html
   doc_script_animation.html
   doc_simple_animation.html
   doc_multiple_animation_types.html
+  doc_timing_combination_animation.html
   head.js
   !/devtools/client/commandline/test/helpers.js
   !/devtools/client/framework/test/shared-head.js
   !/devtools/client/inspector/test/head.js
   !/devtools/client/inspector/test/shared-head.js
   !/devtools/client/shared/test/test-actor-registry.js
   !/devtools/client/shared/test/test-actor.js
 
@@ -51,16 +52,17 @@ skip-if = os == "linux" && !debug # Bug 
 [browser_animation_timeline_pause_button_01.js]
 [browser_animation_timeline_pause_button_02.js]
 [browser_animation_timeline_pause_button_03.js]
 [browser_animation_timeline_rate_selector.js]
 [browser_animation_timeline_rewind_button.js]
 [browser_animation_timeline_scrubber_exists.js]
 [browser_animation_timeline_scrubber_movable.js]
 [browser_animation_timeline_scrubber_moves.js]
+[browser_animation_timeline_setCurrentTime.js]
 [browser_animation_timeline_shows_delay.js]
 [browser_animation_timeline_shows_endDelay.js]
 [browser_animation_timeline_shows_iterations.js]
 [browser_animation_timeline_shows_time_info.js]
 [browser_animation_timeline_takes_rate_into_account.js]
 [browser_animation_timeline_ui.js]
 [browser_animation_toggle_button_resets_on_navigate.js]
 [browser_animation_toggle_button_toggles_animations.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_setCurrentTime.js
@@ -0,0 +1,88 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+requestLongerTimeout(2);
+
+// Animation.currentTime ignores neagtive delay and positive/negative endDelay
+// during fill-mode, even if they are set.
+// For example, when the animation timing is
+// { duration: 1000, iterations: 1, endDelay: -500, easing: linear },
+// the animation progress is 0.5 at 700ms because the progress stops as 0.5 at
+// 500ms in original animation. However, if you set as
+// animation.currentTime = 700 manually, the progress will be 0.7.
+// So we modify setCurrentTime method since
+// AnimationInspector should re-produce same as original animation.
+// In these tests,
+// we confirm the behavior of setCurrentTime by delay and endDelay.
+
+add_task(function* () {
+  yield addTab(URL_ROOT + "doc_timing_combination_animation.html");
+  const { panel, controller } = yield openAnimationInspector();
+
+  yield clickTimelinePlayPauseButton(panel);
+
+  const timelineComponent = panel.animationsTimelineComponent;
+  const timeBlockComponents = timelineComponent.timeBlocks;
+
+  // Test -5000ms.
+  let time = -5000;
+  yield controller.setCurrentTimeAll(time, true);
+  for (let i = 0; i < timeBlockComponents.length; i++) {
+    yield timeBlockComponents[i].animation.refreshState();
+    const state = yield timeBlockComponents[i].animation.state;
+    info(`Check the state at ${ time }ms with `
+         + `delay:${ state.delay } and endDelay:${ state.endDelay }`);
+    is(state.currentTime, 0,
+       `The currentTime should be 0 at setCurrentTime(${ time })`);
+  }
+
+  // Test 10000ms.
+  time = 10000;
+  yield controller.setCurrentTimeAll(time, true);
+  for (let i = 0; i < timeBlockComponents.length; i++) {
+    yield timeBlockComponents[i].animation.refreshState();
+    const state = yield timeBlockComponents[i].animation.state;
+    info(`Check the state at ${ time }ms with `
+         + `delay:${ state.delay } and endDelay:${ state.endDelay }`);
+    const expected = state.delay < 0 ? 0 : time;
+    is(state.currentTime, expected,
+       `The currentTime should be ${ expected } at setCurrentTime(${ time }).`
+       + ` delay: ${ state.delay } and endDelay: ${ state.endDelay }`);
+  }
+
+  // Test 60000ms.
+  time = 60000;
+  yield controller.setCurrentTimeAll(time, true);
+  for (let i = 0; i < timeBlockComponents.length; i++) {
+    yield timeBlockComponents[i].animation.refreshState();
+    const state = yield timeBlockComponents[i].animation.state;
+    info(`Check the state at ${ time }ms with `
+         + `delay:${ state.delay } and endDelay:${ state.endDelay }`);
+    const expected = state.delay < 0 ? time + state.delay : time;
+    is(state.currentTime, expected,
+       `The currentTime should be ${ expected } at setCurrentTime(${ time }).`
+       + ` delay: ${ state.delay } and endDelay: ${ state.endDelay }`);
+  }
+
+  // Test 150000ms.
+  time = 150000;
+  yield controller.setCurrentTimeAll(time, true);
+  for (let i = 0; i < timeBlockComponents.length; i++) {
+    yield timeBlockComponents[i].animation.refreshState();
+    const state = yield timeBlockComponents[i].animation.state;
+    info(`Check the state at ${ time }ms with `
+         + `delay:${ state.delay } and endDelay:${ state.endDelay }`);
+    const currentTime = state.delay < 0 ? time + state.delay : time;
+    const endTime =
+      state.delay + state.iterationCount * state.duration + state.endDelay;
+    const expected =
+      state.endDelay < 0 && state.fill === "both" && currentTime > endTime
+      ? endTime : currentTime;
+    is(state.currentTime, expected,
+       `The currentTime should be ${ expected } at setCurrentTime(${ time }).`
+       + ` delay: ${ state.delay } and endDelay: ${ state.endDelay }`);
+  }
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/animationinspector/test/doc_timing_combination_animation.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8">
+    <style>
+    div {
+      display: inline-block;
+      width: 100px;
+      height: 100px;
+      background-color: lime;
+    }
+    </style>
+  </head>
+  <body>
+    <script>
+    "use strict";
+
+    const delayList = [0, 50000, -50000];
+    const endDelayList = [0, 50000, -50000];
+
+    delayList.forEach(delay => {
+      endDelayList.forEach(endDelay => {
+        const el = document.createElement("div");
+        document.body.appendChild(el);
+        el.animate({ opacity: [0, 1] },
+                   { duration: 200000,
+                     iterations: 1,
+                     fill: "both",
+                     delay: delay,
+                     endDelay: endDelay });
+      });
+    });
+    </script>
+  </body>
+</html>
--- a/devtools/server/actors/animation.js
+++ b/devtools/server/actors/animation.js
@@ -419,16 +419,30 @@ var AnimationPlayerActor = protocol.Acto
   ready: function () {
     return this.player.ready;
   },
 
   /**
    * Set the current time of the animation player.
    */
   setCurrentTime: function (currentTime) {
+    // The spec is that the progress of animation is changed
+    // if the time of setCurrentTime is during the endDelay.
+    // We should prevent the time
+    // to make the same animation behavior as the original.
+    // Likewise, in case the time is less than 0.
+    const timing = this.player.effect.getComputedTiming();
+    if (timing.delay < 0) {
+      currentTime += timing.delay;
+    }
+    if (currentTime < 0) {
+      currentTime = 0;
+    } else if (currentTime * this.player.playbackRate > timing.endTime) {
+      currentTime = timing.endTime;
+    }
     this.player.currentTime = currentTime * this.player.playbackRate;
   },
 
   /**
    * Set the playback rate of the animation player.
    */
   setPlaybackRate: function (playbackRate) {
     this.player.playbackRate = playbackRate;