Bug 1458841 - Introduce a utility function that waits for a given animation being ready to be restyle. r?birtles draft
authorHiroyuki Ikezoe <hikezoe@mozilla.com>
Wed, 30 May 2018 09:41:47 +0900
changeset 801281 0d3599591370d08a8ccb8bda36ff14072071b848
parent 801280 d0bb48c634984edbc1e3b1f05faff25e3df81e66
child 801282 e4e5f48ff82fc437cbdfac5ef62d5c0b5a6b4f66
push id111625
push userhikezoe@mozilla.com
push dateWed, 30 May 2018 00:51:30 +0000
reviewersbirtles
bugs1458841
milestone62.0a1
Bug 1458841 - Introduce a utility function that waits for a given animation being ready to be restyle. r?birtles And replace tweakExpectedRestyleCount with the function. MozReview-Commit-ID: 96jC9looyZq
dom/animation/test/mozilla/file_restyles.html
--- a/dom/animation/test/mozilla/file_restyles.html
+++ b/dom/animation/test/mozilla/file_restyles.html
@@ -127,26 +127,26 @@ function waitForWheelEvent(aTarget) {
 
     sendWheelAndPaintNoFlush(aTarget, centerX, centerY,
                              { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
                                deltaY: targetRect.height },
                              resolve);
   });
 }
 
