Bug 1447874 - Use flushLayoutWithoutThrottledAnimations in the state of STATE_WAITING_TO_FIRE_INVALIDATE_EVENT. r?birtles,kats draft
authorHiroyuki Ikezoe <hikezoe@mozilla.com>
Mon, 02 Apr 2018 18:01:41 +0900
changeset 775977 2a4ad02ed91b625ff7bdea1c36a705cb196fb69d
parent 775943 8431cf05a5f6ec2fad38e7a6448e4fe3d1a9936d
push id104777
push userhikezoe@mozilla.com
push dateMon, 02 Apr 2018 09:02:02 +0000
reviewersbirtles, kats
bugs1447874
milestone61.0a1
Bug 1447874 - Use flushLayoutWithoutThrottledAnimations in the state of STATE_WAITING_TO_FIRE_INVALIDATE_EVENT. r?birtles,kats In the state of STATE_WAITING_TO_FIRE_INVALIDATE_EVENT, we flush all pending styles and layout and wait for a MozAfterPaint that caused by the flush. This will be repeated until neither pending styles nor layout exists. But if there is any throttled animation, flush for the throttled animation might cause a new MozAfterPaint. That means that we will get stuck until the throttled animation finished. In this patch, to avoid this situation, we don't flush throttled animations in the state of STATE_WAITING_TO_FIRE_INVALIDATE_EVENT. MozReview-Commit-ID: LUz279w3Yoj
layout/tools/reftest/reftest-content.js
--- a/layout/tools/reftest/reftest-content.js
+++ b/layout/tools/reftest/reftest-content.js
@@ -465,16 +465,21 @@ function getAssignedLayerMap(contentRoot
         if (!(layerName in layerNameToElementsMap)) {
             layerNameToElementsMap[layerName] = [];
         }
         layerNameToElementsMap[layerName].push(element);
     }
     return layerNameToElementsMap;
 }
 
+const FlushMode = {
+  ALL: 0,
+  IGNORE_THROTTLED_ANIMATIONS: 1
+};
+
 // Initial state. When the document has loaded and all MozAfterPaint events and
 // all explicit paint waits are flushed, we can fire the MozReftestInvalidate
 // event and move to the next state.
 const STATE_WAITING_TO_FIRE_INVALIDATE_EVENT = 0;
 // When reftest-wait has been removed from the root element, we can move to the
 // next state.
 const STATE_WAITING_FOR_REFTEST_WAIT_REMOVAL = 1;
 // When spell checking is done on all spell-checked elements, we can move to the
@@ -483,29 +488,32 @@ const STATE_WAITING_FOR_SPELL_CHECKS = 2
 // When any pending compositor-side repaint requests have been flushed, we can
 // move to the next state.
 const STATE_WAITING_FOR_APZ_FLUSH = 3;
 // When all MozAfterPaint events and all explicit paint waits are flushed, we're
 // done and can move to the COMPLETED state.
 const STATE_WAITING_TO_FINISH = 4;
 const STATE_COMPLETED = 5;
 
-function FlushRendering() {
+function FlushRendering(aFlushMode) {
     var anyPendingPaintsGeneratedInDescendants = false;
 
     function flushWindow(win) {
         var utils = win.QueryInterface(Ci.nsIInterfaceRequestor)
                     .getInterface(Ci.nsIDOMWindowUtils);
         var afterPaintWasPending = utils.isMozAfterPaintPending;
 
         var root = win.document.documentElement;
         if (root && !root.classList.contains("reftest-no-flush")) {
             try {
-                // Flush pending restyles and reflows for this window
-                root.getBoundingClientRect();
+                if (aFlushMode === FlushMode.IGNORE_THROTTLED_ANIMATIONS) {
+                    utils.flushLayoutWithoutThrottledAnimations();
+                } else {
+                    root.getBoundingClientRect();
+                }
             } catch (e) {
                 LogWarning("flushWindow failed: " + e + "\n");
             }
         }
 
         if (!afterPaintWasPending && utils.isMozAfterPaintPending) {
             LogInfo("FlushRendering generated paint for window " + win.location.href);
             anyPendingPaintsGeneratedInDescendants = true;
@@ -580,17 +588,27 @@ function WaitForTestEnd(contentRootEleme
         if (state >= STATE_COMPLETED) {
             LogInfo("MakeProgress: STATE_COMPLETED");
             return;
         }
 
         // We don't need to flush styles any more when we are in the state
         // after reftest-wait has removed.
         if (state != STATE_WAITING_TO_FINISH) {
-          FlushRendering();
+          // If we are waiting for the MozReftestInvalidate event we don't want
+          // to flush throttled animations. Flushing throttled animations can
+          // continue to cause new MozAfterPaint events even when all the
+          // rendering we're concerned about should have ceased. Since
+          // MozReftestInvalidate won't be sent until we finish waiting for all
+          // MozAfterPaint events, we should avoid flushing throttled animations
+          // here or else we'll never leave this state.
+          flushMode = (state === STATE_WAITING_TO_FIRE_INVALIDATE_EVENT)
+                    ? FlushMode.IGNORE_THROTTLED_ANIMATIONS
+                    : FlushMode.ALL;
+          FlushRendering(flushMode);
         }
 
         switch (state) {
         case STATE_WAITING_TO_FIRE_INVALIDATE_EVENT: {
             LogInfo("MakeProgress: STATE_WAITING_TO_FIRE_INVALIDATE_EVENT");
             if (shouldWaitForExplicitPaintWaiters() || shouldWaitForPendingPaints()) {
                 gFailureReason = "timed out waiting for pending paint count to reach zero";
                 if (shouldWaitForExplicitPaintWaiters()) {
@@ -629,17 +647,17 @@ function WaitForTestEnd(contentRootEleme
             if (!inPrintMode && doPrintMode(contentRootElement)) {
                 LogInfo("MakeProgress: setting up print mode");
                 setupPrintMode();
             }
 
             if (hasReftestWait && !shouldWaitForReftestWaitRemoval(contentRootElement)) {
                 // MozReftestInvalidate handler removed reftest-wait.
                 // We expect something to have been invalidated...
-                FlushRendering();
+                FlushRendering(FlushMode.ALL);
                 if (!shouldWaitForPendingPaints() && !shouldWaitForExplicitPaintWaiters()) {
                     LogWarning("MozInvalidateEvent didn't invalidate");
                 }
             }
             // Try next state
             MakeProgress();
             return;
         }
@@ -829,17 +847,17 @@ function OnDocumentLoad(event)
     var inPrintMode = false;
 
     function AfterOnLoadScripts() {
         // Regrab the root element, because the document may have changed.
         var contentRootElement =
           content.document ? content.document.documentElement : null;
 
         // Flush the document in case it got modified in a load event handler.
-        FlushRendering();
+        FlushRendering(FlushMode.ALL);
 
         // Take a snapshot now. We need to do this before we check whether
         // we should wait, since this might trigger dispatching of
         // MozPaintWait events and make shouldWaitForExplicitPaintWaiters() true
         // below.
         var painted = SendInitCanvasWithSnapshot();
 
         if (shouldWaitForExplicitPaintWaiters() ||