Merge m-c to birch.
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 07 May 2013 08:35:02 -0400
changeset 141948 41ff3b67b69232297191c8f8ef78e5facc1c1d19
parent 141947 2188061519bb66a2cd14da4038e5519de9573846 (current diff)
parent 141938 53231b5a86e4f31bde8cecd11ff7c2aca116d4d7 (diff)
child 141949 7d7d3fb2bdf5c9be82279dba82c71d7ba227df10
child 141954 89206d922d851906006f1e3a80dc9f4e84519da9
child 142060 b91ba4c4a4a58da8859289024bab4e3a4f70f3ad
push id2579
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 18:52:47 +0000
treeherdermozilla-beta@b69b7de8a05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone23.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to birch.
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1104,19 +1104,16 @@ pref("devtools.chrome.enabled", false);
 pref("devtools.theme", "light");
 
 // Display the introductory text
 pref("devtools.gcli.hideIntro", false);
 
 // How eager are we to show help: never=1, sometimes=2, always=3
 pref("devtools.gcli.eagerHelper", 2);
 
-// Do we allow the 'pref set' command
-pref("devtools.gcli.allowSet", false);
-
 // Remember the Web Console filters
 pref("devtools.webconsole.filter.network", true);
 pref("devtools.webconsole.filter.networkinfo", true);
 pref("devtools.webconsole.filter.csserror", true);
 pref("devtools.webconsole.filter.cssparser", true);
 pref("devtools.webconsole.filter.exception", true);
 pref("devtools.webconsole.filter.jswarn", true);
 pref("devtools.webconsole.filter.error", true);
--- a/browser/devtools/debugger/DebuggerUI.jsm
+++ b/browser/devtools/debugger/DebuggerUI.jsm
@@ -4,17 +4,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/. */
 "use strict";
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
-const DBG_XUL = "chrome://browser/content/debugger.xul";
+const DBG_XUL = "chrome://browser/content/devtools/debugger.xul";
 const DBG_STRINGS_URI = "chrome://browser/locale/devtools/debugger.properties";
 const CHROME_DEBUGGER_PROFILE_NAME = "-chrome-debugger";
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this,
   "DebuggerServer", "resource://gre/modules/devtools/dbg-server.jsm");
 
--- a/browser/devtools/debugger/debugger.xul
+++ b/browser/devtools/debugger/debugger.xul
@@ -1,24 +1,24 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- 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/. -->
 <?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/content/devtools/widgets.css" type="text/css"?>
-<?xml-stylesheet href="chrome://browser/content/debugger.css" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/content/devtools/debugger.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/common.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/widgets.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/debugger.css" type="text/css"?>
 <!DOCTYPE window [
   <!ENTITY % debuggerDTD SYSTEM "chrome://browser/locale/devtools/debugger.dtd">
   %debuggerDTD;
 ]>
 <?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
-<?xul-overlay href="chrome://browser/content/source-editor-overlay.xul"?>
+<?xul-overlay href="chrome://browser/content/devtools/source-editor-overlay.xul"?>
 
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <script type="text/javascript" src="chrome://global/content/globalOverlay.js"/>
   <script type="text/javascript" src="debugger-controller.js"/>
   <script type="text/javascript" src="debugger-view.js"/>
   <script type="text/javascript" src="debugger-toolbar.js"/>
   <script type="text/javascript" src="debugger-panes.js"/>
 
--- a/browser/devtools/debugger/test/Makefile.in
+++ b/browser/devtools/debugger/test/Makefile.in
@@ -56,16 +56,17 @@ MOCHITEST_BROWSER_TESTS = \
 	browser_dbg_stack-01.js \
 	browser_dbg_stack-02.js \
 	browser_dbg_stack-03.js \
 	browser_dbg_stack-04.js \
 	browser_dbg_stack-05.js \
 	browser_dbg_location-changes.js \
 	browser_dbg_location-changes-new.js \
 	browser_dbg_location-changes-blank.js \
+	browser_dbg_location-changes-bp.js \
 	browser_dbg_sources-cache.js \
 	browser_dbg_scripts-switching.js \
 	browser_dbg_scripts-sorting.js \
 	browser_dbg_scripts-searching-01.js \
 	browser_dbg_scripts-searching-02.js \
 	browser_dbg_scripts-searching-03.js \
 	browser_dbg_scripts-searching-04.js \
 	browser_dbg_scripts-searching-05.js \
@@ -128,13 +129,15 @@ MOCHITEST_BROWSER_PAGES = \
 	browser_dbg_function-search-02.html \
 	test-function-search-01.js \
 	test-function-search-02.js \
 	test-function-search-03.js \
 	binary_search.html \
 	binary_search.coffee \
 	binary_search.js \
 	binary_search.map \
