Bug 1418268 - Tweak expected restyle count for the case where animation start time was clamped. r?birtles draft
authorHiroyuki Ikezoe <hikezoe@mozilla.com>
Thu, 07 Dec 2017 12:57:54 +0900
changeset 708764 4923922a51d44704b9fad2eab7f0f364ba43b559
parent 708763 3c33dc8ddc1460691409d4350727d8d5bdf2073b
child 743241 e7968370091f1a8447ac64654075344b4aeb9e69
push id92440
push userhikezoe@mozilla.com
push dateThu, 07 Dec 2017 03:58:44 +0000
reviewersbirtles
bugs1418268
milestone59.0a1
Bug 1418268 - Tweak expected restyle count for the case where animation start time was clamped. r?birtles MozReview-Commit-ID: IPxRtRucze4
dom/animation/test/mozilla/file_restyles.html
--- a/dom/animation/test/mozilla/file_restyles.html
+++ b/dom/animation/test/mozilla/file_restyles.html
@@ -84,16 +84,26 @@ function waitForWheelEvent(aTarget) {
 
     sendWheelAndPaintNoFlush(aTarget, centerX, centerY,
                              { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
                                deltaY: targetRect.height },
                              resolve);
   });
 }
 
+// Returns true if |aAnimation| begins at the current timeline time.  We
+// sometimes need to detect this case because if we started an animation
+// asynchronously (e.g. using play()) and then ended up running the next frame
+// at precisely the time the animation started (due to aligning with vsync
+// refresh rate) then we won't end up restyling in that frame.
+function startsRightNow(aAnimation) {
+  return aAnimation.startTime === aAnimation.timeline.currentTime &&
+         aAnimation.currentTime === 0;
+}
+
 var omtaEnabled = isOMTAEnabled();
 
 var isAndroid = !!navigator.userAgent.includes("Android");
 var isServo = isStyledByServo();
 var offscreenThrottlingEnabled =
   SpecialPowers.getBoolPref('dom.animations.offscreen-throttling');
 var hasMicroTaskCheckpointForAnimation;
 
@@ -142,18 +152,36 @@ 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;
     ok(!SpecialPowers.wrap(animation).isRunningOnCompositor);
 
+    // Normally we expect one restyling for each requestAnimationFrame (as
+    // called by observeRestyling) PLUS one for the last frame becasue of bug
+    // 1193394.  However, we won't observe that initial restyling unless BOTH of
+    // the following two conditions hold:
+    //
+    // 1. We are running *before* restyling happens.  This only happens if we
+    //    perform a micro task checkpoint after resolving the 'ready' promise
+    //    above (bug 1416966).
+    // 2. The animation actually needs a restyle because it started prior to
+    //    this frame.  Even if (1) is true, in some cases due to aligning with
+    //    the refresh driver, the animation fame 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.
+    const expectedRestyleCount =
+      hasMicroTaskCheckpointForAnimation && !startsRightNow(animation)
+        ? 6
+        : 5;
     var markers = await observeStyling(5);
-    is(markers.length, 5,
+    is(markers.length, expectedRestyleCount,
        '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];
@@ -900,19 +928,23 @@ waitForAllPaints(() => {
     }
 
     var div = addDiv(null, { style: 'transform: translateY(-400px);' });
     var animation =
       div.animate([{ visibility: 'visible' }], 100 * MS_PER_SEC);
 
     await animation.ready;
 
+    const expectedRestyleCount =
+      hasMicroTaskCheckpointForAnimation && !startsRightNow(animation)
+        ? 6
+        : 5;
     var markers = await observeStyling(5);
 
-    is(markers.length, 5,
+    is(markers.length, expectedRestyleCount,
        '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);
   });
 
   // Counter part of the above test.
   add_task(async function no_restyling_discrete_animations_out_of_view_element() {
     if (!offscreenThrottlingEnabled ||
@@ -967,18 +999,22 @@ waitForAllPaints(() => {
     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;
 
+    const expectedRestyleCount =
+      hasMicroTaskCheckpointForAnimation && !startsRightNow(animation)
+        ? 6
+        : 5;
     var markers = await observeStyling(5);
-    is(markers.length, 5,
+    is(markers.length, expectedRestyleCount,
        'CSS animations on an in-view svg element with post-transform should ' +
        'not be throttled.');
 
     await ensureElementRemoval(div);
   });
 
   add_task(async function throttling_animations_out_of_view_svg() {
     if (!offscreenThrottlingEnabled) {
@@ -1027,18 +1063,22 @@ waitForAllPaints(() => {
     var targetDiv = addDiv(null,
                            { style: 'animation: background-color 100s;' +
                                     'transform: translate(-50px, -50px);' });
     scrollDiv.appendChild(targetDiv);
 
     var animation = targetDiv.getAnimations()[0];
     await animation.ready;
 
+    const expectedRestyleCount =
+      hasMicroTaskCheckpointForAnimation && !startsRightNow(animation)
+        ? 6
+        : 5;
     var markers = await observeStyling(5);
-    is(markers.length, 5,
+    is(markers.length, expectedRestyleCount,
        '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() {
     if (!offscreenThrottlingEnabled) {