Bug 1646629 - Set updateCanvasPending explicitly when reftest-wait was removed and take a snapshot of the whole screen if reftest-no-flush is specified. r?mattwoodrow,tnikkel draft
authorHiroyuki Ikezoe <hikezoe.birchill@mozilla.com>
Thu, 18 Jun 2020 18:05:49 +0900
changeset 3000246 5b7326ebe8431a6ea2608971181251745467b49a
parent 2996527 9b38f4b9d883b2bc2c4f3d170942546c2d82aacf
child 3000247 1565ea4eacd1867e2ffeb6702d4b35f73ecfdecd
push id558657
push userhikezoe.birchill@mozilla.com
push dateWed, 24 Jun 2020 01:19:11 +0000
treeherdertry@bb059ebb3e19 [default view] [failures only]
reviewersmattwoodrow, tnikkel
bugs1646629
milestone79.0a1
Bug 1646629 - Set updateCanvasPending explicitly when reftest-wait was removed and take a snapshot of the whole screen if reftest-no-flush is specified. r?mattwoodrow,tnikkel That's because we no longer fire MozAfterPaint event for changes by animations on the compositor. Differential Revision: https://phabricator.services.mozilla.com/D80157
layout/reftests/reftest-sanity/reftest-no-flush-ref.html
layout/reftests/reftest-sanity/reftest-no-flush.html
layout/reftests/reftest-sanity/reftest.list
layout/tools/reftest/reftest-content.js
new file mode 100644
--- /dev/null
+++ b/layout/reftests/reftest-sanity/reftest-no-flush-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<style>
+html {
+  overflow: hidden;
+}
+body {
+  margin: 0px;
+  padding: 0px;
+}
+#target {
+  width: 100px;
+  height: 100px;
+  position: absolute;
+  transform: translateX(100px);
+  background-color: green;
+}
+</style>
+<div id="target"></div>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/reftest-sanity/reftest-no-flush.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html class="reftest-wait reftest-no-flush">
+<style>
+html {
+  /* Suppress scrollbars to avoid periodical unthrottling for transform */
+  /* animations on the compositor. */
+  overflow: hidden;
+}
+body {
+  margin: 0px;
+  padding: 0px;
+}
+@keyframes anim {
+  0% { transform: translateX(100px); }
+  100% { transform: translateX(100px); }
+}
+#target {
+  width: 100px;
+  height: 100px;
+  position: absolute;
+  background-color: green;
+}
+</style>
+<div id="target"></div>
+<script>
+document.addEventListener('MozReftestInvalidate', () => {
+  // Set a bit longer animation delay to avoid painting the initial animation
+  // style on the main thread.
+  target.style.animation = "anim 100s 1s";
+  target.addEventListener("animationstart", () => {
+    document.documentElement.classList.remove("reftest-wait");
+  });
+}, { once: true });
+</script>
+</html>
--- a/layout/reftests/reftest-sanity/reftest.list
+++ b/layout/reftests/reftest-sanity/reftest.list
@@ -206,8 +206,10 @@ fails-if(layerChecksEnabled) != reftest-
 != reftest-assigned-layer-pass.html about:blank
 fails-if(layerChecksEnabled) != reftest-assigned-layer-fail-1.html about:blank
 fails-if(layerChecksEnabled) != reftest-assigned-layer-fail-2.html about:blank
 fails-if(layerChecksEnabled) != reftest-assigned-layer-fail-3.html about:blank
 fails-if(layerChecksEnabled) != reftest-assigned-layer-fail-4.html about:blank
 
 # reftest-resolution
 pref(apz.allow_zooming,true) == reftest-resolution.html reftest-resolution-ref.html
+
+== reftest-no-flush.html reftest-no-flush-ref.html
--- a/layout/tools/reftest/reftest-content.js
+++ b/layout/tools/reftest/reftest-content.js
@@ -438,16 +438,24 @@ function shouldWaitForReftestWaitRemoval
 function shouldSnapshotWholePage(contentRootElement) {
     // use getAttribute because className works differently in HTML and SVG
     return contentRootElement &&
            contentRootElement.hasAttribute('class') &&
            contentRootElement.getAttribute('class').split(/\s+/)
                              .includes("reftest-snapshot-all");
 }
 
