Bug 1415042 - Wait for two requestAnimationFrames to ensure that animations have been tried to send to the compositor in test_animation_performance_warning.html. r?birtles draft
authorHiroyuki Ikezoe <hikezoe@mozilla.com>
Tue, 07 Nov 2017 14:49:59 +0900
changeset 693934 cedcea79c48d7a3a3381dbcdb3536f660c43ec0d
parent 693920 97b647545e766e55a2f48facac50a077646138ac
child 693935 2be10b46bb1b4a9cfc3e51f447b041161c26f04c
push id87989
push userhikezoe@mozilla.com
push dateTue, 07 Nov 2017 05:53:46 +0000
reviewersbirtles
bugs1415042, 1341294, 1193394
milestone58.0a1
Bug 1415042 - Wait for two requestAnimationFrames to ensure that animations have been tried to send to the compositor in test_animation_performance_warning.html. r?birtles To do that, ideally we can wait for MozAfterPaint, but it's sometimes fired before we do a paint process (bug 1341294), we should avoid using it until that bug is fixed. So, we wait for two requestAnimationFrames instead. The callback for requestAnimationFrame is called before styling process, so we need to wait for one more frame there. For now a Promise in waitForFrame is processed after paint process, so these tests would have been working fine with waiting for a single requestAnimationFrame. But after bug 1193394, the Promise will be processed right after requestAnimationFrame, thus these tests will fail with a single requestAnimationFrame. MozReview-Commit-ID: 4pbofZ3DUm3
dom/animation/test/chrome/test_animation_performance_warning.html
--- a/dom/animation/test/chrome/test_animation_performance_warning.html
+++ b/dom/animation/test/chrome/test_animation_performance_warning.html
@@ -37,16 +37,24 @@ Services.locale.setRequestedLocales(["en
 SpecialPowers.pushPrefEnv({ "set": [
                             // Need to set devPixelsPerPx explicitly to gain
                             // consistent pixel values in warning messages
                             // regardless of platform DPIs.
                             ["layout.css.devPixelsPerPx", 1],
                           ] },
                           start);
 
+// a fake function waiting for a paint.
+function waitForPaints() {
+  // FIXME: Bug 1415065 Instead waiting for two requestAnimationFrames, we
+  // should wait for MozAfterPaint once after MozAfterPaint is fired properly
+  // (bug 1341294).
+  return waitForAnimationFrames(2);
+}
+
 function compare_property_state(a, b) {
   if (a.property > b.property) {
     return -1;
   } else if (a.property < b.property) {
     return 1;
   }
   if (a.runningOnCompositor != b.runningOnCompositor) {
     return a.runningOnCompositor ? 1 : -1;
@@ -176,17 +184,17 @@ function testBasicOperation() {
           runningOnCompositor: true
         }
       ]
     },
   ].forEach(subtest => {
     promise_test(t => {
       var animation = addDivAndAnimate(t, { class: 'compositable' },
                                        subtest.frames, 100 * MS_PER_SEC);
-      return animation.ready.then(() => {
+      return waitForPaints().then(() => {
         assert_animation_property_state_equals(
           animation.effect.getProperties(),
           subtest.expected);
       });
     }, subtest.desc);
   });
 }
 
@@ -251,17 +259,17 @@ function testKeyframesWithGeometricPrope
           }
         ]
       }
     },
   ].forEach(subtest => {
     promise_test(t => {
       var animation = addDivAndAnimate(t, { class: 'compositable' },
                                        subtest.frames, 100 * MS_PER_SEC);
-      return animation.ready.then(() => {
+      return waitForPaints().then(() => {
         // First, a transform animation is running on compositor.
         assert_animation_property_state_equals(
           animation.effect.getProperties(),
           subtest.expected.withoutGeometric);
       }).then(() => {
         // Add a 'width' property.
         var keyframes = animation.effect.getKeyframes();
 
@@ -309,17 +317,17 @@ function testSetOfGeometricProperties() 
     promise_test(t => {
       const keyframes = {
         [propertyToIDL(property)]: [ '100px', '200px' ],
         transform: [ 'translate(0px)', 'translate(100px)' ]
       };
       var animation = addDivAndAnimate(t, { class: 'compositable' },
                                        keyframes, 100 * MS_PER_SEC);
 
-      return animation.ready.then(() => {
+      return waitForPaints().then(() => {
         assert_animation_property_state_equals(
           animation.effect.getProperties(),
           [
             {
               property,
               runningOnCompositor: false
             },
             {
@@ -401,17 +409,17 @@ function testStyleChanges() {
           warning: 'CompositorAnimationWarningTransformBackfaceVisibilityHidden'
         }
       ]
     },
   ].forEach(subtest => {
     promise_test(t => {
       var animation = addDivAndAnimate(t, { class: 'compositable' },
                                        subtest.frames, 100 * MS_PER_SEC);
-      return animation.ready.then(() => {
+      return waitForPaints().then(() => {
         assert_all_properties_running_on_compositor(
           animation.effect.getProperties(),
           subtest.expected);
         animation.effect.target.style = subtest.style;
         return waitForFrame();
       }).then(() => {
         assert_animation_property_state_equals(
           animation.effect.getProperties(),
@@ -448,17 +456,17 @@ function testIdChanges() {
   ].forEach(subtest => {
     promise_test(t => {
       if (subtest.createelement) {
         addDiv(t, { style: subtest.createelement });
       }
 
       var animation = addDivAndAnimate(t, { class: 'compositable' },
                                        subtest.frames, 100 * MS_PER_SEC);
-      return animation.ready.then(() => {
+      return waitForPaints().then(() => {
         assert_all_properties_running_on_compositor(
           animation.effect.getProperties(),
           subtest.expected);
         animation.effect.target.id = subtest.id;
         return waitForFrame();
       }).then(() => {
         assert_animation_property_state_equals(
           animation.effect.getProperties(),
@@ -539,17 +547,17 @@ function testMultipleAnimations() {
       var div = addDiv(t, { class: 'compositable' });
       var animations = subtest.animations.map(anim => {
         var animation = div.animate(anim.frames, 100 * MS_PER_SEC);
 
         // Bind expected values to animation object.
         animation.expected = anim.expected;
         return animation;
       });
-      return waitForAllAnimations(animations).then(() => {
+      return waitForPaints().then(() => {
         animations.forEach(anim => {
           assert_all_properties_running_on_compositor(
             anim.effect.getProperties(),
             anim.expected);
         });
         div.style = subtest.style;
         return waitForFrame();
       }).then(() => {
@@ -677,17 +685,17 @@ function testMultipleAnimationsWithGeome
       var div = addDiv(t, { class: 'compositable' });
       var animations = subtest.animations.map(anim => {
         var animation = div.animate(anim.frames, 100 * MS_PER_SEC);
 
         // Bind expected values to animation object.
         animation.expected = anim.expected;
         return animation;
       });
-      return waitForAllAnimations(animations).then(() => {
+      return waitForPaints().then(() => {
         // First, all animations are running on compositor.
         animations.forEach(anim => {
           assert_animation_property_state_equals(
             anim.effect.getProperties(),
             anim.expected.withoutGeometric);
         });
       }).then(() => {
         // Add a 'width' property to animations[1].
@@ -800,17 +808,17 @@ function testMultipleAnimationsWithGeome
 
         // Bind expected values to animation object.
         animation.expected = anim.expected;
         return animation;
       });
 
       var widthAnimation;
 
-      return waitForAllAnimations(animations).then(() => {
+      return waitForPaints().then(() => {
         animations.forEach(anim => {
           assert_all_properties_running_on_compositor(
             anim.effect.getProperties(),
             anim.expected);
         });
       }).then(() => {
         // Append 'width' animation on the same element.
         widthAnimation = div.animate({ width: ['100px', '200px'] },
@@ -873,17 +881,17 @@ function testSmallElements() {
           runningOnCompositor: true
         }
       ]
     },
   ].forEach(subtest => {
     promise_test(t => {
     var div = addDiv(t, subtest.style);
     var animation = div.animate(subtest.frames, 100 * MS_PER_SEC);
-      return animation.ready.then(() => {
+      return waitForPaints().then(() => {
         assert_animation_property_state_equals(
           animation.effect.getProperties(),
           subtest.expected);
       });
     }, subtest.desc);
   });
 }
 
@@ -893,17 +901,17 @@ function testSynchronizedAnimations() {
     const elemB = addDiv(t, { class: 'compositable' });
 
     const animA = elemA.animate({ transform: [ 'translate(0px)',
                                                'translate(100px)' ] },
                                 100 * MS_PER_SEC);
     const animB = elemB.animate({ marginLeft: [ '0px', '100px' ] },
                                 100 * MS_PER_SEC);
 
-    return Promise.all([animA.ready, animB.ready])
+    return waitForPaints()
       .then(() => {
         assert_animation_property_state_equals(
           animA.effect.getProperties(),
           [ { property: 'transform',
               runningOnCompositor: false,
               warning: 'CompositorAnimationWarningTransformWithSyncGeometricAnimations'
           } ]);
       });
@@ -915,17 +923,17 @@ function testSynchronizedAnimations() {
     const elemB = addDiv(t, { class: 'compositable' });
 
     const animA = elemA.animate({ marginLeft: [ '0px', '100px' ] },
                                 100 * MS_PER_SEC);
     const animB = elemB.animate({ transform: [ 'translate(0px)',
                                                'translate(100px)' ] },
                                 100 * MS_PER_SEC);
 
-    return Promise.all([animA.ready, animB.ready])
+    return waitForPaints()
       .then(() => {
         assert_animation_property_state_equals(
           animB.effect.getProperties(),
           [ { property: 'transform',
               runningOnCompositor: false,
               warning: 'CompositorAnimationWarningTransformWithSyncGeometricAnimations'
           } ]);
       });
@@ -986,17 +994,17 @@ function testSynchronizedAnimations() {
 
     const animA = elemA.animate({ transform: [ 'translate(0px)',
                                                'translate(100px)' ],
                                   opacity: [ 0, 1 ] },
                                 100 * MS_PER_SEC);
     const animB = elemB.animate({ marginLeft: [ '0px', '100px' ] },
                                 100 * MS_PER_SEC);
 
-    return Promise.all([animA.ready, animB.ready])
+    return waitForPaints()
       .then(() => {
         assert_animation_property_state_equals(
           animA.effect.getProperties(),
           [ { property: 'transform',
               runningOnCompositor: false,
               warning: 'CompositorAnimationWarningTransformWithSyncGeometricAnimations'
             },
             { property: 'opacity',
@@ -1010,17 +1018,17 @@ function testSynchronizedAnimations() {
   promise_test(t => {
     const elemA = addDiv(t, { class: 'compositable' });
     const elemB = addDiv(t, { class: 'compositable' });
 
     const animA = elemA.animate({ marginLeft: [ '0px', '100px' ] },
                                 100 * MS_PER_SEC);
     let animB;
 
-    return waitForFrame()
+    return waitForPaints()
       .then(() => {
         animB = elemB.animate({ transform: [ 'translate(0px)',
                                              'translate(100px)' ] },
                                 100 * MS_PER_SEC);
         return animB.ready;
       }).then(() => {
         assert_animation_property_state_equals(
           animB.effect.getProperties(),
@@ -1034,17 +1042,17 @@ function testSynchronizedAnimations() {
     const elemA = addDiv(t, { class: 'compositable' });
     const elemB = addDiv(t, { class: 'compositable' });
 
     const animA = elemA.animate({ transform: [ 'translate(0px)',
                                                'translate(100px)' ] },
                                 100 * MS_PER_SEC);
     let animB;
 
-    return waitForFrame()
+    return waitForPaints()
       .then(() => {
         animB = elemB.animate({ marginLeft: [ '0px', '100px' ] },
                               100 * MS_PER_SEC);
         return animB.ready;
       }).then(() => {
         assert_animation_property_state_equals(
           animA.effect.getProperties(),
           [ { property: 'transform',
@@ -1059,17 +1067,17 @@ function testSynchronizedAnimations() {
 
     const animA = elemA.animate({ transform: [ 'translate(0px)',
                                                'translate(100px)' ] },
                                 100 * MS_PER_SEC);
     const animB = elemB.animate({ marginLeft: [ '0px', '100px' ] },
                                 100 * MS_PER_SEC);
     animB.pause();
 
-    return Promise.all([animA.ready, animB.ready])
+    return waitForPaints()
       .then(() => {
         assert_animation_property_state_equals(
           animA.effect.getProperties(),
           [ { property: 'transform', runningOnCompositor: true } ]);
       });
   }, 'Paused animations are not synchronized');
 
   promise_test(t => {
@@ -1080,17 +1088,17 @@ function testSynchronizedAnimations() {
                                                'translate(100px)' ] },
                                 100 * MS_PER_SEC);
     const animB = elemB.animate({ marginLeft: [ '0px', '100px' ] },
                                 100 * MS_PER_SEC);
 
     // Seek one of the animations so that their start times will differ
     animA.currentTime = 5000;
 
-    return Promise.all([animA.ready, animB.ready])
+    return waitForPaints()
       .then(() => {
         assert_not_equals(animA.startTime, animB.startTime,
                           'Animations should have different start times');
         assert_animation_property_state_equals(
           animA.effect.getProperties(),
           [ { property: 'transform',
               runningOnCompositor: false,
               warning: 'CompositorAnimationWarningTransformWithSyncGeometricAnimations'
@@ -1104,17 +1112,17 @@ function testSynchronizedAnimations() {
     const elemB = addDiv(t, { class: 'compositable' });
 
     const animA = elemA.animate({ transform: [ 'translate(0px)',
                                                'translate(100px)' ] },
                                 100 * MS_PER_SEC);
     const animB = elemB.animate({ marginLeft: [ '0px', '100px' ] },
                                 100 * MS_PER_SEC);
 
-    return Promise.all([animA.ready, animB.ready])
+    return waitForPaints()
       .then(() => {
         assert_animation_property_state_equals(
           animA.effect.getProperties(),
           [ { property: 'transform',
               runningOnCompositor: false } ]);
         // Restart animation
         animA.pause();
         animA.play();
@@ -1135,17 +1143,17 @@ function testSynchronizedAnimations() {
                                                'translate(100px)' ] },
                                 100 * MS_PER_SEC);
     const animB = elemB.animate({ marginLeft: [ '0px', '100px' ] },
                                 100 * MS_PER_SEC);
 
     // Clear target effect
     animB.effect.target = null;
 
-    return Promise.all([animA.ready, animB.ready])
+    return waitForPaints()
       .then(() => {
         assert_animation_property_state_equals(
           animA.effect.getProperties(),
           [ { property: 'transform',
               runningOnCompositor: true } ]);
       });
   }, 'A geometric animation with no target element is not synchronized');
 }
@@ -1168,17 +1176,17 @@ function start() {
   testSynchronizedAnimations();
 
   promise_test(t => {
     var animation = addDivAndAnimate(t,
                                      { class: 'compositable' },
                                      { transform: [ 'translate(0px)',
                                                     'translate(100px)'] },
                                      100 * MS_PER_SEC);
-    return animation.ready.then(() => {
+    return waitForPaints().then(() => {
       assert_animation_property_state_equals(
         animation.effect.getProperties(),
         [ { property: 'transform', runningOnCompositor: true } ]);
       animation.effect.target.style = 'width: 5200px; height: 5200px';
       return waitForFrame();
     }).then(() => {
       // viewport depends on test environment.
       var expectedWarning = new RegExp(
@@ -1203,17 +1211,17 @@ function start() {
   }, 'transform on too big element - area');
 
   promise_test(t => {
     var animation = addDivAndAnimate(t,
                                      { class: 'compositable' },
                                      { transform: [ 'translate(0px)',
                                                     'translate(100px)'] },
                                      100 * MS_PER_SEC);
-    return animation.ready.then(() => {
+    return waitForPaints().then(() => {
       assert_animation_property_state_equals(
         animation.effect.getProperties(),
         [ { property: 'transform', runningOnCompositor: true } ]);
       animation.effect.target.style = 'width: 5200px; height: 1px';
       return waitForFrame();
     }).then(() => {
       // viewport depends on test environment.
       var expectedWarning = new RegExp(
@@ -1249,17 +1257,17 @@ function start() {
     svg.appendChild(rect);
     document.body.appendChild(svg);
     t.add_cleanup(() => {
       svg.remove();
     });
 
     var animation = svg.animate(
       { transform: ['translate(0px)', 'translate(100px)'] }, 100 * MS_PER_SEC);
-    return animation.ready.then(() => {
+    return waitForPaints().then(() => {
       assert_animation_property_state_equals(
         animation.effect.getProperties(),
         [ { property: 'transform', runningOnCompositor: true } ]);
       svg.setAttribute('transform', 'translate(10, 20)');
       return waitForFrame();
     }).then(() => {
       assert_animation_property_state_equals(
         animation.effect.getProperties(),
@@ -1277,17 +1285,17 @@ function start() {
     });
   }, 'transform of nsIFrame with SVG transform');
 
   promise_test(t => {
     var div = addDiv(t, { class: 'compositable',
                           style: 'animation: fade 100s' });
     var cssAnimation = div.getAnimations()[0];
     var scriptAnimation = div.animate({ opacity: [ 1, 0 ] }, 100 * MS_PER_SEC);
-    return scriptAnimation.ready.then(() => {
+    return waitForPaints().then(() => {
       assert_animation_property_state_equals(
         cssAnimation.effect.getProperties(),
         [ { property: 'opacity', runningOnCompositor: true } ]);
       assert_animation_property_state_equals(
         scriptAnimation.effect.getProperties(),
         [ { property: 'opacity', runningOnCompositor: true } ]);
     });
   }, 'overridden animation');