Bug 1467399 - Part 1: Wait for next frame after pausing/resuming the animations. r?pbro draft
authorDaisuke Akatsuka <dakatsuka@mozilla.com>
Wed, 20 Jun 2018 20:11:42 +0900
changeset 808668 f70539ffc07ded7e63aa97029038428ffced2c2d
parent 808264 1e2c9151a09e43613a79daa8d4a94dc3e314020c
child 808669 308538e0e17082fc97c10a1d090a15bb79d27ff4
push id113460
push userbmo:dakatsuka@mozilla.com
push dateWed, 20 Jun 2018 11:31:27 +0000
reviewerspbro
bugs1467399
milestone62.0a1
Bug 1467399 - Part 1: Wait for next frame after pausing/resuming the animations. r?pbro MozReview-Commit-ID: 7mQL1LtSMCT
devtools/server/actors/animation.js
--- a/devtools/server/actors/animation.js
+++ b/devtools/server/actors/animation.js
@@ -110,20 +110,22 @@ var AnimationPlayerActor = protocol.Acto
       return this.player.effect.target;
     }
 
     const pseudo = this.player.effect.target;
     const treeWalker = this.walker.getDocumentWalker(pseudo.parentElement);
     return pseudo.type === "::before" ? treeWalker.firstChild() : treeWalker.lastChild();
   },
 
+  get document() {
+    return this.node.ownerDocument;
+  },
+
   get window() {
-    // ownerGlobal doesn't exist in content privileged windows.
-    // eslint-disable-next-line mozilla/use-ownerGlobal
-    return this.node.ownerDocument.defaultView;
+    return this.document.defaultView;
   },
 
   /**
    * Release the actor, when it isn't needed anymore.
    * Protocol.js uses this release method to call the destroy method.
    */
   release: function() {},
 
@@ -861,27 +863,31 @@ exports.AnimationsActor = protocol.Actor
    * Pause given animations.
    *
    * @param {Array} actors A list of AnimationPlayerActor.
    */
   pauseSome: function(actors) {
     for (const { player } of actors) {
       this.pauseSync(player);
     }
+
+    return this.waitForNextFrame(actors);
   },
 
   /**
    * Play given animations.
    *
    * @param {Array} actors A list of AnimationPlayerActor.
    */
   playSome: function(actors) {
     for (const { player } of actors) {
       this.playSync(player);
     }
+
+    return this.waitForNextFrame(actors);
   },
 
   /**
    * Set the current time of several animations at the same time.
    * @param {Array} players A list of AnimationPlayerActor.
    * @param {Number} time The new currentTime.
    * @param {Boolean} shouldPause Should the players be paused too.
    * @param {Object} options
@@ -902,17 +908,17 @@ exports.AnimationsActor = protocol.Actor
 
       if (shouldPause) {
         player.startTime = null;
       }
 
       player.currentTime = (time - actor.createdTime) * player.playbackRate;
     }
 
-    return Promise.resolve();
+    return this.waitForNextFrame(players);
   },
 
   /**
    * Set the playback rate of several animations at the same time.
    * @param {Array} players A list of AnimationPlayerActor.
    * @param {Number} rate The new rate.
    */
   setPlaybackRates: function(players, rate) {
@@ -988,9 +994,35 @@ exports.AnimationsActor = protocol.Actor
   updateAnimationCreatedTime(animation) {
     if (!this.animationCreatedTimeMap.has(animation)) {
       const createdTime =
         animation.startTime ||
         animation.timeline.currentTime - animation.currentTime / animation.playbackRate;
       this.animationCreatedTimeMap.set(animation, createdTime);
     }
   },
+
+  /**
+   * Wait for next animation frame.
+   *
+   * @param {Array} actors
+   * @return {Promise} which waits for next frame
+   */
+  waitForNextFrame(actors) {
+    const promises = actors.map(actor => {
+      const doc = actor.document;
+      const win = actor.window;
+      const timeAtCurrent = doc.timeline.currentTime;
+
+      return new Promise(resolve => {
+        win.requestAnimationFrame(() => {
+          if (timeAtCurrent === doc.timeline.currentTime) {
+            win.requestAnimationFrame(resolve);
+          } else {
+            resolve();
+          }
+        });
+      });
+    });
+
+    return Promise.all(promises);
+  },
 });