Merge m-c to fx-team
authorPanos Astithas <past@mozilla.com>
Fri, 24 Aug 2012 10:27:21 +0300
changeset 103230 1c0ac073dc650d335197c2b14501605de264e4db
parent 103229 844da7b047d2a07984844c795b8cb9d2e529bd07 (current diff)
parent 103228 eccef9b3f1f1a82b6d9753b7b518964a52b4ea50 (diff)
child 103231 b3c4235d1300c55027f95e079d2fd85f85843a3a
child 103236 d6b2e1f60d02c7ef137059c55afbb063b8a45713
push id23335
push userpastithas@mozilla.com
push dateFri, 24 Aug 2012 07:30:03 +0000
treeherdermozilla-central@1c0ac073dc65 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone17.0a1
first release with
nightly linux32
1c0ac073dc65 / 17.0a1 / 20120824030530 / files
nightly linux64
1c0ac073dc65 / 17.0a1 / 20120824030530 / files
nightly mac
1c0ac073dc65 / 17.0a1 / 20120824030530 / files
nightly win32
1c0ac073dc65 / 17.0a1 / 20120824030530 / files
nightly win64
1c0ac073dc65 / 17.0a1 / 20120824030530 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to fx-team
content/base/public/nsBlobProtocolHandler.h
ipc/glue/IPCSerializableParams.ipdlh
netwerk/base/public/nsIIPCSerializableObsolete.idl
xpcom/tests/unit/test_seek_multiplex.js
--- a/accessible/src/jsat/TouchAdapter.jsm
+++ b/accessible/src/jsat/TouchAdapter.jsm
@@ -80,48 +80,51 @@ var TouchAdapter = {
     if (Utils.OS != 'Android')
       Mouse2Touch.detach(aWindow);
 
     delete this.chromeWin;
   },
 
   handleEvent: function TouchAdapter_handleEvent(aEvent) {
     let touches = aEvent.changedTouches;
+    // XXX: Until bug 77992 is resolved, on desktop we get microseconds
+    // instead of milliseconds.
+    let timeStamp = (Utils.OS == 'Android') ? aEvent.timeStamp : Date.now();
     switch (aEvent.type) {
       case 'touchstart':
         for (var i = 0; i < touches.length; i++) {
           let touch = touches[i];
-          let touchPoint = new TouchPoint(touch, aEvent.timeStamp, this._dpi);
+          let touchPoint = new TouchPoint(touch, timeStamp, this._dpi);
           this._touchPoints[touch.identifier] = touchPoint;
-          this._lastExploreTime = aEvent.timeStamp + this.SWIPE_MAX_DURATION;
+          this._lastExploreTime = timeStamp + this.SWIPE_MAX_DURATION;
         }
         this._dwellTimeout = this.chromeWin.setTimeout(
           (function () {
-             this.compileAndEmit(aEvent.timeStamp + this.DWELL_THRESHOLD);
+             this.compileAndEmit(timeStamp + this.DWELL_THRESHOLD);
            }).bind(this), this.DWELL_THRESHOLD);
         break;
       case 'touchmove':
         for (var i = 0; i < touches.length; i++) {
           let touch = touches[i];
           let touchPoint = this._touchPoints[touch.identifier];
-          touchPoint.update(touch, aEvent.timeStamp);
+          touchPoint.update(touch, timeStamp);
         }
-        if (aEvent.timeStamp - this._lastExploreTime >= EXPLORE_THROTTLE) {
-          this.compileAndEmit(aEvent.timeStamp);
-          this._lastExploreTime = aEvent.timeStamp;
+        if (timeStamp - this._lastExploreTime >= EXPLORE_THROTTLE) {
+          this.compileAndEmit(timeStamp);
+          this._lastExploreTime = timeStamp;
         }
         break;
       case 'touchend':
         for (var i = 0; i < touches.length; i++) {
           let touch = touches[i];
           let touchPoint = this._touchPoints[touch.identifier];
-          touchPoint.update(touch, aEvent.timeStamp);
+          touchPoint.update(touch, timeStamp);
           touchPoint.finish();
         }
-        this.compileAndEmit(aEvent.timeStamp);
+        this.compileAndEmit(timeStamp);
         break;
     }
   },
 
   cleanupTouches: function cleanupTouches() {
     for (var identifier in this._touchPoints) {
       if (!this._touchPoints[identifier].done)
         continue;
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -510,16 +510,18 @@ pref("dom.ipc.processPriorityManager.ena
 pref("dom.ipc.processPriorityManager.gracePeriodMS", 1000);
 pref("hal.processPriorityManager.gonk.masterOomAdjust", 0);
 pref("hal.processPriorityManager.gonk.foregroundOomAdjust", 1);
 pref("hal.processPriorityManager.gonk.backgroundOomAdjust", 2);
 pref("hal.processPriorityManager.gonk.masterNice", -1);
 pref("hal.processPriorityManager.gonk.foregroundNice", 0);
 pref("hal.processPriorityManager.gonk.backgroundNice", 10);
 
+#ifndef DEBUG
 // Enable pre-launching content processes for improved startup time
 // (hiding latency).
 pref("dom.ipc.processPrelauch.enabled", true);
 // Wait this long before pre-launching a new subprocess.
 pref("dom.ipc.processPrelauch.delayMs", 1000);
+#endif
 
 // Ignore the "dialog=1" feature in window.open.
 pref("dom.disable_window_open_dialog_feature", true);
--- a/browser/base/content/test/test_contextmenu.html
+++ b/browser/base/content/test/test_contextmenu.html
@@ -47,23 +47,23 @@ function openContextMenuFor(element, shi
 function closeContextMenu() {
     contextMenu.hidePopup();
 }
 
 function executeCopyCommand(command, expectedValue)
 {
   // Just execute the command directly rather than simulating a context menu
   // press to avoid having to deal with its asynchronous nature
-  subwindow.controllers.getControllerForCommand(command).doCommand(command);
+  SpecialPowers.wrap(subwindow).controllers.getControllerForCommand(command).doCommand(command);
 
   // The easiest way to check the clipboard is to paste the contents into a
   // textbox
   input.focus();
   input.value = "";
-  input.controllers.getControllerForCommand("cmd_paste").doCommand("cmd_paste");
+  SpecialPowers.wrap(input).controllers.getControllerForCommand("cmd_paste").doCommand("cmd_paste");
   is(input.value, expectedValue, "paste for command " + command);
 }
 
 function invokeItemAction(generatedItemId)
 {
   var item = contextMenu.getElementsByAttribute("generateditemid",
                                                 generatedItemId)[0];
   ok(item, "Got generated XUL menu item");
@@ -245,17 +245,16 @@ function checkMenu(menu, expectedItems, 
  *
  * Called by a popupshowing event handler. Each test checks for expected menu
  * contents, closes the popup, and finally triggers the popup on a new element
  * (thus kicking off another cycle).
  *
  */
 function runTest(testNum) {
   // Seems we need to enable this again, or sendKeyEvent() complaints.
-  netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
   ok(true, "Starting test #" + testNum);
 
   var inspectItems = [];
   if (SpecialPowers.getBoolPref("devtools.inspector.enabled")) {
     inspectItems = ["---", null,
                     "context-inspect", true];
   }
 
--- a/browser/devtools/debugger/debugger-controller.js
+++ b/browser/devtools/debugger/debugger-controller.js
@@ -180,24 +180,31 @@ let DebuggerController = {
     this.client.close();
 
     this.client = null;
     this.tabClient = null;
     this.activeThread = null;
   },
 
   /**
-   * This function is called on each location change in this tab.
+   * Starts debugging the current tab. This function is called on each location
+   * change in this tab.
    */
   _onTabNavigated: function DC__onTabNavigated(aNotification, aPacket) {
-    DebuggerController.ThreadState._handleTabNavigation(function() {
-      DebuggerController.StackFrames._handleTabNavigation(function() {
-        DebuggerController.SourceScripts._handleTabNavigation();
-      });
-    });
+    let client = this.client;
+
+    client.activeThread.detach(function() {
+      client.activeTab.detach(function() {
+        client.listTabs(function(aResponse) {
+          let tab = aResponse.tabs[aResponse.selected];
+          this._startDebuggingTab(client, tab);
+          this.dispatchEvent("Debugger:Connecting");
+        }.bind(this));
+      }.bind(this));
+    }.bind(this));
   },
 
   /**
    * Stops debugging the current tab.
    */
   _onTabDetached: function DC__onTabDetached() {
     this.dispatchEvent("Debugger:Close");
   },
@@ -315,17 +322,17 @@ ThreadState.prototype = {
    * @param function aCallback
    *        The next function in the initialization sequence.
    */
   connect: function TS_connect(aCallback) {
     this.activeThread.addListener("paused", this._update);
     this.activeThread.addListener("resumed", this._update);
     this.activeThread.addListener("detached", this._update);
 
-    this._handleTabNavigation();
+    this._update();
 
     aCallback && aCallback();
   },
 
   /**
    * Disconnect from the client.
    */
   disconnect: function TS_disconnect() {
@@ -333,25 +340,16 @@ ThreadState.prototype = {
       return;
     }
     this.activeThread.removeListener("paused", this._update);
     this.activeThread.removeListener("resumed", this._update);
     this.activeThread.removeListener("detached", this._update);
   },
 
   /**
-   * Handles any initialization on a tab navigation event issued by the client.
-   */
-  _handleTabNavigation: function TS__handleTabNavigation(aCallback) {
-    DebuggerView.StackFrames.updateState(this.activeThread.state);
-
-    aCallback && aCallback();
-  },
-
-  /**
    * Update the UI after a thread state change.
    */
   _update: function TS__update(aEvent) {
     DebuggerView.StackFrames.updateState(this.activeThread.state);
   }
 };
 
 /**
@@ -394,64 +392,55 @@ StackFrames.prototype = {
   /**
    * Watch the given thread client.
    *
    * @param function aCallback
    *        The next function in the initialization sequence.
    */
   connect: function SF_connect(aCallback) {
     window.addEventListener("Debugger:FetchedVariables", this._onFetchedVars, false);
+
     this.activeThread.addListener("paused", this._onPaused);
     this.activeThread.addListener("resumed", this._onResume);
     this.activeThread.addListener("framesadded", this._onFrames);
     this.activeThread.addListener("framescleared", this._onFramesCleared);
 
-    this._handleTabNavigation();
     this.updatePauseOnExceptions(this.pauseOnExceptions);
 
     aCallback && aCallback();
   },
 
   /**
    * Disconnect from the client.
    */
   disconnect: function SF_disconnect() {
+    window.removeEventListener("Debugger:FetchedVariables", this._onFetchedVars, false);
+
     if (!this.activeThread) {
       return;
     }
-    window.removeEventListener("Debugger:FetchedVariables", this._onFetchedVars, false);
     this.activeThread.removeListener("paused", this._onPaused);
     this.activeThread.removeListener("resumed", this._onResume);
     this.activeThread.removeListener("framesadded", this._onFrames);
     this.activeThread.removeListener("framescleared", this._onFramesCleared);
   },
 
   /**
-   * Handles any initialization on a tab navigation event issued by the client.
-   */
-  _handleTabNavigation: function SF__handleTabNavigation(aCallback) {
-    // Nothing to do here yet.
-
-    aCallback && aCallback();
-  },
-
-  /**
    * Handler for the thread client's paused notification.
    *
    * @param string aEvent
    *        The name of the notification ("paused" in this case).
    * @param object aPacket
    *        The response packet.
    */
   _onPaused: function SF__onPaused(aEvent, aPacket) {
     // In case the pause was caused by an exception, store the exception value.
     if (aPacket.why.type == "exception") {
       this.exception = aPacket.why.exception;
     }
-
     this.activeThread.fillFrames(this.pageSize);
     DebuggerView.editor.focus();
   },
 
   /**
    * Handler for the thread client's resumed notification.
    */
   _onResume: function SF__onResume() {
@@ -840,16 +829,17 @@ StackFrames.prototype = {
 
 /**
  * Keeps the source script list up-to-date, using the thread client's
  * source script cache.
  */
 function SourceScripts() {
   this._onNewScript = this._onNewScript.bind(this);
   this._onScriptsAdded = this._onScriptsAdded.bind(this);
+  this._onScriptsCleared = this._onScriptsCleared.bind(this);
   this._onShowScript = this._onShowScript.bind(this);
   this._onLoadSource = this._onLoadSource.bind(this);
   this._onLoadSourceFinished = this._onLoadSourceFinished.bind(this);
 }
 
 SourceScripts.prototype = {
 
   /**
@@ -874,107 +864,91 @@ SourceScripts.prototype = {
   /**
    * Watch the given thread client.
    *
    * @param function aCallback
    *        The next function in the initialization sequence.
    */
   connect: function SS_connect(aCallback) {
     window.addEventListener("Debugger:LoadSource", this._onLoadSource, false);
+
     this.debuggerClient.addListener("newScript", this._onNewScript);
+    this.activeThread.addListener("scriptsadded", this._onScriptsAdded);
+    this.activeThread.addListener("scriptscleared", this._onScriptsCleared);
 
-    this._handleTabNavigation();
+    this._clearLabelsCache();
+    this._onScriptsCleared();
+
+    // Retrieve the list of scripts known to the server from before the client
+    // was ready to handle new script notifications.
+    this.activeThread.fillScripts();
 
     aCallback && aCallback();
   },
 
   /**
    * Disconnect from the client.
    */
-  disconnect: function SS_disconnect() {
+  disconnect: function TS_disconnect() {
+    window.removeEventListener("Debugger:LoadSource", this._onLoadSource, false);
+
     if (!this.activeThread) {
       return;
     }
-    window.removeEventListener("Debugger:LoadSource", this._onLoadSource, false);
     this.debuggerClient.removeListener("newScript", this._onNewScript);
-  },
-
-  /**
-   * Handles any initialization on a tab navigation event issued by the client.
-   */
-  _handleTabNavigation: function SS__handleTabNavigation(aCallback) {
-    this._clearLabelsCache();
-    this._onScriptsCleared();
-
-    // Retrieve the list of scripts known to the server from before the client
-    // was ready to handle new script notifications.
-    this.activeThread.getScripts(this._onScriptsAdded);
-
-    aCallback && aCallback();
+    this.activeThread.removeListener("scriptsadded", this._onScriptsAdded);
+    this.activeThread.removeListener("scriptscleared", this._onScriptsCleared);
   },
 
   /**
    * Handler for the debugger client's unsolicited newScript notification.
    */
   _onNewScript: function SS__onNewScript(aNotification, aPacket) {
     // Ignore scripts generated from 'clientEvaluate' packets.
     if (aPacket.url == "debugger eval code") {
       return;
     }
 
     this._addScript({ url: aPacket.url, startLine: aPacket.startLine }, true);
 
-    let preferredScriptUrl = DebuggerView.Scripts.preferredScriptUrl;
-
-    // Select this script if it's the preferred one.
+    // Select the script if it's the preferred one.
     if (aPacket.url === DebuggerView.Scripts.preferredScriptUrl) {
       DebuggerView.Scripts.selectScript(aPacket.url);
     }
-    // ..or the first entry if there's not one selected yet.
-    else if (!DebuggerView.Scripts.selected) {
-      DebuggerView.Scripts.selectIndex(0);
-    }
 
     // If there are any stored breakpoints for this script, display them again,
     // both in the editor and the pane.
     for each (let breakpoint in DebuggerController.Breakpoints.store) {
       if (breakpoint.location.url == aPacket.url) {
         DebuggerController.Breakpoints.displayBreakpoint(breakpoint);
       }
     }
-
-    DebuggerController.dispatchEvent("Debugger:AfterNewScript");
   },
 
   /**
-   * Callback for the getScripts() method.
+   * Handler for the thread client's scriptsadded notification.
    */
-  _onScriptsAdded: function SS__onScriptsAdded(aResponse) {
-    for each (let script in aResponse.scripts) {
+  _onScriptsAdded: function SS__onScriptsAdded() {
+    for each (let script in this.activeThread.cachedScripts) {
       this._addScript(script, false);
     }
     DebuggerView.Scripts.commitScripts();
     DebuggerController.Breakpoints.updatePaneBreakpoints();
 
+    // Select the preferred script if one exists, the first entry otherwise.
     let preferredScriptUrl = DebuggerView.Scripts.preferredScriptUrl;
-
-    // Select the preferred script if it exists and was part of the response.
     if (preferredScriptUrl && DebuggerView.Scripts.contains(preferredScriptUrl)) {
       DebuggerView.Scripts.selectScript(preferredScriptUrl);
-    }
-    // ..or the first entry if there's not one selected yet.
-    else if (!DebuggerView.Scripts.selected) {
+    } else {
       DebuggerView.Scripts.selectIndex(0);
     }
-
-    DebuggerController.dispatchEvent("Debugger:AfterScriptsAdded");
   },
 
   /**
-   * Called during navigation to clear the currently-loaded scripts.
+   * Handler for the thread client's scriptscleared notification.
    */
   _onScriptsCleared: function SS__onScriptsCleared() {
     DebuggerView.Scripts.empty();
     DebuggerView.Breakpoints.emptyText();
     DebuggerView.editor.setText("");
   },
 
   /**
--- a/browser/devtools/debugger/test/browser_dbg_bfcache.js
+++ b/browser/devtools/debugger/test/browser_dbg_bfcache.js
@@ -35,62 +35,50 @@ function testInitialLoad() {
   });
 
   gDebuggee.firstCall();
 }
 
 function testLocationChange()
 {
   gDebugger.DebuggerController.activeThread.resume(function() {
-    gDebugger.DebuggerController.client.addOneTimeListener("tabNavigated", function(aEvent, aPacket) {
-      ok(true, "tabNavigated event was fired.");
-      info("Still attached to the tab.");
-
-      gDebugger.addEventListener("Debugger:AfterScriptsAdded", function _onEvent(aEvent) {
-        gDebugger.removeEventListener(aEvent.type, _onEvent);
-
+    gDebugger.DebuggerController.client.addOneTimeListener("tabAttached", function(aEvent, aPacket) {
+      ok(true, "Successfully reattached to the tab again.");
+      gDebugger.DebuggerController.client.addOneTimeListener("resumed", function(aEvent, aPacket) {
         executeSoon(function() {
           validateSecondPage();
           testBack();
         });
       });
     });
     content.location = STACK_URL;
   });
 }
 
 function testBack()
 {
-  gDebugger.DebuggerController.client.addOneTimeListener("tabNavigated", function(aEvent, aPacket) {
-    ok(true, "tabNavigated event was fired after going back.");
-    info("Still attached to the tab.");
-
-    gDebugger.addEventListener("Debugger:AfterScriptsAdded", function _onEvent(aEvent) {
-      gDebugger.removeEventListener(aEvent.type, _onEvent);
-
+  gDebugger.DebuggerController.client.addOneTimeListener("tabAttached", function(aEvent, aPacket) {
+    ok(true, "Successfully reattached to the tab after going back.");
+    gDebugger.DebuggerController.client.addOneTimeListener("resumed", function(aEvent, aPacket) {
       executeSoon(function() {
         validateFirstPage();
         testForward();
       });
     });
   });
 
   info("Going back.");
   content.history.back();
 }
 
 function testForward()
 {
-  gDebugger.DebuggerController.client.addOneTimeListener("tabNavigated", function(aEvent, aPacket) {
-    ok(true, "tabNavigated event was fired after going forward.");
-    info("Still attached to the tab.");
-
-    gDebugger.addEventListener("Debugger:AfterScriptsAdded", function _onEvent(aEvent) {
-      gDebugger.removeEventListener(aEvent.type, _onEvent);
-
+  gDebugger.DebuggerController.client.addOneTimeListener("tabAttached", function(aEvent, aPacket) {
+    ok(true, "Successfully reattached to the tab after going forward.");
+    gDebugger.DebuggerController.client.addOneTimeListener("resumed", function(aEvent, aPacket) {
       executeSoon(function() {
         validateSecondPage();
         closeDebuggerAndFinish();
       });
     });
   });
 
   info("Going forward.");
--- a/browser/devtools/debugger/test/browser_dbg_location-changes-blank.js
+++ b/browser/devtools/debugger/test/browser_dbg_location-changes-blank.js
@@ -52,34 +52,35 @@ function testSimpleCall() {
   gDebuggee.simpleCall();
 }
 
 function testLocationChange()
 {
   gDebugger.DebuggerController.activeThread.resume(function() {
     gDebugger.DebuggerController.client.addOneTimeListener("tabNavigated", function(aEvent, aPacket) {
       ok(true, "tabNavigated event was fired.");
-      info("Still attached to the tab.");
+      gDebugger.DebuggerController.client.addOneTimeListener("tabAttached", function(aEvent, aPacket) {
+        ok(true, "Successfully reattached to the tab again.");
 
-      gDebugger.addEventListener("Debugger:AfterScriptsAdded", function _onEvent(aEvent) {
-        gDebugger.removeEventListener(aEvent.type, _onEvent);
+        // Wait for the initial resume...
+        gDebugger.gClient.addOneTimeListener("resumed", function() {
+          is(gDebugger.DebuggerView.Scripts.selected, null,
+            "There should be no selected script.");
+          is(gDebugger.editor.getText().length, 0,
+            "The source editor not have any text displayed.");
 
-        is(gDebugger.DebuggerView.Scripts.selected, null,
-          "There should be no selected script.");
-        is(gDebugger.editor.getText().length, 0,
-          "The source editor not have any text displayed.");
+          let menulist = gDebugger.DebuggerView.Scripts._scripts;
+          let noScripts = gDebugger.L10N.getStr("noScriptsText");
+          is(menulist.getAttribute("label"), noScripts,
+            "The menulist should display a notice that there are no scripts availalble.");
+          is(menulist.getAttribute("tooltiptext"), "",
+            "The menulist shouldn't have any tooltip text attributed when there are no scripts available.");
 
-        let menulist = gDebugger.DebuggerView.Scripts._scripts;
-        let noScripts = gDebugger.L10N.getStr("noScriptsText");
-        is(menulist.getAttribute("label"), noScripts,
-          "The menulist should display a notice that there are no scripts availalble.");
-        is(menulist.getAttribute("tooltiptext"), "",
-          "The menulist shouldn't have any tooltip text attributed when there are no scripts available.");
-
-        closeDebuggerAndFinish();
+          closeDebuggerAndFinish();
+        });
       });
     });
     content.location = "about:blank";
   });
 }
 
 registerCleanupFunction(function() {
   removeTab(gTab);
--- a/browser/devtools/debugger/test/browser_dbg_location-changes-new.js
+++ b/browser/devtools/debugger/test/browser_dbg_location-changes-new.js
@@ -52,34 +52,35 @@ function testSimpleCall() {
   gDebuggee.simpleCall();
 }
 
 function testLocationChange()
 {
   gDebugger.DebuggerController.activeThread.resume(function() {
     gDebugger.DebuggerController.client.addOneTimeListener("tabNavigated", function(aEvent, aPacket) {
       ok(true, "tabNavigated event was fired.");
-      info("Still attached to the tab.");
+      gDebugger.DebuggerController.client.addOneTimeListener("tabAttached", function(aEvent, aPacket) {
+        ok(true, "Successfully reattached to the tab again.");
 
-      gDebugger.addEventListener("Debugger:AfterScriptsAdded", function _onEvent(aEvent) {
-        gDebugger.removeEventListener(aEvent.type, _onEvent);
+        // Wait for the initial resume...
+        gDebugger.gClient.addOneTimeListener("resumed", function() {
+          isnot(gDebugger.DebuggerView.Scripts.selected, null,
+            "There should be a selected script.");
+          isnot(gDebugger.editor.getText().length, 0,
+            "The source editor should have some text displayed.");
 
-        isnot(gDebugger.DebuggerView.Scripts.selected, null,
-          "There should be a selected script.");
-        isnot(gDebugger.editor.getText().length, 0,
-          "The source editor should have some text displayed.");
+          let menulist = gDebugger.DebuggerView.Scripts._scripts;
+          let noScripts = gDebugger.L10N.getStr("noScriptsText");
+          isnot(menulist.getAttribute("label"), noScripts,
+            "The menulist should not display a notice that there are no scripts availalble.");
+          isnot(menulist.getAttribute("tooltiptext"), "",
+            "The menulist should have a tooltip text attributed.");
 
-        let menulist = gDebugger.DebuggerView.Scripts._scripts;
-        let noScripts = gDebugger.L10N.getStr("noScriptsText");
-        isnot(menulist.getAttribute("label"), noScripts,
-          "The menulist should not display a notice that there are no scripts availalble.");
-        isnot(menulist.getAttribute("tooltiptext"), "",
-          "The menulist should have a tooltip text attributed.");
-
-        closeDebuggerAndFinish();
+          closeDebuggerAndFinish();
+        });
       });
     });
     content.location = EXAMPLE_URL + "browser_dbg_iframes.html";
   });
 }
 
 registerCleanupFunction(function() {
   removeTab(gTab);
--- a/browser/devtools/debugger/test/browser_dbg_location-changes.js
+++ b/browser/devtools/debugger/test/browser_dbg_location-changes.js
@@ -47,19 +47,21 @@ function testSimpleCall() {
   gDebuggee.simpleCall();
 }
 
 function testLocationChange()
 {
   gDebugger.DebuggerController.activeThread.resume(function() {
     gDebugger.DebuggerController.client.addOneTimeListener("tabNavigated", function(aEvent, aPacket) {
       ok(true, "tabNavigated event was fired.");
-      info("Still attached to the tab.");
+      gDebugger.DebuggerController.client.addOneTimeListener("tabAttached", function(aEvent, aPacket) {
+        ok(true, "Successfully reattached to the tab again.");
 
-      closeDebuggerAndFinish();
+        closeDebuggerAndFinish();
+      });
     });
     content.location = TAB1_URL;
   });
 }
 
 registerCleanupFunction(function() {
   removeTab(gTab);
   gPane = null;
--- a/browser/themes/pinstripe/browser.css
+++ b/browser/themes/pinstripe/browser.css
@@ -1523,23 +1523,23 @@ window[tabsontop="false"] richlistitem[t
 #editBookmarkPanel .expander-up {
   list-style-image: url("chrome://browser/skin/panel-expander-open.png");
 }
 
 #editBookmarkPanel .expander-down {
   list-style-image: url("chrome://browser/skin/panel-expander-closed.png");
 }
 
-#editBookmarkPanel .expander-up .button-icon,
-#editBookmarkPanel .expander-down .button-icon {
+#editBookmarkPanel .expander-up > .button-box > .button-icon,
+#editBookmarkPanel .expander-down > .button-box > .button-icon {
   margin: 1px 0 0;
 }
 
-#editBookmarkPanel .expander-up .button-text,
-#editBookmarkPanel .expander-down .button-text {
+#editBookmarkPanel .expander-up > .button-box > .button-text,
+#editBookmarkPanel .expander-down > .button-box > .button-text {
   display: none;
 }
 
 #editBMPanel_tagsField > .autocomplete-textbox-container > .textbox-input-box > html|*.textbox-input:-moz-placeholder {
   color: #bbb;
 }
 
 .editBMPanel_rowLabel {
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -429,38 +429,23 @@ user_pref("extensions.hotfix.url", "http
 // Make sure opening about:addons won't hit the network
 user_pref("extensions.webservice.discoverURL", "http://%(server)s/extensions-dummy/discoveryURL");
 // Make sure AddonRepository won't hit the network
 user_pref("extensions.getAddons.maxResults", 0);
 user_pref("extensions.getAddons.get.url", "http://%(server)s/extensions-dummy/repositoryGetURL");
 user_pref("extensions.getAddons.getWithPerformance.url", "http://%(server)s/extensions-dummy/repositoryGetWithPerformanceURL");
 user_pref("extensions.getAddons.search.browseURL", "http://%(server)s/extensions-dummy/repositoryBrowseURL");
 user_pref("extensions.getAddons.search.url", "http://%(server)s/extensions-dummy/repositorySearchURL");
+
+// Make enablePrivilege continue to work for test code. :-(
+user_pref("security.enablePrivilege.enable_for_tests", true);
 """ % { "server" : self.webServer + ":" + str(self.httpPort) }
     prefs.append(part)
 
-    if useServerLocations == False:
-      part = """
-user_pref("capability.principal.codebase.p1.granted", "UniversalXPConnect");
-user_pref("capability.principal.codebase.p1.id", "%(origin)s");
-user_pref("capability.principal.codebase.p1.subjectName", "");
-"""  % { "origin": "http://" + self.webServer + ":" + str(self.httpPort) }
-      prefs.append(part)
-    else:
-      # Grant God-power to all the privileged servers on which tests run.
-      privileged = filter(lambda loc: "privileged" in loc.options, locations)
-      for (i, l) in itertools.izip(itertools.count(1), privileged):
-        part = """
-user_pref("capability.principal.codebase.p%(i)d.granted", "UniversalXPConnect");
-user_pref("capability.principal.codebase.p%(i)d.id", "%(origin)s");
-user_pref("capability.principal.codebase.p%(i)d.subjectName", "");
-"""  % { "i": i,
-         "origin": (l.scheme + "://" + l.host + ":" + str(l.port)) }
-        prefs.append(part)
-
+    if useServerLocations:
       # We need to proxy every server but the primary one.
       origins = ["'%s://%s:%s'" % (l.scheme, l.host, l.port)
                 for l in filter(lambda l: "primary" not in l.options, locations)]
       origins = ", ".join(origins)
 
       pacURL = """data:text/plain,
 function FindProxyForURL(url, host)
 {
--- a/build/mobile/b2gemulator.py
+++ b/build/mobile/b2gemulator.py
@@ -24,20 +24,27 @@ class B2GEmulator(Emulator):
 
     def _check_file(self, filePath):
         if not os.path.exists(filePath):
             raise Exception(('File not found: %s; did you pass the B2G home '
                              'directory as the homedir parameter, or set '
                              'B2G_HOME correctly?') % filePath)
 
     def _check_for_adb(self, host_dir):
-        self.adb = os.path.join(self.homedir, 'out', 'host', host_dir, 'bin', 'adb')
-        if not os.path.exists(self.adb):
-            self.adb = os.path.join(self.homedir, 'bin/adb')
-        super(B2GEmulator, self)._check_for_adb()
+        if self._default_adb() == 0:
+            return
+        adb_paths = [os.path.join(self.homedir,'glue','gonk','out','host',
+                      host_dir ,'bin','adb'),os.path.join(self.homedir, 'out',
+                      'host', host_dir,'bin','adb'),os.path.join(self.homedir,
+                      'bin','adb')]
+        for option in adb_paths:
+            if os.path.exists(option):
+                self.adb = option
+                return
+        raise Exception('adb not found!')
 
     def _locate_files(self):
         if self.homedir is None:
             self.homedir = os.getenv('B2G_HOME')
         if self.homedir is None:
             raise Exception('Must define B2G_HOME or pass the homedir parameter')
         self._check_file(self.homedir)
 
--- a/build/mobile/devicemanagerADB.py
+++ b/build/mobile/devicemanagerADB.py
@@ -285,27 +285,24 @@ class DeviceManagerADB(DeviceManager):
               else:
                   out += self.removeFile(remoteDir.strip() + "/" + f.strip())
           out += self.removeSingleDir(remoteDir.strip())
       else:
           out += self.removeFile(remoteDir.strip())
       return out
 
   def isDir(self, remotePath):
-      p = self.runCmd(["shell", "ls", "-a", remotePath])
+      p = self.runCmd(["shell", "ls", "-a", remotePath + '/'])
+
       data = p.stdout.readlines()
-      if (len(data) == 0):
-          return True
-      if (len(data) == 1):
-          if (data[0].rstrip() == remotePath):
+      if len(data) == 1:
+          res = data[0]
+          if "Not a directory" in res or "No such file or directory" in res:
               return False
-          if (data[0].find("No such file or directory") != -1):
-              return False
-          if (data[0].find("Not a directory") != -1):
-              return False
+
       return True
 
   def listFiles(self, rootdir):
       p = self.runCmd(["shell", "ls", "-a", rootdir])
       data = p.stdout.readlines()
       data[:] = [item.rstrip('\r\n') for item in data]
       if (len(data) == 1):
           if (data[0] == rootdir):
--- a/build/mobile/emulator.py
+++ b/build/mobile/emulator.py
@@ -82,27 +82,29 @@ class Emulator(object):
 
     @property
     def is_running(self):
         if self._emulator_launched:
             return self.proc is not None and self.proc.poll() is None
         else:
             return self.port is not None
 
+    def _default_adb(self):
+        adb = subprocess.Popen(['which', 'adb'],
+                               stdout=subprocess.PIPE,
+                               stderr=subprocess.STDOUT)
+        retcode = adb.wait()
+        if retcode == 0:
+            self.adb = adb.stdout.read().strip() # remove trailing newline
+        return retcode
+
     def _check_for_adb(self):
         if not os.path.exists(self.adb):
-            adb = subprocess.Popen(['which', 'adb'],
-                                   stdout=subprocess.PIPE,
-                                   stderr=subprocess.STDOUT)
-            retcode = adb.wait()
-            if retcode:
+            if self._default_adb() != 0:
                 raise Exception('adb not found!')
-            out = adb.stdout.read().strip()
-            if len(out) and out.find('/') > -1:
-                self.adb = out
 
     def _run_adb(self, args):
         args.insert(0, self.adb)
         adb = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
         retcode = adb.wait()
         if retcode:
             raise Exception('adb terminated with exit code %d: %s'
             % (retcode, adb.stdout.read()))
--- a/build/unix/build-clang/create-manifest.py
+++ b/build/unix/build-clang/create-manifest.py
@@ -1,39 +1,39 @@
 #!/bin/python
 
 import os
+import os.path
 import simplejson
 import sys
 import subprocess
 import urllib
 import glob
 
 def check_run(args):
     r = subprocess.call(args)
     assert r == 0
 
-old_files = glob.glob('*.manifest') + ['tooltool.py', 'setup.sh']
+old_files = glob.glob('*.manifest')
 for f in old_files:
     try:
         os.unlink(f)
     except:
         pass
 
-urllib.urlretrieve('https://raw.github.com/jhford/tooltool/master/tooltool.py',
-                   'tooltool.py')
-urllib.urlretrieve('https://hg.mozilla.org/mozilla-central/raw-file/tip/build/unix/build-clang/setup.sh',
-                   'setup.sh')
+basedir = os.path.split(os.path.realpath(sys.argv[0]))[0]
+tooltool = basedir + '/tooltool.py'
+setup = basedir + '/setup.sh'
 
-check_run(['python', 'tooltool.py', '-m', 'linux32.manifest', 'add',
-           'clang-linux32.tar.bz2', 'setup.sh'])
-check_run(['python', 'tooltool.py', '-m', 'linux64.manifest', 'add',
-           'clang-linux64.tar.bz2', 'setup.sh'])
-check_run(['python', 'tooltool.py', '-m', 'darwin.manifest', 'add',
-           'clang-darwin.tar.bz2', 'setup.sh'])
+check_run(['python', tooltool, '-m', 'linux32.manifest', 'add',
+           'clang-linux32.tar.bz2', setup])
+check_run(['python', tooltool, '-m', 'linux64.manifest', 'add',
+           'clang-linux64.tar.bz2', setup])
+check_run(['python', tooltool, '-m', 'darwin.manifest', 'add',
+           'clang-darwin.tar.bz2', setup])
 
 def key_sort(item):
     item = item[0]
     if item == 'size':
         return 0
     if item == 'digest':
         return 1
     if item == 'algorithm':
new file mode 100644
--- /dev/null
+++ b/build/unix/build-clang/tooltool.py
@@ -0,0 +1,564 @@
+#!/usr/bin/env python
+
+#tooltool is a lookaside cache implemented in Python
+#Copyright (C) 2011 John H. Ford <john@johnford.info>
+#
+#This program is free software; you can redistribute it and/or
+#modify it under the terms of the GNU General Public License
+#as published by the Free Software Foundation version 2
+#
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+#
+#You should have received a copy of the GNU General Public License
+#along with this program; if not, write to the Free Software
+#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+# An manifest file specifies files in that directory that are stored
+# elsewhere.  This file should only contain file in the directory
+# which the manifest file resides in and it should be called 'manifest.manifest'
+
+__version__ = '1'
+
+import os
+import optparse
+import logging
+import hashlib
+import urllib2
+import ConfigParser
+try:
+    import simplejson as json # I hear simplejson is faster
+except ImportError:
+    import json
+
+log = logging.getLogger(__name__)
+
+class FileRecordJSONEncoderException(Exception): pass
+class InvalidManifest(Exception): pass
+class ExceptionWithFilename(Exception):
+    def __init__(self, filename):
+        Exception.__init__(self)
+        self.filename = filename
+
+class DigestMismatchException(ExceptionWithFilename): pass
+class MissingFileException(ExceptionWithFilename): pass
+
+class FileRecord(object):
+    def __init__(self, filename, size, digest, algorithm):
+        object.__init__(self)
+        self.filename = filename
+        self.size = size
+        self.digest = digest
+        self.algorithm = algorithm
+        log.debug("creating %s 0x%x" % (self.__class__.__name__, id(self)))
+
+    def __eq__(self, other):
+        if self is other:
+            return True
+        if self.filename == other.filename and \
+            self.size == other.size and \
+            self.digest == other.digest and \
+            self.algorithm == other.algorithm:
+            return True
+        else:
+            return False
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+    def __str__(self):
+        return repr(self)
+
+    def __repr__(self):
+        return "%s.%s(filename='%s', size='%s', digest='%s', algorithm='%s')" % (__name__,
+                self.__class__.__name__,
+                self.filename, self.size, self.digest, self.algorithm)
+
+    def present(self):
+        # Doesn't check validity
+        return os.path.exists(self.filename)
+
+    def validate_size(self):
+        if self.present():
+            return self.size == os.path.getsize(self.filename)
+        else:
+            log.debug("trying to validate size on a missing file, %s", self.filename)
+            raise MissingFileException(filename=self.filename)
+
+    def validate_digest(self):
+        if self.present():
+            with open(self.filename, 'rb') as f:
+                return self.digest == digest_file(f, self.algorithm)
+        else:
+            log.debug("trying to validate digest on a missing file, %s', self.filename")
+            raise MissingFileException(filename=self.filename)
+
+    def validate(self):
+        if self.validate_size():
+            if self.validate_digest():
+                return True
+        return False
+
+    def describe(self):
+        if self.present() and self.validate():
+            return "'%s' is present and valid" % self.filename
+        elif self.present():
+            return "'%s' is present and invalid" % self.filename
+        else:
+            return "'%s' is absent" % self.filename
+
+
+def create_file_record(filename, algorithm):
+    fo = open(filename, 'rb')
+    stored_filename = os.path.split(filename)[1]
+    fr = FileRecord(stored_filename, os.path.getsize(filename), digest_file(fo, algorithm), algorithm)
+    fo.close()
+    return fr
+
+
+class FileRecordJSONEncoder(json.JSONEncoder):
+    def encode_file_record(self, obj):
+        if not issubclass(type(obj), FileRecord):
+            err = "FileRecordJSONEncoder is only for FileRecord and lists of FileRecords, not %s" % obj.__class__.__name__
+            log.warn(err)
+            raise FileRecordJSONEncoderException(err)
+        else:
+            return {'filename': obj.filename, 'size': obj.size, 'algorithm': obj.algorithm, 'digest': obj.digest}
+
+    def default(self, f):
+        if issubclass(type(f), list):
+            record_list = []
+            for i in f:
+                record_list.append(self.encode_file_record(i))
+            return record_list
+        else:
+            return self.encode_file_record(f)
+
+
+class FileRecordJSONDecoder(json.JSONDecoder):
+    """I help the json module materialize a FileRecord from
+    a JSON file.  I understand FileRecords and lists of
+    FileRecords.  I ignore things that I don't expect for now"""
+    # TODO: make this more explicit in what it's looking for
+    # and error out on unexpected things
+    def process_file_records(self, obj):
+        if isinstance(obj, list):
+            record_list = []
+            for i in obj:
+                record = self.process_file_records(i)
+                if issubclass(type(record), FileRecord):
+                    record_list.append(record)
+            return record_list
+        if isinstance(obj, dict) and \
+           len(obj.keys()) == 4 and \
+           obj.has_key('filename') and \
+           obj.has_key('size') and \
+           obj.has_key('algorithm') and \
+           obj.has_key('digest'):
+            rv = FileRecord(obj['filename'], obj['size'], obj['digest'], obj['algorithm'])
+            log.debug("materialized %s" % rv)
+            return rv
+        return obj
+
+    def decode(self, s):
+        decoded = json.JSONDecoder.decode(self, s)
+        rv = self.process_file_records(decoded)
+        return rv
+
+
+class Manifest(object):
+
+    valid_formats = ('json',)
+
+    def __init__(self, file_records=[]):
+        self.file_records = file_records
+
+    def __eq__(self, other):
+        if self is other:
+            return True
+        if len(self.file_records) != len(other.file_records):
+            log.debug('Manifests differ in number of files')
+            return False
+        #TODO: Lists in a different order should be equal
+        for record in range(0,len(self.file_records)):
+            if self.file_records[record] != other.file_records[record]:
+                log.debug('FileRecords differ, %s vs %s' % (self.file_records[record],
+                                                            other.file_records[record]))
+                return False
+        return True
+
+    def __deepcopy__(self, memo):
+        # This is required for a deep copy
+        return Manifest(self.file_records[:])
+
+    def __copy__(self):
+        return Manifest(self.file_records)
+
+    def copy(self):
+        return Manifest(self.file_records[:])
+
+    def present(self):
+        return all(i.present() for i in self.file_records)
+
+    def validate_sizes(self):
+        return all(i.validate_size() for i in self.file_records)
+
+    def validate_digests(self):
+        return all(i.validate_digest() for i in self.file_records)
+
+    def validate(self):
+        return all(i.validate() for i in self.file_records)
+
+    def sort(self):
+        #TODO: WRITE TESTS
+        self.file_records.sort(key=lambda x: x.size)
+
+    def load(self, data_file, fmt='json'):
+        assert fmt in self.valid_formats
+        if fmt == 'json':
+            try:
+                self.file_records.extend(json.load(data_file, cls=FileRecordJSONDecoder))
+                self.sort()
+            except ValueError:
+                raise InvalidManifest("trying to read invalid manifest file")
+
+    def loads(self, data_string, fmt='json'):
+        assert fmt in self.valid_formats
+        if fmt == 'json':
+            try:
+                self.file_records.extend(json.loads(data_string, cls=FileRecordJSONDecoder))
+                self.sort()
+            except ValueError:
+                raise InvalidManifest("trying to read invalid manifest file")
+
+    def dump(self, output_file, fmt='json'):
+        assert fmt in self.valid_formats
+        self.sort()
+        if fmt == 'json':
+            rv = json.dump(self.file_records, output_file, indent=0, cls=FileRecordJSONEncoder)
+            print >> output_file, ''
+            return rv
+
+    def dumps(self, fmt='json'):
+        assert fmt in self.valid_formats
+        self.sort()
+        if fmt == 'json':
+            return json.dumps(self.file_records, cls=FileRecordJSONEncoder)
+
+
+def digest_file(f, a):
+    """I take a file like object 'f' and return a hex-string containing
+    of the result of the algorithm 'a' applied to 'f'."""
+    h = hashlib.new(a)
+    chunk_size = 1024*10
+    data = f.read(chunk_size)
+    while data:
+        h.update(data)
+        data = f.read(chunk_size)
+    if hasattr(f, 'name'):
+        log.debug('hashed %s with %s to be %s', f.name, a, h.hexdigest())
+    else:
+        log.debug('hashed a file with %s to be %s', a, h.hexdigest())
+    return h.hexdigest()
+
+# TODO: write tests for this function
+def open_manifest(manifest_file):
+    """I know how to take a filename and load it into a Manifest object"""
+    if os.path.exists(manifest_file):
+        manifest = Manifest()
+        with open(manifest_file) as f:
+            manifest.load(f)
+            log.debug("loaded manifest from file '%s'" % manifest_file)
+        return manifest
+    else:
+        log.debug("tried to load absent file '%s' as manifest" % manifest_file)
+        raise InvalidManifest("manifest file '%s' does not exist" % manifest_file)
+
+# TODO: write tests for this function
+def list_manifest(manifest_file):
+    """I know how print all the files in a location"""
+    try:
+        manifest = open_manifest(manifest_file)
+    except InvalidManifest:
+        log.error("failed to load manifest file at '%s'" % manifest_file)
+        return False
+    for f in manifest.file_records:
+        print "%s\t%s\t%s" % ("P" if f.present() else "-",
+                              "V" if f.present() and f.validate() else "-",
+                              f.filename)
+    return True
+
+def validate_manifest(manifest_file):
+    """I validate that all files in a manifest are present and valid but
+    don't fetch or delete them if they aren't"""
+    try:
+        manifest = open_manifest(manifest_file)
+    except InvalidManifest:
+        log.error("failed to load manifest file at '%s'" % manifest_file)
+        return False
+    invalid_files = []
+    absent_files = []
+    for f in manifest.file_records:
+        if not f.present():
+            absent_files.append(f)
+        else:
+            if not f.validate():
+                invalid_files.append(f)
+    if len(invalid_files + absent_files) == 0:
+        return True
+    else:
+        return False
+
+# TODO: write tests for this function
+def add_files(manifest_file, algorithm, filenames):
+    # returns True if all files successfully added, False if not
+    # and doesn't catch library Exceptions.  If any files are already
+    # tracked in the manifest, return will be False because they weren't
+    # added
+    all_files_added = True
+    # Create a old_manifest object to add to
+    if os.path.exists(manifest_file):
+        old_manifest = open_manifest(manifest_file)
+    else:
+        old_manifest = Manifest()
+        log.debug("creating a new manifest file")
+    new_manifest = Manifest() # use a different manifest for the output
+    for filename in filenames:
+        log.debug("adding %s" % filename)
+        path, name = os.path.split(filename)
+        new_fr = create_file_record(filename, algorithm)
+        log.debug("appending a new file record to manifest file")
+        add = True
+        for fr in old_manifest.file_records:
+            log.debug("manifest file has '%s'" % "', ".join([x.filename for x in old_manifest.file_records]))
+            if new_fr == fr and new_fr.validate():
+                # TODO: Decide if this case should really cause a False return
+                log.info("file already in old_manifest file and matches")
+                add = False
+            elif new_fr == fr and not new_fr.validate():
+                log.error("file already in old_manifest file but is invalid")
+                add = False
+            if filename == fr.filename:
+                log.error("manifest already contains file named %s" % filename)
+                add = False
+        if add:
+            new_manifest.file_records.append(new_fr)
+            log.debug("added '%s' to manifest" % filename)
+        else:
+            all_files_added = False
+    with open(manifest_file, 'wb') as output:
+        new_manifest.dump(output, fmt='json')
+    return all_files_added
+
+
+# TODO: write tests for this function
+def fetch_file(base_url, file_record, overwrite=False, grabchunk=1024*4):
+    # A file which is requested to be fetched that exists locally will be hashed.
+    # If the hash matches the requested file's hash, nothing will be done and the
+    # function will return.  If the function is told to overwrite and there is a 
+    # digest mismatch, the exiting file will be overwritten
+    if file_record.present():
+        if file_record.validate():
+            log.info("existing '%s' is valid, not fetching" % file_record.filename)
+            return True
+        if overwrite:
+            log.info("overwriting '%s' as requested" % file_record.filename)
+        else:
+            # All of the following is for a useful error message
+            with open(file_record.filename, 'rb') as f:
+                d = digest_file(f, file_record.algorithm)
+            log.error("digest mismatch between manifest(%s...) and local file(%s...)" % \
+                    (file_record.digest[:8], d[:8]))
+            log.debug("full digests: manifest (%s) local file (%s)" % (file_record.digest, d))
+            # Let's bail!
+            return False
+
+    # Generate the URL for the file on the server side
+    url = "%s/%s/%s" % (base_url, file_record.algorithm, file_record.digest)
+
+    log.debug("fetching from '%s'" % url)
+
+    # TODO: This should be abstracted to make generic retreival protocol handling easy
+    # Well, the file doesn't exist locally.  Lets fetch it.
+    try:
+        f = urllib2.urlopen(url)
+        log.debug("opened %s for reading" % url)
+        with open(file_record.filename, 'wb') as out:
+            k = True
+            size = 0
+            while k:
+                # TODO: print statistics as file transfers happen both for info and to stop
+                # buildbot timeouts
+                indata = f.read(grabchunk)
+                out.write(indata)
+                size += len(indata)
+                if indata == '':
+                    k = False
+            if size != file_record.size:
+                log.error("transfer from %s to %s failed due to a difference of %d bytes" % (url,
+                            file_record.filename, file_record.size - size))
+                return False
+            log.info("fetched %s" % file_record.filename)
+    except (urllib2.URLError, urllib2.HTTPError) as e:
+        log.error("failed to fetch '%s': %s" % (file_record.filename, e),
+                  exc_info=True)
+        return False
+    except IOError:
+        log.error("failed to write to '%s'" % file_record.filename,
+                  exc_info=True)
+        return False
+    return True
+
+
+# TODO: write tests for this function
+def fetch_files(manifest_file, base_url, overwrite, filenames=[]):
+    # Lets load the manifest file
+    try:
+        manifest = open_manifest(manifest_file)
+    except InvalidManifest:
+        log.error("failed to load manifest file at '%s'" % manifest_file)
+        return False
+    # We want to track files that fail to be fetched as well as
+    # files that are fetched
+    failed_files = []
+
+    # Lets go through the manifest and fetch the files that we want
+    fetched_files = []
+    for f in manifest.file_records:
+        if f.filename in filenames or len(filenames) == 0:
+            log.debug("fetching %s" % f.filename)
+            if fetch_file(base_url, f, overwrite):
+                fetched_files.append(f)
+            else:
+                failed_files.append(f.filename)
+        else:
+            log.debug("skipping %s" % f.filename)
+
+    # Even if we get the file, lets ensure that it matches what the
+    # manifest specified
+    for localfile in fetched_files:
+        if not localfile.validate():
+            log.error("'%s'" % localfile.describe())
+
+    # If we failed to fetch or validate a file, we need to fail
+    if len(failed_files) > 0:
+        log.error("The following files failed: '%s'" % "', ".join(failed_files))
+        return False
+    return True
+
+
+# TODO: write tests for this function
+def process_command(options, args):
+    """ I know how to take a list of program arguments and
+    start doing the right thing with them"""
+    cmd = args[0]
+    cmd_args = args[1:]
+    log.debug("processing '%s' command with args '%s'" % (cmd, '", "'.join(cmd_args)))
+    log.debug("using options: %s" % options)
+    if cmd == 'list':
+        return list_manifest(options['manifest'])
+    if cmd == 'validate':
+        return validate_manifest(options['manifest'])
+    elif cmd == 'add':
+        return add_files(options['manifest'], options['algorithm'], cmd_args)
+    elif cmd == 'fetch':
+        if not options.has_key('base_url') or options.get('base_url') is None:
+            log.critical('fetch command requires url option')
+            return False
+        return fetch_files(options['manifest'], options['base_url'], options['overwrite'], cmd_args)
+    else:
+        log.critical('command "%s" is not implemented' % cmd)
+        return False
+
+# fetching api:
+#   http://hostname/algorithm/hash
+#   example: http://people.mozilla.org/sha1/1234567890abcedf
+# This will make it possible to have the server allow clients to
+# use different algorithms than what was uploaded to the server
+
+# TODO: Implement the following features:
+#   -optimization: do small files first, justification is that they are faster
+#    and cause a faster failure if they are invalid
+#   -store permissions
+#   -local renames i.e. call the file one thing on the server and
+#    something different locally
+#   -deal with the cases:
+#     -local data matches file requested with different filename
+#     -two different files with same name, different hash
+#   -?only ever locally to digest as filename, symlink to real name
+#   -?maybe deal with files as a dir of the filename with all files in that dir as the versions of that file
+#      - e.g. ./python-2.6.7.dmg/0123456789abcdef and ./python-2.6.7.dmg/abcdef0123456789
+
+def main():
+    # Set up logging, for now just to the console
+    ch = logging.StreamHandler()
+    cf = logging.Formatter("%(levelname)s - %(message)s")
+    ch.setFormatter(cf)
+
+    # Set up option parsing
+    parser = optparse.OptionParser()
+    # I wish there was a way to say "only allow args to be
+    # sequential and at the end of the argv.
+    # OH! i could step through sys.argv and check for things starting without -/-- before things starting with them
+    parser.add_option('-q', '--quiet', default=False,
+            dest='quiet', action='store_true')
+    parser.add_option('-v', '--verbose', default=False,
+            dest='verbose', action='store_true')
+    parser.add_option('-m', '--manifest', default='manifest.tt',
+            dest='manifest', action='store',
+            help='specify the manifest file to be operated on')
+    parser.add_option('-d', '--algorithm', default='sha512',
+            dest='algorithm', action='store',
+            help='openssl hashing algorithm to use')
+    parser.add_option('-o', '--overwrite', default=False,
+            dest='overwrite', action='store_true',
+            help='if fetching, remote copy will overwrite a local copy that is different. ')
+    parser.add_option('--url', dest='base_url', action='store',
+            help='base url for fetching files')
+    parser.add_option('--ignore-config-files', action='store_true', default=False,
+                     dest='ignore_cfg_files')
+    (options_obj, args) = parser.parse_args()
+    # Dictionaries are easier to work with
+    options = vars(options_obj)
+
+
+    # Use some of the option parser to figure out application
+    # log level
+    if options.get('verbose'):
+        ch.setLevel(logging.DEBUG)
+    elif options.get('quiet'):
+        ch.setLevel(logging.ERROR)
+    else:
+        ch.setLevel(logging.INFO)
+    log.addHandler(ch)
+
+    cfg_file = ConfigParser.SafeConfigParser()
+    if not options.get("ignore_cfg_files"):
+        read_files = cfg_file.read(['/etc/tooltool', os.path.expanduser('~/.tooltool'),
+                   os.path.join(os.getcwd(), '.tooltool')])
+        log.debug("read in the config files '%s'" % '", '.join(read_files))
+    else:
+        log.debug("skipping config files")
+
+    for option in ('base_url', 'algorithm'):
+        if not options.get(option):
+            try:
+                options[option] = cfg_file.get('general', option)
+                log.debug("read '%s' as '%s' from cfg_file" % (option, options[option]))
+            except (ConfigParser.NoSectionError, ConfigParser.NoOptionError) as e:
+                log.debug("%s in config file" % e, exc_info=True)
+
+    if not options.has_key('manifest'):
+        parser.error("no manifest file specified")
+
+    if len(args) < 1:
+        parser.error('You must specify a command')
+    exit(0 if process_command(options, args) else 1)
+
+if __name__ == "__main__":
+    main()
+else:
+    log.addHandler(logging.NullHandler())
+    #log.addHandler(logging.StreamHandler())
--- a/caps/include/nsScriptSecurityManager.h
+++ b/caps/include/nsScriptSecurityManager.h
@@ -388,19 +388,16 @@ private:
     // GetScriptSecurityManager is the only call that can make one
     nsScriptSecurityManager();
     virtual ~nsScriptSecurityManager();
 
     static JSBool
     CheckObjectAccess(JSContext *cx, JSHandleObject obj,
                       JSHandleId id, JSAccessMode mode,
                       jsval *vp);
-
-    static JSPrincipals *
-    ObjectPrincipalFinder(JSObject *obj);
     
     // Decides, based on CSP, whether or not eval() and stuff can be executed.
     static JSBool
     ContentSecurityPolicyPermitsJSAction(JSContext *cx);
 
     // Returns null if a principal cannot be found; generally callers
     // should error out at that point.
     static nsIPrincipal* doGetObjectPrincipal(JSObject *obj);
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -462,22 +462,16 @@ NS_IMPL_ISUPPORTS4(nsScriptSecurityManag
                    nsIObserver)
 
 ///////////////////////////////////////////////////
 // Methods implementing nsIScriptSecurityManager //
 ///////////////////////////////////////////////////
 
 ///////////////// Security Checks /////////////////
 
-/* static */ JSPrincipals *
-nsScriptSecurityManager::ObjectPrincipalFinder(JSObject *aObj)
-{
-    return nsJSPrincipals::get(doGetObjectPrincipal(aObj));
-}
-
 JSBool
 nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(JSContext *cx)
 {
     // Get the security manager
     nsScriptSecurityManager *ssm =
         nsScriptSecurityManager::GetScriptSecurityManager();
 
     NS_ASSERTION(ssm, "Failed to get security manager service");
@@ -486,23 +480,18 @@ nsScriptSecurityManager::ContentSecurity
 
     nsresult rv;
     nsIPrincipal* subjectPrincipal = ssm->GetSubjectPrincipal(cx, &rv);
 
     NS_ASSERTION(NS_SUCCEEDED(rv), "CSP: Failed to get nsIPrincipal from js context");
     if (NS_FAILED(rv))
         return JS_FALSE; // Not just absence of principal, but failure.
 
-    if (!subjectPrincipal) {
-        // See bug 553448 for discussion of this case.
-        NS_ASSERTION(!JS_GetSecurityCallbacks(js::GetRuntime(cx))->findObjectPrincipals,
-                     "CSP: Should have been able to find subject principal. "
-                     "Reluctantly granting access.");
+    if (!subjectPrincipal)
         return JS_TRUE;
-    }
 
     nsCOMPtr<nsIContentSecurityPolicy> csp;
     rv = subjectPrincipal->GetCsp(getter_AddRefs(csp));
     NS_ASSERTION(NS_SUCCEEDED(rv), "CSP: Failed to get CSP from principal.");
 
     // don't do anything unless there's a CSP
     if (!csp)
         return JS_TRUE;
@@ -2394,20 +2383,17 @@ nsScriptSecurityManager::old_doGetObject
             if (result) {
                 break;
             }
         } else {
             nsISupports *priv;
             if (!(~jsClass->flags & (JSCLASS_HAS_PRIVATE |
                                      JSCLASS_PRIVATE_IS_NSISUPPORTS))) {
                 priv = (nsISupports *) js::GetObjectPrivate(aObj);
-            } else if (IsDOMClass(jsClass) &&
-                       DOMJSClass::FromJSClass(jsClass)->mDOMObjectIsISupports) {
-                priv = UnwrapDOMObject<nsISupports>(aObj);
-            } else {
+            } else if (!UnwrapDOMObjectToISupports(aObj, priv)) {
                 priv = nullptr;
             }
 
             if (aAllowShortCircuit) {
                 nsCOMPtr<nsIXPConnectWrappedNative> xpcWrapper =
                     do_QueryInterface(priv);
 
                 NS_ASSERTION(!xpcWrapper ||
@@ -2450,81 +2436,20 @@ nsScriptSecurityManager::old_doGetObject
 }
 #endif /* DEBUG */
 
 ///////////////// Capabilities API /////////////////////
 NS_IMETHODIMP
 nsScriptSecurityManager::IsCapabilityEnabled(const char *capability,
                                              bool *result)
 {
-    nsresult rv;
-    JSStackFrame *fp = nullptr;
     JSContext *cx = GetCurrentJSContext();
-    fp = cx ? JS_FrameIterator(cx, &fp) : nullptr;
-
-    if (!fp)
-    {
-        // No script code on stack. Allow access if and only if the subject
-        // principal is system.
-        nsresult ignored;
-        nsIPrincipal *subjectPrin = doGetSubjectPrincipal(&ignored);
-        *result = (!subjectPrin || subjectPrin == mSystemPrincipal);
+    if (cx && (*result = xpc::IsUniversalXPConnectEnabled(cx)))
         return NS_OK;
-    }
-
-    *result = false;
-    nsIPrincipal* previousPrincipal = nullptr;
-    do
-    {
-        nsIPrincipal* principal = GetFramePrincipal(cx, fp, &rv);
-        if (NS_FAILED(rv))
-            return rv;
-        if (!principal)
-            continue;
-        // If caller has a different principal, stop looking up the stack.
-        if(previousPrincipal)
-        {
-            bool isEqual = false;
-            if(NS_FAILED(previousPrincipal->Equals(principal, &isEqual)) || !isEqual)
-                break;
-        }
-        else
-            previousPrincipal = principal;
-
-        // First check if the principal is even able to enable the
-        // given capability. If not, don't look any further.
-        int16_t canEnable;
-        rv = principal->CanEnableCapability(capability, &canEnable);
-        if (NS_FAILED(rv)) return rv;
-        if (canEnable != nsIPrincipal::ENABLE_GRANTED &&
-            canEnable != nsIPrincipal::ENABLE_WITH_USER_PERMISSION)
-            return NS_OK;
-
-        // Now see if the capability is enabled.
-        void *annotation = JS_GetFrameAnnotation(cx, fp);
-        rv = principal->IsCapabilityEnabled(capability, annotation, result);
-        if (NS_FAILED(rv)) return rv;
-        if (*result)
-            return NS_OK;
-
-        // Capabilities do not extend to calls into C/C++ and then back into
-        // the JS engine via JS_EvaluateScript or similar APIs.
-        if (JS_IsGlobalFrame(cx, fp))
-            break;
-    } while ((fp = JS_FrameIterator(cx, &fp)) != nullptr);
-
-    if (!previousPrincipal)
-    {
-        // No principals on the stack, all native code.  Allow
-        // execution if the subject principal is the system principal.
-
-        return SubjectPrincipalIsSystem(result);
-    }
-
-    return NS_OK;
+    return SubjectPrincipalIsSystem(result);
 }
 
 void
 nsScriptSecurityManager::FormatCapabilityString(nsAString& aCapability)
 {
     nsAutoString newcaps;
     nsAutoString rawcap;
     NS_NAMED_LITERAL_STRING(capdesc, "capdesc.");
@@ -3046,18 +2971,16 @@ nsresult nsScriptSecurityManager::Init()
         do_QueryInterface(sXPConnect, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = runtimeService->GetRuntime(&sRuntime);
     NS_ENSURE_SUCCESS(rv, rv);
 
     static const JSSecurityCallbacks securityCallbacks = {
         CheckObjectAccess,
-        nsJSPrincipals::Subsume,
-        ObjectPrincipalFinder,
         ContentSecurityPolicyPermitsJSAction
     };
 
     MOZ_ASSERT(!JS_GetSecurityCallbacks(sRuntime));
     JS_SetSecurityCallbacks(sRuntime, &securityCallbacks);
     JS_InitDestroyPrincipalsCallback(sRuntime, nsJSPrincipals::Destroy);
 
     JS_SetTrustedPrincipals(sRuntime, system);
--- a/caps/src/nsSecurityManagerFactory.cpp
+++ b/caps/src/nsSecurityManagerFactory.cpp
@@ -20,94 +20,37 @@
 #include "nsString.h"
 #include "nsNetCID.h"
 #include "nsIClassInfoImpl.h"
 #include "nsJSUtils.h"
 #include "nsPIDOMWindow.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIDocument.h"
 #include "jsfriendapi.h"
+#include "xpcprivate.h"
+#include "mozilla/Preferences.h"
 
 ///////////////////////
 // nsSecurityNameSet //
 ///////////////////////
 
 nsSecurityNameSet::nsSecurityNameSet()
 {
 }
 
 nsSecurityNameSet::~nsSecurityNameSet()
 {
 }
 
 NS_IMPL_ISUPPORTS1(nsSecurityNameSet, nsIScriptExternalNameSet)
 
-static JSString *
-getStringArgument(JSContext *cx, JSObject *obj, uint16_t argNum, unsigned argc, jsval *argv)
-{
-    if (argc <= argNum || !JSVAL_IS_STRING(argv[argNum])) {
-        JS_ReportError(cx, "String argument expected");
-        return nullptr;
-    }
-
-    /*
-     * We don't want to use JS_ValueToString because we want to be able
-     * to have an object to represent a target in subsequent versions.
-     */
-    return JSVAL_TO_STRING(argv[argNum]);
-}
-
-static bool
-getBytesArgument(JSContext *cx, JSObject *obj, uint16_t argNum, unsigned argc, jsval *argv,
-                 JSAutoByteString *bytes)
-{
-    JSString *str = getStringArgument(cx, obj, argNum, argc, argv);
-    return str && bytes->encode(cx, str);
-}
-
 static JSBool
 netscape_security_enablePrivilege(JSContext *cx, unsigned argc, jsval *vp)
 {
-    JSObject *obj = JS_THIS_OBJECT(cx, vp);
-    if (!obj)
-        return JS_FALSE;
-
-    JSAutoByteString cap;
-    if (!getBytesArgument(cx, obj, 0, argc, JS_ARGV(cx, vp), &cap))
-        return JS_FALSE;
-
-    // Can't use nsContentUtils::GetDocumentFromCaller because that
-    // depends on various XPConnect stuff that's not set up here.
-    {
-        JSAutoEnterCompartment ac;
-        if (ac.enter(cx, obj)) {
-            nsCOMPtr<nsPIDOMWindow> win =
-                do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(cx, obj));
-            if (win) {
-                nsCOMPtr<nsIDocument> doc =
-                    do_QueryInterface(win->GetExtantDocument());
-                if (doc) {
-                    doc->WarnOnceAbout(nsIDocument::eEnablePrivilege);
-                }
-            }
-        }
-    }
-
-    nsresult rv;
-    nsCOMPtr<nsIScriptSecurityManager> securityManager = 
-             do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
-    if (NS_FAILED(rv)) 
-        return JS_FALSE;
-
-    //    NS_ASSERTION(cx == GetCurrentContext(), "unexpected context");
-
-    rv = securityManager->EnableCapability(cap.ptr());
-    if (NS_FAILED(rv))
-        return JS_FALSE;
-    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    xpc::EnableUniversalXPConnect(cx);
     return JS_TRUE;
 }
 
 static JSFunctionSpec PrivilegeManager_static_methods[] = {
     JS_FS("enablePrivilege", netscape_security_enablePrivilege, 1, 0),
     JS_FS_END
 };
 
@@ -116,16 +59,25 @@ static JSFunctionSpec PrivilegeManager_s
  * et al. so that code that worked with 4.0 can still work.
  */
 NS_IMETHODIMP 
 nsSecurityNameSet::InitializeNameSet(nsIScriptContext* aScriptContext)
 {
     JSContext* cx = aScriptContext->GetNativeContext();
     JSObject *global = JS_ObjectToInnerObject(cx, JS_GetGlobalObject(cx));
 
+    // We hide enablePrivilege behind a pref because it has been altered in a
+    // way that makes it fundamentally insecure to use in production. Mozilla
+    // uses this pref during automated testing to support legacy test code that
+    // uses enablePrivilege. If you're not doing test automation, you _must_ not
+    // flip this pref, or you will be exposing all your users to security
+    // vulnerabilities.
+    if (!mozilla::Preferences::GetBool("security.enablePrivilege.enable_for_tests"))
+        return NS_OK;
+
     /*
      * Find Object.prototype's class by walking up the global object's
      * prototype chain.
      */
     JSObject *obj = global;
     JSObject *proto;
     JSAutoRequest ar(cx);
     while ((proto = JS_GetPrototype(obj)) != nullptr)
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -1582,32 +1582,30 @@ endif # COMPILER_DEPEND
 #   a previous build in the source tree) and thus neglect to create a
 #   dependency directory in the object directory, where we really need
 #   it.
 
 $(CURDIR)/$(MDDEPDIR):
 	$(MKDIR) -p $@
 
 ifneq (,$(filter-out all chrome default export realchrome tools clean clobber clobber_all distclean realclean,$(MAKECMDGOALS)))
-ifneq (,$(OBJS)$(XPIDLSRCS)$(SIMPLE_PROGRAMS))
 MDDEPEND_FILES		:= $(strip $(wildcard $(MDDEPDIR)/*.pp))
 
 ifneq (,$(MDDEPEND_FILES))
 # The script mddepend.pl checks the dependencies and writes to stdout
 # one rule to force out-of-date objects. For example,
 #   foo.o boo.o: FORCE
 # The script has an advantage over including the *.pp files directly
 # because it handles the case when header files are removed from the build.
 # 'make' would complain that there is no way to build missing headers.
 ALL_PP_RESULTS = $(shell $(PERL) $(BUILD_TOOLS)/mddepend.pl - $(MDDEPEND_FILES))
 $(eval $(ALL_PP_RESULTS))
 endif
 
 endif
-endif
 #############################################################################
 
 -include $(topsrcdir)/$(MOZ_BUILD_APP)/app-rules.mk
 -include $(MY_RULES)
 
 #
 # Generate Emacs tags in a file named TAGS if ETAGS was set in $(MY_CONFIG)
 # or in $(MY_RULES)
--- a/content/base/public/Makefile.in
+++ b/content/base/public/Makefile.in
@@ -37,17 +37,16 @@ nsContentCID.h \
 nsCopySupport.h \
 nsContentCreatorFunctions.h \
 nsDOMFile.h \
 nsLineBreaker.h \
 nsReferencedElement.h \
 nsTreeSanitizer.h \
 nsXMLNameSpaceMap.h \
 nsIXFormsUtilityService.h \
-nsBlobProtocolHandler.h \
 $(NULL)
 
 EXPORTS_NAMESPACES = mozilla/dom mozilla
 
 EXPORTS_mozilla/dom = \
 		DirectionalityUtils.h \
 		Element.h \
 		FragmentOrElement.h \
deleted file mode 100644
--- a/content/base/public/nsBlobProtocolHandler.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef nsBlobProtocolHandler_h
-#define nsBlobProtocolHandler_h
-
-#include "nsIProtocolHandler.h"
-#include "nsIURI.h"
-#include "nsCOMPtr.h"
-
-#define BLOBURI_SCHEME "blob"
-
-class nsIDOMBlob;
-class nsIPrincipal;
-class nsIInputStream;
-
-inline bool IsBlobURI(nsIURI* aUri)
-{
-  bool isBlob;
-  return NS_SUCCEEDED(aUri->SchemeIs(BLOBURI_SCHEME, &isBlob)) && isBlob;
-}
-
-extern nsresult
-NS_GetStreamForBlobURI(nsIURI* aURI, nsIInputStream** aStream);
-
-class nsBlobProtocolHandler : public nsIProtocolHandler
-{
-public:
-  NS_DECL_ISUPPORTS
-
-  // nsIProtocolHandler methods:
-  NS_DECL_NSIPROTOCOLHANDLER
-
-  // nsBlobProtocolHandler methods:
-  nsBlobProtocolHandler() {}
-  virtual ~nsBlobProtocolHandler() {}
-
-  // Methods for managing uri->file mapping
-  static void AddFileDataEntry(nsACString& aUri,
-                               nsIDOMBlob* aFile,
-                               nsIPrincipal* aPrincipal);
-  static void RemoveFileDataEntry(nsACString& aUri);
-  static nsIPrincipal* GetFileDataEntryPrincipal(nsACString& aUri);
-};
-
-#define NS_BLOBPROTOCOLHANDLER_CID \
-{ 0xb43964aa, 0xa078, 0x44b2, \
-  { 0xb0, 0x6b, 0xfd, 0x4d, 0x1b, 0x17, 0x2e, 0x66 } }
-
-#endif /* nsBlobProtocolHandler_h */
--- a/content/base/src/FragmentOrElement.cpp
+++ b/content/base/src/FragmentOrElement.cpp
@@ -386,17 +386,17 @@ NS_INTERFACE_TABLE_HEAD(nsChildContentLi
   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsChildContentList)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(NodeList)
 NS_INTERFACE_MAP_END
 
 JSObject*
 nsChildContentList::WrapObject(JSContext *cx, JSObject *scope,
                                bool *triedToWrap)
 {
-  return mozilla::dom::binding::NodeList::create(cx, scope, this, triedToWrap);
+  return mozilla::dom::oldproxybindings::NodeList::create(cx, scope, this, triedToWrap);
 }
 
 NS_IMETHODIMP
 nsChildContentList::GetLength(uint32_t* aLength)
 {
   *aLength = mNode ? mNode->GetChildCount() : 0;
 
   return NS_OK;
--- a/content/base/src/nsBlobProtocolHandler.cpp
+++ b/content/base/src/nsBlobProtocolHandler.cpp
@@ -158,18 +158,18 @@ nsBlobProtocolHandler::NewChannel(nsIURI
 #endif
 
   nsCOMPtr<nsIInputStream> stream;
   nsresult rv = info->mFile->GetInternalStream(getter_AddRefs(stream));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIChannel> channel;
   rv = NS_NewInputStreamChannel(getter_AddRefs(channel),
-                                uri,
-                                stream);
+				uri,
+				stream);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsISupports> owner = do_QueryInterface(info->mPrincipal);
 
   nsAutoString type;
   rv = info->mFile->GetType(type);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -184,28 +184,8 @@ nsBlobProtocolHandler::NewChannel(nsIURI
 NS_IMETHODIMP 
 nsBlobProtocolHandler::AllowPort(int32_t port, const char *scheme,
                                      bool *_retval)
 {
     // don't override anything.  
     *_retval = false;
     return NS_OK;
 }
-
-nsresult
-NS_GetStreamForBlobURI(nsIURI* aURI, nsIInputStream** aStream)
-{
-  NS_ASSERTION(IsBlobURI(aURI), "Only call this with blob URIs");
-
-  *aStream = nullptr;
-
-  nsCString spec;
-  aURI->GetSpec(spec);
-
-  FileDataInfo* info =
-    GetFileDataInfo(spec);
-
-  if (!info) {
-    return NS_ERROR_DOM_BAD_URI;
-  }
-
-  return info->mFile->GetInternalStream(aStream);
-}
--- a/content/base/src/nsBlobProtocolHandler.h
+++ b/content/base/src/nsBlobProtocolHandler.h
@@ -1,51 +1,40 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsBlobProtocolHandler_h
 #define nsBlobProtocolHandler_h
 
 #include "nsIProtocolHandler.h"
-#include "nsIURI.h"
-#include "nsCOMPtr.h"
 
 #define BLOBURI_SCHEME "blob"
 
 class nsIDOMBlob;
 class nsIPrincipal;
-class nsIInputStream;
-
-inline bool IsBlobURI(nsIURI* aUri)
-{
-  bool isBlob;
-  return NS_SUCCEEDED(aUri->SchemeIs(BLOBURI_SCHEME, &isBlob)) && isBlob;
-}
-
-extern nsresult
-NS_GetStreamForBlobURI(nsIURI* aURI, nsIInputStream** aStream);
 
 class nsBlobProtocolHandler : public nsIProtocolHandler
 {
 public:
   NS_DECL_ISUPPORTS
 
   // nsIProtocolHandler methods:
   NS_DECL_NSIPROTOCOLHANDLER
 
   // nsBlobProtocolHandler methods:
   nsBlobProtocolHandler() {}
   virtual ~nsBlobProtocolHandler() {}
 
   // Methods for managing uri->file mapping
   static void AddFileDataEntry(nsACString& aUri,
-                               nsIDOMBlob* aFile,
+			       nsIDOMBlob* aFile,
                                nsIPrincipal* aPrincipal);
   static void RemoveFileDataEntry(nsACString& aUri);
   static nsIPrincipal* GetFileDataEntryPrincipal(nsACString& aUri);
+  
 };
 
 #define NS_BLOBPROTOCOLHANDLER_CID \
 { 0xb43964aa, 0xa078, 0x44b2, \
   { 0xb0, 0x6b, 0xfd, 0x4d, 0x1b, 0x17, 0x2e, 0x66 } }
 
 #endif /* nsBlobProtocolHandler_h */
--- a/content/base/src/nsContentList.cpp
+++ b/content/base/src/nsContentList.cpp
@@ -157,17 +157,17 @@ NS_INTERFACE_MAP_END_INHERITING(nsBaseCo
 
 NS_IMPL_ADDREF_INHERITED(nsSimpleContentList, nsBaseContentList)
 NS_IMPL_RELEASE_INHERITED(nsSimpleContentList, nsBaseContentList)
 
 JSObject*
 nsSimpleContentList::WrapObject(JSContext *cx, JSObject *scope,
                                 bool *triedToWrap)
 {
-  return mozilla::dom::binding::NodeList::create(cx, scope, this, triedToWrap);
+  return mozilla::dom::oldproxybindings::NodeList::create(cx, scope, this, triedToWrap);
 }
 
 // nsFormContentList
 
 nsFormContentList::nsFormContentList(nsIContent *aForm,
                                      nsBaseContentList& aContentList)
   : nsSimpleContentList(aForm)
 {
@@ -473,17 +473,17 @@ nsContentList::~nsContentList()
     // Clean up mData
     (*mDestroyFunc)(mData);
   }
 }
 
 JSObject*
 nsContentList::WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap)
 {
-  return mozilla::dom::binding::HTMLCollection::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::HTMLCollection::create(cx, scope, this,
                                                        triedToWrap);
 }
 
 DOMCI_DATA(ContentList, nsContentList)
 
 // QueryInterface implementation for nsContentList
 NS_INTERFACE_TABLE_HEAD(nsContentList)
   NS_NODELIST_OFFSET_AND_INTERFACE_TABLE_BEGIN(nsContentList)
--- a/content/base/src/nsDOMFile.cpp
+++ b/content/base/src/nsDOMFile.cpp
@@ -13,17 +13,16 @@
 #include "nsICharsetDetector.h"
 #include "nsICharsetConverterManager.h"
 #include "nsIClassInfo.h"
 #include "nsIConverterInputStream.h"
 #include "nsIDocument.h"
 #include "nsIFileStreams.h"
 #include "nsIInputStream.h"
 #include "nsIIPCSerializableInputStream.h"
-#include "nsIIPCSerializableObsolete.h"
 #include "nsIMIMEService.h"
 #include "nsIPlatformCharset.h"
 #include "nsISeekableStream.h"
 #include "nsIUnicharInputStream.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
 #include "nsIUUIDGenerator.h"
@@ -43,68 +42,57 @@ using namespace mozilla::dom;
 
 // XXXkhuey the input stream that we pass out of a DOMFile
 // can outlive the actual DOMFile object.  Thus, we must
 // ensure that the buffer underlying the stream we get
 // from NS_NewByteInputStream is held alive as long as the
 // stream is.  We do that by passing back this class instead.
 class DataOwnerAdapter MOZ_FINAL : public nsIInputStream,
                                    public nsISeekableStream,
-                                   public nsIIPCSerializableObsolete,
-                                   public nsIClassInfo,
                                    public nsIIPCSerializableInputStream
 {
   typedef nsDOMMemoryFile::DataOwner DataOwner;
 public:
   static nsresult Create(DataOwner* aDataOwner,
                          uint32_t aStart,
                          uint32_t aLength,
                          nsIInputStream** _retval);
 
   NS_DECL_ISUPPORTS
 
   // These are mandatory.
   NS_FORWARD_NSIINPUTSTREAM(mStream->)
   NS_FORWARD_NSISEEKABLESTREAM(mSeekableStream->)
 
-  // These are optional. We use a conditional QI to keep them from being called
-  // if the underlying stream doesn't QI to either interface.
-  NS_FORWARD_NSIIPCSERIALIZABLEOBSOLETE(mSerializableObsolete->)
-  NS_FORWARD_NSICLASSINFO(mClassInfo->)
+  // This is optional. We use a conditional QI to keep it from being called
+  // if the underlying stream doesn't support it.
   NS_FORWARD_NSIIPCSERIALIZABLEINPUTSTREAM(mSerializableInputStream->)
 
 private:
   DataOwnerAdapter(DataOwner* aDataOwner,
                    nsIInputStream* aStream)
     : mDataOwner(aDataOwner), mStream(aStream),
       mSeekableStream(do_QueryInterface(aStream)),
-      mSerializableObsolete(do_QueryInterface(aStream)),
-      mClassInfo(do_QueryInterface(aStream)),
       mSerializableInputStream(do_QueryInterface(aStream))
   {
     NS_ASSERTION(mSeekableStream, "Somebody gave us the wrong stream!");
   }
 
   nsRefPtr<DataOwner> mDataOwner;
   nsCOMPtr<nsIInputStream> mStream;
   nsCOMPtr<nsISeekableStream> mSeekableStream;
-  nsCOMPtr<nsIIPCSerializableObsolete> mSerializableObsolete;
-  nsCOMPtr<nsIClassInfo> mClassInfo;
   nsCOMPtr<nsIIPCSerializableInputStream> mSerializableInputStream;
 };
 
 NS_IMPL_THREADSAFE_ADDREF(DataOwnerAdapter)
 NS_IMPL_THREADSAFE_RELEASE(DataOwnerAdapter)
 
 NS_INTERFACE_MAP_BEGIN(DataOwnerAdapter)
   NS_INTERFACE_MAP_ENTRY(nsIInputStream)
   NS_INTERFACE_MAP_ENTRY(nsISeekableStream)
-  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableObsolete,
-                                     mSerializableObsolete)
-  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIClassInfo, mClassInfo)
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableInputStream,
                                      mSerializableInputStream)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
 NS_INTERFACE_MAP_END
 
 nsresult DataOwnerAdapter::Create(DataOwner* aDataOwner,
                                   uint32_t aStart,
                                   uint32_t aLength,
@@ -683,17 +671,17 @@ NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMFileList)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMFileList)
 
 JSObject*
 nsDOMFileList::WrapObject(JSContext *cx, JSObject *scope,
                           bool *triedToWrap)
 {
-  return mozilla::dom::binding::FileList::create(cx, scope, this, triedToWrap);
+  return mozilla::dom::oldproxybindings::FileList::create(cx, scope, this, triedToWrap);
 }
 
 nsIDOMFile*
 nsDOMFileList::GetItemAt(uint32_t aIndex)
 {
   return mFiles.SafeObjectAt(aIndex);
 }
 
--- a/content/base/src/nsDOMSettableTokenList.cpp
+++ b/content/base/src/nsDOMSettableTokenList.cpp
@@ -46,11 +46,11 @@ nsDOMSettableTokenList::SetValue(const n
 
   return mElement->SetAttr(kNameSpaceID_None, mAttrAtom, aValue, true);
 }
 
 JSObject*
 nsDOMSettableTokenList::WrapObject(JSContext *cx, JSObject *scope,
                                    bool *triedToWrap)
 {
-  return mozilla::dom::binding::DOMSettableTokenList::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::DOMSettableTokenList::create(cx, scope, this,
                                                              triedToWrap);
 }
--- a/content/base/src/nsDOMTokenList.cpp
+++ b/content/base/src/nsDOMTokenList.cpp
@@ -267,12 +267,12 @@ nsDOMTokenList::ToString(nsAString& aRes
   mElement->GetAttr(kNameSpaceID_None, mAttrAtom, aResult);
 
   return NS_OK;
 }
 
 JSObject*
 nsDOMTokenList::WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap)
 {
-  return mozilla::dom::binding::DOMTokenList::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::DOMTokenList::create(cx, scope, this,
                                                      triedToWrap);
 }
 
--- a/content/base/test/test_bug333198.html
+++ b/content/base/test/test_bug333198.html
@@ -25,32 +25,25 @@ var focusTester;
 var focusTester2;
 var focusCount = 0;
 var eventCount = 0;
 function clickHandler() {
   ++eventCount;
 }
 
 function suppressEvents(suppress) {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-        .getInterface(Components.interfaces.nsIDOMWindowUtils)
-        .suppressEventHandling(suppress);
+  SpecialPowers.DOMWindowUtils.suppressEventHandling(suppress);
 }
 
 function sendEvents() {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  windowUtils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                      .getInterface(Components.interfaces.nsIDOMWindowUtils);
+  windowUtils = SpecialPowers.getDOMWindowUtils(window);
   windowUtils.sendMouseEvent("mousedown", 1, 1, 0, 1, 0);
   windowUtils.sendMouseEvent("mouseup", 1, 1, 0, 1, 0);
 
-  iframeUtils = document.getElementById("ifr").contentWindow
-                        .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                        .getInterface(Components.interfaces.nsIDOMWindowUtils);
+  iframeUtils = SpecialPowers.getDOMWindowUtils(document.getElementById("ifr").contentWindow);
   iframeUtils.sendMouseEvent("mousedown", 1, 1, 0, 1, 0);
   iframeUtils.sendMouseEvent("mouseup", 1, 1, 0, 1, 0);
 }
 
 function runTest() {
   window.focus();
   focusTester = document.getElementsByTagName("input")[0];
   focusTester.blur();
--- a/content/events/src/nsPaintRequest.h
+++ b/content/events/src/nsPaintRequest.h
@@ -41,17 +41,17 @@ public:
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsPaintRequestList)
   NS_DECL_NSIDOMPAINTREQUESTLIST
   
   virtual JSObject* WrapObject(JSContext *cx, JSObject *scope,
                                bool *triedToWrap)
   {
-    return mozilla::dom::binding::PaintRequestList::create(cx, scope, this,
+    return mozilla::dom::oldproxybindings::PaintRequestList::create(cx, scope, this,
                                                            triedToWrap);
   }
 
   nsISupports* GetParentObject()
   {
     return mParent;
   }
 
--- a/content/events/test/test_bug226361.xhtml
+++ b/content/events/test/test_bug226361.xhtml
@@ -43,19 +43,17 @@ function setOrRestoreTabFocus(newValue) 
     prefs.setIntPref("tabfocus", newValue);
   }
 }
 
 // =================================
 
 var doc = document;
 function tab_to(id) {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  var wu =  doc.defaultView.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                .getInterface(Components.interfaces.nsIDOMWindowUtils);
+  var wu = SpecialPowers.DOMWindowUtils;
   wu.sendKeyEvent('keypress',  9, 0, 0);
   is(doc.activeElement.id, id, "element with id=" + id + " should have focus");
 }
 
 function tab_iframe() {
   doc = document;
   tab_to('iframe');
 
--- a/content/events/test/test_bug493251.html
+++ b/content/events/test/test_bug493251.html
@@ -26,37 +26,31 @@ https://bugzilla.mozilla.org/show_bug.cg
   var mouseUp = 0;
   var mouseClick = 0;
 
   var keyDown = 0;
   var keyPress = 0;
   var keyUp = 0;
 
   function suppressEventHandling(aSuppress) {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var utils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
-                    getInterface(Components.interfaces.nsIDOMWindowUtils);
+    var utils = SpecialPowers.getDOMWindowUtils(win);
     ok(true, "suppressEventHandling: aSuppress=" + aSuppress);
     utils.suppressEventHandling(aSuppress);
   }
 
   function dispatchKeyEvent(type) {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var utils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
-                    getInterface(Components.interfaces.nsIDOMWindowUtils);
+    var utils = SpecialPowers.getDOMWindowUtils(win);
     ok(true, "Dipatching key event: type=" + type);
     utils.sendKeyEvent(type, 
                        Components.interfaces.nsIDOMKeyEvent.DOM_VK_A,
                        0, 0);
   }
 
   function dispatchMouseEvent(aType, aX, aY, aButton, aClickCount, aModifiers) {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var utils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
-                    getInterface(Components.interfaces.nsIDOMWindowUtils);
+    var utils = SpecialPowers.getDOMWindowUtils(win);
     ok(true, "Dipatching mouse event: aType=" + aType + ", aX=" + aX + ", aY" +
                aY + ", aButton=" + aButton + ", aClickCount=" + aClickCount +
                ", aModifiers=" + aModifiers);
     utils.sendMouseEvent(aType, aX, aY, aButton, aClickCount, aModifiers);
   }
 
   function dumpEvent(aEvent) {
     var detail = "target=" + aEvent.target + ", originalTarget=" +
@@ -83,18 +77,17 @@ https://bugzilla.mozilla.org/show_bug.cg
           ", shiftKey=" + (aEvent.shiftKey ? "PRESSED" : "no") +
           ", metaKey=" + (aEvent.metaKey ? "PRESSED" : "no") +
           ", button=" + aEvent.button +
           ", relatedTarget=" + aEvent.relatedTarget;
         break;
     }
     ok(true, aEvent.type + " event is handled: " + detail);
 
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var fm = Components.classes["@mozilla.org/focus-manager;1"].
+    var fm = SpecialPowers.wrap(Components).classes["@mozilla.org/focus-manager;1"].
                         getService(Components.interfaces.nsIFocusManager);
     ok(true, "focused element is \"" + fm.focusedElement +
              "\" and focused window is \"" + fm.focusedWindow +
              "\" (the testing window is \"" + win + "\"");
   }
 
   function doTest() {
     win.document.getElementsByTagName("input")[0].focus();
--- a/content/events/test/test_bug545268.html
+++ b/content/events/test/test_bug545268.html
@@ -29,28 +29,24 @@ https://bugzilla.mozilla.org/show_bug.cg
   var mouseUp = 0;
   var mouseClick = 0;
 
   var keyDown = 0;
   var keyPress = 0;
   var keyUp = 0;
 
   function dispatchKeyEvent(type) {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var utils = subwin.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
-                    getInterface(Components.interfaces.nsIDOMWindowUtils);
+    var utils = SpecialPowers.getDOMWindowUtils(subwin);
     utils.sendKeyEvent(type, 
                        Components.interfaces.nsIDOMKeyEvent.DOM_VK_A,
                        0, 0);
   }
 
   function doTest() {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var utils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
-                    getInterface(Components.interfaces.nsIDOMWindowUtils);
+    var utils = SpecialPowers.getDOMWindowUtils(win);
     var f = win.document.getElementById("f");
     subwin = f.contentWindow;
     subwin.document.getElementsByTagName("input")[0].focus();
     subwin.addEventListener("keydown", function(e) { ++keyDown; }, true);
     subwin.addEventListener("keypress", function(e) { ++keyPress; }, true);
     subwin.addEventListener("keyup", function(e) { ++keyUp; }, true);
     subwin.addEventListener("mousedown", function(e) { ++mouseDown; }, true);
     subwin.addEventListener("mouseup", function(e) { ++mouseUp; }, true);
@@ -76,34 +72,30 @@ https://bugzilla.mozilla.org/show_bug.cg
     is(keyDown, 1, "Wrong number events (7)");
     is(keyPress, 1, "Wrong number events (8)");
     is(keyUp, 1, "Wrong number events (9)");
 
     setTimeout(continueTest1, 0);
     }
 
   function continueTest1() {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var utils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
-                    getInterface(Components.interfaces.nsIDOMWindowUtils);
+    var utils = SpecialPowers.getDOMWindowUtils(win);
     dispatchKeyEvent("keydown");
     utils.suppressEventHandling(true);
     dispatchKeyEvent("keypress");
     dispatchKeyEvent("keyup");
     is(keyDown, 2, "Wrong number events (10)");
     is(keyPress, 1, "Wrong number events (11)");
     is(keyUp, 1, "Wrong number events (12)");
     utils.suppressEventHandling(false);
     setTimeout(continueTest2, 0);
   }
 
   function continueTest2() {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var utils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
-                    getInterface(Components.interfaces.nsIDOMWindowUtils);
+    var utils = SpecialPowers.getDOMWindowUtils(win);
     is(keyDown, 2, "Wrong number events (13)");
     is(keyPress, 2, "Wrong number events (14)");
     is(keyUp, 2, "Wrong number events (15)");
 
     utils.sendMouseEvent("mousedown", 5, 5, 0, 1, 0);
     utils.sendMouseEvent("mouseup", 5, 5, 0, 1, 0);
     is(mouseDown, 1, "Wrong number events (16)");
     is(mouseUp, 1, "Wrong number events (17)");
@@ -116,19 +108,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     is(mouseDown, 1, "Wrong number events (19)");
     is(mouseUp, 1, "Wrong number events (20)");
     is(mouseClick, 1, "Wrong number events (21)");
 
     setTimeout(continueTest3, 0);
   }
 
   function continueTest3() {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var utils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
-                    getInterface(Components.interfaces.nsIDOMWindowUtils);
+    var utils = SpecialPowers.getDOMWindowUtils(win);
     utils.sendMouseEvent("mousedown", 5, 5, 0, 1, 0);
     utils.suppressEventHandling(true);
     utils.sendMouseEvent("mouseup", 5, 5, 0, 1, 0);
     utils.suppressEventHandling(false);
     setTimeout(continueTest4, 1000);
   }
 
   function continueTest4() {
--- a/content/events/test/test_bug574663.html
+++ b/content/events/test/test_bug574663.html
@@ -39,19 +39,17 @@ function sendTouchpadScrollMotion(scroll
 
 function runTest() {
   var win = open('data:text/html,<!DOCTYPE html>\n' +
     '<div id="scrollbox" style="height: 100px; overflow: auto;">' +
     '  <div style="height: 1000px;"></div>' +
     '</div>', '_blank', 'width=300,height=300');
   SimpleTest.waitForFocus(function () {
     var scrollbox = win.document.getElementById("scrollbox");
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    let winUtils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                      .getInterface(Components.interfaces.nsIDOMWindowUtils);
+    let winUtils = SpecialPowers.getDOMWindowUtils(win);
     let outstandingTests = [
       [false, false],
       [false, true],
       [true, false],
       [true, true],
     ];
     function nextTest() {
       netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
--- a/content/events/test/test_bug593959.html
+++ b/content/events/test/test_bug593959.html
@@ -21,30 +21,27 @@ https://bugzilla.mozilla.org/show_bug.cg
   
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 593959 **/
 
   function doTest() {
-    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
-    var utils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                       .getInterface(Components.interfaces.nsIDOMWindowUtils);
+    var utils = SpecialPowers.getDOMWindowUtils(window);
     var e = document.createEvent("MouseEvent");
     e.initEvent("mousedown", false, false, window, 0, 1, 1, 1, 1,
                 false, false, false, false, 0, null);
     utils.dispatchDOMEventViaPresShell(document.body, e, true);
     
     is(document.querySelector("body:active"), document.body, "body should be active!")
     
     var ifrwindow = document.getElementById("ifr").contentWindow;
     
-    var utils2 = ifrwindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                          .getInterface(Components.interfaces.nsIDOMWindowUtils);
+    var utils2 = SpecialPowers.getDOMWindowUtils(ifrwindow);
    
     var e2 = ifrwindow.document.createEvent("MouseEvent");
     e2.initEvent("mouseup", false, false, ifrwindow, 0, 1, 1, 1, 1,
                  false, false, false, false, 0, null);
     utils2.dispatchDOMEventViaPresShell(ifrwindow.document.body, e2, true);
     
     isnot(document.querySelector("body:active"), document.body, "body shouldn't be active!")
 
--- a/content/html/content/src/HTMLPropertiesCollection.cpp
+++ b/content/html/content/src/HTMLPropertiesCollection.cpp
@@ -103,17 +103,17 @@ HTMLPropertiesCollection::SetDocument(ns
   mNamedItemEntries.EnumerateRead(SetPropertyListDocument, aDocument);
   mIsDirty = true;
 }
 
 JSObject*
 HTMLPropertiesCollection::WrapObject(JSContext* cx, JSObject* scope,
                                      bool* triedToWrap)
 {
-  return mozilla::dom::binding::HTMLPropertiesCollection::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::HTMLPropertiesCollection::create(cx, scope, this,
                                                                  triedToWrap);
 }
 
 NS_IMETHODIMP
 HTMLPropertiesCollection::GetLength(uint32_t* aLength)
 {
   EnsureFresh();
   *aLength = mProperties.Length();
@@ -421,17 +421,17 @@ PropertyNodeList::GetParentObject()
 {
   return mParent;
 }
 
 JSObject*
 PropertyNodeList::WrapObject(JSContext *cx, JSObject *scope,
                              bool *triedToWrap)
 {
-  return mozilla::dom::binding::PropertyNodeList::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::PropertyNodeList::create(cx, scope, this,
                                                          triedToWrap);
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(PropertyNodeList)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(PropertyNodeList)
   // SetDocument(nullptr) ensures that we remove ourselves as a mutation observer
   tmp->SetDocument(nullptr);
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mParent)
--- a/content/html/content/src/nsClientRect.cpp
+++ b/content/html/content/src/nsClientRect.cpp
@@ -101,17 +101,17 @@ nsIDOMClientRect*
 nsClientRectList::GetItemAt(uint32_t aIndex)
 {
   return mArray.SafeObjectAt(aIndex);
 }
 
 JSObject*
 nsClientRectList::WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap)
 {
-  return mozilla::dom::binding::ClientRectList::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::ClientRectList::create(cx, scope, this,
                                                        triedToWrap);
 }
 
 static double
 RoundFloat(double aValue)
 {
   return floor(aValue + 0.5);
 }
--- a/content/html/content/src/nsHTMLFormElement.cpp
+++ b/content/html/content/src/nsHTMLFormElement.cpp
@@ -116,17 +116,17 @@ public:
    * @return NS_OK or NS_ERROR_OUT_OF_MEMORY.
    */
   nsresult GetSortedControls(nsTArray<nsGenericHTMLFormElement*>& aControls) const;
 
   // nsWrapperCache
   virtual JSObject* WrapObject(JSContext *cx, JSObject *scope,
                                bool *triedToWrap)
   {
-    return mozilla::dom::binding::HTMLCollection::create(cx, scope, this,
+    return mozilla::dom::oldproxybindings::HTMLCollection::create(cx, scope, this,
                                                          triedToWrap);
   }
 
   nsHTMLFormElement* mForm;  // WEAK - the form owns me
 
   nsTArray<nsGenericHTMLFormElement*> mElements;  // Holds WEAK references - bug 36639
 
   // This array holds on to all form controls that are not contained
--- a/content/html/content/src/nsHTMLMediaElement.cpp
+++ b/content/html/content/src/nsHTMLMediaElement.cpp
@@ -550,22 +550,16 @@ nsHTMLMediaElement::OnChannelRedirect(ns
 }
 
 void nsHTMLMediaElement::ShutdownDecoder()
 {
   RemoveMediaElementFromURITable();
   NS_ASSERTION(mDecoder, "Must have decoder to shut down");
   mDecoder->Shutdown();
   mDecoder = nullptr;
-  // Discard all output streams. mDecoder->Shutdown() will have finished all
-  // its output streams.
-  // XXX For now we ignore mFinishWhenEnded. We'll fix this later. The
-  // immediate goal is to not crash when reloading a media element with
-  // output streams.
-  mOutputStreams.Clear();
 }
 
 void nsHTMLMediaElement::AbortExistingLoads()
 {
   // Abort any already-running instance of the resource selection algorithm.
   mLoadWaitStatus = NOT_WAITING;
 
   // Set a new load ID. This will cause events which were enqueued
@@ -1519,26 +1513,30 @@ NS_IMETHODIMP nsHTMLMediaElement::SetMut
 
   return NS_OK;
 }
 
 already_AddRefed<nsDOMMediaStream>
 nsHTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded)
 {
   OutputMediaStream* out = mOutputStreams.AppendElement();
-  out->mStream = nsDOMMediaStream::CreateInputStream();
+  out->mStream = nsDOMMediaStream::CreateTrackUnionStream();
   nsRefPtr<nsIPrincipal> principal = GetCurrentPrincipal();
   out->mStream->CombineWithPrincipal(principal);
   out->mFinishWhenEnded = aFinishWhenEnded;
 
   mAudioCaptured = true;
+  // Block the output stream initially.
+  // Decoders are responsible for removing the block while they are playing
+  // back into the output stream.
+  out->mStream->GetStream()->ChangeExplicitBlockerCount(1);
   if (mDecoder) {
     mDecoder->SetAudioCaptured(true);
     mDecoder->AddOutputStream(
-        out->mStream->GetStream()->AsSourceStream(), aFinishWhenEnded);
+        out->mStream->GetStream()->AsProcessedStream(), aFinishWhenEnded);
   }
   nsRefPtr<nsDOMMediaStream> result = out->mStream;
   return result.forget();
 }
 
 NS_IMETHODIMP nsHTMLMediaElement::MozCaptureStream(nsIDOMMediaStream** aStream)
 {
   *aStream = CaptureStreamInternal(false).get();
@@ -2471,17 +2469,17 @@ nsresult nsHTMLMediaElement::FinishDecod
 
   // The new stream has not been suspended by us.
   mPausedForInactiveDocument = false;
 
   aDecoder->SetAudioCaptured(mAudioCaptured);
   aDecoder->SetVolume(mMuted ? 0.0 : mVolume);
   for (uint32_t i = 0; i < mOutputStreams.Length(); ++i) {
     OutputMediaStream* ms = &mOutputStreams[i];
-    aDecoder->AddOutputStream(ms->mStream->GetStream()->AsSourceStream(),
+    aDecoder->AddOutputStream(ms->mStream->GetStream()->AsProcessedStream(),
         ms->mFinishWhenEnded);
   }
 
   nsresult rv = aDecoder->Load(aStream, aListener, aCloneDonor);
   if (NS_FAILED(rv)) {
     LOG(PR_LOG_DEBUG, ("%p Failed to load for decoder %p", this, aDecoder));
     return rv;
   }
@@ -2823,16 +2821,24 @@ void nsHTMLMediaElement::Error(uint16_t 
 
 void nsHTMLMediaElement::PlaybackEnded()
 {
   // We changed state which can affect AddRemoveSelfReference
   AddRemoveSelfReference();
 
   NS_ASSERTION(!mDecoder || mDecoder->IsEnded(),
                "Decoder fired ended, but not in ended state");
+
+  // Discard all output streams that have finished now.
+  for (int32_t i = mOutputStreams.Length() - 1; i >= 0; --i) {
+    if (mOutputStreams[i].mFinishWhenEnded) {
+      mOutputStreams.RemoveElementAt(i);
+    }
+  }
+
   if (mSrcStream || (mDecoder && mDecoder->IsInfinite())) {
     LOG(PR_LOG_DEBUG, ("%p, got duration by reaching the end of the resource", this));
     DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
   }
 
   if (HasAttr(kNameSpaceID_None, nsGkAtoms::loop)) {
     SetCurrentTime(0);
     return;
--- a/content/html/content/src/nsHTMLSelectElement.cpp
+++ b/content/html/content/src/nsHTMLSelectElement.cpp
@@ -2010,17 +2010,17 @@ NS_INTERFACE_MAP_END
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsHTMLOptionCollection)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsHTMLOptionCollection)
 
 
 JSObject*
 nsHTMLOptionCollection::WrapObject(JSContext *cx, JSObject *scope,
                                    bool *triedToWrap)
 {
-  return mozilla::dom::binding::HTMLOptionsCollection::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::HTMLOptionsCollection::create(cx, scope, this,
                                                               triedToWrap);
 }
 
 NS_IMETHODIMP
 nsHTMLOptionCollection::GetLength(uint32_t* aLength)
 {
   *aLength = mElements.Length();
 
--- a/content/html/content/src/nsHTMLTableElement.cpp
+++ b/content/html/content/src/nsHTMLTableElement.cpp
@@ -51,17 +51,17 @@ public:
   NS_IMETHOD    ParentDestroyed();
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TableRowsCollection)
 
   // nsWrapperCache
   virtual JSObject* WrapObject(JSContext *cx, JSObject *scope,
                                bool *triedToWrap)
   {
-    return mozilla::dom::binding::HTMLCollection::create(cx, scope, this,
+    return mozilla::dom::oldproxybindings::HTMLCollection::create(cx, scope, this,
                                                          triedToWrap);
   }
 
 protected:
   // Those rows that are not in table sections
   nsHTMLTableElement* mParent;
   nsRefPtr<nsContentList> mOrphanRows;  
 };
--- a/content/media/MediaResource.cpp
+++ b/content/media/MediaResource.cpp
@@ -23,17 +23,16 @@
 #include "nsCrossSiteListenerProxy.h"
 #include "nsHTMLMediaElement.h"
 #include "nsError.h"
 #include "nsICachingChannel.h"
 #include "nsURILoader.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "mozilla/Util.h" // for DebugOnly
 #include "nsContentUtils.h"
-#include "nsBlobProtocolHandler.h"
 
 static const uint32_t HTTP_OK_CODE = 200;
 static const uint32_t HTTP_PARTIAL_RESPONSE_CODE = 206;
 
 using namespace mozilla;
 
 ChannelMediaResource::ChannelMediaResource(nsMediaDecoder* aDecoder,
     nsIChannel* aChannel, nsIURI* aURI)
@@ -1034,25 +1033,24 @@ nsresult FileMediaResource::Open(nsIStre
   }
 
   nsresult rv = NS_OK;
   if (aStreamListener) {
     // The channel is already open. We need a synchronous stream that
     // implements nsISeekableStream, so we have to find the underlying
     // file and reopen it
     nsCOMPtr<nsIFileChannel> fc(do_QueryInterface(mChannel));
-    if (fc) {
-      nsCOMPtr<nsIFile> file;
-      rv = fc->GetFile(getter_AddRefs(file));
-      NS_ENSURE_SUCCESS(rv, rv);
+    if (!fc)
+      return NS_ERROR_UNEXPECTED;
 
-      rv = NS_NewLocalFileInputStream(getter_AddRefs(mInput), file);
-    } else if (IsBlobURI(mURI)) {
-      rv = NS_GetStreamForBlobURI(mURI, getter_AddRefs(mInput));
-    }
+    nsCOMPtr<nsIFile> file;
+    rv = fc->GetFile(getter_AddRefs(file));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = NS_NewLocalFileInputStream(getter_AddRefs(mInput), file);
   } else {
     // Ensure that we never load a local file from some page on a
     // web server.
     nsHTMLMediaElement* element = mDecoder->GetMediaElement();
     NS_ENSURE_TRUE(element, NS_ERROR_FAILURE);
 
     rv = nsContentUtils::GetSecurityManager()->
            CheckLoadURIWithPrincipal(element->NodePrincipal(),
@@ -1198,27 +1196,27 @@ int64_t FileMediaResource::Tell()
   mSeekable->Tell(&offset);
   return offset;
 }
 
 MediaResource*
 MediaResource::Create(nsMediaDecoder* aDecoder, nsIChannel* aChannel)
 {
   NS_ASSERTION(NS_IsMainThread(),
-               "MediaResource::Open called on non-main thread");
+	             "MediaResource::Open called on non-main thread");
 
   // If the channel was redirected, we want the post-redirect URI;
   // but if the URI scheme was expanded, say from chrome: to jar:file:,
   // we want the original URI.
   nsCOMPtr<nsIURI> uri;
   nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
   NS_ENSURE_SUCCESS(rv, nullptr);
 
   nsCOMPtr<nsIFileChannel> fc = do_QueryInterface(aChannel);
-  if (fc || IsBlobURI(uri)) {
+  if (fc) {
     return new FileMediaResource(aDecoder, aChannel, uri);
   }
   return new ChannelMediaResource(aDecoder, aChannel, uri);
 }
 
 void MediaResource::MoveLoadsToBackground() {
   NS_ASSERTION(!mLoadInBackground, "Why are you calling this more than once?");
   mLoadInBackground = true;
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -2073,29 +2073,28 @@ SourceMediaStream::Finish()
 
 void
 MediaInputPort::Init()
 {
   LOG(PR_LOG_DEBUG, ("Adding MediaInputPort %p (from %p to %p) to the graph",
       this, mSource, mDest));
   mSource->AddConsumer(this);
   mDest->AddInput(this);
-  // mPortCount decremented in Disconnect()
+  // mPortCount decremented via MediaInputPort::Destroy's message
   ++mDest->GraphImpl()->mPortCount;
 }
 
 void
 MediaInputPort::Disconnect()
 {
   NS_ASSERTION(!mSource == !mDest,
                "mSource must either both be null or both non-null");
   if (!mSource)
     return;
 
-  --mDest->GraphImpl()->mPortCount;
   mSource->RemoveConsumer(this);
   mSource = nullptr;
   mDest->RemoveInput(this);
   mDest = nullptr;
 }
 
 MediaInputPort::InputInterval
 MediaInputPort::GetNextInputInterval(GraphTime aTime)
@@ -2118,32 +2117,45 @@ MediaInputPort::GetNextInputInterval(Gra
 }
 
 void
 MediaInputPort::Destroy()
 {
   class Message : public ControlMessage {
   public:
     Message(MediaInputPort* aPort)
-      : ControlMessage(aPort->GetDestination()), mPort(aPort) {}
+      : ControlMessage(nullptr), mPort(aPort) {}
     virtual void Run()
     {
       mPort->Disconnect();
+      --mPort->GraphImpl()->mPortCount;
       NS_RELEASE(mPort);
     }
     virtual void RunDuringShutdown()
     {
       Run();
     }
     // This does not need to be strongly referenced; the graph is holding
     // a strong reference to the port, which we will remove. This will be the
     // last message for the port.
     MediaInputPort* mPort;
   };
-  mSource->GraphImpl()->AppendMessage(new Message(this));
+  GraphImpl()->AppendMessage(new Message(this));
+}
+
+MediaStreamGraphImpl*
+MediaInputPort::GraphImpl()
+{
+  return gGraph;
+}
+
+MediaStreamGraph*
+MediaInputPort::Graph()
+{
+  return gGraph;
 }
 
 MediaInputPort*
 ProcessedMediaStream::AllocateInputPort(MediaStream* aStream, uint32_t aFlags)
 {
   class Message : public ControlMessage {
   public:
     Message(MediaInputPort* aPort)
--- a/content/media/MediaStreamGraph.h
+++ b/content/media/MediaStreamGraph.h
@@ -680,16 +680,22 @@ public:
     GraphTime mStart;
     GraphTime mEnd;
     bool mInputIsBlocked;
   };
   // Find the next time interval starting at or after aTime during which
   // mDest is not blocked and mSource's blocking status does not change.
   InputInterval GetNextInputInterval(GraphTime aTime);
 
+  /**
+   * Returns the graph that owns this port.
+   */
+  MediaStreamGraphImpl* GraphImpl();
+  MediaStreamGraph* Graph();
+
 protected:
   friend class MediaStreamGraphImpl;
   friend class MediaStream;
   friend class ProcessedMediaStream;
   // Never modified after Init()
   MediaStream* mSource;
   ProcessedMediaStream* mDest;
   uint32_t mFlags;
--- a/content/media/nsBuiltinDecoder.cpp
+++ b/content/media/nsBuiltinDecoder.cpp
@@ -54,24 +54,136 @@ void nsBuiltinDecoder::SetAudioCaptured(
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   mInitialAudioCaptured = aCaptured;
   if (mDecoderStateMachine) {
     mDecoderStateMachine->SetAudioCaptured(aCaptured);
   }
 }
 
-void nsBuiltinDecoder::AddOutputStream(SourceMediaStream* aStream, bool aFinishWhenEnded)
+void nsBuiltinDecoder::ConnectDecodedStreamToOutputStream(OutputStreamData* aStream)
+{
+  NS_ASSERTION(!aStream->mPort, "Already connected?");
+
+  // The output stream must stay in sync with the decoded stream, so if
+  // either stream is blocked, we block the other.
+  aStream->mPort = aStream->mStream->AllocateInputPort(mDecodedStream->mStream,
+      MediaInputPort::FLAG_BLOCK_INPUT | MediaInputPort::FLAG_BLOCK_OUTPUT);
+  // Unblock the output stream now. While it's connected to mDecodedStream,
+  // mDecodedStream is responsible for controlling blocking.
+  aStream->mStream->ChangeExplicitBlockerCount(-1);
+}
+
+nsBuiltinDecoder::DecodedStreamData::DecodedStreamData(nsBuiltinDecoder* aDecoder,
+                                                       int64_t aInitialTime,
+                                                       SourceMediaStream* aStream)
+  : mLastAudioPacketTime(-1),
+    mLastAudioPacketEndTime(-1),
+    mAudioFramesWritten(0),
+    mInitialTime(aInitialTime),
+    mNextVideoTime(aInitialTime),
+    mStreamInitialized(false),
+    mHaveSentFinish(false),
+    mHaveSentFinishAudio(false),
+    mHaveSentFinishVideo(false),
+    mStream(aStream),
+    mMainThreadListener(new DecodedStreamMainThreadListener(aDecoder)),
+    mHaveBlockedForPlayState(false)
+{
+  mStream->AddMainThreadListener(mMainThreadListener);
+}
+
+nsBuiltinDecoder::DecodedStreamData::~DecodedStreamData()
+{
+  mStream->RemoveMainThreadListener(mMainThreadListener);
+  mStream->Destroy();
+}
+
+void nsBuiltinDecoder::DestroyDecodedStream()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
+  mReentrantMonitor.AssertCurrentThreadIn();
+
+  // All streams are having their SourceMediaStream disconnected, so they
+  // need to be explicitly blocked again.
+  for (uint32_t i = 0; i < mOutputStreams.Length(); ++i) {
+    OutputStreamData& os = mOutputStreams[i];
+    // During cycle collection, nsDOMMediaStream can be destroyed and send
+    // its Destroy message before this decoder is destroyed. So we have to
+    // be careful not to send any messages after the Destroy().
+    if (!os.mStream->IsDestroyed()) {
+      os.mStream->ChangeExplicitBlockerCount(1);
+    }
+    // Explicitly remove all existing ports. This is not strictly necessary but it's
+    // good form.
+    os.mPort->Destroy();
+    os.mPort = nullptr;
+  }
+
+  mDecodedStream = nullptr;
+}
+
+void nsBuiltinDecoder::RecreateDecodedStream(int64_t aStartTimeUSecs)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
+  mReentrantMonitor.AssertCurrentThreadIn();
+  LOG(PR_LOG_DEBUG, ("nsBuiltinDecoder::RecreateDecodedStream this=%p aStartTimeUSecs=%lld!",
+                     this, (long long)aStartTimeUSecs));
+
+  DestroyDecodedStream();
+
+  mDecodedStream = new DecodedStreamData(this, aStartTimeUSecs,
+    MediaStreamGraph::GetInstance()->CreateInputStream(nullptr));
+
+  // Note that the delay between removing ports in DestroyDecodedStream
+  // and adding new ones won't cause a glitch since all graph operations
+  // between main-thread stable states take effect atomically.
+  for (uint32_t i = 0; i < mOutputStreams.Length(); ++i) {
+    ConnectDecodedStreamToOutputStream(&mOutputStreams[i]);
+  }
+
+  mDecodedStream->mHaveBlockedForPlayState = mPlayState != PLAY_STATE_PLAYING;
+  if (mDecodedStream->mHaveBlockedForPlayState) {
+    mDecodedStream->mStream->ChangeExplicitBlockerCount(1);
+  }
+}
+
+void nsBuiltinDecoder::NotifyDecodedStreamMainThreadStateChanged()
+{
+  if (mTriggerPlaybackEndedWhenSourceStreamFinishes && mDecodedStream &&
+      mDecodedStream->mStream->IsFinished()) {
+    mTriggerPlaybackEndedWhenSourceStreamFinishes = false;
+    if (GetState() == PLAY_STATE_PLAYING) {
+      nsCOMPtr<nsIRunnable> event =
+        NS_NewRunnableMethod(this, &nsBuiltinDecoder::PlaybackEnded);
+      NS_DispatchToCurrentThread(event);
+    }
+  }
+}
+
+void nsBuiltinDecoder::AddOutputStream(ProcessedMediaStream* aStream,
+                                       bool aFinishWhenEnded)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
+  LOG(PR_LOG_DEBUG, ("nsBuiltinDecoder::AddOutputStream this=%p aStream=%p!",
+                     this, aStream));
 
   {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
-    OutputMediaStream* ms = mOutputStreams.AppendElement();
-    ms->Init(int64_t(mCurrentTime*USECS_PER_S), aStream, aFinishWhenEnded);
+    if (!mDecodedStream) {
+      RecreateDecodedStream(mDecoderStateMachine ?
+          int64_t(mDecoderStateMachine->GetCurrentTime()*USECS_PER_S) : 0);
+    }
+    OutputStreamData* os = mOutputStreams.AppendElement();
+    os->Init(aStream, aFinishWhenEnded);
+    ConnectDecodedStreamToOutputStream(os);
+    if (aFinishWhenEnded) {
+      // Ensure that aStream finishes the moment mDecodedStream does.
+      aStream->SetAutofinish(true);
+    }
   }
 
   // This can be called before Load(), in which case our mDecoderStateMachine
   // won't have been created yet and we can rely on Load() to schedule it
   // once it is created.
   if (mDecoderStateMachine) {
     // Make sure the state machine thread runs so that any buffered data
     // is fed into our stream.
@@ -111,17 +223,18 @@ nsBuiltinDecoder::nsBuiltinDecoder() :
   mRequestedSeekTime(-1.0),
   mDuration(-1),
   mSeekable(true),
   mReentrantMonitor("media.decoder"),
   mPlayState(PLAY_STATE_PAUSED),
   mNextState(PLAY_STATE_PAUSED),
   mResourceLoaded(false),
   mIgnoreProgressData(false),
-  mInfiniteStream(false)
+  mInfiniteStream(false),
+  mTriggerPlaybackEndedWhenSourceStreamFinishes(false)
 {
   MOZ_COUNT_CTOR(nsBuiltinDecoder);
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
 #ifdef PR_LOGGING
   if (!gBuiltinDecoderLog) {
     gBuiltinDecoderLog = PR_NewLogModule("nsBuiltinDecoder");
   }
 #endif
@@ -141,16 +254,21 @@ void nsBuiltinDecoder::Shutdown()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   
   if (mShuttingDown)
     return;
 
   mShuttingDown = true;
 
+  {
+    ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
+    DestroyDecodedStream();
+  }
+
   // This changes the decoder state to SHUTDOWN and does other things
   // necessary to unblock the state machine thread if it's blocked, so
   // the asynchronous shutdown in nsDestroyStateMachine won't deadlock.
   if (mDecoderStateMachine) {
     mDecoderStateMachine->Shutdown();
   }
 
   // Force any outstanding seek and byterange requests to complete
@@ -538,20 +656,46 @@ bool nsBuiltinDecoder::IsSeeking() const
 bool nsBuiltinDecoder::IsEnded() const
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   return mPlayState == PLAY_STATE_ENDED || mPlayState == PLAY_STATE_SHUTDOWN;
 }
 
 void nsBuiltinDecoder::PlaybackEnded()
 {
+  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
+
   if (mShuttingDown || mPlayState == nsBuiltinDecoder::PLAY_STATE_SEEKING)
     return;
 
-  printf("nsBuiltinDecoder::PlaybackEnded mPlayState=%d\n", mPlayState);
+  {
+    ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+
+    if (mDecodedStream && !mDecodedStream->mStream->IsFinished()) {
+      // Wait for it to finish before firing PlaybackEnded()
+      mTriggerPlaybackEndedWhenSourceStreamFinishes = true;
+      return;
+    }
+
+    for (int32_t i = mOutputStreams.Length() - 1; i >= 0; --i) {
+      OutputStreamData& os = mOutputStreams[i];
+      if (os.mFinishWhenEnded) {
+        // Shouldn't really be needed since mDecodedStream should already have
+        // finished, but doesn't hurt.
+        os.mStream->Finish();
+        os.mPort->Destroy();
+        os.mPort = nullptr;
+        // Not really needed but it keeps the invariant that a stream not
+        // connected to mDecodedStream is explicity blocked.
+        os.mStream->ChangeExplicitBlockerCount(1);
+        mOutputStreams.RemoveElementAt(i);
+      }
+    }
+  }
+
   PlaybackPositionChanged();
   ChangeState(PLAY_STATE_ENDED);
 
   if (mElement)  {
     UpdateReadyStateForData();
     mElement->PlaybackEnded();
   }
 
@@ -760,17 +904,16 @@ void nsBuiltinDecoder::SeekingStopped()
 
     // An additional seek was requested while the current seek was
     // in operation.
     if (mRequestedSeekTime >= 0.0) {
       ChangeState(PLAY_STATE_SEEKING);
       seekWasAborted = true;
     } else {
       UnpinForSeek();
-      printf("nsBuiltinDecoder::SeekingStopped, next state=%d\n", mNextState);
       ChangeState(mNextState);
     }
   }
 
   if (mElement) {
     UpdateReadyStateForData();
     if (!seekWasAborted) {
       mElement->SeekCompleted();
@@ -837,16 +980,23 @@ void nsBuiltinDecoder::ChangeState(PlayS
     mNextState = PLAY_STATE_PAUSED;
   }
 
   if (mPlayState == PLAY_STATE_SHUTDOWN) {
     mReentrantMonitor.NotifyAll();
     return;
   }
 
+  if (mDecodedStream) {
+    bool blockForPlayState = aState != PLAY_STATE_PLAYING;
+    if (mDecodedStream->mHaveBlockedForPlayState != blockForPlayState) {
+      mDecodedStream->mStream->ChangeExplicitBlockerCount(blockForPlayState ? 1 : -1);
+      mDecodedStream->mHaveBlockedForPlayState = blockForPlayState;
+    }
+  }
   mPlayState = aState;
   if (mDecoderStateMachine) {
     switch (aState) {
     case PLAY_STATE_PLAYING:
       mDecoderStateMachine->Play();
       break;
     case PLAY_STATE_SEEKING:
       mDecoderStateMachine->Seek(mRequestedSeekTime);
@@ -1043,51 +1193,8 @@ bool nsBuiltinDecoder::OnStateMachineThr
 void nsBuiltinDecoder::NotifyAudioAvailableListener()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   if (mDecoderStateMachine) {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     mDecoderStateMachine->NotifyAudioAvailableListener();
   }
 }
-
-nsBuiltinDecoder::OutputMediaStream::OutputMediaStream()
-{
-
-}
-
-nsBuiltinDecoder::OutputMediaStream::~OutputMediaStream()
-{
-
-}
-    
-
-void nsBuiltinDecoder::OutputMediaStream::Init(int64_t aInitialTime, SourceMediaStream* aStream, bool aFinishWhenEnded)
-{
-  mLastAudioPacketTime = -1;
-  mLastAudioPacketEndTime = -1;
-  mAudioFramesWrittenBaseTime = aInitialTime;
-  mAudioFramesWritten = 0;
-  mNextVideoTime = aInitialTime;
-  mStream = aStream;
-  mStreamInitialized = false;
-  mFinishWhenEnded = aFinishWhenEnded;
-  mHaveSentFinish = false;
-  mHaveSentFinishAudio = false;
-  mHaveSentFinishVideo = false;
-}
-
-nsBuiltinDecoder::OutputMediaStream::OutputMediaStream(const OutputMediaStream& rhs)
-{
-  mLastAudioPacketTime = rhs.mLastAudioPacketTime;
-  mLastAudioPacketEndTime = rhs.mLastAudioPacketEndTime;
-  mAudioFramesWritten = rhs.mAudioFramesWritten;
-  mAudioFramesWrittenBaseTime = rhs.mAudioFramesWrittenBaseTime;
-  mNextVideoTime = rhs.mNextVideoTime;
-  mLastVideoImage = rhs.mLastVideoImage;
-  mStream = rhs.mStream;
-  mLastVideoImageDisplaySize = rhs.mLastVideoImageDisplaySize;
-  mStreamInitialized = rhs.mStreamInitialized;
-  mFinishWhenEnded = rhs.mFinishWhenEnded;
-  mHaveSentFinish = rhs.mHaveSentFinish;
-  mHaveSentFinishAudio = rhs.mHaveSentFinishAudio;
-  mHaveSentFinishVideo = rhs.mHaveSentFinishVideo;
-}
--- a/content/media/nsBuiltinDecoder.h
+++ b/content/media/nsBuiltinDecoder.h
@@ -327,16 +327,17 @@ public:
   // element. Called on the main thread.
   virtual void NotifyAudioAvailableListener() = 0;
 };
 
 class nsBuiltinDecoder : public nsMediaDecoder
 {
 public:
   typedef mozilla::MediaChannelStatistics MediaChannelStatistics;
+  class DecodedStreamMainThreadListener;
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
   // Enumeration for the valid play states (see mPlayState)
   enum PlayState {
     PLAY_STATE_START,
     PLAY_STATE_LOADING,
@@ -372,53 +373,116 @@ public:
   virtual nsresult Seek(double aTime);
 
   virtual nsresult PlaybackRateChanged();
 
   virtual void Pause();
   virtual void SetVolume(double aVolume);
   virtual void SetAudioCaptured(bool aCaptured);
 
-  virtual void AddOutputStream(SourceMediaStream* aStream, bool aFinishWhenEnded);
-  // Protected by mReentrantMonitor. All decoder output is copied to these streams.
-  struct OutputMediaStream {
-    OutputMediaStream();
-    ~OutputMediaStream();
-    OutputMediaStream(const OutputMediaStream& rhs);
+  // All MediaStream-related data is protected by mReentrantMonitor.
+  // We have at most one DecodedStreamData per nsBuiltinDecoder. Its stream
+  // is used as the input for each ProcessedMediaStream created by calls to
+  // captureStream(UntilEnded). Seeking creates a new source stream, as does
+  // replaying after the input as ended. In the latter case, the new source is
+  // not connected to streams created by captureStreamUntilEnded.
 
-    void Init(int64_t aInitialTime, SourceMediaStream* aStream, bool aFinishWhenEnded);
-    
+  struct DecodedStreamData {
+    DecodedStreamData(nsBuiltinDecoder* aDecoder,
+                      int64_t aInitialTime, SourceMediaStream* aStream);
+    ~DecodedStreamData();
+
+    // The following group of fields are protected by the decoder's monitor
+    // and can be read or written on any thread.    
     int64_t mLastAudioPacketTime; // microseconds
     int64_t mLastAudioPacketEndTime; // microseconds
     // Count of audio frames written to the stream
     int64_t mAudioFramesWritten;
-    // Timestamp of the first audio packet whose frames we wrote.
-    int64_t mAudioFramesWrittenBaseTime; // microseconds
+    // Saved value of aInitialTime. Timestamp of the first audio and/or
+    // video packet written.
+    int64_t mInitialTime; // microseconds
     // mNextVideoTime is the end timestamp for the last packet sent to the stream.
     // Therefore video packets starting at or after this time need to be copied
     // to the output stream.
     int64_t mNextVideoTime; // microseconds
     // The last video image sent to the stream. Useful if we need to replicate
     // the image.
     nsRefPtr<Image> mLastVideoImage;
-    nsRefPtr<SourceMediaStream> mStream;
     gfxIntSize mLastVideoImageDisplaySize;
     // This is set to true when the stream is initialized (audio and
     // video tracks added).
     bool mStreamInitialized;
-    bool mFinishWhenEnded;
     bool mHaveSentFinish;
     bool mHaveSentFinishAudio;
     bool mHaveSentFinishVideo;
+
+    // The decoder is responsible for calling Destroy() on this stream.
+    // Can be read from any thread.
+    const nsRefPtr<SourceMediaStream> mStream;
+    // A listener object that receives notifications when mStream's
+    // main-thread-visible state changes. Used on the main thread only.
+    const nsRefPtr<DecodedStreamMainThreadListener> mMainThreadListener;
+    // True when we've explicitly blocked this stream because we're
+    // not in PLAY_STATE_PLAYING. Used on the main thread only.
+    bool mHaveBlockedForPlayState;
   };
-  nsTArray<OutputMediaStream>& OutputStreams()
+  struct OutputStreamData {
+    void Init(ProcessedMediaStream* aStream, bool aFinishWhenEnded)
+    {
+      mStream = aStream;
+      mFinishWhenEnded = aFinishWhenEnded;
+    }
+    nsRefPtr<ProcessedMediaStream> mStream;
+    // mPort connects mDecodedStream->mStream to our mStream.
+    nsRefPtr<MediaInputPort> mPort;
+    bool mFinishWhenEnded;
+  };
+  /**
+   * Connects mDecodedStream->mStream to aStream->mStream.
+   */
+  void ConnectDecodedStreamToOutputStream(OutputStreamData* aStream);
+  /**
+   * Disconnects mDecodedStream->mStream from all outputs and clears
+   * mDecodedStream.
+   */
+  void DestroyDecodedStream();
+  /**
+   * Recreates mDecodedStream. Call this to create mDecodedStream at first,
+   * and when seeking, to ensure a new stream is set up with fresh buffers.
+   * aStartTimeUSecs is relative to the state machine's mStartTime.
+   */
+  void RecreateDecodedStream(int64_t aStartTimeUSecs);
+  /**
+   * Called when the state of mDecodedStream as visible on the main thread
+   * has changed. In particular we want to know when the stream has finished
+   * so we can call PlaybackEnded.
+   */
+  void NotifyDecodedStreamMainThreadStateChanged();
+  nsTArray<OutputStreamData>& OutputStreams()
   {
     GetReentrantMonitor().AssertCurrentThreadIn();
     return mOutputStreams;
   }
+  DecodedStreamData* GetDecodedStream()
+  {
+    GetReentrantMonitor().AssertCurrentThreadIn();
+    return mDecodedStream;
+  }
+  class DecodedStreamMainThreadListener : public MainThreadMediaStreamListener {
+  public:
+    DecodedStreamMainThreadListener(nsBuiltinDecoder* aDecoder)
+      : mDecoder(aDecoder) {}
+    virtual void NotifyMainThreadStateChanged()
+    {
+      mDecoder->NotifyDecodedStreamMainThreadStateChanged();
+    }
+    nsBuiltinDecoder* mDecoder;
+  };
+
+  virtual void AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
 
   virtual double GetDuration();
 
   virtual void SetInfinite(bool aInfinite);
   virtual bool IsInfinite();
 
   virtual MediaResource* GetResource() { return mResource; }
   virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal();
@@ -705,17 +769,23 @@ public:
   nsAutoPtr<MediaResource> mResource;
 
   // ReentrantMonitor for detecting when the video play state changes. A call
   // to Wait on this monitor will block the thread until the next
   // state change.
   ReentrantMonitor mReentrantMonitor;
 
   // Data about MediaStreams that are being fed by this decoder.
-  nsTArray<OutputMediaStream> mOutputStreams;
+  nsTArray<OutputStreamData> mOutputStreams;
+  // The SourceMediaStream we are using to feed the mOutputStreams. This stream
+  // is never exposed outside the decoder.
+  // Only written on the main thread while holding the monitor. Therefore it
+  // can be read on any thread while holding the monitor, or on the main thread
+  // without holding the monitor.
+  nsAutoPtr<DecodedStreamData> mDecodedStream;
 
   // Set to one of the valid play states.
   // This can only be changed on the main thread while holding the decoder
   // monitor. Thus, it can be safely read while holding the decoder monitor
   // OR on the main thread.
   // Any change to the state on the main thread must call NotifyAll on the
   // monitor so the decode thread can wake up.
   PlayState mPlayState;
@@ -737,11 +807,15 @@ public:
   // such a manner that progress event data is inaccurate. This is set
   // during seek and duration operations to prevent the progress indicator
   // from jumping around. Read/Write from any thread. Must have decode monitor
   // locked before accessing.
   bool mIgnoreProgressData;
 
   // True if the stream is infinite (e.g. a webradio).
   bool mInfiniteStream;
+
+  // True if NotifyDecodedStreamMainThreadStateChanged should retrigger
+  // PlaybackEnded when mDecodedStream->mStream finishes.
+  bool mTriggerPlaybackEndedWhenSourceStreamFinishes;
 };
 
 #endif
--- a/content/media/nsBuiltinDecoderStateMachine.cpp
+++ b/content/media/nsBuiltinDecoderStateMachine.cpp
@@ -423,16 +423,18 @@ nsBuiltinDecoderStateMachine::nsBuiltinD
   mBufferingWait = mRealTime ? 0 : BUFFERING_WAIT_S;
   mLowDataThresholdUsecs = mRealTime ? 0 : LOW_DATA_THRESHOLD_USECS;
 }
 
 nsBuiltinDecoderStateMachine::~nsBuiltinDecoderStateMachine()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   MOZ_COUNT_DTOR(nsBuiltinDecoderStateMachine);
+  NS_ASSERTION(!mPendingWakeDecoder.get(),
+               "WakeDecoder should have been revoked already");
   NS_ASSERTION(!StateMachineTracker::Instance().IsQueued(this),
     "Should not have a pending request for a new decode thread");
   NS_ASSERTION(!mRequestedNewDecodeThread,
     "Should not have (or flagged) a pending request for a new decode thread");
   if (mTimer)
     mTimer->Cancel();
   mTimer = nullptr;
   mReader = nullptr;
@@ -491,36 +493,37 @@ void nsBuiltinDecoderStateMachine::Decod
       DecodeSeek();
     }
   }
 
   mDecodeThreadIdle = true;
   LOG(PR_LOG_DEBUG, ("%p Decode thread finished", mDecoder.get()));
 }
 
-void nsBuiltinDecoderStateMachine::SendOutputStreamAudio(AudioData* aAudio,
-                                                         OutputMediaStream* aStream,
-                                                         AudioSegment* aOutput)
+void nsBuiltinDecoderStateMachine::SendStreamAudio(AudioData* aAudio,
+                                                   DecodedStreamData* aStream,
+                                                   AudioSegment* aOutput)
 {
+  NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
   mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
 
   if (aAudio->mTime <= aStream->mLastAudioPacketTime) {
     // ignore packet that we've already processed
     return;
   }
   aStream->mLastAudioPacketTime = aAudio->mTime;
   aStream->mLastAudioPacketEndTime = aAudio->GetEnd();
 
   NS_ASSERTION(aOutput->GetChannels() == int32_t(aAudio->mChannels),
                "Wrong number of channels");
 
   // This logic has to mimic AudioLoop closely to make sure we write
   // the exact same silences
   CheckedInt64 audioWrittenOffset = UsecsToFrames(mInfo.mAudioRate,
-      aStream->mAudioFramesWrittenBaseTime + mStartTime) + aStream->mAudioFramesWritten;
+      aStream->mInitialTime + mStartTime) + aStream->mAudioFramesWritten;
   CheckedInt64 frameOffset = UsecsToFrames(mInfo.mAudioRate, aAudio->mTime);
   if (!audioWrittenOffset.isValid() || !frameOffset.isValid())
     return;
   if (audioWrittenOffset.value() < frameOffset.value()) {
     // Write silence to catch up
     LOG(PR_LOG_DEBUG, ("%p Decoder writing %d frames of silence to MediaStream",
                        mDecoder.get(), int32_t(frameOffset.value() - audioWrittenOffset.value())));
     AudioSegment silence;
@@ -560,121 +563,122 @@ static void WriteVideoToMediaStream(mozi
   nsRefPtr<mozilla::layers::Image> image = aImage;
   aOutput->AppendFrame(image.forget(), aDuration, aIntrinsicSize);
 }
 
 static const TrackID TRACK_AUDIO = 1;
 static const TrackID TRACK_VIDEO = 2;
 static const TrackRate RATE_VIDEO = USECS_PER_S;
 
-void nsBuiltinDecoderStateMachine::SendOutputStreamData()
+void nsBuiltinDecoderStateMachine::SendStreamData()
 {
+  NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
   mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
 
+  DecodedStreamData* stream = mDecoder->GetDecodedStream();
+  if (!stream)
+    return;
+
   if (mState == DECODER_STATE_DECODING_METADATA)
     return;
 
-  nsTArray<OutputMediaStream>& streams = mDecoder->OutputStreams();
   int64_t minLastAudioPacketTime = PR_INT64_MAX;
+  SourceMediaStream* mediaStream = stream->mStream;
+  StreamTime endPosition = 0;
+
+  if (!stream->mStreamInitialized) {
+    if (mInfo.mHasAudio) {
+      AudioSegment* audio = new AudioSegment();
+      audio->Init(mInfo.mAudioChannels);
+      mediaStream->AddTrack(TRACK_AUDIO, mInfo.mAudioRate, 0, audio);
+    }
+    if (mInfo.mHasVideo) {
+      VideoSegment* video = new VideoSegment();
+      mediaStream->AddTrack(TRACK_VIDEO, RATE_VIDEO, 0, video);
+    }
+    stream->mStreamInitialized = true;
+  }
+
+  if (mInfo.mHasAudio) {
+    nsAutoTArray<AudioData*,10> audio;
+    // It's OK to hold references to the AudioData because while audio
+    // is captured, only the decoder thread pops from the queue (see below).
+    mReader->mAudioQueue.GetElementsAfter(stream->mLastAudioPacketTime, &audio);
+    AudioSegment output;
+    output.Init(mInfo.mAudioChannels);
+    for (uint32_t i = 0; i < audio.Length(); ++i) {
+      SendStreamAudio(audio[i], stream, &output);
+    }
+    if (output.GetDuration() > 0) {
+      mediaStream->AppendToTrack(TRACK_AUDIO, &output);
+    }
+    if (mReader->mAudioQueue.IsFinished() && !stream->mHaveSentFinishAudio) {
+      mediaStream->EndTrack(TRACK_AUDIO);
+      stream->mHaveSentFinishAudio = true;
+    }
+    minLastAudioPacketTime = NS_MIN(minLastAudioPacketTime, stream->mLastAudioPacketTime);
+    endPosition = NS_MAX(endPosition,
+        TicksToTimeRoundDown(mInfo.mAudioRate, stream->mAudioFramesWritten));
+  }
+
+  if (mInfo.mHasVideo) {
+    nsAutoTArray<VideoData*,10> video;
+    // It's OK to hold references to the VideoData only the decoder thread
+    // pops from the queue.
+    mReader->mVideoQueue.GetElementsAfter(stream->mNextVideoTime + mStartTime, &video);
+    VideoSegment output;
+    for (uint32_t i = 0; i < video.Length(); ++i) {
+      VideoData* v = video[i];
+      if (stream->mNextVideoTime + mStartTime < v->mTime) {
+        LOG(PR_LOG_DEBUG, ("%p Decoder writing last video to MediaStream %p for %lld ms",
+                           mDecoder.get(), mediaStream,
+                           v->mTime - (stream->mNextVideoTime + mStartTime)));
+        // Write last video frame to catch up. mLastVideoImage can be null here
+        // which is fine, it just means there's no video.
+        WriteVideoToMediaStream(stream->mLastVideoImage,
+          v->mTime - (stream->mNextVideoTime + mStartTime), stream->mLastVideoImageDisplaySize,
+            &output);
+        stream->mNextVideoTime = v->mTime - mStartTime;
+      }
+      if (stream->mNextVideoTime + mStartTime < v->mEndTime) {
+        LOG(PR_LOG_DEBUG, ("%p Decoder writing video frame %lld to MediaStream %p for %lld ms",
+                           mDecoder.get(), v->mTime, mediaStream,
+                           v->mEndTime - (stream->mNextVideoTime + mStartTime)));
+        WriteVideoToMediaStream(v->mImage,
+            v->mEndTime - (stream->mNextVideoTime + mStartTime), v->mDisplay,
+            &output);
+        stream->mNextVideoTime = v->mEndTime - mStartTime;
+        stream->mLastVideoImage = v->mImage;
+        stream->mLastVideoImageDisplaySize = v->mDisplay;
+      } else {
+        LOG(PR_LOG_DEBUG, ("%p Decoder skipping writing video frame %lld to MediaStream",
+                           mDecoder.get(), v->mTime));
+      }
+    }
+    if (output.GetDuration() > 0) {
+      mediaStream->AppendToTrack(TRACK_VIDEO, &output);
+    }
+    if (mReader->mVideoQueue.IsFinished() && !stream->mHaveSentFinishVideo) {
+      mediaStream->EndTrack(TRACK_VIDEO);
+      stream->mHaveSentFinishVideo = true;
+    }
+    endPosition = NS_MAX(endPosition,
+        TicksToTimeRoundDown(RATE_VIDEO, stream->mNextVideoTime - stream->mInitialTime));
+  }
+
+  if (!stream->mHaveSentFinish) {
+    stream->mStream->AdvanceKnownTracksTime(endPosition);
+  }
 
   bool finished =
       (!mInfo.mHasAudio || mReader->mAudioQueue.IsFinished()) &&
       (!mInfo.mHasVideo || mReader->mVideoQueue.IsFinished());
-
-  for (uint32_t i = 0; i < streams.Length(); ++i) {
-    OutputMediaStream* stream = &streams[i];
-    SourceMediaStream* mediaStream = stream->mStream;
-    StreamTime endPosition = 0;
-
-    if (!stream->mStreamInitialized) {
-      if (mInfo.mHasAudio) {
-        AudioSegment* audio = new AudioSegment();
-        audio->Init(mInfo.mAudioChannels);
-        mediaStream->AddTrack(TRACK_AUDIO, mInfo.mAudioRate, 0, audio);
-      }
-      if (mInfo.mHasVideo) {
-        VideoSegment* video = new VideoSegment();
-        mediaStream->AddTrack(TRACK_VIDEO, RATE_VIDEO, 0, video);
-      }
-      stream->mStreamInitialized = true;
-    }
-
-    if (mInfo.mHasAudio) {
-      nsAutoTArray<AudioData*,10> audio;
-      // It's OK to hold references to the AudioData because while audio
-      // is captured, only the decoder thread pops from the queue (see below).
-      mReader->mAudioQueue.GetElementsAfter(stream->mLastAudioPacketTime, &audio);
-      AudioSegment output;
-      output.Init(mInfo.mAudioChannels);
-      for (uint32_t i = 0; i < audio.Length(); ++i) {
-        SendOutputStreamAudio(audio[i], stream, &output);
-      }
-      if (output.GetDuration() > 0) {
-        mediaStream->AppendToTrack(TRACK_AUDIO, &output);
-      }
-      if (mReader->mAudioQueue.IsFinished() && !stream->mHaveSentFinishAudio) {
-        mediaStream->EndTrack(TRACK_AUDIO);
-        stream->mHaveSentFinishAudio = true;
-      }
-      minLastAudioPacketTime = NS_MIN(minLastAudioPacketTime, stream->mLastAudioPacketTime);
-      endPosition = NS_MAX(endPosition,
-          TicksToTimeRoundDown(mInfo.mAudioRate, stream->mAudioFramesWritten));
-    }
-
-    if (mInfo.mHasVideo) {
-      nsAutoTArray<VideoData*,10> video;
-      // It's OK to hold references to the VideoData only the decoder thread
-      // pops from the queue.
-      mReader->mVideoQueue.GetElementsAfter(stream->mNextVideoTime + mStartTime, &video);
-      VideoSegment output;
-      for (uint32_t i = 0; i < video.Length(); ++i) {
-        VideoData* v = video[i];
-        if (stream->mNextVideoTime + mStartTime < v->mTime) {
-          LOG(PR_LOG_DEBUG, ("%p Decoder writing last video to MediaStream for %lld ms",
-                             mDecoder.get(), v->mTime - (stream->mNextVideoTime + mStartTime)));
-          // Write last video frame to catch up. mLastVideoImage can be null here
-          // which is fine, it just means there's no video.
-          WriteVideoToMediaStream(stream->mLastVideoImage,
-              v->mTime - (stream->mNextVideoTime + mStartTime), stream->mLastVideoImageDisplaySize,
-              &output);
-          stream->mNextVideoTime = v->mTime - mStartTime;
-        }
-        if (stream->mNextVideoTime + mStartTime < v->mEndTime) {
-          LOG(PR_LOG_DEBUG, ("%p Decoder writing video frame %lld to MediaStream",
-                             mDecoder.get(), v->mTime));
-          WriteVideoToMediaStream(v->mImage,
-              v->mEndTime - (stream->mNextVideoTime + mStartTime), v->mDisplay,
-              &output);
-          stream->mNextVideoTime = v->mEndTime - mStartTime;
-          stream->mLastVideoImage = v->mImage;
-          stream->mLastVideoImageDisplaySize = v->mDisplay;
-        } else {
-          LOG(PR_LOG_DEBUG, ("%p Decoder skipping writing video frame %lld to MediaStream",
-                             mDecoder.get(), v->mTime));
-        }
-      }
-      if (output.GetDuration() > 0) {
-        mediaStream->AppendToTrack(TRACK_VIDEO, &output);
-      }
-      if (mReader->mVideoQueue.IsFinished() && !stream->mHaveSentFinishVideo) {
-        mediaStream->EndTrack(TRACK_VIDEO);
-        stream->mHaveSentFinishVideo = true;
-      }
-      endPosition = NS_MAX(endPosition,
-          TicksToTimeRoundDown(RATE_VIDEO, stream->mNextVideoTime));
-    }
-
-    if (!stream->mHaveSentFinish) {
-      stream->mStream->AdvanceKnownTracksTime(endPosition);
-    }
-
-    if (finished && !stream->mHaveSentFinish) {
-      stream->mHaveSentFinish = true;
-      stream->mStream->Finish();
-    }
+  if (finished && !stream->mHaveSentFinish) {
+    stream->mHaveSentFinish = true;
+    stream->mStream->Finish();
   }
 
   if (mAudioCaptured) {
     // Discard audio packets that are no longer needed.
     int64_t audioPacketTimeToDiscard =
         NS_MIN(minLastAudioPacketTime, mStartTime + mCurrentFrameTime);
     while (true) {
       nsAutoPtr<AudioData> a(mReader->mAudioQueue.PopFront());
@@ -694,106 +698,68 @@ void nsBuiltinDecoderStateMachine::SendO
 
     if (finished) {
       mAudioCompleted = true;
       UpdateReadyState();
     }
   }
 }
 
-void nsBuiltinDecoderStateMachine::FinishOutputStreams()
+nsBuiltinDecoderStateMachine::WakeDecoderRunnable*
+nsBuiltinDecoderStateMachine::GetWakeDecoderRunnable()
 {
-  // Tell all our output streams that all tracks have ended and we've
-  // finished.
-  nsTArray<OutputMediaStream>& streams = mDecoder->OutputStreams();
-  for (uint32_t i = 0; i < streams.Length(); ++i) {
-    OutputMediaStream* stream = &streams[i];
-    if (!stream->mStreamInitialized) {
-      continue;
-    }
-    SourceMediaStream* mediaStream = stream->mStream;
-    if (mInfo.mHasAudio && !stream->mHaveSentFinishAudio) {
-      mediaStream->EndTrack(TRACK_AUDIO);
-      stream->mHaveSentFinishAudio = true;
-    }
-    if (mInfo.mHasVideo && !stream->mHaveSentFinishVideo) {
-      mediaStream->EndTrack(TRACK_VIDEO);
-      stream->mHaveSentFinishVideo = true;
-    }
-    // XXX ignoring mFinishWhenEnded for now. Immediate goal is to not crash.
-    if (!stream->mHaveSentFinish) {
-      mediaStream->Finish();
-      stream->mHaveSentFinish = true;
-    }
+  mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
+
+  if (!mPendingWakeDecoder.get()) {
+    mPendingWakeDecoder = new WakeDecoderRunnable(this);
   }
+  return mPendingWakeDecoder.get();
 }
 
 bool nsBuiltinDecoderStateMachine::HaveEnoughDecodedAudio(int64_t aAmpleAudioUSecs)
 {
   mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
 
   if (mReader->mAudioQueue.GetSize() == 0 ||
       GetDecodedAudioDuration() < aAmpleAudioUSecs) {
     return false;
   }
   if (!mAudioCaptured) {
     return true;
   }
 
-  nsTArray<OutputMediaStream>& streams = mDecoder->OutputStreams();
-  for (uint32_t i = 0; i < streams.Length(); ++i) {
-    OutputMediaStream* stream = &streams[i];
-    if (stream->mStreamInitialized && !stream->mHaveSentFinishAudio &&
-        !stream->mStream->HaveEnoughBuffered(TRACK_AUDIO)) {
+  DecodedStreamData* stream = mDecoder->GetDecodedStream();
+  if (stream && stream->mStreamInitialized && !stream->mHaveSentFinishAudio) {
+    if (!stream->mStream->HaveEnoughBuffered(TRACK_AUDIO)) {
       return false;
     }
+    stream->mStream->DispatchWhenNotEnoughBuffered(TRACK_AUDIO,
+        GetStateMachineThread(), GetWakeDecoderRunnable());
   }
 
-  nsIThread* thread = GetStateMachineThread();
-  nsCOMPtr<nsIRunnable> callback = NS_NewRunnableMethod(this,
-      &nsBuiltinDecoderStateMachine::ScheduleStateMachineWithLockAndWakeDecoder);
-  for (uint32_t i = 0; i < streams.Length(); ++i) {
-    OutputMediaStream* stream = &streams[i];
-    if (stream->mStreamInitialized && !stream->mHaveSentFinishAudio) {
-      stream->mStream->DispatchWhenNotEnoughBuffered(TRACK_AUDIO, thread, callback);
-    }
-  }
   return true;
 }
 
 bool nsBuiltinDecoderStateMachine::HaveEnoughDecodedVideo()
 {
   mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
 
   if (static_cast<uint32_t>(mReader->mVideoQueue.GetSize()) < AMPLE_VIDEO_FRAMES) {
     return false;
   }
 
-  nsTArray<OutputMediaStream>& streams = mDecoder->OutputStreams();
-  if (streams.IsEmpty()) {
-    return true;
-  }
-
-  for (uint32_t i = 0; i < streams.Length(); ++i) {
-    OutputMediaStream* stream = &streams[i];
-    if (stream->mStreamInitialized && !stream->mHaveSentFinishVideo &&
-        !stream->mStream->HaveEnoughBuffered(TRACK_VIDEO)) {
+  DecodedStreamData* stream = mDecoder->GetDecodedStream();
+  if (stream && stream->mStreamInitialized && !stream->mHaveSentFinishVideo) {
+    if (!stream->mStream->HaveEnoughBuffered(TRACK_VIDEO)) {
       return false;
     }
+    stream->mStream->DispatchWhenNotEnoughBuffered(TRACK_VIDEO,
+        GetStateMachineThread(), GetWakeDecoderRunnable());
   }
 
-  nsIThread* thread = GetStateMachineThread();
-  nsCOMPtr<nsIRunnable> callback = NS_NewRunnableMethod(this,
-      &nsBuiltinDecoderStateMachine::ScheduleStateMachineWithLockAndWakeDecoder);
-  for (uint32_t i = 0; i < streams.Length(); ++i) {
-    OutputMediaStream* stream = &streams[i];
-    if (stream->mStreamInitialized && !stream->mHaveSentFinishVideo) {
-      stream->mStream->DispatchWhenNotEnoughBuffered(TRACK_VIDEO, thread, callback);
-    }
-  }
   return true;
 }
 
 void nsBuiltinDecoderStateMachine::DecodeLoop()
 {
   LOG(PR_LOG_DEBUG, ("%p Start DecodeLoop()", mDecoder.get()));
 
   mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
@@ -910,17 +876,17 @@ void nsBuiltinDecoderStateMachine::Decod
       audioPump = true;
     }
     mDidThrottleAudioDecoding = throttleAudioDecoding;
     if (!mDidThrottleAudioDecoding) {
       ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
       audioPlaying = mReader->DecodeAudioData();
     }
 
-    SendOutputStreamData();
+    SendStreamData();
 
     // Notify to ensure that the AudioLoop() is not waiting, in case it was
     // waiting for more audio to be decoded.
     mDecoder->GetReentrantMonitor().NotifyAll();
 
     // The ready state can change when we've decoded data, so update the
     // ready state, so that DOM events can fire.
     UpdateReadyState();
@@ -1520,16 +1486,17 @@ void nsBuiltinDecoderStateMachine::Seek(
 
   // Bound the seek time to be inside the media range.
   NS_ASSERTION(mStartTime != -1, "Should know start time by now");
   NS_ASSERTION(mEndTime != -1, "Should know end time by now");
   mSeekTime = NS_MIN(mSeekTime, mEndTime);
   mSeekTime = NS_MAX(mStartTime, mSeekTime);
   LOG(PR_LOG_DEBUG, ("%p Changed state to SEEKING (to %f)", mDecoder.get(), aTime));
   mState = DECODER_STATE_SEEKING;
+  mDecoder->RecreateDecodedStream(mSeekTime - mStartTime);
   ScheduleStateMachine();
 }
 
 void nsBuiltinDecoderStateMachine::StopDecodeThread()
 {
   NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread.");
   mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
   if (mRequestedNewDecodeThread) {
@@ -1996,22 +1963,21 @@ nsresult nsBuiltinDecoderStateMachine::R
 
   switch (mState) {
     case DECODER_STATE_SHUTDOWN: {
       if (IsPlaying()) {
         StopPlayback();
       }
       StopAudioThread();
       StopDecodeThread();
+      // Now that those threads are stopped, there's no possibility of
+      // mPendingWakeDecoder being needed again. Revoke it.
+      mPendingWakeDecoder = nullptr;
       NS_ASSERTION(mState == DECODER_STATE_SHUTDOWN,
                    "How did we escape from the shutdown state?");
-      // Need to call this before dispatching nsDispatchDisposeEvent below, to
-      // ensure that any notifications dispatched by the stream graph
-      // will run before nsDispatchDisposeEvent below.
-      FinishOutputStreams();
       // We must daisy-chain these events to destroy the decoder. We must
       // destroy the decoder on the main thread, but we can't destroy the
       // decoder while this thread holds the decoder monitor. We can't
       // dispatch an event to the main thread to destroy the decoder from
       // here, as the event may run before the dispatch returns, and we
       // hold the decoder monitor here. We also want to guarantee that the
       // state machine is destroyed on the main thread, and so the
       // event runner running this function (which holds a reference to the
--- a/content/media/nsBuiltinDecoderStateMachine.h
+++ b/content/media/nsBuiltinDecoderStateMachine.h
@@ -101,17 +101,17 @@ hardware (via nsAudioStream and libsydne
 */
 class nsBuiltinDecoderStateMachine : public nsDecoderStateMachine
 {
 public:
   typedef mozilla::ReentrantMonitor ReentrantMonitor;
   typedef mozilla::TimeStamp TimeStamp;
   typedef mozilla::TimeDuration TimeDuration;
   typedef mozilla::VideoFrameContainer VideoFrameContainer;
-  typedef nsBuiltinDecoder::OutputMediaStream OutputMediaStream;
+  typedef nsBuiltinDecoder::DecodedStreamData DecodedStreamData;
   typedef mozilla::SourceMediaStream SourceMediaStream;
   typedef mozilla::AudioSegment AudioSegment;
   typedef mozilla::VideoSegment VideoSegment;
 
   nsBuiltinDecoderStateMachine(nsBuiltinDecoder* aDecoder, nsBuiltinDecoderReader* aReader, bool aRealTime = false);
   ~nsBuiltinDecoderStateMachine();
 
   // nsDecoderStateMachine interface
@@ -255,22 +255,56 @@ public:
   void ReleaseDecoder() { mDecoder = nullptr; }
 
    // Called when a "MozAudioAvailable" event listener is added to the media
    // element. Called on the main thread.
    void NotifyAudioAvailableListener();
 
   // Copy queued audio/video data in the reader to any output MediaStreams that
   // need it.
-  void SendOutputStreamData();
-  void FinishOutputStreams();
+  void SendStreamData();
+  void FinishStreamData();
   bool HaveEnoughDecodedAudio(int64_t aAmpleAudioUSecs);
   bool HaveEnoughDecodedVideo();
 
 protected:
+  class WakeDecoderRunnable : public nsRunnable {
+  public:
+    WakeDecoderRunnable(nsBuiltinDecoderStateMachine* aSM)
+      : mMutex("WakeDecoderRunnable"), mStateMachine(aSM) {}
+    NS_IMETHOD Run()
+    {
+      nsRefPtr<nsBuiltinDecoderStateMachine> stateMachine;
+      {
+        // Don't let Run() (called by media stream graph thread) race with
+        // Revoke() (called by decoder state machine thread)
+        MutexAutoLock lock(mMutex);
+        if (!mStateMachine)
+          return NS_OK;
+        stateMachine = mStateMachine;
+      }
+      stateMachine->ScheduleStateMachineWithLockAndWakeDecoder();
+      return NS_OK;
+    }
+    void Revoke()
+    {
+      MutexAutoLock lock(mMutex);
+      mStateMachine = nullptr;
+    }
+
+    Mutex mMutex;
+    // Protected by mMutex.
+    // We don't use an owning pointer here, because keeping mStateMachine alive
+    // would mean in some cases we'd have to destroy mStateMachine from this
+    // object, which would be problematic since nsBuiltinDecoderStateMachine can
+    // only be destroyed on the main thread whereas this object can be destroyed
+    // on the media stream graph thread.
+    nsBuiltinDecoderStateMachine* mStateMachine;
+  };
+  WakeDecoderRunnable* GetWakeDecoderRunnable();
 
   // Returns true if we've got less than aAudioUsecs microseconds of decoded
   // and playable data. The decoder monitor must be held.
   bool HasLowDecodedData(int64_t aAudioUsecs) const;
 
   // Returns true if we're running low on data which is not yet decoded.
   // The decoder monitor must be held.
   bool HasLowUndecodedData() const;
@@ -425,18 +459,18 @@ protected:
   void DecodeLoop();
 
   // Decode thread run function. Determines which of the Decode*() functions
   // to call.
   void DecodeThreadRun();
 
   // Copy audio from an AudioData packet to aOutput. This may require
   // inserting silence depending on the timing of the audio packet.
-  void SendOutputStreamAudio(AudioData* aAudio, OutputMediaStream* aStream,
-                             AudioSegment* aOutput);
+  void SendStreamAudio(AudioData* aAudio, DecodedStreamData* aStream,
+                       AudioSegment* aOutput);
 
   // State machine thread run function. Defers to RunStateMachine().
   nsresult CallRunStateMachine();
 
   // Performs one "cycle" of the state machine. Polls the state, and may send
   // a video frame to be displayed, and generally manages the decode. Called
   // periodically via timer to ensure the video stays in sync.
   nsresult RunStateMachine();
@@ -525,16 +559,23 @@ protected:
   // first acquire the decoder monitor and check that it is non-null.
   nsRefPtr<nsAudioStream> mAudioStream;
 
   // The reader, don't call its methods with the decoder monitor held.
   // This is created in the play state machine's constructor, and destroyed
   // in the play state machine's destructor.
   nsAutoPtr<nsBuiltinDecoderReader> mReader;
 
+  // Accessed only on the state machine thread.
+  // Not an nsRevocableEventPtr since we must Revoke() it well before
+  // this object is destroyed, anyway.
+  // Protected by decoder monitor except during the SHUTDOWN state after the
+  // decoder thread has been stopped.
+  nsRevocableEventPtr<WakeDecoderRunnable> mPendingWakeDecoder;
+
   // The time of the current frame in microseconds. This is referenced from
   // 0 which is the initial playback position. Set by the state machine
   // thread, and read-only from the main thread to get the current
   // time value. Synchronised via decoder monitor.
   int64_t mCurrentFrameTime;
 
   // The presentation time of the first audio frame that was played in
   // microseconds. We can add this to the audio stream position to determine
--- a/content/media/nsDOMMediaStream.cpp
+++ b/content/media/nsDOMMediaStream.cpp
@@ -46,13 +46,22 @@ already_AddRefed<nsDOMMediaStream>
 nsDOMMediaStream::CreateInputStream()
 {
   nsRefPtr<nsDOMMediaStream> stream = new nsDOMMediaStream();
   MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
   stream->mStream = gm->CreateInputStream(stream);
   return stream.forget();
 }
 
+already_AddRefed<nsDOMMediaStream>
+nsDOMMediaStream::CreateTrackUnionStream()
+{
+  nsRefPtr<nsDOMMediaStream> stream = new nsDOMMediaStream();
+  MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
+  stream->mStream = gm->CreateTrackUnionStream(stream);
+  return stream.forget();
+}
+
 bool
 nsDOMMediaStream::CombineWithPrincipal(nsIPrincipal* aPrincipal)
 {
   return nsContentUtils::CombineResourcePrincipals(&mPrincipal, aPrincipal);
 }
--- a/content/media/nsDOMMediaStream.h
+++ b/content/media/nsDOMMediaStream.h
@@ -50,16 +50,21 @@ public:
    */
   bool CombineWithPrincipal(nsIPrincipal* aPrincipal);
 
   /**
    * Create an nsDOMMediaStream whose underlying stream is a SourceMediaStream.
    */
   static already_AddRefed<nsDOMMediaStream> CreateInputStream();
 
+  /**
+   * Create an nsDOMMediaStream whose underlying stream is a TrackUnionStream.
+   */
+  static already_AddRefed<nsDOMMediaStream> CreateTrackUnionStream();
+
 protected:
   // MediaStream is owned by the graph, but we tell it when to die, and it won't
   // die until we let it.
   MediaStream* mStream;
   // Principal identifying who may access the contents of this stream.
   // If null, this stream can be used by anyone because it has no content yet.
   nsCOMPtr<nsIPrincipal> mPrincipal;
 };
--- a/content/media/nsMediaDecoder.h
+++ b/content/media/nsMediaDecoder.h
@@ -36,16 +36,19 @@ static const uint32_t FRAMEBUFFER_LENGTH
 // with the exception of GetVideoFrameContainer and GetStatistics,
 // which can be called from any thread.
 class nsMediaDecoder : public nsIObserver
 {
 public:
   typedef mozilla::MediaResource MediaResource;
   typedef mozilla::ReentrantMonitor ReentrantMonitor;
   typedef mozilla::SourceMediaStream SourceMediaStream;
+  typedef mozilla::ProcessedMediaStream ProcessedMediaStream;
+  typedef mozilla::MediaInputPort MediaInputPort;
+  typedef mozilla::MainThreadMediaStreamListener MainThreadMediaStreamListener;
   typedef mozilla::TimeStamp TimeStamp;
   typedef mozilla::TimeDuration TimeDuration;
   typedef mozilla::VideoFrameContainer VideoFrameContainer;
 
   nsMediaDecoder();
   virtual ~nsMediaDecoder();
 
   // Create a new decoder of the same type as this one.
@@ -97,17 +100,20 @@ public:
   // Set the audio volume. It should be a value from 0 to 1.0.
   virtual void SetVolume(double aVolume) = 0;
 
   // Sets whether audio is being captured. If it is, we won't play any
   // of our audio.
   virtual void SetAudioCaptured(bool aCaptured) = 0;
 
   // Add an output stream. All decoder output will be sent to the stream.
-  virtual void AddOutputStream(SourceMediaStream* aStream, bool aFinishWhenEnded) = 0;
+  // The stream is initially blocked. The decoder is responsible for unblocking
+  // it while it is playing back.
+  virtual void AddOutputStream(ProcessedMediaStream* aStream,
+                               bool aFinishWhenEnded) = 0;
 
   // Start playback of a video. 'Load' must have previously been
   // called.
   virtual nsresult Play() = 0;
 
   // Start downloading the media. Decode the downloaded data up to the
   // point of the first frame of data.
   // aResource is the media stream to use. Ownership of aResource passes to
--- a/content/media/test/test_streams_element_capture_reset.html
+++ b/content/media/test/test_streams_element_capture_reset.html
@@ -4,69 +4,92 @@
   <title>Test that reloading and seeking in a media element that's being captured doesn't crash</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
   <script type="text/javascript" src="manifest.js"></script>
 </head>
 <body>
 <video id="v"></video>
 <video id="vout"></video>
+<video id="vout_untilended"></video>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 SimpleTest.waitForExplicitFinish();
 
 var v = document.getElementById('v');
 var vout = document.getElementById('vout');
-var stream = v.mozCaptureStream();
-vout.src = stream;
+var vout_untilended = document.getElementById('vout_untilended');
+vout.src = v.mozCaptureStream();
+vout_untilended.src = v.mozCaptureStreamUntilEnded();
 
 function dumpEvent(event) {
   dump("GOT EVENT " + event.type + " currentTime=" + event.target.currentTime +
        " paused=" + event.target.paused + " ended=" + event.target.ended +
        " readyState=" + event.target.readyState + "\n");
 }
 var events = ["timeupdate", "seeking", "seeked", "ended", "playing", "pause"];
 for (var i = 0; i < events.length; ++i) {
   v.addEventListener(events[i], dumpEvent, false);
 }
+function isWithinEps(a, b, msg) {
+  ok(Math.abs(a - b) < 0.01,
+     "Got " + a + ", expected " + b + "; " + msg);
+}
 
 function startTest(test) {
   var seekTime = test.duration/2;
 
-  function ended() {
-    ok(true, "Final ended after changing src");
+  function endedAfterReplay() {
+    isWithinEps(v.currentTime, test.duration, "checking v.currentTime at third 'ended' event");
+    isWithinEps(vout.currentTime, (v.currentTime - seekTime) + test.duration*2,
+	            "checking vout.currentTime after seeking, playing through and reloading");
     SimpleTest.finish();
   };
-  function timeupdateAfterSeek() {
-    if (v.currentTime < seekTime + 0.001)
-      return;
-    ok(true, "timeupdate after seek");
-    v.removeEventListener("timeupdate", timeupdateAfterSeek, false);
+  function endedAfterSeek() {
+    isWithinEps(v.currentTime, test.duration, "checking v.currentTime at second 'ended' event");
+    isWithinEps(vout.currentTime, (v.currentTime - seekTime) + test.duration,
+                "checking vout.currentTime after seeking and playing through again");
+    v.removeEventListener("ended", endedAfterSeek, false);
+    v.addEventListener("ended", endedAfterReplay, false);
     v.src = test.name + "?1";
     v.play();
-    v.addEventListener("ended", ended, false);
   };
   function seeked() {
-    ok(true, "Finished seeking");
+    isWithinEps(v.currentTime, seekTime, "Finished seeking");
+    isWithinEps(vout.currentTime, test.duration,
+                "checking vout.currentTime has not changed after seeking");
     v.removeEventListener("seeked", seeked, false);
-    v.addEventListener("timeupdate", timeupdateAfterSeek, false);
+    function dontPlayAgain() {
+      ok(false, "vout_untilended should not play again");
+    }
+    vout_untilended.addEventListener("playing", dontPlayAgain, false);
+    vout_untilended.addEventListener("ended", dontPlayAgain, false);
+    v.addEventListener("ended", endedAfterSeek, false);
+    v.play();
   };
-  function timeupdate() {
-    if (v.currentTime == 0)
-      return;
-    ok(true, "Initial timeupdate");
-    v.removeEventListener("timeupdate", timeupdate, false);
+  function ended() {
+    isWithinEps(vout.currentTime, test.duration, "checking vout.currentTime at first 'ended' event");
+    isWithinEps(v.currentTime, test.duration, "checking v.currentTime at first 'ended' event");
+    is(vout.ended, false, "checking vout has not ended");
+    is(vout_untilended.ended, true, "checking vout_untilended has actually ended");
+    vout_untilended.removeEventListener("ended", ended, false);
+    v.pause();
     v.currentTime = seekTime;
     v.addEventListener("seeked", seeked, false);
   };
-  v.addEventListener("timeupdate", timeupdate, false);
+  vout_untilended.addEventListener("ended", ended, false);
 
   v.src = test.name;
   v.play();
+  function checkNoEnded() {
+    ok(false, "ended event received unexpectedly");
+  };
+  vout.addEventListener("ended", checkNoEnded, false);
   vout.play();
+  vout_untilended.play();
 }
 
 var testVideo = getPlayableVideo(gSmallTests);
 if (testVideo) {
   startTest(testVideo);
 } else {
   todo(false, "No playable video");
 }
--- a/content/svg/content/src/DOMSVGAnimatedLengthList.cpp
+++ b/content/svg/content/src/DOMSVGAnimatedLengthList.cpp
@@ -53,24 +53,23 @@ DOMSVGAnimatedLengthList::GetAnimVal(nsI
 }
 
 /* static */ already_AddRefed<DOMSVGAnimatedLengthList>
 DOMSVGAnimatedLengthList::GetDOMWrapper(SVGAnimatedLengthList *aList,
                                         nsSVGElement *aElement,
                                         uint8_t aAttrEnum,
                                         uint8_t aAxis)
 {
-  DOMSVGAnimatedLengthList *wrapper =
+  nsRefPtr<DOMSVGAnimatedLengthList> wrapper =
     sSVGAnimatedLengthListTearoffTable.GetTearoff(aList);
   if (!wrapper) {
     wrapper = new DOMSVGAnimatedLengthList(aElement, aAttrEnum, aAxis);
     sSVGAnimatedLengthListTearoffTable.AddTearoff(aList, wrapper);
   }
-  NS_ADDREF(wrapper);
-  return wrapper;
+  return wrapper.forget();
 }
 
 /* static */ DOMSVGAnimatedLengthList*
 DOMSVGAnimatedLengthList::GetDOMWrapperIfExists(SVGAnimatedLengthList *aList)
 {
   return sSVGAnimatedLengthListTearoffTable.GetTearoff(aList);
 }
 
--- a/content/svg/content/src/DOMSVGAnimatedNumberList.cpp
+++ b/content/svg/content/src/DOMSVGAnimatedNumberList.cpp
@@ -52,24 +52,23 @@ DOMSVGAnimatedNumberList::GetAnimVal(nsI
   return NS_OK;
 }
 
 /* static */ already_AddRefed<DOMSVGAnimatedNumberList>
 DOMSVGAnimatedNumberList::GetDOMWrapper(SVGAnimatedNumberList *aList,
                                         nsSVGElement *aElement,
                                         uint8_t aAttrEnum)
 {
-  DOMSVGAnimatedNumberList *wrapper =
+  nsRefPtr<DOMSVGAnimatedNumberList> wrapper =
     sSVGAnimatedNumberListTearoffTable.GetTearoff(aList);
   if (!wrapper) {
     wrapper = new DOMSVGAnimatedNumberList(aElement, aAttrEnum);
     sSVGAnimatedNumberListTearoffTable.AddTearoff(aList, wrapper);
   }
-  NS_ADDREF(wrapper);
-  return wrapper;
+  return wrapper.forget();
 }
 
 /* static */ DOMSVGAnimatedNumberList*
 DOMSVGAnimatedNumberList::GetDOMWrapperIfExists(SVGAnimatedNumberList *aList)
 {
   return sSVGAnimatedNumberListTearoffTable.GetTearoff(aList);
 }
 
--- a/content/svg/content/src/DOMSVGAnimatedTransformList.cpp
+++ b/content/svg/content/src/DOMSVGAnimatedTransformList.cpp
@@ -53,24 +53,23 @@ DOMSVGAnimatedTransformList::GetAnimVal(
   NS_ADDREF(*aAnimVal = mAnimVal);
   return NS_OK;
 }
 
 /* static */ already_AddRefed<DOMSVGAnimatedTransformList>
 DOMSVGAnimatedTransformList::GetDOMWrapper(SVGAnimatedTransformList *aList,
                                            nsSVGElement *aElement)
 {
-  DOMSVGAnimatedTransformList *wrapper =
+  nsRefPtr<DOMSVGAnimatedTransformList> wrapper =
     sSVGAnimatedTransformListTearoffTable.GetTearoff(aList);
   if (!wrapper) {
     wrapper = new DOMSVGAnimatedTransformList(aElement);
     sSVGAnimatedTransformListTearoffTable.AddTearoff(aList, wrapper);
   }
-  NS_ADDREF(wrapper);
-  return wrapper;
+  return wrapper.forget();
 }
 
 /* static */ DOMSVGAnimatedTransformList*
 DOMSVGAnimatedTransformList::GetDOMWrapperIfExists(
   SVGAnimatedTransformList *aList)
 {
   return sSVGAnimatedTransformListTearoffTable.GetTearoff(aList);
 }
--- a/content/svg/content/src/DOMSVGLengthList.cpp
+++ b/content/svg/content/src/DOMSVGLengthList.cpp
@@ -71,17 +71,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGLengthList)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGLengthList)
 NS_INTERFACE_MAP_END
 
 JSObject*
 DOMSVGLengthList::WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap)
 {
-  return mozilla::dom::binding::SVGLengthList::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::SVGLengthList::create(cx, scope, this,
                                                       triedToWrap);
 }
 
 nsIDOMSVGLength*
 DOMSVGLengthList::GetItemAt(uint32_t aIndex)
 {
   if (IsAnimValList()) {
     Element()->FlushAnimations();
--- a/content/svg/content/src/DOMSVGNumberList.cpp
+++ b/content/svg/content/src/DOMSVGNumberList.cpp
@@ -72,17 +72,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGNumberList)
 NS_INTERFACE_MAP_END
 
 
 JSObject*
 DOMSVGNumberList::WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap)
 {
-  return mozilla::dom::binding::SVGNumberList::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::SVGNumberList::create(cx, scope, this,
                                                       triedToWrap);
 }
 
 nsIDOMSVGNumber*
 DOMSVGNumberList::GetItemAt(uint32_t aIndex)
 {
   if (IsAnimValList()) {
     Element()->FlushAnimations();
--- a/content/svg/content/src/DOMSVGPathSegList.cpp
+++ b/content/svg/content/src/DOMSVGPathSegList.cpp
@@ -50,24 +50,23 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
 NS_INTERFACE_MAP_END
 
 
 /* static */ already_AddRefed<DOMSVGPathSegList>
 DOMSVGPathSegList::GetDOMWrapper(void *aList,
                                  nsSVGElement *aElement,
                                  bool aIsAnimValList)
 {
-  DOMSVGPathSegList *wrapper =
+  nsRefPtr<DOMSVGPathSegList> wrapper =
     sSVGPathSegListTearoffTable.GetTearoff(aList);
   if (!wrapper) {
     wrapper = new DOMSVGPathSegList(aElement, aIsAnimValList);
     sSVGPathSegListTearoffTable.AddTearoff(aList, wrapper);
   }
-  NS_ADDREF(wrapper);
-  return wrapper;
+  return wrapper.forget();
 }
 
 /* static */ DOMSVGPathSegList*
 DOMSVGPathSegList::GetDOMWrapperIfExists(void *aList)
 {
   return sSVGPathSegListTearoffTable.GetTearoff(aList);
 }
 
@@ -79,17 +78,17 @@ DOMSVGPathSegList::~DOMSVGPathSegList()
     InternalAList().GetAnimValKey() :
     InternalAList().GetBaseValKey();
   sSVGPathSegListTearoffTable.RemoveTearoff(key);
 }
 
 JSObject*
 DOMSVGPathSegList::WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap)
 {
-  return mozilla::dom::binding::SVGPathSegList::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::SVGPathSegList::create(cx, scope, this,
                                                        triedToWrap);
 }
 
 nsIDOMSVGPathSeg*
 DOMSVGPathSegList::GetItemAt(uint32_t aIndex)
 {
   if (IsAnimValList()) {
     Element()->FlushAnimations();
--- a/content/svg/content/src/DOMSVGPointList.cpp
+++ b/content/svg/content/src/DOMSVGPointList.cpp
@@ -69,24 +69,23 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
 NS_INTERFACE_MAP_END
 
 
 /* static */ already_AddRefed<DOMSVGPointList>
 DOMSVGPointList::GetDOMWrapper(void *aList,
                                nsSVGElement *aElement,
                                bool aIsAnimValList)
 {
-  DOMSVGPointList *wrapper =
+  nsRefPtr<DOMSVGPointList> wrapper =
     sSVGPointListTearoffTable.GetTearoff(aList);
   if (!wrapper) {
     wrapper = new DOMSVGPointList(aElement, aIsAnimValList);
     sSVGPointListTearoffTable.AddTearoff(aList, wrapper);
   }
-  NS_ADDREF(wrapper);
-  return wrapper;
+  return wrapper.forget();
 }
 
 /* static */ DOMSVGPointList*
 DOMSVGPointList::GetDOMWrapperIfExists(void *aList)
 {
   return sSVGPointListTearoffTable.GetTearoff(aList);
 }
 
@@ -98,17 +97,17 @@ DOMSVGPointList::~DOMSVGPointList()
     InternalAList().GetAnimValKey() :
     InternalAList().GetBaseValKey();
   sSVGPointListTearoffTable.RemoveTearoff(key);
 }
 
 JSObject*
 DOMSVGPointList::WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap)
 {
-  return mozilla::dom::binding::SVGPointList::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::SVGPointList::create(cx, scope, this,
                                                      triedToWrap);
 }
 
 nsIDOMSVGPoint*
 DOMSVGPointList::GetItemAt(uint32_t aIndex)
 {
   if (IsAnimValList()) {
     Element()->FlushAnimations();
--- a/content/svg/content/src/DOMSVGStringList.cpp
+++ b/content/svg/content/src/DOMSVGStringList.cpp
@@ -34,26 +34,25 @@ NS_INTERFACE_MAP_END
 
 
 /* static */ already_AddRefed<DOMSVGStringList>
 DOMSVGStringList::GetDOMWrapper(SVGStringList *aList,
                                 nsSVGElement *aElement,
                                 bool aIsConditionalProcessingAttribute,
                                 uint8_t aAttrEnum)
 {
-  DOMSVGStringList *wrapper =
+  nsRefPtr<DOMSVGStringList> wrapper =
     sSVGStringListTearoffTable.GetTearoff(aList);
   if (!wrapper) {
     wrapper = new DOMSVGStringList(aElement, 
                                    aIsConditionalProcessingAttribute,
                                    aAttrEnum);
     sSVGStringListTearoffTable.AddTearoff(aList, wrapper);
   }
-  NS_ADDREF(wrapper);
-  return wrapper;
+  return wrapper.forget();
 }
 
 DOMSVGStringList::~DOMSVGStringList()
 {
   // Script no longer has any references to us.
   sSVGStringListTearoffTable.RemoveTearoff(&InternalList());
 }
 
--- a/content/svg/content/src/DOMSVGTransformList.cpp
+++ b/content/svg/content/src/DOMSVGTransformList.cpp
@@ -72,17 +72,17 @@ NS_INTERFACE_MAP_END
 
 //----------------------------------------------------------------------
 // DOMSVGTransformList methods:
 
 JSObject*
 DOMSVGTransformList::WrapObject(JSContext *cx, JSObject *scope,
                                 bool *triedToWrap)
 {
-  return mozilla::dom::binding::SVGTransformList::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::SVGTransformList::create(cx, scope, this,
                                                          triedToWrap);
 }
 
 nsIDOMSVGTransform*
 DOMSVGTransformList::GetItemAt(uint32_t aIndex)
 {
   if (IsAnimValList()) {
     Element()->FlushAnimations();
--- a/content/svg/content/src/nsSVGLength2.cpp
+++ b/content/svg/content/src/nsSVGLength2.cpp
@@ -63,21 +63,21 @@ static nsIAtom** const unitMap[] =
   &nsGkAtoms::px,
   &nsGkAtoms::cm,
   &nsGkAtoms::mm,
   &nsGkAtoms::in,
   &nsGkAtoms::pt,
   &nsGkAtoms::pc
 };
 
-static nsSVGAttrTearoffTable<nsSVGLength2, nsIDOMSVGAnimatedLength>
+static nsSVGAttrTearoffTable<nsSVGLength2, nsSVGLength2::DOMAnimatedLength>
   sSVGAnimatedLengthTearoffTable;
-static nsSVGAttrTearoffTable<nsSVGLength2, nsIDOMSVGLength>
+static nsSVGAttrTearoffTable<nsSVGLength2, nsSVGLength2::DOMBaseVal>
   sBaseSVGLengthTearoffTable;
-static nsSVGAttrTearoffTable<nsSVGLength2, nsIDOMSVGLength>
+static nsSVGAttrTearoffTable<nsSVGLength2, nsSVGLength2::DOMAnimVal>
   sAnimSVGLengthTearoffTable;
 
 /* Helper functions */
 
 static bool
 IsValidUnitType(uint16_t unit)
 {
   if (unit > nsIDOMSVGLength::SVG_LENGTHTYPE_UNKNOWN &&
@@ -354,45 +354,43 @@ nsSVGLength2::NewValueSpecifiedUnits(uin
   }
   aSVGElement->DidChangeLength(mAttrEnum, emptyOrOldValue);
   return NS_OK;
 }
 
 nsresult
 nsSVGLength2::ToDOMBaseVal(nsIDOMSVGLength **aResult, nsSVGElement *aSVGElement)
 {
-  *aResult = sBaseSVGLengthTearoffTable.GetTearoff(this);
-  if (!*aResult) {
-    *aResult = new DOMBaseVal(this, aSVGElement);
-    if (!*aResult)
-      return NS_ERROR_OUT_OF_MEMORY;
-    sBaseSVGLengthTearoffTable.AddTearoff(this, *aResult);
+  nsRefPtr<DOMBaseVal> domBaseVal =
+    sBaseSVGLengthTearoffTable.GetTearoff(this);
+  if (!domBaseVal) {
+    domBaseVal = new DOMBaseVal(this, aSVGElement);
+    sBaseSVGLengthTearoffTable.AddTearoff(this, domBaseVal);
   }
 
-  NS_ADDREF(*aResult);
+  domBaseVal.forget(aResult);
   return NS_OK;
 }
 
 nsSVGLength2::DOMBaseVal::~DOMBaseVal()
 {
   sBaseSVGLengthTearoffTable.RemoveTearoff(mVal);
 }
 
 nsresult
 nsSVGLength2::ToDOMAnimVal(nsIDOMSVGLength **aResult, nsSVGElement *aSVGElement)
 {
-  *aResult = sAnimSVGLengthTearoffTable.GetTearoff(this);
-  if (!*aResult) {
-    *aResult = new DOMAnimVal(this, aSVGElement);
-    if (!*aResult)
-      return NS_ERROR_OUT_OF_MEMORY;
-    sAnimSVGLengthTearoffTable.AddTearoff(this, *aResult);
+  nsRefPtr<DOMAnimVal> domAnimVal =
+    sAnimSVGLengthTearoffTable.GetTearoff(this);
+  if (!domAnimVal) {
+    domAnimVal = new DOMAnimVal(this, aSVGElement);
+    sAnimSVGLengthTearoffTable.AddTearoff(this, domAnimVal);
   }
 
-  NS_ADDREF(*aResult);
+  domAnimVal.forget(aResult);
   return NS_OK;
 }
 
 nsSVGLength2::DOMAnimVal::~DOMAnimVal()
 {
   sAnimSVGLengthTearoffTable.RemoveTearoff(mVal);
 }
 
@@ -476,25 +474,24 @@ nsSVGLength2::SetAnimValue(float aValue,
                                                            mSpecifiedUnitType),
                                aSVGElement);
 }
 
 nsresult
 nsSVGLength2::ToDOMAnimatedLength(nsIDOMSVGAnimatedLength **aResult,
                                   nsSVGElement *aSVGElement)
 {
-  *aResult = sSVGAnimatedLengthTearoffTable.GetTearoff(this);
-  if (!*aResult) {
-    *aResult = new DOMAnimatedLength(this, aSVGElement);
-    if (!*aResult)
-      return NS_ERROR_OUT_OF_MEMORY;
-    sSVGAnimatedLengthTearoffTable.AddTearoff(this, *aResult);
+  nsRefPtr<DOMAnimatedLength> domAnimatedLength =
+    sSVGAnimatedLengthTearoffTable.GetTearoff(this);
+  if (!domAnimatedLength) {
+    domAnimatedLength = new DOMAnimatedLength(this, aSVGElement);
+    sSVGAnimatedLengthTearoffTable.AddTearoff(this, domAnimatedLength);
   }
 
-  NS_ADDREF(*aResult);
+  domAnimatedLength.forget(aResult);
   return NS_OK;
 }
 
 nsSVGLength2::DOMAnimatedLength::~DOMAnimatedLength()
 {
   sSVGAnimatedLengthTearoffTable.RemoveTearoff(mVal);
 }
 
--- a/content/svg/content/src/nsSVGLength2.h
+++ b/content/svg/content/src/nsSVGLength2.h
@@ -122,16 +122,17 @@ private:
   void SetAnimValue(float aValue, nsSVGElement *aSVGElement);
   void SetAnimValueInSpecifiedUnits(float aValue, nsSVGElement *aSVGElement);
   nsresult NewValueSpecifiedUnits(uint16_t aUnitType, float aValue,
                                   nsSVGElement *aSVGElement);
   nsresult ConvertToSpecifiedUnits(uint16_t aUnitType, nsSVGElement *aSVGElement);
   nsresult ToDOMBaseVal(nsIDOMSVGLength **aResult, nsSVGElement* aSVGElement);
   nsresult ToDOMAnimVal(nsIDOMSVGLength **aResult, nsSVGElement* aSVGElement);
 
+public:
   struct DOMBaseVal : public nsIDOMSVGLength
   {
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_CYCLE_COLLECTION_CLASS(DOMBaseVal)
 
     DOMBaseVal(nsSVGLength2* aVal, nsSVGElement *aSVGElement)
       : mVal(aVal), mSVGElement(aSVGElement) {}
     virtual ~DOMBaseVal();
@@ -230,17 +231,16 @@ private:
     NS_IMETHOD NewValueSpecifiedUnits(uint16_t unitType,
                                       float valueInSpecifiedUnits)
       { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
 
     NS_IMETHOD ConvertToSpecifiedUnits(uint16_t unitType)
       { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
   };
 
-public:
   struct DOMAnimatedLength : public nsIDOMSVGAnimatedLength
   {
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_CYCLE_COLLECTION_CLASS(DOMAnimatedLength)
 
     DOMAnimatedLength(nsSVGLength2* aVal, nsSVGElement *aSVGElement)
       : mVal(aVal), mSVGElement(aSVGElement) {}
     virtual ~DOMAnimatedLength();
--- a/content/xbl/src/nsBindingManager.cpp
+++ b/content/xbl/src/nsBindingManager.cpp
@@ -75,17 +75,17 @@ public:
   int32_t GetInsertionPointCount() { return mElements->Length(); }
 
   nsXBLInsertionPoint* GetInsertionPointAt(int32_t i) { return static_cast<nsXBLInsertionPoint*>(mElements->ElementAt(i)); }
   void RemoveInsertionPointAt(int32_t i) { mElements->RemoveElementAt(i); }
 
   virtual JSObject* WrapObject(JSContext *cx, JSObject *scope,
                                bool *triedToWrap)
   {
-    return mozilla::dom::binding::NodeList::create(cx, scope, this,
+    return mozilla::dom::oldproxybindings::NodeList::create(cx, scope, this,
                                                    triedToWrap);
   }
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ANONYMOUS_CONTENT_LIST_IID)
 private:
   nsCOMPtr<nsIContent> mContent;
   nsInsertionPointList* mElements;
 };
--- a/docshell/test/navigation/NavigationUtils.js
+++ b/docshell/test/navigation/NavigationUtils.js
@@ -53,17 +53,17 @@ function navigateByHyperlink(name) {
 
 ///////////////////////////////////////////////////////////////////////////
 // Functions that call into Mochitest framework
 ///////////////////////////////////////////////////////////////////////////
 
 function isNavigated(wnd, message) {
   var result = null;
   try {
-    result = wnd.document.body.innerHTML;
+    result = SpecialPowers.wrap(wnd).document.body.innerHTML;
   } catch(ex) {
     result = ex;
   }
   is(result, body, message);
 }
 
 function isBlank(wnd, message) {
   var result = null;
@@ -104,26 +104,26 @@ function xpcEnumerateContentWindows(call
                         .classes["@mozilla.org/embedcomp/window-watcher;1"]
                         .getService(Ci.nsIWindowWatcher);
   var enumerator = ww.getWindowEnumerator();
 
   var contentWindows = [];
 
   while (enumerator.hasMoreElements()) {
     var win = enumerator.getNext();
-    if (typeof ChromeWindow != "undefined" && SpecialPowers.call_Instanceof(win, ChromeWindow)) {
+    if (/ChromeWindow/.exec(win)) {
       var docshellTreeNode = win.QueryInterface(Ci.nsIInterfaceRequestor)
                                 .getInterface(Ci.nsIWebNavigation)
                                 .QueryInterface(Ci.nsIDocShellTreeNode);
       var childCount = docshellTreeNode.childCount;
       for (var i = 0; i < childCount; ++i) {
         var childTreeNode = docshellTreeNode.getChildAt(i);
 
         // we're only interested in content docshells
-        if (childTreeNode.itemType != Ci.nsIDocShellTreeItem.typeContent)
+        if (SpecialPowers.unwrap(childTreeNode.itemType) != Ci.nsIDocShellTreeItem.typeContent)
           continue;
 
         var webNav = childTreeNode.QueryInterface(Ci.nsIWebNavigation);
         contentWindows.push(webNav.document.defaultView);
       }
     } else {
       contentWindows.push(win);
     }
--- a/docshell/test/test_bug511449.html
+++ b/docshell/test/test_bug511449.html
@@ -33,19 +33,17 @@ function runTest() {
   SimpleTest.waitForFocus(runNextTest, win);
 }
 
 function runNextTest() {
   var didClose = false;
   win.onunload = function() {
     didClose = true;
   }
-  netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
-  var utils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
-                  getInterface(Components.interfaces.nsIDOMWindowUtils);
+  var utils = SpecialPowers.getDOMWindowUtils(win);
   utils.sendNativeKeyEvent(0, MAC_VK_ANSI_W, 0x4000 /* cmd */, "w", "w");
 
   setTimeout(function () {
     ok(didClose, "Cmd+W should have closed the tab");
     if (!didClose) {
       win.close();
     }
     SimpleTest.finish();
--- a/dom/activities/src/ActivityWrapper.js
+++ b/dom/activities/src/ActivityWrapper.js
@@ -1,26 +1,26 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
- 
+
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
- 
+
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 function debug(aMsg) {
   //dump("-- ActivityWrapper.js " + Date.now() + " : " + aMsg + "\n");
 }
 
 /**
-  * nsISystemMessagesWrapper implementation. Will return a 
+  * nsISystemMessagesWrapper implementation. Will return a
   * nsIDOMMozActivityRequestHandler
   */
 function ActivityWrapper() {
   debug("ActivityWrapper");
 }
 
 ActivityWrapper.prototype = {
   wrapMessage: function wrapMessage(aMessage) {
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -34,16 +34,18 @@
 #include "mozilla/Hal.h"
 #include "nsIWebNavigation.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/StaticPtr.h"
 #include "Connection.h"
 #include "MobileConnection.h"
 #include "nsIIdleObserver.h"
 #include "nsIPermissionManager.h"
+#include "nsNetUtil.h"
+#include "nsIHttpChannel.h"
 
 #ifdef MOZ_MEDIA_NAVIGATOR
 #include "MediaManager.h"
 #endif
 #ifdef MOZ_B2G_RIL
 #include "TelephonyFactory.h"
 #endif
 #ifdef MOZ_B2G_BT
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -538,16 +538,17 @@ using mozilla::dom::indexedDB::IDBWrappe
 #include "LockedFile.h"
 #include "GeneratedEvents.h"
 #include "mozilla/Likely.h"
 #include "nsDebug.h"
 
 #undef None // something included above defines this preprocessor symbol, maybe Xlib headers
 #include "WebGLContext.h"
 #include "nsICanvasRenderingContextInternal.h"
+#include "mozilla/dom/BindingUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
 
 static const char kDOMStringBundleURL[] =
   "chrome://global/locale/dom/dom.properties";
@@ -4570,22 +4571,23 @@ nsDOMClassInfo::Init()
   RegisterExternalClasses();
 
   sDisableDocumentAllSupport =
     Preferences::GetBool("browser.dom.document.all.disabled");
 
   sDisableGlobalScopePollutionSupport =
     Preferences::GetBool("browser.dom.global_scope_pollution.disabled");
 
-  // Proxy bindings
-  mozilla::dom::binding::Register(nameSpaceManager);
-
   // Non-proxy bindings
   mozilla::dom::Register(nameSpaceManager);
 
+  // This needs to happen after the call to mozilla::dom::Register, because we
+  // overwrite some values.
+  mozilla::dom::oldproxybindings::Register(nameSpaceManager);
+
   if (!AzureCanvasEnabled()) {
     nameSpaceManager->RegisterDefineDOMInterface(NS_LITERAL_STRING("CanvasRenderingContext2D"), NULL);
   }
 
   sIsInitialized = true;
 
   return NS_OK;
 }
@@ -6741,25 +6743,25 @@ nsWindowSH::GlobalResolve(nsGlobalWindow
     }
   }
 
   if (name_struct->mType == nsGlobalNameStruct::eTypeNewDOMBinding ||
       name_struct->mType == nsGlobalNameStruct::eTypeInterface ||
       name_struct->mType == nsGlobalNameStruct::eTypeClassProto ||
       name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
     // Lookup new DOM bindings.
-    mozilla::dom::binding::DefineInterface define =
+    mozilla::dom::DefineInterface define =
       name_struct->mDefineDOMInterface;
     if (define) {
       if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor &&
           !ConstructorEnabled(name_struct, aWin)) {
         return NS_OK;
       }
 
-      if (mozilla::dom::binding::DefineConstructor(cx, obj, define, &rv)) {
+      if (mozilla::dom::DefineConstructor(cx, obj, define, &rv)) {
         *did_resolve = NS_SUCCEEDED(rv);
 
         return rv;
       }
     }
   }
 
   if (name_struct->mType == nsGlobalNameStruct::eTypeInterface) {
@@ -8786,19 +8788,19 @@ nsHTMLDocumentSH::GetDocumentAllNodeList
   // in a reserved slot (0) on the document.all JSObject.
   nsresult rv = NS_OK;
 
   jsval collection = JS_GetReservedSlot(obj, 0);
 
   if (!JSVAL_IS_PRIMITIVE(collection)) {
     // We already have a node list in our reserved slot, use it.
     JSObject *obj = JSVAL_TO_OBJECT(collection);
-    if (mozilla::dom::binding::HTMLCollection::objIsWrapper(obj)) {
+    if (mozilla::dom::oldproxybindings::HTMLCollection::objIsWrapper(obj)) {
       nsIHTMLCollection *native =
-        mozilla::dom::binding::HTMLCollection::getNative(obj);
+        mozilla::dom::oldproxybindings::HTMLCollection::getNative(obj);
       NS_ADDREF(*nodeList = static_cast<nsContentList*>(native));
     }
     else {
       nsISupports *native = sXPConnect->GetNativeOfWrapper(cx, obj);
       if (native) {
         NS_ADDREF(*nodeList = nsContentList::FromSupports(native));
       }
       else {
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -6125,17 +6125,17 @@ PostMessageReadStructuredClone(JSContext
 
   const JSStructuredCloneCallbacks* runtimeCallbacks =
     js::GetContextStructuredCloneCallbacks(cx);
 
   if (runtimeCallbacks) {
     return runtimeCallbacks->read(cx, reader, tag, data, nullptr);
   }
 
-  return JS_FALSE;
+  return nullptr;
 }
 
 static JSBool
 PostMessageWriteStructuredClone(JSContext* cx,
                                 JSStructuredCloneWriter* writer,
                                 JSObject* obj,
                                 void *closure)
 {
--- a/dom/base/nsScriptNameSpaceManager.cpp
+++ b/dom/base/nsScriptNameSpaceManager.cpp
@@ -776,17 +776,17 @@ nsScriptNameSpaceManager::Observe(nsISup
   // and NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID but we are safe without it.
   // See bug 600460.
 
   return NS_OK;
 }
 
 void
 nsScriptNameSpaceManager::RegisterDefineDOMInterface(const nsAFlatString& aName,
-    mozilla::dom::binding::DefineInterface aDefineDOMInterface)
+    mozilla::dom::DefineInterface aDefineDOMInterface)
 {
   nsGlobalNameStruct *s = AddToHash(&mGlobalNames, &aName);
   if (s) {
     if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
       s->mType = nsGlobalNameStruct::eTypeNewDOMBinding;
     }
     s->mDefineDOMInterface = aDefineDOMInterface;
   }
--- a/dom/base/nsScriptNameSpaceManager.h
+++ b/dom/base/nsScriptNameSpaceManager.h
@@ -62,17 +62,17 @@ struct nsGlobalNameStruct
     int32_t mDOMClassInfoID; // eTypeClassConstructor
     nsIID mIID; // eTypeInterface, eTypeClassProto
     nsExternalDOMClassInfoData* mData; // eTypeExternalClassInfo
     ConstructorAlias* mAlias; // eTypeExternalConstructorAlias
     nsCID mCID; // All other types except eTypeNewDOMBinding
   };
 
   // For new style DOM bindings.
-  mozilla::dom::binding::DefineInterface mDefineDOMInterface;
+  mozilla::dom::DefineInterface mDefineDOMInterface;
 
 private:
 
   // copy constructor
 };
 
 
 class nsIScriptContext;
@@ -134,17 +134,17 @@ public:
                              const nsIID **aInterfaces,
                              uint32_t aScriptableFlags,
                              bool aHasClassInterface,
                              const nsCID *aConstructorCID);
 
   nsGlobalNameStruct* GetConstructorProto(const nsGlobalNameStruct* aStruct);
 
   void RegisterDefineDOMInterface(const nsAFlatString& aName,
-    mozilla::dom::binding::DefineInterface aDefineDOMInterface);
+    mozilla::dom::DefineInterface aDefineDOMInterface);
 
 private:
   // Adds a new entry to the hash and returns the nsGlobalNameStruct
   // that aKey will be mapped to. If mType in the returned
   // nsGlobalNameStruct is != eTypeNotInitialized, an entry for aKey
   // already existed.
   nsGlobalNameStruct *AddToHash(PLDHashTable *aTable, const nsAString *aKey,
                                 const PRUnichar **aClassName = nullptr);
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <stdarg.h>
 
 #include "BindingUtils.h"
 
+#include "WrapperFactory.h"
 #include "xpcprivate.h"
 #include "XPCQuickStubs.h"
 
 namespace mozilla {
 namespace dom {
 
 JSErrorFormatString ErrorFormatString[] = {
 #define MSG_DEF(_name, _argc, _str) \
@@ -237,17 +238,17 @@ CreateInterfacePrototypeObject(JSContext
 
   return ourProto;
 }
 
 JSObject*
 CreateInterfaceObjects(JSContext* cx, JSObject* global, JSObject *receiver,
                        JSObject* protoProto, JSClass* protoClass,
                        JSClass* constructorClass, JSNative constructor,
-                       unsigned ctorNargs, JSClass* instanceClass,
+                       unsigned ctorNargs, const DOMClass* domClass,
                        Prefable<JSFunctionSpec>* methods,
                        Prefable<JSPropertySpec>* properties,
                        Prefable<ConstantSpec>* constants,
                        Prefable<JSFunctionSpec>* staticMethods, const char* name)
 {
   MOZ_ASSERT(protoClass || constructorClass || constructor,
              "Need at least one class or a constructor!");
   MOZ_ASSERT(!(methods || properties) || protoClass,
@@ -262,17 +263,17 @@ CreateInterfaceObjects(JSContext* cx, JS
   if (protoClass) {
     proto = CreateInterfacePrototypeObject(cx, global, protoProto, protoClass,
                                            methods, properties, constants);
     if (!proto) {
       return NULL;
     }
 
     js::SetReservedSlot(proto, DOM_PROTO_INSTANCE_CLASS_SLOT,
-                        JS::PrivateValue(instanceClass));
+                        JS::PrivateValue(const_cast<DOMClass*>(domClass)));
   }
   else {
     proto = NULL;
   }
 
   JSObject* interface;
   if (constructorClass || constructor) {
     interface = CreateInterfaceObject(cx, global, receiver, constructorClass,
@@ -328,20 +329,18 @@ DoHandleNewBindingWrappingFailure(JSCont
 }
 
 // Can only be called with the immediate prototype of the instance object. Can
 // only be called on the prototype of an object known to be a DOM instance.
 JSBool
 InstanceClassHasProtoAtDepth(JSHandleObject protoObject, uint32_t protoID,
                              uint32_t depth)
 {
-  JSClass* instanceClass = static_cast<JSClass*>(
+  const DOMClass* domClass = static_cast<DOMClass*>(
     js::GetReservedSlot(protoObject, DOM_PROTO_INSTANCE_CLASS_SLOT).toPrivate());
-  MOZ_ASSERT(IsDOMClass(instanceClass));
-  DOMJSClass* domClass = DOMJSClass::FromJSClass(instanceClass);
   return (uint32_t)domClass->mInterfaceChain[depth] == protoID;
 }
 
 // Only set allowNativeWrapper to false if you really know you need it, if in
 // doubt use true. Setting it to false disables security wrappers.
 bool
 XPCOMObjectToJsval(JSContext* cx, JSObject* scope, xpcObjectHelper &helper,
                    const nsIID* iid, bool allowNativeWrapper, JS::Value* rval)
@@ -372,24 +371,21 @@ QueryInterface(JSContext* cx, unsigned a
 
   // Get the object. It might be a security wrapper, in which case we do a checked
   // unwrap.
   JSObject* origObj = JSVAL_TO_OBJECT(thisv);
   JSObject* obj = js::UnwrapObjectChecked(cx, origObj);
   if (!obj)
       return false;
 
-  JSClass* clasp = js::GetObjectJSClass(obj);
-  if (!IsDOMClass(clasp) ||
-      !DOMJSClass::FromJSClass(clasp)->mDOMObjectIsISupports) {
+  nsISupports* native;
+  if (!UnwrapDOMObjectToISupports(obj, native)) {
     return Throw<true>(cx, NS_ERROR_FAILURE);
   }
 
-  nsISupports* native = UnwrapDOMObject<nsISupports>(obj);
-
   if (argc < 1) {
     return Throw<true>(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
   }
 
   JS::Value* argv = JS_ARGV(cx, vp);
   if (!argv[0].isObject()) {
     return Throw<true>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
   }
@@ -446,18 +442,19 @@ XrayResolveProperty(JSContext* cx, JSObj
       // Set i to be the index into our full list of ids/specs that we're
       // looking at now.
       size_t i = methods[prefIdx].specs - methodSpecs;
       for ( ; methodIds[i] != JSID_VOID; ++i) {
         if (id == methodIds[i]) {
           JSFunction *fun = JS_NewFunctionById(cx, methodSpecs[i].call.op,
                                                methodSpecs[i].nargs, 0,
                                                wrapper, id);
-          if (!fun)
-              return false;
+          if (!fun) {
+            return false;
+          }
           SET_JITINFO(fun, methodSpecs[i].call.info);
           JSObject *funobj = JS_GetFunctionObject(fun);
           desc->value.setObject(*funobj);
           desc->attrs = methodSpecs[i].flags;
           desc->obj = wrapper;
           desc->setter = nullptr;
           desc->getter = nullptr;
           return true;
@@ -585,10 +582,51 @@ XrayEnumerateProperties(JS::AutoIdVector
         }
       }
     }
   }
 
   return true;
 }
 
+bool
+GetPropertyOnPrototype(JSContext* cx, JSObject* proxy, jsid id, bool* found,
+                       JS::Value* vp)
+{
+  JSObject* proto = js::GetObjectProto(proxy);
+  if (!proto) {
+    *found = false;
+    return true;
+  }
+
+  JSBool hasProp;
+  if (!JS_HasPropertyById(cx, proto, id, &hasProp)) {
+    return false;
+  }
+
+  *found = hasProp;
+  if (!hasProp || !vp) {
+    return true;
+  }
+
+  return JS_ForwardGetPropertyTo(cx, proto, id, proxy, vp);
+}
+
+bool
+HasPropertyOnPrototype(JSContext* cx, JSObject* proxy, DOMProxyHandler* handler,
+                       jsid id)
+{
+  JSAutoEnterCompartment ac;
+  if (xpc::WrapperFactory::IsXrayWrapper(proxy)) {
+    proxy = js::UnwrapObject(proxy);
+    if (!ac.enter(cx, proxy)) {
+      return false;
+    }
+  }
+  MOZ_ASSERT(js::IsProxy(proxy) && js::GetProxyHandler(proxy) == handler);
+
+  bool found;
+  // We ignore an error from GetPropertyOnPrototype.
+  return !GetPropertyOnPrototype(cx, proxy, id, &found, NULL) || found;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_BindingUtils_h__
 #define mozilla_dom_BindingUtils_h__
 
 #include "mozilla/dom/DOMJSClass.h"
+#include "mozilla/dom/DOMJSProxyHandler.h"
 #include "mozilla/dom/workers/Workers.h"
 #include "mozilla/ErrorResult.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "jswrapper.h"
 
 #include "nsIXPConnect.h"
@@ -73,72 +74,147 @@ IsDOMClass(const JSClass* clasp)
 }
 
 inline bool
 IsDOMClass(const js::Class* clasp)
 {
   return IsDOMClass(Jsvalify(clasp));
 }
 
+// It's ok for eRegularDOMObject and eProxyDOMObject to be the same, but
+// eNonDOMObject should always be different from the other two. This enum
+// shouldn't be used to differentiate between non-proxy and proxy bindings.
+enum DOMObjectSlot {
+  eNonDOMObject = -1,
+  eRegularDOMObject = DOM_OBJECT_SLOT,
+  eProxyDOMObject = DOM_PROXY_OBJECT_SLOT
+};
+
 template <class T>
 inline T*
-UnwrapDOMObject(JSObject* obj)
+UnwrapDOMObject(JSObject* obj, DOMObjectSlot slot)
 {
-  MOZ_ASSERT(IsDOMClass(JS_GetClass(obj)));
+  MOZ_ASSERT(slot != eNonDOMObject,
+             "Don't pass non-DOM objects to this function");
 
-  JS::Value val = js::GetReservedSlot(obj, DOM_OBJECT_SLOT);
+#ifdef DEBUG
+  if (IsDOMClass(js::GetObjectClass(obj))) {
+    MOZ_ASSERT(slot == eRegularDOMObject);
+  } else {
+    MOZ_ASSERT(js::IsObjectProxyClass(js::GetObjectClass(obj)) ||
+               js::IsFunctionProxyClass(js::GetObjectClass(obj)));
+    MOZ_ASSERT(js::GetProxyHandler(obj)->family() == ProxyFamily());
+    MOZ_ASSERT(slot == eProxyDOMObject);
+  }
+#endif
+
+  JS::Value val = js::GetReservedSlot(obj, slot);
   // XXXbz/khuey worker code tries to unwrap interface objects (which have
   // nothing here).  That needs to stop.
   // XXX We don't null-check UnwrapObject's result; aren't we going to crash
   // anyway?
   if (val.isUndefined()) {
     return NULL;
   }
   
   return static_cast<T*>(val.toPrivate());
 }
 
+// Only use this with a new DOM binding object (either proxy or regular).
+inline const DOMClass*
+GetDOMClass(JSObject* obj)
+{
+  js::Class* clasp = js::GetObjectClass(obj);
+  if (IsDOMClass(clasp)) {
+    return &DOMJSClass::FromJSClass(clasp)->mClass;
+  }
+
+  js::BaseProxyHandler* handler = js::GetProxyHandler(obj);
+  MOZ_ASSERT(handler->family() == ProxyFamily());
+  return &static_cast<DOMProxyHandler*>(handler)->mClass;
+}
+
+inline DOMObjectSlot
+GetDOMClass(JSObject* obj, const DOMClass*& result)
+{
+  js::Class* clasp = js::GetObjectClass(obj);
+  if (IsDOMClass(clasp)) {
+    result = &DOMJSClass::FromJSClass(clasp)->mClass;
+    return eRegularDOMObject;
+  }
+
+  if (js::IsObjectProxyClass(clasp) || js::IsFunctionProxyClass(clasp)) {
+    js::BaseProxyHandler* handler = js::GetProxyHandler(obj);
+    if (handler->family() == ProxyFamily()) {
+      result = &static_cast<DOMProxyHandler*>(handler)->mClass;
+      return eProxyDOMObject;
+    }
+  }
+
+  return eNonDOMObject;
+}
+
+inline bool
+UnwrapDOMObjectToISupports(JSObject* obj, nsISupports*& result)
+{
+  const DOMClass* clasp;
+  DOMObjectSlot slot = GetDOMClass(obj, clasp);
+  if (slot == eNonDOMObject || !clasp->mDOMObjectIsISupports) {
+    return false;
+  }
+ 
+  result = UnwrapDOMObject<nsISupports>(obj, slot);
+  return true;
+}
+
+inline bool
+IsDOMObject(JSObject* obj)
+{
+  js::Class* clasp = js::GetObjectClass(obj);
+  return IsDOMClass(clasp) ||
+         ((js::IsObjectProxyClass(clasp) || js::IsFunctionProxyClass(clasp)) &&
+          js::GetProxyHandler(obj)->family() == ProxyFamily());
+}
+
 // Some callers don't want to set an exception when unwrappin fails
 // (for example, overload resolution uses unwrapping to tell what sort
 // of thing it's looking at).
 // U must be something that a T* can be assigned to (e.g. T* or an nsRefPtr<T>).
 template <prototypes::ID PrototypeID, class T, typename U>
 inline nsresult
 UnwrapObject(JSContext* cx, JSObject* obj, U& value)
 {
   /* First check to see whether we have a DOM object */
-  JSClass* clasp = js::GetObjectJSClass(obj);
-  if (!IsDOMClass(clasp)) {
+  const DOMClass* domClass;
+  DOMObjectSlot slot = GetDOMClass(obj, domClass);
+  if (slot == eNonDOMObject) {
     /* Maybe we have a security wrapper or outer window? */
     if (!js::IsWrapper(obj)) {
       /* Not a DOM object, not a wrapper, just bail */
       return NS_ERROR_XPC_BAD_CONVERT_JS;
     }
 
     obj = xpc::Unwrap(cx, obj, false);
     if (!obj) {
       return NS_ERROR_XPC_SECURITY_MANAGER_VETO;
     }
     MOZ_ASSERT(!js::IsWrapper(obj));
-    clasp = js::GetObjectJSClass(obj);
-    if (!IsDOMClass(clasp)) {
+    slot = GetDOMClass(obj, domClass);
+    if (slot == eNonDOMObject) {
       /* We don't have a DOM object */
       return NS_ERROR_XPC_BAD_CONVERT_JS;
     }
   }
 
-  MOZ_ASSERT(IsDOMClass(clasp));
-
   /* This object is a DOM object.  Double-check that it is safely
      castable to T by checking whether it claims to inherit from the
      class identified by protoID. */
-  DOMJSClass* domClass = DOMJSClass::FromJSClass(clasp);
   if (domClass->mInterfaceChain[PrototypeTraits<PrototypeID>::Depth] ==
       PrototypeID) {
-    value = UnwrapDOMObject<T>(obj);
+    value = UnwrapDOMObject<T>(obj, slot);
     return NS_OK;
   }
 
   /* It's the wrong sort of DOM object */
   return NS_ERROR_XPC_BAD_CONVERT_JS;
 }
 
 inline bool
@@ -304,17 +380,17 @@ struct Prefable {
  *
  * returns the interface prototype object if protoClass is non-null, else it
  * returns the interface object.
  */
 JSObject*
 CreateInterfaceObjects(JSContext* cx, JSObject* global, JSObject* receiver,
                        JSObject* protoProto, JSClass* protoClass,
                        JSClass* constructorClass, JSNative constructor,
-                       unsigned ctorNargs, JSClass* instanceClass,
+                       unsigned ctorNargs, const DOMClass* domClass,
                        Prefable<JSFunctionSpec>* methods,
                        Prefable<JSPropertySpec>* properties,
                        Prefable<ConstantSpec>* constants,
                        Prefable<JSFunctionSpec>* staticMethods, const char* name);
 
 template <class T>
 inline bool
 WrapNewBindingObject(JSContext* cx, JSObject* scope, T* value, JS::Value* vp)
@@ -550,16 +626,32 @@ GetParentPointer(T* aObject)
 }
 
 inline nsISupports*
 GetParentPointer(const ParentObject& aObject)
 {
   return ToSupports(aObject.mObject);
 }
 
+template<class T>
+inline void
+ClearWrapper(T* p, nsWrapperCache* cache)
+{
+  cache->ClearWrapper();
+}
+
+template<class T>
+inline void
+ClearWrapper(T* p, void*)
+{
+  nsWrapperCache* cache;
+  CallQueryInterface(p, &cache);
+  ClearWrapper(p, cache);
+}
+
 // Can only be called with the immediate prototype of the instance object. Can
 // only be called on the prototype of an object known to be a DOM instance.
 JSBool
 InstanceClassHasProtoAtDepth(JSHandleObject protoObject, uint32_t protoID,
                              uint32_t depth);
 
 // Only set allowNativeWrapper to false if you really know you need it, if in
 // doubt use true. Setting it to false disables security wrappers.
@@ -695,16 +787,24 @@ InitIds(JSContext* cx, Prefable<Spec>* p
   return true;
 }
 
 JSBool
 QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp);
 JSBool
 ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
 
+bool
+GetPropertyOnPrototype(JSContext* cx, JSObject* proxy, jsid id, bool* found,
+                       JS::Value* vp);
+
+bool
+HasPropertyOnPrototype(JSContext* cx, JSObject* proxy, DOMProxyHandler* handler,
+                       jsid id);
+
 template<class T>
 class NonNull
 {
 public:
   NonNull()
 #ifdef DEBUG
     : inited(false)
 #endif
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -296,16 +296,62 @@ DOMInterfaces = {
         },
 
 'OnlyForUseInConstructor' : {
         'nativeType': 'mozilla::dom::OnlyForUseInConstructor',
         'headerFile': 'TestBindingHeader.h',
         'register': False
         },
 
+
+'TestIndexedGetterInterface' : {
+        'nativeType': 'mozilla::dom::TestIndexedGetterInterface',
+        'headerFile': 'TestBindingHeader.h',
+        'register': False,
+        'infallible': [ 'length' ]
+        },
+
+'TestNamedGetterInterface' : {
+        'nativeType': 'mozilla::dom::TestNamedGetterInterface',
+        'headerFile': 'TestBindingHeader.h',
+        'register': False
+        },
+
+'TestIndexedAndNamedGetterInterface' : {
+        'nativeType': 'mozilla::dom::TestIndexedAndNamedGetterInterface',
+        'headerFile': 'TestBindingHeader.h',
+        'register': False,
+        'infallible': [ 'length' ]
+        },
+
+'TestIndexedSetterInterface' : {
+        'nativeType': 'mozilla::dom::TestIndexedSetterInterface',
+        'headerFile': 'TestBindingHeader.h',
+        'register': False
+        },
+
+'TestNamedSetterInterface' : {
+        'nativeType': 'mozilla::dom::TestNamedSetterInterface',
+        'headerFile': 'TestBindingHeader.h',
+        'register': False
+        },
+
+'TestIndexedAndNamedSetterInterface' : {
+        'nativeType': 'mozilla::dom::TestIndexedAndNamedSetterInterface',
+        'headerFile': 'TestBindingHeader.h',
+        'register': False
+        },
+
+'TestIndexedAndNamedGetterAndSetterInterface' : {
+        'nativeType': 'mozilla::dom::TestIndexedAndNamedGetterAndSetterInterface',
+        'headerFile': 'TestBindingHeader.h',
+        'register': False,
+        'infallible': [ 'length', '__stringifier' ],
+        'binaryNames': { '__stringifier': 'Stringify' }
+        },
 }
 
 # These are temporary, until they've been converted to use new DOM bindings
 def addExternalIface(iface, nativeType=None, headerFile=None):
     if nativeType is None:
         nativeType = 'nsIDOM' + iface
     domInterface = {
         'nativeType': nativeType,
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -63,47 +63,53 @@ class CGNativePropertyHooks(CGThing):
     Generate a NativePropertyHooks for a given descriptor
     """
     def __init__(self, descriptor):
         CGThing.__init__(self)
         self.descriptor = descriptor
     def declare(self):
         if self.descriptor.workers:
             return ""
-        return "  extern const NativePropertyHooks NativeHooks;\n"
+        return "extern const NativePropertyHooks NativeHooks;\n"
     def define(self):
         if self.descriptor.workers:
             return ""
         parent = self.descriptor.interface.parent
         parentHooks = ("&" + toBindingNamespace(parent.identifier.name) + "::NativeHooks"
                        if parent else 'NULL')
         return """
 const NativePropertyHooks NativeHooks = { ResolveProperty, EnumerateProperties, %s };
 """ % parentHooks
 
+def DOMClass(descriptor):
+        protoList = ['prototypes::id::' + proto for proto in descriptor.prototypeChain]
+        # Pad out the list to the right length with _ID_Count so we
+        # guarantee that all the lists are the same length.  _ID_Count
+        # is never the ID of any prototype, so it's safe to use as
+        # padding.
+        protoList.extend(['prototypes::id::_ID_Count'] * (descriptor.config.maxProtoChainLength - len(protoList)))
+        prototypeChainString = ', '.join(protoList)
+        nativeHooks = "NULL" if descriptor.workers else "&NativeHooks"
+        return """{
+  { %s },
+  %s, %s
+}""" % (prototypeChainString, toStringBool(descriptor.nativeIsISupports),
+          nativeHooks)
+
 class CGDOMJSClass(CGThing):
     """
     Generate a DOMJSClass for a given descriptor
     """
     def __init__(self, descriptor):
         CGThing.__init__(self)
         self.descriptor = descriptor
     def declare(self):
-        return "  extern DOMJSClass Class;\n"
+        return "extern DOMJSClass Class;\n"
     def define(self):
         traceHook = TRACE_HOOK_NAME if self.descriptor.customTrace else 'NULL'
-        protoList = ['prototypes::id::' + proto for proto in self.descriptor.prototypeChain]
-        # Pad out the list to the right length with _ID_Count so we
-        # guarantee that all the lists are the same length.  _ID_Count
-        # is never the ID of any prototype, so it's safe to use as
-        # padding.
-        while len(protoList) < self.descriptor.config.maxProtoChainLength:
-            protoList.append('prototypes::id::_ID_Count')
-        prototypeChainString = ', '.join(protoList)
-        nativeHooks = "NULL" if self.descriptor.workers else "&NativeHooks"
         return """
 DOMJSClass Class = {
   { "%s",
     JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(1),
     %s, /* addProperty */
     JS_PropertyStub,       /* delProperty */
     JS_PropertyStub,       /* getProperty */
     JS_StrictPropertyStub, /* setProperty */
@@ -113,36 +119,33 @@ DOMJSClass Class = {
     %s, /* finalize */
     NULL,                  /* checkAccess */
     NULL,                  /* call */
     NULL,                  /* hasInstance */
     NULL,                  /* construct */
     %s, /* trace */
     JSCLASS_NO_INTERNAL_MEMBERS
   },
-  { %s },
-  -1, %s,
-  %s
+  %s,
+  -1
 };
 """ % (self.descriptor.interface.identifier.name,
        ADDPROPERTY_HOOK_NAME if self.descriptor.concrete and not self.descriptor.workers and self.descriptor.wrapperCache else 'JS_PropertyStub',
-       FINALIZE_HOOK_NAME, traceHook, prototypeChainString,
-       str(self.descriptor.nativeIsISupports).lower(),
-       nativeHooks)
+       FINALIZE_HOOK_NAME, traceHook,
+       CGIndenter(CGGeneric(DOMClass(self.descriptor))).define())
 
 class CGPrototypeJSClass(CGThing):
     def __init__(self, descriptor):
         CGThing.__init__(self)
         self.descriptor = descriptor
     def declare(self):
         # We're purely for internal consumption
         return ""
     def define(self):
-        return """
-static JSClass PrototypeClass = {
+        return """static JSClass PrototypeClass = {
   "%sPrototype",
   JSCLASS_HAS_RESERVED_SLOTS(1),
   JS_PropertyStub,       /* addProperty */
   JS_PropertyStub,       /* delProperty */
   JS_PropertyStub,       /* getProperty */
   JS_StrictPropertyStub, /* setProperty */
   JS_EnumerateStub,
   JS_ResolveStub,
@@ -197,22 +200,22 @@ class CGList(CGThing):
     def __init__(self, children, joiner=""):
         CGThing.__init__(self)
         self.children = children
         self.joiner = joiner
     def append(self, child):
         self.children.append(child)
     def prepend(self, child):
         self.children.insert(0, child)
+    def join(self, generator):
+        return self.joiner.join(filter(lambda s: len(s) > 0, (child for child in generator)))
     def declare(self):
-        return self.joiner.join([child.declare() for child in self.children
-                                 if child is not None])
+        return self.join(child.declare() for child in self.children if child is not None)
     def define(self):
-        return self.joiner.join([child.define() for child in self.children
-                                 if child is not None])
+        return self.join(child.define() for child in self.children if child is not None)
 
 class CGGeneric(CGThing):
     """
     A class that spits out a fixed string into the codegen.  Can spit out a
     separate string for the declaration too.
     """
     def __init__(self, define="", declare=""):
         self.declareText = declare
@@ -226,32 +229,33 @@ class CGGeneric(CGThing):
 # don't want to indent empty lines.  So only indent lines that have a
 # non-newline character on them.
 lineStartDetector = re.compile("^(?=[^\n#])", re.MULTILINE)
 class CGIndenter(CGThing):
     """
     A class that takes another CGThing and generates code that indents that
     CGThing by some number of spaces.  The default indent is two spaces.
     """
-    def __init__(self, child, indentLevel=2):
+    def __init__(self, child, indentLevel=2, declareOnly=False):
         CGThing.__init__(self)
         self.child = child
         self.indent = " " * indentLevel
+        self.declareOnly = declareOnly
     def declare(self):
         decl = self.child.declare()
         if decl is not "":
             return re.sub(lineStartDetector, self.indent, decl)
         else:
             return ""
     def define(self):
         defn = self.child.define()
-        if defn is not "":
+        if defn is not "" and not self.declareOnly:
             return re.sub(lineStartDetector, self.indent, defn)
         else:
-            return ""
+            return defn
 
 class CGWrapper(CGThing):
     """
     Generic CGThing that wraps other CGThings with pre and post text.
     """
     def __init__(self, child, pre="", post="", declarePre=None,
                  declarePost=None, definePre=None, definePost=None,
                  declareOnly=False, defineOnly=False, reindent=False):
@@ -280,16 +284,23 @@ class CGWrapper(CGThing):
         defn = self.child.define()
         if self.reindent:
             # We don't use lineStartDetector because we don't want to
             # insert whitespace at the beginning of our _first_ line.
             defn = stripTrailingWhitespace(
                 defn.replace("\n", "\n" + (" " * len(self.definePre))))
         return self.definePre + defn + self.definePost
 
+class CGIfWrapper(CGWrapper):
+    def __init__(self, child, condition):
+        pre = CGWrapper(CGGeneric(condition), pre="if (", post=") {\n",
+                        reindent=True)
+        CGWrapper.__init__(self, CGIndenter(child), pre=pre.define(),
+                           post="\n}")
+
 class CGNamespace(CGWrapper):
     def __init__(self, namespace, child, declareOnly=False):
         pre = "namespace %s {\n" % namespace
         post = "} // namespace %s\n" % namespace
         CGWrapper.__init__(self, child, pre=pre, post=post,
                            declareOnly=declareOnly)
     @staticmethod
     def build(namespaces, child, declareOnly=False):
@@ -514,49 +525,64 @@ class CGAbstractMethod(CGThing):
 
     returnType is the IDLType of the return value
 
     args is a list of Argument objects
 
     inline should be True to generate an inline method, whose body is
     part of the declaration.
 
+    alwaysInline should be True to generate an inline method annotated with
+    MOZ_ALWAYS_INLINE.
+
     static should be True to generate a static method, which only has
     a definition.
+
+    If templateArgs is not None it should be a list of strings containing
+    template arguments, and the function will be templatized using those
+    arguments.
     """
-    def __init__(self, descriptor, name, returnType, args, inline=False, static=False):
+    def __init__(self, descriptor, name, returnType, args, inline=False, alwaysInline=False, static=False, templateArgs=None):
         CGThing.__init__(self)
         self.descriptor = descriptor
         self.name = name
         self.returnType = returnType
         self.args = args
         self.inline = inline
+        self.alwaysInline = alwaysInline
         self.static = static
+        self.templateArgs = templateArgs
     def _argstring(self):
         return ', '.join([str(a) for a in self.args])
+    def _template(self):
+        if self.templateArgs is None:
+            return ''
+        return 'template <%s>\n' % ', '.join(self.templateArgs)
     def _decorators(self):
         decorators = []
-        if self.inline:
+        if self.alwaysInline:
+            decorators.append('MOZ_ALWAYS_INLINE')
+        elif self.inline:
             decorators.append('inline')
         if self.static:
             decorators.append('static')
         decorators.append(self.returnType)
-        return ' '.join(decorators)
+        maybeNewline = " " if self.inline else "\n"
+        return ' '.join(decorators) + maybeNewline
     def declare(self):
         if self.inline:
             return self._define()
-        return "\n  %s %s(%s);\n" % (self._decorators(), self.name, self._argstring())
+        return "%s%s%s(%s);\n" % (self._template(), self._decorators(), self.name, self._argstring())
     def _define(self):
         return self.definition_prologue() + "\n" + self.definition_body() + self.definition_epilogue()
     def define(self):
         return "" if self.inline else self._define()
     def definition_prologue(self):
-        maybeNewline = " " if self.inline else "\n"
-        return "\n%s%s%s(%s)\n{" % (self._decorators(), maybeNewline,
-                                    self.name, self._argstring())
+        return "%s%s%s(%s)\n{" % (self._template(), self._decorators(),
+                                  self.name, self._argstring())
     def definition_epilogue(self):
         return "\n}\n"
     def definition_body(self):
         assert(False) # Override me!
 
 class CGAbstractStaticMethod(CGAbstractMethod):
     """
     Abstract base class for codegen of implementation-only (no
@@ -575,17 +601,17 @@ class CGAbstractClassHook(CGAbstractStat
     'this' unwrapping as it assumes that the unwrapped type is always known.
     """
     def __init__(self, descriptor, name, returnType, args):
         CGAbstractStaticMethod.__init__(self, descriptor, name, returnType,
                                         args)
 
     def definition_body_prologue(self):
         return """
-  %s* self = UnwrapDOMObject<%s>(obj);
+  %s* self = UnwrapDOMObject<%s>(obj, eRegularDOMObject);
 """ % (self.descriptor.nativeType, self.descriptor.nativeType)
 
     def definition_body(self):
         return self.definition_body_prologue() + self.generate_code()
 
     def generate_code(self):
         # Override me
         assert(False)
@@ -603,43 +629,45 @@ class CGAddPropertyHook(CGAbstractClassH
     def generate_code(self):
         # FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=774279
         # Using a real trace hook might enable us to deal with non-nsISupports
         # wrappercached things here.
         assert self.descriptor.nativeIsISupports
         return """  nsContentUtils::PreserveWrapper(reinterpret_cast<nsISupports*>(self), self);
   return true;"""
 
+def finalizeHook(descriptor, hookName, context):
+    if descriptor.customFinalize:
+        return """if (self) {
+  self->%s(%s);
+}""" % (hookName, context)
+    clearWrapper = "ClearWrapper(self, self);\n" if descriptor.wrapperCache else ""
+    if descriptor.workers:
+        release = "self->Release();"
+    else:
+        assert descriptor.nativeIsISupports
+        release = """XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance();
+if (rt) {
+  rt->DeferredRelease(reinterpret_cast<nsISupports*>(self));
+} else {
+  NS_RELEASE(self);
+}"""
+    return clearWrapper + release
+
 class CGClassFinalizeHook(CGAbstractClassHook):
     """
     A hook for finalize, used to release our native object.
     """
     def __init__(self, descriptor):
         args = [Argument('JSFreeOp*', 'fop'), Argument('JSObject*', 'obj')]
         CGAbstractClassHook.__init__(self, descriptor, FINALIZE_HOOK_NAME,
                                      'void', args)
 
     def generate_code(self):
-        if self.descriptor.customFinalize:
-            return """  if (self) {
-    self->%s(%s);
-  }""" % (self.name, self.args[0].name)
-        clearWrapper = "self->ClearWrapper();\n  " if self.descriptor.wrapperCache else ""
-        if self.descriptor.workers:
-            release = "self->Release();"
-        else:
-            assert self.descriptor.nativeIsISupports
-            release = """XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance();
-  if (rt) {
-    rt->DeferredRelease(reinterpret_cast<nsISupports*>(self));
-  } else {
-    NS_RELEASE(self);
-  }"""
-        return """
-  %s%s""" % (clearWrapper, release)
+        return CGIndenter(CGGeneric(finalizeHook(self.descriptor, self.name, self.args[0].name))).define()
 
 class CGClassTraceHook(CGAbstractClassHook):
     """
     A hook to trace through our native object; used for GC and CC
     """
     def __init__(self, descriptor):
         args = [Argument('JSTracer*', 'trc'), Argument('JSObject*', 'obj')]
         CGAbstractClassHook.__init__(self, descriptor, TRACE_HOOK_NAME, 'void',
@@ -889,34 +917,56 @@ def methodLength(method):
 
 class MethodDefiner(PropertyDefiner):
     """
     A class for defining methods on a prototype object.
     """
     def __init__(self, descriptor, name, static):
         PropertyDefiner.__init__(self, descriptor, name)
 
+        # FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=772822
+        #       We should be able to check for special operations without an
+        #       identifier. For now we check if the name starts with __
         methods = [m for m in descriptor.interface.members if
-                   m.isMethod() and m.isStatic() == static]
+                   m.isMethod() and m.isStatic() == static and
+                   not m.isIdentifierLess()]
         self.chrome = [{"name": m.identifier.name,
                         "length": methodLength(m),
                         "flags": "JSPROP_ENUMERATE",
                         "pref": PropertyDefiner.getControllingPref(m) }
                        for m in methods]
         self.regular = [{"name": m.identifier.name,
                          "length": methodLength(m),
                          "flags": "JSPROP_ENUMERATE",
                          "pref": PropertyDefiner.getControllingPref(m) }
                         for m in methods if not isChromeOnly(m)]
+
+        # FIXME Check for an existing iterator on the interface first.
+        if any(m.isGetter() and m.isIndexed() for m in methods):
+            self.chrome.append({"name": 'iterator',
+                                "methodInfo": False,
+                                "nativeName": "JS_ArrayIterator",
+                                "length": 0,
+                                "flags": "JSPROP_ENUMERATE",
+                                "pref": None })
+            self.regular.append({"name": 'iterator',
+                                 "methodInfo": False,
+                                 "nativeName": "JS_ArrayIterator",
+                                 "length": 0,
+                                 "flags": "JSPROP_ENUMERATE",
+                                 "pref": None })
+
         if not descriptor.interface.parent and not static and not descriptor.workers:
             self.chrome.append({"name": 'QueryInterface',
+                                "methodInfo": False,
                                 "length": 1,
                                 "flags": "0",
                                 "pref": None })
             self.regular.append({"name": 'QueryInterface',
+                                 "methodInfo": False,
                                  "length": 1,
                                  "flags": "0",
                                  "pref": None })
 
         if static:
             if not descriptor.interface.hasInterfaceObject():
                 # static methods go on the interface object
                 assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
@@ -928,19 +978,22 @@ class MethodDefiner(PropertyDefiner):
     def generateArray(self, array, name, doIdArrays):
         if len(array) == 0:
             return ""
 
         def pref(m):
             return m["pref"]
 
         def specData(m):
-            isQI = (m["name"] == 'QueryInterface')
-            jitinfo = ("&%s_methodinfo" % m["name"]) if not isQI else "NULL"
-            accessor = "genericMethod" if not isQI else "QueryInterface"
+            if m.get("methodInfo", True):
+                jitinfo = ("&%s_methodinfo" % m["name"])
+                accessor = "genericMethod"
+            else:
+                jitinfo = "nullptr"
+                accessor = m.get("nativeName", m["name"])
             return (m["name"], accessor, jitinfo, m["length"], m["flags"])
 
         return self.generatePrefableArray(
             array, name,
             '  JS_FNINFO("%s", %s, %s, %s, %s)',
             '  JS_FS_END',
             'JSFunctionSpec',
             pref, specData, doIdArrays)
@@ -1101,58 +1154,66 @@ class CGCreateInterfaceObjectsMethod(CGA
             prefCache = CGWrapper(CGIndenter(CGList(prefCacheData, "\n")),
                                   pre=("static bool sPrefCachesInited = false;\n"
                                        "if (!sPrefCachesInited) {\n"
                                        "  sPrefCachesInited = true;\n"),
                                   post="\n}")
         else:
             prefCache = None
             
-        getParentProto = ("JSObject* parentProto = %s;\n"
-                          "if (!parentProto) {\n"
-                          "  return NULL;\n"
-                          "}") % getParentProto
+        getParentProto = ("JSObject* parentProto = %s;\n" +
+                          "if (!parentProto) {\n" +
+                          "  return NULL;\n" +
+                          "}\n") % getParentProto
 
         needInterfaceObjectClass = (needInterfaceObject and
                                     self.descriptor.hasInstanceInterface)
         needConstructor = (needInterfaceObject and
                            not self.descriptor.hasInstanceInterface)
         if self.descriptor.interface.ctor():
             constructHook = CONSTRUCT_HOOK_NAME
             constructArgs = methodLength(self.descriptor.interface.ctor())
         else:
             constructHook = "ThrowingConstructor"
             constructArgs = 0
 
-        call = CGGeneric(("return dom::CreateInterfaceObjects(aCx, aGlobal, aReceiver, parentProto,\n"
-                          "                                   %s, %s, %s, %d,\n"
-                          "                                   %s,\n"
-                          "                                   %%(methods)s, %%(attrs)s, %%(consts)s, %%(staticMethods)s,\n"
-                          "                                   %s);") % (
+        if self.descriptor.concrete:
+            if self.descriptor.proxy:
+                domClass = "&Class"
+            else:
+                domClass = "&Class.mClass"
+        else:
+            domClass = "nullptr"
+
+        call = """return dom::CreateInterfaceObjects(aCx, aGlobal, aReceiver, parentProto,
+                                   %s, %s, %s, %d,
+                                   %s,
+                                   %%(methods)s, %%(attrs)s,
+                                   %%(consts)s, %%(staticMethods)s,
+                                   %s);""" % (
             "&PrototypeClass" if needInterfacePrototypeObject else "NULL",
             "&InterfaceObjectClass" if needInterfaceObjectClass else "NULL",
             constructHook if needConstructor else "NULL",
             constructArgs,
-            "&Class.mBase" if self.descriptor.concrete else "NULL",
-            '"' + self.descriptor.interface.identifier.name + '"' if needInterfaceObject else "NULL"))
-
+            domClass,
+            '"' + self.descriptor.interface.identifier.name + '"' if needInterfaceObject else "NULL")
         if self.properties.hasChromeOnly():
             if self.descriptor.workers:
                 accessCheck = "mozilla::dom::workers::GetWorkerPrivateFromContext(aCx)->IsChromeWorker()"
             else:
                 accessCheck = "xpc::AccessCheck::isChrome(js::GetObjectCompartment(aGlobal))"
-            accessCheck = "if (" + accessCheck + ") {\n"
-            chrome = CGWrapper(CGGeneric((CGIndenter(call).define() % self.properties.variableNames(True))),
-                               pre=accessCheck, post="\n}")
+            chrome = CGIfWrapper(CGGeneric(call % self.properties.variableNames(True)),
+                                 accessCheck)
+            chrome = CGWrapper(chrome, pre="\n\n")
         else:
             chrome = None
 
         functionBody = CGList(
             [CGGeneric(getParentProto), initIds, prefCache, chrome,
-             CGGeneric(call.define() % self.properties.variableNames(False))],
+             CGGeneric(call % self.properties.variableNames(False))],
             "\n\n")
         return CGIndenter(functionBody).define()
 
 class CGGetPerInterfaceObject(CGAbstractMethod):
     """
     A method for getting a per-interface object (a prototype object or interface
     constructor object).
     """
@@ -1267,33 +1328,58 @@ class CGDefineDOMInterfaceMethod(CGAbstr
             getter = "GetConstructorObject"
 
         return ("  JSObject* global = JS_GetGlobalForObject(aCx, aReceiver);\n" +
                 CheckPref(self.descriptor, "global", "*aEnabled", "false") + 
                 """
   *aEnabled = true;
   return !!%s(aCx, global, aReceiver);""" % (getter))
 
-class CGWrapMethod(CGAbstractMethod):
+class CGIsMethod(CGAbstractMethod):
     def __init__(self, descriptor):
-        # XXX can we wrap if we don't have an interface prototype object?
+        args = [Argument('JSObject*', 'obj')]
+        CGAbstractMethod.__init__(self, descriptor, 'Is', 'bool', args)
+
+    def definition_body(self):
+        # Non-proxy implementation would check
+        #   js::GetObjectJSClass(obj) == &Class.mBase
+        return """  return IsProxy(obj);"""
+
+class CGWrapWithCacheMethod(CGAbstractMethod):
+    def __init__(self, descriptor):
         assert descriptor.interface.hasInterfacePrototypeObject()
         args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aScope'),
                 Argument(descriptor.nativeType + '*', 'aObject'),
+                Argument('nsWrapperCache*', 'aCache'),
                 Argument('bool*', 'aTriedToWrap')]
         CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
 
     def definition_body(self):
         if self.descriptor.workers:
-            return """
-  *aTriedToWrap = true;
+            return """  *aTriedToWrap = true;
   return aObject->GetJSObject();"""
 
-        return """
-  *aTriedToWrap = true;
+        if self.descriptor.proxy:
+            create = """  JSObject *obj = NewProxyObject(aCx, &DOMProxyHandler::instance,
+                                 JS::PrivateValue(aObject), proto, parent);
+  if (!obj) {
+    return NULL;
+  }
+
+"""
+        else:
+            create = """  JSObject* obj = JS_NewObject(aCx, &Class.mBase, proto, parent);
+  if (!obj) {
+    return NULL;
+  }
+
+  js::SetReservedSlot(obj, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aObject));
+"""
+
+        return """  *aTriedToWrap = true;
 
   JSObject* parent = WrapNativeParent(aCx, aScope, aObject->GetParentObject());
   if (!parent) {
     return NULL;
   }
 
   JSAutoEnterCompartment ac;
   if (js::GetGlobalForObjectCrossCompartment(parent) != aScope) {
@@ -1304,27 +1390,33 @@ class CGWrapMethod(CGAbstractMethod):
 
   JSObject* global = JS_GetGlobalForObject(aCx, parent);
 %s
   JSObject* proto = GetProtoObject(aCx, global, global);
   if (!proto) {
     return NULL;
   }
 
-  JSObject* obj = JS_NewObject(aCx, &Class.mBase, proto, parent);
-  if (!obj) {
-    return NULL;
-  }
-
-  js::SetReservedSlot(obj, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aObject));
+%s
   NS_ADDREF(aObject);
 
-  aObject->SetWrapper(obj);
-
-  return obj;""" % (CheckPref(self.descriptor, "global", "*aTriedToWrap", "NULL", "aObject"))
+  aCache->SetWrapper(obj);
+
+  return obj;""" % (CheckPref(self.descriptor, "global", "*aTriedToWrap", "NULL", "aCache"), create)
+
+class CGWrapMethod(CGAbstractMethod):
+    def __init__(self, descriptor):
+        # XXX can we wrap if we don't have an interface prototype object?
+        assert descriptor.interface.hasInterfacePrototypeObject()
+        args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aScope'),
+                Argument('T*', 'aObject'), Argument('bool*', 'aTriedToWrap')]
+        CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args, inline=True, templateArgs=["class T"])
+
+    def definition_body(self):
+        return "  return Wrap(aCx, aScope, aObject, aObject, aTriedToWrap);"
 
 class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
     def __init__(self, descriptor):
         # XXX can we wrap if we don't have an interface prototype object?
         assert descriptor.interface.hasInterfacePrototypeObject()
         args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aScope'),
                 Argument(descriptor.nativeType + '*', 'aObject')]
         CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
@@ -2200,17 +2292,17 @@ for (uint32_t i = 0; i < length; ++i) {
 
         template = ("if (!%s.Init(cx, %s)) {\n"
                     "  return false;\n"
                     "}" % (selfRef, val))
 
         return (template, declType, None, False)
 
     if not type.isPrimitive():
-        raise TypeError("Need conversion for argument type '%s'" % type)
+        raise TypeError("Need conversion for argument type '%s'" % str(type))
 
     # XXXbz need to add support for [EnforceRange] and [Clamp]
     typeName = builtinNames[type.tag()]
     if type.nullable():
         dataLoc = "${declName}.SetValue()"
         nullCondition = "${val}.isNullOrUndefined()"
         if defaultValue is not None and isinstance(defaultValue, IDLNullValue):
             nullCondition = "!(${haveValue}) || " + nullCondition
@@ -2653,131 +2745,132 @@ def infallibleForAttr(attr, descriptorPr
                                   memberIsCreator(attr))[1]
 
 def typeNeedsCx(type):
     return (type is not None and
             (type.isCallback() or type.isAny() or type.isObject() or
              (type.isUnion() and
               any(typeNeedsCx(t) for t in type.unroll().flatMemberTypes))))
 
-# Returns a CGThing containing the type of the return value, or None
-# if there is no need for a return value.
+# Returns a tuple consisting of a CGThing containing the type of the return
+# value, or None if there is no need for a return value, and a boolean signaling
+# whether the return value is passed in an out parameter.
 def getRetvalDeclarationForType(returnType, descriptorProvider,
                                 resultAlreadyAddRefed):
     if returnType is None or returnType.isVoid():
         # Nothing to declare
-        return None
+        return None, False
     if returnType.isPrimitive() and returnType.tag() in builtinNames:
         result = CGGeneric(builtinNames[returnType.tag()])
         if returnType.nullable():
             result = CGWrapper(result, pre="Nullable<", post=">")
-        return result
+        return result, False
     if returnType.isString():
-        return CGGeneric("nsString")
+        return CGGeneric("nsString"), True
     if returnType.isEnum():
         if returnType.nullable():
             raise TypeError("We don't support nullable enum return values")
-        return CGGeneric(returnType.inner.identifier.name)
+        return CGGeneric(returnType.inner.identifier.name), False
     if returnType.isGeckoInterface():
         result = CGGeneric(descriptorProvider.getDescriptor(
             returnType.unroll().inner.identifier.name).nativeType)
         if resultAlreadyAddRefed:
             result = CGWrapper(result, pre="nsRefPtr<", post=">")
         else:
             result = CGWrapper(result, post="*")
-        return result
+        return result, False
     if returnType.isCallback():
         # XXXbz we're going to assume that callback types are always
         # nullable for now.
-        return CGGeneric("JSObject*")
-    if returnType.isAny():
-        return CGGeneric("JS::Value")
+        return CGGeneric("JSObject*"), False
+    if returnType.tag() is IDLType.Tags.any:
+        return CGGeneric("JS::Value"), False
     if returnType.isObject():
-        return CGGeneric("JSObject*")
+        return CGGeneric("JSObject*"), False
     if returnType.isSequence():
         nullable = returnType.nullable()
         if nullable:
             returnType = returnType.inner
         # If our result is already addrefed, use the right type in the
         # sequence argument here.
-        result = getRetvalDeclarationForType(returnType.inner,
-                                             descriptorProvider,
-                                             resultAlreadyAddRefed)
+        (result, _) = getRetvalDeclarationForType(returnType.inner,
+                                                  descriptorProvider,
+                                                  resultAlreadyAddRefed)
         result = CGWrapper(result, pre="nsTArray< ", post=" >")
         if nullable:
             result = CGWrapper(result, pre="Nullable< ", post=" >")
-        return result
+        return result, True
     raise TypeError("Don't know how to declare return value for %s" %
                     returnType)
 
 def isResultAlreadyAddRefed(descriptor, extendedAttributes):
     # Default to already_AddRefed on the main thread, raw pointer in workers
     return not descriptor.workers and not 'resultNotAddRefed' in extendedAttributes
 
 class CGCallGenerator(CGThing):
     """
     A class to generate an actual call to a C++ object.  Assumes that the C++
-    object is stored in a variable named "self".
+    object is stored in a variable whose name is given by the |object| argument.
     """
     def __init__(self, errorReport, arguments, argsPre, returnType,
-                 extendedAttributes, descriptorProvider, nativeMethodName, static):
+                 extendedAttributes, descriptorProvider, nativeMethodName,
+                 static, object="self", declareResult=True):
         CGThing.__init__(self)
 
         isFallible = errorReport is not None
 
+        resultAlreadyAddRefed = isResultAlreadyAddRefed(descriptorProvider,
+                                                        extendedAttributes)
+        (result, resultOutParam) = getRetvalDeclarationForType(returnType,
+                                                               descriptorProvider,
+                                                               resultAlreadyAddRefed)
+
         args = CGList([CGGeneric(arg) for arg in argsPre], ", ")
-        for (i, a) in enumerate(arguments):
-            arg = "arg" + str(i)
+        for (a, name) in arguments:
             # This is a workaround for a bug in Apple's clang.
             if a.type.isObject() and not a.type.nullable() and not a.optional:
-                arg = "(JSObject&)" + arg
-            args.append(CGGeneric(arg))
-        resultOutParam = (returnType is not None and
-                          (returnType.isString() or returnType.isSequence()))
+                name = "(JSObject&)" + name
+            args.append(CGGeneric(name))
+
         # Return values that go in outparams go here
         if resultOutParam:
             args.append(CGGeneric("result"))
         if isFallible:
             args.append(CGGeneric("rv"))
 
-        resultAlreadyAddRefed = isResultAlreadyAddRefed(descriptorProvider,
-                                                        extendedAttributes)
-        result = getRetvalDeclarationForType(returnType,
-                                             descriptorProvider,
-                                             resultAlreadyAddRefed)
         needsCx = (typeNeedsCx(returnType) or
-                   any(typeNeedsCx(a.type) for a in arguments) or
+                   any(typeNeedsCx(a.type) for (a, _) in arguments) or
                    'implicitJSContext' in extendedAttributes)
 
         if not "cx" in argsPre and needsCx:
             args.prepend(CGGeneric("cx"))
 
         # Build up our actual call
         self.cgRoot = CGList([], "\n")
 
         call = CGGeneric(nativeMethodName)
         if static:
-            call = CGWrapper(call, pre="%s::" % (descriptorProvider.getDescriptor(
-                returnType.unroll().inner.identifier.name).nativeType))
+            call = CGWrapper(call, pre="%s::" % descriptorProvider.nativeType)
         else: 
-            call = CGWrapper(call, pre="self->")
+            call = CGWrapper(call, pre="%s->" % object)
         call = CGList([call, CGWrapper(args, pre="(", post=");")])
         if result is not None:
-            result = CGWrapper(result, post=" result;")
-            self.cgRoot.prepend(result)
+            if declareResult:
+                result = CGWrapper(result, post=" result;")
+                self.cgRoot.prepend(result)
             if not resultOutParam:
                 call = CGWrapper(call, pre="result = ")
 
         call = CGWrapper(call)
         self.cgRoot.append(call)
 
         if isFallible:
             self.cgRoot.prepend(CGGeneric("ErrorResult rv;"))
             self.cgRoot.append(CGGeneric("if (rv.Failed()) {"))
-            self.cgRoot.append(CGIndenter(CGGeneric(errorReport)))
+            self.cgRoot.append(CGIndenter(errorReport))
             self.cgRoot.append(CGGeneric("}"))
 
     def define(self):
         return self.cgRoot.define()
 
 class MethodNotCreatorError(Exception):
     def __init__(self, typename):
         self.typename = typename
@@ -2825,27 +2918,29 @@ class CGPerSignatureCall(CGThing):
             cgThings = []
         cgThings.extend([CGArgumentConverter(arguments[i], i, self.getArgv(),
                                              self.getArgc(), self.descriptor,
                                              invalidEnumValueFatal=not setter) for
                          i in range(argConversionStartsAt, self.argCount)])
 
         cgThings.append(CGCallGenerator(
                     self.getErrorReport() if self.isFallible() else None,
-                    self.arguments, self.argsPre, returnType,
+                    self.getArguments(), self.argsPre, returnType,
                     self.extendedAttributes, descriptor, nativeMethodName,
                     static))
         self.cgRoot = CGList(cgThings, "\n")
 
     def getArgv(self):
         return "argv" if self.argCount > 0 else ""
     def getArgvDecl(self):
         return "\nJS::Value* argv = JS_ARGV(cx, vp);\n"
     def getArgc(self):
         return "argc"
+    def getArguments(self):
+        return [(a, "arg" + str(i)) for (i, a) in enumerate(self.arguments)]
 
     def isFallible(self):
         return not 'infallible' in self.extendedAttributes
 
     def wrap_return_value(self):
         isCreator = memberIsCreator(self.idlNode)
         if isCreator:
             # We better be returning addrefed things!
@@ -2860,20 +2955,20 @@ class CGPerSignatureCall(CGThing):
         except MethodNotCreatorError, err:
             assert not isCreator
             raise TypeError("%s being returned from non-creator method or property %s.%s" %
                             (err.typename,
                              self.descriptor.interface.identifier.name,
                              self.idlNode.identifier.name))
 
     def getErrorReport(self):
-        return 'return ThrowMethodFailedWithDetails<%s>(cx, rv, "%s", "%s");'\
-               % (toStringBool(not self.descriptor.workers),
-                  self.descriptor.interface.identifier.name,
-                  self.idlNode.identifier.name)
+        return CGGeneric('return ThrowMethodFailedWithDetails<%s>(cx, rv, "%s", "%s");'
+                         % (toStringBool(not self.descriptor.workers),
+                            self.descriptor.interface.identifier.name,
+                            self.idlNode.identifier.name))
 
     def define(self):
         return (self.cgRoot.define() + "\n" + self.wrap_return_value())
 
 class CGSwitch(CGList):
     """
     A class to generate code for a switch statement.
 
@@ -3841,37 +3936,127 @@ class ClassMethod(ClassItem):
                   'decorators': self.getDecorators(False),
                   'returnType': self.returnType,
                   'className': cgClass.getNameString(),
                   'name': self.name,
                   'args': args,
                   'const': ' const' if self.const else '',
                   'body': body })
 
+class ClassConstructor(ClassItem):
+    """
+    Used for adding a constructor to a CGClass.
+    
+    args is a list of Argument objects that are the arguments taken by the
+    constructor.
+    
+    inline should be True if the constructor should be marked inline.
+
+    bodyInHeader should be True if the body should be placed in the class
+    declaration in the header.
+
+    visibility determines the visibility of the constructor (public,
+    protected, private), defaults to private.
+
+    baseConstructors is a list of strings containing calls to base constructors,
+    defaults to None.
+
+    body contains a string with the code for the constructor, defaults to None.
+    """
+    def __init__(self, args, inline=False, bodyInHeader=False,
+                 visibility="private", baseConstructors=None, body=None):
+        self.args = args
+        self.inline = inline or bodyInHeader
+        self.bodyInHeader = bodyInHeader
+        self.baseConstructors = baseConstructors
+        self.body = body
+        ClassItem.__init__(self, None, visibility)
+
+    def getDecorators(self, declaring):
+        decorators = []
+        if self.inline and declaring:
+            decorators.append('inline')
+        if decorators:
+            return ' '.join(decorators) + ' '
+        return ''
+
+    def getInitializationList(self, cgClass):
+        items = [str(c) for c in self.baseConstructors]
+        for m in cgClass.members:
+            if not m.static:
+                initialize = m.getBody()
+                if initialize:
+                    items.append(m.name + "(" + initialize + ")")
+            
+        if len(items) > 0:
+            return '\n  : ' + ',\n    '.join(items)
+        return ''
+
+    def getBody(self):
+        assert self.body is not None
+        return self.body
+
+    def declare(self, cgClass):
+        args = ', '.join([str(a) for a in self.args])
+        if self.bodyInHeader:
+            body = '  ' + self.getBody();
+            body = stripTrailingWhitespace(body.replace('\n', '\n  '))
+            if len(body) > 0:
+                body += '\n'
+            body = self.getInitializationList(cgClass) + '\n{\n' + body + '}'
+        else:
+            body = ';'
+
+        return string.Template("""${decorators}${className}(${args})${body}
+""").substitute({ 'decorators': self.getDecorators(True),
+                  'className': cgClass.getNameString(),
+                  'args': args,
+                  'body': body })
+
+    def define(self, cgClass):
+        if self.bodyInHeader:
+            return ''
+
+        args = ', '.join([str(a) for a in self.args])
+
+        body = '  ' + self.getBody()
+        body = '\n' + stripTrailingWhitespace(body.replace('\n', '\n  '))
+        if len(body) > 0:
+            body += '\n'
+
+        return string.Template("""${decorators}
+${className}::${className}(${args})${initializationList}
+{${body}}\n
+""").substitute({ 'decorators': self.getDecorators(False),
+                  'className': cgClass.getNameString(),
+                  'args': args,
+                  'initializationList': self.getInitializationList(cgClass),
+                  'body': body })
+
 class ClassMember(ClassItem):
     def __init__(self, name, type, visibility="private", static=False,
                  body=None):
         self.type = type;
         self.static = static
         self.body = body
         ClassItem.__init__(self, name, visibility)
 
-    def getBody(self):
-        assert self.body is not None
-        return self.body
-
     def declare(self, cgClass):
         return '%s%s %s;\n' % ('static ' if self.static else '', self.type,
                                self.name)
 
     def define(self, cgClass):
         if not self.static:
             return ''
-        return '%s %s::%s = %s;\n' % (self.type, cgClass.getNameString(),
-                                      self.name, self.getBody())
+        if self.body:
+            body = " = " + self.body
+        else:
+            body = ""
+        return '%s %s::%s%s;\n' % (self.type, cgClass.getNameString(),
+                                      self.name, body)
 
 class ClassTypedef(ClassItem):
     def __init__(self, name, type, visibility="public"):
         self.type = type
         ClassItem.__init__(self, name, visibility)
 
     def declare(self, cgClass):
         return 'typedef %s %s;\n' % (self.type, self.name)
@@ -3897,23 +4082,24 @@ class ClassEnum(ClassItem):
         name = '' if not self.name else ' ' + self.name
         return 'enum%s\n{\n  %s\n};\n' % (name, ',\n  '.join(entries))
 
     def define(self, cgClass):
         # Only goes in the header
         return ''
 
 class CGClass(CGThing):
-    def __init__(self, name, bases=[], members=[], methods=[], typedefs = [],
-                 enums=[], templateArgs=[], templateSpecialization=[],
-                 isStruct=False, indent=''):
+    def __init__(self, name, bases=[], members=[], constructors=[], methods=[],
+                 typedefs = [], enums=[], templateArgs=[],
+                 templateSpecialization=[], isStruct=False, indent=''):
         CGThing.__init__(self)
         self.name = name
         self.bases = bases
         self.members = members
+        self.constructors = constructors
         self.methods = methods
         self.typedefs = typedefs
         self.enums = enums
         self.templateArgs = templateArgs
         self.templateSpecialization = templateSpecialization
         self.isStruct = isStruct
         self.indent = indent
         self.defaultVisibility ='public' if isStruct else 'private'
@@ -3980,43 +4166,44 @@ class CGClass(CGThing):
                         declaration = member.declare(cgClass)
                         declaration = CGIndenter(CGGeneric(declaration)).define()
                         result = result + declaration
                         itemCount = itemCount + 1
                     lastVisibility = visibility
             return (result, lastVisibility, itemCount)
 
         order = [(self.enums, ''), (self.typedefs, ''), (self.members, ''),
-                 (self.methods, '\n')]
+                 (self.constructors, '\n'), (self.methods, '\n')]
 
         lastVisibility = self.defaultVisibility
         itemCount = 0
         for (memberList, separator) in order:
             (memberString, lastVisibility, itemCount) = \
                 declareMembers(self, memberList, lastVisibility, itemCount,
                                separator)
             if self.indent:
                 memberString = CGIndenter(CGGeneric(memberString),
                                           len(self.indent)).define()
             result = result + memberString
 
-        result = result + self.indent + '};\n\n'
+        result = result + self.indent + '};\n'
         return result
 
     def define(self):
         def defineMembers(cgClass, memberList, itemCount, separator=''):
             result = ''
             for member in memberList:
                 if itemCount != 0:
                     result = result + separator
                 result = result + member.define(cgClass)
                 itemCount = itemCount + 1
             return (result, itemCount)
 
-        order = [(self.members, '\n'), (self.methods, '\n')]
+        order = [(self.members, '\n'), (self.constructors, '\n'),
+                 (self.methods, '\n')]
 
         result = ''
         itemCount = 0
         for (memberList, separator) in order:
             (memberString, itemCount) = defineMembers(self, memberList,
                                                       itemCount, separator)
             result = result + memberString
         return result
@@ -4112,99 +4299,632 @@ class CGClassForwardDeclare(CGThing):
         self.isStruct = isStruct
     def declare(self):
         type = 'struct' if self.isStruct else 'class'
         return '%s %s;\n' % (type, self.name)
     def define(self):
         # Header only
         return ''
 
+class CGProxySpecialOperation(CGPerSignatureCall):
+    """
+    Base class for classes for calling an indexed or named special operation
+    (don't use this directly, use the derived classes below).
+    """
+    def __init__(self, descriptor, operation):
+        nativeName = MakeNativeName(descriptor.binaryNames.get(operation, operation))
+        operation = descriptor.operations[operation]
+        assert len(operation.signatures()) == 1
+        signature = operation.signatures()[0]
+        extendedAttributes = descriptor.getExtendedAttributes(operation)
+
+        (returnType, arguments) = signature
+
+        # We pass len(arguments) as the final argument so that the
+        # CGPerSignatureCall won't do any argument conversion of its own.
+        CGPerSignatureCall.__init__(self, returnType, "", arguments, nativeName,
+                                    False, descriptor, operation,
+                                    len(arguments))
+
+        if operation.isSetter() or operation.isCreator():
+            # arguments[0] is the index or name of the item that we're setting.
+            argument = arguments[1]
+            template = getJSToNativeConversionTemplate(argument.type, descriptor)
+            templateValues = {
+                "declName": argument.identifier.name,
+                "holderName": argument.identifier.name + "_holder",
+                "val": "desc->value",
+                "valPtr": "&desc->value"
+            }
+            self.cgRoot.prepend(instantiateJSToNativeConversionTemplate(template, templateValues))
+        elif operation.isGetter():
+            self.cgRoot.prepend(CGGeneric("bool found;"))
+
+    def getArguments(self):
+        args = [(a, a.identifier.name) for a in self.arguments]
+        if self.idlNode.isGetter():
+            args.append((FakeArgument(BuiltinTypes[IDLBuiltinType.Types.boolean]), "found"))
+        return args
+
+    def wrap_return_value(self):
+        if not self.idlNode.isGetter() or self.templateValues is None:
+            return ""
+
+        wrap = CGGeneric(wrapForType(self.returnType, self.descriptor, self.templateValues))
+        wrap = CGIfWrapper(wrap, "found")
+        return "\n" + wrap.define()
+
+class CGProxyIndexedGetter(CGProxySpecialOperation):
+    """
+    Class to generate a call to an indexed getter. If templateValues is not None
+    the returned value will be wrapped with wrapForType using templateValues.
+    """
+    def __init__(self, descriptor, templateValues=None):
+        self.templateValues = templateValues
+        CGProxySpecialOperation.__init__(self, descriptor, 'IndexedGetter')
+
+class CGProxyIndexedSetter(CGProxySpecialOperation):
+    """
+    Class to generate a call to an indexed setter.
+    """
+    def __init__(self, descriptor):
+        CGProxySpecialOperation.__init__(self, descriptor, 'IndexedSetter')
+
+class CGProxyNamedGetter(CGProxySpecialOperation):
+    """
+    Class to generate a call to an named getter. If templateValues is not None
+    the returned value will be wrapped with wrapForType using templateValues.
+    """
+    def __init__(self, descriptor, templateValues=None):
+        self.templateValues = templateValues
+        CGProxySpecialOperation.__init__(self, descriptor, 'NamedGetter')
+
+class CGProxyNamedSetter(CGProxySpecialOperation):
+    """
+    Class to generate a call to a named setter.
+    """
+    def __init__(self, descriptor):
+        CGProxySpecialOperation.__init__(self, descriptor, 'NamedSetter')
+
+class CGProxyIsProxy(CGAbstractMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSObject*', 'obj')]
+        CGAbstractMethod.__init__(self, descriptor, "IsProxy", "bool", args, alwaysInline=True)
+    def declare(self):
+        return ""
+    def definition_body(self):
+        return "  return js::IsProxy(obj) && js::GetProxyHandler(obj) == &DOMProxyHandler::instance;"
+
+class CGProxyUnwrap(CGAbstractMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSObject*', 'obj')]
+        CGAbstractMethod.__init__(self, descriptor, "UnwrapProxy", descriptor.nativeType + '*', args, alwaysInline=True)
+    def declare(self):
+        return ""
+    def definition_body(self):
+        return """  if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
+    obj = js::UnwrapObject(obj);
+  }
+  MOZ_ASSERT(IsProxy(obj));
+  return static_cast<%s*>(js::GetProxyPrivate(obj).toPrivate());""" % (self.descriptor.nativeType)
+
+class CGDOMJSProxyHandlerDOMClass(CGThing):
+    def __init__(self, descriptor):
+        CGThing.__init__(self)
+        self.descriptor = descriptor
+    def declare(self):
+        return "extern const DOMClass Class;\n"
+    def define(self):
+        return """
+const DOMClass Class = """ + DOMClass(self.descriptor) + """;
+
+"""
+
+class CGDOMJSProxyHandler_CGDOMJSProxyHandler(ClassConstructor):
+    def __init__(self):
+        ClassConstructor.__init__(self, [], inline=True, visibility="public",
+                                  baseConstructors=["mozilla::dom::DOMProxyHandler(Class)"],
+                                  body="")
+
+class CGDOMJSProxyHandler_getOwnPropertyDescriptor(ClassMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
+                Argument('jsid', 'id'), Argument('bool', 'set'),
+                Argument('JSPropertyDescriptor*', 'desc')]
+        ClassMethod.__init__(self, "getOwnPropertyDescriptor", "bool", args)
+        self.descriptor = descriptor
+    def getBody(self):
+        indexedGetter = self.descriptor.operations['IndexedGetter']
+        indexedSetter = self.descriptor.operations['IndexedSetter']
+
+        setOrIndexedGet = ""
+        if indexedGetter or indexedSetter:
+            setOrIndexedGet += "int32_t index = GetArrayIndexFromId(cx, id);\n"
+
+        if indexedGetter:
+            readonly = toStringBool(self.descriptor.operations['IndexedSetter'] is None)
+            fillDescriptor = "FillPropertyDescriptor(desc, proxy, %s);\nreturn true;" % readonly
+            templateValues = {'jsvalRef': 'desc->value', 'jsvalPtr': '&desc->value',
+                              'obj': 'proxy', 'successCode': fillDescriptor}
+            get = ("if (index >= 0) {\n" +
+                   "  %s* self = UnwrapProxy(proxy);\n" +
+                   CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define() + "\n" +
+                   "}\n") % (self.descriptor.nativeType)
+
+        if indexedSetter or self.descriptor.operations['NamedSetter']:
+            setOrIndexedGet += "if (set) {\n"
+            if indexedSetter:
+                setOrIndexedGet += ("  if (index >= 0) {\n")
+                if not 'IndexedCreator' in self.descriptor.operations:
+                    # FIXME need to check that this is a 'supported property index'
+                    assert False
+                setOrIndexedGet += ("    FillPropertyDescriptor(desc, proxy, JSVAL_VOID, false);\n" +
+                                    "    return true;\n" +
+                                    "  }\n")
+            if self.descriptor.operations['NamedSetter']:
+                setOrIndexedGet += "  if (JSID_IS_STRING(id)) {\n"
+                if not 'NamedCreator' in self.descriptor.operations:
+                    # FIXME need to check that this is a 'supported property name'
+                    assert False
+                setOrIndexedGet += ("    FillPropertyDescriptor(desc, proxy, JSVAL_VOID, false);\n" +
+                                    "    return true;\n" +
+                                    "  }\n")
+            setOrIndexedGet += "}"
+            if indexedGetter:
+                setOrIndexedGet += (" else {\n" +
+                                    CGIndenter(CGGeneric(get)).define() +
+                                    "}")
+            setOrIndexedGet += "\n\n"
+        elif indexedGetter:
+            setOrIndexedGet += ("if (!set) {\n" +
+                                CGIndenter(CGGeneric(get)).define() +
+                                "}\n\n")
+
+        namedGetter = self.descriptor.operations['NamedGetter']
+        if namedGetter:
+            readonly = toStringBool(self.descriptor.operations['NamedSetter'] is None)
+            fillDescriptor = "FillPropertyDescriptor(desc, proxy, %s);\nreturn true;" % readonly
+            templateValues = {'jsvalRef': 'desc->value', 'jsvalPtr': '&desc->value',
+                              'obj': 'proxy', 'successCode': fillDescriptor}
+            namedGet = ("\n" +
+                        "if (!set && JSID_IS_STRING(id) && !HasPropertyOnPrototype(cx, proxy, this, id)) {\n" +
+                        "  JS::Value nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n" +
+                        "  FakeDependentString name;\n"
+                        "  if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" +
+                        "                              eStringify, eStringify, name)) {\n" +
+                        "    return false;\n" +
+                        "  }\n" +
+                        "\n" +
+                        "  %s* self = UnwrapProxy(proxy);\n" +
+                        CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() + "\n" +
+                        "}\n") % (self.descriptor.nativeType)
+        else:
+            namedGet = ""
+
+        return setOrIndexedGet + """JSObject* expando;
+if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) {
+  unsigned flags = (set ? JSRESOLVE_ASSIGNING : 0) | JSRESOLVE_QUALIFIED;
+  if (!JS_GetPropertyDescriptorById(cx, expando, id, flags, desc)) {
+    return false;
+  }
+  if (desc->obj) {
+    // Pretend the property lives on the wrapper.
+    desc->obj = proxy;
+    return true;
+  }
+}
+""" + namedGet + """
+desc->obj = NULL;
+return true;"""
+
+class CGDOMJSProxyHandler_defineProperty(ClassMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
+                Argument('jsid', 'id'),
+                Argument('JSPropertyDescriptor*', 'desc')]
+        ClassMethod.__init__(self, "defineProperty", "bool", args)
+        self.descriptor = descriptor
+    def getBody(self):
+        set = ""
+
+        indexedSetter = self.descriptor.operations['IndexedSetter']
+        if indexedSetter:
+            if not (self.descriptor.operations['IndexedCreator'] is indexedSetter):
+                raise TypeError("Can't handle creator that's different from the setter")
+            set += ("int32_t index = GetArrayIndexFromId(cx, id);\n" +
+                    "if (index >= 0) {\n" +
+                    "  %s* self = UnwrapProxy(proxy);\n" +
+                    CGIndenter(CGProxyIndexedSetter(self.descriptor)).define() +
+                    "  return true;\n" +
+                    "}\n") % (self.descriptor.nativeType)
+        elif self.descriptor.operations['IndexedGetter']:
+            set += ("if (GetArrayIndexFromId(cx, id)) {\n" +
+                    "  return ThrowErrorMessage(cx, MSG_NO_PROPERTY_SETTER, \"%s\");\n" +
+                    "}\n") % self.descriptor.name
+        namedSetter = self.descriptor.operations['NamedSetter']
+        if namedSetter:
+            if not self.descriptor.operations['NamedCreator'] is namedSetter:
+                raise TypeError("Can't handle creator that's different from the setter")
+            set += ("if (JSID_IS_STRING(id)) {\n" +
+                    "  JS::Value nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n" +
+                    "  FakeDependentString name;\n"
+                    "  if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" +
+                    "                              eStringify, eStringify, name)) {\n" +
+                    "    return false;\n" +
+                    "  }\n" +
+                    "\n" +
+                    "  %s* self = UnwrapProxy(proxy);\n" +
+                    CGIndenter(CGProxyNamedSetter(self.descriptor)).define() + "\n" +
+                    "}\n") % (self.descriptor.nativeType)
+        elif self.descriptor.operations['NamedGetter']:
+            set += ("if (JSID_IS_STRING(id)) {\n" +
+                    "  JS::Value nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n" +
+                    "  FakeDependentString name;\n"
+                    "  if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" +
+                    "                              eStringify, eStringify, name)) {\n" +
+                    "    return false;\n" +
+                    "  }\n" +
+                    "  %s* self = UnwrapProxy(proxy);\n" +
+                    CGIndenter(CGProxyNamedGetter(self.descriptor)).define() +
+                    "  if (found) {\n"
+                    "    return ThrowErrorMessage(cx, MSG_NO_PROPERTY_SETTER, \"%s\");\n" +
+                    "  }\n" +
+                    "}\n") % (self.descriptor.nativeType, self.descriptor.name)
+        return set + """return mozilla::dom::DOMProxyHandler::defineProperty(%s);""" % ", ".join(a.name for a in self.args)
+
+class CGDOMJSProxyHandler_getOwnPropertyNames(ClassMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
+                Argument('JS::AutoIdVector&', 'props')]
+        ClassMethod.__init__(self, "getOwnPropertyNames", "bool", args)
+        self.descriptor = descriptor
+    def getBody(self):
+        indexedGetter = self.descriptor.operations['IndexedGetter']
+        if indexedGetter:
+            addIndices = """uint32_t length = UnwrapProxy(proxy)->GetLength();
+MOZ_ASSERT(int32_t(length) >= 0);
+for (int32_t i = 0; i < int32_t(length); ++i) {
+  if (!props.append(INT_TO_JSID(i))) {
+    return false;
+  }
+}
+
+"""
+        else:
+            addIndices = ""
+
+        return addIndices + """JSObject* expando;
+if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = DOMProxyHandler::GetExpandoObject(proxy)) &&
+    !js::GetPropertyNames(cx, expando, JSITER_OWNONLY | JSITER_HIDDEN, &props)) {
+  return false;
+}
+
+// FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=772869 Add named items
+return true;"""
+
+class CGDOMJSProxyHandler_hasOwn(ClassMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
+                Argument('jsid', 'id'), Argument('bool*', 'bp')]
+        ClassMethod.__init__(self, "hasOwn", "bool", args)
+        self.descriptor = descriptor
+    def getBody(self):
+        indexedGetter = self.descriptor.operations['IndexedGetter']
+        if indexedGetter:
+            indexed = ("int32_t index = GetArrayIndexFromId(cx, id);\n" + 
+                       "if (index >= 0) {\n" +
+                       "  %s* self = UnwrapProxy(proxy);\n" +
+                       CGIndenter(CGProxyIndexedGetter(self.descriptor)).define() + "\n" +
+                       "  *bp = found;\n" +
+                       "  return true;\n" +
+                       "}\n\n") % (self.descriptor.nativeType)
+        else:
+            indexed = ""
+
+        namedGetter = self.descriptor.operations['NamedGetter']
+        if namedGetter:
+            named = ("if (JSID_IS_STRING(id) && !HasPropertyOnPrototype(cx, proxy, this, id)) {\n" +
+                     "  jsval nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n" +
+                     "  FakeDependentString name;\n"
+                     "  if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" +
+                     "                              eStringify, eStringify, name)) {\n" +
+                     "    return false;\n" +
+                     "  }\n" +
+                     "\n" +
+                     "  %s* self = UnwrapProxy(proxy);\n" +
+                     CGIndenter(CGProxyNamedGetter(self.descriptor)).define() + "\n" +
+                     "  *bp = found;\n"
+                     "  return true;\n"
+                     "}\n" +
+                     "\n") % (self.descriptor.nativeType)
+        else:
+            named = ""
+
+        return indexed + """JSObject* expando = GetExpandoObject(proxy);
+if (expando) {
+  JSBool b = true;
+  JSBool ok = JS_HasPropertyById(cx, expando, id, &b);
+  *bp = !!b;
+  if (!ok || *bp) {
+    return ok;
+  }
+}
+
+""" + named + """*bp = false;
+return true;"""
+
+class CGDOMJSProxyHandler_get(ClassMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
+                Argument('JSObject*', 'receiver'), Argument('jsid', 'id'),
+                Argument('JS::Value*', 'vp')]
+        ClassMethod.__init__(self, "get", "bool", args)
+        self.descriptor = descriptor
+    def getBody(self):
+        getFromExpando = """JSObject* expando = DOMProxyHandler::GetExpandoObject(proxy);
+if (expando) {
+  JSBool hasProp;
+  if (!JS_HasPropertyById(cx, expando, id, &hasProp)) {
+    return false;
+  }
+
+  if (hasProp) {
+    return JS_GetPropertyById(cx, expando, id, vp);
+  }
+}"""
+
+        templateValues = {'jsvalRef': '*vp', 'jsvalPtr': 'vp', 'obj': 'proxy'}
+
+        indexedGetter = self.descriptor.operations['IndexedGetter']
+        if indexedGetter:
+            getIndexedOrExpando = ("int32_t index = GetArrayIndexFromId(cx, id);\n" +
+                                   "if (index >= 0) {\n" +
+                                   "  %s* self = UnwrapProxy(proxy);\n" +
+                                   CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define()) % (self.descriptor.nativeType)
+            getIndexedOrExpando += """
+  // Even if we don't have this index, we don't forward the
+  // get on to our expando object.
+} else {
+  %s
+}
+""" % (stripTrailingWhitespace(getFromExpando.replace('\n', '\n  ')))
+        else:
+            getIndexedOrExpando = getFromExpando + "\n"
+
+        namedGetter = self.descriptor.operations['NamedGetter']
+        if namedGetter:
+            getNamed = ("if (JSID_IS_STRING(id)) {\n" +
+                        "  JS::Value nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n" +
+                        "  FakeDependentString name;\n"
+                        "  if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" +
+                        "                              eStringify, eStringify, name)) {\n" +
+                        "    return false;\n" +
+                        "  }\n" +
+                        "\n" +
+                        "  %s* self = UnwrapProxy(proxy);\n" +
+                        CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() +
+                        "}\n") % (self.descriptor.nativeType)
+        else:
+            getNamed = ""
+
+        return """MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
+            "Should not have a XrayWrapper here");
+
+%s
+bool found;
+if (!GetPropertyOnPrototype(cx, proxy, id, &found, vp)) {
+  return false;
+}
+
+if (found) {
+  return true;
+}
+%s
+vp->setUndefined();
+return true;""" % (getIndexedOrExpando, getNamed)
+
+class CGDOMJSProxyHandler_obj_toString(ClassMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy')]
+        ClassMethod.__init__(self, "obj_toString", "JSString*", args)
+        self.descriptor = descriptor
+    def getBody(self):
+        stringifier = self.descriptor.operations['Stringifier']
+        if stringifier:
+            name = stringifier.identifier.name
+            nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name))
+            signature = stringifier.signatures()[0]
+            returnType = signature[0]
+            extendedAttributes = self.descriptor.getExtendedAttributes(stringifier)
+            infallible = 'infallible' in extendedAttributes
+            if not infallible:
+                error = ('ThrowMethodFailedWithDetails(cx, rv, "%s", "toString")\n' +
+                         "return NULL;") % self.descriptor.interface.identifier.name
+            else:
+                error = None
+            call = CGCallGenerator(error, [], "", returnType, extendedAttributes, self.descriptor, nativeName, False, object="UnwrapProxy(proxy)")
+            return call.define() + """
+
+JSString* jsresult;
+return xpc_qsStringToJsstring(cx, result, &jsresult) ? jsresult : NULL;""" 
+
+        return "return mozilla::dom::DOMProxyHandler::obj_toString(cx, \"%s\");" % self.descriptor.name
+
+class CGDOMJSProxyHandler_finalize(ClassMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSFreeOp*', 'fop'), Argument('JSObject*', 'proxy')]
+        ClassMethod.__init__(self, "finalize", "void", args)
+        self.descriptor = descriptor
+    def getBody(self):
+        return ("%s self = UnwrapProxy(proxy);\n\n" % (self.descriptor.nativeType + "*") +
+                finalizeHook(self.descriptor, FINALIZE_HOOK_NAME, self.args[0].name))
+
+class CGDOMJSProxyHandler_getElementIfPresent(ClassMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
+                Argument('JSObject*', 'receiver'),
+                Argument('uint32_t', 'index'),
+                Argument('JS::Value*', 'vp'), Argument('bool*', 'present')]
+        ClassMethod.__init__(self, "getElementIfPresent", "bool", args)
+        self.descriptor = descriptor
+    def getBody(self):
+        indexedGetter = self.descriptor.operations['IndexedGetter']
+        if indexedGetter:
+            successCode = """*present = found;
+return true;"""
+            templateValues = {'jsvalRef': '*vp', 'jsvalPtr': 'vp',
+                              'obj': 'proxy', 'successCode': successCode}
+            get = ("%s* self = UnwrapProxy(proxy);\n" +
+                   CGProxyIndexedGetter(self.descriptor, templateValues).define() + "\n"
+                   "// We skip the expando object if there is an indexed getter.\n" +
+                   "\n") % (self.descriptor.nativeType)
+        else:
+            get = """
+
+JSObject* expando = GetExpandoObject(proxy);
+if (expando) {
+  JSBool isPresent;
+  if (!JS_GetElementIfPresent(cx, expando, index, expando, vp, &isPresent)) {
+    return false;
+  }
+  if (isPresent) {
+    *present = true;
+    return true;
+  }
+}
+"""
+
+        return """MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
+             "Should not have a XrayWrapper here");
+
+""" + get + """
+// No need to worry about name getters here, so just check the proto.
+
+JSObject *proto = js::GetObjectProto(proxy);
+if (proto) {
+  JSBool isPresent;
+  if (!JS_GetElementIfPresent(cx, proto, index, proxy, vp, &isPresent)) {
+    return false;
+  }
+  *present = isPresent;
+  return true;
+}
+
+*present = false;
+// Can't Debug_SetValueRangeToCrashOnTouch because it's not public
+return true;"""
+
+class CGDOMJSProxyHandler(CGClass):
+    def __init__(self, descriptor):
+        constructors = [CGDOMJSProxyHandler_CGDOMJSProxyHandler()]
+        methods = [CGDOMJSProxyHandler_getOwnPropertyDescriptor(descriptor)]
+        if descriptor.operations['IndexedSetter'] or descriptor.operations['NamedSetter']:
+            methods.append(CGDOMJSProxyHandler_defineProperty(descriptor))
+        methods.extend([CGDOMJSProxyHandler_getOwnPropertyNames(descriptor),
+                        CGDOMJSProxyHandler_hasOwn(descriptor),
+                        CGDOMJSProxyHandler_get(descriptor),
+                        CGDOMJSProxyHandler_obj_toString(descriptor),
+                        CGDOMJSProxyHandler_finalize(descriptor),
+                        CGDOMJSProxyHandler_getElementIfPresent(descriptor)])
+        CGClass.__init__(self, 'DOMProxyHandler',
+                         bases=[ClassBase('mozilla::dom::DOMProxyHandler')],
+                         members=[ClassMember('instance', 'DOMProxyHandler', visibility='public', static=True)],
+                         constructors=constructors,
+                         methods=methods)
+
 def stripTrailingWhitespace(text):
     lines = text.splitlines()
     for i in range(len(lines)):
         lines[i] = lines[i].rstrip()
     return '\n'.join(lines)
 
 class CGDescriptor(CGThing):
     def __init__(self, descriptor):
         CGThing.__init__(self)
 
         assert not descriptor.concrete or descriptor.interface.hasInterfacePrototypeObject()
 
         cgThings = []
         if descriptor.interface.hasInterfacePrototypeObject():
             hasMethod, hasGetter, hasSetter = False, False, False
             for m in descriptor.interface.members:
-                if m.isMethod() and not m.isStatic():
+                if m.isMethod() and not m.isStatic() and not m.isIdentifierLess():
                     cgThings.append(CGSpecializedMethod(descriptor, m))
                     cgThings.append(CGMemberJITInfo(descriptor, m))
                     hasMethod = True
                 elif m.isAttr():
                     cgThings.append(CGSpecializedGetter(descriptor, m))
                     hasGetter = True
                     if not m.readonly:
                         cgThings.append(CGSpecializedSetter(descriptor, m))
                         hasSetter = True
                     cgThings.append(CGMemberJITInfo(descriptor, m))
             if hasMethod: cgThings.append(CGGenericMethod(descriptor))
             if hasGetter: cgThings.append(CGGenericGetter(descriptor))
             if hasSetter: cgThings.append(CGGenericSetter(descriptor))
 
-
-        if descriptor.concrete:
+        if descriptor.concrete and not descriptor.proxy:
             if not descriptor.workers and descriptor.wrapperCache:
                 cgThings.append(CGAddPropertyHook(descriptor))
 
             # Always have a finalize hook, regardless of whether the class wants a
             # custom hook.
             cgThings.append(CGClassFinalizeHook(descriptor))
 
             # Only generate a trace hook if the class wants a custom hook.
             if (descriptor.customTrace):
                 cgThings.append(CGClassTraceHook(descriptor))
 
-        if descriptor.interface.hasInterfacePrototypeObject():
-            cgThings.append(CGNativePropertyHooks(descriptor))
-        if descriptor.concrete:
-            cgThings.append(CGDOMJSClass(descriptor))
-
         if descriptor.interface.hasInterfaceObject():
             cgThings.append(CGClassConstructHook(descriptor))
             cgThings.append(CGClassHasInstanceHook(descriptor))
             cgThings.append(CGInterfaceObjectJSClass(descriptor))
 
         if descriptor.interface.hasInterfacePrototypeObject():
             cgThings.append(CGPrototypeJSClass(descriptor))
 
         properties = PropertyArrays(descriptor)
         cgThings.append(CGGeneric(define=str(properties)))
         cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties))
         if descriptor.interface.hasInterfacePrototypeObject():
-            cgThings.append(CGIndenter(CGGetProtoObjectMethod(descriptor)))
+            cgThings.append(CGGetProtoObjectMethod(descriptor))
         else:
-            cgThings.append(CGIndenter(CGGetConstructorObjectMethod(descriptor)))
+            cgThings.append(CGGetConstructorObjectMethod(descriptor))
 
         # Set up our Xray callbacks as needed.  Note that we don't need to do
         # it in workers.
         if (descriptor.interface.hasInterfacePrototypeObject() and
             not descriptor.workers):
             cgThings.append(CGResolveProperty(descriptor, properties))
             cgThings.append(CGEnumerateProperties(descriptor, properties))
 
         if descriptor.interface.hasInterfaceObject():
             cgThings.append(CGDefineDOMInterfaceMethod(descriptor))
 
+        if descriptor.interface.hasInterfacePrototypeObject():
+            cgThings.append(CGNativePropertyHooks(descriptor))
+
         if descriptor.concrete:
+            if descriptor.proxy:
+                cgThings.append(CGProxyIsProxy(descriptor))
+                cgThings.append(CGProxyUnwrap(descriptor))
+                cgThings.append(CGDOMJSProxyHandlerDOMClass(descriptor))
+                cgThings.append(CGDOMJSProxyHandler(descriptor))
+                cgThings.append(CGIsMethod(descriptor))
+            else:
+                cgThings.append(CGDOMJSClass(descriptor))
+
             if descriptor.wrapperCache:
+                cgThings.append(CGWrapWithCacheMethod(descriptor))
                 cgThings.append(CGWrapMethod(descriptor))
             else:
                 cgThings.append(CGWrapNonWrapperCacheMethod(descriptor))
 
-        cgThings = CGList(cgThings)
-        cgThings = CGWrapper(cgThings, post='\n')
+        cgThings = CGList((CGIndenter(t, declareOnly=True) for t in cgThings), "\n")
+        cgThings = CGWrapper(cgThings, pre='\n', post='\n')
         self.cgRoot = CGWrapper(CGNamespace(toBindingNamespace(descriptor.name),
                                             cgThings),
                                 post='\n')
 
     def declare(self):
         return self.cgRoot.declare()
     def define(self):
         return self.cgRoot.define()
@@ -4607,17 +5327,18 @@ class CGBindingRoot(CGThing):
                                  defineOnly=True),
                        traitsClasses, curr],
                       "\n")
 
         # Add header includes.
         curr = CGHeaders(descriptors,
                          dictionaries,
                          ['mozilla/dom/BindingUtils.h',
-                          'mozilla/dom/DOMJSClass.h'],
+                          'mozilla/dom/DOMJSClass.h',
+                          'mozilla/dom/DOMJSProxyHandler.h'],
                          ['mozilla/dom/Nullable.h',
                           'PrimitiveConversions.h',
                           'XPCQuickStubs.h',
                           'nsDOMQS.h',
                           'AccessCheck.h',
                           'WorkerPrivate.h',
                           'nsContentUtils.h',
                           'mozilla/Preferences.h',
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -142,23 +142,73 @@ class Descriptor(DescriptorProvider):
         else:
             self.castable = desc.get('castable', True)
 
         self.notflattened = desc.get('notflattened', False)
         self.register = desc.get('register', True)
 
         # If we're concrete, we need to crawl our ancestor interfaces and mark
         # them as having a concrete descendant.
-        self.concrete = desc.get('concrete', True)
+        self.concrete = desc.get('concrete', not self.interface.isExternal())
         if self.concrete:
+            self.proxy = False
+            operations = {
+                'IndexedGetter': None,
+                'IndexedSetter': None,
+                'IndexedCreator': None,
+                'IndexedDeleter': None,
+                'NamedGetter': None,
+                'NamedSetter': None,
+                'NamedCreator': None,
+                'NamedDeleter': None,
+                'Stringifier': None
+            }
             iface = self.interface
             while iface:
+                for m in iface.members:
+                    if not m.isMethod():
+                        continue
+
+                    def addOperation(operation, m):
+                        if not operations[operation]:
+                            operations[operation] = m
+                    def addIndexedOrNamedOperation(operation, m):
+                        self.proxy = True
+                        if m.isIndexed():
+                            operation = 'Indexed' + operation
+                        else:
+                            assert m.isNamed()
+                            operation = 'Named' + operation
+                        addOperation(operation, m)
+                        
+                    if m.isStringifier():
+                        addOperation('Stringifier', m)
+                    else:
+                        if m.isGetter():
+                            addIndexedOrNamedOperation('Getter', m)
+                        if m.isSetter():
+                            addIndexedOrNamedOperation('Setter', m)
+                        if m.isCreator():
+                            addIndexedOrNamedOperation('Creator', m)
+                        if m.isDeleter():
+                            addIndexedOrNamedOperation('Deleter', m)
+                            raise TypeError("deleter specified on %s but we "
+                                            "don't support deleters yet" %
+                                            self.interface.identifier.name)
+
                 iface.setUserData('hasConcreteDescendant', True)
                 iface = iface.parent
 
+            if self.proxy:
+                self.operations = operations
+                iface = self.interface
+                while iface:
+                    iface.setUserData('hasProxyDescendant', True)
+                    iface = iface.parent
+
         if self.interface.isExternal() and 'prefable' in desc:
             raise TypeError("%s is external but has a prefable setting" %
                             self.interface.identifier.name)
         self.prefable = desc.get('prefable', False)
 
         self.nativeIsISupports = not self.workers
         self.customTrace = desc.get('customTrace', self.workers)
         self.customFinalize = desc.get('customFinalize', self.workers)
@@ -183,18 +233,24 @@ class Descriptor(DescriptorProvider):
                     self.extendedAttributes[key].setdefault(member, []).append(attribute)
 
             if isinstance(config, dict):
                 for key in ['all', 'getterOnly', 'setterOnly']:
                     add(key, config.get(key, []), attribute)
             elif isinstance(config, list):
                 add('all', config, attribute)
             else:
-                assert isinstance(config, string)
-                add('all', [config], attribute)
+                assert isinstance(config, str)
+                if config == '*':
+                    iface = self.interface
+                    while iface:
+                        add('all', map(lambda m: m.name, iface.members), attribute)
+                        iface = iface.parent
+                else:
+                    add('all', [config], attribute)
 
         for attribute in ['infallible', 'implicitJSContext', 'resultNotAddRefed']:
             addExtendedAttribute(attribute, desc.get(attribute, {}))
 
         self.binaryNames = desc.get('binaryNames', {})
 
         # Build the prototype chain.
         self.prototypeChain = []
--- a/dom/bindings/DOMJSClass.h
+++ b/dom/bindings/DOMJSClass.h
@@ -40,41 +40,47 @@ typedef bool
 struct NativePropertyHooks
 {
   ResolveProperty mResolveProperty;
   EnumerateProperties mEnumerateProperties;
 
   const NativePropertyHooks *mProtoHooks;
 };
 
+struct DOMClass
+{
+  // A list of interfaces that this object implements, in order of decreasing
+  // derivedness.
+  const prototypes::ID mInterfaceChain[prototypes::id::_ID_Count];
+
+  // We store the DOM object in reserved slot with index DOM_OBJECT_SLOT or in
+  // the proxy private if we use a proxy object.
+  // Sometimes it's an nsISupports and sometimes it's not; this class tells
+  // us which it is.
+  const bool mDOMObjectIsISupports;
+
+  const NativePropertyHooks* mNativeHooks;
+};
+
 // Special JSClass for reflected DOM objects.
 struct DOMJSClass
 {
   // It would be nice to just inherit from JSClass, but that precludes pure
   // compile-time initialization of the form |DOMJSClass = {...};|, since C++
   // only allows brace initialization for aggregate/POD types.
   JSClass mBase;
 
-  // A list of interfaces that this object implements, in order of decreasing
-  // derivedness.
-  const prototypes::ID mInterfaceChain[prototypes::id::_ID_Count];
+  DOMClass mClass;
 
   // We cache the VTable index of GetWrapperCache for objects that support it.
   //
   // -1 indicates that GetWrapperCache is not implemented on the underlying object.
   // XXXkhuey this is unused and needs to die.
   const int16_t mGetWrapperCacheVTableOffset;
 
-  // We store the DOM object in a reserved slot whose index is mNativeSlot.
-  // Sometimes it's an nsISupports and sometimes it's not; this class tells
-  // us which it is.
-  const bool mDOMObjectIsISupports;
-
-  const NativePropertyHooks* mNativeHooks;
-
   static DOMJSClass* FromJSClass(JSClass* base) {
     MOZ_ASSERT(base->flags & JSCLASS_IS_DOMJSCLASS);
     return reinterpret_cast<DOMJSClass*>(base);
   }
   static const DOMJSClass* FromJSClass(const JSClass* base) {
     MOZ_ASSERT(base->flags & JSCLASS_IS_DOMJSCLASS);
     return reinterpret_cast<const DOMJSClass*>(base);
   }
new file mode 100644
--- /dev/null
+++ b/dom/bindings/DOMJSProxyHandler.cpp
@@ -0,0 +1,228 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=2 sw=2 et tw=99 ft=cpp: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/Util.h"
+
+#include "DOMJSProxyHandler.h"
+#include "xpcpublic.h"
+#include "xpcprivate.h"
+#include "XPCQuickStubs.h"
+#include "XPCWrapper.h"
+#include "WrapperFactory.h"
+#include "nsDOMClassInfo.h"
+#include "nsGlobalWindow.h"
+#include "nsWrapperCacheInlines.h"
+#include "mozilla/dom/BindingUtils.h"
+
+#include "jsapi.h"
+#include "jsatom.h"
+
+using namespace JS;
+
+namespace mozilla {
+namespace dom {
+
+jsid s_length_id = JSID_VOID;
+
+bool
+DefineStaticJSVals(JSContext* cx)
+{
+  JSAutoRequest ar(cx);
+
+  return InternJSString(cx, s_length_id, "length");
+}
+
+
+int HandlerFamily;
+
+bool
+DefineConstructor(JSContext* cx, JSObject* obj, DefineInterface aDefine, nsresult* aResult)
+{
+  bool enabled;
+  bool defined = aDefine(cx, obj, &enabled);
+  MOZ_ASSERT(!defined || enabled,
+             "We defined a constructor but the new bindings are disabled?");
+  *aResult = defined ? NS_OK : NS_ERROR_FAILURE;
+  return enabled;
+}
+
+// static
+JSObject*
+DOMProxyHandler::EnsureExpandoObject(JSContext* cx, JSObject* obj)
+{
+  NS_ASSERTION(IsDOMProxy(obj), "expected a DOM proxy object");
+  JSObject* expando = GetExpandoObject(obj);
+  if (!expando) {
+    expando = JS_NewObjectWithGivenProto(cx, nullptr, nullptr,
+                                         js::GetObjectParent(obj));
+    if (!expando) {
+      return NULL;
+    }
+
+    xpc::CompartmentPrivate* priv = xpc::GetCompartmentPrivate(obj);
+    if (!priv->RegisterDOMExpandoObject(obj)) {
+      return NULL;
+    }
+
+    nsWrapperCache* cache;
+    CallQueryInterface(UnwrapDOMObject<nsISupports>(obj, eProxyDOMObject), &cache);
+    cache->SetPreservingWrapper(true);
+
+    js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, ObjectValue(*expando));
+  }
+  return expando;
+}
+
+bool
+DOMProxyHandler::getPropertyDescriptor(JSContext* cx, JSObject* proxy, jsid id, bool set,
+                                       JSPropertyDescriptor* desc)
+{
+  if (!getOwnPropertyDescriptor(cx, proxy, id, set, desc)) {
+    return false;
+  }
+  if (desc->obj) {
+    return true;
+  }
+
+  JSObject* proto = js::GetObjectProto(proxy);
+  if (!proto) {
+    desc->obj = NULL;
+    return true;
+  }
+
+  return JS_GetPropertyDescriptorById(cx, proto, id, JSRESOLVE_QUALIFIED, desc);
+}
+
+bool
+DOMProxyHandler::defineProperty(JSContext* cx, JSObject* proxy, jsid id,
+                                JSPropertyDescriptor* desc)
+{
+  if ((desc->attrs & JSPROP_GETTER) && desc->setter == JS_StrictPropertyStub) {
+    return JS_ReportErrorFlagsAndNumber(cx,
+                                        JSREPORT_WARNING | JSREPORT_STRICT |
+                                        JSREPORT_STRICT_MODE_ERROR,
+                                        js_GetErrorMessage, NULL,
+                                        JSMSG_GETTER_ONLY);
+  }
+
+  if (xpc::WrapperFactory::IsXrayWrapper(proxy)) {
+    return true;
+  }
+
+  JSObject* expando = EnsureExpandoObject(cx, proxy);
+  if (!expando) {
+    return false;
+  }
+
+  return JS_DefinePropertyById(cx, expando, id, desc->value, desc->getter, desc->setter,
+                               desc->attrs);
+}
+
+bool
+DOMProxyHandler::delete_(JSContext* cx, JSObject* proxy, jsid id, bool* bp)
+{
+  JSBool b = true;
+
+  JSObject* expando;
+  if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) {
+    Value v;
+    if (!JS_DeletePropertyById2(cx, expando, id, &v) || !JS_ValueToBoolean(cx, v, &b)) {
+      return false;
+    }
+  }
+
+  *bp = !!b;
+  return true;
+}
+
+bool
+DOMProxyHandler::enumerate(JSContext* cx, JSObject* proxy, AutoIdVector& props)
+{
+  JSObject* proto = JS_GetPrototype(proxy);
+  return getOwnPropertyNames(cx, proxy, props) &&
+         (!proto || js::GetPropertyNames(cx, proto, 0, &props));
+}
+
+bool
+DOMProxyHandler::fix(JSContext* cx, JSObject* proxy, Value* vp)
+{
+  vp->setUndefined();
+  return true;
+}
+
+bool
+DOMProxyHandler::has(JSContext* cx, JSObject* proxy, jsid id, bool* bp)
+{
+  if (!hasOwn(cx, proxy, id, bp)) {
+    return false;
+  }
+
+  if (*bp) {
+    // We have the property ourselves; no need to worry about our prototype
+    // chain.
+    return true;
+  }
+
+  // OK, now we have to look at the proto
+  JSObject *proto = js::GetObjectProto(proxy);
+  if (!proto) {
+    return true;
+  }
+  JSBool protoHasProp;
+  bool ok = JS_HasPropertyById(cx, proto, id, &protoHasProp);
+  if (ok) {
+    *bp = protoHasProp;
+  }
+  return ok;
+}
+
+// static
+JSString*
+DOMProxyHandler::obj_toString(JSContext* cx, const char* className)
+{
+  size_t nchars = sizeof("[object ]") - 1 + strlen(className);
+  jschar* chars = static_cast<jschar*>(JS_malloc(cx, (nchars + 1) * sizeof(jschar)));
+  if (!chars) {
+    return NULL;
+  }
+
+  const char* prefix = "[object ";
+  nchars = 0;
+  while ((chars[nchars] = (jschar)*prefix) != 0) {
+    nchars++, prefix++;
+  }
+  while ((chars[nchars] = (jschar)*className) != 0) {
+    nchars++, className++;
+  }
+  chars[nchars++] = ']';
+  chars[nchars] = 0;
+
+  JSString* str = JS_NewUCString(cx, chars, nchars);
+  if (!str) {
+    JS_free(cx, chars);
+  }
+  return str;
+}
+
+int32_t
+IdToInt32(JSContext* cx, jsid id)
+{
+  JSAutoRequest ar(cx);
+
+  jsval idval;
+  double array_index;
+  int32_t i;
+  if (!::JS_IdToValue(cx, id, &idval) ||
+      !::JS_ValueToNumber(cx, idval, &array_index) ||
+      !::JS_DoubleIsInt32(array_index, &i)) {
+    return -1;
+  }
+
+  return i;
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/bindings/DOMJSProxyHandler.h
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_DOMJSProxyHandler_h
+#define mozilla_dom_DOMJSProxyHandler_h
+
+#include "jsapi.h"
+#include "jsatom.h"
+#include "jsproxy.h"
+#include "xpcpublic.h"
+#include "nsString.h"
+#include "mozilla/Likely.h"
+
+#define DOM_PROXY_OBJECT_SLOT js::JSSLOT_PROXY_PRIVATE
+
+namespace mozilla {
+namespace dom {
+
+enum {
+  JSPROXYSLOT_EXPANDO = 0
+};
+
+template<typename T> struct Prefable;
+
+class DOMProxyHandler : public js::BaseProxyHandler
+{
+public:
+  DOMProxyHandler(const DOMClass& aClass)
+    : js::BaseProxyHandler(ProxyFamily()),
+      mClass(aClass)
+  {
+  }
+
+  bool getPropertyDescriptor(JSContext* cx, JSObject* proxy, jsid id, bool set,
+                             JSPropertyDescriptor* desc);
+  bool defineProperty(JSContext* cx, JSObject* proxy, jsid id,
+                      JSPropertyDescriptor* desc);
+  bool delete_(JSContext* cx, JSObject* proxy, jsid id, bool* bp);
+  bool enumerate(JSContext* cx, JSObject* proxy, JS::AutoIdVector& props);
+  bool fix(JSContext* cx, JSObject* proxy, JS::Value* vp);
+  bool has(JSContext* cx, JSObject* proxy, jsid id, bool* bp);
+  using js::BaseProxyHandler::obj_toString;
+
+  static JSObject* GetExpandoObject(JSObject* obj)
+  {
+    MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object");
+    JS::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO);
+    return v.isUndefined() ? NULL : v.toObjectOrNull();
+  }
+  static JSObject* EnsureExpandoObject(JSContext* cx, JSObject* obj);
+
+  const DOMClass& mClass;
+
+protected:
+  static JSString* obj_toString(JSContext* cx, const char* className);
+};
+
+extern jsid s_length_id;
+
+int32_t IdToInt32(JSContext* cx, jsid id);
+
+inline int32_t
+GetArrayIndexFromId(JSContext* cx, jsid id)
+{
+  if (MOZ_LIKELY(JSID_IS_INT(id))) {
+    return JSID_TO_INT(id);
+  }
+  if (MOZ_LIKELY(id == s_length_id)) {
+    return -1;
+  }
+  if (MOZ_LIKELY(JSID_IS_ATOM(id))) {
+    JSAtom* atom = JSID_TO_ATOM(id);
+    jschar s = *js::GetAtomChars(atom);
+    if (MOZ_LIKELY((unsigned)s >= 'a' && (unsigned)s <= 'z'))
+      return -1;
+
+    uint32_t i;
+    JSLinearString* str = js::AtomToLinearString(JSID_TO_ATOM(id));
+    return js::StringIsArrayIndex(str, &i) ? i : -1;
+  }
+  return IdToInt32(cx, id);
+}
+
+inline void
+FillPropertyDescriptor(JSPropertyDescriptor* desc, JSObject* obj, bool readonly)
+{
+  desc->obj = obj;
+  desc->attrs = (readonly ? JSPROP_READONLY : 0) | JSPROP_ENUMERATE;
+  desc->getter = NULL;
+  desc->setter = NULL;
+  desc->shortid = 0;
+}
+
+inline void
+FillPropertyDescriptor(JSPropertyDescriptor* desc, JSObject* obj, jsval v, bool readonly)
+{
+  desc->value = v;
+  FillPropertyDescriptor(desc, obj, readonly);
+}
+
+JSObject* 
+EnsureExpandoObject(JSContext* cx, JSObject* obj);
+
+} // namespace dom
+} // namespace mozilla
+
+#endif /* mozilla_dom_DOMProxyHandler_h */
--- a/dom/bindings/Errors.msg
+++ b/dom/bindings/Errors.msg
@@ -20,8 +20,9 @@
  */
 
 MSG_DEF(MSG_INVALID_ENUM_VALUE, 2, "Value '{0}' is not a valid value for enumeration {1}.")
 MSG_DEF(MSG_MISSING_ARGUMENTS, 1, "Not enough arguments to {0}.")
 MSG_DEF(MSG_NOT_OBJECT, 0, "Value not an object.")
 MSG_DEF(MSG_DOES_NOT_IMPLEMENT_INTERFACE, 1, "Value does not implement interface {0}.")
 MSG_DEF(MSG_NOT_IN_UNION, 1, "Value could not be converted to any of: {0}.")
 MSG_DEF(MSG_ILLEGAL_CONSTRUCTOR, 0, "Illegal constructor.")
+MSG_DEF(MSG_NO_PROPERTY_SETTER, 1, "{0} doesn't have an indexed property setter.")
\ No newline at end of file
--- a/dom/bindings/Makefile.in
+++ b/dom/bindings/Makefile.in
@@ -40,27 +40,29 @@ globalgen_targets := \
   UnionTypes.h \
   UnionConversions.h \
   $(NULL)
 
 CPPSRCS = \
   $(linked_binding_cpp_files) \
   $(filter %.cpp, $(globalgen_targets)) \
   BindingUtils.cpp \
+  DOMJSProxyHandler.cpp \
   $(NULL)
 
 EXPORTS_NAMESPACES = $(binding_include_path) mozilla
 
 EXPORTS_mozilla = \
   ErrorResult.h \
   $(NULL)
 
 EXPORTS_$(binding_include_path) = \
   BindingUtils.h \
   DOMJSClass.h \
+  DOMJSProxyHandler.h \
   Errors.msg \
   Nullable.h \
   PrimitiveConversions.h \
   PrototypeList.h \
   RegisterBindings.h \
   TypedArray.h \
   UnionConversions.h \
   UnionTypes.h \
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -2128,16 +2128,19 @@ class IDLMethod(IDLInterfaceMember, IDLS
         return self._legacycaller
 
     def isStringifier(self):
         return self._stringifier
 
     def hasOverloads(self):
         return self._hasOverloads
 
+    def isIdentifierLess(self):
+        return self.identifier.name[:2] == "__"
+
     def resolve(self, parentScope):
         assert isinstance(parentScope, IDLScope)
         IDLObjectWithIdentifier.resolve(self, parentScope)
         IDLScope.__init__(self, self.location, parentScope, self.identifier)
         for (returnType, arguments) in self.signatures():
             for argument in arguments:
                 argument.resolve(self)
 
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -553,12 +553,108 @@ private:
   void PassNullableString(nsAString&, ErrorResult&) MOZ_DELETE;
   void PassOptionalString(Optional<nsAString>&, ErrorResult&) MOZ_DELETE;
   void PassOptionalStringWithDefaultValue(nsAString&, ErrorResult&) MOZ_DELETE;
   void PassOptionalNullableString(Optional<nsAString>&, ErrorResult&) MOZ_DELETE;
   void PassOptionalNullableStringWithDefaultValue(nsAString&, ErrorResult&) MOZ_DELETE;
 
 };
 
+class TestIndexedGetterInterface : public nsISupports,
+                                   public nsWrapperCache
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  // We need a GetParentObject to make binding codegen happy
+  virtual nsISupports* GetParentObject();
+
+  uint32_t IndexedGetter(uint32_t, bool&, ErrorResult&);
+  uint32_t IndexedGetter(uint32_t, ErrorResult&) MOZ_DELETE;
+  uint32_t Item(uint32_t, ErrorResult&);
+  uint32_t Item(uint32_t, bool&, ErrorResult&) MOZ_DELETE;
+  uint32_t GetLength();
+};
+
+class TestNamedGetterInterface : public nsISupports,
+                                 public nsWrapperCache
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  // We need a GetParentObject to make binding codegen happy
+  virtual nsISupports* GetParentObject();
+
+  void NamedGetter(const nsAString&, bool&, nsAString&, ErrorResult&);
+};
+
+class TestIndexedAndNamedGetterInterface : public nsISupports,
+                                           public nsWrapperCache
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  // We need a GetParentObject to make binding codegen happy
+  virtual nsISupports* GetParentObject();
+
+  uint32_t IndexedGetter(uint32_t, bool&, ErrorResult&);
+  void NamedGetter(const nsAString&, bool&, nsAString&, ErrorResult&);
+  void NamedItem(const nsAString&, nsAString&, ErrorResult&);
+  uint32_t GetLength();
+};
+
+class TestIndexedSetterInterface : public nsISupports,
+                                   public nsWrapperCache
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  // We need a GetParentObject to make binding codegen happy
+  virtual nsISupports* GetParentObject();
+
+  void IndexedSetter(uint32_t, const nsAString&, ErrorResult&);
+  void SetItem(uint32_t, const nsAString&, ErrorResult&);
+};
+
+class TestNamedSetterInterface : public nsISupports,
+                                 public nsWrapperCache
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  // We need a GetParentObject to make binding codegen happy
+  virtual nsISupports* GetParentObject();
+
+  void NamedSetter(const nsAString&, TestIndexedSetterInterface&, ErrorResult&);
+};
+
+class TestIndexedAndNamedSetterInterface : public nsISupports,
+                                           public nsWrapperCache
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  // We need a GetParentObject to make binding codegen happy
+  virtual nsISupports* GetParentObject();
+
+  void IndexedSetter(uint32_t, TestIndexedSetterInterface&, ErrorResult&);
+  void NamedSetter(const nsAString&, TestIndexedSetterInterface&, ErrorResult&);
+  void SetNamedItem(const nsAString&, TestIndexedSetterInterface&, ErrorResult&);
+};
+
+class TestIndexedAndNamedGetterAndSetterInterface : public TestIndexedSetterInterface
+{
+public:
+  uint32_t IndexedGetter(uint32_t, bool&, ErrorResult&);
+  uint32_t Item(uint32_t, ErrorResult&);
+  void NamedGetter(const nsAString&, bool&, nsAString&, ErrorResult&);
+  void NamedItem(const nsAString&, nsAString&, ErrorResult&);
+  void IndexedSetter(uint32_t, int32_t&, ErrorResult&);
+  void IndexedSetter(uint32_t, const nsAString&, ErrorResult&) MOZ_DELETE;
+  void NamedSetter(const nsAString&, const nsAString&, ErrorResult&);
+  void Stringify(nsAString&);
+  uint32_t GetLength();
+};
+
 } // namespace dom
 } // namespace mozilla
 
 #endif /* TestBindingHeader_h */
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -367,8 +367,45 @@ dictionary ParentDict : GrandparentDict 
   long c = 5;
   TestInterface someInterface;
   TestExternalInterface someExternalInterface;
 };
 
 dictionary DictContainingDict {
   Dict memberDict;
 };
+
+interface TestIndexedGetterInterface {
+  getter long item(unsigned long index);
+  readonly attribute unsigned long length;
+};
+
+interface TestNamedGetterInterface {
+  getter DOMString (DOMString name);
+};
+
+interface TestIndexedAndNamedGetterInterface {
+  getter long (unsigned long index);
+  getter DOMString namedItem(DOMString name);
+  readonly attribute unsigned long length;
+};
+
+interface TestIndexedSetterInterface {
+  setter creator void setItem(unsigned long index, DOMString item);
+};
+
+interface TestNamedSetterInterface {
+  setter creator void (DOMString name, TestIndexedSetterInterface item);
+};
+
+interface TestIndexedAndNamedSetterInterface {
+  setter creator void (unsigned long index, TestIndexedSetterInterface item);
+  setter creator void setNamedItem(DOMString name, TestIndexedSetterInterface item);
+};
+
+interface TestIndexedAndNamedGetterAndSetterInterface : TestIndexedSetterInterface {
+  getter long item(unsigned long index);
+  getter DOMString namedItem(DOMString name);
+  setter creator void (unsigned long index, long item);
+  setter creator void (DOMString name, DOMString item);
+  stringifier DOMString ();
+  readonly attribute unsigned long length;
+};
--- a/dom/bluetooth/BluetoothDevice.cpp
+++ b/dom/bluetooth/BluetoothDevice.cpp
@@ -25,23 +25,27 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(Bluetooth
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(BluetoothDevice,
                                                nsDOMEventTargetHelper)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mJsUuids)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothDevice, 
                                                   nsDOMEventTargetHelper)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
-  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(propertychanged)  
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(propertychanged)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(connected)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(disconnected)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothDevice, 
                                                 nsDOMEventTargetHelper)
   tmp->Unroot();
-  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(propertychanged)  
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(propertychanged)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(connected)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(disconnected)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothDevice)
   NS_INTERFACE_MAP_ENTRY(nsIDOMBluetoothDevice)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothDevice)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(BluetoothDevice, nsDOMEventTargetHelper)
@@ -165,19 +169,39 @@ BluetoothDevice::Create(nsPIDOMWindow* a
 
 void
 BluetoothDevice::Notify(const BluetoothSignal& aData)
 {
   if (aData.name().EqualsLiteral("PropertyChanged")) {
     // Get BluetoothNamedValue, make sure array length is 1
     BluetoothNamedValue v = aData.value().get_ArrayOfBluetoothNamedValue()[0];
     nsString name = v.name();
-    SetPropertyByValue(v);
-    nsRefPtr<BluetoothPropertyEvent> e = BluetoothPropertyEvent::Create(name);
-    e->Dispatch(ToIDOMEventTarget(), NS_LITERAL_STRING("propertychanged"));
+
+    if (name.EqualsLiteral("Connected")) {
+      bool isConnected = v.value();
+      nsRefPtr<nsDOMEvent> event = new nsDOMEvent(nullptr, nullptr);
+      nsresult rv;
+      if (isConnected) {
+        rv = event->InitEvent(NS_LITERAL_STRING("connected"), false, false);
+      } else {
+        rv = event->InitEvent(NS_LITERAL_STRING("disconnected"), false, false);
+      }
+      if (NS_FAILED(rv)) {
+        NS_WARNING("Failed to init the connected/disconnected event!!!");
+        return;
+      }
+
+      event->SetTrusted(true);
+      bool dummy;
+      DispatchEvent(event, &dummy);
+    } else {
+      SetPropertyByValue(v);
+      nsRefPtr<BluetoothPropertyEvent> e = BluetoothPropertyEvent::Create(name);
+      e->Dispatch(ToIDOMEventTarget(), NS_LITERAL_STRING("propertychanged"));
+    }
   } else {
 #ifdef DEBUG
     nsCString warningMsg;
     warningMsg.AssignLiteral("Not handling device signal: ");
     warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
     NS_WARNING(warningMsg.get());
 #endif
   }
@@ -226,8 +250,10 @@ BluetoothDevice::GetUuids(JSContext* aCx
   } else {
     NS_WARNING("UUIDs not yet set!\n");
     return NS_ERROR_FAILURE;
   }    
   return NS_OK;
 }
 
 NS_IMPL_EVENT_HANDLER(BluetoothDevice, propertychanged)
+NS_IMPL_EVENT_HANDLER(BluetoothDevice, connected)
+NS_IMPL_EVENT_HANDLER(BluetoothDevice, disconnected)
--- a/dom/bluetooth/BluetoothDevice.h
+++ b/dom/bluetooth/BluetoothDevice.h
@@ -70,13 +70,15 @@ private:
   nsString mName;
   uint32_t mClass;
   bool mConnected;
   bool mPaired;
   bool mIsRooted;
   nsTArray<nsString> mUuids;
 
   NS_DECL_EVENT_HANDLER(propertychanged)
+  NS_DECL_EVENT_HANDLER(connected)
+  NS_DECL_EVENT_HANDLER(disconnected)
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
--- a/dom/bluetooth/nsIDOMBluetoothDevice.idl
+++ b/dom/bluetooth/nsIDOMBluetoothDevice.idl
@@ -1,19 +1,21 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIDOMEventTarget.idl"
 
-[scriptable, builtinclass, uuid(24c64513-9587-46c6-b718-bb9b9a754b0d)]
+[scriptable, builtinclass, uuid(647bb64c-8d45-4642-b86b-b3b80d4c8c25)]
 interface nsIDOMBluetoothDevice : nsIDOMEventTarget
 {
   readonly attribute DOMString address;
   readonly attribute DOMString name;
   [binaryname(DeviceClass)] readonly attribute unsigned long class;
   [implicit_jscontext] readonly attribute jsval uuids;
   readonly attribute bool connected;
   readonly attribute bool paired;
   attribute nsIDOMEventListener onpropertychanged;
+  attribute nsIDOMEventListener onconnected;
+  attribute nsIDOMEventListener ondisconnected;
 };
--- a/dom/browser-element/BrowserElementParent.cpp
+++ b/dom/browser-element/BrowserElementParent.cpp
@@ -12,16 +12,17 @@
 #undef CreateEvent
 #endif
 
 #include "BrowserElementParent.h"
 #include "nsHTMLIFrameElement.h"
 #include "nsOpenWindowEventDetail.h"
 #include "nsEventDispatcher.h"
 #include "nsIDOMCustomEvent.h"
+#include "nsIInterfaceRequestorUtils.h"
 #include "nsVariant.h"
 
 using mozilla::dom::Element;
 using mozilla::dom::TabParent;
 
 namespace {
 
 /**
--- a/dom/browser-element/BrowserElementScrolling.js
+++ b/dom/browser-element/BrowserElementScrolling.js
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const ContentPanning = {
   init: function cp_init() {
     ['mousedown', 'mouseup', 'mousemove'].forEach(function(type) {
-      addEventListener(type, ContentPanning, true);
+      addEventListener(type, ContentPanning, false);
     });
 
     addMessageListener("Viewport:Change", this._recvViewportChange.bind(this));
     addMessageListener("Gesture:DoubleTap", this._recvDoubleTap.bind(this));
   },
 
   handleEvent: function cp_handleEvent(evt) {
     switch (evt.type) {
@@ -25,17 +25,17 @@ const ContentPanning = {
         break;
       case 'click':
         evt.stopPropagation();
         evt.preventDefault();
         
         let target = evt.target;
         let view = target.ownerDocument ? target.ownerDocument.defaultView
                                         : target;
-        view.removeEventListener('click', this, true, true);
+        view.removeEventListener('click', this, false, true);
         break;
     }
   },
 
   position: new Point(0 , 0),
 
   onTouchStart: function cp_onTouchStart(evt) {
     this.dragging = true;
@@ -78,17 +78,17 @@ const ContentPanning = {
 
     this.onTouchMove(evt);
 
     let click = evt.detail;
     if (this.target && click && (this.panning || this.preventNextClick)) {
       let target = this.target;
       let view = target.ownerDocument ? target.ownerDocument.defaultView
                                       : target;
-      view.addEventListener('click', this, true, true);
+      view.addEventListener('click', this, false, true);
     }
 
     if (this.panning)
       KineticPanning.start(this);
   },
 
   onTouchMove: function cp_onTouchMove(evt) {
     if (!this.dragging || !this.scrollCallback)
@@ -102,16 +102,18 @@ const ContentPanning = {
     this.scrollCallback(delta.scale(-1));
 
     // If a pan action happens, cancel the active state of the
     // current target.
     if (!this.panning && KineticPanning.isPan()) {
       this.panning = true;
       this._resetActive();
     }
+    evt.stopPropagation();
+    evt.preventDefault();
   },
 
 
   onKineticBegin: function cp_onKineticBegin(evt) {
   },
 
   onKineticPan: function cp_onKineticPan(delta) {
     return !this.scrollCallback(delta);
--- a/dom/contacts/ContactManager.js
+++ b/dom/contacts/ContactManager.js
@@ -543,17 +543,17 @@ ContactManager.prototype = {
     let request;
     request = this.createRequest();
 
     let allowCallback = function() {
       let callback = function(aType, aContacts) {
         if (DEBUG) debug("got SIM contacts: " + aType + " " + JSON.stringify(aContacts));
         let result = aContacts.map(function(c) {
           var contact = new Contact();
-          contact.init( { name: [c.alphaId], tel: [ { number: c.number } ] } );
+          contact.init( { name: [c.alphaId], tel: [ { value: c.number } ] } );
           return contact;
         });
         if (DEBUG) debug("result: " + JSON.stringify(result));
         Services.DOMRequest.fireSuccess(request, result);
       };
       if (DEBUG) debug("getSimContacts " + aType);
 
       mRIL.getICCContacts(aType, callback);
--- a/dom/indexedDB/ipc/IndexedDBChild.cpp
+++ b/dom/indexedDB/ipc/IndexedDBChild.cpp
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/basictypes.h"
 
 #include "IndexedDBChild.h"
 
 #include "nsIAtom.h"
+#include "nsIInputStream.h"
 
 #include "mozilla/Assertions.h"
 #include "mozilla/dom/ContentChild.h"
 
 #include "AsyncConnectionHelper.h"
 #include "DatabaseInfo.h"
 #include "IDBEvents.h"
 #include "IDBFactory.h"
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -89,16 +89,17 @@
 
 #include "mozilla/dom/indexedDB/PIndexedDBChild.h"
 #include "mozilla/dom/sms/SmsChild.h"
 #include "mozilla/dom/devicestorage/DeviceStorageRequestChild.h"
 
 #include "nsDOMFile.h"
 #include "nsIRemoteBlob.h"
 #include "StructuredCloneUtils.h"
+#include "URIUtils.h"
 
 using namespace mozilla::docshell;
 using namespace mozilla::dom::devicestorage;
 using namespace mozilla::dom::sms;
 using namespace mozilla::dom::indexedDB;
 using namespace mozilla::hal_sandbox;
 using namespace mozilla::ipc;
 using namespace mozilla::layers;
@@ -220,16 +221,18 @@ ConsoleListener::Observe(nsIConsoleMessa
 ContentChild* ContentChild::sSingleton;
 
 ContentChild::ContentChild()
  :
    mID(uint64_t(-1))
 #ifdef ANDROID
    ,mScreenSize(0, 0)
 #endif
+   , mIsForApp(false)
+   , mIsForBrowser(false)
 {
     // This process is a content process, so it's clearly running in
     // multiprocess mode!
     nsDebugImpl::SetMultiprocessMode("Child");
 }
 
 ContentChild::~ContentChild()
 {
@@ -617,22 +620,22 @@ ContentChild::AllocPNecko()
 bool 
 ContentChild::DeallocPNecko(PNeckoChild* necko)
 {
     delete necko;
     return true;
 }
 
 PExternalHelperAppChild*
-ContentChild::AllocPExternalHelperApp(const IPC::URI& uri,
+ContentChild::AllocPExternalHelperApp(const OptionalURIParams& uri,
                                       const nsCString& aMimeContentType,
                                       const nsCString& aContentDisposition,
                                       const bool& aForceSave,
                                       const int64_t& aContentLength,
-                                      const IPC::URI& aReferrer)
+                                      const OptionalURIParams& aReferrer)
 {
     ExternalHelperAppChild *child = new ExternalHelperAppChild();
     child->AddRef();
     return child;
 }
 
 bool
 ContentChild::DeallocPExternalHelperApp(PExternalHelperAppChild* aService)
@@ -778,19 +781,22 @@ ContentChild::RecvNotifyAlertsObserver(c
             }
         }
         ++i;
     }
     return true;
 }
 
 bool
-ContentChild::RecvNotifyVisited(const IPC::URI& aURI)
+ContentChild::RecvNotifyVisited(const URIParams& aURI)
 {
-    nsCOMPtr<nsIURI> newURI(aURI);
+    nsCOMPtr<nsIURI> newURI = DeserializeURI(aURI);
+    if (!newURI) {
+        return false;
+    }
     History::GetService()->NotifyVisited(newURI);
     return true;
 }
 
 bool
 ContentChild::RecvAsyncMessage(const nsString& aMsg,
                                      const ClonedMessageData& aData)
 {
@@ -915,22 +921,26 @@ ContentChild::RecvAppInfo(const nsCStrin
     mAppInfo.version.Assign(version);
     mAppInfo.buildID.Assign(buildID);
 
     PreloadSlowThings();
     return true;
 }
 
 bool
-ContentChild::RecvSetID(const uint64_t &id)
+ContentChild::RecvSetProcessAttributes(const uint64_t &id,
+                                       const bool& aIsForApp,
+                                       const bool& aIsForBrowser)
 {
     if (mID != uint64_t(-1)) {
         NS_WARNING("Setting content child's ID twice?");
     }
     mID = id;
+    mIsForApp = aIsForApp;
+    mIsForBrowser = aIsForBrowser;
     return true;
 }
 
 bool
 ContentChild::RecvLastPrivateDocShellDestroyed()
 {
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     obs->NotifyObservers(nullptr, "last-pb-context-exited", nullptr);
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -17,32 +17,39 @@
 struct ChromePackage;
 class nsIDOMBlob;
 class nsIObserver;
 struct ResourceMapping;
 struct OverrideMapping;
 
 namespace mozilla {
 
+namespace ipc {
+class OptionalURIParams;
+class URIParams;
+}// namespace ipc
+
 namespace layers {
 class PCompositorChild;
-}
+} // namespace layers
 
 namespace dom {
 
 class AlertObserver;
 class PrefObserver;
 class ConsoleListener;
 class PStorageChild;
 class ClonedMessageData;
 
 class ContentChild : public PContentChild
 {
     typedef layers::PCompositorChild PCompositorChild;
     typedef mozilla::dom::ClonedMessageData ClonedMessageData;
+    typedef mozilla::ipc::OptionalURIParams OptionalURIParams;
+    typedef mozilla::ipc::URIParams URIParams;
 
 public:
     ContentChild();
     virtual ~ContentChild();
 
     struct AppInfo
     {
         nsCString version;
@@ -106,38 +113,38 @@ public:
                                      const int32_t&,
                                      const int32_t&);
     virtual bool DeallocPAudio(PAudioChild*);
 
     virtual PNeckoChild* AllocPNecko();
     virtual bool DeallocPNecko(PNeckoChild*);
 
     virtual PExternalHelperAppChild *AllocPExternalHelperApp(
-            const IPC::URI& uri,
+            const OptionalURIParams& uri,
             const nsCString& aMimeContentType,
             const nsCString& aContentDisposition,
             const bool& aForceSave,
             const int64_t& aContentLength,
-            const IPC::URI& aReferrer);
+            const OptionalURIParams& aReferrer);
     virtual bool DeallocPExternalHelperApp(PExternalHelperAppChild *aService);
 
     virtual PSmsChild* AllocPSms();
     virtual bool DeallocPSms(PSmsChild*);
 
     virtual PStorageChild* AllocPStorage(const StorageConstructData& aData);
     virtual bool DeallocPStorage(PStorageChild* aActor);
 
     virtual bool RecvRegisterChrome(const InfallibleTArray<ChromePackage>& packages,
                                     const InfallibleTArray<ResourceMapping>& resources,
                                     const InfallibleTArray<OverrideMapping>& overrides,
                                     const nsCString& locale);
 
     virtual bool RecvSetOffline(const bool& offline);
 
-    virtual bool RecvNotifyVisited(const IPC::URI& aURI);
+    virtual bool RecvNotifyVisited(const URIParams& aURI);
     // auto remove when alertfinished is received.
     nsresult AddRemoteAlertObserver(const nsString& aData, nsIObserver* aObserver);
 
     virtual bool RecvPreferenceUpdate(const PrefSetting& aPref);
 
     virtual bool RecvNotifyAlertsObserver(const nsCString& aType, const nsString& aData);
 
     virtual bool RecvAsyncMessage(const nsString& aMsg,
@@ -152,33 +159,38 @@ public:
     virtual bool RecvFlushMemory(const nsString& reason);
 
     virtual bool RecvActivateA11y();
 
     virtual bool RecvGarbageCollect();
     virtual bool RecvCycleCollect();
 
     virtual bool RecvAppInfo(const nsCString& version, const nsCString& buildID);
-    virtual bool RecvSetID(const uint64_t &id);
+    virtual bool RecvSetProcessAttributes(const uint64_t& id,
+                                          const bool& aIsForApp,
+                                          const bool& aIsForBrowser);
 
     virtual bool RecvLastPrivateDocShellDestroyed();
 
     virtual bool RecvFilePathUpdate(const nsString& path, const nsCString& reason);
     virtual bool RecvFileSystemUpdate(const nsString& aFsName, const nsString& aName, const int32_t& aState);
 
 #ifdef ANDROID
     gfxIntSize GetScreenSize() { return mScreenSize; }
 #endif
 
     // Get the directory for IndexedDB files. We query the parent for this and
     // cache the value
     nsString &GetIndexedDBPath();
 
     uint64_t GetID() { return mID; }
 
+    bool IsForApp() { return mIsForApp; }
+    bool IsForBrowser() { return mIsForBrowser; }
+
     BlobChild* GetOrCreateActorForBlob(nsIDOMBlob* aBlob);
 
 private:
     virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
 
     virtual void ProcessingError(Result what) MOZ_OVERRIDE;
 
     /**
@@ -200,16 +212,19 @@ private:
     uint64_t mID;
 
     AppInfo mAppInfo;
 
 #ifdef ANDROID
     gfxIntSize mScreenSize;
 #endif
 
+    bool mIsForApp;
+    bool mIsForBrowser;
+
     static ContentChild* sSingleton;
 
     DISALLOW_EVIL_CONSTRUCTORS(ContentChild);
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -71,16 +71,17 @@
 #include "nsServiceManagerUtils.h"
 #include "nsSystemInfo.h"
 #include "nsThreadUtils.h"
 #include "nsToolkitCompsCID.h"
 #include "nsWidgetsCID.h"
 #include "SandboxHal.h"
 #include "StructuredCloneUtils.h"
 #include "TabParent.h"
+#include "URIUtils.h"
 
 #ifdef ANDROID
 # include "gfxAndroidPlatform.h"
 #endif
 
 #ifdef MOZ_CRASHREPORTER
 # include "nsExceptionHandler.h"
 # include "nsICrashReporter.h"
@@ -181,17 +182,18 @@ ContentParent::PreallocateAppProcess()
 
     if (sPreallocateAppProcessTask) {
         // We were called directly while a delayed task was scheduled.
         sPreallocateAppProcessTask->Cancel();
         sPreallocateAppProcessTask = nullptr;
     }
 
     sPreallocatedAppProcess =
-        new ContentParent(MAGIC_PREALLOCATED_APP_MANIFEST_URL);
+        new ContentParent(MAGIC_PREALLOCATED_APP_MANIFEST_URL,
+                          /*isBrowserElement=*/false);
     sPreallocatedAppProcess->Init();
 }
 
 /*static*/ void
 ContentParent::DelayedPreallocateAppProcess()
 {
     sPreallocateAppProcessTask = nullptr;
     if (!sPreallocatedAppProcess) {
@@ -243,44 +245,51 @@ ContentParent::StartUp()
 /*static*/ void
 ContentParent::ShutDown()
 {
     // No-op for now.  We rely on normal process shutdown and
     // ClearOnShutdown() to clean up our state.
 }
 
 /*static*/ ContentParent*
-ContentParent::GetNewOrUsed()
+ContentParent::GetNewOrUsed(bool aForBrowserElement)
 {
     if (!gNonAppContentParents)
         gNonAppContentParents = new nsTArray<ContentParent*>();
 
     int32_t maxContentProcesses = Preferences::GetInt("dom.ipc.processCount", 1);
     if (maxContentProcesses < 1)
         maxContentProcesses = 1;
 
     if (gNonAppContentParents->Length() >= uint32_t(maxContentProcesses)) {
         uint32_t idx = rand() % gNonAppContentParents->Length();
         ContentParent* p = (*gNonAppContentParents)[idx];
         NS_ASSERTION(p->IsAlive(), "Non-alive contentparent in gNonAppContentParents?");
         return p;
     }
 
     nsRefPtr<ContentParent> p =
-        new ContentParent(/* appManifestURL = */ EmptyString());
+        new ContentParent(/* appManifestURL = */ EmptyString(),
+                          aForBrowserElement);
     p->Init();
     gNonAppContentParents->AppendElement(p);
     return p;
 }
 
 /*static*/ TabParent*
 ContentParent::CreateBrowser(mozIApplication* aApp, bool aIsBrowserElement)
 {
+    // We currently don't set the <app> ancestor for <browser> content
+    // correctly.  This assertion is to notify the person who fixes
+    // this code that they need to reevaluate places here where we may
+    // make bad assumptions based on that bug.
+    MOZ_ASSERT(!aApp || !aIsBrowserElement);
+
     if (!aApp) {
-        if (ContentParent* cp = GetNewOrUsed()) {
+        if (ContentParent* cp = GetNewOrUsed(aIsBrowserElement)) {
             nsRefPtr<TabParent> tp(new TabParent(aApp, aIsBrowserElement));
             return static_cast<TabParent*>(
                 cp->SendPBrowserConstructor(
                     // DeallocPBrowserParent() releases the ref we take here
                     tp.forget().get(),
                     /*chromeFlags*/0,
                     aIsBrowserElement, nsIScriptSecurityManager::NO_APP_ID));
         }
@@ -316,17 +325,17 @@ ContentParent::CreateBrowser(mozIApplica
 
     nsRefPtr<ContentParent> p = gAppContentParents->Get(manifestURL);
     if (!p) {
         p = MaybeTakePreallocatedAppProcess();
         if (p) {
             p->SetManifestFromPreallocated(manifestURL);
         } else {
             NS_WARNING("Unable to use pre-allocated app process");
-            p = new ContentParent(manifestURL);
+            p = new ContentParent(manifestURL, aIsBrowserElement);
             p->Init();
         }
         gAppContentParents->Put(manifestURL, p);
     }
 
     nsRefPtr<TabParent> tp(new TabParent(aApp, aIsBrowserElement));
     return static_cast<TabParent*>(
         // DeallocPBrowserParent() releases the ref we take here
@@ -642,17 +651,18 @@ ContentParent::DestroyTestShell(TestShel
 TestShellParent*
 ContentParent::GetTestShellSingleton()
 {
     if (!ManagedPTestShellParent().Length())
         return nullptr;
     return static_cast<TestShellParent*>(ManagedPTestShellParent()[0]);
 }
 
-ContentParent::ContentParent(const nsAString& aAppManifestURL)
+ContentParent::ContentParent(const nsAString& aAppManifestURL,
+                             bool aIsForBrowser)
     : mGeolocationWatchID(-1)
     , mRunToCompletionDepth(0)
     , mShouldCallUnblockChild(false)
     , mIsAlive(true)
     , mSendPermissionUpdates(false)
     , mAppManifestURL(aAppManifestURL)
 {
     // From this point on, NS_WARNING, NS_ASSERTION, etc. should print out the
@@ -666,17 +676,18 @@ ContentParent::ContentParent(const nsASt
     if (useOffMainThreadCompositing) {
         // We need the subprocess's ProcessHandle to create the
         // PCompositor channel below.  Block just until we have that.
         mSubprocess->LaunchAndWaitForProcessHandle();
     } else {
         mSubprocess->AsyncLaunch();
     }
     Open(mSubprocess->GetChannel(), mSubprocess->GetChildProcessHandle());
-    unused << SendSetID(gContentChildID++);
+    unused << SendSetProcessAttributes(gContentChildID++,
+                                       IsForApp(), aIsForBrowser);
 
     // NB: internally, this will send an IPC message to the child
     // process to get it to create the CompositorChild.  This
     // message goes through the regular IPC queue for this
     // channel, so delivery will happen-before any other messages
     // we send.  The CompositorChild must be created before any
     // PBrowsers are created, because they rely on the Compositor
     // already being around.  (Creation is async, so can't happen
@@ -1332,22 +1343,22 @@ ContentParent::AllocPNecko()
 bool 
 ContentParent::DeallocPNecko(PNeckoParent* necko)
 {
     delete necko;
     return true;
 }
 
 PExternalHelperAppParent*
-ContentParent::AllocPExternalHelperApp(const IPC::URI& uri,
+ContentParent::AllocPExternalHelperApp(const OptionalURIParams& uri,
                                        const nsCString& aMimeContentType,
                                        const nsCString& aContentDisposition,
                                        const bool& aForceSave,
                                        const int64_t& aContentLength,
-                                       const IPC::URI& aReferrer)
+                                       const OptionalURIParams& aReferrer)
 {
     ExternalHelperAppParent *parent = new ExternalHelperAppParent(uri, aContentLength);
     parent->AddRef();
     parent->Init(this, aMimeContentType, aContentDisposition, aForceSave, aReferrer);
     return parent;
 }
 
 bool
@@ -1409,53 +1420,62 @@ ContentParent::RequestRunToCompletion()
 #endif
         mRunToCompletionDepth = 1;
         mShouldCallUnblockChild = true;
     }
     return !!mRunToCompletionDepth;
 }
 
 bool
-ContentParent::RecvStartVisitedQuery(const IPC::URI& aURI)
+ContentParent::RecvStartVisitedQuery(const URIParams& aURI)
 {
-    nsCOMPtr<nsIURI> newURI(aURI);
+    nsCOMPtr<nsIURI> newURI = DeserializeURI(aURI);
+    if (!newURI) {
+        return false;
+    }
     nsCOMPtr<IHistory> history = services::GetHistoryService();
     NS_ABORT_IF_FALSE(history, "History must exist at this point.");
     if (history) {
-      history->RegisterVisitedCallback(newURI, nullptr);
+        history->RegisterVisitedCallback(newURI, nullptr);
     }
     return true;
 }
 
 
 bool
-ContentParent::RecvVisitURI(const IPC::URI& uri,
-                                   const IPC::URI& referrer,
-                                   const uint32_t& flags)
+ContentParent::RecvVisitURI(const URIParams& uri,
+                            const OptionalURIParams& referrer,
+                            const uint32_t& flags)
 {
-    nsCOMPtr<nsIURI> ourURI(uri);
-    nsCOMPtr<nsIURI> ourReferrer(referrer);
+    nsCOMPtr<nsIURI> ourURI = DeserializeURI(uri);
+    if (!ourURI) {
+        return false;
+    }
+    nsCOMPtr<nsIURI> ourReferrer = DeserializeURI(referrer);
     nsCOMPtr<IHistory> history = services::GetHistoryService();
     NS_ABORT_IF_FALSE(history, "History must exist at this point");
     if (history) {
-      history->VisitURI(ourURI, ourReferrer, flags);
+        history->VisitURI(ourURI, ourReferrer, flags);
     }
     return true;
 }
 
 
 bool
-ContentParent::RecvSetURITitle(const IPC::URI& uri,
-                                      const nsString& title)
+ContentParent::RecvSetURITitle(const URIParams& uri,
+                               const nsString& title)
 {
-    nsCOMPtr<nsIURI> ourURI(uri);
+    nsCOMPtr<nsIURI> ourURI = DeserializeURI(uri);
+    if (!ourURI) {
+        return false;
+    }
     nsCOMPtr<IHistory> history = services::GetHistoryService();
     NS_ABORT_IF_FALSE(history, "History must exist at this point");
     if (history) {
-      history->SetURITitle(ourURI, title);
+        history->SetURITitle(ourURI, title);
     }
     return true;
 }
 
 bool
 ContentParent::RecvShowFilePicker(const int16_t& mode,
                                   const int16_t& selectedType,
                                   const bool& addToRecentDocs,
@@ -1526,22 +1546,26 @@ ContentParent::RecvShowFilePicker(const 
         file->GetPath(filePath);
         files->AppendElement(filePath);
     }
 
     return true;
 }
 
 bool
-ContentParent::RecvLoadURIExternal(const IPC::URI& uri)
+ContentParent::RecvLoadURIExternal(const URIParams& uri)
 {
     nsCOMPtr<nsIExternalProtocolService> extProtService(do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
-    if (!extProtService)
+    if (!extProtService) {
         return true;
-    nsCOMPtr<nsIURI> ourURI(uri);
+    }
+    nsCOMPtr<nsIURI> ourURI = DeserializeURI(uri);
+    if (!ourURI) {
+        return false;
+    }
     extProtService->LoadURI(ourURI, nullptr);
     return true;
 }
 
 /* void onDispatchedEvent (in nsIThreadInternal thread); */
 NS_IMETHODIMP
 ContentParent::OnDispatchedEvent(nsIThreadInternal *thread)
 {
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -27,50 +27,53 @@
 
 class mozIApplication;
 class nsFrameMessageManager;
 class nsIDOMBlob;
 
 namespace mozilla {
 
 namespace ipc {
+class OptionalURIParams;
+class URIParams;
 class TestShellParent;
-}
+} // namespace ipc
 
 namespace layers {
 class PCompositorParent;
-}
+} // namespace layers
 
 namespace dom {
 
 class TabParent;
 class PStorageParent;
 class ClonedMessageData;
 
 class ContentParent : public PContentParent
                     , public nsIObserver
                     , public nsIThreadObserver
                     , public nsIDOMGeoPositionCallback
 {
-private:
     typedef mozilla::ipc::GeckoChildProcessHost GeckoChildProcessHost;
+    typedef mozilla::ipc::OptionalURIParams OptionalURIParams;
     typedef mozilla::ipc::TestShellParent TestShellParent;
+    typedef mozilla::ipc::URIParams URIParams;
     typedef mozilla::layers::PCompositorParent PCompositorParent;
     typedef mozilla::dom::ClonedMessageData ClonedMessageData;
 
 public:
     /**
      * Start up the content-process machinery.  This might include
      * scheduling pre-launch tasks.
      */
     static void StartUp();
     /** Shut down the content-process machinery. */
     static void ShutDown();
 
-    static ContentParent* GetNewOrUsed();
+    static ContentParent* GetNewOrUsed(bool aForBrowserElement = false);
 
     /**
      * Get or create a content process for the given app descriptor,
      * which may be null.  This function will assign processes to app
      * or non-app browsers by internal heuristics.
      *
      * Currently apps are given their own process, and browser tabs
      * share processes.
@@ -124,17 +127,17 @@ private:
     static void ScheduleDelayedPreallocateAppProcess();
     static already_AddRefed<ContentParent> MaybeTakePreallocatedAppProcess();
 
     // Hide the raw constructor methods since we don't want client code
     // using them.
     using PContentParent::SendPBrowserConstructor;
     using PContentParent::SendPTestShellConstructor;
 
-    ContentParent(const nsAString& aAppManifestURL);
+    ContentParent(const nsAString& aAppManifestURL, bool aIsForBrowser);
     virtual ~ContentParent();
 
     void Init();
 
     // Transform a pre-allocated app process into a "real" app
     // process, for the specified manifest URL.
     void SetManifestFromPreallocated(const nsAString& aAppManifestURL);
 
@@ -193,22 +196,22 @@ private:
                                      const int32_t&,
                                      const int32_t&);
     virtual bool DeallocPAudio(PAudioParent*);
 
     virtual PNeckoParent* AllocPNecko();
     virtual bool DeallocPNecko(PNeckoParent* necko);
 
     virtual PExternalHelperAppParent* AllocPExternalHelperApp(
-            const IPC::URI& uri,
+            const OptionalURIParams& aUri,
             const nsCString& aMimeContentType,
             const nsCString& aContentDisposition,
             const bool& aForceSave,
             const int64_t& aContentLength,
-            const IPC::URI& aReferrer);
+            const OptionalURIParams& aReferrer);
     virtual bool DeallocPExternalHelperApp(PExternalHelperAppParent* aService);
 
     virtual PSmsParent* AllocPSms();
     virtual bool DeallocPSms(PSmsParent*);
 
     virtual PStorageParent* AllocPStorage(const StorageConstructData& aData);
     virtual bool DeallocPStorage(PStorageParent* aActor);
 
@@ -221,23 +224,23 @@ private:
     virtual bool RecvGetClipboardText(const int32_t& whichClipboard, nsString* text);
     virtual bool RecvEmptyClipboard();
     virtual bool RecvClipboardHasText(bool* hasText);
 
     virtual bool RecvGetSystemColors(const uint32_t& colorsCount, InfallibleTArray<uint32_t>* colors);
     virtual bool RecvGetIconForExtension(const nsCString& aFileExt, const uint32_t& aIconSize, InfallibleTArray<uint8_t>* bits);
     virtual bool RecvGetShowPasswordSetting(bool* showPassword);
 
-    virtual bool RecvStartVisitedQuery(const IPC::URI& uri);
+    virtual bool RecvStartVisitedQuery(const URIParams& uri);
 
-    virtual bool RecvVisitURI(const IPC::URI& uri,
-                              const IPC::URI& referrer,
+    virtual bool RecvVisitURI(const URIParams& uri,
+                              const OptionalURIParams& referrer,
                               const uint32_t& flags);
 
-    virtual bool RecvSetURITitle(const IPC::URI& uri,
+    virtual bool RecvSetURITitle(const URIParams& uri,
                                  const nsString& title);
     
     virtual bool RecvShowFilePicker(const int16_t& mode,
                                     const int16_t& selectedType,
                                     const bool& addToRecentDocs,
                                     const nsString& title,
                                     const nsString& defaultFile,
                                     const nsString& defaultExtension,
@@ -246,17 +249,17 @@ private:
                                     InfallibleTArray<nsString>* files,
                                     int16_t* retValue,
                                     nsresult* result);
  
     virtual bool RecvShowAlertNotification(const nsString& aImageUrl, const nsString& aTitle,
                                            const nsString& aText, const bool& aTextClickable,
                                            const nsString& aCookie, const nsString& aName);
 
-    virtual bool RecvLoadURIExternal(const IPC::URI& uri);
+    virtual bool RecvLoadURIExternal(const URIParams& uri);
 
     virtual bool RecvSyncMessage(const nsString& aMsg,
                                  const ClonedMessageData& aData,
                                  InfallibleTArray<nsString>* aRetvals);
     virtual bool RecvAsyncMessage(const nsString& aMsg,
                                   const ClonedMessageData& aData);
 
     virtual bool RecvAddGeolocationListener();
--- a/dom/ipc/PBlobStream.ipdl
+++ b/dom/ipc/PBlobStream.ipdl
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PBlob;
-include IPCSerializableParams;
+include InputStreamParams;
 
 namespace mozilla {
 namespace dom {
 
 protocol PBlobStream
 {
   manager PBlob;
 
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -8,28 +8,26 @@
 include protocol PBlob;
 include protocol PContent;
 include protocol PContentDialog;
 include protocol PDocumentRenderer;
 include protocol PContentPermissionRequest;
 include protocol PRenderFrame;
 include protocol POfflineCacheUpdate;
 include protocol PIndexedDB;
+include DOMTypes;
+include URIParams;
 
 include "gfxMatrix.h";
 include "FrameMetrics.h";
 include "IPC/nsGUIEventIPC.h";
 include "mozilla/dom/TabMessageUtils.h";
 include "mozilla/dom/PermissionMessageUtils.h";
 include "mozilla/layout/RenderFrameUtils.h";
-include "mozilla/net/NeckoMessageUtils.h";
 
-include DOMTypes;
-
-using IPC::URI;
 using IPC::Principal;
 using gfxMatrix;
 using gfxRect;
 using gfxSize;
 using mozilla::layers::LayersBackend;
 using mozilla::layers::FrameMetrics;
 using mozilla::layout::ScrollingBehavior;
 using mozilla::WindowsHandle;
@@ -225,18 +223,18 @@ parent:
      *   Why this argument? If the document was not found in an offline cache 
      *   before load and refers a manifest and this manifest itself has not 
      *   been changed since the last fetch, we will not do the application 
      *   cache group update. But we must cache the document (identified by the
      *   documentURI). This argument will ensure that a previously uncached 
      *   document will get cached and that we don't re-cache a document that 
      *   has already been cached (stickDocument=false).
      */
-    POfflineCacheUpdate(URI manifestURI, URI documentURI, nsCString clientID,
-                        bool stickDocument);
+    POfflineCacheUpdate(URIParams manifestURI, URIParams documentURI,
+                        nsCString clientID, bool stickDocument);
 
     sync PIndexedDB(nsCString asciiOrigin)
         returns (bool allowed);
 
     /**
      * window.open from inside <iframe mozbrowser> is special.  When the child
      * process calls window.open, it creates a new PBrowser (in its own
      * process), then calls BrowserFrameOpenWindow on it.
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -13,32 +13,31 @@ include protocol PExternalHelperApp;
 include protocol PDeviceStorageRequest;
 include protocol PHal;
 include protocol PIndexedDB;
 include protocol PMemoryReportRequest;
 include protocol PNecko;
 include protocol PSms;
 include protocol PStorage;
 include protocol PTestShell;
+include DOMTypes;
+include URIParams;
 
 include "mozilla/chrome/RegistryMessageUtils.h";
 include "mozilla/net/NeckoMessageUtils.h";
 include "mozilla/dom/TabMessageUtils.h";
 
 include "nsGeoPositionIPCSerialiser.h";
 
-include DOMTypes;
-
 using GeoPosition;
 using PrefTuple;
 
 using ChromePackage;
 using ResourceMapping;
 using OverrideMapping;
-using IPC::URI;
 using IPC::Permission;
 using mozilla::null_t;
 using mozilla::void_t;
 using mozilla::dom::NativeThreadId;
 using gfxIntSize;
 
 namespace mozilla {
 namespace dom {
@@ -187,22 +186,33 @@ both:
 
     async PBlob(BlobConstructorParams params);
 
 child:
     PMemoryReportRequest();
 
     PTestShell();
 
+    /**
+     * Tell the content process some attributes of itself.  This is
+     * the first message received by content processes after startup.
+     *
+     * |id| is a unique ID among all subprocesses.  When |isForApp &&
+     * isForBrowser|, we're loading <browser> for an app.  When
+     * |isForBrowser|, we're loading <browser>.  When |!isForApp &&
+     * !isForBrowser|, we're probably loading <xul:browser remote>.
+     */
+    SetProcessAttributes(uint64_t id, bool isForApp, bool isForBrowser);
+
     RegisterChrome(ChromePackage[] packages, ResourceMapping[] resources,
                    OverrideMapping[] overrides, nsCString locale);
 
     async SetOffline(bool offline);
 
-    async NotifyVisited(URI uri);
+    async NotifyVisited(URIParams uri);
 
     PreferenceUpdate(PrefSetting pref);
 
     NotifyAlertsObserver(nsCString topic, nsString data);
 
     GeolocationUpdate(GeoPosition somewhere);
 
     // nsIPermissionManager messages
@@ -217,18 +227,16 @@ child:
     
     /**
      * Start accessibility engine in content process.
      */
     ActivateA11y();
 
     AppInfo(nsCString version, nsCString buildID);
 
-    SetID(uint64_t id);
-
     // Notify child that last-pb-context-exited notification was observed
     LastPrivateDocShellDestroyed();
 
     FilePathUpdate(nsString filepath, nsCString reasons);
 
     FileSystemUpdate(nsString fsName, nsString mountPoint, int32_t fsState);
 
 parent:
@@ -245,47 +253,47 @@ parent:
     PNecko();
 
     PSms();
     
     PStorage(StorageConstructData data);
 
     // Services remoting
 
-    async StartVisitedQuery(URI uri);
-    async VisitURI(URI uri, URI referrer, uint32_t flags);
-    async SetURITitle(URI uri, nsString title);
+    async StartVisitedQuery(URIParams uri);
+    async VisitURI(URIParams uri, OptionalURIParams referrer, uint32_t flags);
+    async SetURITitle(URIParams uri, nsString title);
     
     // filepicker remoting
     sync ShowFilePicker(int16_t mode, int16_t selectedType, bool addToRecentDocs,
                         nsString title, nsString defaultFile, nsString defaultExtension,
                         nsString[] filters, nsString[] filterNames)
         returns (nsString[] files, int16_t retValue, nsresult result);
 
-    async LoadURIExternal(URI uri);
+    async LoadURIExternal(URIParams uri);
 
     // PrefService message
     sync ReadPrefsArray() returns (PrefSetting[] prefs);
 
     sync ReadFontList() returns (FontListEntry[] retValue);
 
     sync SyncMessage(nsString aMessage, ClonedMessageData aData)
       returns (nsString[] retval);
 
     ShowAlertNotification(nsString imageUrl, 
                           nsString title, 
                           nsString text, 
                           bool textClickable,
                           nsString cookie,
                           nsString name);
 
-    PExternalHelperApp(URI uri, nsCString aMimeContentType,
+    PExternalHelperApp(OptionalURIParams uri, nsCString aMimeContentType,
                        nsCString aContentDisposition, bool aForceSave,
-                       int64_t aContentLength, URI aReferrer);
-    
+                       int64_t aContentLength, OptionalURIParams aReferrer);
+
     AddGeolocationListener();
     RemoveGeolocationListener();
 
     ConsoleMessage(nsString message);
     ScriptError(nsString message, nsString sourceName, nsString sourceLine,
                 uint32_t lineNumber, uint32_t colNumber, uint32_t flags,
                 nsCString category); 
 
@@ -313,9 +321,9 @@ parent:
     // Notify the parent of the presence or absence of private docshells
     PrivateDocShellsExist(bool aExist);
 
 both:
      AsyncMessage(nsString aMessage, ClonedMessageData aData);
 };
 
 }
-}
+}
\ No newline at end of file
--- a/dom/ipc/PContentPermissionRequest.ipdl
+++ b/dom/ipc/PContentPermissionRequest.ipdl
@@ -1,16 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PBrowser;
-include "mozilla/net/NeckoMessageUtils.h";
-
-using IPC::URI;
 
 namespace mozilla {
 namespace dom {
 
 protocol PContentPermissionRequest
 {
   manager PBrowser;
 
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1025,18 +1025,18 @@ TabChild::RecvActivateFrameEvent(const n
   NS_ENSURE_TRUE(chromeHandler, true);
   nsRefPtr<ContentListener> listener = new ContentListener(this);
   NS_ENSURE_TRUE(listener, true);
   chromeHandler->AddEventListener(aType, listener, capture);
   return true;
 }
 
 POfflineCacheUpdateChild*
-TabChild::AllocPOfflineCacheUpdate(const URI& manifestURI,
-            const URI& documentURI,
+TabChild::AllocPOfflineCacheUpdate(const URIParams& manifestURI,
+            const URIParams& documentURI,
             const nsCString& clientID,
             const bool& stickDocument)
 {
   NS_RUNTIMEABORT("unused");
   return nullptr;
 }
 
 bool
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -240,18 +240,18 @@ public:
       child->mIPCOpen = true;
       return request;
     }
 #endif /* DEBUG */
 
     virtual PContentPermissionRequestChild* AllocPContentPermissionRequest(const nsCString& aType, const IPC::Principal& aPrincipal);
     virtual bool DeallocPContentPermissionRequest(PContentPermissionRequestChild* actor);
 
-    virtual POfflineCacheUpdateChild* AllocPOfflineCacheUpdate(const URI& manifestURI,
-            const URI& documentURI,
+    virtual POfflineCacheUpdateChild* AllocPOfflineCacheUpdate(const URIParams& manifestURI,
+            const URIParams& documentURI,
             const nsCString& clientID,
             const bool& stickDocument);
     virtual bool DeallocPOfflineCacheUpdate(POfflineCacheUpdateChild* offlineCacheUpdate);
 
     nsIWebNavigation* WebNavigation() { return mWebNav; }
 
     JSContext* GetJSContext() { return mCx; }
 
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -949,18 +949,18 @@ TabParent::AllocPRenderFrame(ScrollingBe
 bool
 TabParent::DeallocPRenderFrame(PRenderFrameParent* aFrame)
 {
   delete aFrame;
   return true;
 }
 
 mozilla::docshell::POfflineCacheUpdateParent*
-TabParent::AllocPOfflineCacheUpdate(const URI& aManifestURI,
-                                    const URI& aDocumentURI,
+TabParent::AllocPOfflineCacheUpdate(const URIParams& aManifestURI,
+                                    const URIParams& aDocumentURI,
                                     const nsCString& aClientID,
                                     const bool& stickDocument)
 {
   nsRefPtr<mozilla::docshell::OfflineCacheUpdateParent> update =
     new mozilla::docshell::OfflineCacheUpdateParent();
 
   nsresult rv = update->Schedule(aManifestURI, aDocumentURI, aClientID,
                                  stickDocument);
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -154,18 +154,18 @@ public:
                            const nsIntSize& renderSize);
     virtual bool DeallocPDocumentRenderer(PDocumentRendererParent* actor);
 
     virtual PContentPermissionRequestParent*
     AllocPContentPermissionRequest(const nsCString& aType, const IPC::Principal& aPrincipal);
     virtual bool DeallocPContentPermissionRequest(PContentPermissionRequestParent* actor);
 
     virtual POfflineCacheUpdateParent* AllocPOfflineCacheUpdate(
-            const URI& aManifestURI,
-            const URI& aDocumentURI,
+            const URIParams& aManifestURI,
+            const URIParams& aDocumentURI,
             const nsCString& aClientID,
             const bool& stickDocument);
     virtual bool DeallocPOfflineCacheUpdate(POfflineCacheUpdateParent* actor);
 
     JSBool GetGlobalJSObject(JSContext* cx, JSObject** globalp);
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIAUTHPROMPTPROVIDER
--- a/dom/messages/SystemMessageManager.js
+++ b/dom/messages/SystemMessageManager.js
@@ -23,18 +23,18 @@ XPCOMUtils.defineLazyGetter(this, "cpmm"
 let kMaxPendingMessages;
 try {
   kMaxPendingMessages = Services.prefs.getIntPref("dom.messages.maxPendingMessages");
 } catch(e) {
   // getIntPref throws when the pref is not set.
   kMaxPendingMessages = 5;
 }
 
-function debug(aMsg) { 
-  //dump("-- SystemMessageManager " + Date.now() + " : " + aMsg + "\n"); 
+function debug(aMsg) {
+  //dump("-- SystemMessageManager " + Date.now() + " : " + aMsg + "\n");
 }
 
 // Implementation of the DOM API for system messages
 
 function SystemMessageManager() {
   // Message handlers for this page.
   // We can have only one handler per message type.
   this._handlers = {};
@@ -49,27 +49,29 @@ SystemMessageManager.prototype = {
   _dispatchMessage: function sysMessMgr_dispatchMessage(aType, aHandler, aMessage) {
     // We get a json blob, but in some cases we want another kind of object
     // to be dispatched.
     // To do so, we check if we have a with a contract ID of
     // "@mozilla.org/dom/system-messages/wrapper/TYPE;1" component implementing
     // nsISystemMessageWrapper.
     debug("Dispatching " + JSON.stringify(aMessage) + "\n");
     let contractID = "@mozilla.org/dom/system-messages/wrapper/" + aType + ";1";
+    let wrapped = false;
 
     if (contractID in Cc) {
       debug(contractID + " is registered, creating an instance");
       let wrapper = Cc[contractID].createInstance(Ci.nsISystemMessagesWrapper);
       if (wrapper) {
         aMessage = wrapper.wrapMessage(aMessage);
+        wrapped = true;
         debug("wrapped = " + aMessage);
       }
     }
 
-    aHandler.handleMessage(ObjectWrapper.wrap(aMessage, this._window));
+    aHandler.handleMessage(wrapped ? aMessage : ObjectWrapper.wrap(aMessage, this._window));
   },
 
   mozSetMessageHandler: function sysMessMgr_setMessageHandler(aType, aHandler) {
     debug("setMessage handler for [" + aType + "] " + aHandler);
     if (!aType) {
       // Just bail out if we have no type.
       return;
     }
@@ -107,19 +109,19 @@ SystemMessageManager.prototype = {
 
     // If we have a handler for this type, we can't have any pending message.
     // If called from setMessageHandler, we still want to update the pending
     // queue to deliver existing messages.
     if (aType in this._handlers && !aForceUpdate) {
       return false;
     }
 
-    // Send a sync message to the parent to check if we have a pending message 
+    // Send a sync message to the parent to check if we have a pending message
     // for this type.
-    let messages = cpmm.sendSyncMessage("SystemMessageManager:GetPending", 
+    let messages = cpmm.sendSyncMessage("SystemMessageManager:GetPending",
                                         { type: aType,
                                           uri: this._uri,
                                           manifest: this._manifest })[0];
     if (!messages) {
       // No new pending messages, but the queue may not be empty yet.
       return pendings[aType] && pendings[aType].length != 0;
     }
 
@@ -143,17 +145,17 @@ SystemMessageManager.prototype = {
   },
 
   uninit: function sysMessMgr_uninit()  {
     this._handlers = null;
     this._pendings =  null;
   },
 
   receiveMessage: function sysMessMgr_receiveMessage(aMessage) {
-    debug("receiveMessage " + aMessage.name + " - " + 
+    debug("receiveMessage " + aMessage.name + " - " +
           aMessage.json.type + " for " + aMessage.json.manifest +
           " (" + this._manifest + ")");
 
     let msg = aMessage.json;
     if (msg.manifest != this._manifest)
       return;
 
     // Bail out if we have no handlers registered for this type.
--- a/dom/plugins/base/nsNPAPIPlugin.h
+++ b/dom/plugins/base/nsNPAPIPlugin.h
@@ -15,21 +15,17 @@
 #include "mozilla/PluginLibrary.h"
 
 /*
  * Use this macro before each exported function
  * (between the return address and the function
  * itself), to ensure that the function has the
  * right calling conventions on OS/2.
  */
-#ifdef XP_OS2
-#define NP_CALLBACK _System
-#else
-#define NP_CALLBACK
-#endif
+#define NP_CALLBACK NP_LOADDS
 
 #if defined(XP_WIN)
 #define NS_NPAPIPLUGIN_CALLBACK(_type, _name) _type (__stdcall * _name)
 #elif defined(XP_OS2)
 #define NS_NPAPIPLUGIN_CALLBACK(_type, _name) _type (_System * _name)
 #else
 #define NS_NPAPIPLUGIN_CALLBACK(_type, _name) _type (* _name)
 #endif
--- a/dom/plugins/ipc/PluginModuleChild.h
+++ b/dom/plugins/ipc/PluginModuleChild.h
@@ -35,21 +35,17 @@
 // NOTE: stolen from nsNPAPIPlugin.h
 
 /*
  * Use this macro before each exported function
  * (between the return address and the function
  * itself), to ensure that the function has the
  * right calling conventions on OS/2.
  */
-#ifdef XP_OS2
-#define NP_CALLBACK _System
-#else
-#define NP_CALLBACK
-#endif
+#define NP_CALLBACK NP_LOADDS
 
 #if defined(XP_WIN)
 #define NS_NPAPIPLUGIN_CALLBACK(_type, _name) _type (__stdcall * _name)
 #elif defined(XP_OS2)
 #define NS_NPAPIPLUGIN_CALLBACK(_type, _name) _type (_System * _name)
 #else
 #define NS_NPAPIPLUGIN_CALLBACK(_type, _name) _type (* _name)
 #endif
--- a/dom/sms/src/SmsManager.cpp
+++ b/dom/sms/src/SmsManager.cpp
@@ -82,17 +82,17 @@ SmsManager::CheckPermissionAndCreateInst
 
   nsCOMPtr<nsIPrincipal> principal = document->NodePrincipal();
   NS_ENSURE_TRUE(principal, nullptr);
 
   nsCOMPtr<nsIPermissionManager> permMgr =
     do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
   NS_ENSURE_TRUE(permMgr, nullptr);
 
-  PRUint32 permission = nsIPermissionManager::DENY_ACTION;
+  uint32_t permission = nsIPermissionManager::DENY_ACTION;
   permMgr->TestPermissionFromPrincipal(principal, "sms", &permission);
 
   if (permission != nsIPermissionManager::ALLOW_ACTION) {
     return nullptr;
   }
 
   nsRefPtr<SmsManager> smsMgr = new SmsManager();
   smsMgr->Init(aWindow);
--- a/dom/tests/mochitest/webapps/apphelper.js
+++ b/dom/tests/mochitest/webapps/apphelper.js
@@ -100,14 +100,13 @@ function readFile(aFile) {
 }
 
 function getOrigin(url) {
   return Services.io.newURI(url, null, null).prePath;
 }
 
 function tearDown() {
   debug("in " + arguments.callee.name);
-  uninstallAll();
   popupNotifications.panel.removeEventListener("popupshown", mainCommand, false);
   SpecialPowers.clearUserPref('browser.mozApps.installer.dry_run');
   DOMApplicationRegistry.allAppsLaunchable = originalAAL;
 }
 
--- a/dom/tests/mochitest/webapps/jshelper.js
+++ b/dom/tests/mochitest/webapps/jshelper.js
@@ -29,51 +29,16 @@ function onIframeLoad(name, check, next)
   document.getElementById(name).contentWindow.wrappedJSObject.getOrigin = getOrigin;
   document.getElementById(name).contentWindow.wrappedJSObject.check = check;
   document.getElementById(name).contentWindow.wrappedJSObject.debug = debug;
   document.getElementById(name).contentWindow.wrappedJSObject.appURL = SERVERS[name]; 
   document.getElementById(name).contentWindow.wrappedJSObject.popup_listener = popup_listener;
   document.getElementById(name).contentWindow.wrappedJSObject.readFile = readFile;
 }
 
-/**
- * Uninstall All uninstalls all Apps
- * @next  The next operation to jump to, this might need to be invoked by the iframe when the test has completed
- */
-
-function uninstallAll(next) {
-  var pendingGetAll = navigator.mozApps.mgmt.getAll();
-  pendingGetAll.onsuccess = function() {
-    var m = this.result;
-    var total = m.length;
-    var finished = (total === 0);
-    debug("total = " + total);
-    for (var i=0; i < m.length; i++) {
-      var app = m[i];
-      var pendingUninstall = app.uninstall();
-      pendingUninstall.onsuccess = function(r) {
-        finished = (--total === 0);
-        if(finished == true) {
-          next();
-        }
-      };
-      pendingUninstall.onerror = function () {
-        finished = true;
-        throw('Failed');
-        if(finished == true) {
-          next();
-        }
-      };
-    }
-    if(finished == true && total ==  0) {
-      next();
-    }
-  }
-}
-
 function subsetOf(resultObj, list) {
   var returnObj = {} ;
   for (var i=0; i < list.length; i++) {
     returnObj[list[i]] = resultObj[list[i]];
   }
   return returnObj;
 }
 
--- a/dom/tests/mochitest/webapps/test_cross_domain.xul
+++ b/dom/tests/mochitest/webapps/test_cross_domain.xul
@@ -21,44 +21,29 @@
      target="_blank">Mozilla Bug 741549</a>
   <iframe id="super_crazy" onload="go();" src="http://www.example.com:80/chrome/dom/tests/mochitest/webapps/apps/include.html"/>
   <iframe id="no_delegated_install" onload="go();" src="http://sub2.test2.example.org:80/chrome/dom/tests/mochitest/webapps/apps/include.html"/>
 
   </body>
 
 <script> 
 
-steps = [setUp, verify_no_apps, get_installed_returns_nothing, install_super_crazy, check_event_listener_fired, get_self_returns_nothing, 
+steps = [get_installed_returns_nothing, install_super_crazy, check_event_listener_fired, get_self_returns_nothing, 
          get_self_on_domain, install_on_domain, check_event_listener_fired, get_all_installed, 
          get_installed_on_domain, uninstall_on_domain, get_all_on_domain, tearDown];
 var iframes_loaded = 0 ;
 
 function go() {
   ++iframes_loaded;
   if (iframes_loaded >= 2) {
     runAll(steps);
   } 
 }
 
 
-function setUp(next) { 
-  debug("in " + arguments.callee.name);
-  
-  uninstallAll(next);
-}
-
-function verify_no_apps(next)  {
-  debug("in " + arguments.callee.name);
-  mozAppscb(navigator.mozApps.mgmt.getAll(),
-            [{}],
-            "success",
-            ok,
-            next);
-}
-
 function get_installed_returns_nothing(next) {
   debug("in " + arguments.callee.name);
   mozAppscb(navigator.mozApps.getInstalled(), 
             [{}],
             "success",
             ok, 
             next);
 }
--- a/dom/tests/mochitest/webapps/test_getNotInstalled.xul
+++ b/dom/tests/mochitest/webapps/test_getNotInstalled.xul
@@ -10,60 +10,64 @@
         title="Mozilla Bug 781379">
 <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
 <script type="application/javascript" src="apphelper.js"/>
 <script type="application/javascript" src="jshelper.js"/>
 <script type="application/javascript;version=1.8">
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 Cu.import("resource://gre/modules/Webapps.jsm");
 
+let notInstalled = 0;
+
 let _isLaunchable;
 let steps = [
-  cleanUp, installApp, monkeyPatchDOMApplicationRegistry, getNotInstalled,
-  unmonkeyPatchDOMApplicationRegistry, cleanUp, tearDown
+  monkeyPatchDOMApplicationRegistry, getNotInstalled, installApp,
+  compareNotInstalled, unmonkeyPatchDOMApplicationRegistry, cleanUp, tearDown
 ];
 runAll(steps);
 
-// Remove all installed apps and apps from the appregistry
-function cleanUp (next) { 
-  uninstallAll(next);
-}
-
-// Add an app to the appregistry
-function installApp (next) {
-  let appURL = SERVERS["super_crazy"];
-  install(appURL, ok, next);
-}
-
 // Monkey patch DOMApplicationRegistry._isLaunchable for testing.
 // This way, we don't have to create a platform specific application with a
 // status other than "installed".
 function monkeyPatchDOMApplicationRegistry (next) {
   _isLaunchable = DOMApplicationRegistry._isLaunchable;
   DOMApplicationRegistry._isLaunchable = function mockIsLaunchable (aOrigin) {
     return false;
   }
   next();
 }
 
-// Call navigator.mozApps.mgmt.getNotInstalled
+// Call navigator.mozApps.mgmt.getNotInstalled and save the result.
 function getNotInstalled (next) {
+  window.navigator.mozApps.mgmt.getNotInstalled().onsuccess = function() {
+    notInstalled = this.result.length;
+    next();
+  };
+}
+
+// Add an app to the appregistry
+function installApp (next) {
+  let appURL = SERVERS["super_crazy"];
+  install(appURL, ok, next);
+}
+
+// Call navigator.mozApps.mgmt.getNotInstalled and make sure there is one more.
+function compareNotInstalled (next) {
   let results;
   function getNotInstalledError () {
     ok(false, "window.mozApps.mgmt.getNotInstalled onerror called");
     next();
   }
   function getNotInstalledSuccess () {
     ok(true, "window.mozApps.mgmt.getNotInstalled onsuccess called");
-    if (this.result.length === 1) {
-      ok(true, "got the single notInstalled app back")
-      is(this.result[0].origin, "http://www.example.com",
+    is(this.result.length, notInstalled + 1, "should get one more notInstalled app");
+
+    if (this.result.length > 0) {
+      is(this.result[this.result.length-1].origin, "http://www.example.com",
         "getNotInstalled returned the expected app");
-    } else {
-      ok(false, "got an unexpected result from the call to getNotInstalled");
     }
     next();
   }
 
   let type = typeof window.navigator.mozApps.getNotInstalled;
   is(type, "undefined", "getNotInstalled moved from window.navigator");
   type = typeof window.navigator.mozApps.mgmt.getNotInstalled;
   if (type === "function") {
@@ -81,10 +85,17 @@ function unmonkeyPatchDOMApplicationRegi
   if (typeof _isLaunchable === "function") {
     DOMApplicationRegistry._isLaunchable = _isLaunchable;
     ok(true, "restored DOMApplicationRegistry._isLaunchable")
   } else {
     ok(false, "can't restore DOMApplicationRegistry._isLaunchable")
   }
   next();
 }
+
+// Remove installed app.
+function cleanUp (next) {
+  let appURL = SERVERS["super_crazy"];
+  uninstall(appURL, ok, next);
+}
+
 </script>
 </window>
--- a/dom/tests/mochitest/webapps/test_install_app.xul
+++ b/dom/tests/mochitest/webapps/test_install_app.xul
@@ -19,35 +19,21 @@
   <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=741549"
      target="_blank">Mozilla Bug 741549</a> <br />
   <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=734294"
      target="_blank">Mozilla Bug 734294</a>
   </body>
 
 <script> 
 
-steps = [setUp, verify_no_apps, get_installed_returns_nothing, install_super_crazy, get_self_returns_nothing, 
+steps = [get_installed_returns_nothing, install_super_crazy, get_self_returns_nothing, 
          install_wild_crazy, uninstall_wild_crazy, tearDown];
 
 runAll(steps);
 
-function setUp(next) { 
-  debug("in " + arguments.callee.name);
-  uninstallAll(next);
-}
-
-function verify_no_apps(next)  {
-  debug("in " + arguments.callee.name);
-  mozAppscb(navigator.mozApps.mgmt.getAll(), 
-            [{}],
-            "success",
-            ok,
-            next);
-}
-
 function get_installed_returns_nothing(next) {
   debug("in " + arguments.callee.name);
   mozAppscb(navigator.mozApps.getInstalled(), 
             [{}],
             "success",
             ok,
             next);
 }
--- a/dom/tests/mochitest/webapps/test_install_errors.xul
+++ b/dom/tests/mochitest/webapps/test_install_errors.xul
@@ -21,23 +21,18 @@
   </body>
 
 <script> 
 
 function go() {
   runAll(steps);
 }
 
-steps = [setUp, no_args, parse_error, invalid_manifest, permission_denied, invalid_content,
-         mgmt_api_errors, mgmt_api_add_listener, tearDown];
-
-function setUp(next) {
-  debug("in " + arguments.callee.name);
-  uninstallAll(next);
-}
+steps = [no_args, parse_error, invalid_manifest, permission_denied, invalid_content,
+         mgmt_api_errors, mgmt_api_add_listener, uninstall_apps, tearDown];
 
 function no_args(next)  {
   debug("in " + arguments.callee.name);
   try { 
     navigator.mozApps.install();
   } catch (e) {
     ok(e.message == "Not enough arguments \[mozIDOMApplicationRegistry.install\]", "install returned " + e.message);
     next();
@@ -75,12 +70,21 @@ function mgmt_api_errors(next) {
 }
 
 function mgmt_api_add_listener(next) {
   debug("in " + arguments.callee.name);
   onIframeLoad("no_delegated_install", todo, next);
   document.getElementById("no_delegated_install").contentWindow.postMessage("mgmt.event_error", '*');
 }
 
+function uninstall_apps(next) {
+  debug("in " + arguments.callee.name);
+  var appURL = SERVERS['bad_content_type'];
+  uninstall(appURL, ok, function() {
+    appURL = SERVERS['no_delegated_install'];
+    uninstall(appURL, ok, function() { next(); });
+  });
+}
+
 </script> 
 
 </window>
 
--- a/dom/tests/mochitest/webapps/test_install_receipts.xul
+++ b/dom/tests/mochitest/webapps/test_install_receipts.xul
@@ -17,26 +17,20 @@
   <!-- test results are displayed in the html:body -->
   <body xmlns="http://www.w3.org/1999/xhtml">
   <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=741549"
      target="_blank">Mozilla Bug 741549</a>
   </body>
 
 <script> 
 
-steps = [setUp, install_super_crazy, tearDown];
+steps = [install_super_crazy, uninstall_super_crazy, tearDown];
 
 runAll(steps);
 
-function setUp(next) { 
-  debug("in " + arguments.callee.name);
-  uninstallAll(next);
-}
-
-
 function install_super_crazy(next)  {
   debug("in " + arguments.callee.name);
   var appURL = SERVERS['super_crazy'];
   var pending = navigator.mozApps.install(appURL, {receipts: ["a",0, true,false,null,undefined,{one:1},{nest:{ed:"hi"}},NaN,Infinity]});
   pending.onsuccess = function ()  {
     var receipts = pending.result.receipts; 
     ok(receipts[0] == "a", receipts[0]);
     ok(receipts[1] == 0, receipts[1]);
@@ -48,12 +42,18 @@ function install_super_crazy(next)  {
     ok(receipts[7].nest.ed == "hi", receipts[7].nest.ed);
     todo(receipts[8] == NaN, receipts[8]);
     todo(receipts[9] == Infinity, receipts[9]);
  
     next();
   };
 }
 
+function uninstall_super_crazy(next)  {
+  debug("in " + arguments.callee.name);
+  var appURL = SERVERS['super_crazy'];
+  uninstall(appURL, ok, function() { next(); });
+}
+
 </script> 
 
 </window>
 
--- a/dom/tests/mochitest/webapps/test_install_utf8.xul
+++ b/dom/tests/mochitest/webapps/test_install_utf8.xul
@@ -17,52 +17,43 @@
   <!-- test results are displayed in the html:body -->
   <body xmlns="http://www.w3.org/1999/xhtml">
   <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=741549"
      target="_blank">Mozilla Bug 741549</a>
   </body>
 
 <script> 
 
-steps = [setUp, verify_no_apps, get_installed_returns_nothing, install_bom, tearDown];
+steps = [get_installed_returns_nothing, install_bom, uninstall_bom, tearDown];
 
 runAll(steps);
 
-function setUp(next) { 
-  debug("in " + arguments.callee.name);
-  uninstallAll(next);
-}
-
-function verify_no_apps(next)  {
-  debug("in " + arguments.callee.name);
-  mozAppscb(navigator.mozApps.mgmt.getAll(), 
-            [{}],
-            "success",
-            ok,
-            next);
-}
-
 function get_installed_returns_nothing(next) {
   debug("in " + arguments.callee.name);
-  mozAppscb(navigator.mozApps.getInstalled(), 
-            [{}],
-            "success",
-            ok, 
-            next);
+  navigator.mozApps.getInstalled().onsuccess = function() {
+    is(this.result.length, 0, "should get no installed app");
+    next();
+  };
 }
 
 function install_bom(next)  {
   debug("in " + arguments.callee.name);
   var appURL = SERVERS['manifest_with_bom'];
   var pending = navigator.mozApps.install(appURL, null);
   pending.onsuccess = function()  {
      var name = pending.result.manifest.name;
      var description = pending.result.manifest.description;
      ok(name == "TheBOM  ゲゴケ゚セニツ゚ヅヂチ", name);
      ok(description == "This App is THE BOM, yo. ヅヂチ", description);
      next();
   };
 }
 
+function uninstall_bom(next)  {
+  debug("in " + arguments.callee.name);
+  var appURL = SERVERS['manifest_with_bom'];
+  uninstall(appURL, ok, function() { next(); });
+}
+
 </script> 
 
 </window>
 
--- a/dom/workers/Worker.cpp
+++ b/dom/workers/Worker.cpp
@@ -228,27 +228,29 @@ private:
   {
     return ConstructInternal(aCx, aArgc, aVp, false, Class());
   }
 
   static void
   Finalize(JSFreeOp* aFop, JSObject* aObj)
   {
     JS_ASSERT(JS_GetClass(aObj) == Class());
-    WorkerPrivate* worker = UnwrapDOMObject<WorkerPrivate>(aObj);
+    WorkerPrivate* worker =
+      UnwrapDOMObject<WorkerPrivate>(aObj, eRegularDOMObject);
     if (worker) {
       worker->_finalize(aFop);
     }
   }
 
   static void
   Trace(JSTracer* aTrc, JSObject* aObj)
   {
     JS_ASSERT(JS_GetClass(aObj) == Class());
-    WorkerPrivate* worker = UnwrapDOMObject<WorkerPrivate>(aObj);
+    WorkerPrivate* worker =
+      UnwrapDOMObject<WorkerPrivate>(aObj, eRegularDOMObject);
     if (worker) {
       worker->_trace(aTrc);
     }
   }
 
   static JSBool
   Terminate(JSContext* aCx, unsigned aArgc, jsval* aVp)
   {
@@ -298,19 +300,23 @@ DOMJSClass Worker::sClass = {
   {
     "Worker",
     JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(1) |
     JSCLASS_IMPLEMENTS_BARRIERS,
     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
     NULL, NULL, NULL, NULL, Trace
   },
-  { prototypes::id::EventTarget_workers, prototypes::id::_ID_Count,
-    prototypes::id::_ID_Count },
-  -1, false, &sNativePropertyHooks
+  {
+    { prototypes::id::EventTarget_workers, prototypes::id::_ID_Count,
+      prototypes::id::_ID_Count },
+    false,
+    &sNativePropertyHooks
+  },
+  -1
 };
 
 JSPropertySpec Worker::sProperties[] = {
   { sEventStrings[STRING_onerror], STRING_onerror, PROPERTY_FLAGS,
     JSOP_WRAPPER(GetEventListener), JSOP_WRAPPER(SetEventListener) },
   { sEventStrings[STRING_onmessage], STRING_onmessage, PROPERTY_FLAGS,
     JSOP_WRAPPER(GetEventListener), JSOP_WRAPPER(SetEventListener) },
   { 0, 0, 0, JSOP_NULLWRAPPER, JSOP_NULLWRAPPER }
@@ -371,44 +377,46 @@ private:
   ~ChromeWorker();
 
   static WorkerPrivate*
   GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName)
   {
     if (aObj) {
       JSClass* classPtr = JS_GetClass(aObj);
       if (classPtr == Class()) {
-        return UnwrapDOMObject<WorkerPrivate>(aObj);
+        return UnwrapDOMObject<WorkerPrivate>(aObj, eRegularDOMObject);
       }
     }
 
     return Worker::GetInstancePrivate(aCx, aObj, aFunctionName);
   }
 
   static JSBool
   Construct(JSContext* aCx, unsigned aArgc, jsval* aVp)
   {
     return ConstructInternal(aCx, aArgc, aVp, true, Class());
   }
 
   static void
   Finalize(JSFreeOp* aFop, JSObject* aObj)
   {
     JS_ASSERT(JS_GetClass(aObj) == Class());
-    WorkerPrivate* worker = UnwrapDOMObject<WorkerPrivate>(aObj);
+    WorkerPrivate* worker =
+      UnwrapDOMObject<WorkerPrivate>(aObj, eRegularDOMObject);
     if (worker) {
       worker->_finalize(aFop);
     }
   }
 
   static void
   Trace(JSTracer* aTrc, JSObject* aObj)
   {
     JS_ASSERT(JS_GetClass(aObj) == Class());
-    WorkerPrivate* worker = UnwrapDOMObject<WorkerPrivate>(aObj);
+    WorkerPrivate* worker =
+      UnwrapDOMObject<WorkerPrivate>(aObj, eRegularDOMObject);
     if (worker) {
       worker->_trace(aTrc);
     }
   }
 };
 
 MOZ_STATIC_ASSERT(prototypes::MaxProtoChainLength == 3,
                   "The MaxProtoChainLength must match our manual DOMJSClasses");
@@ -418,28 +426,32 @@ MOZ_STATIC_ASSERT(prototypes::MaxProtoCh
 DOMJSClass ChromeWorker::sClass = {
   { "ChromeWorker",
     JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(1) |
     JSCLASS_IMPLEMENTS_BARRIERS,
     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
     NULL, NULL, NULL, NULL, Trace,
   },
-  { prototypes::id::EventTarget_workers, prototypes::id::_ID_Count,
-    prototypes::id::_ID_Count },
-  -1, false, &sNativePropertyHooks
+  {
+    { prototypes::id::EventTarget_workers, prototypes::id::_ID_Count,
+      prototypes::id::_ID_Count },
+    false,
+    &sNativePropertyHooks
+  },
+  -1
 };
 
 WorkerPrivate*
 Worker::GetInstancePrivate(JSContext* aCx, JSObject* aObj,
                            const char* aFunctionName)
 {
   JSClass* classPtr = JS_GetClass(aObj);
   if (classPtr == Class() || classPtr == ChromeWorker::Class()) {
-    return UnwrapDOMObject<WorkerPrivate>(aObj);
+    return UnwrapDOMObject<WorkerPrivate>(aObj, eRegularDOMObject);
   }
 
   JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
                        Class()->name, aFunctionName, classPtr->name);
   return NULL;
 }
 
 } // anonymous namespace
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -763,17 +763,18 @@ private:
     return true;
   }
 
   static DedicatedWorkerGlobalScope*
   GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName)
   {
     JSClass* classPtr = JS_GetClass(aObj);
     if (classPtr == Class()) {
-      return UnwrapDOMObject<DedicatedWorkerGlobalScope>(aObj);
+      return UnwrapDOMObject<DedicatedWorkerGlobalScope>(aObj,
+                                                         eRegularDOMObject);
     }
 
     JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
                          JSMSG_INCOMPATIBLE_PROTO, Class()->name, aFunctionName,
                          classPtr->name);
     return NULL;
   }
 
@@ -798,29 +799,29 @@ private:
     return true;
   }
 
   static void
   Finalize(JSFreeOp* aFop, JSObject* aObj)
   {
     JS_ASSERT(JS_GetClass(aObj) == Class());
     DedicatedWorkerGlobalScope* scope =
-      UnwrapDOMObject<DedicatedWorkerGlobalScope>(aObj);
+      UnwrapDOMObject<DedicatedWorkerGlobalScope>(aObj, eRegularDOMObject);
     if (scope) {
       DestroyProtoOrIfaceCache(aObj);
       scope->_finalize(aFop);
     }
   }
 
   static void
   Trace(JSTracer* aTrc, JSObject* aObj)
   {
     JS_ASSERT(JS_GetClass(aObj) == Class());
     DedicatedWorkerGlobalScope* scope =
-      UnwrapDOMObject<DedicatedWorkerGlobalScope>(aObj);
+      UnwrapDOMObject<DedicatedWorkerGlobalScope>(aObj, eRegularDOMObject);
     if (scope) {
       mozilla::dom::TraceProtoOrIfaceCache(aTrc, aObj);
       scope->_trace(aTrc);
     }
   }
 
   static JSBool
   PostMessage(JSContext* aCx, unsigned aArgc, jsval* aVp)
@@ -854,19 +855,23 @@ DOMJSClass DedicatedWorkerGlobalScope::s
   {
     "DedicatedWorkerGlobalScope",
     JSCLASS_DOM_GLOBAL | JSCLASS_IS_DOMJSCLASS | JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(3) | JSCLASS_NEW_RESOLVE,
     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     JS_EnumerateStub, reinterpret_cast<JSResolveOp>(Resolve), JS_ConvertStub,
     Finalize, NULL, NULL, NULL, NULL, Trace
   },
-  { prototypes::id::EventTarget_workers, prototypes::id::_ID_Count,
-    prototypes::id::_ID_Count },
-  -1, false, &sNativePropertyHooks
+  {
+    { prototypes::id::EventTarget_workers, prototypes::id::_ID_Count,
+      prototypes::id::_ID_Count },
+    false,
+    &sNativePropertyHooks
+  },
+  -1
 };
 
 JSPropertySpec DedicatedWorkerGlobalScope::sProperties[] = {
   { sEventStrings[STRING_onmessage], STRING_onmessage, PROPERTY_FLAGS,
     JSOP_WRAPPER(GetEventListener), JSOP_WRAPPER(SetEventListener) },
   { 0, 0, 0, JSOP_NULLWRAPPER, JSOP_NULLWRAPPER }
 };
 
@@ -885,17 +890,17 @@ WorkerGlobalScope::GetInstancePrivate(JS
 {
   JSClass* classPtr = JS_GetClass(aObj);
 
   // We can only make DedicatedWorkerGlobalScope, not WorkerGlobalScope, so this
   // should never happen.
   JS_ASSERT(classPtr != Class());
 
   if (classPtr == DedicatedWorkerGlobalScope::Class()) {
-    return UnwrapDOMObject<DedicatedWorkerGlobalScope>(aObj);
+    return UnwrapDOMObject<DedicatedWorkerGlobalScope>(aObj, eRegularDOMObject);
   }
 
   JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
                        sClass.name, aFunctionName, classPtr->name);
   return NULL;
 }
 
 } /* anonymous namespace */
--- a/gfx/layers/opengl/LayerManagerOGLShaders.h
+++ b/gfx/layers/opengl/LayerManagerOGLShaders.h
@@ -228,42 +228,43 @@ void main()\n\
 vec2 maskCoords = vMaskCoord.xy / vMaskCoord.z;\n\
 float mask = texture2D(uMaskTexture, maskCoords).r;\n\
 \n\
 gl_FragColor = texture2D(uTexture, vTexCoord) * uLayerOpacity * mask;\n\
 }\n\
 ";
 
 static const char sRGBATextureLayerExternalFS[] = "/* sRGBATextureLayerExternalFS */\n\
+#extension GL_OES_EGL_image_external : require\n\
 /* Fragment Shader */\n\
 #ifdef GL_ES\n\
 precision lowp float;\n\
 #endif\n\
 \n\
 #ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
 #endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
-#extension GL_OES_EGL_image_external : require\n\
 uniform samplerExternalOES uTexture;\n\
 uniform mat4 uTextureTransform;\n\
 void main()\n\
 {\n\
 float mask = 1.0;\n\
 \n\
 gl_FragColor = texture2D(uTexture, (uTextureTransform * vec4(vTexCoord.x, vTexCoord.y, 0.0, 1.0)).xy) * uLayerOpacity * mask;\n\
 }\n\
 ";
 
 static const char sRGBATextureLayerExternalMaskFS[] = "/* sRGBATextureLayerExternalMaskFS */\n\
+#extension GL_OES_EGL_image_external : require\n\
 /* Fragment Shader */\n\
 #ifdef GL_ES\n\
 precision lowp float;\n\
 #endif\n\
 \n\
 #ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
 #endif\n\
@@ -271,28 +272,28 @@ uniform float uLayerOpacity;\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 varying vec2 vMaskCoord;\n\
 uniform sampler2D uMaskTexture;\n\
 \n\
-#extension GL_OES_EGL_image_external : require\n\
 uniform samplerExternalOES uTexture;\n\
 uniform mat4 uTextureTransform;\n\
 void main()\n\
 {\n\
 float mask = texture2D(uMaskTexture, vMaskCoord).r;\n\
 \n\
 gl_FragColor = texture2D(uTexture, (uTextureTransform * vec4(vTexCoord.x, vTexCoord.y, 0.0, 1.0)).xy) * uLayerOpacity * mask;\n\
 }\n\
 ";
 
 static const char sRGBATextureLayerExternalMask3DFS[] = "/* sRGBATextureLayerExternalMask3DFS */\n\
+#extension GL_OES_EGL_image_external : require\n\
 /* Fragment Shader */\n\
 #ifdef GL_ES\n\
 precision lowp float;\n\
 #endif\n\
 \n\
 #ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
 #endif\n\
@@ -300,17 +301,16 @@ uniform float uLayerOpacity;\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 varying vec3 vMaskCoord;\n\
 uniform sampler2D uMaskTexture;\n\
 \n\
-#extension GL_OES_EGL_image_external : require\n\
 uniform samplerExternalOES uTexture;\n\
 uniform mat4 uTextureTransform;\n\
 void main()\n\
 {\n\
 vec2 maskCoords = vMaskCoord.xy / vMaskCoord.z;\n\
 float mask = texture2D(uMaskTexture, maskCoords).r;\n\
 \n\
 gl_FragColor = texture2D(uTexture, (uTextureTransform * vec4(vTexCoord.x, vTexCoord.y, 0.0, 1.0)).xy) * uLayerOpacity * mask;\n\
--- a/gfx/layers/opengl/LayerManagerOGLShaders.txt
+++ b/gfx/layers/opengl/LayerManagerOGLShaders.txt
@@ -208,18 +208,20 @@ void main()
 {
 $FRAGMENT_CALC_MASK<mask>$
   gl_FragColor = texture2D(uTexture, vTexCoord) * uLayerOpacity * mask;
 }
 @end
 
 // Single texture in RGBA format for use with GL_TEXTURE_EXTERNAL_OES
 @shader sRGBATextureLayerExternal<mask:,Mask,Mask3D>FS
+#extension GL_OES_EGL_image_external : require
+
 $LAYER_FRAGMENT<mask>$
-#extension GL_OES_EGL_image_external : require
+
 uniform samplerExternalOES uTexture;
 uniform mat4 uTextureTransform;
 
 void main()
 {
 $FRAGMENT_CALC_MASK<mask>$
   gl_FragColor = texture2D(uTexture, (uTextureTransform * vec4(vTexCoord.x, vTexCoord.y, 0.0, 1.0)).xy) * uLayerOpacity * mask;
 }
--- a/gfx/thebes/gfxAndroidPlatform.cpp
+++ b/gfx/thebes/gfxAndroidPlatform.cpp
@@ -1,27 +1,31 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "base/basictypes.h"
+
 #include "gfxAndroidPlatform.h"
 #include "mozilla/gfx/2D.h"
 
 #include "gfxFT2FontList.h"
 #include "gfxImageSurface.h"
+#include "mozilla/dom/ContentChild.h"
 #include "nsXULAppAPI.h"
 #include "nsIScreen.h"
 #include "nsIScreenManager.h"
 
 #include "cairo.h"
 
 #include "ft2build.h"
 #include FT_FREETYPE_H
 using namespace mozilla;
+using namespace mozilla::dom;
 using namespace mozilla::gfx;
 
 static FT_Library gPlatformFTLibrary = NULL;
 
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoFonts" , ## args)
 
 gfxAndroidPlatform::gfxAndroidPlatform()
 {
@@ -185,25 +189,21 @@ gfxAndroidPlatform::FontHintingEnabled()
     // On android-java, we currently only use gecko to render web
     // content that can always be be non-reflow-zoomed.  So turn off
     // hinting.
     // 
     // XXX when gecko-android-java is used as an "app runtime", we'll
     // want to re-enable hinting.
     return false;
 #else
-    // Otherwise, if we're in a content process, assume we don't want
-    // hinting.
-    //
-    // XXX when we use content processes to load "apps", we'll want to
-    // configure this dynamically based on whether we're an "app
-    // content process" or a "browser content process".  The former
-    // wants hinting, the latter doesn't since it might be
-    // non-reflow-zoomed.
-    return (XRE_GetProcessType() != GeckoProcessType_Content);
+    // Otherwise, enable hinting unless we're in a content process
+    // that might be used for non-reflowing zoom.
+    return (XRE_GetProcessType() != GeckoProcessType_Content ||
+            (ContentChild::GetSingleton()->IsForApp() &&
+             !ContentChild::GetSingleton()->IsForBrowser()));
 #endif //  MOZ_USING_ANDROID_JAVA_WIDGETS
 }
 
 int
 gfxAndroidPlatform::GetScreenDepth() const
 {
     return mScreenDepth;
 }
--- a/image/decoders/icon/android/nsIconChannel.cpp
+++ b/image/decoders/icon/android/nsIconChannel.cpp
@@ -4,16 +4,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <stdlib.h>
 #include "mozilla/dom/ContentChild.h"
 #include "nsIURL.h"
 #include "nsXULAppAPI.h"
 #include "AndroidBridge.h"
 #include "nsIconChannel.h"
+#include "nsIStringStream.h"
+#include "nsNetUtil.h"
 
 NS_IMPL_ISUPPORTS2(nsIconChannel,
                    nsIRequest,
                    nsIChannel)
 
 using namespace mozilla;
 using mozilla::dom::ContentChild;
 
--- a/image/src/imgLoader.cpp
+++ b/image/src/imgLoader.cpp
@@ -59,54 +59,16 @@
 #include "nsIContentSecurityPolicy.h"
 #include "nsIChannelPolicy.h"
 
 #include "nsContentUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::image;
 
-#if defined(DEBUG_pavlov) || defined(DEBUG_timeless)
-#include "nsISimpleEnumerator.h"
-#include "nsXPCOM.h"
-#include "nsISupportsPrimitives.h"
-#include "nsXPIDLString.h"
-#include "nsComponentManagerUtils.h"
-
-
-static void PrintImageDecoders()
-{
-  nsCOMPtr<nsIComponentRegistrar> compMgr;
-  if (NS_FAILED(NS_GetComponentRegistrar(getter_AddRefs(compMgr))) || !compMgr)
-    return;
-  nsCOMPtr<nsISimpleEnumerator> enumer;
-  if (NS_FAILED(compMgr->EnumerateContractIDs(getter_AddRefs(enumer))) || !enumer)
-    return;
-  
-  nsCString str;
-  nsCOMPtr<nsISupports> s;
-  bool more = false;
-  while (NS_SUCCEEDED(enumer->HasMoreElements(&more)) && more) {
-    enumer->GetNext(getter_AddRefs(s));
-    if (s) {
-      nsCOMPtr<nsISupportsCString> ss(do_QueryInterface(s));
-
-      nsCAutoString xcs;
-      ss->GetData(xcs);
-
-      NS_NAMED_LITERAL_CSTRING(decoderContract, "@mozilla.org/image/decoder;3?type=");
-
-      if (StringBeginsWith(xcs, decoderContract)) {
-        printf("Have decoder for mime type: %s\n", xcs.get()+decoderContract.Length());
-      }
-    }
-  }
-}
-#endif
-
 NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(ImagesMallocSizeOf, "images")
 
 class imgMemoryReporter MOZ_FINAL :
   public nsIMemoryMultiReporter
 {
 public:
   imgMemoryReporter()
   {
rename from ipc/glue/IPCSerializableParams.ipdlh
rename to ipc/glue/InputStreamParams.ipdlh
--- a/ipc/glue/IPCSerializableParams.ipdlh
+++ b/ipc/glue/InputStreamParams.ipdlh
@@ -1,12 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+include "IPC/IPCMessageUtils.h";
+
+using mozilla::void_t;
+
 namespace mozilla {
 namespace ipc {
 
 struct StringInputStreamParams
 {
   nsCString data;
 };
 
@@ -32,13 +36,36 @@ struct MultiplexInputStreamParams
   bool startedReadingCurrent;
 };
 
 union InputStreamParams
 {
   StringInputStreamParams;
   FileInputStreamParams;
   PartialFileInputStreamParams;
+  BufferedInputStreamParams;
+  MIMEInputStreamParams;
   MultiplexInputStreamParams;
 };
 
+union OptionalInputStreamParams
+{
+  void_t;
+  InputStreamParams;
+};
+
+struct BufferedInputStreamParams
+{
+  OptionalInputStreamParams optionalStream;
+  uint32_t bufferSize;
+};
+
+struct MIMEInputStreamParams
+{
+  OptionalInputStreamParams optionalStream;
+  nsCString headers;
+  nsCString contentLength;
+  bool startedReading;
+  bool addContentLength;
+};
+
 } // namespace ipc
 } // namespace mozilla
--- a/ipc/glue/InputStreamUtils.cpp
+++ b/ipc/glue/InputStreamUtils.cpp
@@ -5,75 +5,141 @@
 #include "InputStreamUtils.h"
 
 #include "nsIIPCSerializableInputStream.h"
 
 #include "mozilla/Assertions.h"
 #include "nsComponentManagerUtils.h"
 #include "nsDebug.h"
 #include "nsID.h"
+#include "nsMIMEInputStream.h"
 #include "nsMultiplexInputStream.h"
 #include "nsNetCID.h"
 #include "nsStringStream.h"
 #include "nsThreadUtils.h"
 
 using namespace mozilla::ipc;
 
 namespace {
 
 NS_DEFINE_CID(kStringInputStreamCID, NS_STRINGINPUTSTREAM_CID);
 NS_DEFINE_CID(kFileInputStreamCID, NS_LOCALFILEINPUTSTREAM_CID);
 NS_DEFINE_CID(kPartialFileInputStreamCID, NS_PARTIALLOCALFILEINPUTSTREAM_CID);
+NS_DEFINE_CID(kBufferedInputStreamCID, NS_BUFFEREDINPUTSTREAM_CID);
+NS_DEFINE_CID(kMIMEInputStreamCID, NS_MIMEINPUTSTREAM_CID);
 NS_DEFINE_CID(kMultiplexInputStreamCID, NS_MULTIPLEXINPUTSTREAM_CID);
 
 } // anonymous namespace
 
 namespace mozilla {
 namespace ipc {
 
+void
+SerializeInputStream(nsIInputStream* aInputStream,
+                     InputStreamParams& aParams)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aInputStream);
+
+  nsCOMPtr<nsIIPCSerializableInputStream> serializable =
+    do_QueryInterface(aInputStream);
+  if (!serializable) {
+    MOZ_NOT_REACHED("Input stream is not serializable!");
+  }
+
+  serializable->Serialize(aParams);
+
+  if (aParams.type() == InputStreamParams::T__None) {
+    MOZ_NOT_REACHED("Serialize failed!");
+  }
+}
+
+void
+SerializeInputStream(nsIInputStream* aInputStream,
+                     OptionalInputStreamParams& aParams)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (aInputStream) {
+    InputStreamParams params;
+    SerializeInputStream(aInputStream, params);
+    aParams = params;
+  }
+  else {
+    aParams = mozilla::void_t();
+  }
+}
+
 already_AddRefed<nsIInputStream>
 DeserializeInputStream(const InputStreamParams& aParams)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsCOMPtr<nsIIPCSerializableInputStream> serializable;
 
   switch (aParams.type()) {
-    case InputStreamParams::T__None:
-      NS_WARNING("This union has no type!");
-      return nullptr;
-
     case InputStreamParams::TStringInputStreamParams:
       serializable = do_CreateInstance(kStringInputStreamCID);
       break;
 
     case InputStreamParams::TFileInputStreamParams:
       serializable = do_CreateInstance(kFileInputStreamCID);
       break;
 
     case InputStreamParams::TPartialFileInputStreamParams:
       serializable = do_CreateInstance(kPartialFileInputStreamCID);
       break;
 
+    case InputStreamParams::TBufferedInputStreamParams:
+      serializable = do_CreateInstance(kBufferedInputStreamCID);
+      break;
+
+    case InputStreamParams::TMIMEInputStreamParams:
+      serializable = do_CreateInstance(kMIMEInputStreamCID);
+      break;
+
     case InputStreamParams::TMultiplexInputStreamParams:
       serializable = do_CreateInstance(kMultiplexInputStreamCID);
       break;
 
     default:
-      NS_WARNING("Unknown params!");
+      MOZ_ASSERT(false, "Unknown params!");
       return nullptr;
   }
 
   MOZ_ASSERT(serializable);
 
   if (!serializable->Deserialize(aParams)) {
-    NS_WARNING("Deserialize failed!");
+    MOZ_ASSERT(false, "Deserialize failed!");
     return nullptr;
   }
 
   nsCOMPtr<nsIInputStream> stream = do_QueryInterface(serializable);
   MOZ_ASSERT(stream);
 
   return stream.forget();
 }
 
+already_AddRefed<nsIInputStream>
+DeserializeInputStream(const OptionalInputStreamParams& aParams)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsCOMPtr<nsIInputStream> stream;
+
+  switch (aParams.type()) {
+    case OptionalInputStreamParams::Tvoid_t:
+      // Leave stream null.
+      break;
+
+    case OptionalInputStreamParams::TInputStreamParams:
+      stream = DeserializeInputStream(aParams.get_InputStreamParams());
+      break;
+
+    default:
+      MOZ_ASSERT(false, "Unknown params!");
+  }
+
+  return stream.forget();
+}
+
 } // namespace ipc
 } // namespace mozilla
--- a/ipc/glue/InputStreamUtils.h
+++ b/ipc/glue/InputStreamUtils.h
@@ -1,21 +1,32 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_ipc_InputStreamUtils_h
 #define mozilla_ipc_InputStreamUtils_h
 
-#include "mozilla/ipc/IPCSerializableParams.h"
+#include "mozilla/ipc/InputStreamParams