+	test-location-changes-bp.js \
+	test-location-changes-bp.html \
 	$(NULL)
 
 MOCHITEST_BROWSER_FILES_PARTS = MOCHITEST_BROWSER_TESTS MOCHITEST_BROWSER_PAGES
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_location-changes-bp.js
@@ -0,0 +1,163 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Make sure that reloading a page with a breakpoint set does not cause it to
+ * fire more than once.
+ */
+
+const TAB_URL = EXAMPLE_URL + "test-location-changes-bp.html";
+const SCRIPT_URL = EXAMPLE_URL + "test-location-changes-bp.js";
+
+var gPane = null;
+var gTab = null;
+var gDebuggee = null;
+var gDebugger = null;
+var sourcesShown = false;
+var tabNavigated = false;
+
+function test()
+{
+  debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
+    gTab = aTab;
+    gDebuggee = aDebuggee;
+    gPane = aPane;
+    gDebugger = gPane.panelWin;
+
+    testAddBreakpoint();
+  });
+}
+
+function testAddBreakpoint()
+{
+  let controller = gDebugger.DebuggerController;
+  controller.activeThread.addOneTimeListener("framesadded", function() {
+    Services.tm.currentThread.dispatch({ run: function() {
+
+      var frames = gDebugger.DebuggerView.StackFrames._container._list;
+
+      is(controller.activeThread.state, "paused",
+         "The debugger statement was reached.");
+
+      is(frames.querySelectorAll(".dbg-stackframe").length, 1,
+         "Should have one frame.");
+
+      gPane.addBreakpoint({ url: SCRIPT_URL, line: 5 }, testResume);
+    }}, 0);
+  });
+
+  gDebuggee.runDebuggerStatement();
+}
+
+function testResume()
+{
+  is(gDebugger.DebuggerController.activeThread.state, "paused",
+    "The breakpoint wasn't hit yet.");
+
+  let thread = gDebugger.DebuggerController.activeThread;
+  thread.addOneTimeListener("resumed", function() {
+    thread.addOneTimeListener("paused", function() {
+      executeSoon(testBreakpointHit);
+    });
+
+    EventUtils.sendMouseEvent({ type: "click" },
+      content.document.querySelector("button"));
+  });
+
+  thread.resume();
+}
+
+function testBreakpointHit()
+{
+  is(gDebugger.DebuggerController.activeThread.state, "paused",
+    "The breakpoint was hit.");
+
+  let thread = gDebugger.DebuggerController.activeThread;
+  thread.addOneTimeListener("paused", function test(aEvent, aPacket) {
+    thread.addOneTimeListener("resumed", function() {
+      executeSoon(testReloadPage);
+    });
+
+    is(aPacket.why.type, "debuggerStatement", "Execution has advanced to the next line.");
+    isnot(aPacket.why.type, "breakpoint", "No ghost breakpoint was hit.");
+    thread.resume();
+  });
+
+  thread.resume();
+}
+
+function testReloadPage()
+{
+  let controller = gDebugger.DebuggerController;
+  controller._target.once("navigate", function onTabNavigated(aEvent, aPacket) {
+    tabNavigated = true;
+    ok(true, "tabNavigated event was fired.");
+    info("Still attached to the tab.");
+    clickAgain();
+  });
+
+  gDebugger.addEventListener("Debugger:SourceShown", function onSourcesShown() {
+    sourcesShown = true;
+    gDebugger.removeEventListener("Debugger:SourceShown", onSourcesShown);
+    clickAgain();
+  });
+
+  content.location.reload();
+}
+
+function clickAgain()
+{
+  if (!sourcesShown || !tabNavigated) {
+    return;
+  }
+
+  let controller = gDebugger.DebuggerController;
+  controller.activeThread.addOneTimeListener("framesadded", function() {
+    is(gDebugger.DebuggerController.activeThread.state, "paused",
+      "The breakpoint was hit.");
+
+    let thread = gDebugger.DebuggerController.activeThread;
+    thread.addOneTimeListener("paused", function test(aEvent, aPacket) {
+      thread.addOneTimeListener("resumed", function() {
+        executeSoon(closeDebuggerAndFinish);
+      });
+
+      is(aPacket.why.type, "debuggerStatement", "Execution has advanced to the next line.");
+      isnot(aPacket.why.type, "breakpoint", "No ghost breakpoint was hit.");
+      thread.resume();
+    });
+
+    thread.resume();
+  });
+
+  EventUtils.sendMouseEvent({ type: "click" },
+    content.document.querySelector("button"));
+}
+
+function testBreakpointHitAfterReload()
+{
+  is(gDebugger.DebuggerController.activeThread.state, "paused",
+    "The breakpoint was hit.");
+
+  let thread = gDebugger.DebuggerController.activeThread;
+  thread.addOneTimeListener("paused", function test(aEvent, aPacket) {
+    thread.addOneTimeListener("resumed", function() {
+      executeSoon(closeDebuggerAndFinish);
+    });
+
+    is(aPacket.why.type, "debuggerStatement", "Execution has advanced to the next line.");
+    isnot(aPacket.why.type, "breakpoint", "No ghost breakpoint was hit.");
+    thread.resume();
+  });
+
+  thread.resume();
+}
+
+registerCleanupFunction(function() {
+  removeTab(gTab);
+  gPane = null;
+  gTab = null;
+  gDebuggee = null;
+  gDebugger = null;
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/test-location-changes-bp.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset='utf-8'/>
+<script type="text/javascript" src="test-location-changes-bp.js"></script>
+<script type="text/javascript">
+function runDebuggerStatement() {
+  debugger;
+}
+</script>
+</head>
+<body>
+
+<button type="button" onclick="myFunction()">Run</button>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/test-location-changes-bp.js
@@ -0,0 +1,7 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function myFunction() {
+  var a = 1;
+  debugger;
+}
--- a/browser/devtools/framework/gDevTools.jsm
+++ b/browser/devtools/framework/gDevTools.jsm
@@ -187,16 +187,17 @@ this.devtools = {
     this._provider.unload("reload");
     delete this._provider;
     gDevTools._teardown();
     this._chooseProvider();
   },
 };
 
 const FORBIDDEN_IDS = new Set(["toolbox", ""]);
+const MAX_ORDINAL = 99;
 
 /**
  * DevTools is a class that represents a set of developer tools, it holds a
  * set of tools and keeps track of open toolboxes in the browser.
  */
 this.DevTools = function DevTools() {
   this._tools = new Map();     // Map<toolId, tool>
   this._toolboxes = new Map(); // Map<target, toolbox>
@@ -269,28 +270,37 @@ DevTools.prototype = {
     }
     this._tools.delete(toolId);
 
     if (!isQuitApplication) {
       this.emit("tool-unregistered", tool);
     }
   },
 
+  /**
+   * Sorting function used for sorting tools based on their ordinals.
+   */
+  ordinalSort: function DT_ordinalSort(d1, d2) {
+    let o1 = (typeof d1.ordinal == "number") ? d1.ordinal : MAX_ORDINAL;
+    let o2 = (typeof d2.ordinal == "number") ? d2.ordinal : MAX_ORDINAL;
+    return o1 - o2;
+  },
+
   getDefaultTools: function DT_getDefaultTools() {
-    return devtools.defaultTools;
+    return devtools.defaultTools.sort(this.ordinalSort);
   },
 
   getAdditionalTools: function DT_getAdditionalTools() {
     let tools = [];
     for (let [key, value] of this._tools) {
       if (devtools.defaultTools.indexOf(value) == -1) {
         tools.push(value);
       }
     }
-    return tools;
+    return tools.sort(this.ordinalSort);
   },
 
   /**
    * Allow ToolBoxes to get at the list of tools that they should populate
    * themselves with.
    *
    * @return {Map} tools
    *         A map of the the tool definitions registered in this instance
@@ -322,30 +332,22 @@ DevTools.prototype = {
    * Tools have an inherent ordering that can't be represented in a Map so
    * getToolDefinitionArray provides an alternative representation of the
    * definitions sorted by ordinal value.
    *
    * @return {Array} tools
    *         A sorted array of the tool definitions registered in this instance
    */
   getToolDefinitionArray: function DT_getToolDefinitionArray() {
-    const MAX_ORDINAL = 99;
-
     let definitions = [];
     for (let [id, definition] of this.getToolDefinitionMap()) {
       definitions.push(definition);
     }
 
-    definitions.sort(function(d1, d2) {
-      let o1 = (typeof d1.ordinal == "number") ? d1.ordinal : MAX_ORDINAL;
-      let o2 = (typeof d2.ordinal == "number") ? d2.ordinal : MAX_ORDINAL;
-      return o1 - o2;
-    });
-
-    return definitions;
+    return definitions.sort(this.ordinalSort);
   },
 
   /**
    * Show a Toolbox for a target (either by creating a new one, or if a toolbox
    * already exists for the target, by bring to the front the existing one)
    * If |toolId| is specified then the displayed toolbox will have the
    * specified tool selected.
    * If |hostType| is specified then the toolbox will be displayed using the
--- a/browser/devtools/framework/test/browser_toolbox_options.js
+++ b/browser/devtools/framework/test/browser_toolbox_options.js
@@ -81,16 +81,20 @@ function prefChanged(event, data) {
 
 function checkTools() {
   let toolsPref = panelWin.document.querySelectorAll("#default-tools-box > checkbox");
   prefNodes = [];
   index = 0;
   for (let tool of toolsPref) {
     prefNodes.push(tool);
   }
+  // Randomize the order in which we remove the tool and then add them back so
+  // that we get to know if the tabs are correctly placed as per their ordinals.
+  prefNodes = prefNodes.sort(() => Math.random() > 0.5 ? 1: -1);
+
   // Wait for the next turn of the event loop to avoid stack overflow errors.
   executeSoon(toggleTools);
 }
 
 function toggleTools() {
   if (index < prefNodes.length) {
     gDevTools.once("tool-unregistered", checkUnregistered);
     EventUtils.synthesizeMouse(prefNodes[index], 10, 10, {}, panelWin);
@@ -119,17 +123,32 @@ function checkUnregistered(event, data) 
   ok(false, "Something went wrong, " + data.id + " was not unregistered");
   cleanup();
 }
 
 function checkRegistered(event, data) {
   if (data == prefNodes[index - prefNodes.length].getAttribute("id")) {
     ok(true, "Correct tool added back");
     // checking tab on the toolbox
-    ok(doc.getElementById("toolbox-tab-" + data), "Tab added back for " + data);
+    let radio = doc.getElementById("toolbox-tab-" + data);
+    ok(radio, "Tab added back for " + data);
+    if (radio.previousSibling) {
+      ok(+radio.getAttribute("ordinal") >=
+         +radio.previousSibling.getAttribute("ordinal"),
+         "Inserted tab's ordinal is greater than equal to its previous tab." +
+         "Expected " + radio.getAttribute("ordinal") + " >= " +
+         radio.previousSibling.getAttribute("ordinal"));
+    }
+    if (radio.nextSibling) {
+      ok(+radio.getAttribute("ordinal") <
+         +radio.nextSibling.getAttribute("ordinal"),
+         "Inserted tab's ordinal is less than its next tab. Expected " +
+         radio.getAttribute("ordinal") + " < " +
+         radio.nextSibling.getAttribute("ordinal"));
+    }
     index++;
     // Wait for the next turn of the event loop to avoid stack overflow errors.
     executeSoon(toggleTools);
     return;
   }
   ok(false, "Something went wrong, " + data + " was not registered back");
   cleanup();
 }
--- a/browser/devtools/framework/toolbox-options.js
+++ b/browser/devtools/framework/toolbox-options.js
@@ -1,8 +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/. */
+
+"use strict";
 
 const { utils: Cu } = Components;
 const DISABLED_TOOLS = "devtools.toolbox.disabledTools";
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource:///modules/devtools/gDevTools.jsm");
 
 window.addEventListener("load", function onLoad() {
   window.removeEventListener("load", onLoad);
--- a/browser/devtools/framework/toolbox.js
+++ b/browser/devtools/framework/toolbox.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/. */
 
 "use strict";
 
 const {Cc, Ci, Cu} = require("chrome");
-
+const MAX_ORDINAL = 99;
 let Promise = require("sdk/core/promise");
 let EventEmitter = require("devtools/shared/event-emitter");
 
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource:///modules/devtools/gDevTools.jsm");
 
 loader.lazyGetter(this, "Hosts", () => require("devtools/framework/toolbox-hosts").Hosts);
@@ -355,16 +355,20 @@ Toolbox.prototype = {
 
     let id = toolDefinition.id;
 
     let radio = this.doc.createElement("radio");
     radio.className = "toolbox-tab devtools-tab";
     radio.id = "toolbox-tab-" + id;
     radio.setAttribute("flex", "1");
     radio.setAttribute("toolid", id);
+    if (toolDefinition.ordinal == undefined || toolDefinition.ordinal < 0) {
+      toolDefinition.ordinal = MAX_ORDINAL;
+    }
+    radio.setAttribute("ordinal", toolDefinition.ordinal);
     radio.setAttribute("tooltiptext", toolDefinition.tooltip);
 
     radio.addEventListener("command", function(id) {
       this.selectTool(id);
     }.bind(this, id));
 
     if (toolDefinition.icon) {
       let image = this.doc.createElement("image");
@@ -377,18 +381,34 @@ Toolbox.prototype = {
     label.setAttribute("crop", "end");
     label.setAttribute("flex", "1");
 
     let vbox = this.doc.createElement("vbox");
     vbox.className = "toolbox-panel";
     vbox.id = "toolbox-panel-" + id;
 
     radio.appendChild(label);
-    tabs.appendChild(radio);
-    deck.appendChild(vbox);
+
+    // If there is no tab yet, or the ordinal to be added is the largest one.
+    if (tabs.childNodes.length == 0 ||
+        +tabs.lastChild.getAttribute("ordinal") <= toolDefinition.ordinal) {
+      tabs.appendChild(radio);
+      deck.appendChild(vbox);
+    }
+    // else, iterate over all the tabs to get the correct location.
+    else {
+      Array.some(tabs.childNodes, (node, i) => {
+        if (+node.getAttribute("ordinal") > toolDefinition.ordinal) {
+          tabs.insertBefore(radio, node);
+          deck.insertBefore(vbox, deck.childNodes[i + 1]);
+          // + 1 because of options panel.
+          return true;
+        }
+      });
+    }
 
     this._addKeysToWindow();
   },
 
   /**
    * Switch to the tool with the given id
    *
    * @param {string} id
--- a/browser/devtools/jar.mn
+++ b/browser/devtools/jar.mn
@@ -1,68 +1,68 @@
 # 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/.
 
 browser.jar:
-    content/browser/devtools/widgets.css          (shared/widgets/widgets.css)
-    content/browser/devtools/widgets/VariablesView.xul (shared/widgets/VariablesView.xul)
-    content/browser/devtools/markup-view.xhtml    (markupview/markup-view.xhtml)
-    content/browser/devtools/markup-view.css      (markupview/markup-view.css)
-    content/browser/devtools/netmonitor.xul           (netmonitor/netmonitor.xul)
-    content/browser/devtools/netmonitor.css           (netmonitor/netmonitor.css)
-    content/browser/devtools/netmonitor-controller.js (netmonitor/netmonitor-controller.js)
-    content/browser/devtools/netmonitor-view.js       (netmonitor/netmonitor-view.js)
-    content/browser/NetworkPanel.xhtml            (webconsole/NetworkPanel.xhtml)
-    content/browser/devtools/webconsole.js        (webconsole/webconsole.js)
-    content/browser/devtools/webconsole.xul       (webconsole/webconsole.xul)
-*   content/browser/scratchpad.xul                (scratchpad/scratchpad.xul)
-    content/browser/scratchpad.js                 (scratchpad/scratchpad.js)
-    content/browser/splitview.css                 (shared/splitview.css)
-    content/browser/devtools/theme-switching.js   (shared/theme-switching.js)
-    content/browser/styleeditor.xul               (styleeditor/styleeditor.xul)
-    content/browser/styleeditor.css               (styleeditor/styleeditor.css)
-    content/browser/devtools/computedview.xhtml   (styleinspector/computedview.xhtml)
-    content/browser/devtools/cssruleview.xhtml    (styleinspector/cssruleview.xhtml)
-    content/browser/devtools/ruleview.css         (styleinspector/ruleview.css)
-    content/browser/devtools/layoutview/view.js   (layoutview/view.js)
-    content/browser/devtools/layoutview/view.xhtml  (layoutview/view.xhtml)
-    content/browser/devtools/layoutview/view.css  (layoutview/view.css)
-    content/browser/devtools/fontinspector/font-inspector.js    (fontinspector/font-inspector.js)
-    content/browser/devtools/fontinspector/font-inspector.xhtml (fontinspector/font-inspector.xhtml)
-    content/browser/devtools/fontinspector/font-inspector.css   (fontinspector/font-inspector.css)
-    content/browser/orion.js                      (sourceeditor/orion/orion.js)
-*   content/browser/source-editor-overlay.xul     (sourceeditor/source-editor-overlay.xul)
-    content/browser/debugger.xul                  (debugger/debugger.xul)
-    content/browser/debugger.css                  (debugger/debugger.css)
-    content/browser/debugger-controller.js        (debugger/debugger-controller.js)
-    content/browser/debugger-view.js              (debugger/debugger-view.js)
-    content/browser/debugger-toolbar.js           (debugger/debugger-toolbar.js)
-    content/browser/debugger-panes.js             (debugger/debugger-panes.js)
-    content/browser/profiler.xul                  (profiler/profiler.xul)
-    content/browser/devtools/cleopatra.html       (profiler/cleopatra/cleopatra.html)
-    content/browser/devtools/profiler/cleopatra/css/ui.css              (profiler/cleopatra/css/ui.css)
-    content/browser/devtools/profiler/cleopatra/css/tree.css            (profiler/cleopatra/css/tree.css)
-    content/browser/devtools/profiler/cleopatra/css/devtools.css        (profiler/cleopatra/css/devtools.css)
-    content/browser/devtools/profiler/cleopatra/js/strings.js           (profiler/cleopatra/js/strings.js)
-    content/browser/devtools/profiler/cleopatra/js/parser.js            (profiler/cleopatra/js/parser.js)
-    content/browser/devtools/profiler/cleopatra/js/parserWorker.js      (profiler/cleopatra/js/parserWorker.js)
-    content/browser/devtools/profiler/cleopatra/js/tree.js              (profiler/cleopatra/js/tree.js)
-    content/browser/devtools/profiler/cleopatra/js/ui.js                (profiler/cleopatra/js/ui.js)
-    content/browser/devtools/profiler/cleopatra/js/ProgressReporter.js  (profiler/cleopatra/js/ProgressReporter.js)
-    content/browser/devtools/profiler/cleopatra/js/devtools.js          (profiler/cleopatra/js/devtools.js)
-    content/browser/devtools/profiler/cleopatra/images/circlearrow.svg  (profiler/cleopatra/images/circlearrow.svg)
-    content/browser/devtools/profiler/cleopatra/images/noise.png        (profiler/cleopatra/images/noise.png)
-    content/browser/devtools/profiler/cleopatra/images/throbber.svg     (profiler/cleopatra/images/throbber.svg)
-    content/browser/devtools/profiler/cleopatra/images/treetwisty.svg   (profiler/cleopatra/images/treetwisty.svg)
-    content/browser/devtools/commandline.css      (commandline/commandline.css)
-    content/browser/devtools/commandlineoutput.xhtml  (commandline/commandlineoutput.xhtml)
-    content/browser/devtools/commandlinetooltip.xhtml  (commandline/commandlinetooltip.xhtml)
-    content/browser/devtools/framework/toolbox-window.xul    (framework/toolbox-window.xul)
-    content/browser/devtools/framework/toolbox-options.xul   (framework/toolbox-options.xul)
-    content/browser/devtools/framework/toolbox-options.js    (framework/toolbox-options.js)
-*   content/browser/devtools/framework/toolbox.xul           (framework/toolbox.xul)
-    content/browser/devtools/framework/toolbox.css           (framework/toolbox.css)
-    content/browser/devtools/inspector/inspector.xul         (inspector/inspector.xul)
-    content/browser/devtools/inspector/inspector.css         (inspector/inspector.css)
-    content/browser/devtools/connect.xhtml  (framework/connect/connect.xhtml)
-    content/browser/devtools/connect.css    (framework/connect/connect.css)
-    content/browser/devtools/connect.js     (framework/connect/connect.js)
+    content/browser/devtools/widgets.css                               (shared/widgets/widgets.css)
+    content/browser/devtools/widgets/VariablesView.xul                 (shared/widgets/VariablesView.xul)
+    content/browser/devtools/markup-view.xhtml                         (markupview/markup-view.xhtml)
+    content/browser/devtools/markup-view.css                           (markupview/markup-view.css)
+    content/browser/devtools/netmonitor.xul                            (netmonitor/netmonitor.xul)
+    content/browser/devtools/netmonitor.css                            (netmonitor/netmonitor.css)
+    content/browser/devtools/netmonitor-controller.js                  (netmonitor/netmonitor-controller.js)
+    content/browser/devtools/netmonitor-view.js                        (netmonitor/netmonitor-view.js)
+    content/browser/devtools/NetworkPanel.xhtml                        (webconsole/NetworkPanel.xhtml)
+    content/browser/devtools/webconsole.js                             (webconsole/webconsole.js)
+    content/browser/devtools/webconsole.xul                            (webconsole/webconsole.xul)
+*   content/browser/devtools/scratchpad.xul                            (scratchpad/scratchpad.xul)
+    content/browser/devtools/scratchpad.js                             (scratchpad/scratchpad.js)
+    content/browser/devtools/splitview.css                             (shared/splitview.css)
+    content/browser/devtools/theme-switching.js                        (shared/theme-switching.js)
+    content/browser/devtools/styleeditor.xul                           (styleeditor/styleeditor.xul)
+    content/browser/devtools/styleeditor.css                           (styleeditor/styleeditor.css)
+    content/browser/devtools/computedview.xhtml                        (styleinspector/computedview.xhtml)
+    content/browser/devtools/cssruleview.xhtml                         (styleinspector/cssruleview.xhtml)
+    content/browser/devtools/ruleview.css                              (styleinspector/ruleview.css)
+    content/browser/devtools/layoutview/view.js                        (layoutview/view.js)
+    content/browser/devtools/layoutview/view.xhtml                     (layoutview/view.xhtml)
+    content/browser/devtools/layoutview/view.css                       (layoutview/view.css)
+    content/browser/devtools/fontinspector/font-inspector.js           (fontinspector/font-inspector.js)
+    content/browser/devtools/fontinspector/font-inspector.xhtml        (fontinspector/font-inspector.xhtml)
+    content/browser/devtools/fontinspector/font-inspector.css          (fontinspector/font-inspector.css)
+    content/browser/devtools/orion.js                                  (sourceeditor/orion/orion.js)
+*   content/browser/devtools/source-editor-overlay.xul                 (sourceeditor/source-editor-overlay.xul)
+    content/browser/devtools/debugger.xul                              (debugger/debugger.xul)
+    content/browser/devtools/debugger.css                              (debugger/debugger.css)
+    content/browser/devtools/debugger-controller.js                    (debugger/debugger-controller.js)
+    content/browser/devtools/debugger-view.js                          (debugger/debugger-view.js)
+    content/browser/devtools/debugger-toolbar.js                       (debugger/debugger-toolbar.js)
+    content/browser/devtools/debugger-panes.js                         (debugger/debugger-panes.js)
+    content/browser/devtools/profiler.xul                              (profiler/profiler.xul)
+    content/browser/devtools/cleopatra.html                            (profiler/cleopatra/cleopatra.html)
+    content/browser/devtools/profiler/cleopatra/css/ui.css             (profiler/cleopatra/css/ui.css)
+    content/browser/devtools/profiler/cleopatra/css/tree.css           (profiler/cleopatra/css/tree.css)
+    content/browser/devtools/profiler/cleopatra/css/devtools.css       (profiler/cleopatra/css/devtools.css)
+    content/browser/devtools/profiler/cleopatra/js/strings.js          (profiler/cleopatra/js/strings.js)
+    content/browser/devtools/profiler/cleopatra/js/parser.js           (profiler/cleopatra/js/parser.js)
+    content/browser/devtools/profiler/cleopatra/js/parserWorker.js     (profiler/cleopatra/js/parserWorker.js)
+    content/browser/devtools/profiler/cleopatra/js/tree.js             (profiler/cleopatra/js/tree.js)
+    content/browser/devtools/profiler/cleopatra/js/ui.js               (profiler/cleopatra/js/ui.js)
+    content/browser/devtools/profiler/cleopatra/js/ProgressReporter.js (profiler/cleopatra/js/ProgressReporter.js)
+    content/browser/devtools/profiler/cleopatra/js/devtools.js         (profiler/cleopatra/js/devtools.js)
+    content/browser/devtools/profiler/cleopatra/images/circlearrow.svg (profiler/cleopatra/images/circlearrow.svg)
+    content/browser/devtools/profiler/cleopatra/images/noise.png       (profiler/cleopatra/images/noise.png)
+    content/browser/devtools/profiler/cleopatra/images/throbber.svg    (profiler/cleopatra/images/throbber.svg)
+    content/browser/devtools/profiler/cleopatra/images/treetwisty.svg  (profiler/cleopatra/images/treetwisty.svg)
+    content/browser/devtools/commandline.css                           (commandline/commandline.css)
+    content/browser/devtools/commandlineoutput.xhtml                   (commandline/commandlineoutput.xhtml)
+    content/browser/devtools/commandlinetooltip.xhtml                  (commandline/commandlinetooltip.xhtml)
+    content/browser/devtools/framework/toolbox-window.xul              (framework/toolbox-window.xul)
+    content/browser/devtools/framework/toolbox-options.xul             (framework/toolbox-options.xul)
+    content/browser/devtools/framework/toolbox-options.js              (framework/toolbox-options.js)
+*   content/browser/devtools/framework/toolbox.xul                     (framework/toolbox.xul)
+    content/browser/devtools/framework/toolbox.css                     (framework/toolbox.css)
+    content/browser/devtools/inspector/inspector.xul                   (inspector/inspector.xul)
+    content/browser/devtools/inspector/inspector.css                   (inspector/inspector.css)
+    content/browser/devtools/connect.xhtml                             (framework/connect/connect.xhtml)
+    content/browser/devtools/connect.css                               (framework/connect/connect.css)
+    content/browser/devtools/connect.js                                (framework/connect/connect.js)
--- a/browser/devtools/main.js
+++ b/browser/devtools/main.js
@@ -77,17 +77,17 @@ Tools.webConsole = {
 Tools.jsdebugger = {
   id: "jsdebugger",
   key: l10n("open.commandkey", debuggerStrings),
   accesskey: l10n("debuggerMenu.accesskey", debuggerStrings),
   modifiers: osString == "Darwin" ? "accel,alt" : "accel,shift",
   ordinal: 2,
   killswitch: "devtools.debugger.enabled",
   icon: "chrome://browser/skin/devtools/tool-debugger.png",
-  url: "chrome://browser/content/debugger.xul",
+  url: "chrome://browser/content/devtools/debugger.xul",
   label: l10n("ToolboxDebugger.label", debuggerStrings),
   tooltip: l10n("ToolboxDebugger.tooltip", debuggerStrings),
 
   isTargetSupported: function(target) {
     return true;
   },
 
   build: function(iframeWindow, toolbox) {
@@ -119,17 +119,17 @@ Tools.inspector = {
 
 Tools.styleEditor = {
   id: "styleeditor",
   key: l10n("open.commandkey", styleEditorStrings),
   ordinal: 3,
   accesskey: l10n("open.accesskey", styleEditorStrings),
   modifiers: "shift",
   icon: "chrome://browser/skin/devtools/tool-styleeditor.png",
-  url: "chrome://browser/content/styleeditor.xul",
+  url: "chrome://browser/content/devtools/styleeditor.xul",
   label: l10n("ToolboxStyleEditor.label", styleEditorStrings),
   tooltip: l10n("ToolboxStyleEditor.tooltip", styleEditorStrings),
 
   isTargetSupported: function(target) {
     return true;
   },
 
   build: function(iframeWindow, toolbox) {
@@ -141,17 +141,17 @@ Tools.styleEditor = {
 Tools.jsprofiler = {
   id: "jsprofiler",
   accesskey: l10n("profiler.accesskey", profilerStrings),
   key: l10n("profiler2.commandkey", profilerStrings),
   ordinal: 4,
   modifiers: "shift",
   killswitch: "devtools.profiler.enabled",
   icon: "chrome://browser/skin/devtools/tool-profiler.png",
-  url: "chrome://browser/content/profiler.xul",
+  url: "chrome://browser/content/devtools/profiler.xul",
   label: l10n("profiler.label", profilerStrings),
   tooltip: l10n("profiler.tooltip", profilerStrings),
 
   isTargetSupported: function (target) {
     return true;
   },
 
   build: function (frame, target) {
--- a/browser/devtools/profiler/ProfilerPanel.jsm
+++ b/browser/devtools/profiler/ProfilerPanel.jsm
@@ -56,17 +56,17 @@ function ProfileUI(uid, name, panel) {
 
   this.panel = panel;
   this.uid = uid;
   this.name = name;
 
   this.iframe = doc.createElement("iframe");
   this.iframe.setAttribute("flex", "1");
   this.iframe.setAttribute("id", "profiler-cleo-" + uid);
-  this.iframe.setAttribute("src", "devtools/cleopatra.html?" + uid);
+  this.iframe.setAttribute("src", "cleopatra.html?" + uid);
   this.iframe.setAttribute("hidden", "true");
 
   // Append our iframe and subscribe to postMessage events.
   // They'll tell us when the underlying page is done loading
   // or when user clicks on start/stop buttons.
 
   doc.getElementById("profiler-report").appendChild(this.iframe);
   win.addEventListener("message", function (event) {
--- a/browser/devtools/profiler/profiler.xul
+++ b/browser/devtools/profiler/profiler.xul
@@ -3,17 +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/. -->
 
 <?xml-stylesheet href="chrome://global/skin/global.css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/common.css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/splitview.css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/profiler.css"?>
-<?xml-stylesheet href="chrome://browser/content/splitview.css"?>
+<?xml-stylesheet href="chrome://browser/content/devtools/splitview.css"?>
 
 <!DOCTYPE window [
 <!ENTITY % profilerDTD SYSTEM "chrome://browser/locale/devtools/profiler.dtd">
   %profilerDTD;
 ]>
 
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <box flex="1" id="profiler-chrome" class="splitview-root">
--- a/browser/devtools/scratchpad/scratchpad-manager.jsm
+++ b/browser/devtools/scratchpad/scratchpad-manager.jsm
@@ -6,17 +6,17 @@
 "use strict";
 
 this.EXPORTED_SYMBOLS = ["ScratchpadManager"];
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
-const SCRATCHPAD_WINDOW_URL = "chrome://browser/content/scratchpad.xul";
+const SCRATCHPAD_WINDOW_URL = "chrome://browser/content/devtools/scratchpad.xul";
 const SCRATCHPAD_WINDOW_FEATURES = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
 
 Cu.import("resource://gre/modules/Services.jsm");
 
 /**
  * The ScratchpadManager object opens new Scratchpad windows and manages the state
  * of open scratchpads for session restore. There's only one ScratchpadManager in
  * the life of the browser.
--- a/browser/devtools/scratchpad/scratchpad.js
+++ b/browser/devtools/scratchpad/scratchpad.js
@@ -25,25 +25,33 @@ Cu.import("resource:///modules/PropertyP
 Cu.import("resource:///modules/source-editor.jsm");
 Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
 Cu.import("resource:///modules/devtools/scratchpad-manager.jsm");
 Cu.import("resource://gre/modules/jsdebugger.jsm");
 Cu.import("resource:///modules/devtools/gDevTools.jsm");
 Cu.import("resource://gre/modules/osfile.jsm");
 Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js");
 
+XPCOMUtils.defineLazyModuleGetter(this, "VariablesView",
+                                  "resource:///modules/devtools/VariablesView.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "devtools",
+                                  "resource:///modules/devtools/gDevTools.jsm");
+
 const SCRATCHPAD_CONTEXT_CONTENT = 1;
 const SCRATCHPAD_CONTEXT_BROWSER = 2;
 const SCRATCHPAD_L10N = "chrome://browser/locale/devtools/scratchpad.properties";
 const DEVTOOLS_CHROME_ENABLED = "devtools.chrome.enabled";
 const PREF_RECENT_FILES_MAX = "devtools.scratchpad.recentFilesMax";
 const BUTTON_POSITION_SAVE = 0;
 const BUTTON_POSITION_CANCEL = 1;
 const BUTTON_POSITION_DONT_SAVE = 2;
-const BUTTON_POSITION_REVERT=0;
+const BUTTON_POSITION_REVERT = 0;
+const VARIABLES_VIEW_URL = "chrome://browser/content/devtools/widgets/VariablesView.xul";
+
 
 /**
  * The scratchpad object handles the Scratchpad window functionality.
  */
 var Scratchpad = {
   _instanceId: null,
   _initialWindowTitle: document.title,
 
@@ -248,16 +256,28 @@ var Scratchpad = {
    * Unique name for the current Scratchpad instance. Used to distinguish
    * Scratchpad windows between each other. See bug 661762.
    */
   get uniqueName()
   {
     return "Scratchpad/" + this._instanceId;
   },
 
+
+  /**
+   * Sidebar that contains the VariablesView for object inspection.
+   */
+  get sidebar()
+  {
+    if (!this._sidebar) {
+      this._sidebar = new ScratchpadSidebar();
+    }
+    return this._sidebar;
+  },
+
   /**
    * Get the Cu.Sandbox object for the active tab content window object. Note
    * that the returned object is cached for later reuse. The cached object is
    * kept only for the current location in the current tab of the current
    * browser window and it is reset for each context switch,
    * navigator:browser window switch, tab switch or navigation.
    */
   get contentSandbox()
@@ -418,35 +438,45 @@ var Scratchpad = {
         this.deselect();
       }
     });
     return promise;
   },
 
   /**
    * Execute the selected text (if any) or the entire editor content in the
-   * current context. The resulting object is opened up in the Property Panel
-   * for inspection.
+   * current context. If the result is primitive then it is written as a
+   * comment. Otherwise, the resulting object is inspected up in the sidebar.
    *
    * @return Promise
    *         The promise for the script evaluation result.
    */
   inspect: function SP_inspect()
   {
-    let promise = this.execute();
-    promise.then(([aString, aError, aResult]) => {
+    let deferred = Promise.defer();
+    let reject = aReason => deferred.reject(aReason);
+
+    this.execute().then(([aString, aError, aResult]) => {
+      let resolve = () => deferred.resolve([aString, aError, aResult]);
+
       if (aError) {
         this.writeAsErrorComment(aError);
+        resolve();
+      }
+      else if (!isObject(aResult)) {
+        this.writeAsComment(aResult);
+        resolve();
       }
       else {
         this.deselect();
-        this.openPropertyPanel(aString, aResult);
+        this.sidebar.open(aString, aResult).then(resolve, reject);
       }
-    });
-    return promise;
+    }, reject);
+    
+    return deferred.promise;
   },
 
   /**
    * Reload the current page and execute the entire editor content when
    * the page finishes loading. Note that this operation should be available
    * only in the content context.
    *
    * @return Promise
@@ -547,68 +577,16 @@ var Scratchpad = {
       stack = "@" + aError.lineNumber;
     }
 
     let newComment = "Exception: " + ( aError.message || aError) + ( stack == "" ? stack : "\n" + stack.replace(/\n$/, "") );
 
     this.writeAsComment(newComment);
   },
 
-  /**
-   * Open the Property Panel to inspect the given object.
-   *
-   * @param string aEvalString
-   *        The string that was evaluated. This is re-used when the user updates
-   *        the properties list, by clicking the Update button.
-   * @param object aOutputObject
-   *        The object to inspect, which is the aEvalString evaluation result.
-   * @return object
-   *         The PropertyPanel object instance.
-   */
-  openPropertyPanel: function SP_openPropertyPanel(aEvalString, aOutputObject)
-  {
-    let propPanel;
-    // The property panel has a button:
-    // `Update`: reexecutes the string executed on the command line. The
-    // result will be inspected by this panel.
-    let buttons = [];
-
-    // If there is a evalString passed to this function, then add a `Update`
-    // button to the panel so that the evalString can be reexecuted to update
-    // the content of the panel.
-    if (aEvalString !== null) {
-      buttons.push({
-        label: this.strings.
-               GetStringFromName("propertyPanel.updateButton.label"),
-        accesskey: this.strings.
-                   GetStringFromName("propertyPanel.updateButton.accesskey"),
-        oncommand: () => {
-          this.evalForContext(aEvalString).then(([, aError, aResult]) => {
-            if (!aError) {
-              propPanel.treeView.data = { object: aResult };
-            }
-          });
-        }
-      });
-    }
-
-    let doc = this.browserWindow.document;
-    let parent = doc.getElementById("mainPopupSet");
-    let title = String(aOutputObject);
-    propPanel = new PropertyPanel(parent, title, { object: aOutputObject },
-                                  buttons);
-
-    let panel = propPanel.panel;
-    panel.setAttribute("class", "scratchpad_propertyPanel");
-    panel.openPopup(null, "after_pointer", 0, 0, false, false);
-    panel.sizeTo(200, 400);
-
-    return propPanel;
-  },
-
   // Menu Operations
 
   /**
    * Open a new Scratchpad window.
    *
    * @return nsIWindow
    */
   openScratchpad: function SP_openScratchpad()
@@ -1490,16 +1468,142 @@ var Scratchpad = {
   {
     let url = this.strings.GetStringFromName("help.openDocumentationPage");
     let newTab = this.gBrowser.addTab(url);
     this.browserWindow.focus();
     this.gBrowser.selectedTab = newTab;
   },
 };
 
+
+/**
+ * Encapsulates management of the sidebar containing the VariablesView for
+ * object inspection.
+ */
+function ScratchpadSidebar()
+{
+  let ToolSidebar = devtools.require("devtools/framework/sidebar").ToolSidebar;
+  let tabbox = document.querySelector("#scratchpad-sidebar");
+  this._sidebar = new ToolSidebar(tabbox, this);
+  this._splitter = document.querySelector(".devtools-side-splitter");
+}
+
+ScratchpadSidebar.prototype = {
+  /*
+   * The ToolSidebar for this sidebar.
+   */
+  _sidebar: null,
+
+  /*
+   * The splitter element between the sidebar and the editor.
+   */
+  _splitter: null,
+
+  /*
+   * The VariablesView for this sidebar.
+   */
+  variablesView: null,
+
+  /*
+   * Whether the sidebar is currently shown.
+   */
+  visible: false,
+
+  /**
+   * Open the sidebar, if not open already, and populate it with the properties
+   * of the given object.
+   *
+   * @param string aString
+   *        The string that was evaluated.
+   * @param object aObject
+   *        The object to inspect, which is the aEvalString evaluation result.
+   * @return Promise
+   *         A promise that will resolve once the sidebar is open.
+   */
+  open: function SS_open(aEvalString, aObject)
+  {
+    this.show();
+
+    let deferred = Promise.defer();
+
+    let onTabReady = () => {
+      if (!this.variablesView) {
+        let window = this._sidebar.getWindowForTab("variablesview");
+        let container = window.document.querySelector("#variables");
+        this.variablesView = new VariablesView(container);
+      }
+      this._update(aObject).then(() => deferred.resolve());
+    };
+
+    if (this._sidebar.getCurrentTabID() == "variablesview") {
+      onTabReady();
+    }
+    else {
+      this._sidebar.once("variablesview-ready", onTabReady);
+      this._sidebar.addTab("variablesview", VARIABLES_VIEW_URL, true);
+    }
+
+    return deferred.promise;
+  },
+
+  /**
+   * Show the sidebar.
+   */
+  show: function SS_show()
+  {
+    if (!this.visible) {
+      this.visible = true;
+      this._sidebar.show();
+      this._splitter.setAttribute("state", "open");
+    }
+  },
+
+  /**
+   * Hide the sidebar.
+   */
+  hide: function SS_hide()
+  {
+    if (this.visible) {
+      this.visible = false;
+      this._sidebar.hide();
+      this._splitter.setAttribute("state", "collapsed");
+    }
+  },
+
+  /**
+   * Update the object currently inspected by the sidebar.
+   *
+   * @param object aObject
+   *        The object to inspect in the sidebar.
+   * @return Promise
+   *         A promise that resolves when the update completes.
+   */
+  _update: function SS__update(aObject)
+  {
+    let deferred = Promise.defer();
+
+    this.variablesView.rawObject = aObject;
+
+    // In the future this will work on remote values (bug 825039).
+    setTimeout(() => deferred.resolve(), 0);
+    return deferred.promise;
+  }
+};
+
+
+/**
+ * Check whether a value is non-primitive.
+ */
+function isObject(aValue)
+{
+  let type = typeof aValue;
+  return type == "object" ? aValue != null : type == "function";
+}
+
+
 /**
  * The PreferenceObserver listens for preference changes while Scratchpad is
  * running.
  */
 var PreferenceObserver = {
   _initialized: false,
 
   init: function PO_init()
--- a/browser/devtools/scratchpad/scratchpad.xul
+++ b/browser/devtools/scratchpad/scratchpad.xul
@@ -3,32 +3,34 @@
 <!-- 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/. -->
 #endif
 <!DOCTYPE window [
 <!ENTITY % scratchpadDTD SYSTEM "chrome://browser/locale/devtools/scratchpad.dtd" >
  %scratchpadDTD;
 ]>
-<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
+<?xml-stylesheet href="chrome://global/skin/global.css"?>
+<?xml-stylesheet href="chrome://browser/skin/devtools/common.css"?>
+<?xml-stylesheet href="chrome://browser/skin/devtools/scratchpad.css"?>
 <?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
-<?xul-overlay href="chrome://browser/content/source-editor-overlay.xul"?>
+<?xul-overlay href="chrome://browser/content/devtools/source-editor-overlay.xul"?>
 
 <window id="main-window"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         title="&window.title;"
         windowtype="devtools:scratchpad"
         macanimationtype="document"
         fullscreenbutton="true"
         screenX="4" screenY="4"
         width="640" height="480"
         persist="screenX screenY width height sizemode">
 
 <script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
-<script type="application/javascript" src="chrome://browser/content/scratchpad.js"/>
+<script type="application/javascript" src="chrome://browser/content/devtools/scratchpad.js"/>
 
 <commandset id="editMenuCommands"/>
 <commandset id="sourceEditorCommands"/>
 
 <commandset id="sp-commandset">
   <command id="sp-cmd-newWindow" oncommand="Scratchpad.openScratchpad();"/>
   <command id="sp-cmd-openFile" oncommand="Scratchpad.openFile();"/>
   <command id="sp-cmd-clearRecentFiles" oncommand="Scratchpad.clearRecentFiles();"/>
@@ -275,12 +277,21 @@
     <menuitem id="sp-text-resetContext"
               label="&resetContext2.label;"
               accesskey="&resetContext2.accesskey;"
               command="sp-cmd-resetContext"/>
   </menupopup>
 </popupset>
 
 <notificationbox id="scratchpad-notificationbox" flex="1">
-  <hbox id="scratchpad-editor" flex="1"/>
+  <hbox flex="1">
+    <vbox id="scratchpad-editor" flex="1"/>
+    <splitter class="devtools-side-splitter"
+              collapse="after"
+              state="collapsed"/>
+    <tabbox id="scratchpad-sidebar" class="devtools-sidebar-tabs" width="300">
+      <tabs/>
+      <tabpanels flex="1"/>
+    </tabbox>
+  </hbox>
 </notificationbox>
 
 </window>
--- a/browser/devtools/scratchpad/test/browser_scratchpad_inspect.js
+++ b/browser/devtools/scratchpad/test/browser_scratchpad_inspect.js
@@ -7,52 +7,40 @@ function test()
   waitForExplicitFinish();
 
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
     gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
     openScratchpad(runTests);
   }, true);
 
-  content.location = "data:text/html,<title>foobarBug636725</title>" +
-    "<p>test inspect() in Scratchpad";
+  content.location = "data:text/html;charset=utf8,<p>test inspect() in Scratchpad</p>";
 }
 
 function runTests()
 {
   let sp = gScratchpadWindow.Scratchpad;
 
-  sp.setText("document");
+  sp.setText("({ a: 'foobarBug636725' })");
 
   sp.inspect().then(function() {
+    let sidebar = sp.sidebar;
+    ok(sidebar.visible, "sidebar is open");
 
-    let propPanel = document.querySelector(".scratchpad_propertyPanel");
-    ok(propPanel, "property panel is open");
 
-    propPanel.addEventListener("popupshown", function onPopupShown() {
-      propPanel.removeEventListener("popupshown", onPopupShown, false);
+    let found = false;
 
-      let tree = propPanel.querySelector("tree");
-      ok(tree, "property panel tree found");
-
-      let column = tree.columns[0];
-      let found = false;
-
-      for (let i = 0; i < tree.view.rowCount; i++) {
-        let cell = tree.view.getCellText(i, column);
-        if (cell == 'title: "foobarBug636725"') {
-          found = true;
-          break;
+    outer: for (let scope in sidebar.variablesView) {
+      for (let [, obj] in scope) {
+        for (let [, prop] in obj) {
+          if (prop.name == "a" && prop.value == "foobarBug636725") {
+            found = true;
+            break outer;
+          }
         }
       }
-      ok(found, "found the document.title property");
-
-      executeSoon(function() {
-        propPanel.hidePopup();
+    }
 
-        finish();
-      });
-    }, false);
-  }, function() {
-    notok(true, "document not found");
+    ok(found, "found the property");
+
     finish();
   });
-}
+}
\ No newline at end of file
--- a/browser/devtools/sourceeditor/source-editor-orion.jsm
+++ b/browser/devtools/sourceeditor/source-editor-orion.jsm
@@ -11,17 +11,17 @@ const Ci = Components.interfaces;
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource:///modules/source-editor-ui.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "clipboardHelper",
                                    "@mozilla.org/widget/clipboardhelper;1",
                                    "nsIClipboardHelper");
 
-const ORION_SCRIPT = "chrome://browser/content/orion.js";
+const ORION_SCRIPT = "chrome://browser/content/devtools/orion.js";
 const ORION_IFRAME = "data:text/html;charset=utf8,<!DOCTYPE html>" +
   "<html style='height:100%' dir='ltr'>" +
   "<head><link rel='stylesheet'" +
   " href='chrome://browser/skin/devtools/orion-container.css'></head>" +
   "<body style='height:100%;margin:0;overflow:hidden'>" +
   "<div id='editor' style='height:100%'></div>" +
   "</body></html>";
 
--- a/browser/devtools/styleeditor/styleeditor.xul
+++ b/browser/devtools/styleeditor/styleeditor.xul
@@ -2,23 +2,23 @@
 <!-- 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/. -->
 <!DOCTYPE window [
 <!ENTITY % styleEditorDTD SYSTEM "chrome://browser/locale/devtools/styleeditor.dtd" >
  %styleEditorDTD;
 ]>
 <?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
-<?xml-stylesheet href="chrome://browser/content/splitview.css" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/content/devtools/splitview.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/common.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/splitview.css" type="text/css"?>
-<?xml-stylesheet href="chrome://browser/content/styleeditor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/content/devtools/styleeditor.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/styleeditor.css" type="text/css"?>
 <?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
-<?xul-overlay href="chrome://browser/content/source-editor-overlay.xul"?>
+<?xul-overlay href="chrome://browser/content/devtools/source-editor-overlay.xul"?>
 <xul:window xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         xmlns="http://www.w3.org/1999/xhtml"
         id="style-editor-chrome-window">
 
   <xul:script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
 
   <xul:popupset id="style-editor-popups">
     <xul:menupopup id="sourceEditorContextMenu"
--- a/browser/devtools/styleeditor/test/Makefile.in
+++ b/browser/devtools/styleeditor/test/Makefile.in
@@ -20,16 +20,17 @@ include $(topsrcdir)/config/rules.mk
                  browser_styleeditor_import_rule.js \
                  browser_styleeditor_init.js \
                  browser_styleeditor_loading.js \
                  browser_styleeditor_new.js \
                  browser_styleeditor_pretty.js \
                  browser_styleeditor_private_perwindowpb.js \
                  browser_styleeditor_sv_keynav.js \
                  browser_styleeditor_sv_resize.js \
+                 browser_styleeditor_bug_740541_iframes.js \
                  browser_styleeditor_bug_851132_middle_click.js \
                  head.js \
                  helpers.js \
                  four.html \
                  head.js \
                  helpers.js \
                  import.css \
                  import.html \
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleeditor/test/browser_styleeditor_bug_740541_iframes.js
@@ -0,0 +1,90 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test()
+{
+
+  function makeStylesheet(selector) {
+    return ("data:text/css;charset=UTF-8," +
+            encodeURIComponent(selector + " { }"));
+  }
+
+  function makeDocument(stylesheets, framedDocuments) {
+    stylesheets = stylesheets || [];
+    framedDocuments = framedDocuments || [];
+    return "data:text/html;charset=UTF-8," + encodeURIComponent(
+      Array.prototype.concat.call(
+        ["<!DOCTYPE html>",
+         "<html>",
+         "<head>",
+         "<title>Bug 740541</title>"],
+        stylesheets.map(function (sheet) {
+          return '<link rel="stylesheet" type="text/css" href="'+sheet+'">';
+        }),
+        ["</head>",
+         "<body>"],
+        framedDocuments.map(function (doc) {
+          return '<iframe src="'+doc+'"></iframe>';
+        }),
+        ["</body>",
+         "</html>"]
+      ).join("\n"));
+  }
+
+  const DOCUMENT_WITH_INLINE_STYLE = "data:text/html;charset=UTF-8," +
+          encodeURIComponent(
+            ["<!DOCTYPE html>",
+             "<html>",
+             " <head>",
+             "  <title>Bug 740541</title>",
+             '  <style type="text/css">',
+             "    .something {",
+             "    }",
+             "  </style>",
+             " </head>",
+             " <body>",
+             " </body>",
+             " </html>"
+            ].join("\n"));
+
+  const FOUR = TEST_BASE_HTTP + "four.html";
+
+  const SIMPLE = TEST_BASE_HTTP + "simple.css";
+
+  const SIMPLE_DOCUMENT = TEST_BASE_HTTP + "simple.html";
+
+
+  const TESTCASE_URI = makeDocument(
+    [makeStylesheet(".a")],
+    [makeDocument([],
+                  [FOUR,
+                   DOCUMENT_WITH_INLINE_STYLE]),
+     makeDocument([makeStylesheet(".b"),
+                   SIMPLE],
+                  [makeDocument([makeStylesheet(".c")],
+                                [])]),
+     makeDocument([SIMPLE], []),
+     SIMPLE_DOCUMENT
+    ]);
+
+  const EXPECTED_STYLE_SHEET_COUNT = 12;
+
+  waitForExplicitFinish();
+  let styleSheetCount = 0;
+  addTabAndOpenStyleEditor(function (aPanel) {
+    aPanel.UI.on("editor-added", function () {
+      ++styleSheetCount;
+      info(styleSheetCount+" out of "+
+           EXPECTED_STYLE_SHEET_COUNT+" style sheets loaded");
+      if (styleSheetCount == EXPECTED_STYLE_SHEET_COUNT) {
+        ok(true, "all style sheets loaded");
+        // The right number of events have been received; check that
+        // they actually show up in the style editor UI.
+        is(aPanel.UI.editors.length, EXPECTED_STYLE_SHEET_COUNT,
+           "UI elements present");
+        finish();
+      }
+    });
+  });
+  content.location = TESTCASE_URI;
+}
--- a/browser/devtools/webconsole/NetworkPanel.jsm
+++ b/browser/devtools/webconsole/NetworkPanel.jsm
@@ -57,17 +57,17 @@ function NetworkPanel(aParent, aHttpActi
     titlebar: "normal",
     noautofocus: "true",
     noautohide: "true",
     close: "true"
   });
 
   // Create the iframe that displays the NetworkPanel XHTML.
   this.iframe = createAndAppendElement(this.panel, "iframe", {
-    src: "chrome://browser/content/NetworkPanel.xhtml",
+    src: "chrome://browser/content/devtools/NetworkPanel.xhtml",
     type: "content",
     flex: "1"
   });
 
   let self = this;
 
   // Destroy the panel when it's closed.
   this.panel.addEventListener("popuphidden", function onPopupHide() {
--- a/browser/devtools/webconsole/webconsole.js
+++ b/browser/devtools/webconsole/webconsole.js
@@ -3478,17 +3478,17 @@ JSTerm.prototype = {
         if (setter) {
           setter.evaluationMacro = this._variablesViewGetterOrSetterEvalMacro;
         }
       }
       else {
         aProperty.evaluationMacro = this._variablesViewSimpleValueEvalMacro;
       }
 
-      let grips = [aProperty.value, aProperty.gettter, aProperty.settter];
+      let grips = [aProperty.value, aProperty.getter, aProperty.setter];
       grips.forEach(addActorForDescriptor);
 
       let inspectable = !VariablesView.isPrimitive({ value: aProperty.value });
       let longString = WebConsoleUtils.isActorGrip(aProperty.value) &&
                        aProperty.value.type == "longString";
       if (inspectable) {
         aProperty.onexpand = this._fetchVarProperties;
       }
new file mode 100644
--- /dev/null
+++ b/browser/themes/linux/devtools/scratchpad.css
@@ -0,0 +1,5 @@
+/* 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 ../../shared/devtools/scratchpad.inc.css
\ No newline at end of file
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -166,16 +166,17 @@ browser.jar:
   skin/classic/browser/devtools/breadcrumbs/rtl-start-selected-pressed.png   (devtools/breadcrumbs/rtl-start-selected-pressed.png)
   skin/classic/browser/devtools/breadcrumbs/rtl-start.png                    (devtools/breadcrumbs/rtl-start.png)
   skin/classic/browser/devtools/breadcrumbs/rtl-start-selected.png           (devtools/breadcrumbs/rtl-start-selected.png)
   skin/classic/browser/devtools/splitview.css         (devtools/splitview.css)
   skin/classic/browser/devtools/styleeditor.css       (devtools/styleeditor.css)
   skin/classic/browser/devtools/debugger.css          (devtools/debugger.css)
 * skin/classic/browser/devtools/profiler.css          (devtools/profiler.css)
   skin/classic/browser/devtools/netmonitor.css        (devtools/netmonitor.css)
+* skin/classic/browser/devtools/scratchpad.css        (devtools/scratchpad.css)
   skin/classic/browser/devtools/magnifying-glass.png  (devtools/magnifying-glass.png)
   skin/classic/browser/devtools/option-icon.png       (devtools/option-icon.png)
   skin/classic/browser/devtools/itemToggle.png        (devtools/itemToggle.png)
   skin/classic/browser/devtools/itemArrow-rtl.png     (devtools/itemArrow-rtl.png)
   skin/classic/browser/devtools/itemArrow-ltr.png     (devtools/itemArrow-ltr.png)
   skin/classic/browser/devtools/background-noise-toolbar.png (devtools/background-noise-toolbar.png)
   skin/classic/browser/devtools/inspect-button.png    (devtools/inspect-button.png)
   skin/classic/browser/devtools/dropmarker.png        (devtools/dropmarker.png)
new file mode 100644
--- /dev/null
+++ b/browser/themes/osx/devtools/scratchpad.css
@@ -0,0 +1,5 @@
+/* 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 ../../shared/devtools/scratchpad.inc.css
\ No newline at end of file
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -257,16 +257,17 @@ browser.jar:
   skin/classic/browser/devtools/breadcrumbs/rtl-start-selected-pressed.png   (devtools/breadcrumbs/rtl-start-selected-pressed.png)
   skin/classic/browser/devtools/breadcrumbs/rtl-start.png                    (devtools/breadcrumbs/rtl-start.png)
   skin/classic/browser/devtools/breadcrumbs/rtl-start-selected.png           (devtools/breadcrumbs/rtl-start-selected.png)
   skin/classic/browser/devtools/splitview.css               (devtools/splitview.css)
   skin/classic/browser/devtools/styleeditor.css             (devtools/styleeditor.css)
 * skin/classic/browser/devtools/debugger.css                (devtools/debugger.css)
 * skin/classic/browser/devtools/profiler.css                (devtools/profiler.css)
   skin/classic/browser/devtools/netmonitor.css              (devtools/netmonitor.css)
+* skin/classic/browser/devtools/scratchpad.css              (devtools/scratchpad.css)
   skin/classic/browser/devtools/magnifying-glass.png        (devtools/magnifying-glass.png)
   skin/classic/browser/devtools/option-icon.png             (devtools/option-icon.png)
   skin/classic/browser/devtools/itemToggle.png              (devtools/itemToggle.png)
   skin/classic/browser/devtools/itemArrow-rtl.png           (devtools/itemArrow-rtl.png)
   skin/classic/browser/devtools/itemArrow-ltr.png           (devtools/itemArrow-ltr.png)
   skin/classic/browser/devtools/background-noise-toolbar.png (devtools/background-noise-toolbar.png)
   skin/classic/browser/devtools/inspect-button.png          (devtools/inspect-button.png)
   skin/classic/browser/devtools/dropmarker.png              (devtools/dropmarker.png)
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/devtools/scratchpad.inc.css
@@ -0,0 +1,10 @@
+%if 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/. */
+%endif
+
+#scratchpad-sidebar > tabs {
+  height: 0;
+  border: none;
+}
new file mode 100644
--- /dev/null
+++ b/browser/themes/windows/devtools/scratchpad.css
@@ -0,0 +1,5 @@
+/* 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 ../../shared/devtools/scratchpad.inc.css
\ No newline at end of file
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -194,16 +194,17 @@ browser.jar:
         skin/classic/browser/devtools/breadcrumbs/rtl-start-selected-pressed.png   (devtools/breadcrumbs/rtl-start-selected-pressed.png)
         skin/classic/browser/devtools/breadcrumbs/rtl-start.png                    (devtools/breadcrumbs/rtl-start.png)
         skin/classic/browser/devtools/breadcrumbs/rtl-start-selected.png           (devtools/breadcrumbs/rtl-start-selected.png)
         skin/classic/browser/devtools/splitview.css                 (devtools/splitview.css)
         skin/classic/browser/devtools/styleeditor.css               (devtools/styleeditor.css)
         skin/classic/browser/devtools/debugger.css                  (devtools/debugger.css)
 *       skin/classic/browser/devtools/profiler.css                  (devtools/profiler.css)
         skin/classic/browser/devtools/netmonitor.css                (devtools/netmonitor.css)
+*       skin/classic/browser/devtools/scratchpad.css                (devtools/scratchpad.css)
         skin/classic/browser/devtools/magnifying-glass.png          (devtools/magnifying-glass.png)
         skin/classic/browser/devtools/option-icon.png               (devtools/option-icon.png)
         skin/classic/browser/devtools/itemToggle.png                (devtools/itemToggle.png)
         skin/classic/browser/devtools/itemArrow-rtl.png             (devtools/itemArrow-rtl.png)
         skin/classic/browser/devtools/itemArrow-ltr.png             (devtools/itemArrow-ltr.png)
         skin/classic/browser/devtools/background-noise-toolbar.png  (devtools/background-noise-toolbar.png)
         skin/classic/browser/devtools/inspect-button.png            (devtools/inspect-button.png)
         skin/classic/browser/devtools/dropmarker.png                (devtools/dropmarker.png)
@@ -441,16 +442,17 @@ browser.jar:
         skin/classic/aero/browser/devtools/breadcrumbs/rtl-start-selected-pressed.png   (devtools/breadcrumbs/rtl-start-selected-pressed.png)
         skin/classic/aero/browser/devtools/breadcrumbs/rtl-start.png                    (devtools/breadcrumbs/rtl-start.png)
         skin/classic/aero/browser/devtools/breadcrumbs/rtl-start-selected.png           (devtools/breadcrumbs/rtl-start-selected.png)
         skin/classic/aero/browser/devtools/splitview.css             (devtools/splitview.css)
         skin/classic/aero/browser/devtools/styleeditor.css           (devtools/styleeditor.css)
         skin/classic/aero/browser/devtools/debugger.css              (devtools/debugger.css)
 *       skin/classic/aero/browser/devtools/profiler.css              (devtools/profiler.css)
         skin/classic/aero/browser/devtools/netmonitor.css            (devtools/netmonitor.css)
+*       skin/classic/aero/browser/devtools/scratchpad.css            (devtools/scratchpad.css)
         skin/classic/aero/browser/devtools/magnifying-glass.png      (devtools/magnifying-glass.png)
         skin/classic/aero/browser/devtools/option-icon.png           (devtools/option-icon.png)
         skin/classic/aero/browser/devtools/itemToggle.png            (devtools/itemToggle.png)
         skin/classic/aero/browser/devtools/itemArrow-rtl.png         (devtools/itemArrow-rtl.png)
         skin/classic/aero/browser/devtools/background-noise-toolbar.png (devtools/background-noise-toolbar.png)
         skin/classic/aero/browser/devtools/itemArrow-ltr.png         (devtools/itemArrow-ltr.png)
         skin/classic/aero/browser/devtools/inspect-button.png        (devtools/inspect-button.png)
         skin/classic/aero/browser/devtools/dropmarker.png            (devtools/dropmarker.png)
--- a/content/media/AudioEventTimeline.h
+++ b/content/media/AudioEventTimeline.h
@@ -146,22 +146,16 @@ public:
   void SetValue(float aValue)
   {
     // Silently don't change anything if there are any events
     if (mEvents.IsEmpty()) {
       mValue = aValue;
     }
   }
 
-  float ComputedValue() const
-  {
-    // TODO: implement
-    return 0;
-  }
-
   void SetValueAtTime(float aValue, double aStartTime, ErrorResult& aRv)
   {
     InsertEvent(AudioTimelineEvent(AudioTimelineEvent::SetValue, aStartTime, aValue), aRv);
   }
 
   void LinearRampToValueAtTime(float aValue, double aEndTime, ErrorResult& aRv)
   {
     InsertEvent(AudioTimelineEvent(AudioTimelineEvent::LinearRamp, aEndTime, aValue), aRv);
--- a/content/media/AudioNodeStream.cpp
+++ b/content/media/AudioNodeStream.cpp
@@ -1,442 +1,442 @@
-/* -*- 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/. */
-
-#include "AudioNodeStream.h"
-
-#include "MediaStreamGraphImpl.h"
-#include "AudioNodeEngine.h"
-#include "ThreeDPoint.h"
-
-using namespace mozilla::dom;
-
-namespace mozilla {
-
-/**
- * An AudioNodeStream produces a single audio track with ID
- * AUDIO_NODE_STREAM_TRACK_ID. This track has rate IdealAudioRate().
- * Each chunk in the track is a single block of WEBAUDIO_BLOCK_SIZE samples.
- */
-static const int AUDIO_NODE_STREAM_TRACK_ID = 1;
-
-AudioNodeStream::~AudioNodeStream()
-{
-  MOZ_COUNT_DTOR(AudioNodeStream);
-}
-
-void
-AudioNodeStream::SetStreamTimeParameter(uint32_t aIndex, MediaStream* aRelativeToStream,
-                                        double aStreamTime)
-{
-  class Message : public ControlMessage {
-  public:
-    Message(AudioNodeStream* aStream, uint32_t aIndex, MediaStream* aRelativeToStream,
-            double aStreamTime)
-      : ControlMessage(aStream), mStreamTime(aStreamTime),
-        mRelativeToStream(aRelativeToStream), mIndex(aIndex) {}
-    virtual void Run()
-    {
-      static_cast<AudioNodeStream*>(mStream)->
-          SetStreamTimeParameterImpl(mIndex, mRelativeToStream, mStreamTime);
-    }
-    double mStreamTime;
-    MediaStream* mRelativeToStream;
-    uint32_t mIndex;
-  };
-
-  MOZ_ASSERT(this);
-  GraphImpl()->AppendMessage(new Message(this, aIndex, aRelativeToStream, aStreamTime));
-}
-
-void
-AudioNodeStream::SetStreamTimeParameterImpl(uint32_t aIndex, MediaStream* aRelativeToStream,
-                                            double aStreamTime)
-{
-  StreamTime streamTime = std::max<MediaTime>(0, SecondsToMediaTime(aStreamTime));
-  GraphTime graphTime = aRelativeToStream->StreamTimeToGraphTime(streamTime);
-  StreamTime thisStreamTime = GraphTimeToStreamTimeOptimistic(graphTime);
-  TrackTicks ticks = TimeToTicksRoundUp(IdealAudioRate(), thisStreamTime);
-  mEngine->SetStreamTimeParameter(aIndex, ticks);
-}
-
-void
-AudioNodeStream::SetDoubleParameter(uint32_t aIndex, double aValue)
-{
-  class Message : public ControlMessage {
-  public:
-    Message(AudioNodeStream* aStream, uint32_t aIndex, double aValue)
-      : ControlMessage(aStream), mValue(aValue), mIndex(aIndex) {}
-    virtual void Run()
-    {
-      static_cast<AudioNodeStream*>(mStream)->Engine()->
-          SetDoubleParameter(mIndex, mValue);
-    }
-    double mValue;
-    uint32_t mIndex;
-  };
-
-  MOZ_ASSERT(this);
-  GraphImpl()->AppendMessage(new Message(this, aIndex, aValue));
-}
-
-void
-AudioNodeStream::SetInt32Parameter(uint32_t aIndex, int32_t aValue)
-{
-  class Message : public ControlMessage {
-  public:
-    Message(AudioNodeStream* aStream, uint32_t aIndex, int32_t aValue)
-      : ControlMessage(aStream), mValue(aValue), mIndex(aIndex) {}
-    virtual void Run()
-    {
-      static_cast<AudioNodeStream*>(mStream)->Engine()->
-          SetInt32Parameter(mIndex, mValue);
-    }
-    int32_t mValue;
-    uint32_t mIndex;
-  };
-
-  MOZ_ASSERT(this);
-  GraphImpl()->AppendMessage(new Message(this, aIndex, aValue));
-}
-
-void
-AudioNodeStream::SetTimelineParameter(uint32_t aIndex,
-                                      const AudioParamTimeline& aValue)
-{
-  class Message : public ControlMessage {
-  public:
-    Message(AudioNodeStream* aStream, uint32_t aIndex,
-            const AudioParamTimeline& aValue)
-      : ControlMessage(aStream), mValue(aValue), mIndex(aIndex) {}
-    virtual void Run()
-    {
-      static_cast<AudioNodeStream*>(mStream)->Engine()->
-          SetTimelineParameter(mIndex, mValue);
-    }
-    AudioParamTimeline mValue;
-    uint32_t mIndex;
-  };
-  GraphImpl()->AppendMessage(new Message(this, aIndex, aValue));
-}
-
-void
-AudioNodeStream::SetThreeDPointParameter(uint32_t aIndex, const ThreeDPoint& aValue)
-{
-  class Message : public ControlMessage {
-  public:
-    Message(AudioNodeStream* aStream, uint32_t aIndex, const ThreeDPoint& aValue)
-      : ControlMessage(aStream), mValue(aValue), mIndex(aIndex) {}
-    virtual void Run()
-    {
-      static_cast<AudioNodeStream*>(mStream)->Engine()->
-          SetThreeDPointParameter(mIndex, mValue);
-    }
-    ThreeDPoint mValue;
-    uint32_t mIndex;
-  };
-
-  MOZ_ASSERT(this);
-  GraphImpl()->AppendMessage(new Message(this, aIndex, aValue));
-}
-
-void
-AudioNodeStream::SetBuffer(already_AddRefed<ThreadSharedFloatArrayBufferList> aBuffer)
-{
-  class Message : public ControlMessage {
-  public:
-    Message(AudioNodeStream* aStream,
-            already_AddRefed<ThreadSharedFloatArrayBufferList> aBuffer)
-      : ControlMessage(aStream), mBuffer(aBuffer) {}
-    virtual void Run()
-    {
-      static_cast<AudioNodeStream*>(mStream)->Engine()->
-          SetBuffer(mBuffer.forget());
-    }
-    nsRefPtr<ThreadSharedFloatArrayBufferList> mBuffer;
-  };
-
-  MOZ_ASSERT(this);
-  GraphImpl()->AppendMessage(new Message(this, aBuffer));
-}
-
-void
-AudioNodeStream::SetChannelMixingParameters(uint32_t aNumberOfChannels,
-                                            ChannelCountMode aChannelCountMode,
-                                            ChannelInterpretation aChannelInterpretation)
-{
-  class Message : public ControlMessage {
-  public:
-    Message(AudioNodeStream* aStream,
-            uint32_t aNumberOfChannels,
-            ChannelCountMode aChannelCountMode,
-            ChannelInterpretation aChannelInterpretation)
-      : ControlMessage(aStream),
-        mNumberOfChannels(aNumberOfChannels),
-        mChannelCountMode(aChannelCountMode),
-        mChannelInterpretation(aChannelInterpretation)
-    {}
-    virtual void Run()
-    {
-      static_cast<AudioNodeStream*>(mStream)->
-        SetChannelMixingParametersImpl(mNumberOfChannels, mChannelCountMode,
-                                       mChannelInterpretation);
-    }
-    uint32_t mNumberOfChannels;
-    ChannelCountMode mChannelCountMode;
-    ChannelInterpretation mChannelInterpretation;
-  };
-
-  MOZ_ASSERT(this);
-  GraphImpl()->AppendMessage(new Message(this, aNumberOfChannels,
-                                         aChannelCountMode,
-                                         aChannelInterpretation));
-}
-
-void
-AudioNodeStream::SetChannelMixingParametersImpl(uint32_t aNumberOfChannels,
-                                                ChannelCountMode aChannelCountMode,
-                                                ChannelInterpretation aChannelInterpretation)
-{
-  // Make sure that we're not clobbering any significant bits by fitting these
-  // values in 16 bits.
-  MOZ_ASSERT(int(aChannelCountMode) < INT16_MAX);
-  MOZ_ASSERT(int(aChannelInterpretation) < INT16_MAX);
-
-  mNumberOfInputChannels = aNumberOfChannels;
-  mMixingMode.mChannelCountMode = aChannelCountMode;
-  mMixingMode.mChannelInterpretation = aChannelInterpretation;
-}
-
-StreamBuffer::Track*
-AudioNodeStream::EnsureTrack()
-{
-  StreamBuffer::Track* track = mBuffer.FindTrack(AUDIO_NODE_STREAM_TRACK_ID);
-  if (!track) {
-    nsAutoPtr<MediaSegment> segment(new AudioSegment());
-    for (uint32_t j = 0; j < mListeners.Length(); ++j) {
-      MediaStreamListener* l = mListeners[j];
-      l->NotifyQueuedTrackChanges(Graph(), AUDIO_NODE_STREAM_TRACK_ID, IdealAudioRate(), 0,
-                                  MediaStreamListener::TRACK_EVENT_CREATED,
-                                  *segment);
-    }
-    track = &mBuffer.AddTrack(AUDIO_NODE_STREAM_TRACK_ID, IdealAudioRate(), 0, segment.forget());
-  }
-  return track;
-}
-
-bool
-AudioNodeStream::AllInputsFinished() const
-{
-  uint32_t inputCount = mInputs.Length();
-  for (uint32_t i = 0; i < inputCount; ++i) {
-    if (!mInputs[i]->GetSource()->IsFinishedOnGraphThread()) {
-      return false;
-    }
-  }
-  return !!inputCount;
-}
-
-void
-AudioNodeStream::ObtainInputBlock(AudioChunk& aTmpChunk, uint32_t aPortIndex)
-{
-  uint32_t inputCount = mInputs.Length();
-  uint32_t outputChannelCount = 1;
-  nsAutoTArray<AudioChunk*,250> inputChunks;
-  for (uint32_t i = 0; i < inputCount; ++i) {
-    if (aPortIndex != mInputs[i]->InputNumber()) {
-      // This input is connected to a different port
-      continue;
-    }
-    MediaStream* s = mInputs[i]->GetSource();
-    AudioNodeStream* a = static_cast<AudioNodeStream*>(s);
-    MOZ_ASSERT(a == s->AsAudioNodeStream());
-    if (a->IsFinishedOnGraphThread() ||
-        a->IsAudioParamStream()) {
-      continue;
-    }
-    AudioChunk* chunk = &a->mLastChunks[mInputs[i]->OutputNumber()];
-    MOZ_ASSERT(chunk);
-    if (chunk->IsNull()) {
-      continue;
-    }
-
-    inputChunks.AppendElement(chunk);
-    outputChannelCount =
-      GetAudioChannelsSuperset(outputChannelCount, chunk->mChannelData.Length());
-  }
-
-  switch (mMixingMode.mChannelCountMode) {
-  case ChannelCountMode::Explicit:
-    // Disregard the output channel count that we've calculated, and just use
-    // mNumberOfInputChannels.
-    outputChannelCount = mNumberOfInputChannels;
-    break;
-  case ChannelCountMode::Clamped_max:
-    // Clamp the computed output channel count to mNumberOfInputChannels.
-    outputChannelCount = std::min(outputChannelCount, mNumberOfInputChannels);
-    break;
-  case ChannelCountMode::Max:
-    // Nothing to do here, just shut up the compiler warning.
-    break;
-  }
-
-  uint32_t inputChunkCount = inputChunks.Length();
-  if (inputChunkCount == 0) {
-    aTmpChunk.SetNull(WEBAUDIO_BLOCK_SIZE);
-    return;
-  }
-
-  if (inputChunkCount == 1 &&
-      inputChunks[0]->mChannelData.Length() == outputChannelCount) {
-    aTmpChunk = *inputChunks[0];
-    return;
-  }
-
-  AllocateAudioBlock(outputChannelCount, &aTmpChunk);
-  float silenceChannel[WEBAUDIO_BLOCK_SIZE] = {0.f};
-  // The static storage here should be 1KB, so it's fine
-  nsAutoTArray<float, GUESS_AUDIO_CHANNELS*WEBAUDIO_BLOCK_SIZE> downmixBuffer;
-
-  for (uint32_t i = 0; i < inputChunkCount; ++i) {
-    AudioChunk* chunk = inputChunks[i];
-    nsAutoTArray<const void*,GUESS_AUDIO_CHANNELS> channels;
-    channels.AppendElements(chunk->mChannelData);
-    if (channels.Length() < outputChannelCount) {
-      if (mMixingMode.mChannelInterpretation == ChannelInterpretation::Speakers) {
-        AudioChannelsUpMix(&channels, outputChannelCount, nullptr);
-        NS_ASSERTION(outputChannelCount == channels.Length(),
-                     "We called GetAudioChannelsSuperset to avoid this");
-      } else {
-        // Fill up the remaining channels by zeros
-        for (uint32_t j = channels.Length(); j < outputChannelCount; ++j) {
-          channels.AppendElement(silenceChannel);
-        }
-      }
-    } else if (channels.Length() > outputChannelCount) {
-      if (mMixingMode.mChannelInterpretation == ChannelInterpretation::Speakers) {
-        nsAutoTArray<float*,GUESS_AUDIO_CHANNELS> outputChannels;
-        outputChannels.SetLength(outputChannelCount);
-        downmixBuffer.SetLength(outputChannelCount * WEBAUDIO_BLOCK_SIZE);
-        for (uint32_t j = 0; j < outputChannelCount; ++j) {
-          outputChannels[j] = &downmixBuffer[j * WEBAUDIO_BLOCK_SIZE];
-        }
-
-        AudioChannelsDownMix(channels, outputChannels.Elements(),
-                             outputChannelCount, WEBAUDIO_BLOCK_SIZE);
-
-        channels.SetLength(outputChannelCount);
-        for (uint32_t j = 0; j < channels.Length(); ++j) {
-          channels[j] = outputChannels[j];
-        }
-      } else {
-        // Drop the remaining channels
-        channels.RemoveElementsAt(outputChannelCount,
-                                  channels.Length() - outputChannelCount);
-      }
-    }
-
-    for (uint32_t c = 0; c < channels.Length(); ++c) {
-      const float* inputData = static_cast<const float*>(channels[c]);
-      float* outputData = static_cast<float*>(const_cast<void*>(aTmpChunk.mChannelData[c]));
-      if (inputData) {
-        if (i == 0) {
-          AudioBlockCopyChannelWithScale(inputData, chunk->mVolume, outputData);
-        } else {
-          AudioBlockAddChannelWithScale(inputData, chunk->mVolume, outputData);
-        }
-      } else {
-        if (i == 0) {
-          memset(outputData, 0, WEBAUDIO_BLOCK_SIZE*sizeof(float));
-        }
-      }
-    }
-  }
-}
-
-// The MediaStreamGraph guarantees that this is actually one block, for
-// AudioNodeStreams.
-void
-AudioNodeStream::ProduceOutput(GraphTime aFrom, GraphTime aTo)
-{
-  if (mMarkAsFinishedAfterThisBlock) {
-    // This stream was finished the last time that we looked at it, and all
-    // of the depending streams have finished their output as well, so now
-    // it's time to mark this stream as finished.
-    FinishOutput();
-  }
-
-  StreamBuffer::Track* track = EnsureTrack();
-
-  AudioSegment* segment = track->Get<AudioSegment>();
-
-  mLastChunks.SetLength(1);
-  mLastChunks[0].SetNull(0);
-
-  if (mInCycle) {
-    // XXX DelayNode not supported yet so just produce silence
-    mLastChunks[0].SetNull(WEBAUDIO_BLOCK_SIZE);
-  } else {
-    // We need to generate at least one input
-    uint16_t maxInputs = std::max(uint16_t(1), mEngine->InputCount());
-    OutputChunks inputChunks;
-    inputChunks.SetLength(maxInputs);
-    for (uint16_t i = 0; i < maxInputs; ++i) {
-      ObtainInputBlock(inputChunks[i], i);
-    }
-    bool finished = false;
-    if (maxInputs <= 1 && mEngine->OutputCount() <= 1) {
-      mEngine->ProduceAudioBlock(this, inputChunks[0], &mLastChunks[0], &finished);
-    } else {
-      mEngine->ProduceAudioBlocksOnPorts(this, inputChunks, mLastChunks, &finished);
-    }
-    if (finished) {
-      mMarkAsFinishedAfterThisBlock = true;
-    }
-  }
-
-  if (mKind == MediaStreamGraph::EXTERNAL_STREAM) {
-    segment->AppendAndConsumeChunk(&mLastChunks[0]);
-  } else {
-    segment->AppendNullData(mLastChunks[0].GetDuration());
-  }
-
-  for (uint32_t j = 0; j < mListeners.Length(); ++j) {
-    MediaStreamListener* l = mListeners[j];
-    AudioChunk copyChunk = mLastChunks[0];
-    AudioSegment tmpSegment;
-    tmpSegment.AppendAndConsumeChunk(&copyChunk);
-    l->NotifyQueuedTrackChanges(Graph(), AUDIO_NODE_STREAM_TRACK_ID,
-                                IdealAudioRate(), segment->GetDuration(), 0,
-                                tmpSegment);
-  }
-}
-
-TrackTicks
-AudioNodeStream::GetCurrentPosition()
-{
-  return EnsureTrack()->Get<AudioSegment>()->GetDuration();
-}
-
-void
-AudioNodeStream::FinishOutput()
-{
-  if (IsFinishedOnGraphThread()) {
-    return;
-  }
-
-  StreamBuffer::Track* track = EnsureTrack();
-  track->SetEnded();
-  FinishOnGraphThread();
-
-  for (uint32_t j = 0; j < mListeners.Length(); ++j) {
-    MediaStreamListener* l = mListeners[j];
-    AudioSegment emptySegment;
-    l->NotifyQueuedTrackChanges(Graph(), AUDIO_NODE_STREAM_TRACK_ID,
-                                IdealAudioRate(),
-                                track->GetSegment()->GetDuration(),
-                                MediaStreamListener::TRACK_EVENT_ENDED, emptySegment);
-  }
-}
-
-}
+/* -*- 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/. */
+
+#include "AudioNodeStream.h"
+
+#include "MediaStreamGraphImpl.h"
+#include "AudioNodeEngine.h"
+#include "ThreeDPoint.h"
+
+using namespace mozilla::dom;
+
+namespace mozilla {
+
+/**
+ * An AudioNodeStream produces a single audio track with ID
+ * AUDIO_NODE_STREAM_TRACK_ID. This track has rate IdealAudioRate().
+ * Each chunk in the track is a single block of WEBAUDIO_BLOCK_SIZE samples.
+ */
+static const int AUDIO_NODE_STREAM_TRACK_ID = 1;
+
+AudioNodeStream::~AudioNodeStream()
+{
+  MOZ_COUNT_DTOR(AudioNodeStream);
+}
+
+void
+AudioNodeStream::SetStreamTimeParameter(uint32_t aIndex, MediaStream* aRelativeToStream,
+                                        double aStreamTime)
+{
+  class Message : public ControlMessage {
+  public:
+    Message(AudioNodeStream* aStream, uint32_t aIndex, MediaStream* aRelativeToStream,
+            double aStreamTime)
+      : ControlMessage(aStream), mStreamTime(aStreamTime),
+        mRelativeToStream(aRelativeToStream), mIndex(aIndex) {}
+    virtual void Run()
+    {
+      static_cast<AudioNodeStream*>(mStream)->
+          SetStreamTimeParameterImpl(mIndex, mRelativeToStream, mStreamTime);
+    }
+    double mStreamTime;
+    MediaStream* mRelativeToStream;
+    uint32_t mIndex;
+  };
+
+  MOZ_ASSERT(this);
+  GraphImpl()->AppendMessage(new Message(this, aIndex, aRelativeToStream, aStreamTime));
+}
+
+void
+AudioNodeStream::SetStreamTimeParameterImpl(uint32_t aIndex, MediaStream* aRelativeToStream,
+                                            double aStreamTime)
+{
+  StreamTime streamTime = std::max<MediaTime>(0, SecondsToMediaTime(aStreamTime));
+  GraphTime graphTime = aRelativeToStream->StreamTimeToGraphTime(streamTime);
+  StreamTime thisStreamTime = GraphTimeToStreamTimeOptimistic(graphTime);
+  TrackTicks ticks = TimeToTicksRoundUp(IdealAudioRate(), thisStreamTime);
+  mEngine->SetStreamTimeParameter(aIndex, ticks);
+}
+
+void
+AudioNodeStream::SetDoubleParameter(uint32_t aIndex, double aValue)
+{
+  class Message : public ControlMessage {
+  public:
+    Message(AudioNodeStream* aStream, uint32_t aIndex, double aValue)
+      : ControlMessage(aStream), mValue(aValue), mIndex(aIndex) {}
+    virtual void Run()
+    {
+      static_cast<AudioNodeStream*>(mStream)->Engine()->
+          SetDoubleParameter(mIndex, mValue);
+    }
+    double mValue;
+    uint32_t mIndex;
+  };
+
+  MOZ_ASSERT(this);
+  GraphImpl()->AppendMessage(new Message(this, aIndex, aValue));
+}
+
+void
+AudioNodeStream::SetInt32Parameter(uint32_t aIndex, int32_t aValue)
+{
+  class Message : public ControlMessage {
+  public:
+    Message(AudioNodeStream* aStream, uint32_t aIndex, int32_t aValue)
+      : ControlMessage(aStream), mValue(aValue), mIndex(aIndex) {}
+    virtual void Run()
+    {
+      static_cast<AudioNodeStream*>(mStream)->Engine()->
+          SetInt32Parameter(mIndex, mValue);
+    }
+    int32_t mValue;
+    uint32_t mIndex;
+  };
+
+  MOZ_ASSERT(this);
+  GraphImpl()->AppendMessage(new Message(this, aIndex, aValue));
+}
+
+void
+AudioNodeStream::SetTimelineParameter(uint32_t aIndex,
+                                      const AudioParamTimeline& aValue)
+{
+  class Message : public ControlMessage {
+  public:
+    Message(AudioNodeStream* aStream, uint32_t aIndex,
+            const AudioParamTimeline& aValue)
+      : ControlMessage(aStream), mValue(aValue), mIndex(aIndex) {}
+    virtual void Run()
+    {
+      static_cast<AudioNodeStream*>(mStream)->Engine()->
+          SetTimelineParameter(mIndex, mValue);
+    }
+    AudioParamTimeline mValue;
+    uint32_t mIndex;
+  };
+  GraphImpl()->AppendMessage(new Message(this, aIndex, aValue));
+}
+
+void
+AudioNodeStream::SetThreeDPointParameter(uint32_t aIndex, const ThreeDPoint& aValue)
+{
+  class Message : public ControlMessage {
+  public:
+    Message(AudioNodeStream* aStream, uint32_t aIndex, const ThreeDPoint& aValue)
+      : ControlMessage(aStream), mValue(aValue), mIndex(aIndex) {}
+    virtual void Run()
+    {
+      static_cast<AudioNodeStream*>(mStream)->Engine()->
+          SetThreeDPointParameter(mIndex, mValue);
+    }
+    ThreeDPoint mValue;
+    uint32_t mIndex;
+  };
+
+  MOZ_ASSERT(this);
+  GraphImpl()->AppendMessage(new Message(this, aIndex, aValue));
+}
+
+void
+AudioNodeStream::SetBuffer(already_AddRefed<ThreadSharedFloatArrayBufferList> aBuffer)
+{
+  class Message : public ControlMessage {
+  public:
+    Message(AudioNodeStream* aStream,
+            already_AddRefed<ThreadSharedFloatArrayBufferList> aBuffer)
+      : ControlMessage(aStream), mBuffer(aBuffer) {}
+    virtual void Run()
+    {
+      static_cast<AudioNodeStream*>(mStream)->Engine()->
+          SetBuffer(mBuffer.forget());
+    }
+    nsRefPtr<ThreadSharedFloatArrayBufferList> mBuffer;
+  };
+
+  MOZ_ASSERT(this);
+  GraphImpl()->AppendMessage(new Message(this, aBuffer));
+}
+
+void
+AudioNodeStream::SetChannelMixingParameters(uint32_t aNumberOfChannels,
+                                            ChannelCountMode aChannelCountMode,
+                                            ChannelInterpretation aChannelInterpretation)
+{
+  class Message : public ControlMessage {
+  public:
+    Message(AudioNodeStream* aStream,
+            uint32_t aNumberOfChannels,
+            ChannelCountMode aChannelCountMode,
+            ChannelInterpretation aChannelInterpretation)
+      : ControlMessage(aStream),
+        mNumberOfChannels(aNumberOfChannels),
+        mChannelCountMode(aChannelCountMode),
+        mChannelInterpretation(aChannelInterpretation)
+    {}
+    virtual void Run()
+    {
+      static_cast<AudioNodeStream*>(mStream)->
+        SetChannelMixingParametersImpl(mNumberOfChannels, mChannelCountMode,
+                                       mChannelInterpretation);
+    }
+    uint32_t mNumberOfChannels;
+    ChannelCountMode mChannelCountMode;
+    ChannelInterpretation mChannelInterpretation;
+  };
+
+  MOZ_ASSERT(this);
+  GraphImpl()->AppendMessage(new Message(this, aNumberOfChannels,
+                                         aChannelCountMode,
+                                         aChannelInterpretation));
+}
+
+void
+AudioNodeStream::SetChannelMixingParametersImpl(uint32_t aNumberOfChannels,
+                                                ChannelCountMode aChannelCountMode,
+                                                ChannelInterpretation aChannelInterpretation)
+{
+  // Make sure that we're not clobbering any significant bits by fitting these
+  // values in 16 bits.
+  MOZ_ASSERT(int(aChannelCountMode) < INT16_MAX);
+  MOZ_ASSERT(int(aChannelInterpretation) < INT16_MAX);
+
+  mNumberOfInputChannels = aNumberOfChannels;
+  mMixingMode.mChannelCountMode = aChannelCountMode;
+  mMixingMode.mChannelInterpretation = aChannelInterpretation;
+}
+
+StreamBuffer::Track*
+AudioNodeStream::EnsureTrack()
+{
+  StreamBuffer::Track* track = mBuffer.FindTrack(AUDIO_NODE_STREAM_TRACK_ID);
+  if (!track) {
+    nsAutoPtr<MediaSegment> segment(new AudioSegment());
+    for (uint32_t j = 0; j < mListeners.Length(); ++j) {
+      MediaStreamListener* l = mListeners[j];
+      l->NotifyQueuedTrackChanges(Graph(), AUDIO_NODE_STREAM_TRACK_ID, IdealAudioRate(), 0,
+                                  MediaStreamListener::TRACK_EVENT_CREATED,
+                                  *segment);
+    }
+    track = &mBuffer.AddTrack(AUDIO_NODE_STREAM_TRACK_ID, IdealAudioRate(), 0, segment.forget());
+  }
+  return track;
+}
+
+bool
+AudioNodeStream::AllInputsFinished() const
+{
+  uint32_t inputCount = mInputs.Length();
+  for (uint32_t i = 0; i < inputCount; ++i) {
+    if (!mInputs[i]->GetSource()->IsFinishedOnGraphThread()) {
+      return false;
+    }
+  }
+  return !!inputCount;
+}
+
+void
+AudioNodeStream::ObtainInputBlock(AudioChunk& aTmpChunk, uint32_t aPortIndex)
+{
+  uint32_t inputCount = mInputs.Length();
+  uint32_t outputChannelCount = 1;
+  nsAutoTArray<AudioChunk*,250> inputChunks;
+  for (uint32_t i = 0; i < inputCount; ++i) {
+    if (aPortIndex != mInputs[i]->InputNumber()) {
+      // This input is connected to a different port
+      continue;
+    }
+    MediaStream* s = mInputs[i]->GetSource();
+    AudioNodeStream* a = static_cast<AudioNodeStream*>(s);
+    MOZ_ASSERT(a == s->AsAudioNodeStream());
+    if (a->IsFinishedOnGraphThread() ||
+        a->IsAudioParamStream()) {
+      continue;
+    }
+    AudioChunk* chunk = &a->mLastChunks[mInputs[i]->OutputNumber()];
+    MOZ_ASSERT(chunk);
+    if (chunk->IsNull()) {
+      continue;
+    }
+
+    inputChunks.AppendElement(chunk);
+    outputChannelCount =
+      GetAudioChannelsSuperset(outputChannelCount, chunk->mChannelData.Length());
+  }
+
+  switch (mMixingMode.mChannelCountMode) {
+  case ChannelCountMode::Explicit:
+    // Disregard the output channel count that we've calculated, and just use
+    // mNumberOfInputChannels.
+    outputChannelCount = mNumberOfInputChannels;
+    break;
+  case ChannelCountMode::Clamped_max:
+    // Clamp the computed output channel count to mNumberOfInputChannels.
+    outputChannelCount = std::min(outputChannelCount, mNumberOfInputChannels);
+    break;
+  case ChannelCountMode::Max:
+    // Nothing to do here, just shut up the compiler warning.
+    break;
+  }
+
+  uint32_t inputChunkCount = inputChunks.Length();
+  if (inputChunkCount == 0) {
+    aTmpChunk.SetNull(WEBAUDIO_BLOCK_SIZE);
+    return;
+  }
+
+  if (inputChunkCount == 1 &&
+      inputChunks[0]->mChannelData.Length() == outputChannelCount) {
+    aTmpChunk = *inputChunks[0];
+    return;
+  }
+
+  AllocateAudioBlock(outputChannelCount, &aTmpChunk);
+  float silenceChannel[WEBAUDIO_BLOCK_SIZE] = {0.f};
+  // The static storage here should be 1KB, so it's fine
+  nsAutoTArray<float, GUESS_AUDIO_CHANNELS*WEBAUDIO_BLOCK_SIZE> downmixBuffer;
+
+  for (uint32_t i = 0; i < inputChunkCount; ++i) {
+    AudioChunk* chunk = inputChunks[i];
+    nsAutoTArray<const void*,GUESS_AUDIO_CHANNELS> channels;
+    channels.AppendElements(chunk->mChannelData);
+    if (channels.Length() < outputChannelCount) {
+      if (mMixingMode.mChannelInterpretation == ChannelInterpretation::Speakers) {
+        AudioChannelsUpMix(&channels, outputChannelCount, nullptr);
+        NS_ASSERTION(outputChannelCount == channels.Length(),
+                     "We called GetAudioChannelsSuperset to avoid this");
+      } else {
+        // Fill up the remaining channels by zeros
+        for (uint32_t j = channels.Length(); j < outputChannelCount; ++j) {
+          channels.AppendElement(silenceChannel);
+        }
+      }
+    } else if (channels.Length() > outputChannelCount) {
+      if (mMixingMode.mChannelInterpretation == ChannelInterpretation::Speakers) {
+        nsAutoTArray<float*,GUESS_AUDIO_CHANNELS> outputChannels;
+        outputChannels.SetLength(outputChannelCount);
+        downmixBuffer.SetLength(outputChannelCount * WEBAUDIO_BLOCK_SIZE);
+        for (uint32_t j = 0; j < outputChannelCount; ++j) {
+          outputChannels[j] = &downmixBuffer[j * WEBAUDIO_BLOCK_SIZE];
+        }
+
+        AudioChannelsDownMix(channels, outputChannels.Elements(),
+                             outputChannelCount, WEBAUDIO_BLOCK_SIZE);
+
+        channels.SetLength(outputChannelCount);
+        for (uint32_t j = 0; j < channels.Length(); ++j) {
+          channels[j] = outputChannels[j];
+        }
+      } else {
+        // Drop the remaining channels
+        channels.RemoveElementsAt(outputChannelCount,
+                                  channels.Length() - outputChannelCount);
+      }
+    }
+
+    for (uint32_t c = 0; c < channels.Length(); ++c) {
+      const float* inputData = static_cast<const float*>(channels[c]);
+      float* outputData = static_cast<float*>(const_cast<void*>(aTmpChunk.mChannelData[c]));
+      if (inputData) {
+        if (i == 0) {
+          AudioBlockCopyChannelWithScale(inputData, chunk->mVolume, outputData);
+        } else {
+          AudioBlockAddChannelWithScale(inputData, chunk->mVolume, outputData);
+        }
+      } else {
+        if (i == 0) {
+          memset(outputData, 0, WEBAUDIO_BLOCK_SIZE*sizeof(float));
+        }
+      }
+    }
+  }
+}
+
+// The MediaStreamGraph guarantees that this is actually one block, for
+// AudioNodeStreams.
+void
+AudioNodeStream::ProduceOutput(GraphTime aFrom, GraphTime aTo)
+{
+  if (mMarkAsFinishedAfterThisBlock) {
+    // This stream was finished the last time that we looked at it, and all
+    // of the depending streams have finished their output as well, so now
+    // it's time to mark this stream as finished.
+    FinishOutput();
+  }
+
+  StreamBuffer::Track* track = EnsureTrack();
+
+  AudioSegment* segment = track->Get<AudioSegment>();
+
+  mLastChunks.SetLength(1);
+  mLastChunks[0].SetNull(0);
+
+  if (mInCycle) {
+    // XXX DelayNode not supported yet so just produce silence
+    mLastChunks[0].SetNull(WEBAUDIO_BLOCK_SIZE);
+  } else {
+    // We need to generate at least one input
+    uint16_t maxInputs = std::max(uint16_t(1), mEngine->InputCount());
+    OutputChunks inputChunks;
+    inputChunks.SetLength(maxInputs);
+    for (uint16_t i = 0; i < maxInputs; ++i) {
+      ObtainInputBlock(inputChunks[i], i);
+    }
+    bool finished = false;
+    if (maxInputs <= 1 && mEngine->OutputCount() <= 1) {
+      mEngine->ProduceAudioBlock(this, inputChunks[0], &mLastChunks[0], &finished);
+    } else {
+      mEngine->ProduceAudioBlocksOnPorts(this, inputChunks, mLastChunks, &finished);
+    }
+    if (finished) {
+      mMarkAsFinishedAfterThisBlock = true;
+    }
+  }
+
+  if (mKind == MediaStreamGraph::EXTERNAL_STREAM) {
+    segment->AppendAndConsumeChunk(&mLastChunks[0]);
+  } else {
+    segment->AppendNullData(mLastChunks[0].GetDuration());
+  }
+
+  for (uint32_t j = 0; j < mListeners.Length(); ++j) {
+    MediaStreamListener* l = mListeners[j];
+    AudioChunk copyChunk = mLastChunks[0];
+    AudioSegment tmpSegment;
+    tmpSegment.AppendAndConsumeChunk(&copyChunk);
+    l->NotifyQueuedTrackChanges(Graph(), AUDIO_NODE_STREAM_TRACK_ID,
+                                IdealAudioRate(), segment->GetDuration(), 0,
+                                tmpSegment);
+  }
+}
+
+TrackTicks
+AudioNodeStream::GetCurrentPosition()
+{
+  return EnsureTrack()->Get<AudioSegment>()->GetDuration();
+}
+
+void
+AudioNodeStream::FinishOutput()
+{
+  if (IsFinishedOnGraphThread()) {
+    return;
+  }
+
+  StreamBuffer::Track* track = EnsureTrack();
+  track->SetEnded();
+  FinishOnGraphThread();
+
+  for (uint32_t j = 0; j < mListeners.Length(); ++j) {
+    MediaStreamListener* l = mListeners[j];
+    AudioSegment emptySegment;
+    l->NotifyQueuedTrackChanges(Graph(), AUDIO_NODE_STREAM_TRACK_ID,
+                                IdealAudioRate(),
+                                track->GetSegment()->GetDuration(),
+                                MediaStreamListener::TRACK_EVENT_ENDED, emptySegment);
+  }
+}
+
+}
--- a/toolkit/devtools/debugger/server/dbg-browser-actors.js
+++ b/toolkit/devtools/debugger/server/dbg-browser-actors.js
@@ -663,27 +663,25 @@ DebuggerProgressListener.prototype = {
 
     // Skip non-interesting states.
     if (!isWindow || !isNetwork ||
         aProgress.DOMWindow != this._tabActor.contentWindow) {
       return;
     }
 
     if (isStart && aRequest instanceof Ci.nsIChannel) {
-      // If the request is about to happen in a new window, we are not concerned
-      // about the request.
-
       // Proceed normally only if the debuggee is not paused.
       if (this._tabActor.threadActor.state == "paused") {
         aRequest.suspend();
         this._tabActor.threadActor.onResume();
         this._tabActor.threadActor.dbg.enabled = false;
         this._tabActor._pendingNavigation = aRequest;
       }
 
+      this._tabActor.threadActor.disableAllBreakpoints();
       this._tabActor.conn.send({
         from: this._tabActor.actorID,
         type: "tabNavigated",
         url: aRequest.URI.spec,
         nativeConsoleAPI: true,
         state: "start",
       });
     } else if (isStop) {
--- a/toolkit/devtools/debugger/server/dbg-script-actors.js
+++ b/toolkit/devtools/debugger/server/dbg-script-actors.js
@@ -736,16 +736,32 @@ ThreadActor.prototype = {
     return this._discoverScriptsAndSources().then(() => {
       return {
         sources: [s.form() for (s of this.sources.iter())]
       };
     });
   },
 
   /**
+   * Disassociate all breakpoint actors from their scripts and clear the
+   * breakpoint handlers. This method can be used when the thread actor intends
+   * to keep the breakpoint store, but needs to clear any actual breakpoints,
+   * e.g. due to a page navigation. This way the breakpoint actors' script
+   * caches won't hold on to the Debugger.Script objects leaking memory.
+   */
+  disableAllBreakpoints: function () {
+    for (let url in this._breakpointStore) {
+      for (let line in this._breakpointStore[url]) {
+        let bp = this._breakpointStore[url][line];
+        bp.actor.removeScripts();
+      }
+    }
+  },
+
+  /**
    * Handle a protocol request to pause the debuggee.
    */
   onInterrupt: function TA_onInterrupt(aRequest) {
     if (this.state == "exited") {
       return { type: "exited" };
     } else if (this.state == "paused") {
       // TODO: return the actual reason for the existing pause.
       return { type: "paused", why: { type: "alreadyPaused" } };
@@ -1263,18 +1279,21 @@ ThreadActor.prototype = {
       // Set any stored breakpoints.
       let existing = this._breakpointStore[aScript.url];
       if (existing) {
         let endLine = aScript.startLine + aScript.lineCount - 1;
         // Iterate over the lines backwards, so that sliding breakpoints don't
         // affect the loop.
         for (let line = existing.length - 1; line >= 0; line--) {
           let bp = existing[line];
-          // Limit search to the line numbers contained in the new script.
-          if (bp && line >= aScript.startLine && line <= endLine) {
+          // Only consider breakpoints that are not already associated with
+          // scripts, and limit search to the line numbers contained in the new
+          // script.
+          if (bp && !bp.actor.scripts.length &&
+              line >= aScript.startLine && line <= endLine) {
             this._setBreakpoint(bp);
           }
         }
       }
 
       return true;
     });
   },
@@ -2046,16 +2065,26 @@ BreakpointActor.prototype = {
    *        The parent thread actor that contains this breakpoint.
    */
   addScript: function BA_addScript(aScript, aThreadActor) {
     this.threadActor = aThreadActor;
     this.scripts.push(aScript);
   },
 
   /**
+   * Remove the breakpoints from associated scripts and clear the script cache.
+   */
+  removeScripts: function () {
+    for (let script of this.scripts) {
+      script.clearBreakpoint(this);
+    }
+    this.scripts = [];
+  },
+
+  /**
    * A function that the engine calls when a breakpoint has been hit.
    *
    * @param aFrame Debugger.Frame
    *        The stack frame that contained the breakpoint.
    */
   hit: function BA_hit(aFrame) {
     // TODO: add the rest of the breakpoints on that line (bug 676602).
     let reason = { type: "breakpoint", actors: [ this.actorID ] };
@@ -2074,22 +2103,19 @@ BreakpointActor.prototype = {
    *
    * @param aRequest object
    *        The protocol request object.
    */
   onDelete: function BA_onDelete(aRequest) {
     // Remove from the breakpoint store.
     let scriptBreakpoints = this.threadActor._breakpointStore[this.location.url];
     delete scriptBreakpoints[this.location.line];
-    // Remove the actual breakpoint.
     this.threadActor._hooks.removeFromParentPool(this);
-    for (let script of this.scripts) {
-      script.clearBreakpoint(this);
-    }
-    this.scripts = null;
+    // Remove the actual breakpoint from the associated scripts.
+    this.removeScripts();
 
     return { from: this.actorID };
   }
 };
 
 BreakpointActor.prototype.requestTypes = {
   "delete": BreakpointActor.prototype.onDelete
 };
--- a/toolkit/devtools/styleeditor/dbg-styleeditor-actors.js
+++ b/toolkit/devtools/styleeditor/dbg-styleeditor-actors.js
@@ -144,20 +144,24 @@ StyleEditorActor.prototype = {
 
   /**
    * Event handler for document loaded event.
    */
   _onDocumentLoaded: function(event) {
     if (event) {
       this.win.removeEventListener("load", this._onDocumentLoaded, false);
     }
-    let styleSheets = [];
 
-    if (this.doc.styleSheets.length) {
-      this._addStyleSheets(this.doc.styleSheets);
+    let documents = [this.doc];
+    for (let doc of documents) {
+      this._addStyleSheets(doc.styleSheets);
+      // Recursively handle style sheets of the documents in iframes.
+      for (let iframe of doc.getElementsByTagName("iframe")) {
+        documents.push(iframe.contentDocument);
+      }
     }
   },
 
   /**
    * Clear all the current stylesheet actors in map.
    */
   _clearStyleSheetActors: function() {
     for (let actor in this._sheets) {