Back out 14463b9d2d14 and 97d43d93ab55 (Bug 621363 and Bug 676274) because of mochitest-browser-chrome leaks
authorMatt Brubeck <mbrubeck@mozilla.com>
Fri, 26 Aug 2011 15:28:28 -0700
changeset 77280 4dc1e45afdd7282835ea2081ce334176ee30d51a
parent 77279 b721f8ec43b71d10d1c507ec002351233d3b6a29
child 77281 0938cf5252cd5ea0b79c4c165385bbf170418a76
push id78
push userclegnitto@mozilla.com
push dateFri, 16 Dec 2011 17:32:24 +0000
treeherdermozilla-release@79d24e644fdd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs621363, 676274
milestone9.0a1
backs out14463b9d2d143045b7d88b601207f9dcd5a0e45d
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Back out 14463b9d2d14 and 97d43d93ab55 (Bug 621363 and Bug 676274) because of mochitest-browser-chrome leaks
content/events/test/test_bug648573.html
content/events/test/test_bug662678.html
layout/base/tests/chrome/chrome_content_integration_window.xul
layout/style/test/test_bug389464.html
layout/style/test/test_bug401046.html
layout/style/test/test_pointer-events.html
testing/mochitest/Makefile.in
testing/mochitest/browser-test-overlay.xul
testing/mochitest/browser-test.js
testing/mochitest/harness-overlay.xul
testing/mochitest/jar.mn
testing/mochitest/redirect.html
testing/mochitest/redirect.js
testing/mochitest/runtests.py
testing/mochitest/specialpowers/components/SpecialPowersObserver.js
testing/mochitest/specialpowers/content/specialpowers.js
testing/mochitest/specialpowers/jar.mn
testing/mochitest/tests/SimpleTest/ChromePowers.js
testing/mochitest/tests/SimpleTest/Makefile.in
testing/mochitest/tests/SimpleTest/SimpleTest.js
testing/mochitest/tests/SimpleTest/SpecialPowersObserverAPI.js
testing/mochitest/tests/SimpleTest/TestRunner.js
testing/mochitest/tests/SimpleTest/specialpowersAPI.js
--- 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,&lt;div style='position:absolute;left:0;top:0;width:100%;height:100px;background:yellow;border-bottom:100px solid black'&gt;"/>
     <!-- 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();
-  },
-};
-