Bug 1437295 - Ensure that waitUntilApzStable also flushes the parent process. r?botond draft
authorKartikaya Gupta <kgupta@mozilla.com>
Sat, 10 Mar 2018 23:26:27 -0500
changeset 765929 474993cc116f4a7b2172baa922e34405fc889aa8
parent 765928 a5dc6dd28c3d376426152e4b127c08237175d2ce
child 765930 cc23cdb7eaa0c7ce3298bdaaebc8b6c1b76ee662
push id102181
push userkgupta@mozilla.com
push dateSun, 11 Mar 2018 04:27:20 +0000
reviewersbotond
bugs1437295
milestone60.0a1
Bug 1437295 - Ensure that waitUntilApzStable also flushes the parent process. r?botond With e10s enabled, we need to make sure that not only has the content process layer tree reached the compositor, but also that the parent process layer tree with the correct RefLayer has reached the compositor. This is important for some APZ tests which proceed on the assumption that the content process has been composited. MozReview-Commit-ID: D0peZsJMHNT
gfx/layers/apz/test/mochitest/apz_test_utils.js
--- a/gfx/layers/apz/test/mochitest/apz_test_utils.js
+++ b/gfx/layers/apz/test/mochitest/apz_test_utils.js
@@ -276,16 +276,70 @@ function runSubtestsSeriallyInFreshWindo
   });
 }
 
 function pushPrefs(prefs) {
   return SpecialPowers.pushPrefEnv({'set': prefs});
 }
 
 async function waitUntilApzStable() {
+  if (!SpecialPowers.isMainProcess()) {
+    // We use this waitUntilApzStable function during test initialization
+    // and for those scenarios we want to flush the parent-process layer
+    // tree to the compositor and wait for that as well. That way we know
+    // that not only is the content-process layer tree ready in the compositor,
+    // the parent-process layer tree in the compositor has the appropriate
+    // RefLayer pointing to the content-process layer tree.
+
+    // Sadly this helper function cannot reuse any code from other places because
+    // it must be totally self-contained to be shipped over to the parent process.
+    function parentProcessFlush() {
+      addMessageListener("apz-flush", function() {
+        ChromeUtils.import("resource://gre/modules/Services.jsm");
+        var topWin = Services.wm.getMostRecentWindow("navigator:browser");
+        var topUtils = topWin.QueryInterface(Ci.nsIInterfaceRequestor)
+                             .getInterface(Ci.nsIDOMWindowUtils);
+
+        var repaintDone = function() {
+          Services.obs.removeObserver(repaintDone, "apz-repaints-flushed");
+          // send message back to content process
+          sendAsyncMessage("apz-flush-done", null);
+        };
+        var flushRepaint = function() {
+          if (topUtils.isMozAfterPaintPending) {
+            topWin.addEventListener("MozAfterPaint", flushRepaint, { once: true });
+            return;
+          }
+
+          Services.obs.addObserver(repaintDone, "apz-repaints-flushed");
+          if (topUtils.flushApzRepaints()) {
+            dump("Parent process: flushed APZ repaints, waiting for callback...\n");
+          } else {
+            dump("Parent process: flushing APZ repaints was a no-op, triggering callback directly...\n");
+            repaintDone();
+          }
+        }
+
+        // Flush APZ repaints, but wait until all the pending paints have been
+        // sent.
+        flushRepaint();
+      });
+    }
+
+    // This is the first time waitUntilApzStable is being called, do initialization
+    if (typeof waitUntilApzStable.chromeHelper == "undefined") {
+      waitUntilApzStable.chromeHelper = SpecialPowers.loadChromeScript(parentProcessFlush);
+      ApzCleanup.register(() => { waitUntilApzStable.chromeHelper.destroy(); });
+    }
+
+    // Actually trigger the parent-process flush and wait for it to finish
+    waitUntilApzStable.chromeHelper.sendAsyncMessage("apz-flush", null);
+    await waitUntilApzStable.chromeHelper.promiseOneMessage("apz-flush-done");
+  }
+
   await SimpleTest.promiseFocus(window);
   await promiseAllPaintsDone();
   await promiseApzRepaintsFlushed();
 }
 
 function isApzEnabled() {
   var enabled = SpecialPowers.getDOMWindowUtils(window).asyncPanZoomEnabled;
   if (!enabled) {