merge m-c to fx-team
authorTim Taubert <tim.taubert@gmx.de>
Wed, 15 Feb 2012 11:15:26 +0100
changeset 86788 81f6b9cbb2a92ac08d1ccc0c1b44d6a5c28f6e2a
parent 86782 d45c7d7b0079239c093dcb2ef3c0dda82ec793b4 (current diff)
parent 86787 5acf0e26ddcdf2afe5cedf7c8903d6058c6b572c (diff)
child 86891 46e22ce549b0b87f8bc944416894a1352af5d2ad
child 86970 4f8f17eacf31390bb66954fee225582f0548ab82
push id22057
push usertim.taubert@gmx.de
push dateWed, 15 Feb 2012 10:16:19 +0000
treeherdermozilla-central@81f6b9cbb2a9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone13.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 fx-team
toolkit/devtools/debugger/server/dbg-server.js
--- a/toolkit/content/tests/widgets/test_audiocontrols_dimensions.html
+++ b/toolkit/content/tests/widgets/test_audiocontrols_dimensions.html
@@ -5,32 +5,33 @@
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>  
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <p id="display"></p>
 
 <div id="content">
-  <audio id="audio" src="audio.wav" controls preload="auto"></audio>
+  <audio id="audio" controls preload="auto"></audio>
 </div>
 
 <pre id="test">
 <script type="text/javascript" src="use_large_cache.js"></script>
 <script class="testbody" type="text/javascript">
   function loadedmetadata(event) {
     is(event.type, "loadedmetadata", "checking event type");
     is(audio.clientHeight, "28", "checking height of audio element");
 
     SimpleTest.finish();
   }
 
-  var audio = document.getElementById("audio"), video;
+  var audio = document.getElementById("audio");
 
   // Kick off test once audio has loaded.
   audio.addEventListener("loadedmetadata", loadedmetadata, false);
+  audio.src = "audio.wav";
 
   SimpleTest.waitForExplicitFinish();
 
 </script>
 </pre>
 </body>
 </html>
--- a/toolkit/content/widgets/videocontrols.css
+++ b/toolkit/content/widgets/videocontrols.css
@@ -21,16 +21,20 @@
   direction: ltr;
   /* Prevent unwanted style inheritance. See bug 554717. */
   text-align: left;
   list-style-image: none !important;
   font: normal normal normal 100%/normal sans-serif !important;
   text-decoration: none !important;
 }
 