+function shouldNotFlush(contentRootElement) {
+    // use getAttribute because className works differently in HTML and SVG
+    return contentRootElement &&
+           contentRootElement.hasAttribute('class') &&
+           contentRootElement.getAttribute('class').split(/\s+/)
+                             .includes("reftest-no-flush");
+}
+
 function getNoPaintElements(contentRootElement) {
     return contentRootElement.getElementsByClassName('reftest-no-paint');
 }
 function getNoDisplayListElements(contentRootElement) {
     return contentRootElement.getElementsByClassName('reftest-no-display-list');
 }
 function getDisplayListElements(contentRootElement) {
     return contentRootElement.getElementsByClassName('reftest-display-list');
@@ -849,16 +857,23 @@ function WaitForTestEnd(contentRootEleme
             LogInfo("MakeProgress: STATE_WAITING_FOR_REFTEST_WAIT_REMOVAL");
             CheckForLivenessOfContentRootElement();
             if (shouldWaitForReftestWaitRemoval(contentRootElement)) {
                 gFailureReason = "timed out waiting for reftest-wait to be removed";
                 LogInfo("MakeProgress: waiting for reftest-wait to be removed");
                 return;
             }
 
+            if (shouldNotFlush(contentRootElement)) {
+              // If reftest-no-flush is specified, we need to set
+              // updateCanvasPending explicitly to take the latest snapshot
+              // since animation changes on the compositor thread don't invoke
+              // any MozAfterPaint events at all.
+              updateCanvasPending = true;
+            }
             // Try next state
             state = STATE_WAITING_FOR_SPELL_CHECKS;
             MakeProgress();
             return;
 
         case STATE_WAITING_FOR_SPELL_CHECKS:
             LogInfo("MakeProgress: STATE_WAITING_FOR_SPELL_CHECKS");
             if (numPendingSpellChecks) {
@@ -881,19 +896,17 @@ function WaitForTestEnd(contentRootEleme
                 } else {
                     MakeProgress();
                 }
             };
             os.addObserver(flushWaiter, "apz-repaints-flushed");
 
             var willSnapshot = IsSnapshottableTestType();
             CheckForLivenessOfContentRootElement();
-            var noFlush =
-                !(contentRootElement &&
-                  contentRootElement.classList.contains("reftest-no-flush"));
+            var noFlush = !shouldNotFlush(contentRootElement);
             if (noFlush && willSnapshot && windowUtils().flushApzRepaints()) {
                 LogInfo("MakeProgress: done requesting APZ flush");
             } else {
                 LogInfo("MakeProgress: APZ flush not required");
                 flushWaiter(null, null, null);
             }
             return;
 
@@ -1370,17 +1383,17 @@ function SynchronizeForSnapshot(flags)
     if (!IsSnapshottableTestType()) {
         return Promise.resolve(undefined);
     }
 
     if (flags & SYNC_ALLOW_DISABLE) {
         var docElt = content.document.documentElement;
         if (docElt &&
             (docElt.hasAttribute("reftest-no-sync-layers") ||
-             docElt.classList.contains("reftest-no-flush"))) {
+             shouldNotFlush(docElt))) {
             LogInfo("Test file chose to skip SynchronizeForSnapshot");
             return Promise.resolve(undefined);
         }
     }
 
     let browsingContext = content.docShell.browsingContext;
     let promise = content.windowGlobalChild.getActor("ReftestFission").sendQuery("UpdateLayerTree", {browsingContext});
     return promise.then(function (result) {
@@ -1637,20 +1650,22 @@ function SendUpdateCanvasForEvent(forURL
           return promise.then(function () {
             sendAsyncMessage("reftest:UpdateWholeCanvasForInvalidation");
           });
       }
       return Promise.resolve(undefined);
     }
 
     var message;
-    if (gIsWebRenderEnabled && !windowUtils().isMozAfterPaintPending) {
-        // Webrender doesn't have invalidation, so we just invalidate the whole
-        // screen once we don't have anymore paints pending. This will force
-        // the snapshot.
+    if ((gIsWebRenderEnabled || shouldNotFlush(contentRootElement)) &&
+        !windowUtils().isMozAfterPaintPending) {
+        // Webrender doesn't have invalidation, and animations on the compositor
+        // don't invoke any MozAfterEvent which means we have no invalidated
+        // rect so we just invalidate the whole screen once we don't have
+        // anymore paints pending. This will force the snapshot.
 
         LogInfo("Webrender enabled, sending update whole canvas for invalidation");
         message = "reftest:UpdateWholeCanvasForInvalidation";
     } else {
         LogInfo("SendUpdateCanvasForEvent with " + rectList.length + " rects");
         for (var i = 0; i < rectList.length; ++i) {
             var r = rectList[i];
             // Set left/top/right/bottom to "device pixel" boundaries