Bug 676274 - refactor specialpowers so we can use the api in mochitest-chrome without specialpowers. r=ted, a=test-only.

This commit is contained in:
Joel Maher 2011-10-06 10:51:03 -04:00
Родитель b5c9f7bcb5
Коммит 30e9deddd9
30 изменённых файлов: 961 добавлений и 612 удалений

Просмотреть файл

@ -1,7 +1,7 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=648573
https://bugzilla.mozilla.org/show_bug.cgi?id=648573
-->
<head>
<title>Test for Bug 648573</title>
@ -19,7 +19,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=648573
/** Test for Bug 648573 **/
ok(!SpecialPowers.DOMWindowUtils.mayHaveTouchEventListeners,
var utils = SpecialPowers.getDOMWindowUtils(window);
ok(!utils.mayHaveTouchEventListeners,
"There shouldn't be any touch event listeners yet.");
ok("createTouch" in document, "Should have createTouch function");
@ -101,7 +103,7 @@ for (var i = 0; i < events.length; ++i) {
runEventTest(events[i]);
}
ok(SpecialPowers.DOMWindowUtils.mayHaveTouchEventListeners,
ok(utils.mayHaveTouchEventListeners,
"There should be touch event listeners.");
</script>
</pre>

Просмотреть файл

@ -18,8 +18,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=662678
<script type="application/javascript">
/** Test for Bug 662678 **/
SimpleTest.waitForExplicitFinish();
var checkMotion = function(event) {
window.removeEventListener("devicemotion", checkMotion, true);
window.addEventListener("devicemotion", function(event) {
is(event.acceleration.x, 1.5);
is(event.acceleration.y, 1.5);
is(event.acceleration.z, 1.5);
@ -32,7 +35,9 @@ window.addEventListener("devicemotion", function(event) {
is(event.rotationRate.beta, 1.5);
is(event.rotationRate.gamma, 1.5);
SimpleTest.finish();
}, true);
};
window.addEventListener("devicemotion", checkMotion, true);
var event = DeviceMotionEvent;
ok(!!event, "Should have seen DeviceMotionEvent!");
@ -44,7 +49,6 @@ event.initDeviceMotionEvent('devicemotion', true, true,
{alpha:1.5,beta:1.5,gamma:1.5},
0);
window.dispatchEvent(event);
SimpleTest.waitForExplicitFinish();
</script>
</pre>

Просмотреть файл

@ -8,13 +8,19 @@
onload="setTimeout(nextTest,0);"
title="bug 293235 test">
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/specialpowersAPI.js"/>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SpecialPowersObserverAPI.js"/>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/ChromePowers.js"/>
<script type="application/javascript" src= "chrome://mochikit/content/chrome-harness.js" />
<script type="application/javascript" src="docshell_helpers.js" />
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>
<script type="application/javascript"><![CDATA[
const Ci = Components.interfaces;
const Cc = Components.classes;
var Ci = Components.interfaces;
var Cc = Components.classes;
Components.utils.import("resource://gre/modules/NetUtil.jsm");
// Define the generator-iterator for the tests.

Просмотреть файл

@ -8,6 +8,12 @@
onload="setTimeout(nextTest,0);"
title="bug 298622 test">
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/specialpowersAPI.js"/>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SpecialPowersObserverAPI.js"/>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/ChromePowers.js"/>
<script type="application/javascript" src= "chrome://mochikit/content/chrome-harness.js" />
<script type="application/javascript" src= "docshell_helpers.js" />
<script type="application/javascript"><![CDATA[

Просмотреть файл

@ -8,6 +8,12 @@
onload="setTimeout(nextTest,0);"
title="bug 301397 test">
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/specialpowersAPI.js"/>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SpecialPowersObserverAPI.js"/>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/ChromePowers.js"/>
<script type="application/javascript" src= "chrome://mochikit/content/chrome-harness.js" />
<script type="application/javascript" src="docshell_helpers.js" />
<script type="application/javascript"><![CDATA[

Просмотреть файл

@ -8,6 +8,12 @@
onload="setTimeout(nextTest,0);"
title="bug 321671 test">
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/specialpowersAPI.js"/>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SpecialPowersObserverAPI.js"/>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/ChromePowers.js"/>
<script type="application/javascript" src= "chrome://mochikit/content/chrome-harness.js" />
<script type="application/javascript" src="docshell_helpers.js" />
<script type="application/javascript"><![CDATA[

Просмотреть файл

@ -8,6 +8,12 @@
onload="setTimeout(nextTest,0);"
title="bug 396649 test">
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/specialpowersAPI.js"/>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SpecialPowersObserverAPI.js"/>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/ChromePowers.js"/>
<script type="application/javascript" src= "chrome://mochikit/content/chrome-harness.js" />
<script type="application/javascript" src="docshell_helpers.js" />
<script type="application/javascript"><![CDATA[

Просмотреть файл

@ -8,6 +8,12 @@
onload="nextTestAsync();"
title="bug 582176 test">
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/specialpowersAPI.js"/>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SpecialPowersObserverAPI.js"/>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/ChromePowers.js"/>
<script type="application/javascript" src= "chrome://mochikit/content/chrome-harness.js" />
<script type="application/javascript" src="docshell_helpers.js" />
<script type="application/javascript"><![CDATA[

Просмотреть файл

@ -9,6 +9,12 @@
title="bug 89419 test">
<script type="application/javascript" src= "chrome://mochikit/content/chrome-harness.js" />
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/specialpowersAPI.js"/>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SpecialPowersObserverAPI.js"/>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/ChromePowers.js"/>
<script type="application/javascript" src="docshell_helpers.js" />
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>

Просмотреть файл

@ -50,7 +50,7 @@
function testSteps() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
let uri = SpecialPowers.getDocumentURIObject(window.document);
let uri = window.parent.SpecialPowers.getDocumentURIObject(window.document);
Components.classes["@mozilla.org/permissionmanager;1"]
.getService(Components.interfaces.nsIPermissionManager)
.add(uri, "indexedDB",

Просмотреть файл

@ -89,7 +89,7 @@
function testSteps() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
let uri = SpecialPowers.getDocumentURIObject(window.document);
let uri = window.parent.SpecialPowers.getDocumentURIObject(window.document);
Components.classes["@mozilla.org/permissionmanager;1"]
.getService(Components.interfaces.nsIPermissionManager)
.add(uri, "indexedDB",

Просмотреть файл

@ -8,6 +8,12 @@
onload="setTimeout(nextTest,0);"
title="bug 514732 test">
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/specialpowersAPI.js"/>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SpecialPowersObserverAPI.js"/>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/ChromePowers.js"/>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/docshell_helpers.js">
</script>

Просмотреть файл

@ -4,7 +4,7 @@
<title>Test for pointer-events in HTML</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<style type="text/css">
div { height: 10px; width: 10px; background: black; }
@ -69,8 +69,9 @@ function synthesizeMouseEvent(type, // string
modifiers, // long
ignoreWindowBounds) // boolean
{
SpecialPowers.DOMWindowUtils.sendMouseEvent(type, x, y, button, clickCount,
modifiers, ignoreWindowBounds);
var utils = SpecialPowers.getDOMWindowUtils(window);
utils.sendMouseEvent(type, x, y, button, clickCount,
modifiers, ignoreWindowBounds);
}
function run_test()

Просмотреть файл

@ -95,7 +95,6 @@ _SERV_FILES = \
ipc.js \
browser-harness.xul \
redirect.html \
redirect.js \
$(topsrcdir)/build/pgo/server-locations.txt \
$(topsrcdir)/netwerk/test/httpserver/httpd.js \
mozprefs.js \

Просмотреть файл

@ -23,6 +23,7 @@
-
- Contributor(s):
- Gavin Sharp <gavin@gavinsharp.com> (original author)
- Joel Maher <joel.maher@gmail.com>
-
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or

Просмотреть файл

@ -12,16 +12,16 @@ window.addEventListener("load", testOnLoad, false);
function testOnLoad() {
window.removeEventListener("load", testOnLoad, false);
// Make sure to launch the test harness for the first opened window only
var prefs = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
if (prefs.prefHasUserValue("testing.browserTestHarness.running"))
return;
prefs.setBoolPref("testing.browserTestHarness.running", true);
gConfig = readConfig();
if (gConfig.testRoot == "browser") {
// Make sure to launch the test harness for the first opened window only
var prefs = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
if (prefs.prefHasUserValue("testing.browserTestHarness.running"))
return;
prefs.setBoolPref("testing.browserTestHarness.running", true);
var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
getService(Ci.nsIWindowWatcher);
var sstring = Cc["@mozilla.org/supports-string;1"].
@ -30,6 +30,22 @@ function testOnLoad() {
ww.openWindow(window, "chrome://mochikit/content/browser-harness.xul", "browserTest",
"chrome,centerscreen,dialog=no,resizable,titlebar,toolbar=no,width=800,height=600", sstring);
} else {
// This code allows us to redirect without requiring specialpowers for chrome and a11y tests.
function messageHandler(m) {
messageManager.removeMessageListener("chromeEvent", messageHandler);
var url = m.json.data;
// Window is the [ChromeWindow] for messageManager, so we need content.window
// Currently chrome tests are run in a content window instead of a ChromeWindow
var webNav = content.window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation);
webNav.loadURI(url, null, null, null, null);
}
var listener = 'data:,function doLoad(e) { var data=e.getData("data");removeEventListener("contentEvent", function (e) { doLoad(e); }, false, true);sendAsyncMessage("chromeEvent", {"data":data}); };addEventListener("contentEvent", function (e) { doLoad(e); }, false, true);';
messageManager.loadFrameScript(listener, true);
messageManager.addMessageListener("chromeEvent", messageHandler);
}
}
@ -48,6 +64,9 @@ function Tester(aTests, aDumper, aCallback) {
getService(Ci.mozIJSSubScriptLoader);
this._scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/EventUtils.js", this.EventUtils);
var simpleTestScope = {};
this._scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/specialpowersAPI.js", simpleTestScope);
this._scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/SpecialPowersObserverAPI.js", simpleTestScope);
this._scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/ChromePowers.js", simpleTestScope);
this._scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/SimpleTest.js", simpleTestScope);
this._scriptLoader.loadSubScript("chrome://mochikit/content/chrome-harness.js", simpleTestScope);
this.SimpleTest = simpleTestScope.SimpleTest;

Просмотреть файл

@ -11,6 +11,12 @@
<window>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/LogController.js"/>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/specialpowersAPI.js"/>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SpecialPowersObserverAPI.js"/>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/ChromePowers.js"/>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/TestRunner.js"/>
<script type="text/javascript"

Просмотреть файл

@ -10,10 +10,12 @@ mochikit.jar:
content/ipc-overlay.xul (ipc-overlay.xul)
content/mozprefs.js (mozprefs.js)
content/redirect.html (redirect.html)
content/redirect.js (redirect.js)
content/server.js (server.js)
content/dynamic/getMyDirectory.sjs (dynamic/getMyDirectory.sjs)
content/static/harness.css (static/harness.css)
content/tests/SimpleTest/ChromePowers.js (tests/SimpleTest/ChromePowers.js)
content/tests/SimpleTest/specialpowersAPI.js (tests/SimpleTest/specialpowersAPI.js)
content/tests/SimpleTest/SpecialPowersObserverAPI.js (tests/SimpleTest/SpecialPowersObserverAPI.js)
content/tests/SimpleTest/EventUtils.js (tests/SimpleTest/EventUtils.js)
content/tests/SimpleTest/ChromeUtils.js (tests/SimpleTest/ChromeUtils.js)
content/tests/SimpleTest/MozillaLogger.js (tests/SimpleTest/MozillaLogger.js)

Просмотреть файл

@ -2,9 +2,18 @@
<head>
<title>redirecting...</title>
<script type="text/javascript" src="redirect.js"></script>
<script type="text/javascript">
function redirect(aURL)
{
// We create a listener for this event in browser-test.js
// which will get picked up when specifying --chrome or --a11y
var element = document.createEvent("datacontainerevent");
element.initEvent("contentEvent", true, false);
element.setData("data", aURL + location.search);
element.setData("type", "loadURI");
document.dispatchEvent(element);
}
redirect("chrome://mochikit/content/harness.xul");
</script>
</head>

Просмотреть файл

@ -1,45 +0,0 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is MozJSHTTP code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Robert Sayre <sayrer@gmail.com>
* Alexander Surkov <surkov.alexander@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
function redirect(aURL)
{
SpecialPowers.loadURI(window, aURL + location.search,
null, null, null, null);
}

Просмотреть файл

@ -529,7 +529,6 @@ class Mochitest(object):
self.automation.initializeProfile(options.profilePath, options.extraPrefs, useServerLocations = True)
manifest = self.addChromeToProfile(options)
self.copyExtraFilesToProfile(options)
self.installSpecialPowersExtension(options)
self.installExtensionsToProfile(options)
return manifest

Просмотреть файл

@ -50,19 +50,15 @@ const Cc = Components.classes;
const Ci = Components.interfaces;
const CHILD_SCRIPT = "chrome://specialpowers/content/specialpowers.js"
const CHILD_SCRIPT_API = "chrome://specialpowers/content/specialpowersAPI.js"
const CHILD_LOGGER_SCRIPT = "chrome://specialpowers/content/MozillaLogger.js"
/**
* Special Powers Exception - used to throw exceptions nicely
**/
function SpecialPowersException(aMsg) {
this.message = aMsg;
this.name = "SpecialPowersException";
}
SpecialPowersException.prototype.toString = function() {
return this.name + ': "' + this.message + '"';
};
// Glue to add in the observer API to this object. This allows us to share code with chrome tests
var loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Components.interfaces.mozIJSSubScriptLoader);
loader.loadSubScript("chrome://specialpowers/content/SpecialPowersObserverAPI.js");
/* XPCOM gunk */
function SpecialPowersObserver() {
@ -71,14 +67,16 @@ function SpecialPowersObserver() {
getService(Ci.nsIChromeFrameMessageManager);
}
SpecialPowersObserver.prototype = {
classDescription: "Special powers Observer for use in testing.",
classID: Components.ID("{59a52458-13e0-4d93-9d85-a637344f29a1}"),
contractID: "@mozilla.org/special-powers-observer;1",
QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIObserver]),
_xpcom_categories: [{category: "profile-after-change", service: true }],
observe: function(aSubject, aTopic, aData)
SpecialPowersObserver.prototype = new SpecialPowersObserverAPI();
SpecialPowersObserver.prototype.classDescription = "Special powers Observer for use in testing.";
SpecialPowersObserver.prototype.classID = Components.ID("{59a52458-13e0-4d93-9d85-a637344f29a1}");
SpecialPowersObserver.prototype.contractID = "@mozilla.org/special-powers-observer;1";
SpecialPowersObserver.prototype.QueryInterface = XPCOMUtils.generateQI([Components.interfaces.nsIObserver]);
SpecialPowersObserver.prototype._xpcom_categories = [{category: "profile-after-change", service: true }];
SpecialPowersObserver.prototype.observe = function(aSubject, aTopic, aData)
{
switch (aTopic) {
case "profile-after-change":
@ -93,6 +91,7 @@ SpecialPowersObserver.prototype = {
this._messageManager.addMessageListener("SPPingService", this);
this._messageManager.loadFrameScript(CHILD_LOGGER_SCRIPT, true);
this._messageManager.loadFrameScript(CHILD_SCRIPT_API, true);
this._messageManager.loadFrameScript(CHILD_SCRIPT, true);
this._isFrameScriptLoaded = true;
}
@ -102,180 +101,67 @@ SpecialPowersObserver.prototype = {
this.uninit();
break;
case "plugin-crashed":
case "ipc:content-shutdown":
function addDumpIDToMessage(propertyName) {
var id = aSubject.getPropertyAsAString(propertyName);
if (id) {
message.dumpIDs.push(id);
}
}
var message = { type: "crash-observed", dumpIDs: [] };
aSubject = aSubject.QueryInterface(Ci.nsIPropertyBag2);
if (aTopic == "plugin-crashed") {
addDumpIDToMessage("pluginDumpID");
addDumpIDToMessage("browserDumpID");
} else { // ipc:content-shutdown
addDumpIDToMessage("dumpID");
}
this._messageManager.sendAsyncMessage("SPProcessCrashService", message);
default:
this._observe(aSubject, aTopic, aData);
break;
}
},
};
init: function()
SpecialPowersObserver.prototype._sendAsyncMessage = function(msgname, msg)
{
this._messageManager.sendAsyncMessage(msgname, msg);
};
SpecialPowersObserver.prototype._receiveMessage = function(aMessage) {
return this._receiveMessageAPI(aMessage);
};
SpecialPowersObserver.prototype.init = function()
{
var obs = Services.obs;
obs.addObserver(this, "xpcom-shutdown", false);
obs.addObserver(this, "chrome-document-global-created", false);
},
};
uninit: function()
SpecialPowersObserver.prototype.uninit = function()
{
var obs = Services.obs;
obs.removeObserver(this, "chrome-document-global-created", false);
this.removeProcessCrashObservers();
},
addProcessCrashObservers: function() {
this._removeProcessCrashObservers();
};
SpecialPowersObserver.prototype._addProcessCrashObservers = function() {
if (this._processCrashObserversRegistered) {
return;
}
Services.obs.addObserver(this, "plugin-crashed", false);
Services.obs.addObserver(this, "ipc:content-shutdown", false);
this._processCrashObserversRegistered = true;
},
var obs = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
removeProcessCrashObservers: function() {
obs.addObserver(this, "plugin-crashed", false);
obs.addObserver(this, "ipc:content-shutdown", false);
this._processCrashObserversRegistered = true;
};
SpecialPowersObserver.prototype._removeProcessCrashObservers = function() {
if (!this._processCrashObserversRegistered) {
return;
}
Services.obs.removeObserver(this, "plugin-crashed");
Services.obs.removeObserver(this, "ipc:content-shutdown");
var obs = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
obs.removeObserver(this, "plugin-crashed");
obs.removeObserver(this, "ipc:content-shutdown");
this._processCrashObserversRegistered = false;
},
getCrashDumpDir: function() {
if (!this._crashDumpDir) {
var directoryService = Cc["@mozilla.org/file/directory_service;1"]
.getService(Ci.nsIProperties);
this._crashDumpDir = directoryService.get("ProfD", Ci.nsIFile);
this._crashDumpDir.append("minidumps");
}
return this._crashDumpDir;
},
deleteCrashDumpFiles: function(aFilenames) {
var crashDumpDir = this.getCrashDumpDir();
if (!crashDumpDir.exists()) {
return false;
}
var success = aFilenames.length != 0;
aFilenames.forEach(function(crashFilename) {
var file = crashDumpDir.clone();
file.append(crashFilename);
if (file.exists()) {
file.remove(false);
} else {
success = false;
}
});
return success;
},
findCrashDumpFiles: function(aToIgnore) {
var crashDumpDir = this.getCrashDumpDir();
var entries = crashDumpDir.exists() && crashDumpDir.directoryEntries;
if (!entries) {
return [];
}
var crashDumpFiles = [];
while (entries.hasMoreElements()) {
var file = entries.getNext().QueryInterface(Ci.nsIFile);
var path = String(file.path);
if (path.match(/\.(dmp|extra)$/) && !aToIgnore[path]) {
crashDumpFiles.push(path);
}
}
return crashDumpFiles.concat();
},
};
/**
* messageManager callback function
* This will get requests from our API in the window and process them in chrome for it
**/
receiveMessage: function(aMessage) {
SpecialPowersObserver.prototype.receiveMessage = function(aMessage) {
switch(aMessage.name) {
case "SPPrefService":
var prefs = Services.prefs;
var prefType = aMessage.json.prefType.toUpperCase();
var prefName = aMessage.json.prefName;
var prefValue = "prefValue" in aMessage.json ? aMessage.json.prefValue : null;
if (aMessage.json.op == "get") {
if (!prefName || !prefType)
throw new SpecialPowersException("Invalid parameters for get in SPPrefService");
} else if (aMessage.json.op == "set") {
if (!prefName || !prefType || prefValue === null)
throw new SpecialPowersException("Invalid parameters for set in SPPrefService");
} else if (aMessage.json.op == "clear") {
if (!prefName)
throw new SpecialPowersException("Invalid parameters for clear in SPPrefService");
} else {
throw new SpecialPowersException("Invalid operation for SPPrefService");
}
// Now we make the call
switch(prefType) {
case "BOOL":
if (aMessage.json.op == "get")
return(prefs.getBoolPref(prefName));
else
return(prefs.setBoolPref(prefName, prefValue));
case "INT":
if (aMessage.json.op == "get")
return(prefs.getIntPref(prefName));
else
return(prefs.setIntPref(prefName, prefValue));
case "CHAR":
if (aMessage.json.op == "get")
return(prefs.getCharPref(prefName));
else
return(prefs.setCharPref(prefName, prefValue));
case "COMPLEX":
if (aMessage.json.op == "get")
return(prefs.getComplexValue(prefName, prefValue[0]));
else
return(prefs.setComplexValue(prefName, prefValue[0], prefValue[1]));
case "":
if (aMessage.json.op == "clear") {
prefs.clearUserPref(prefName);
return;
}
}
break;
case "SPProcessCrashService":
switch (aMessage.json.op) {
case "register-observer":
this.addProcessCrashObservers();
break;
case "unregister-observer":
this.removeProcessCrashObservers();
break;
case "delete-crash-dump-files":
return this.deleteCrashDumpFiles(aMessage.json.filenames);
case "find-crash-dump-files":
return this.findCrashDumpFiles(aMessage.json.crashDumpFilesToIgnore);
default:
throw new SpecialPowersException("Invalid operation for SPProcessCrashService");
}
break;
case "SPPingService":
if (aMessage.json.op == "ping") {
aMessage.target
@ -285,11 +171,9 @@ SpecialPowersObserver.prototype = {
.sendAsyncMessage("SPPingService", { op: "pong" });
}
break;
default:
throw new SpecialPowersException("Unrecognized Special Powers API");
return this._receiveMessage(aMessage);
}
}
};
};
const NSGetFactory = XPCOMUtils.generateNSGetFactory([SpecialPowersObserver]);

Просмотреть файл

@ -38,399 +38,80 @@
* order to be used as a replacement for UniversalXPConnect
*/
var Ci = Components.interfaces;
var Cc = Components.classes;
function SpecialPowers(window) {
this.window = window;
bindDOMWindowUtils(this, window);
this._encounteredCrashDumpFiles = [];
this._unexpectedCrashDumpFiles = { };
this._crashDumpDir = null;
this.DOMWindowUtils = bindDOMWindowUtils(window);
this._pongHandlers = [];
this._messageListener = this._messageReceived.bind(this);
addMessageListener("SPPingService", this._messageListener);
this._consoleListeners = [];
}
function bindDOMWindowUtils(sp, window) {
var util = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
// This bit of magic brought to you by the letters
// B Z, and E, S and the number 5.
//
// Take all of the properties on the nsIDOMWindowUtils-implementing
// object, and rebind them onto a new object with a stub that uses
// apply to call them from this privileged scope. This way we don't
// have to explicitly stub out new methods that appear on
// nsIDOMWindowUtils.
var proto = Object.getPrototypeOf(util);
var target = {};
function rebind(desc, prop) {
if (prop in desc && typeof(desc[prop]) == "function") {
var oldval = desc[prop];
try {
desc[prop] = function() { return oldval.apply(util, arguments); };
} catch (ex) {
dump("WARNING: Special Powers failed to rebind function: " + desc + "::" + prop + "\n");
SpecialPowers.prototype = new SpecialPowersAPI();
SpecialPowers.prototype.toString = function() { return "[SpecialPowers]"; };
SpecialPowers.prototype.sanityCheck = function() { return "foo"; };
// This gets filled in in the constructor.
SpecialPowers.prototype.DOMWindowUtils = undefined;
SpecialPowers.prototype._sendSyncMessage = function(msgname, msg) {
return sendSyncMessage(msgname, msg);
};
SpecialPowers.prototype._sendAsyncMessage = function(msgname, msg) {
sendAsyncMessage(msgname, msg);
};
SpecialPowers.prototype.registerProcessCrashObservers = function() {
addMessageListener("SPProcessCrashService", this._messageListener);
sendSyncMessage("SPProcessCrashService", { op: "register-observer" });
};
SpecialPowers.prototype.unregisterProcessCrashObservers = function() {
addMessageListener("SPProcessCrashService", this._messageListener);
sendSyncMessage("SPProcessCrashService", { op: "unregister-observer" });
};
SpecialPowers.prototype._messageReceived = function(aMessage) {
switch (aMessage.name) {
case "SPProcessCrashService":
if (aMessage.json.type == "crash-observed") {
var self = this;
aMessage.json.dumpIDs.forEach(function(id) {
self._encounteredCrashDumpFiles.push(id + ".dmp");
self._encounteredCrashDumpFiles.push(id + ".extra");
});
}
}
}
for (var i in proto) {
var desc = Object.getOwnPropertyDescriptor(proto, i);
rebind(desc, "get");
rebind(desc, "set");
rebind(desc, "value");
Object.defineProperty(target, i, desc);
}
sp.DOMWindowUtils = target;
}
break;
SpecialPowers.prototype = {
toString: function() { return "[SpecialPowers]"; },
sanityCheck: function() { return "foo"; },
// This gets filled in in the constructor.
DOMWindowUtils: undefined,
// Mimic the get*Pref API
getBoolPref: function(aPrefName) {
return (this._getPref(aPrefName, 'BOOL'));
},
getIntPref: function(aPrefName) {
return (this._getPref(aPrefName, 'INT'));
},
getCharPref: function(aPrefName) {
return (this._getPref(aPrefName, 'CHAR'));
},
getComplexValue: function(aPrefName, aIid) {
return (this._getPref(aPrefName, 'COMPLEX', aIid));
},
// Mimic the set*Pref API
setBoolPref: function(aPrefName, aValue) {
return (this._setPref(aPrefName, 'BOOL', aValue));
},
setIntPref: function(aPrefName, aValue) {
return (this._setPref(aPrefName, 'INT', aValue));
},
setCharPref: function(aPrefName, aValue) {
return (this._setPref(aPrefName, 'CHAR', aValue));
},
setComplexValue: function(aPrefName, aIid, aValue) {
return (this._setPref(aPrefName, 'COMPLEX', aValue, aIid));
},
// Mimic the clearUserPref API
clearUserPref: function(aPrefName) {
var msg = {'op':'clear', 'prefName': aPrefName, 'prefType': ""};
sendSyncMessage('SPPrefService', msg);
},
// Private pref functions to communicate to chrome
_getPref: function(aPrefName, aPrefType, aIid) {
var msg = {};
if (aIid) {
// Overloading prefValue to handle complex prefs
msg = {'op':'get', 'prefName': aPrefName, 'prefType':aPrefType, 'prefValue':[aIid]};
} else {
msg = {'op':'get', 'prefName': aPrefName,'prefType': aPrefType};
}
var val = sendSyncMessage('SPPrefService', msg);
if (val == null || val[0] == null)
throw "Error getting pref";
return val[0];
},
_setPref: function(aPrefName, aPrefType, aValue, aIid) {
var msg = {};
if (aIid) {
msg = {'op':'set','prefName':aPrefName, 'prefType': aPrefType, 'prefValue': [aIid,aValue]};
} else {
msg = {'op':'set', 'prefName': aPrefName, 'prefType': aPrefType, 'prefValue': aValue};
}
return(sendSyncMessage('SPPrefService', msg)[0]);
},
//XXX: these APIs really ought to be removed, they're not e10s-safe.
// (also they're pretty Firefox-specific)
_getTopChromeWindow: function(window) {
return window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow)
.QueryInterface(Ci.nsIDOMChromeWindow);
},
_getDocShell: function(window) {
return window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
},
_getMUDV: function(window) {
return this._getDocShell(window).contentViewer
.QueryInterface(Ci.nsIMarkupDocumentViewer);
},
_getAutoCompletePopup: function(window) {
return this._getTopChromeWindow(window).document
.getElementById("PopupAutoComplete");
},
addAutoCompletePopupEventListener: function(window, listener) {
this._getAutoCompletePopup(window).addEventListener("popupshowing",
listener,
false);
},
removeAutoCompletePopupEventListener: function(window, listener) {
this._getAutoCompletePopup(window).removeEventListener("popupshowing",
listener,
false);
},
isBackButtonEnabled: function(window) {
return !this._getTopChromeWindow(window).document
.getElementById("Browser:Back")
.hasAttribute("disabled");
},
addChromeEventListener: function(type, listener, capture, allowUntrusted) {
addEventListener(type, listener, capture, allowUntrusted);
},
removeChromeEventListener: function(type, listener, capture) {
removeEventListener(type, listener, capture);
},
addErrorConsoleListener: function(listener) {
var consoleListener = {
userListener: listener,
observe: function(consoleMessage) {
this.userListener(consoleMessage.message);
}
};
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService)
.registerListener(consoleListener);
this._consoleListeners.push(consoleListener);
},
removeErrorConsoleListener: function(listener) {
for (var index in this._consoleListeners) {
var consoleListener = this._consoleListeners[index];
if (consoleListener.userListener == listener) {
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService)
.unregisterListener(consoleListener);
this._consoleListeners = this._consoleListeners.splice(index, 1);
break;
}
}
},
getFullZoom: function(window) {
return this._getMUDV(window).fullZoom;
},
setFullZoom: function(window, zoom) {
this._getMUDV(window).fullZoom = zoom;
},
getTextZoom: function(window) {
return this._getMUDV(window).textZoom;
},
setTextZoom: function(window, zoom) {
this._getMUDV(window).textZoom = zoom;
},
createSystemXHR: function() {
return Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(Ci.nsIXMLHttpRequest);
},
loadURI: function(window, uri, referrer, charset, x, y) {
var webNav = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation);
webNav.loadURI(uri, referrer, charset, x, y);
},
snapshotWindow: function (win, withCaret) {
var el = this.window.document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
el.width = win.innerWidth;
el.height = win.innerHeight;
var ctx = el.getContext("2d");
ctx.drawWindow(win, win.scrollX, win.scrollY,
win.innerWidth, win.innerHeight,
"rgb(255,255,255)",
withCaret ? ctx.DRAWWINDOW_DRAW_CARET : 0);
return el;
},
gc: function() {
this.DOMWindowUtils.garbageCollect();
},
forceGC: function() {
Components.utils.forceGC();
},
hasContentProcesses: function() {
try {
var rt = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
return rt.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
} catch (e) {
return true;
}
},
_xpcomabi: null,
get XPCOMABI() {
if (this._xpcomabi != null)
return this._xpcomabi;
var xulRuntime = Cc["@mozilla.org/xre/app-info;1"]
.getService(Components.interfaces.nsIXULAppInfo)
.QueryInterface(Components.interfaces.nsIXULRuntime);
this._xpcomabi = xulRuntime.XPCOMABI;
return this._xpcomabi;
},
_os: null,
get OS() {
if (this._os != null)
return this._os;
var xulRuntime = Cc["@mozilla.org/xre/app-info;1"]
.getService(Components.interfaces.nsIXULAppInfo)
.QueryInterface(Components.interfaces.nsIXULRuntime);
this._os = xulRuntime.OS;
return this._os;
},
registerProcessCrashObservers: function() {
addMessageListener("SPProcessCrashService", this._messageListener);
sendSyncMessage("SPProcessCrashService", { op: "register-observer" });
},
_messageReceived: function(aMessage) {
switch (aMessage.name) {
case "SPProcessCrashService":
if (aMessage.json.type == "crash-observed") {
var self = this;
aMessage.json.dumpIDs.forEach(function(id) {
self._encounteredCrashDumpFiles.push(id + ".dmp");
self._encounteredCrashDumpFiles.push(id + ".extra");
});
case "SPPingService":
if (aMessage.json.op == "pong") {
var handler = this._pongHandlers.shift();
if (handler) {
handler();
}
break;
case "SPPingService":
if (aMessage.json.op == "pong") {
var handler = this._pongHandlers.shift();
if (handler) {
handler();
}
}
break;
}
return true;
},
removeExpectedCrashDumpFiles: function(aExpectingProcessCrash) {
var success = true;
if (aExpectingProcessCrash) {
var message = {
op: "delete-crash-dump-files",
filenames: this._encounteredCrashDumpFiles
};
if (!sendSyncMessage("SPProcessCrashService", message)[0]) {
success = false;
}
}
this._encounteredCrashDumpFiles.length = 0;
return success;
},
break;
}
return true;
};
findUnexpectedCrashDumpFiles: function() {
var self = this;
var message = {
op: "find-crash-dump-files",
crashDumpFilesToIgnore: this._unexpectedCrashDumpFiles
};
var crashDumpFiles = sendSyncMessage("SPProcessCrashService", message)[0];
crashDumpFiles.forEach(function(aFilename) {
self._unexpectedCrashDumpFiles[aFilename] = true;
});
return crashDumpFiles;
},
executeAfterFlushingMessageQueue: function(aCallback) {
this._pongHandlers.push(aCallback);
sendAsyncMessage("SPPingService", { op: "ping" });
},
executeSoon: function(aFunc) {
var tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
tm.mainThread.dispatch({
run: function() {
aFunc();
}
}, Ci.nsIThread.DISPATCH_NORMAL);
},
addSystemEventListener: function(target, type, listener, useCapture) {
Cc["@mozilla.org/eventlistenerservice;1"].
getService(Ci.nsIEventListenerService).
addSystemEventListener(target, type, listener, useCapture);
},
removeSystemEventListener: function(target, type, listener, useCapture) {
Cc["@mozilla.org/eventlistenerservice;1"].
getService(Ci.nsIEventListenerService).
removeSystemEventListener(target, type, listener, useCapture);
},
setLogFile: function(path) {
this._mfl = new MozillaFileLogger(path);
},
log: function(data) {
this._mfl.log(data);
},
closeLogFile: function() {
this._mfl.close();
},
addCategoryEntry: function(category, entry, value, persists, replace) {
Cc["@mozilla.org/categorymanager;1"].
getService(Components.interfaces.nsICategoryManager).
addCategoryEntry(category, entry, value, persists, replace);
},
getNodePrincipal: function(aNode) {
return aNode.nodePrincipal;
},
getNodeBaseURIObject: function(aNode) {
return aNode.baseURIObject;
},
getDocumentURIObject: function(aDocument) {
return aDocument.documentURIObject;
},
copyString: function(str) {
Cc["@mozilla.org/widget/clipboardhelper;1"].
getService(Ci.nsIClipboardHelper).
copyString(str);
},
SpecialPowers.prototype.executeAfterFlushingMessageQueue = function(aCallback) {
this._pongHandlers.push(aCallback);
sendAsyncMessage("SPPingService", { op: "ping" });
};
// Expose everything but internal APIs (starting with underscores) to
// web content.
// web content. We cannot use Object.keys to view SpecialPowers.prototype since
// we are using the functions from SpecialPowersAPI.prototype
SpecialPowers.prototype.__exposedProps__ = {};
for each (i in Object.keys(SpecialPowers.prototype).filter(function(v) {return v.charAt(0) != "_";})) {
SpecialPowers.prototype.__exposedProps__[i] = "r";
for (var i in SpecialPowers.prototype) {
if (i.charAt(0) != "_")
SpecialPowers.prototype.__exposedProps__[i] = "r";
}
// Attach our API to the window.
@ -439,7 +120,16 @@ function attachSpecialPowersToWindow(aWindow) {
if ((aWindow !== null) &&
(aWindow !== undefined) &&
(aWindow.wrappedJSObject) &&
(aWindow.parent !== null) &&
(aWindow.parent !== undefined) &&
(aWindow.parent.wrappedJSObject.SpecialPowers) &&
!(aWindow.wrappedJSObject.SpecialPowers)) {
aWindow.wrappedJSObject.SpecialPowers = aWindow.parent.SpecialPowers;
}
else if ((aWindow !== null) &&
(aWindow !== undefined) &&
(aWindow.wrappedJSObject) &&
!(aWindow.wrappedJSObject.SpecialPowers)) {
aWindow.wrappedJSObject.SpecialPowers = new SpecialPowers(aWindow);
}
} catch(ex) {

Просмотреть файл

@ -1,4 +1,6 @@
specialpowers.jar:
% content specialpowers %content/
content/specialpowers.js (content/specialpowers.js)
content/specialpowersAPI.js (../tests/SimpleTest/specialpowersAPI.js)
content/SpecialPowersObserverAPI.js (../tests/SimpleTest/SpecialPowersObserverAPI.js)
content/MozillaLogger.js (../tests/SimpleTest/MozillaLogger.js)

Просмотреть файл

@ -0,0 +1,120 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Special Powers code.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Joel Maher <joel.maher@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
function ChromePowers(window) {
this.window = window;
// In the case of browser-chrome tests, we are running as a [ChromeWindow]
// and we have no window.QueryInterface available, content.window is what we need
if (typeof(window) == "ChromeWindow" && typeof(content.window) == "Window") {
this.DOMWindowUtils = bindDOMWindowUtils(content.window);
this.window = content.window
} else {
this.DOMWindowUtils = bindDOMWindowUtils(window);
}
this.spObserver = new SpecialPowersObserverAPI();
}
ChromePowers.prototype = new SpecialPowersAPI();
ChromePowers.prototype.toString = function() { return "[ChromePowers]"; };
ChromePowers.prototype.sanityCheck = function() { return "foo"; };
// This gets filled in in the constructor.
ChromePowers.prototype.DOMWindowUtils = undefined;
ChromePowers.prototype._sendSyncMessage = function(type, msg) {
var aMessage = {'name':type, 'json': msg};
return [this._receiveMessage(aMessage)];
};
ChromePowers.prototype._sendAsyncMessage = function(type, msg) {
var aMessage = {'name':type, 'json': msg};
this._receiveMessage(aMessage);
};
ChromePowers.prototype.registerProcessCrashObservers = function() {
this._sendSyncMessage("SPProcessCrashService", { op: "register-observer" });
};
ChromePowers.prototype.unregisterProcessCrashObservers = function() {
this._sendSyncMessage("SPProcessCrashService", { op: "unregister-observer" });
};
ChromePowers.prototype._receiveMessage = function(aMessage) {
switch (aMessage.name) {
case "SPProcessCrashService":
if (aMessage.json.op == "register-observer" || aMessage.json.op == "unregister-observer") {
// Hack out register/unregister specifically for browser-chrome leaks
break;
} else if (aMessage.type == "crash-observed") {
var self = this;
msg.dumpIDs.forEach(function(id) {
self._encounteredCrashDumpFiles.push(id + ".dmp");
self._encounteredCrashDumpFiles.push(id + ".extra");
});
}
default:
// All calls go here, because we need to handle SPProcessCrashService calls as well
return this.spObserver._receiveMessageAPI(aMessage);
break;
}
};
ChromePowers.prototype.executeAfterFlushingMessageQueue = function(aCallback) {
aCallback();
};
// Expose everything but internal APIs (starting with underscores) to
// web content. We cannot use Object.keys to view SpecialPowers.prototype since
// we are using the functions from SpecialPowersAPI.prototype
ChromePowers.prototype.__exposedProps__ = {};
for (var i in ChromePowers.prototype) {
if (i.charAt(0) != "_")
ChromePowers.prototype.__exposedProps__[i] = "r";
}
if ((window.parent !== null) &&
(window.parent !== undefined) &&
(window.parent.wrappedJSObject.SpecialPowers) &&
!(window.wrappedJSObject.SpecialPowers)) {
window.wrappedJSObject.SpecialPowers = window.parent.SpecialPowers;
} else {
window.wrappedJSObject.SpecialPowers = new ChromePowers(window);
}

Просмотреть файл

@ -53,6 +53,8 @@ _SIMPLETEST_FILES = MozillaLogger.js \
ChromeUtils.js \
WindowSnapshot.js \
PluginUtils.js \
specialpowersAPI.js \
SpecialPowersObserverAPI.js \
$(DEPTH)/toolkit/content/tests/browser/common/mockObjects.js \
$(DEPTH)/docshell/test/chrome/docshell_helpers.js \
$(NULL)

Просмотреть файл

@ -22,6 +22,11 @@ if (parent) {
if (!parentRunner && parent.wrappedJSObject) {
parentRunner = parent.wrappedJSObject.TestRunner;
}
// This is the case where we have ChromePowers in harness.xul and we need it in the iframe
if (window.SpecialPowers == undefined && parent.SpecialPowers !== undefined) {
window.SpecialPowers = parent.SpecialPowers;
}
}
// running in e10s build and need to use IPC?

Просмотреть файл

@ -0,0 +1,208 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Special Powers code
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Jesse Ruderman <jruderman@mozilla.com>
* Robert Sayre <sayrer@gmail.com>
* Joel Maher <joel.maher@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK *****/
/**
* Special Powers Exception - used to throw exceptions nicely
**/
function SpecialPowersException(aMsg) {
this.message = aMsg;
this.name = "SpecialPowersException";
}
SpecialPowersException.prototype.toString = function() {
return this.name + ': "' + this.message + '"';
};
function SpecialPowersObserverAPI() {
this._crashDumpDir = null;
this._processCrashObserversRegistered = false;
}
SpecialPowersObserverAPI.prototype = {
_observe: function(aSubject, aTopic, aData) {
switch(aTopic) {
case "plugin-crashed":
case "ipc:content-shutdown":
function addDumpIDToMessage(propertyName) {
var id = aSubject.getPropertyAsAString(propertyName);
if (id) {
message.dumpIDs.push(id);
}
}
var message = { type: "crash-observed", dumpIDs: [] };
aSubject = aSubject.QueryInterface(Components.interfaces.nsIPropertyBag2);
if (aTopic == "plugin-crashed") {
addDumpIDToMessage("pluginDumpID");
addDumpIDToMessage("browserDumpID");
} else { // ipc:content-shutdown
addDumpIDToMessage("dumpID");
}
this._sendAsyncMessage("SPProcessCrashService", message);
break;
}
},
_getCrashDumpDir: function() {
if (!this._crashDumpDir) {
var directoryService = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties);
this._crashDumpDir = directoryService.get("ProfD", Components.interfaces.nsIFile);
this._crashDumpDir.append("minidumps");
}
return this._crashDumpDir;
},
_deleteCrashDumpFiles: function(aFilenames) {
var crashDumpDir = this._getCrashDumpDir();
if (!crashDumpDir.exists()) {
return false;
}
var success = aFilenames.length != 0;
aFilenames.forEach(function(crashFilename) {
var file = crashDumpDir.clone();
file.append(crashFilename);
if (file.exists()) {
file.remove(false);
} else {
success = false;
}
});
return success;
},
_findCrashDumpFiles: function(aToIgnore) {
var crashDumpDir = this._getCrashDumpDir();
var entries = crashDumpDir.exists() && crashDumpDir.directoryEntries;
if (!entries) {
return [];
}
var crashDumpFiles = [];
while (entries.hasMoreElements()) {
var file = entries.getNext().QueryInterface(Components.interfaces.nsIFile);
var path = String(file.path);
if (path.match(/\.(dmp|extra)$/) && !aToIgnore[path]) {
crashDumpFiles.push(path);
}
}
return crashDumpFiles.concat();
},
/**
* messageManager callback function
* This will get requests from our API in the window and process them in chrome for it
**/
_receiveMessageAPI: function(aMessage) {
switch(aMessage.name) {
case "SPPrefService":
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefBranch2);
var prefType = aMessage.json.prefType.toUpperCase();
var prefName = aMessage.json.prefName;
var prefValue = "prefValue" in aMessage.json ? aMessage.json.prefValue : null;
if (aMessage.json.op == "get") {
if (!prefName || !prefType)
throw new SpecialPowersException("Invalid parameters for get in SPPrefService");
} else if (aMessage.json.op == "set") {
if (!prefName || !prefType || prefValue === null)
throw new SpecialPowersException("Invalid parameters for set in SPPrefService");
} else if (aMessage.json.op == "clear") {
if (!prefName)
throw new SpecialPowersException("Invalid parameters for clear in SPPrefService");
} else {
throw new SpecialPowersException("Invalid operation for SPPrefService");
}
// Now we make the call
switch(prefType) {
case "BOOL":
if (aMessage.json.op == "get")
return(prefs.getBoolPref(prefName));
else
return(prefs.setBoolPref(prefName, prefValue));
case "INT":
if (aMessage.json.op == "get")
return(prefs.getIntPref(prefName));
else
return(prefs.setIntPref(prefName, prefValue));
case "CHAR":
if (aMessage.json.op == "get")
return(prefs.getCharPref(prefName));
else
return(prefs.setCharPref(prefName, prefValue));
case "COMPLEX":
if (aMessage.json.op == "get")
return(prefs.getComplexValue(prefName, prefValue[0]));
else
return(prefs.setComplexValue(prefName, prefValue[0], prefValue[1]));
case "":
if (aMessage.json.op == "clear") {
prefs.clearUserPref(prefName);
return;
}
}
break;
case "SPProcessCrashService":
switch (aMessage.json.op) {
case "register-observer":
this._addProcessCrashObservers();
break;
case "unregister-observer":
this._removeProcessCrashObservers();
break;
case "delete-crash-dump-files":
return this._deleteCrashDumpFiles(aMessage.json.filenames);
case "find-crash-dump-files":
return this._findCrashDumpFiles(aMessage.json.crashDumpFilesToIgnore);
default:
throw new SpecialPowersException("Invalid operation for SPProcessCrashService");
}
break;
default:
throw new SpecialPowersException("Unrecognized Special Powers API");
}
}
};

Просмотреть файл

@ -311,6 +311,8 @@ TestRunner.runNextTest = function() {
indicator.style.backgroundColor = "red";
}
SpecialPowers.unregisterProcessCrashObservers();
TestRunner.log("TEST-START | Shutdown"); // used by automation.py
TestRunner.log("Passed: " + $("pass-count").innerHTML);
TestRunner.log("Failed: " + $("fail-count").innerHTML);

Просмотреть файл

@ -0,0 +1,391 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Special Powers code
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Clint Talbert cmtalbert@gmail.com
* Joel Maher joel.maher@gmail.com
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK *****/
/* This code is loaded in every child process that is started by mochitest in
* order to be used as a replacement for UniversalXPConnect
*/
var Ci = Components.interfaces;
var Cc = Components.classes;
function SpecialPowersAPI() {
this._consoleListeners = [];
this._encounteredCrashDumpFiles = [];
this._unexpectedCrashDumpFiles = { };
this._crashDumpDir = null;
this._mfl = null;
}
function bindDOMWindowUtils(aWindow) {
if (!aWindow)
return
var util = aWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils);
// This bit of magic brought to you by the letters
// B Z, and E, S and the number 5.
//
// Take all of the properties on the nsIDOMWindowUtils-implementing
// object, and rebind them onto a new object with a stub that uses
// apply to call them from this privileged scope. This way we don't
// have to explicitly stub out new methods that appear on
// nsIDOMWindowUtils.
var proto = Object.getPrototypeOf(util);
var target = {};
function rebind(desc, prop) {
if (prop in desc && typeof(desc[prop]) == "function") {
var oldval = desc[prop];
try {
desc[prop] = function() { return oldval.apply(util, arguments); };
} catch (ex) {
dump("WARNING: Special Powers failed to rebind function: " + desc + "::" + prop + "\n");
}
}
}
for (var i in proto) {
var desc = Object.getOwnPropertyDescriptor(proto, i);
rebind(desc, "get");
rebind(desc, "set");
rebind(desc, "value");
Object.defineProperty(target, i, desc);
}
return target;
}
SpecialPowersAPI.prototype = {
getDOMWindowUtils: function(aWindow) {
if (aWindow == this.window && this.DOMWindowUtils != null)
return this.DOMWindowUtils;
return bindDOMWindowUtils(aWindow);
},
removeExpectedCrashDumpFiles: function(aExpectingProcessCrash) {
var success = true;
if (aExpectingProcessCrash) {
var message = {
op: "delete-crash-dump-files",
filenames: this._encounteredCrashDumpFiles
};
if (!this._sendSyncMessage("SPProcessCrashService", message)[0]) {
success = false;
}
}
this._encounteredCrashDumpFiles.length = 0;
return success;
},
findUnexpectedCrashDumpFiles: function() {
var self = this;
var message = {
op: "find-crash-dump-files",
crashDumpFilesToIgnore: this._unexpectedCrashDumpFiles
};
var crashDumpFiles = this._sendSyncMessage("SPProcessCrashService", message)[0];
crashDumpFiles.forEach(function(aFilename) {
self._unexpectedCrashDumpFiles[aFilename] = true;
});
return crashDumpFiles;
},
// Mimic the get*Pref API
getBoolPref: function(aPrefName) {
return (this._getPref(aPrefName, 'BOOL'));
},
getIntPref: function(aPrefName) {
return (this._getPref(aPrefName, 'INT'));
},
getCharPref: function(aPrefName) {
return (this._getPref(aPrefName, 'CHAR'));
},
getComplexValue: function(aPrefName, aIid) {
return (this._getPref(aPrefName, 'COMPLEX', aIid));
},
// Mimic the set*Pref API
setBoolPref: function(aPrefName, aValue) {
return (this._setPref(aPrefName, 'BOOL', aValue));
},
setIntPref: function(aPrefName, aValue) {
return (this._setPref(aPrefName, 'INT', aValue));
},
setCharPref: function(aPrefName, aValue) {
return (this._setPref(aPrefName, 'CHAR', aValue));
},
setComplexValue: function(aPrefName, aIid, aValue) {
return (this._setPref(aPrefName, 'COMPLEX', aValue, aIid));
},
// Mimic the clearUserPref API
clearUserPref: function(aPrefName) {
var msg = {'op':'clear', 'prefName': aPrefName, 'prefType': ""};
this._sendSyncMessage('SPPrefService', msg);
},
// Private pref functions to communicate to chrome
_getPref: function(aPrefName, aPrefType, aIid) {
var msg = {};
if (aIid) {
// Overloading prefValue to handle complex prefs
msg = {'op':'get', 'prefName': aPrefName, 'prefType':aPrefType, 'prefValue':[aIid]};
} else {
msg = {'op':'get', 'prefName': aPrefName,'prefType': aPrefType};
}
var val = this._sendSyncMessage('SPPrefService', msg);
if (val == null || val[0] == null)
throw "Error getting pref";
return val[0];
},
_setPref: function(aPrefName, aPrefType, aValue, aIid) {
var msg = {};
if (aIid) {
msg = {'op':'set','prefName':aPrefName, 'prefType': aPrefType, 'prefValue': [aIid,aValue]};
} else {
msg = {'op':'set', 'prefName': aPrefName, 'prefType': aPrefType, 'prefValue': aValue};
}
return(this._sendSyncMessage('SPPrefService', msg)[0]);
},
//XXX: these APIs really ought to be removed, they're not e10s-safe.
// (also they're pretty Firefox-specific)
_getTopChromeWindow: function(window) {
return window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow)
.QueryInterface(Ci.nsIDOMChromeWindow);
},
_getDocShell: function(window) {
return window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
},
_getMUDV: function(window) {
return this._getDocShell(window).contentViewer
.QueryInterface(Ci.nsIMarkupDocumentViewer);
},
_getAutoCompletePopup: function(window) {
return this._getTopChromeWindow(window).document
.getElementById("PopupAutoComplete");
},
addAutoCompletePopupEventListener: function(window, listener) {
this._getAutoCompletePopup(window).addEventListener("popupshowing",
listener,
false);
},
removeAutoCompletePopupEventListener: function(window, listener) {
this._getAutoCompletePopup(window).removeEventListener("popupshowing",
listener,
false);
},
isBackButtonEnabled: function(window) {
return !this._getTopChromeWindow(window).document
.getElementById("Browser:Back")
.hasAttribute("disabled");
},
addChromeEventListener: function(type, listener, capture, allowUntrusted) {
addEventListener(type, listener, capture, allowUntrusted);
},
removeChromeEventListener: function(type, listener, capture) {
removeEventListener(type, listener, capture);
},
addErrorConsoleListener: function(listener) {
var consoleListener = {
userListener: listener,
observe: function(consoleMessage) {
this.userListener(consoleMessage.message);
}
};
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService)
.registerListener(consoleListener);
this._consoleListeners.push(consoleListener);
},
removeErrorConsoleListener: function(listener) {
for (var index in this._consoleListeners) {
var consoleListener = this._consoleListeners[index];
if (consoleListener.userListener == listener) {
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService)
.unregisterListener(consoleListener);
this._consoleListeners = this._consoleListeners.splice(index, 1);
break;
}
}
},
getFullZoom: function(window) {
return this._getMUDV(window).fullZoom;
},
setFullZoom: function(window, zoom) {
this._getMUDV(window).fullZoom = zoom;
},
getTextZoom: function(window) {
return this._getMUDV(window).textZoom;
},
setTextZoom: function(window, zoom) {
this._getMUDV(window).textZoom = zoom;
},
createSystemXHR: function() {
return Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(Ci.nsIXMLHttpRequest);
},
snapshotWindow: function (win, withCaret) {
var el = this.window.document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
el.width = win.innerWidth;
el.height = win.innerHeight;
var ctx = el.getContext("2d");
var flags = 0;
ctx.drawWindow(win, win.scrollX, win.scrollY,
win.innerWidth, win.innerHeight,
"rgb(255,255,255)",
withCaret ? ctx.DRAWWINDOW_DRAW_CARET : 0);
return el;
},
gc: function() {
this.DOMWindowUtils.garbageCollect();
},
forceGC: function() {
Components.utils.forceGC();
},
hasContentProcesses: function() {
try {
var rt = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
return rt.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
} catch (e) {
return true;
}
},
_xpcomabi: null,
get XPCOMABI() {
if (this._xpcomabi != null)
return this._xpcomabi;
var xulRuntime = Cc["@mozilla.org/xre/app-info;1"]
.getService(Components.interfaces.nsIXULAppInfo)
.QueryInterface(Components.interfaces.nsIXULRuntime);
this._xpcomabi = xulRuntime.XPCOMABI;
return this._xpcomabi;
},
executeSoon: function(aFunc) {
var tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
tm.mainThread.dispatch({
run: function() {
aFunc();
}
}, Ci.nsIThread.DISPATCH_NORMAL);
},
_os: null,
get OS() {
if (this._os != null)
return this._os;
var xulRuntime = Cc["@mozilla.org/xre/app-info;1"]
.getService(Components.interfaces.nsIXULAppInfo)
.QueryInterface(Components.interfaces.nsIXULRuntime);
this._os = xulRuntime.OS;
return this._os;
},
addSystemEventListener: function(target, type, listener, useCapture) {
Cc["@mozilla.org/eventlistenerservice;1"].
getService(Ci.nsIEventListenerService).
addSystemEventListener(target, type, listener, useCapture);
},
removeSystemEventListener: function(target, type, listener, useCapture) {
Cc["@mozilla.org/eventlistenerservice;1"].
getService(Ci.nsIEventListenerService).
removeSystemEventListener(target, type, listener, useCapture);
},
setLogFile: function(path) {
this._mfl = new MozillaFileLogger(path);
},
log: function(data) {
this._mfl.log(data);
},
closeLogFile: function() {
this._mfl.close();
},
addCategoryEntry: function(category, entry, value, persists, replace) {
Components.classes["@mozilla.org/categorymanager;1"].
getService(Components.interfaces.nsICategoryManager).
addCategoryEntry(category, entry, value, persists, replace);
},
getNodePrincipal: function(aNode) {
return aNode.nodePrincipal;
},
getNodeBaseURIObject: function(aNode) {
return aNode.baseURIObject;
},
getDocumentURIObject: function(aDocument) {
return aDocument.documentURIObject;
},
copyString: function(str) {
Components.classes["@mozilla.org/widget/clipboardhelper;1"].
getService(Components.interfaces.nsIClipboardHelper).
copyString(str);
},
};