+.controlsSpacer[hideCursor] {
+ cursor: none;
+}
+
 /* CSS Transitions
  *
  * These are overriden by the default theme; the rules here just 
  * provide a fallback to drive the required transitionend event
  * (in case a 3rd party theme does not provide transitions).
  */
 .controlBar:not([immediate]) {
   -moz-transition-property: opacity;
--- a/toolkit/content/widgets/videocontrols.xml
+++ b/toolkit/content/widgets/videocontrols.xml
@@ -443,16 +443,20 @@
                     this._playButtonWidth = this.playButton.clientWidth;
                     this._durationLabelWidth = this.durationLabel.clientWidth;
                     this._muteButtonWidth = this.muteButton.clientWidth;
                     this._fullscreenButtonWidth = this.fullscreenButton.clientWidth;
                     this._controlBarHeight = this.controlBar.clientHeight;
                     this.controlBar.hidden = true;
                     this.adjustControlSize();
 
+                    // Preserve Statistics when toggling fullscreen mode due to bug 714071.
+                    if (this.video.mozMediaStatisticsShowing)
+                        this.showStatistics(true);
+
                     this._handleCustomEventsBound = this.handleCustomEvents.bind(this);
                     this.video.addEventListener("media-showStatistics", this._handleCustomEventsBound, false, true);
                 },
 
                 handleCustomEvents : function (e) {
                     if (!e.isTrusted)
                         return;
                     this.showStatistics(e.detail);
@@ -610,16 +614,17 @@
                             if (this.hasError()) {
                                 this.clickToPlay.hidden = true;
                                 this.statusIcon.setAttribute("type", "error");
                                 this.updateErrorText();
                                 this.setupStatusFader(true);
                                 // If video hasn't shown anything yet, disable the controls.
                                 if (!this.firstFrameShown)
                                     this.startFadeOut(this.controlBar);
+                                this.controlsSpacer.removeAttribute("hideCursor");
                             }
                             break;
                         default:
                             this.log("!!! event " + aEvent.type + " not handled!");
                     }
                 },
 
                 terminateEventListeners : function () {
@@ -891,18 +896,24 @@
                         element.removeAttribute("immediate");
 
                     if (fadeIn) {
                         element.hidden = false;
                         // force style resolution, so that transition begins
                         // when we remove the attribute.
                         element.clientTop;
                         element.removeAttribute("fadeout");
+                        if (element.className == "controlBar")
+                            this.controlsSpacer.removeAttribute("hideCursor");
                     } else {
                         element.setAttribute("fadeout", true);
+                        if (element.className == "controlBar" && !this.hasError() &&
+                            document.mozFullScreenElement == this.video)
+                            this.controlsSpacer.setAttribute("hideCursor", true);
+
                     }
                 },
 
                 onTransitionEnd : function (event) {
                     // Ignore events for things other than opacity changes.
                     if (event.propertyName != "opacity")
                         return;
 
--- a/toolkit/devtools/debugger/dbg-transport.js
+++ b/toolkit/devtools/debugger/dbg-transport.js
@@ -53,31 +53,37 @@ Cu.import("resource://gre/modules/NetUti
  *        The input stream.
  * @param aOutput nsIOutputStream
  *        The output stream.
  */
 function DebuggerTransport(aInput, aOutput)
 {
   this._input = aInput;
   this._output = aOutput;
+
+  this._converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
+    .createInstance(Ci.nsIScriptableUnicodeConverter);
+  this._converter.charset = "UTF-8";
+
   this._outgoing = "";
   this._incoming = "";
 }
 
 DebuggerTransport.prototype = {
   _hooks: null,
   get hooks() { return this._hooks; },
   set hooks(aHooks) { this._hooks = aHooks; },
 
   /**
    * Transmit the specified packet.
    */
   send: function DT_send(aPacket) {
     // TODO (bug 709088): remove pretty printing when the protocol is done.
     let data = JSON.stringify(aPacket, null, 2);
+    data = this._converter.ConvertFromUnicode(data);
     data = data.length + ':' + data;
     this._outgoing += data;
     this._flushOutgoing();
   },
 
   /**
    * Close the transport.
    */
@@ -154,16 +160,17 @@ DebuggerTransport.prototype = {
     }
 
     // We have a complete request, pluck it out of the data and parse it.
     this._incoming = this._incoming.substring(sep + 1);
     let packet = this._incoming.substring(0, count);
     this._incoming = this._incoming.substring(count);
 
     try {
+      packet = this._converter.ConvertToUnicode(packet);
       var parsed = JSON.parse(packet);
     } catch(e) {
       dumpn("Error parsing incoming packet: " + packet + " (" + e + " - " + e.stack + ")");
       return true;
     }
 
     try {
       dumpn("Got: " + packet);
deleted file mode 100644
--- a/toolkit/devtools/debugger/server/dbg-server.js
+++ /dev/null
@@ -1,474 +0,0 @@
-/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- *   Mozilla Foundation
- * Portions created by the Initial Developer are Copyright (C) 2011
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Dave Camp <dcamp@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-"use strict";
-/**
- * Toolkit glue for the remote debugging protocol, loaded into the
- * debugging global.
- */
-
-const Ci = Components.interfaces;
-const Cc = Components.classes;
-const CC = Components.Constructor;
-const Cu = Components.utils;
-
-function dumpn(str) {
-  dump("DBG-SERVER: " + str + "\n");
-}
-
-function dbg_assert(cond, e) {
-  if (!cond) {
-    return e;
-  }
-}
-
-loadSubScript.call(this, "chrome://global/content/devtools/dbg-transport.js");
-
-// XPCOM constructors
-const ServerSocket = CC("@mozilla.org/network/server-socket;1",
-                        "nsIServerSocket",
-                        "init");
-
-/***
- * Public API
- */
-var DebuggerServer = {
-  _listener: null,
-  _transportInitialized: false,
-  xpcInspector: null,
-
-  /**
-   * Initialize the debugger server.
-   */
-  init: function DH_init() {
-    if (this.initialized) {
-      return;
-    }
-
-    Cu.import("resource://gre/modules/jsdebugger.jsm");
-    this.xpcInspector = Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector);
-    this.initTransport();
-    this.addActors("chrome://global/content/devtools/dbg-script-actors.js");
-  },
-
-  /**
-   * Initialize the debugger server's transport variables.  This can be
-   * in place of init() for cases where the jsdebugger isn't needed.
-   */
-  initTransport: function DH_initTransport() {
-    if (this._transportInitialized) {
-      return;
-    }
-
-    this._connections = {};
-    this._nextConnID = 0;
-    this._transportInitialized = true;
-  },
-
-  get initialized() { return !!this.xpcInspector; },
-
-  /**
-   * Load a subscript into the debugging global.
-   *
-   * @param aURL string A url that will be loaded as a subscript into the
-   *        debugging global.  The user must load at least one script
-   *        that implements a createRootActor() function to create the
-   *        server's root actor.
-   */
-  addActors: function DH_addActors(aURL) {
-    loadSubScript.call(this, aURL);
-  },
-
-  /**
-   * Install Firefox-specific actors.
-   */
-  addBrowserActors: function DH_addBrowserActors() {
-    this.addActors("chrome://global/content/devtools/dbg-browser-actors.js");
-  },
-
-  /**
-   * Listens on the given port for remote debugger connections.
-   *
-   * @param aPort int
-   *        The port to listen on.
-   * @param aLocalOnly bool
-   *        If true, server will listen on the loopback device.
-   */
-  openListener: function DH_openListener(aPort, aLocalOnly) {
-    this._checkInit();
-
-    if (this._listener) {
-      throw "Debugging listener already open.";
-    }
-
-    try {
-      let socket = new ServerSocket(aPort, aLocalOnly, 4);
-      socket.asyncListen(this);
-      this._listener = socket;
-    } catch (e) {
-      dumpn("Could not start debugging listener on port " + aPort + ": " + e);
-      throw Cr.NS_ERROR_NOT_AVAILABLE;
-    }
-
-    return true;
-  },
-
-  /**
-   * Close a previously-opened TCP listener.
-   */
-  closeListener: function DH_closeListener() {
-    this._checkInit();
-
-    if (!this._listener) {
-      return false;
-    }
-
-    this._listener.close();
-    this._listener = null;
-
-    return true;
-  },
-
-  /**
-   * Creates a new connection to the local debugger speaking over an
-   * nsIPipe.
-   *
-   * @returns a client-side DebuggerTransport for communicating with
-   *          the newly-created connection.
-   */
-  connectPipe: function DH_connectPipe() {
-    this._checkInit();
-
-    let toServer = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe);
-    toServer.init(true, true, 0, 0, null);
-    let toClient = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe);
-    toClient.init(true, true, 0, 0, null);
-
-    let serverTransport = new DebuggerTransport(toServer.inputStream,
-                                                toClient.outputStream);
-    this._onConnection(serverTransport);
-
-    return new DebuggerTransport(toClient.inputStream, toServer.outputStream);
-  },
-
-
-  // nsIServerSocketListener implementation
-
-  onSocketAccepted: function DH_onSocketAccepted(aSocket, aTransport) {
-    dumpn("New debugging connection on " + aTransport.host + ":" + aTransport.port);
-
-    try {
-      let input = aTransport.openInputStream(0, 0, 0);
-      let output = aTransport.openOutputStream(0, 0, 0);
-      let transport = new DebuggerTransport(input, output);
-      DebuggerServer._onConnection(transport);
-    } catch (e) {
-      dumpn("Couldn't initialize connection: " + e + " - " + e.stack);
-    }
-  },
-
-  onStopListening: function DH_onStopListening() { },
-
-  /**
-   * Raises an exception if the server has not been properly initialized.
-   */
-  _checkInit: function DH_checkInit() {
-    if (!this._transportInitialized) {
-      throw "DebuggerServer has not been initialized.";
-    }
-
-    if (!this.createRootActor) {
-      throw "Use DebuggerServer.addActors() to add a root actor implementation.";
-    }
-  },
-
-  /**
-   * Create a new debugger connection for the given transport.  Called
-   * after connectPipe() or after an incoming socket connection.
-   */
-  _onConnection: function DH_onConnection(aTransport) {
-    let connID = "conn" + this._nextConnID++ + '.';
-    let conn = new DebuggerServerConnection(connID, aTransport);
-    this._connections[connID] = conn;
-
-    // Create a root actor for the connection and send the hello packet.
-    conn.rootActor = this.createRootActor(conn);
-    conn.addActor(conn.rootActor);
-    aTransport.send(conn.rootActor.sayHello());
-    aTransport.ready();
-  },
-
-  /**
-   * Remove the connection from the debugging server.
-   */
-  _connectionClosed: function DH_connectionClosed(aConnection) {
-    delete this._connections[aConnection.prefix];
-  }
-};
-
-/**
- * Construct an ActorPool.
- *
- * ActorPools are actorID -> actor mapping and storage.  These are
- * used to accumulate and quickly dispose of groups of actors that
- * share a lifetime.
- */
-function ActorPool(aConnection)
-{
-  this.conn = aConnection;
-  this._cleanups = {};
-  this._actors = {};
-}
-
-ActorPool.prototype = {
-  /**
-   * Add an actor to the actor pool.  If the actor doesn't have an ID,
-   * allocate one from the connection.
-   *
-   * @param aActor object
-   *        The actor implementation.  If the object has a
-   *        'disconnected' property, it will be called when the actor
-   *        pool is cleaned up.
-   */
-  addActor: function AP_addActor(aActor) {
-    aActor.conn = this.conn;
-    if (!aActor.actorID) {
-      aActor.actorID = this.conn.allocID(aActor.actorPrefix || undefined);
-    }
-
-    if (aActor.registeredPool) {
-      aActor.registeredPool.removeActor(aActor);
-    }
-    aActor.registeredPool = this;
-
-    this._actors[aActor.actorID] = aActor;
-    if (aActor.disconnect) {
-      this._cleanups[aActor.actorID] = aActor;
-    }
-  },
-
-  get: function AP_get(aActorID) {
-    return this._actors[aActorID];
-  },
-
-  has: function AP_has(aActorID) {
-    return aActorID in this._actors;
-  },
-
-  /**
-   * Remove an actor from the actor pool.
-   */
-  removeActor: function AP_remove(aActorID) {
-    delete this._actors[aActorID];
-    delete this._cleanups[aActorID];
-  },
-
-  /**
-   * Run all cleanups previously registered with addCleanup.
-   */
-  cleanup: function AP_cleanup() {
-    for each (let actor in this._cleanups) {
-      actor.disconnect();
-    }
-    this._cleanups = {};
-  }
-}
-
-/**
- * Creates a DebuggerServerConnection.
- *
- * Represents a connection to this debugging global from a client.
- * Manages a set of actors and actor pools, allocates actor ids, and
- * handles incoming requests.
- *
- * @param aPrefix string
- *        All actor IDs created by this connection should be prefixed
- *        with aPrefix.
- * @param aTransport transport
- *        Packet transport for the debugging protocol.
- */
-function DebuggerServerConnection(aPrefix, aTransport)
-{
-  this._prefix = aPrefix;
-  this._transport = aTransport;
-  this._transport.hooks = this;
-  this._nextID = 1;
-
-  this._actorPool = new ActorPool(this);
-  this._extraPools = [];
-}
-
-DebuggerServerConnection.prototype = {
-  _prefix: null,
-  get prefix() { return this._prefix },
-
-  _transport: null,
-  get transport() { return this._transport },
-
-  send: function DSC_send(aPacket) {
-    this.transport.send(aPacket);
-  },
-
-  allocID: function DSC_allocID(aPrefix) {
-    return this.prefix + (aPrefix || '') + this._nextID++;
-  },
-
-  /**
-   * Add a map of actor IDs to the connection.
-   */
-  addActorPool: function DSC_addActorPool(aActorPool) {
-    this._extraPools.push(aActorPool);
-  },
-
-  /**
-   * Remove a previously-added pool of actors to the connection.
-   */
-  removeActorPool: function DSC_removeActorPool(aActorPool) {
-    let index = this._extraPools.splice(this._extraPools.lastIndexOf(aActorPool), 1);
-  },
-
-  /**
-   * Add an actor to the default actor pool for this connection.
-   */
-  addActor: function DSC_addActor(aActor) {
-    this._actorPool.addActor(aActor);
-  },
-
-  /**
-   * Remove an actor to the default actor pool for this connection.
-   */
-  removeActor: function DSC_removeActor(aActor) {
-    this._actorPool.removeActor(aActor);
-  },
-
-  /**
-   * Add a cleanup to the default actor pool for this connection.
-   */
-  addCleanup: function DSC_addCleanup(aCleanup) {
-    this._actorPool.addCleanup(aCleanup);
-  },
-
-  /**
-   * Look up an actor implementation for an actorID.  Will search
-   * all the actor pools registered with the connection.
-   *
-   * @param aActorID string
-   *        Actor ID to look up.
-   */
-  getActor: function DSC_getActor(aActorID) {
-    if (this._actorPool.has(aActorID)) {
-      return this._actorPool.get(aActorID);
-    }
-
-    for each (let pool in this._extraPools) {
-      if (pool.has(aActorID)) {
-        return pool.get(aActorID);
-      }
-    }
-
-    if (aActorID === "root") {
-      return this.rootActor;
-    }
-
-    return null;
-  },
-
-  // Transport hooks.
-
-  /**
-   * Called by DebuggerTransport to dispatch incoming packets as appropriate.
-   *
-   * @param aPacket object
-   *        The incoming packet.
-   */
-  onPacket: function DSC_onPacket(aPacket) {
-    let actor = this.getActor(aPacket.to);
-    if (!actor) {
-      this.transport.send({ from: aPacket.to ? aPacket.to : "root",
-                            error: "noSuchActor" });
-      return;
-    }
-
-    var ret = null;
-
-    // Dispatch the request to the actor.
-    if (actor.requestTypes && actor.requestTypes[aPacket.type]) {
-      try {
-        ret = actor.requestTypes[aPacket.type].bind(actor)(aPacket);
-      } catch(e) {
-        Cu.reportError(e);
-        ret = { error: "unknownError",
-                message: "An unknown error has occurred while processing request." };
-      }
-    } else {
-      ret = { error: "unrecognizedPacketType",
-              message: 'Actor "' + actor.actorID + '" does not recognize the packet type "' + aPacket.type + '"' };
-    }
-
-    if (!ret) {
-      // XXX: The actor wasn't ready to reply yet, don't process new
-      // requests until it does.
-      return;
-    }
-
-    if (!ret.from) {
-      ret.from = aPacket.to;
-    }
-
-    this.transport.send(ret);
-  },
-
-  /**
-   * Called by DebuggerTransport when the underlying stream is closed.
-   *
-   * @param aStatus nsresult
-   *        The status code that corresponds to the reason for closing
-   *        the stream.
-   */
-  onClosed: function DSC_onClosed(aStatus) {
-    dumpn("Cleaning up connection.");
-
-    this._actorPool.cleanup();
-    this._actorPool = null;
-    this._extraPools.map(function(p) { p.cleanup(); });
-    this._extraPools = null;
-
-    DebuggerServer._connectionClosed(this);
-  }
-};
--- a/toolkit/devtools/debugger/server/dbg-server.jsm
+++ b/toolkit/devtools/debugger/server/dbg-server.jsm
@@ -32,40 +32,458 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+"use strict";
+/**
+ * Toolkit glue for the remote debugging protocol, loaded into the
+ * debugging global.
+ */
+
+const Ci = Components.interfaces;
 const Cc = Components.classes;
-const Ci = Components.interfaces;
+const CC = Components.Constructor;
 const Cu = Components.utils;
-const Cr = Components.results;
 
-var EXPORTED_SYMBOLS = ["DebuggerServer"]
+var EXPORTED_SYMBOLS = ["DebuggerServer"];
 
 function loadSubScript(aURL)
 {
   try {
     let loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
       .getService(Components.interfaces.mozIJSSubScriptLoader);
     loader.loadSubScript(aURL, this);
   } catch(e) {
     dump("Error loading: " + aURL + ": " + e + " - " + e.stack + "\n");
 
     throw e;
   }
 }
 
-Cu.import("resource:///modules/devtools/dbg-client.jsm");
+function dumpn(str) {
+  dump("DBG-SERVER: " + str + "\n");
+}
+
+function dbg_assert(cond, e) {
+  if (!cond) {
+    return e;
+  }
+}
+
+loadSubScript.call(this, "chrome://global/content/devtools/dbg-transport.js");
+
+// XPCOM constructors
+const ServerSocket = CC("@mozilla.org/network/server-socket;1",
+                        "nsIServerSocket",
+                        "init");
+
+/***
+ * Public API
+ */
+var DebuggerServer = {
+  _listener: null,
+  _transportInitialized: false,
+  xpcInspector: null,
+
+  /**
+   * Initialize the debugger server.
+   */
+  init: function DH_init() {
+    if (this.initialized) {
+      return;
+    }
+
+    Cu.import("resource://gre/modules/jsdebugger.jsm");
+    this.xpcInspector = Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector);
+    this.initTransport();
+    this.addActors("chrome://global/content/devtools/dbg-script-actors.js");
+  },
+
+  /**
+   * Initialize the debugger server's transport variables.  This can be
+   * in place of init() for cases where the jsdebugger isn't needed.
+   */
+  initTransport: function DH_initTransport() {
+    if (this._transportInitialized) {
+      return;
+    }
+
+    this._connections = {};
+    this._nextConnID = 0;
+    this._transportInitialized = true;
+  },
+
+  get initialized() { return !!this.xpcInspector; },
+
+  /**
+   * Load a subscript into the debugging global.
+   *
+   * @param aURL string A url that will be loaded as a subscript into the
+   *        debugging global.  The user must load at least one script
+   *        that implements a createRootActor() function to create the
+   *        server's root actor.
+   */
+  addActors: function DH_addActors(aURL) {
+    loadSubScript.call(this, aURL);
+  },
+
+  /**
+   * Install Firefox-specific actors.
+   */
+  addBrowserActors: function DH_addBrowserActors() {
+    this.addActors("chrome://global/content/devtools/dbg-browser-actors.js");
+  },
+
+  /**
+   * Listens on the given port for remote debugger connections.
+   *
+   * @param aPort int
+   *        The port to listen on.
+   * @param aLocalOnly bool
+   *        If true, server will listen on the loopback device.
+   */
+  openListener: function DH_openListener(aPort, aLocalOnly) {
+    this._checkInit();
+
+    if (this._listener) {
+      throw "Debugging listener already open.";
+    }
+
+    try {
+      let socket = new ServerSocket(aPort, aLocalOnly, 4);
+      socket.asyncListen(this);
+      this._listener = socket;
+    } catch (e) {
+      dumpn("Could not start debugging listener on port " + aPort + ": " + e);
+      throw Cr.NS_ERROR_NOT_AVAILABLE;
+    }
+
+    return true;
+  },
+
+  /**
+   * Close a previously-opened TCP listener.
+   */
+  closeListener: function DH_closeListener() {
+    this._checkInit();
+
+    if (!this._listener) {
+      return false;
+    }
+
+    this._listener.close();
+    this._listener = null;
+
+    return true;
+  },
+
+  /**
+   * Creates a new connection to the local debugger speaking over an
+   * nsIPipe.
+   *
+   * @returns a client-side DebuggerTransport for communicating with
+   *          the newly-created connection.
+   */
+  connectPipe: function DH_connectPipe() {
+    this._checkInit();
+
+    let toServer = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe);
+    toServer.init(true, true, 0, 0, null);
+    let toClient = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe);
+    toClient.init(true, true, 0, 0, null);
+
+    let serverTransport = new DebuggerTransport(toServer.inputStream,
+                                                toClient.outputStream);
+    this._onConnection(serverTransport);
+
+    return new DebuggerTransport(toClient.inputStream, toServer.outputStream);
+  },
+
+
+  // nsIServerSocketListener implementation
+
+  onSocketAccepted: function DH_onSocketAccepted(aSocket, aTransport) {
+    dumpn("New debugging connection on " + aTransport.host + ":" + aTransport.port);
+
+    try {
+      let input = aTransport.openInputStream(0, 0, 0);
+      let output = aTransport.openOutputStream(0, 0, 0);
+      let transport = new DebuggerTransport(input, output);
+      DebuggerServer._onConnection(transport);
+    } catch (e) {
+      dumpn("Couldn't initialize connection: " + e + " - " + e.stack);
+    }
+  },
+
+  onStopListening: function DH_onStopListening() { },
+
+  /**
+   * Raises an exception if the server has not been properly initialized.
+   */
+  _checkInit: function DH_checkInit() {
+    if (!this._transportInitialized) {
+      throw "DebuggerServer has not been initialized.";
+    }
+
+    if (!this.createRootActor) {
+      throw "Use DebuggerServer.addActors() to add a root actor implementation.";
+    }
+  },
+
+  /**
+   * Create a new debugger connection for the given transport.  Called
+   * after connectPipe() or after an incoming socket connection.
+   */
+  _onConnection: function DH_onConnection(aTransport) {
+    let connID = "conn" + this._nextConnID++ + '.';
+    let conn = new DebuggerServerConnection(connID, aTransport);
+    this._connections[connID] = conn;
+
+    // Create a root actor for the connection and send the hello packet.
+    conn.rootActor = this.createRootActor(conn);
+    conn.addActor(conn.rootActor);
+    aTransport.send(conn.rootActor.sayHello());
+    aTransport.ready();
+  },
+
+  /**
+   * Remove the connection from the debugging server.
+   */
+  _connectionClosed: function DH_connectionClosed(aConnection) {
+    delete this._connections[aConnection.prefix];
+  }
+};
+
+/**
+ * Construct an ActorPool.
+ *
+ * ActorPools are actorID -> actor mapping and storage.  These are
+ * used to accumulate and quickly dispose of groups of actors that
+ * share a lifetime.
+ */
+function ActorPool(aConnection)
+{
+  this.conn = aConnection;
+  this._cleanups = {};
+  this._actors = {};
+}
 
