summaryrefslogtreecommitdiffstats
path: root/layout/tools/reftest/ReftestFissionParent.jsm
diff options
context:
space:
mode:
Diffstat (limited to 'layout/tools/reftest/ReftestFissionParent.jsm')
-rw-r--r--layout/tools/reftest/ReftestFissionParent.jsm238
1 files changed, 238 insertions, 0 deletions
diff --git a/layout/tools/reftest/ReftestFissionParent.jsm b/layout/tools/reftest/ReftestFissionParent.jsm
new file mode 100644
index 0000000000..703e3b8193
--- /dev/null
+++ b/layout/tools/reftest/ReftestFissionParent.jsm
@@ -0,0 +1,238 @@
+var EXPORTED_SYMBOLS = ["ReftestFissionParent"];
+
+class ReftestFissionParent extends JSWindowActorParent {
+
+ tellChildrenToFlushRendering(browsingContext, ignoreThrottledAnimations) {
+ let promises = [];
+ this.tellChildrenToFlushRenderingRecursive(browsingContext, ignoreThrottledAnimations, promises);
+ return Promise.allSettled(promises);
+ }
+
+ tellChildrenToFlushRenderingRecursive(browsingContext, ignoreThrottledAnimations, promises) {
+ let cwg = browsingContext.currentWindowGlobal;
+ if (cwg && cwg.isProcessRoot) {
+ let a = cwg.getActor("ReftestFission");
+ if (a) {
+ let responsePromise = a.sendQuery("FlushRendering", {ignoreThrottledAnimations});
+ promises.push(responsePromise);
+ }
+ }
+
+ for (let context of browsingContext.children) {
+ this.tellChildrenToFlushRenderingRecursive(context, ignoreThrottledAnimations, promises);
+ }
+ }
+
+ // not including browsingContext
+ getNearestProcessRootProperDescendants(browsingContext) {
+ let result = [];
+ for (let context of browsingContext.children) {
+ this.getNearestProcessRootProperDescendantsRecursive(context, result);
+ }
+ return result;
+ }
+
+ getNearestProcessRootProperDescendantsRecursive(browsingContext, result) {
+ let cwg = browsingContext.currentWindowGlobal;
+ if (cwg && cwg.isProcessRoot) {
+ result.push(browsingContext);
+ return;
+ }
+ for (let context of browsingContext.children) {
+ this.getNearestProcessRootProperDescendantsRecursive(context, result);
+ }
+ }
+
+ // tell children and itself
+ async tellChildrenToUpdateLayerTree(browsingContext) {
+ let errorStrings = [];
+ let infoStrings = [];
+
+ let cwg = browsingContext.currentWindowGlobal;
+ if (!cwg || !cwg.isProcessRoot) {
+ if (cwg) {
+ errorStrings.push("tellChildrenToUpdateLayerTree called on a non process root?");
+ }
+ return {errorStrings, infoStrings};
+ }
+
+ let actor = cwg.getActor("ReftestFission");
+ if (!actor) {
+ return {errorStrings, infoStrings};
+ }
+
+ // When we paint a document we also update the EffectsInfo visible rect in
+ // nsSubDocumentFrame for any remote subdocuments. This visible rect is
+ // used to limit painting for the subdocument in the subdocument's process.
+ // So we want to ensure that the IPC message that updates the visible rect
+ // to the subdocument's process arrives before we paint the subdocument
+ // (otherwise our painting might not be up to date). We do this by sending,
+ // and waiting for reply, an "EmptyMessage" to every direct descendant that
+ // is in another process. Since we send the "EmptyMessage" after the
+ // visible rect update message we know that the visible rect will be
+ // updated by the time we hear back from the "EmptyMessage". Then we can
+ // ask the subdocument process to paint.
+
+ try {
+ let result = await actor.sendQuery("UpdateLayerTree");
+ errorStrings.push(...result.errorStrings);
+ } catch (e) {
+ infoStrings.push("tellChildrenToUpdateLayerTree UpdateLayerTree msg to child rejected: " + e);
+ }
+
+ let descendants = actor.getNearestProcessRootProperDescendants(browsingContext);
+ for (let context of descendants) {
+ let cwg2 = context.currentWindowGlobal;
+ if (cwg2) {
+ if (!cwg2.isProcessRoot) {
+ errorStrings.push("getNearestProcessRootProperDescendants returned a non process root?");
+ }
+ let actor2 = cwg2.getActor("ReftestFission");
+ if (actor2) {
+ try {
+ await actor2.sendQuery("EmptyMessage");
+ } catch(e) {
+ infoStrings.push("tellChildrenToUpdateLayerTree EmptyMessage msg to child rejected: " + e);
+ }
+
+ try {
+ let result2 = await actor2.tellChildrenToUpdateLayerTree(context);
+ errorStrings.push(...result2.errorStrings);
+ infoStrings.push(...result2.infoStrings);
+ } catch (e) {
+ errorStrings.push("tellChildrenToUpdateLayerTree recursive tellChildrenToUpdateLayerTree call rejected: " + e);
+ }
+
+ }
+ }
+ }
+
+ return {errorStrings, infoStrings};
+ }
+
+ tellChildrenToSetupDisplayport(browsingContext, promises) {
+ let cwg = browsingContext.currentWindowGlobal;
+ if (cwg && cwg.isProcessRoot) {
+ let a = cwg.getActor("ReftestFission");
+ if (a) {
+ let responsePromise = a.sendQuery("SetupDisplayport");
+ promises.push(responsePromise);
+ }
+ }
+
+ for (let context of browsingContext.children) {
+ this.tellChildrenToSetupDisplayport(context, promises);
+ }
+ }
+
+ tellChildrenToSetupAsyncScrollOffsets(browsingContext, allowFailure, promises) {
+ let cwg = browsingContext.currentWindowGlobal;
+ if (cwg && cwg.isProcessRoot) {
+ let a = cwg.getActor("ReftestFission");
+ if (a) {
+ let responsePromise = a.sendQuery("SetupAsyncScrollOffsets", {allowFailure});
+ promises.push(responsePromise);
+ }
+ }
+
+ for (let context of browsingContext.children) {
+ this.tellChildrenToSetupAsyncScrollOffsets(context, allowFailure, promises);
+ }
+ }
+
+
+ receiveMessage(msg) {
+ switch (msg.name) {
+ case "ForwardAfterPaintEvent":
+ {
+ let cwg = msg.data.toBrowsingContext.currentWindowGlobal;
+ if (cwg) {
+ let a = cwg.getActor("ReftestFission");
+ if (a) {
+ a.sendAsyncMessage("ForwardAfterPaintEventToSelfAndParent", msg.data);
+ }
+ }
+ break;
+ }
+ case "FlushRendering":
+ {
+ let promise = this.tellChildrenToFlushRendering(msg.data.browsingContext, msg.data.ignoreThrottledAnimations);
+ return promise.then(function (results) {
+ let errorStrings = [];
+ let warningStrings = [];
+ let infoStrings = [];
+ for (let r of results) {
+ if (r.status != "fulfilled") {
+ if (r.status == "pending") {
+ errorStrings.push("FlushRendering sendQuery to child promise still pending?");
+ } else {
+ // We expect actors to go away causing sendQuery's to fail, so
+ // just note it.
+ infoStrings.push("FlushRendering sendQuery to child promise rejected: " + r.reason);
+ }
+ continue;
+ }
+
+ errorStrings.push(...r.value.errorStrings);
+ warningStrings.push(...r.value.warningStrings);
+ infoStrings.push(...r.value.infoStrings);
+ }
+ return {errorStrings, warningStrings, infoStrings};
+ });
+ }
+ case "UpdateLayerTree":
+ {
+ return this.tellChildrenToUpdateLayerTree(msg.data.browsingContext);
+ }
+ case "TellChildrenToSetupDisplayport":
+ {
+ let promises = [];
+ this.tellChildrenToSetupDisplayport(msg.data.browsingContext, promises);
+ return Promise.allSettled(promises).then(function (results) {
+ let errorStrings = [];
+ let infoStrings = [];
+ for (let r of results) {
+ if (r.status != "fulfilled") {
+ // We expect actors to go away causing sendQuery's to fail, so
+ // just note it.
+ infoStrings.push("SetupDisplayport sendQuery to child promise rejected: " + r.reason);
+ continue;
+ }
+
+ errorStrings.push(...r.value.errorStrings);
+ infoStrings.push(...r.value.infoStrings);
+ }
+ return {errorStrings, infoStrings}
+ });
+ }
+
+ case "SetupAsyncScrollOffsets":
+ {
+ let promises = [];
+ this.tellChildrenToSetupAsyncScrollOffsets(this.manager.browsingContext, msg.data.allowFailure, promises);
+ return Promise.allSettled(promises).then(function (results) {
+ let errorStrings = [];
+ let infoStrings = [];
+ let updatedAny = false;
+ for (let r of results) {
+ if (r.status != "fulfilled") {
+ // We expect actors to go away causing sendQuery's to fail, so
+ // just note it.
+ infoStrings.push("SetupAsyncScrollOffsets sendQuery to child promise rejected: " + r.reason);
+ continue;
+ }
+
+ errorStrings.push(...r.value.errorStrings);
+ infoStrings.push(...r.value.infoStrings);
+ if (r.value.updatedAny) {
+ updatedAny = true;
+ }
+ }
+ return {errorStrings, infoStrings, updatedAny};
+ });
+ }
+
+ }
+ }
+
+}