Bug 1395971 - Wait for few frames until sending target animation to the compositor. r?hiro draft
authorMantaroh Yoshinaga <mantaroh@gmail.com>
Wed, 06 Sep 2017 15:59:05 +0900
changeset 659701 81976f45fccb1053cc29228d117d75fbe83474e7
parent 659384 f64e2b4dcf5eec0b4ad456c149680a67b7c26dc4
child 730030 c839aa2592cfec65771dde2a88abd4ba30da9060
push id78173
push usermantaroh@gmail.com
push dateWed, 06 Sep 2017 06:59:41 +0000
reviewershiro
bugs1395971, 1341294
milestone57.0a1
Bug 1395971 - Wait for few frames until sending target animation to the compositor. r?hiro This patch is a workaround for bug 1341294. This test checks compositor's animation properties, so we should check this values after sending animation to the compositor. This patch adds waiting for few frames until sending target animation to the compositor. MozReview-Commit-ID: 3dCG3gj46tA
dom/animation/test/mozilla/file_deferred_start.html
dom/animation/test/testcommon.js
--- a/dom/animation/test/mozilla/file_deferred_start.html
+++ b/dom/animation/test/mozilla/file_deferred_start.html
@@ -96,26 +96,21 @@ promise_test(function(t) {
   // for paints and only then do we commence the test. Even doing that, this
   // test can sometimes pass when it should not due to a stray paint. Most of
   // the time, however, it will correctly fail so hopefully even if we do
   // occasionally produce a false negative on one platform, another platform
   // will fail as expected.
   return waitForDocLoad().then(() => waitForIdle())
   .then(() => waitForPaints())
   .then(() => {
-    div.animate({ transform: [ 'translate(0px)', 'translate(100px)' ] },
-                { duration: 400 * MS_PER_SEC,
-                  delay: -200 * MS_PER_SEC });
-
-    // TODO: Current waitForPaint() will not wait for MozAfterPaint in this
-    // case(Bug 1341294), so this waiting code is workaround for it.
-    // This waitForFrame() uses Promise, but bug 1193394 will be using same
-    // handling of  microtask, so if landed bug 1193394 this test might be
-    // failure since this promise will resolve in same tick of Element.animate.
-    return waitForFrame();
+    const anim = div.animate(
+                   { transform: [ 'translate(0px)', 'translate(100px)' ] },
+                   { duration: 400 * MS_PER_SEC,
+                     delay: -200 * MS_PER_SEC });
+    return waitForBeginAnimationSentToCompositor(anim);
   }).then(() => waitForPaints())
   .then(() => {
     const transformStr =
       SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform');
     const translateX = getTranslateXFromTransform(transformStr);
 
     // If the delay has been applied we should be about half-way through
     // the animation. However, if we applied it twice we will be at the
@@ -149,21 +144,18 @@ promise_test(function(t) {
   .then(() => waitForPaints())
   .then(() => {
     const animation =
       div.animate({ transform: [ 'translate(0px)', 'translate(100px)' ] },
                   200 * MS_PER_SEC);
     animation.currentTime = 100 * MS_PER_SEC;
     animation.playbackRate = 0.1;
 
-    // As the above test case, we should fix bug 1341294 before bug 1193394
-    // lands.
-    return waitForFrame();
-  }).then(() => waitForPaints())
-  .then(() => {
+    return waitForBeginAnimationSentToCompositor(animation);
+  }).then(() => {
     const transformStr =
       SpecialPowers.DOMWindowUtils.getOMTAStyle(div, 'transform');
     const translateX = getTranslateXFromTransform(transformStr);
 
     // We pass the playback rate to the compositor independently and we have
     // tests to ensure that it is correctly applied there. However, if, when
     // we resolve the start time of the pending animation, we fail to
     // incorporate the playback rate, we will end up starting from the wrong
--- a/dom/animation/test/testcommon.js
+++ b/dom/animation/test/testcommon.js
@@ -250,16 +250,39 @@ function waitForIdle() {
  */
 function waitForAllAnimations(animations) {
   return Promise.all(animations.map(function(animation) {
     return animation.ready;
   }));
 }
 
 /**
+ * Wait for few frames until sending animation to the compositor.
+ */
+function waitForBeginAnimationSentToCompositor(animation) {
+  // For present, An animation doesn't sent to compositor immediately, we should
+  // wait 3 frames at least. This value is fluctuant, the three times is
+  // empirically defined maximum value from try result.
+  let maxWaitForFrames = 3;
+  return new Promise(resolve => {
+    function handleFrame() {
+      if (SpecialPowers.wrap(animation).isRunningOnCompositor) {
+        resolve();
+      }
+      if (--maxWaitForFrames <= 0) {
+        resolve();
+      } else {
+        window.requestAnimationFrame(handleFrame);
+      }
+    }
+    window.requestAnimationFrame(handleFrame);
+  });
+}
+
+/**
  * Flush the computed style for the given element. This is useful, for example,
  * when we are testing a transition and need the initial value of a property
  * to be computed so that when we synchronouslyet set it to a different value
  * we actually get a transition instead of that being the initial value.
  */
 function flushComputedStyle(elem) {
   var cs = getComputedStyle(elem);
   cs.marginLeft;