Bug 1362623 - Wait for idle callback before executing document_idle content scripts. r?mixedpuppy
MozReview-Commit-ID: 6pOrH1lrTV2
--- a/toolkit/components/extensions/ExtensionContent.jsm
+++ b/toolkit/components/extensions/ExtensionContent.jsm
@@ -21,16 +21,20 @@ XPCOMUtils.defineLazyModuleGetter(this,
"resource://gre/modules/Schemas.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "WebNavigationFrames",
"resource://gre/modules/WebNavigationFrames.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "styleSheetService",
"@mozilla.org/content/style-sheet-service;1",
"nsIStyleSheetService");
+// xpcshell doesn't handle idle callbacks well.
+XPCOMUtils.defineLazyGetter(this, "idleTimeout",
+ () => Services.appinfo.name === "XPCShell" ? 500 : undefined);
+
const DocumentEncoder = Components.Constructor(
"@mozilla.org/layout/documentEncoder;1?type=text/plain",
"nsIDocumentEncoder", "init");
const Timer = Components.Constructor("@mozilla.org/timer;1", "nsITimer", "initWithCallback");
Cu.import("resource://gre/modules/ExtensionChild.jsm");
Cu.import("resource://gre/modules/ExtensionCommon.jsm");
@@ -304,16 +308,22 @@ class Script {
let {document} = context.contentWindow;
if (this.runAt === "document_start" && document.readyState !== "complete") {
document.blockParsing(scriptsPromise);
}
let scripts = await scriptsPromise;
let result;
+ if (this.runAt === "document_idle") {
+ await new Promise(resolve =>
+ context.contentWindow.requestIdleCallback(resolve,
+ {timeout: idleTimeout}));
+ }
+
// The evaluations below may throw, in which case the promise will be
// automatically rejected.
for (let script of scripts) {
result = script.executeInGlobal(context.cloneScope);
}
if (this.options.jsCode) {
result = Cu.evalInSandbox(this.options.jsCode, context.cloneScope, "latest");
--- a/toolkit/components/extensions/test/xpcshell/test_ext_contentscript.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_contentscript.js
@@ -1,15 +1,17 @@
"use strict";
const server = createHttpServer();
server.registerDirectory("/data/", do_get_file("data"));
const BASE_URL = `http://localhost:${server.identity.primaryPort}/data`;
+ExtensionTestUtils.mockAppInfo();
+
add_task(function* test_contentscript() {
function background() {
browser.runtime.onMessage.addListener(([msg, expectedStates, readyState], sender) => {
if (msg == "chrome-namespace-ok") {
browser.test.sendMessage(msg);
return;
}