Bug 1447874 - Use flushLayoutWithoutThrottledAnimations in the state of STATE_WAITING_TO_FIRE_INVALIDATE_EVENT. r=birtles,kats
authorHiroyuki Ikezoe <hikezoe@mozilla.com>
Mon, 02 Apr 2018 18:01:41 +0900
changeset 777792 4b4230db0bdce11b915a896b84ab99631c77aa82
parent 777791 c3dc86c628f40d3ad6d6848346fc9721031ae732
child 777793 16bec207dc418bac3bef71ae5c15ade76032d6e0
push id105296
push userpaolo.mozmail@amadzone.org
push dateThu, 05 Apr 2018 10:49:16 +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() ||