зеркало из https://github.com/mozilla/gecko-dev.git
Bug 914633 - Implement SpecialPowers.loadChromeScript to easily add new chrome features without having to modify SpecialPowers. r=ted
This commit is contained in:
Родитель
c23595f345
Коммит
756c89efbe
|
@ -46,6 +46,8 @@ if (outOfProcess) {
|
|||
mm.addMessageListener("SpecialPowers.Quit", specialPowersObserver);
|
||||
mm.addMessageListener("SpecialPowers.Focus", specialPowersObserver);
|
||||
mm.addMessageListener("SPPermissionManager", specialPowersObserver);
|
||||
mm.addMessageListener("SPLoadChromeScript", specialPowersObserver);
|
||||
mm.addMessageListener("SPChromeScriptMessage", specialPowersObserver);
|
||||
|
||||
mm.loadFrameScript(CHILD_LOGGER_SCRIPT, true);
|
||||
mm.loadFrameScript(CHILD_SCRIPT_API, true);
|
||||
|
|
|
@ -16,6 +16,8 @@ _TEST_FILES = \
|
|||
test_SpecialPowersPushPrefEnv.html \
|
||||
file_SpecialPowersFrame1.html \
|
||||
test_SimpleTestGetTestFileURL.html \
|
||||
test_SpecialPowersLoadChromeScript.html \
|
||||
SpecialPowersLoadChromeScript.js \
|
||||
test_bug816847.html \
|
||||
test_sanity_cleanup.html \
|
||||
test_sanity_cleanup2.html \
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
// Just receive 'foo' message and forward it back
|
||||
// as 'bar' message
|
||||
addMessageListener("foo", function (message) {
|
||||
sendAsyncMessage("bar", message);
|
||||
});
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for SpecialPowers extension</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var url = SimpleTest.getTestFileURL("SpecialPowersLoadChromeScript.js");
|
||||
var script = SpecialPowers.loadChromeScript(url);
|
||||
|
||||
var MESSAGE = { bar: true };
|
||||
script.addMessageListener("bar", function (message) {
|
||||
is(JSON.stringify(message), JSON.stringify(MESSAGE));
|
||||
script.destroy();
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
script.sendAsyncMessage("foo", MESSAGE);
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -59,6 +59,8 @@ SpecialPowersObserver.prototype = new SpecialPowersObserverAPI();
|
|||
this._messageManager.addMessageListener("SPPermissionManager", this);
|
||||
this._messageManager.addMessageListener("SPWebAppService", this);
|
||||
this._messageManager.addMessageListener("SPObserverService", this);
|
||||
this._messageManager.addMessageListener("SPLoadChromeScript", this);
|
||||
this._messageManager.addMessageListener("SPChromeScriptMessage", this);
|
||||
|
||||
this._messageManager.loadFrameScript(CHILD_LOGGER_SCRIPT, true);
|
||||
this._messageManager.loadFrameScript(CHILD_SCRIPT_API, true);
|
||||
|
|
|
@ -23,6 +23,7 @@ SpecialPowersException.prototype.toString = function() {
|
|||
this.SpecialPowersObserverAPI = function SpecialPowersObserverAPI() {
|
||||
this._crashDumpDir = null;
|
||||
this._processCrashObserversRegistered = false;
|
||||
this._chromeScriptListeners = [];
|
||||
}
|
||||
|
||||
function parseKeyValuePairs(text) {
|
||||
|
@ -288,6 +289,55 @@ SpecialPowersObserverAPI.prototype = {
|
|||
}
|
||||
break;
|
||||
|
||||
case "SPLoadChromeScript":
|
||||
var url = aMessage.json.url;
|
||||
var id = aMessage.json.id;
|
||||
|
||||
// Fetch script content as we can't use scriptloader's loadSubScript
|
||||
// to evaluate http:// urls...
|
||||
var scriptableStream = Cc["@mozilla.org/scriptableinputstream;1"]
|
||||
.getService(Ci.nsIScriptableInputStream);
|
||||
var channel = Services.io.newChannel(url, null, null);
|
||||
var input = channel.open();
|
||||
scriptableStream.init(input);
|
||||
var jsScript = scriptableStream.read(input.available());
|
||||
scriptableStream.close();
|
||||
input.close();
|
||||
|
||||
// Setup a chrome sandbox that has access to sendAsyncMessage
|
||||
// and addMessageListener in order to communicate with
|
||||
// the mochitest.
|
||||
var systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
|
||||
var sb = Components.utils.Sandbox(systemPrincipal);
|
||||
var mm = aMessage.target
|
||||
.QueryInterface(Ci.nsIFrameLoaderOwner)
|
||||
.frameLoader
|
||||
.messageManager;
|
||||
sb.sendAsyncMessage = (name, message) => {
|
||||
mm.sendAsyncMessage("SPChromeScriptMessage",
|
||||
{ id: id, name: name, message: message });
|
||||
};
|
||||
sb.addMessageListener = (name, listener) => {
|
||||
this._chromeScriptListeners.push({ id: id, name: name, listener: listener });
|
||||
};
|
||||
// Evaluate the chrome script
|
||||
try {
|
||||
Components.utils.evalInSandbox(jsScript, sb, "1.8", url, 1);
|
||||
} catch(e) {
|
||||
throw new SpecialPowersException("Error while executing chrome " +
|
||||
"script '" + url + "':\n" + e);
|
||||
}
|
||||
break;
|
||||
|
||||
case "SPChromeScriptMessage":
|
||||
var id = aMessage.json.id;
|
||||
var name = aMessage.json.name;
|
||||
var message = aMessage.json.message;
|
||||
this._chromeScriptListeners
|
||||
.filter(o => (o.name == name && o.id == id))
|
||||
.forEach(o => o.listener(message));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new SpecialPowersException("Unrecognized Special Powers API");
|
||||
}
|
||||
|
|
|
@ -40,6 +40,14 @@ SpecialPowers.prototype._sendAsyncMessage = function(msgname, msg) {
|
|||
sendAsyncMessage(msgname, msg);
|
||||
};
|
||||
|
||||
SpecialPowers.prototype._addMessageListener = function(msgname, listener) {
|
||||
addMessageListener(msgname, listener);
|
||||
};
|
||||
|
||||
SpecialPowers.prototype._removeMessageListener = function(msgname, listener) {
|
||||
removeMessageListener(msgname, listener);
|
||||
};
|
||||
|
||||
SpecialPowers.prototype.registerProcessCrashObservers = function() {
|
||||
addMessageListener("SPProcessCrashService", this._messageListener);
|
||||
sendSyncMessage("SPProcessCrashService", { op: "register-observer" });
|
||||
|
|
|
@ -494,6 +494,56 @@ SpecialPowersAPI.prototype = {
|
|||
return MockPermissionPrompt
|
||||
},
|
||||
|
||||
loadChromeScript: function (url) {
|
||||
// Create a unique id for this chrome script
|
||||
let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"]
|
||||
.getService(Ci.nsIUUIDGenerator);
|
||||
let id = uuidGenerator.generateUUID().toString();
|
||||
|
||||
// Tells chrome code to evaluate this chrome script
|
||||
this._sendSyncMessage("SPLoadChromeScript",
|
||||
{ url: url, id: id });
|
||||
|
||||
// Returns a MessageManager like API in order to be
|
||||
// able to communicate with this chrome script
|
||||
let listeners = [];
|
||||
let chromeScript = {
|
||||
addMessageListener: (name, listener) => {
|
||||
listeners.push({ name: name, listener: listener });
|
||||
},
|
||||
|
||||
removeMessageListener: (name, listener) => {
|
||||
listeners = listeners.filter(
|
||||
o => (o.name != name || o.listener != listener)
|
||||
);
|
||||
},
|
||||
|
||||
sendAsyncMessage: (name, message) => {
|
||||
this._sendSyncMessage("SPChromeScriptMessage",
|
||||
{ id: id, name: name, message: message });
|
||||
},
|
||||
|
||||
destroy: () => {
|
||||
listeners = [];
|
||||
this._removeMessageListener("SPChromeScriptMessage", chromeScript);
|
||||
},
|
||||
|
||||
receiveMessage: (aMessage) => {
|
||||
let messageId = aMessage.json.id;
|
||||
let name = aMessage.json.name;
|
||||
let message = aMessage.json.message;
|
||||
// Ignore message from other chrome script
|
||||
if (messageId != id)
|
||||
return;
|
||||
|
||||
listeners.filter(o => (o.name == name))
|
||||
.forEach(o => o.listener(this.wrap(message)));
|
||||
}
|
||||
};
|
||||
this._addMessageListener("SPChromeScriptMessage", chromeScript);
|
||||
return this.wrap(chromeScript);
|
||||
},
|
||||
|
||||
get Services() {
|
||||
return wrapPrivileged(Services);
|
||||
},
|
||||
|
|
Загрузка…
Ссылка в новой задаче