-// Load the debugging server in a sandbox with its own compartment.
-// Note that this is slated for elimination in bug 703718.
-var systemPrincipal = Cc["@mozilla.org/systemprincipal;1"]
-  .createInstance(Ci.nsIPrincipal);
+ActorPool.prototype = {
+  /**
+   * Add an actor to the actor pool.  If the actor doesn't have an ID,
+   * allocate one from the connection.
+   *
+   * @param aActor object
+   *        The actor implementation.  If the object has a
+   *        'disconnected' property, it will be called when the actor
+   *        pool is cleaned up.
+   */
+  addActor: function AP_addActor(aActor) {
+    aActor.conn = this.conn;
+    if (!aActor.actorID) {
+      aActor.actorID = this.conn.allocID(aActor.actorPrefix || undefined);
+    }
+
+    if (aActor.registeredPool) {
+      aActor.registeredPool.removeActor(aActor);
+    }
+    aActor.registeredPool = this;
+
+    this._actors[aActor.actorID] = aActor;
+    if (aActor.disconnect) {
+      this._cleanups[aActor.actorID] = aActor;
+    }
+  },
+
+  get: function AP_get(aActorID) {
+    return this._actors[aActorID];
+  },
+
+  has: function AP_has(aActorID) {
+    return aActorID in this._actors;
+  },
+
+  /**
+   * Remove an actor from the actor pool.
+   */
+  removeActor: function AP_remove(aActorID) {
+    delete this._actors[aActorID];
+    delete this._cleanups[aActorID];
+  },
+
+  /**
+   * Run all cleanups previously registered with addCleanup.
+   */
+  cleanup: function AP_cleanup() {
+    for each (let actor in this._cleanups) {
+      actor.disconnect();
+    }
+    this._cleanups = {};
+  }
+}
+
+/**
+ * Creates a DebuggerServerConnection.
+ *
+ * Represents a connection to this debugging global from a client.
+ * Manages a set of actors and actor pools, allocates actor ids, and
+ * handles incoming requests.
+ *
+ * @param aPrefix string
+ *        All actor IDs created by this connection should be prefixed
+ *        with aPrefix.
+ * @param aTransport transport
+ *        Packet transport for the debugging protocol.
+ */
+function DebuggerServerConnection(aPrefix, aTransport)
+{
+  this._prefix = aPrefix;
+  this._transport = aTransport;
+  this._transport.hooks = this;
+  this._nextID = 1;
+
+  this._actorPool = new ActorPool(this);
+  this._extraPools = [];
+}
+
+DebuggerServerConnection.prototype = {
+  _prefix: null,
+  get prefix() { return this._prefix },
+
+  _transport: null,
+  get transport() { return this._transport },
+
+  send: function DSC_send(aPacket) {
+    this.transport.send(aPacket);
+  },
+
+  allocID: function DSC_allocID(aPrefix) {
+    return this.prefix + (aPrefix || '') + this._nextID++;
+  },
+
+  /**
+   * Add a map of actor IDs to the connection.
+   */
+  addActorPool: function DSC_addActorPool(aActorPool) {
+    this._extraPools.push(aActorPool);
+  },
+
+  /**
+   * Remove a previously-added pool of actors to the connection.
+   */
+  removeActorPool: function DSC_removeActorPool(aActorPool) {
+    let index = this._extraPools.splice(this._extraPools.lastIndexOf(aActorPool), 1);
+  },
 
-var gGlobal = Cu.Sandbox(systemPrincipal);
-gGlobal.importFunction(loadSubScript);
-gGlobal.loadSubScript("chrome://global/content/devtools/dbg-server.js");
+  /**
+   * Add an actor to the default actor pool for this connection.
+   */
+  addActor: function DSC_addActor(aActor) {
+    this._actorPool.addActor(aActor);
+  },
+
+  /**
+   * Remove an actor to the default actor pool for this connection.
+   */
+  removeActor: function DSC_removeActor(aActor) {
+    this._actorPool.removeActor(aActor);
+  },
+
+  /**
+   * Add a cleanup to the default actor pool for this connection.
+   */
+  addCleanup: function DSC_addCleanup(aCleanup) {
+    this._actorPool.addCleanup(aCleanup);
+  },
+
+  /**
+   * Look up an actor implementation for an actorID.  Will search
+   * all the actor pools registered with the connection.
+   *
+   * @param aActorID string
+   *        Actor ID to look up.
+   */
+  getActor: function DSC_getActor(aActorID) {
+    if (this._actorPool.has(aActorID)) {
+      return this._actorPool.get(aActorID);
+    }
+
+    for each (let pool in this._extraPools) {
+      if (pool.has(aActorID)) {
+        return pool.get(aActorID);
+      }
+    }
+
+    if (aActorID === "root") {
+      return this.rootActor;
+    }
+
+    return null;
+  },
+
+  // Transport hooks.
 
-var DebuggerServer = gGlobal.DebuggerServer;
+  /**
+   * Called by DebuggerTransport to dispatch incoming packets as appropriate.
+   *
+   * @param aPacket object
+   *        The incoming packet.
+   */
+  onPacket: function DSC_onPacket(aPacket) {
+    let actor = this.getActor(aPacket.to);
+    if (!actor) {
+      this.transport.send({ from: aPacket.to ? aPacket.to : "root",
+                            error: "noSuchActor" });
+      return;
+    }
+
+    var ret = null;
+
+    // Dispatch the request to the actor.
+    if (actor.requestTypes && actor.requestTypes[aPacket.type]) {
+      try {
+        ret = actor.requestTypes[aPacket.type].bind(actor)(aPacket);
+      } catch(e) {
+        Cu.reportError(e);
+        ret = { error: "unknownError",
+                message: "An unknown error has occurred while processing request." };
+      }
+    } else {
+      ret = { error: "unrecognizedPacketType",
+              message: 'Actor "' + actor.actorID + '" does not recognize the packet type "' + aPacket.type + '"' };
+    }
+
+    if (!ret) {
+      // XXX: The actor wasn't ready to reply yet, don't process new
+      // requests until it does.
+      return;
+    }
+
+    if (!ret.from) {
+      ret.from = aPacket.to;
+    }
+
+    this.transport.send(ret);
+  },
+
+  /**
+   * Called by DebuggerTransport when the underlying stream is closed.
+   *
+   * @param aStatus nsresult
+   *        The status code that corresponds to the reason for closing
+   *        the stream.
+   */
+  onClosed: function DSC_onClosed(aStatus) {
+    dumpn("Cleaning up connection.");
+
+    this._actorPool.cleanup();
+    this._actorPool = null;
+    this._extraPools.map(function(p) { p.cleanup(); });
+    this._extraPools = null;
+
+    DebuggerServer._connectionClosed(this);
+  }
+};
--- a/toolkit/devtools/debugger/tests/unit/test_dbgsocket.js
+++ b/toolkit/devtools/debugger/tests/unit/test_dbgsocket.js
@@ -23,27 +23,30 @@ function really_long() {
   }
   return ret;
 }
 
 function test_socket_conn()
 {
   DebuggerServer.openListener(2929, true);
 
+  let unicodeString = "(╯°□°)╯︵ ┻━┻";
   let transport = debuggerSocketConnect("127.0.0.1", 2929);
   transport.hooks = {
     onPacket: function(aPacket) {
       this.onPacket = function(aPacket) {
+        do_check_eq(aPacket.unicode, unicodeString);
         transport.close();
       }
       // Verify that things work correctly when bigger than the output
-      // transport buffers...
+      // transport buffers and when transporting unicode...
       transport.send({to: "root",
                       type: "echo",
-                      reallylong: really_long()});
+                      reallylong: really_long(),
+                      unicode: unicodeString});
       do_check_eq(aPacket.from, "root");
     },
     onClosed: function(aStatus) {
       run_next_test();
     },
   };
   transport.ready();
 }
--- a/toolkit/devtools/jar.mn
+++ b/toolkit/devtools/jar.mn
@@ -1,5 +1,4 @@
 toolkit.jar:
   content/global/devtools/dbg-transport.js        (debugger/dbg-transport.js)
-  content/global/devtools/dbg-server.js           (debugger/server/dbg-server.js)
   content/global/devtools/dbg-script-actors.js    (debugger/server/dbg-script-actors.js)
   content/global/devtools/dbg-browser-actors.js   (debugger/server/dbg-browser-actors.js)