--- a/content/events/test/test_bug648573.html
+++ b/content/events/test/test_bug648573.html
@@ -14,19 +14,17 @@ https://bugzilla.mozilla.org/show_bug.cg
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 648573 **/
-var utils = SpecialPowers.getDOMWindowUtils(window);
-
-ok(!utils.mayHaveTouchEventListeners,
+ok(!SpecialPowers.DOMWindowUtils.mayHaveTouchEventListeners,
"There shouldn't be any touch event listeners yet.");
ok("createTouch" in document, "Should have createTouch function");
ok("createTouchList" in document, "Should have createTouchList function");
ok(document.createEvent("touchevent"), "Should be able to create TouchEvent objects");
var t1 = document.createTouch(window, document, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
is(t1.target, document, "Wrong target");
@@ -98,15 +96,15 @@ function runEventTest(type) {
t.dispatchEvent(e);
ok(t.didCall, "Should have called the listener(2)");
}
for (var i = 0; i < events.length; ++i) {
runEventTest(events[i]);
}
-ok(utils.mayHaveTouchEventListeners,
+ok(SpecialPowers.DOMWindowUtils.mayHaveTouchEventListeners,
"There should be touch event listeners.");
</script>
</pre>
</body>
</html>
--- a/content/events/test/test_bug662678.html
+++ b/content/events/test/test_bug662678.html
@@ -13,44 +13,40 @@ https://bugzilla.mozilla.org/show_bug.cg
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<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);
is(event.accelerationIncludingGravity.x, 1.5);
is(event.accelerationIncludingGravity.y, 1.5);
is(event.accelerationIncludingGravity.z, 1.5);
is(event.rotationRate.alpha, 1.5);
is(event.rotationRate.beta, 1.5);
is(event.rotationRate.gamma, 1.5);
SimpleTest.finish();
-};
-
-window.addEventListener("devicemotion", checkMotion, true);
+}, true);
var event = DeviceMotionEvent;
ok(!!event, "Should have seen DeviceMotionEvent!");
event = document.createEvent("DeviceMotionEvent");
event.initDeviceMotionEvent('devicemotion', true, true,
{x:1.5,y:1.5,z:1.5},
{x:1.5,y:1.5,z:1.5},
{alpha:1.5,beta:1.5,gamma:1.5},
0);
window.dispatchEvent(event);
+SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>
--- a/layout/base/tests/chrome/chrome_content_integration_window.xul
+++ b/layout/base/tests/chrome/chrome_content_integration_window.xul
@@ -15,26 +15,25 @@
transparent="transparent"
src="data:text/html,<div style='position:absolute;left:0;top:0;width:100%;height:100px;background:yellow;border-bottom:100px solid black'>"/>
<!-- the top 100px is a strip of black above the content iframe -->
<vbox style="border-top:100px solid black;"/>
</stack>
<script type="application/javascript">
<![CDATA[
- //we need SpecialPowers for WindowSnapshot.snapshotWindow()
- var imports = [ "SimpleTest", "is", "isnot", "ok", "SpecialPowers"];
+ var imports = [ "SimpleTest", "is", "isnot", "ok" ];
for each (var name in imports) {
window[name] = window.opener.wrappedJSObject[name];
}
function runTests() {
- var testCanvas = snapshotWindow(window);
+ var testCanvas = window.opener.SpecialPowers.snapshotWindow(window);
- var refCanvas = snapshotWindow(window);
+ var refCanvas = window.opener.SpecialPowers.snapshotWindow(window);
var ctx = refCanvas.getContext('2d');
ctx.fillStyle = "black";
ctx.fillRect(0, 0, refCanvas.width, refCanvas.height);
var comparison = compareSnapshots(testCanvas, refCanvas, true);
ok(comparison[0], "Rendering OK, got " + comparison[1] + ", expected " + comparison[2]);
var tester = window.SimpleTest;
--- a/layout/style/test/test_bug389464.html
+++ b/layout/style/test/test_bug389464.html
@@ -22,26 +22,42 @@
<p><font id="two" size="-1">text</font></p>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
+function get_pref(pref)
+{
+ return SpecialPowers.getIntPref("font.size." + pref);
+}
+
+function set_pref(pref, val)
+{
+ SpecialPowers.setIntPref("font.size." + pref, val);
+}
+
var cs1 = getComputedStyle(document.getElementById("one"), "");
var cs2 = getComputedStyle(document.getElementById("two"), "");
-SpecialPowers.pushPrefEnv({'set': [['variable.x-western', 25], ['fixed.x-western', 20]]}, function() setTimeout(part1, 0));
+var oldVariable = get_pref("variable.x-western");
+var oldFixed = get_pref("fixed.x-western");
+set_pref("variable.x-western", 25);
+set_pref("fixed.x-western", 20);
+setTimeout(part1, 0);
function part1()
{
var fs1 = cs1.fontSize.match(/(.*)px/)[1];
var fs2 = cs2.fontSize.match(/(.*)px/)[1];
ok(fs1 < fs2, "<font size=-1> shrinks relative to font-family: -moz-fixed");
+ set_pref("variable.x-western", oldVariable);
+ set_pref("fixed.x-western", oldFixed);
SimpleTest.finish();
}
</script>
</pre>
</body>
</html>
--- a/layout/style/test/test_bug401046.html
+++ b/layout/style/test/test_bug401046.html
@@ -51,42 +51,53 @@ var elts = [
function fs(idx) {
// The computed font size actually *doesn't* currently reflect the
// minimum font size preference, but things in em units do. Not sure
// if this is how it ought to be...
return getComputedStyle(elts[idx], "").marginBottom;
}
-SpecialPowers.pushPrefEnv({'clear': [['font.minimum-size.x-western']]}, function() setTimeout(step1, 0));
+SpecialPowers.clearUserPref('font.minimum-size.x-western');
+
+// preference change is async (although one setTimeout might be enough?)
+setTimeout(setTimeout, 0, step1, 0);
function step1() {
is(fs(0), "0px", "at min font size 0, 0px should compute to 0px");
is(fs(1), "4px", "at min font size 0, 4px should compute to 4px");
is(fs(2), "12px", "at min font size 0, 12px should compute to 12px");
is(fs(3), "28px", "at min font size 0, 28px should compute to 28px");
- SpecialPowers.pushPrefEnv({'set': [['font.minimum-size.x-western', 7]]}, function() setTimeout(step2, 0));
+ SpecialPowers.setIntPref('font.minimum-size.x-western', 7);
+
+ // preference change is async (although one setTimeout might be enough?)
+ setTimeout(setTimeout, 0, step2, 0);
}
function step2() {
is(fs(0), "0px", "at min font size 7, 0px should compute to 0px");
is(fs(1), "7px", "at min font size 7, 4px should compute to 7px");
is(fs(2), "12px", "at min font size 7, 12px should compute to 12px");
is(fs(3), "28px", "at min font size 7, 28px should compute to 28px");
- SpecialPowers.pushPrefEnv({'set': [['font.minimum-size.x-western', 18]]}, function() setTimeout(step3, 0));
+ SpecialPowers.setIntPref('font.minimum-size.x-western', 18);
+
+ // preference change is async (although one setTimeout might be enough?)
+ setTimeout(setTimeout, 0, step3, 0);
}
function step3() {
is(fs(0), "0px", "at min font size 18, 0px should compute to 0px");
is(fs(1), "18px", "at min font size 18, 4px should compute to 18px");
is(fs(2), "18px", "at min font size 18, 12px should compute to 18px");
is(fs(3), "28px", "at min font size 18, 28px should compute to 28px");
- SpecialPowers.pushPrefEnv({'clear': [['font.minimum-size.x-western']]}, SimpleTest.finish);
+ SpecialPowers.clearUserPref('font.minimum-size.x-western');
+
+ SimpleTest.finish();
}
</script>
</pre>
</body>
</html>
--- a/layout/style/test/test_pointer-events.html
+++ b/layout/style/test/test_pointer-events.html
@@ -64,19 +64,18 @@ function catches_pointer_events(element_
function synthesizeMouseEvent(type, // string
x, // float
y, // float
button, // long
clickCount, // long
modifiers, // long
ignoreWindowBounds) // boolean
{
- var utils = SpecialPowers.getDOMWindowUtils(window);
- utils.sendMouseEvent(type, x, y, button, clickCount,
- modifiers, ignoreWindowBounds);
+ SpecialPowers.DOMWindowUtils.sendMouseEvent(type, x, y, button, clickCount,
+ modifiers, ignoreWindowBounds);
}
function run_test()
{
ok(catches_pointer_events("one"), "one: div should default to catching pointer events");
ok(catches_pointer_events("two"), "two: div should catch pointer events with explicit visiblePainted");
ok(!catches_pointer_events("three"), "three: div should not catch pointer events with explicit none");
ok(!catches_pointer_events("four"), "four: div should not catch pointer events with inherited none");
--- a/testing/mochitest/Makefile.in
+++ b/testing/mochitest/Makefile.in
@@ -90,16 +90,17 @@ include $(topsrcdir)/build/automation-bu
harness.xul \
browser-test-overlay.xul \
browser-test.js \
chrome-harness.js \
ipc-overlay.xul \
ipc.js \
browser-harness.xul \
redirect.html \
+ redirect.js \
$(topsrcdir)/build/pgo/server-locations.txt \
$(topsrcdir)/netwerk/test/httpserver/httpd.js \
mozprefs.js \
pywebsocket_wrapper.py \
plain-loop.html \
$(NULL)
_PYWEBSOCKET_FILES = \
--- a/testing/mochitest/browser-test-overlay.xul
+++ b/testing/mochitest/browser-test-overlay.xul
@@ -18,17 +18,16 @@
- The Initial Developer of the Original Code is
- Mozilla Corporation.
-
- Portions created by the Initial Developer are Copyright (C) 2007
- the Initial Developer. All Rights Reserved.
-
- 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
- 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
--- a/testing/mochitest/browser-test.js
+++ b/testing/mochitest/browser-test.js
@@ -7,50 +7,34 @@ if (Cc === undefined) {
var Ci = Components.interfaces;
var Cu = Components.utils;
}
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"].
createInstance(Ci.nsISupportsString);
sstring.data = location.search;
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);
}
}
function Tester(aTests, aDumper, aCallback) {
this.dumper = aDumper;
this.tests = aTests;
this.callback = aCallback;
this._cs = Cc["@mozilla.org/consoleservice;1"].
@@ -59,19 +43,16 @@ function Tester(aTests, aDumper, aCallba
getService(Ci.nsIWindowMediator);
this._fm = Cc["@mozilla.org/focus-manager;1"].
getService(Ci.nsIFocusManager);
this._scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
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;
}
Tester.prototype = {
EventUtils: {},
SimpleTest: {},
--- a/testing/mochitest/harness-overlay.xul
+++ b/testing/mochitest/harness-overlay.xul
@@ -7,22 +7,16 @@
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<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"
src="chrome://mochikit/content/tests/SimpleTest/MozillaLogger.js"/>
<script type="text/javascript"
src="chrome://mochikit/content/tests/SimpleTest/quit.js" />
<script type="application/javascript"
src="chrome://mochikit/content/chrome-harness.js" />
<script type="text/javascript"
--- a/testing/mochitest/jar.mn
+++ b/testing/mochitest/jar.mn
@@ -5,22 +5,20 @@ mochikit.jar:
content/browser-test-overlay.xul (browser-test-overlay.xul)
content/chrome-harness.js (chrome-harness.js)
content/harness-overlay.xul (harness-overlay.xul)
content/harness.xul (harness.xul)
content/ipc.js (ipc.js)
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)
content/tests/SimpleTest/LogController.js (tests/SimpleTest/LogController.js)
content/tests/SimpleTest/PluginUtils.js (tests/SimpleTest/PluginUtils.js)
content/tests/SimpleTest/quit.js (tests/SimpleTest/quit.js)
content/tests/SimpleTest/setup.js (tests/SimpleTest/setup.js)
content/tests/SimpleTest/SimpleTest.js (tests/SimpleTest/SimpleTest.js)
--- a/testing/mochitest/redirect.html
+++ b/testing/mochitest/redirect.html
@@ -1,21 +1,14 @@
<html>
<head>
<title>redirecting...</title>
+ <script type="text/javascript" src="redirect.js"></script>
+
<script type="text/javascript">
- function redirect(aURL)
- {
- 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>
<body>
redirecting...
</body>
</html>
new file mode 100644
--- /dev/null
+++ b/testing/mochitest/redirect.js
@@ -0,0 +1,45 @@
+/* -*- 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);
+}
--- a/testing/mochitest/runtests.py
+++ b/testing/mochitest/runtests.py
@@ -505,21 +505,17 @@ class Mochitest(object):
self.automation.log.info("INFO | runtests.py | Done installing extension.")
def buildProfile(self, options):
""" create the profile and add optional chrome bits and files if requested """
self.automation.initializeProfile(options.profilePath, options.extraPrefs, useServerLocations = True)
manifest = self.addChromeToProfile(options)
self.copyExtraFilesToProfile(options)
- # We only need special powers in non-chrome harnesses
- if (not options.browserChrome and
- not options.chrome and
- not options.a11y):
- self.installSpecialPowersExtension(options)
+ self.installSpecialPowersExtension(options)
self.installExtensionsToProfile(options)
return manifest
def buildBrowserEnv(self, options):
""" build the environment variables for the specific test and operating system """
browserEnv = self.automation.environment(xrePath = options.xrePath)
# These variables are necessary for correct application startup; change
--- a/testing/mochitest/specialpowers/components/SpecialPowersObserver.js
+++ b/testing/mochitest/specialpowers/components/SpecialPowersObserver.js
@@ -45,109 +45,251 @@
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
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";
+}
-//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");
-
+SpecialPowersException.prototype.toString = function() {
+ return this.name + ': "' + this.message + '"';
+};
/* XPCOM gunk */
function SpecialPowersObserver() {
this._isFrameScriptLoaded = false;
this._messageManager = Cc["@mozilla.org/globalmessagemanager;1"].
getService(Ci.nsIChromeFrameMessageManager);
}
-
-SpecialPowersObserver.prototype = new SpecialPowersObserverAPI();
+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 }],
- 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)
+ observe: function(aSubject, aTopic, aData)
{
switch (aTopic) {
case "profile-after-change":
this.init();
break;
case "chrome-document-global-created":
if (!this._isFrameScriptLoaded) {
// Register for any messages our API needs us to handle
this._messageManager.addMessageListener("SPPrefService", this);
this._messageManager.addMessageListener("SPProcessCrashService", this);
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;
}
break;
case "xpcom-shutdown":
this.uninit();
break;
- default:
- this._observe(aSubject, aTopic, aData);
+ 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);
break;
}
- };
+ },
- SpecialPowersObserver.prototype._sendAsyncMessage = function(msgname, msg)
- {
- this._messageManager.sendAsyncMessage(msgname, msg);
- };
-
- SpecialPowersObserver.prototype._receiveMessage = function(aMessage) {
- return this._receiveMessageAPI(aMessage);
- };
-
- SpecialPowersObserver.prototype.init = function()
+ init: function()
{
var obs = Services.obs;
obs.addObserver(this, "xpcom-shutdown", false);
obs.addObserver(this, "chrome-document-global-created", false);
- };
+ },
- SpecialPowersObserver.prototype.uninit = function()
+ uninit: function()
{
var obs = Services.obs;
obs.removeObserver(this, "chrome-document-global-created", false);
- this._removeProcessCrashObservers();
- };
+ this.removeProcessCrashObservers();
+ },
+
+ addProcessCrashObservers: function() {
+ if (this._processCrashObserversRegistered) {
+ return;
+ }
+
+ Services.obs.addObserver(this, "plugin-crashed", false);
+ Services.obs.addObserver(this, "ipc:content-shutdown", false);
+ this._processCrashObserversRegistered = true;
+ },
+
+ removeProcessCrashObservers: function() {
+ if (!this._processCrashObserversRegistered) {
+ return;
+ }
+
+ Services.obs.removeObserver(this, "plugin-crashed");
+ Services.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
**/
- SpecialPowersObserver.prototype.receiveMessage = function(aMessage) {
+ 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
.QueryInterface(Ci.nsIFrameLoaderOwner)
.frameLoader
.messageManager
.sendAsyncMessage("SPPingService", { op: "pong" });
}
break;
+
default:
- return this._receiveMessage(aMessage);
+ throw new SpecialPowersException("Unrecognized Special Powers API");
}
- };
+ }
+};
const NSGetFactory = XPCOMUtils.generateNSGetFactory([SpecialPowersObserver]);
--- a/testing/mochitest/specialpowers/content/specialpowers.js
+++ b/testing/mochitest/specialpowers/content/specialpowers.js
@@ -33,103 +33,381 @@
* 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 SpecialPowers(window) {
this.window = window;
- this.DOMWindowUtils = bindDOMWindowUtils(window);
+ bindDOMWindowUtils(this, window);
+ this._encounteredCrashDumpFiles = [];
+ this._unexpectedCrashDumpFiles = { };
+ this._crashDumpDir = null;
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");
+ }
+ }
+ }
+ 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;
}
-SpecialPowers.prototype = new SpecialPowersAPI();
+SpecialPowers.prototype = {
+ toString: function() { return "[SpecialPowers]"; },
+ sanityCheck: function() { return "foo"; },
+
+ // This gets filled in in the constructor.
+ DOMWindowUtils: undefined,
-SpecialPowers.prototype.toString = function() { return "[SpecialPowers]"; };
-SpecialPowers.prototype.sanityCheck = function() { return "foo"; };
+ // 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));
+ },
-// This gets filled in in the constructor.
-SpecialPowers.prototype.DOMWindowUtils = undefined;
+ // 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);
+ },
-SpecialPowers.prototype._sendSyncMessage = function(msgname, msg) {
- return sendSyncMessage(msgname, 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]);
+ },
-SpecialPowers.prototype._sendAsyncMessage = function(msgname, msg) {
- sendAsyncMessage(msgname, msg);
-};
+ //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");
+ },
-SpecialPowers.prototype.registerProcessCrashObservers = function() {
- addMessageListener("SPProcessCrashService", this._messageListener);
- sendSyncMessage("SPProcessCrashService", { op: "register-observer" });
-};
+ 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);
+ }
+ };
-SpecialPowers.prototype.unregisterProcessCrashObservers = function() {
- addMessageListener("SPProcessCrashService", this._messageListener);
- sendSyncMessage("SPProcessCrashService", { op: "unregister-observer" });
-};
+ 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;
+ }
+ }
+ },
-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");
- });
- }
- 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");
+ 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;
+ },
+
+ registerProcessCrashObservers: function() {
+ addMessageListener("SPProcessCrashService", this._messageListener);
+ sendSyncMessage("SPProcessCrashService", { op: "register-observer" });
+ },
- case "SPPingService":
- if (aMessage.json.op == "pong") {
- var handler = this._pongHandlers.shift();
- if (handler) {
- handler();
+ _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");
+ });
}
+ 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;
}
- break;
- }
- return true;
-};
+ }
+ this._encounteredCrashDumpFiles.length = 0;
+ return success;
+ },
+
+ 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" });
+ },
-SpecialPowers.prototype.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();
+ },
};
// 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
+// web content.
SpecialPowers.prototype.__exposedProps__ = {};
-for (var i in SpecialPowers.prototype) {
- if (i.charAt(0) != "_")
- SpecialPowers.prototype.__exposedProps__[i] = "r";
+for each (i in Object.keys(SpecialPowers.prototype).filter(function(v) {return v.charAt(0) != "_";})) {
+ SpecialPowers.prototype.__exposedProps__[i] = "r";
}
// Attach our API to the window.
function attachSpecialPowersToWindow(aWindow) {
try {
if ((aWindow !== null) &&
(aWindow !== undefined) &&
- (aWindow.parent !== null) &&
- (aWindow.parent !== undefined) &&
- (aWindow.parent.wrappedJSObject.SpecialPowers) &&
+ (aWindow.wrappedJSObject) &&
!(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) {
dump("TEST-INFO | specialpowers.js | Failed to attach specialpowers to window exception: " + ex + "\n");
}
}
// This is a frame script, so it may be running in a content process.
@@ -140,19 +418,19 @@ function attachSpecialPowersToWindow(aWi
function SpecialPowersManager() {
addEventListener("DOMWindowCreated", this, false);
}
SpecialPowersManager.prototype = {
handleEvent: function handleEvent(aEvent) {
var window = aEvent.target.defaultView;
- // only add SpecialPowers to data pages, not about:* or chrome://*
+ // only add SpecialPowers to data pages, not about:*
var uri = window.document.documentURIObject;
- if (uri.scheme === "chrome" || uri.spec.split(":")[0] == "about") {
+ if (uri.spec.split(":")[0] == "about") {
return;
}
attachSpecialPowersToWindow(window);
}
};
var specialpowersmanager = new SpecialPowersManager();
--- a/testing/mochitest/specialpowers/jar.mn
+++ b/testing/mochitest/specialpowers/jar.mn
@@ -1,6 +1,4 @@
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)
deleted file mode 100644
--- a/testing/mochitest/tests/SimpleTest/ChromePowers.js
+++ /dev/null
@@ -1,120 +0,0 @@
-/* ***** 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);
-}
-
--- a/testing/mochitest/tests/SimpleTest/Makefile.in
+++ b/testing/mochitest/tests/SimpleTest/Makefile.in
@@ -48,17 +48,15 @@ include $(topsrcdir)/config/rules.mk
SimpleTest.js \
test.css \
TestRunner.js \
setup.js \
EventUtils.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)
libs:: $(_SIMPLETEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/$(relativesrcdir)
--- a/testing/mochitest/tests/SimpleTest/SimpleTest.js
+++ b/testing/mochitest/tests/SimpleTest/SimpleTest.js
@@ -17,21 +17,16 @@
var SimpleTest = { };
var parentRunner = null;
if (parent) {
parentRunner = parent.TestRunner;
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?
var ipcMode = false;
if (parentRunner) {
ipcMode = parentRunner.ipcMode;
} else if (typeof SpecialPowers != 'undefined') {
ipcMode = SpecialPowers.hasContentProcesses();
deleted file mode 100644
--- a/testing/mochitest/tests/SimpleTest/SpecialPowersObserverAPI.js
+++ /dev/null
@@ -1,234 +0,0 @@
-/* ***** 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;
- }
- },
-
- _addProcessCrashObservers: function() {
- if (this._processCrashObserversRegistered) {
- return;
- }
-
- var obs = Components.classes["@mozilla.org/observer-service;1"]
- .getService(Components.interfaces.nsIObserverService);
-
- obs.addObserver(this, "plugin-crashed", false);
- obs.addObserver(this, "ipc:content-shutdown", false);
- this._processCrashObserversRegistered = true;
- },
-
- _removeProcessCrashObservers: function() {
- if (!this._processCrashObserversRegistered) {
- return;
- }
-
- 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 = 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");
- }
- }
-};
-
--- a/testing/mochitest/tests/SimpleTest/TestRunner.js
+++ b/testing/mochitest/tests/SimpleTest/TestRunner.js
@@ -306,18 +306,16 @@ TestRunner.runNextTest = function() {
// ... the count,
$("fail-count").innerHTML = 1;
// ... the indicator.
var indicator = $("indicator");
indicator.innerHTML = "Status: Fail (No checks actually run)";
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);
TestRunner.log("Todo: " + $("todo-count").innerHTML);
// If we are looping, don't send this cause it closes the log file
if (TestRunner.loops == 0)
TestRunner.log("SimpleTest FINISHED");
@@ -380,17 +378,17 @@ TestRunner.testFinished = function(tests
TestRunner.updateUI(tests);
TestRunner._currentTest++;
TestRunner.runNextTest();
}
SpecialPowers.executeAfterFlushingMessageQueue(function() {
cleanUpCrashDumpFiles();
- SpecialPowers.flushPrefEnv(runNextTest);
+ runNextTest();
});
};
/**
* Get the results.
*/
TestRunner.countResults = function(tests) {
var nOK = 0;
deleted file mode 100644
--- a/testing/mochitest/tests/SimpleTest/specialpowersAPI.js
+++ /dev/null
@@ -1,559 +0,0 @@
-/* ***** 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;
- this._prefEnvUndoStack = [];
- this._pendingPrefs = [];
- this._applyingPrefs = false;
-}
-
-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;
-}
-
-function Observer(specialPowers, aTopic, aCallback, aIsPref) {
- this._sp = specialPowers;
- this._topic = aTopic;
- this._callback = aCallback;
- this._isPref = aIsPref;
-}
-
-Observer.prototype = {
- _sp: null,
- _topic: null,
- _callback: null,
- _isPref: false,
-
- observe: function(aSubject, aTopic, aData) {
- if ((!this._isPref && aTopic == this._topic) ||
- (this._isPref && aTopic == "nsPref:changed")) {
- if (aData == this._topic) {
- this.cleanup();
- /* The callback must execute asynchronously after all the preference observers have run */
- content.window.setTimeout(this._callback, 0);
- content.window.setTimeout(this._sp._finishPrefEnv, 0);
- }
- }
- },
-
- cleanup: function() {
- if (this._isPref) {
- var os = Cc["@mozilla.org/preferences-service;1"].getService()
- .QueryInterface(Ci.nsIPrefBranch2);
- os.removeObserver(this._topic, this);
- } else {
- var os = Cc["@mozilla.org/observer-service;1"]
- .getService(Ci.nsIObserverService)
- .QueryInterface(Ci.nsIObserverService);
- os.removeObserver(this, this._topic);
- }
- },
-};
-
-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;
- },
-
- /*
- * Take in a list of prefs and put the original value on the _prefEnvUndoStack so we can undo
- * preferences that we set. Note, that this is a stack of values to revert to, not
- * what we have set.
- *
- * prefs: {set|clear: [[pref, value], [pref, value, Iid], ...], set|clear: [[pref, value], ...], ...}
- * ex: {'set': [['foo.bar', 2], ['browser.magic', '0xfeedface']], 'remove': [['bad.pref']] }
- *
- * In the scenario where our prefs specify the same pref more than once, we do not guarantee
- * the behavior.
- *
- * If a preference is not changing a value, we will ignore it.
- *
- * TODO: complex values for original cleanup?
- *
- */
- pushPrefEnv: function(inPrefs, callback) {
- var prefs = Components.classes["@mozilla.org/preferences-service;1"].
- getService(Components.interfaces.nsIPrefBranch);
-
- var pref_string = [];
- pref_string[prefs.PREF_INT] = "INT";
- pref_string[prefs.PREF_BOOL] = "BOOL";
- pref_string[prefs.PREF_STRING] = "STRING";
-
- var pendingActions = [];
- var cleanupActions = [];
-
- for (var action in inPrefs) { /* set|clear */
- for (var idx in inPrefs[action]) {
- var aPref = inPrefs[action][idx];
- var prefName = aPref[0];
- var prefValue = null;
- var prefIid = null;
- var prefType = prefs.PREF_INVALID;
- var originalValue = null;
-
- if (aPref.length == 3) {
- prefValue = aPref[1];
- prefIid = aPref[2];
- } else if (aPref.length == 2) {
- prefValue = aPref[1];
- }
-
- /* If pref is not found or invalid it doesn't exist. */
- if (prefs.getPrefType(prefName) != prefs.PREF_INVALID) {
- prefType = pref_string[prefs.getPrefType(prefName)];
- if ((prefs.prefHasUserValue(prefName) && action == 'clear') ||
- (action == 'set'))
- originalValue = this._getPref(prefName, prefType);
- } else if (action == 'set') {
- /* prefName doesn't exist, so 'clear' is pointless */
- if (aPref.length == 3) {
- prefType = "COMPLEX";
- } else if (aPref.length == 2) {
- if (typeof(prefValue) == "boolean")
- prefType = "BOOL";
- else if (typeof(prefValue) == "number")
- prefType = "INT";
- else if (typeof(prefValue) == "string")
- prefType = "CHAR";
- }
- }
-
- /* PREF_INVALID: A non existing pref which we are clearing or invalid values for a set */
- if (prefType == prefs.PREF_INVALID)
- continue;
-
- /* We are not going to set a pref if the value is the same */
- if (originalValue == prefValue)
- continue;
-
- pendingActions.push({'action': action, 'type': prefType, 'name': prefName, 'value': prefValue, 'Iid': prefIid});
-
- /* Push original preference value or clear into cleanup array */
- var cleanupTodo = {'action': action, 'type': prefType, 'name': prefName, 'value': originalValue, 'Iid': prefIid};
- if (originalValue == null) {
- cleanupTodo.action = 'clear';
- } else {
- cleanupTodo.action = 'set';
- }
- cleanupActions.push(cleanupTodo);
- }
- }
-
- if (pendingActions.length > 0) {
- this._prefEnvUndoStack.push(cleanupActions);
- this._pendingPrefs.push([pendingActions, callback]);
- this._applyPrefs();
- } else {
- content.window.setTimeout(callback, 0);
- }
- },
-
- popPrefEnv: function(callback) {
- if (this._prefEnvUndoStack.length > 0) {
- /* Each pop will have a valid block of preferences */
- this._pendingPrefs.push([this._prefEnvUndoStack.pop(), callback]);
- this._applyPrefs();
- } else {
- content.window.setTimeout(callback, 0);
- }
- },
-
- flushPrefEnv: function(callback) {
- while (this._prefEnvUndoStack.length > 1)
- this.popPrefEnv(null);
-
- this.popPrefEnv(callback);
- },
-
- /*
- Iterate through one atomic set of pref actions and perform sets/clears as appropriate.
- All actions performed must modify the relevant pref.
- */
- _applyPrefs: function() {
- if (this._applyingPrefs || this._pendingPrefs.length <= 0) {
- return;
- }
-
- /* Set lock and get prefs from the _pendingPrefs queue */
- this._applyingPrefs = true;
- var transaction = this._pendingPrefs.shift();
- var pendingActions = transaction[0];
- var callback = transaction[1];
-
- var lastPref = pendingActions[pendingActions.length-1];
- this._addObserver(lastPref.name, callback, true);
-
- for (var idx in pendingActions) {
- var pref = pendingActions[idx];
- if (pref.action == 'set') {
- this._setPref(pref.name, pref.type, pref.value, pref.Iid);
- } else if (pref.action == 'clear') {
- this.clearUserPref(pref.name);
- }
- }
- },
-
- _addObserver: function(aTopic, aCallback, aIsPref) {
- var observer = new Observer(this, aTopic, aCallback, aIsPref);
-
- if (aIsPref) {
- var os = Cc["@mozilla.org/preferences-service;1"].getService()
- .QueryInterface(Ci.nsIPrefBranch2);
- os.addObserver(aTopic, observer, false);
- } else {
- var os = Cc["@mozilla.org/observer-service;1"]
- .getService(Ci.nsIObserverService)
- .QueryInterface(Ci.nsIObserverService);
- os.addObserver(observer, aTopic, false);
- }
- },
-
- /* called from the observer when we get a pref:changed. */
- _finishPrefEnv: function() {
- /*
- Any subsequent pref environment pushes that occurred while waiting
- for the preference update are pending, and will now be executed.
- */
- this.wrappedJSObject.SpecialPowers._applyingPrefs = false;
- this.wrappedJSObject.SpecialPowers._applyPrefs();
- },
-
- // 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);
- },
-
- 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();
- },
-};
-