-function tweakExpectedRestyleCount(aAnimation, aExpectedRestyleCount) {
+async function waitForAnimationReadyToRestyle(aAnimation) {
+  await aAnimation.ready;
   // If |aAnimation| begins at the current timeline time, we will not process
   // restyling in the initial frame because of aligning with the refresh driver,
   // the animation frame in which the ready promise is resolved happens to
   // coincide perfectly with the start time of the animation.  In this case no
-  // restyling is needed so we won't observe an additional restyle.
+  // restyling is needed in the frame so we have to wait one more frame.
   if (animationStartsRightNow(aAnimation)) {
-    return aExpectedRestyleCount - 1;
+    await waitForNextFrame();
   }
-  return aExpectedRestyleCount;
 }
 
 var omtaEnabled = isOMTAEnabled();
 
 var isAndroid = !!navigator.userAgent.includes("Android");
 const isWebRender =
   SpecialPowers.DOMWindowUtils.layerManagerType == 'WebRender';
 
@@ -160,24 +160,22 @@ function add_task_if_omta_enabled(test) 
 
 // We need to wait for all paints before running tests to avoid contaminations
 // from styling of this document itself.
 waitForAllPaints(() => {
   add_task(async function restyling_for_main_thread_animations() {
     var div = addDiv(null, { style: 'animation: background-color 100s' });
     var animation = div.getAnimations()[0];
 
-    await animation.ready;
+    await waitForAnimationReadyToRestyle(animation);
+
     ok(!SpecialPowers.wrap(animation).isRunningOnCompositor);
 
-    // We need to tweak expected restyle count depending on animation state and
-    // micro task handling.
-    const expectedRestyleCount = tweakExpectedRestyleCount(animation, 5);
     var markers = await observeStyling(5);
-    is(markers.length, expectedRestyleCount,
+    is(markers.length, 5,
        'CSS animations running on the main-thread should update style ' +
        'on the main thread');
     await ensureElementRemoval(div);
   });
 
   add_task_if_omta_enabled(async function no_restyling_for_compositor_animations() {
     var div = addDiv(null, { style: 'animation: opacity 100s' });
     var animation = div.getAnimations()[0];
@@ -474,23 +472,21 @@ waitForAllPaints(() => {
     var div = addDiv(null);
     var animation =
       div.animate({ transform: [ 'translateX(120%)', 'translateX(100%)' ] },
                                 // This animation will move a bit but
                                 // will remain out-of-view.
                   100 * MS_PER_SEC);
     parentElement.appendChild(div);
 
-    await animation.ready;
+    await waitForAnimationReadyToRestyle(animation);
     ok(!SpecialPowers.wrap(animation).isRunningOnCompositor);
 
-    const expectedRestyleCount = tweakExpectedRestyleCount(animation, 20);
-
     var markers = await observeStyling(20);
-    is(markers.length, expectedRestyleCount,
+    is(markers.length, 20,
        'Finite transform animation in out-of-view element should never be ' +
        'throttled');
 
     await ensureElementRemoval(parentElement);
   });
 
   add_task(async function restyling_main_thread_animations_in_scrolled_out_element() {
     var parentElement = addDiv(null,
@@ -1220,59 +1216,56 @@ waitForAllPaints(() => {
 
   add_task(
     async function no_throttling_additive_animations_out_of_view_element() {
       var div = addDiv(null, { style: 'transform: translateY(-400px);' });
       var animation =
         div.animate([{ visibility: 'visible' }],
                     { duration: 100 * MS_PER_SEC, composite: 'add' });
 
-      await animation.ready;
+      await waitForAnimationReadyToRestyle(animation);
 
-      const expectedRestyleCount = tweakExpectedRestyleCount(animation, 5);
       var markers = await observeStyling(5);
 
-      is(markers.length, expectedRestyleCount,
+      is(markers.length, 5,
          'Additive animation has no keyframe whose offset is 0 or 1 in an ' +
          'out-of-view element should not be throttled');
       await ensureElementRemoval(div);
     }
   );
 
   // Tests that missing keyframes animations don't throttle at all.
   add_task(async function no_throttling_animations_out_of_view_element() {
     var div = addDiv(null, { style: 'transform: translateY(-400px);' });
     var animation =
       div.animate([{ visibility: 'visible' }], 100 * MS_PER_SEC);
 
-    await animation.ready;
+    await waitForAnimationReadyToRestyle(animation);
 
-    const expectedRestyleCount = tweakExpectedRestyleCount(animation, 5);
     var markers = await observeStyling(5);
 
-    is(markers.length, expectedRestyleCount,
+    is(markers.length, 5,
        'Discrete animation has has no keyframe whose offset is 0 or 1 in an ' +
        'out-of-view element should not be throttled');
     await ensureElementRemoval(div);
   });
 
   // Tests that missing keyframes animation on scrolled out element that the
   // animation is not able to be throttled.
   add_task(
     async function no_throttling_missing_keyframe_animations_out_of_view_element() {
       var div =
         addDiv(null, { style: 'transform: translateY(-400px);' +
                               'visibility: collapse;' });
       var animation =
         div.animate([{ visibility: 'visible' }], 100 * MS_PER_SEC);
-      await animation.ready;
+      await waitForAnimationReadyToRestyle(animation);
 
-      const expectedRestyleCount = tweakExpectedRestyleCount(animation, 5);
       var markers = await observeStyling(5);
-      is(markers.length, expectedRestyleCount,
+      is(markers.length, 5,
          'visibility animation has no keyframe whose offset is 0 or 1 in an ' +
          'out-of-view element and produces change hint other than paint-only ' +
          'change hint should not be throttled');
       await ensureElementRemoval(div);
     }
   );
 
   // Counter part of the above test.
@@ -1314,21 +1307,20 @@ waitForAllPaints(() => {
                                           width:   '50px',
                                           height:  '50px' });
     var rect = addSVGElement(svg, 'rect', { x:      '-10',
                                             y:      '-10',
                                             width:  '10',
                                             height: '10',
                                             fill:   'red' });
     var animation = rect.animate({ fill: ['blue', 'lime'] }, 100 * MS_PER_SEC);
-    await animation.ready;
+    await waitForAnimationReadyToRestyle(animation);
 
-    const expectedRestyleCount = tweakExpectedRestyleCount(animation, 5);
     var markers = await observeStyling(5);
-    is(markers.length, expectedRestyleCount,
+    is(markers.length, 5,
        'CSS animations on an in-view svg element with post-transform should ' +
        'not be throttled.');
 
     await ensureElementRemoval(div);
   });
 
   add_task(async function no_throttling_animations_in_transformed_parent() {
     var div = addDiv(null, { style: 'overflow: scroll;' +
@@ -1337,21 +1329,20 @@ waitForAllPaints(() => {
                                           width:   '40px',
                                           height:  '40px' });
     var rect = addSVGElement(svg, 'rect', { x:      '0',
                                             y:      '0',
                                             width:  '1250',
                                             height: '1250',
                                             fill:   'red' });
     var animation = rect.animate({ fill: ['blue', 'lime'] }, 100 * MS_PER_SEC);
-    await animation.ready;
+    await waitForAnimationReadyToRestyle(animation);
 
-    const expectedRestyleCount = tweakExpectedRestyleCount(animation, 5);
     var markers = await observeStyling(5);
-    is(markers.length, expectedRestyleCount,
+    is(markers.length, 5,
        'CSS animations on an in-view svg element which is inside transformed ' +
        'parent should not be throttled.');
 
     await ensureElementRemoval(div);
   });
 
   add_task(async function throttling_animations_out_of_view_svg() {
     var div = addDiv(null, { style: 'overflow: scroll;' +
@@ -1378,21 +1369,20 @@ waitForAllPaints(() => {
     var scrollDiv = addDiv(null, { style: 'overflow: scroll; ' +
                                           'height: 100px; width: 100px;' });
     var targetDiv = addDiv(null,
                            { style: 'animation: background-color 100s;' +
                                     'transform: translate(-50px, -50px);' });
     scrollDiv.appendChild(targetDiv);
 
     var animation = targetDiv.getAnimations()[0];
-    await animation.ready;
+    await waitForAnimationReadyToRestyle(animation);
 
-    const expectedRestyleCount = tweakExpectedRestyleCount(animation, 5);
     var markers = await observeStyling(5);
-    is(markers.length, expectedRestyleCount,
+    is(markers.length, 5,
        'CSS animation on an in-view element with pre-transform should not ' +
        'be throttled.');
 
     await ensureElementRemoval(scrollDiv);
   });
 
   add_task(async function throttling_animations_out_of_view_css_transform() {
     var scrollDiv = addDiv(null, { style: 'overflow: scroll;' +
@@ -1524,21 +1514,20 @@ waitForAllPaints(() => {
       var parent = addDiv(null, { style: 'overflow: scroll; height: 0px;' });
       var target = addDiv(null,
                           { style: 'animation: background-color 100s infinite;' +
                                    'position: absolute; top: 50%;' +
                                    'width: 100px; height: 100px;' });
       parent.appendChild(target);
 
       var animation = target.getAnimations()[0];
-      await animation.ready;
+      await waitForAnimationReadyToRestyle(animation);
 
-      const expectedRestyleCount = tweakExpectedRestyleCount(animation, 5);
       var markers = await observeStyling(5);
-      is(markers.length, expectedRestyleCount,
+      is(markers.length, 5,
          'Animation on position:absolute element in collapsed element ' +
          'should not be throttled');
 
       await ensureElementRemoval(parent);
     }
   );
 
   add_task(