Merge mozilla-central to fx-team
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Tue, 18 Nov 2014 17:34:34 +0100
changeset 216370 a8a9d42356c8bdf21f91432d28a0999b59a44057
parent 216369 2ca6377a2a16f31241bb8a34de936619072c961a (current diff)
parent 216266 084441e904d1225f15d5f641cc0efb82d4ead4cd (diff)
child 216371 121a5cc63382816393d515993817925c41c1f2f7
push id52026
push userkwierso@gmail.com
push dateWed, 19 Nov 2014 02:37:17 +0000
treeherdermozilla-inbound@d197d16c0caa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone36.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 mozilla-central to fx-team
b2g/components/test/unit/data/test_properties
dom/apps/tests/file_test_widget.js
dom/apps/tests/test_widget_browser.html
dom/browser-element/BrowserElementParent.js
dom/browser-element/nsIBrowserElementAPI.idl
dom/html/nsBrowserElement.cpp
dom/html/nsBrowserElement.h
dom/webidl/BrowserElement.webidl
netwerk/protocol/http/SpdyPush3.cpp
netwerk/protocol/http/SpdyPush3.h
netwerk/protocol/http/SpdySession3.cpp
netwerk/protocol/http/SpdySession3.h
netwerk/protocol/http/SpdyStream3.cpp
netwerk/protocol/http/SpdyStream3.h
security/manager/ssl/tests/unit/test_ev_certs/cert8.db
security/manager/ssl/tests/unit/test_ev_certs/int-ev-valid.p12
security/manager/ssl/tests/unit/test_ev_certs/int-non-ev-root.p12
security/manager/ssl/tests/unit/test_ev_certs/key3.db
security/manager/ssl/tests/unit/test_ev_certs/non-evroot-ca.p12
security/manager/ssl/tests/unit/test_ev_certs/secmod.db
testing/xpcshell/node-spdy/lib/spdy/parser.js
testing/xpcshell/node-spdy/lib/spdy/protocol/generic.js
testing/xpcshell/node-spdy/lib/spdy/protocol/v2/dictionary.js
testing/xpcshell/node-spdy/lib/spdy/protocol/v2/framer.js
testing/xpcshell/node-spdy/lib/spdy/protocol/v2/index.js
testing/xpcshell/node-spdy/lib/spdy/protocol/v2/protocol.js
testing/xpcshell/node-spdy/lib/spdy/protocol/v3/dictionary.js
testing/xpcshell/node-spdy/lib/spdy/protocol/v3/framer.js
testing/xpcshell/node-spdy/lib/spdy/protocol/v3/index.js
testing/xpcshell/node-spdy/lib/spdy/protocol/v3/protocol.js
testing/xpcshell/node-spdy/test/unit/framer-test.js
testing/xpcshell/node-spdy/test/unit/parser-test.js
testing/xpcshell/node-spdy/test/unit/server-test.js
--- a/accessible/jsat/Presentation.jsm
+++ b/accessible/jsat/Presentation.jsm
@@ -446,16 +446,28 @@ AndroidPresenter.prototype.announce =
 
 AndroidPresenter.prototype.liveRegion =
   function AndroidPresenter_liveRegion(aContext, aIsPolite,
     aIsHide, aModifiedText) {
     return this.announce(
       UtteranceGenerator.genForLiveRegion(aContext, aIsHide, aModifiedText));
   };
 
+AndroidPresenter.prototype.noMove =
+  function AndroidPresenter_noMove(aMoveMethod) {
+    return {
+      type: this.type,
+      details: [
+      { eventType: this.ANDROID_VIEW_ACCESSIBILITY_FOCUSED,
+        exitView: aMoveMethod,
+        text: ['']
+      }]
+    };
+  };
+
 /**
  * A B2G presenter for Gaia.
  */
 function B2GPresenter() {}
 
 B2GPresenter.prototype = Object.create(Presenter.prototype);
 
 B2GPresenter.prototype.type = 'B2G';
--- a/accessible/tests/mochitest/textattrs/test_general.html
+++ b/accessible/tests/mochitest/textattrs/test_general.html
@@ -704,22 +704,22 @@
     <span style="font-family: monospace;">text</span>text
     <span style="font-family: serif;">text</span>text
     <span style="font-family: BodoniThatDoesntExist;">text</span>text
     <span style="font-family: Comic Sans MS, cursive;">text</span>text
     <span style="font-family: sans-serif, fantasy;">text</span>text
   </p>
 
   <p id="area17">
-    <span style="-moz-text-decoration-line: underline;">underline
-    </span><span style="text-decoration: underline; -moz-text-decoration-color: blue;">blue
-    </span><span style="text-decoration: underline; -moz-text-decoration-style: dotted;">dotted
-    </span><span style="-moz-text-decoration-line: line-through;">linethrough
-    </span><span style="text-decoration: line-through; -moz-text-decoration-color: blue;">blue
-    </span><span style="text-decoration: line-through; -moz-text-decoration-style: wavy;">wavy
+    <span style="text-decoration-line: underline;">underline
+    </span><span style="text-decoration: underline; text-decoration-color: blue;">blue
+    </span><span style="text-decoration: underline; text-decoration-style: dotted;">dotted
+    </span><span style="text-decoration-line: line-through;">linethrough
+    </span><span style="text-decoration: line-through; text-decoration-color: blue;">blue
+    </span><span style="text-decoration: line-through; text-decoration-style: wavy;">wavy
     </span>
   </p>
 
   <ul>
     <li id="area18" class="gencontent">item</li>
   </ul>
 
   <p id="area19">uncolored
--- a/b2g/components/LogCapture.jsm
+++ b/b2g/components/LogCapture.jsm
@@ -3,89 +3,157 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 /* jshint moz: true */
 /* global Uint8Array, Components, dump */
 
 'use strict';
 
 this.EXPORTED_SYMBOLS = ['LogCapture'];
 
-/**
- * readLogFile
- * Read in /dev/log/{{log}} in nonblocking mode, which will return -1 if
- * reading would block the thread.
- *
- * @param log {String} The log from which to read. Must be present in /dev/log
- * @return {Uint8Array} Raw log data
- */
-let readLogFile = function(logLocation) {
-  if (!this.ctypes) {
+const SYSTEM_PROPERTY_KEY_MAX = 32;
+const SYSTEM_PROPERTY_VALUE_MAX = 92;
+
+function debug(msg) {
+  dump('LogCapture.jsm: ' + msg + '\n');
+}
+
+let LogCapture = {
+  ensureLoaded: function() {
+    if (!this.ctypes) {
+      this.load();
+    }
+  },
+
+  load: function() {
     // load in everything on first use
     Components.utils.import('resource://gre/modules/ctypes.jsm', this);
 
-    this.lib = this.ctypes.open(this.ctypes.libraryName('c'));
+    this.libc = this.ctypes.open(this.ctypes.libraryName('c'));
 
-    this.read = this.lib.declare('read',
+    this.read = this.libc.declare('read',
       this.ctypes.default_abi,
       this.ctypes.int,       // bytes read (out)
       this.ctypes.int,       // file descriptor (in)
       this.ctypes.voidptr_t, // buffer to read into (in)
       this.ctypes.size_t     // size_t size of buffer (in)
     );
 
-    this.open = this.lib.declare('open',
+    this.open = this.libc.declare('open',
       this.ctypes.default_abi,
       this.ctypes.int,      // file descriptor (returned)
       this.ctypes.char.ptr, // path
       this.ctypes.int       // flags
     );
 
-    this.close = this.lib.declare('close',
+    this.close = this.libc.declare('close',
       this.ctypes.default_abi,
       this.ctypes.int, // error code (returned)
       this.ctypes.int  // file descriptor
     );
-  }
+
+    this.property_find_nth =
+      this.libc.declare("__system_property_find_nth",
+                        this.ctypes.default_abi,
+                        this.ctypes.voidptr_t,     // return value: nullable prop_info*
+                        this.ctypes.unsigned_int); // n: the index of the property to return
 
-  const O_READONLY = 0;
-  const O_NONBLOCK = 1 << 11;
+    this.property_read =
+      this.libc.declare("__system_property_read",
+                        this.ctypes.default_abi,
+                        this.ctypes.void_t,     // return: none
+                        this.ctypes.voidptr_t,  // non-null prop_info*
+                        this.ctypes.char.ptr,   // key
+                        this.ctypes.char.ptr);  // value
 
-  const BUF_SIZE = 2048;
+    this.key_buf   = this.ctypes.char.array(SYSTEM_PROPERTY_KEY_MAX)();
+    this.value_buf = this.ctypes.char.array(SYSTEM_PROPERTY_VALUE_MAX)();
+  },
+
+  cleanup: function() {
+    this.libc.close();
 
-  let BufType = this.ctypes.ArrayType(this.ctypes.char);
-  let buf = new BufType(BUF_SIZE);
-  let logArray = [];
+    this.read = null;
+    this.open = null;
+    this.close = null;
+    this.property_find_nth = null;
+    this.property_read = null;
+    this.key_buf = null;
+    this.value_buf = null;
+
+    this.libc = null;
+    this.ctypes = null;
+  },
 
-  let logFd = this.open(logLocation, O_READONLY | O_NONBLOCK);
-  if (logFd === -1) {
-    return null;
-  }
+  /**
+   * readLogFile
+   * Read in /dev/log/{{log}} in nonblocking mode, which will return -1 if
+   * reading would block the thread.
+   *
+   * @param log {String} The log from which to read. Must be present in /dev/log
+   * @return {Uint8Array} Raw log data
+   */
+  readLogFile: function(logLocation) {
+    this.ensureLoaded();
+
+    const O_READONLY = 0;
+    const O_NONBLOCK = 1 << 11;
+
+    const BUF_SIZE = 2048;
 
-  let readStart = Date.now();
-  let readCount = 0;
-  while (true) {
-    let count = this.read(logFd, buf, BUF_SIZE);
-    readCount += 1;
+    let BufType = this.ctypes.ArrayType(this.ctypes.char);
+    let buf = new BufType(BUF_SIZE);
+    let logArray = [];
+
+    let logFd = this.open(logLocation, O_READONLY | O_NONBLOCK);
+    if (logFd === -1) {
+      return null;
+    }
 
-    if (count <= 0) {
-      // log has return due to being nonblocking or running out of things
-      break;
+    let readStart = Date.now();
+    let readCount = 0;
+    while (true) {
+      let count = this.read(logFd, buf, BUF_SIZE);
+      readCount += 1;
+
+      if (count <= 0) {
+        // log has return due to being nonblocking or running out of things
+        break;
+      }
+      for(let i = 0; i < count; i++) {
+        logArray.push(buf[i]);
+      }
     }
-    for(let i = 0; i < count; i++) {
-      logArray.push(buf[i]);
-    }
-  }
+
+    let logTypedArray = new Uint8Array(logArray);
+
+    this.close(logFd);
+
+    return logTypedArray;
+  },
+
+ /**
+   * Get all system properties as a dict with keys mapping to values
+   */
+  readProperties: function() {
+    this.ensureLoaded();
+    let n = 0;
+    let propertyDict = {};
 
-  let logTypedArray = new Uint8Array(logArray);
+    while(true) {
+      let prop_info = this.property_find_nth(n);
+      if(prop_info.isNull()) {
+        break;
+      }
 
-  this.close(logFd);
+      // read the prop_info into the key and value buffers
+      this.property_read(prop_info, this.key_buf, this.value_buf);
+      let key = this.key_buf.readString();;
+      let value = this.value_buf.readString()
 
-  return logTypedArray;
+      propertyDict[key] = value;
+      n++;
+    }
+
+    return propertyDict;
+  }
 };
 
-let cleanup = function() {
-  this.lib.close();
-  this.read = this.open = this.close = null;
-  this.lib = null;
-  this.ctypes = null;
-};
-
-this.LogCapture = { readLogFile: readLogFile, cleanup: cleanup };
+this.LogCapture = LogCapture;
--- a/b2g/components/LogParser.jsm
+++ b/b2g/components/LogParser.jsm
@@ -210,92 +210,34 @@ function formatLogMessage(logMessage) {
  * @return {String} Pretty-printed log
  */
 function prettyPrintLogArray(array) {
   let logMessages = parseLogArray(array);
   return logMessages.map(formatLogMessage).join("");
 }
 
 /**
- * Parse an array of bytes as a properties file. The structure of the
- * properties file is derived from bionic/libc/bionic/system_properties.c
- * @param array {Uint8Array} Array containing property data
- * @return {Object} Map from property name to property value, both strings
- */
-function parsePropertiesArray(array) {
-  let data = new DataView(array.buffer);
-  let byteString = String.fromCharCode.apply(null, array);
-
-  let properties = {};
-
-  let propIndex = 0;
-  let propCount = data.getUint32(0, true);
-
-  // first TOC entry is at 32
-  let tocOffset = 32;
-
-  const PROP_NAME_MAX = 32;
-  const PROP_VALUE_MAX = 92;
-
-  while (propIndex < propCount) {
-    // Retrieve offset from file start
-    let infoOffset = data.getUint32(tocOffset, true) & 0xffffff;
-
-    // Now read the name, integer serial, and value
-    let propName = "";
-    let nameOffset = infoOffset;
-    while (byteString[nameOffset] != "\0" &&
-           (nameOffset - infoOffset) < PROP_NAME_MAX) {
-      propName += byteString[nameOffset];
-      nameOffset ++;
-    }
-
-    infoOffset += PROP_NAME_MAX;
-    // Skip serial number
-    infoOffset += 4;
-
-    let propValue = "";
-    nameOffset = infoOffset;
-    while (byteString[nameOffset] != "\0" &&
-           (nameOffset - infoOffset) < PROP_VALUE_MAX) {
-      propValue += byteString[nameOffset];
-      nameOffset ++;
-    }
-
-    // Move to next table of contents entry
-    tocOffset += 4;
-
-    properties[propName] = propValue;
-    propIndex += 1;
-  }
-
-  return properties;
-}
-
-/**
- * Pretty-print an array read from the /dev/__properties__ file.
- * @param array {Uint8Array} File data array
+ * Pretty-print an array read from the list of propreties.
+ * @param {Object} Object representing the properties
  * @return {String} Human-readable string of property name: property value
  */
-function prettyPrintPropertiesArray(array) {
-  let properties = parsePropertiesArray(array);
+function prettyPrintPropertiesArray(properties) {
   let propertiesString = "";
   for(let propName in properties) {
-    propertiesString += propName + ": " + properties[propName] + "\n";
+    propertiesString += "[" + propName + "]: [" + properties[propName] + "]\n";
   }
   return propertiesString;
 }
 
 /**
  * Pretty-print a normal array. Does nothing.
  * @param array {Uint8Array} Input array
  */
 function prettyPrintArray(array) {
   return array;
 }
 
 this.LogParser = {
   parseLogArray: parseLogArray,
-  parsePropertiesArray: parsePropertiesArray,
   prettyPrintArray: prettyPrintArray,
   prettyPrintLogArray: prettyPrintLogArray,
   prettyPrintPropertiesArray: prettyPrintPropertiesArray
 };
--- a/b2g/components/LogShake.jsm
+++ b/b2g/components/LogShake.jsm
@@ -74,17 +74,16 @@ let LogShake = {
    * debouncing.
    */
   captureRequested: false,
 
   /**
    * Map of files which have log-type information to their parsers
    */
   LOGS_WITH_PARSERS: {
-    '/dev/__properties__': LogParser.prettyPrintPropertiesArray,
     '/dev/log/main': LogParser.prettyPrintLogArray,
     '/dev/log/system': LogParser.prettyPrintLogArray,
     '/dev/log/radio': LogParser.prettyPrintLogArray,
     '/dev/log/events': LogParser.prettyPrintLogArray,
     '/proc/cmdline': LogParser.prettyPrintArray,
     '/proc/kmsg': LogParser.prettyPrintArray,
     '/proc/meminfo': LogParser.prettyPrintArray,
     '/proc/uptime': LogParser.prettyPrintArray,
@@ -205,16 +204,24 @@ let LogShake = {
     return saveLogs(logArrays);
   },
 
   /**
    * Read in all log files, returning their formatted contents
    */
   readLogs: function() {
     let logArrays = {};
+
+    try {
+      logArrays["properties"] =
+        LogParser.prettyPrintPropertiesArray(LogCapture.readProperties());
+    } catch (ex) {
+      Cu.reportError("Unable to get device properties: " + ex);
+    }
+
     for (let loc in this.LOGS_WITH_PARSERS) {
       let logArray;
       try {
         logArray = LogCapture.readLogFile(loc);
         if (!logArray) {
           continue;
         }
       } catch (ex) {
deleted file mode 100644
index a8254853738e2083fbea3c659e4346c141214f2f..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
--- a/b2g/components/test/unit/test_logcapture.js
+++ b/b2g/components/test/unit/test_logcapture.js
@@ -3,23 +3,28 @@
 
 
 /**
  * Test that LogCapture successfully reads from the /dev/log devices, returning
  * a Uint8Array of some length, including zero. This tests a few standard
  * log devices
  */
 function run_test() {
-  Components.utils.import('resource:///modules/LogCapture.jsm');
+  Components.utils.import("resource:///modules/LogCapture.jsm");
 
   function verifyLog(log) {
     // log exists
     notEqual(log, null);
     // log has a length and it is non-negative (is probably array-like)
     ok(log.length >= 0);
   }
 
-  let mainLog = LogCapture.readLogFile('/dev/log/main');
+  let propertiesLog = LogCapture.readProperties();
+  notEqual(propertiesLog, null, "Properties should not be null");
+  notEqual(propertiesLog, undefined, "Properties should not be undefined");
+  equal(propertiesLog["ro.kernel.qemu"], "1", "QEMU property should be 1");
+
+  let mainLog = LogCapture.readLogFile("/dev/log/main");
   verifyLog(mainLog);
 
-  let meminfoLog = LogCapture.readLogFile('/proc/meminfo');
+  let meminfoLog = LogCapture.readLogFile("/proc/meminfo");
   verifyLog(meminfoLog);
 }
--- a/b2g/components/test/unit/test_logparser.js
+++ b/b2g/components/test/unit/test_logparser.js
@@ -1,49 +1,74 @@
 /* jshint moz: true */
 
 const {utils: Cu, classes: Cc, interfaces: Ci} = Components;
 
+function debug(msg) {
+  var timestamp = Date.now();
+  dump("LogParser: " + timestamp + ": " + msg + "\n");
+}
+
 function run_test() {
-  Cu.import('resource:///modules/LogParser.jsm');
+  Cu.import("resource:///modules/LogParser.jsm");
+  debug("Starting");
+  run_next_test();
+}
 
-  let propertiesFile = do_get_file('data/test_properties');
-  let loggerFile = do_get_file('data/test_logger_file');
+function makeStream(file) {
+  var fileStream = Cc["@mozilla.org/network/file-input-stream;1"]
+                .createInstance(Ci.nsIFileInputStream);
+  fileStream.init(file, -1, -1, 0);
+  var bis = Cc["@mozilla.org/binaryinputstream;1"]
+                .createInstance(Ci.nsIBinaryInputStream);
+  bis.setInputStream(fileStream);
+  return bis;
+}
 
-  let propertiesStream = makeStream(propertiesFile);
+add_test(function test_parse_logfile() {
+  let loggerFile = do_get_file("data/test_logger_file");
+
   let loggerStream = makeStream(loggerFile);
 
   // Initialize arrays to hold the file contents (lengths are hardcoded)
-  let propertiesArray = new Uint8Array(propertiesStream.readByteArray(65536));
   let loggerArray = new Uint8Array(loggerStream.readByteArray(4037));
 
-  propertiesStream.close();
   loggerStream.close();
 
-  let properties = LogParser.parsePropertiesArray(propertiesArray);
   let logMessages = LogParser.parseLogArray(loggerArray);
 
-  // Test arbitrary property entries for correctness
-  equal(properties['ro.boot.console'], 'ttyHSL0');
-  equal(properties['net.tcp.buffersize.lte'],
-        '524288,1048576,2097152,262144,524288,1048576');
-
-  ok(logMessages.length === 58, 'There should be 58 messages in the log');
+  ok(logMessages.length === 58, "There should be 58 messages in the log");
 
   let expectedLogEntry = {
     processId: 271, threadId: 271,
     seconds: 790796, nanoseconds: 620000001, time: 790796620.000001,
-    priority: 4, tag: 'Vold',
-    message: 'Vold 2.1 (the revenge) firing up\n'
+    priority: 4, tag: "Vold",
+    message: "Vold 2.1 (the revenge) firing up\n"
   };
 
   deepEqual(expectedLogEntry, logMessages[0]);
-}
+  run_next_test();
+});
+
+add_test(function test_print_properties() {
+  let properties = {
+    "ro.secure": "1",
+    "sys.usb.state": "diag,serial_smd,serial_tty,rmnet_bam,mass_storage,adb"
+  };
+
+  let logMessages = LogParser.prettyPrintPropertiesArray(properties);
+  let logMessagesArray = logMessages.split("\n");
 
-function makeStream(file) {
-  var fileStream = Cc['@mozilla.org/network/file-input-stream;1']
-                .createInstance(Ci.nsIFileInputStream);
-  fileStream.init(file, -1, -1, 0);
-  var bis = Cc['@mozilla.org/binaryinputstream;1']
-                .createInstance(Ci.nsIBinaryInputStream);
-  bis.setInputStream(fileStream);
-  return bis;
-}
+  ok(logMessagesArray.length === 3, "There should be 3 lines in the log.");
+  notEqual(logMessagesArray[0], "", "First line should not be empty");
+  notEqual(logMessagesArray[1], "", "Second line should not be empty");
+  equal(logMessagesArray[2], "", "Last line should be empty");
+
+  let expectedLog = [
+    "[ro.secure]: [1]",
+    "[sys.usb.state]: [diag,serial_smd,serial_tty,rmnet_bam,mass_storage,adb]",
+    ""
+  ].join("\n");
+
+  deepEqual(expectedLog, logMessages);
+
+  run_next_test();
+});
--- a/b2g/components/test/unit/test_logshake.js
+++ b/b2g/components/test/unit/test_logshake.js
@@ -3,70 +3,70 @@
  */
 
 /* jshint moz: true */
 /* global Components, LogCapture, LogShake, ok, add_test, run_next_test, dump */
 /* exported run_test */
 
 /* disable use strict warning */
 /* jshint -W097 */
-'use strict';
+"use strict";
 
 const Cu = Components.utils;
 
-Cu.import('resource://gre/modules/LogCapture.jsm');
-Cu.import('resource://gre/modules/LogShake.jsm');
+Cu.import("resource://gre/modules/LogCapture.jsm");
+Cu.import("resource://gre/modules/LogShake.jsm");
 
 // Force logshake to handle a device motion event with given components
 // Does not use SystemAppProxy because event needs special
 // accelerationIncludingGravity property
 function sendDeviceMotionEvent(x, y, z) {
   let event = {
-    type: 'devicemotion',
+    type: "devicemotion",
     accelerationIncludingGravity: {
       x: x,
       y: y,
       z: z
     }
   };
   LogShake.handleEvent(event);
 }
 
 // Send a screen change event directly, does not use SystemAppProxy due to race
 // conditions.
 function sendScreenChangeEvent(screenEnabled) {
   let event = {
-    type: 'screenchange',
+    type: "screenchange",
     detail: {
       screenEnabled: screenEnabled
     }
   };
   LogShake.handleEvent(event);
 }
 
 function debug(msg) {
   var timestamp = Date.now();
-  dump('LogShake: ' + timestamp + ': ' + msg);
+  dump("LogShake: " + timestamp + ": " + msg);
 }
 
 add_test(function test_do_log_capture_after_shaking() {
   // Enable LogShake
   LogShake.init();
 
   let readLocations = [];
   LogCapture.readLogFile = function(loc) {
     readLocations.push(loc);
     return null; // we don't want to provide invalid data to a parser
   };
 
   // Fire a devicemotion event that is of shake magnitude
   sendDeviceMotionEvent(9001, 9001, 9001);
 
   ok(readLocations.length > 0,
-      'LogShake should attempt to read at least one log');
+      "LogShake should attempt to read at least one log");
 
   LogShake.uninit();
   run_next_test();
 });
 
 add_test(function test_do_nothing_when_resting() {
   // Enable LogShake
   LogShake.init();
@@ -76,39 +76,39 @@ add_test(function test_do_nothing_when_r
     readLocations.push(loc);
     return null; // we don't want to provide invalid data to a parser
   };
 
   // Fire a devicemotion event that is relatively tiny
   sendDeviceMotionEvent(0, 9.8, 9.8);
 
   ok(readLocations.length === 0,
-      'LogShake should not read any logs');
+      "LogShake should not read any logs");
 
-  debug('test_do_nothing_when_resting: stop');
+  debug("test_do_nothing_when_resting: stop");
   LogShake.uninit();
   run_next_test();
 });
 
 add_test(function test_do_nothing_when_disabled() {
-  debug('test_do_nothing_when_disabled: start');
+  debug("test_do_nothing_when_disabled: start");
   // Disable LogShake
   LogShake.uninit();
 
   let readLocations = [];
   LogCapture.readLogFile = function(loc) {
     readLocations.push(loc);
     return null; // we don't want to provide invalid data to a parser
   };
 
   // Fire a devicemotion event that would normally be a shake
   sendDeviceMotionEvent(0, 9001, 9001);
 
   ok(readLocations.length === 0,
-      'LogShake should not read any logs');
+      "LogShake should not read any logs");
 
   run_next_test();
 });
 
 add_test(function test_do_nothing_when_screen_off() {
   // Enable LogShake
   LogShake.init();
 
@@ -121,17 +121,17 @@ add_test(function test_do_nothing_when_s
     readLocations.push(loc);
     return null; // we don't want to provide invalid data to a parser
   };
 
   // Fire a devicemotion event that would normally be a shake
   sendDeviceMotionEvent(0, 9001, 9001);
 
   ok(readLocations.length === 0,
-      'LogShake should not read any logs');
+      "LogShake should not read any logs");
 
   // Restore the screen
   sendScreenChangeEvent(true);
 
   LogShake.uninit();
   run_next_test();
 });
 
@@ -144,17 +144,17 @@ add_test(function test_do_log_capture_re
     readLocations.push(loc);
     throw new Error("Exception during readLogFile for: " + loc);
   };
 
   // Fire a devicemotion event that is of shake magnitude
   sendDeviceMotionEvent(9001, 9001, 9001);
 
   ok(readLocations.length > 0,
-      'LogShake should attempt to read at least one log');
+      "LogShake should attempt to read at least one log");
 
   LogShake.uninit();
   run_next_test();
 });
 
 add_test(function test_do_log_capture_resilient_parseLog() {
   // Enable LogShake
   LogShake.init();
@@ -167,18 +167,18 @@ add_test(function test_do_log_capture_re
     };
     return null;
   };
 
   // Fire a devicemotion event that is of shake magnitude
   sendDeviceMotionEvent(9001, 9001, 9001);
 
   ok(readLocations.length > 0,
-      'LogShake should attempt to read at least one log');
+      "LogShake should attempt to read at least one log");
 
   LogShake.uninit();
   run_next_test();
 });
 
 function run_test() {
-  debug('Starting');
+  debug("Starting");
   run_next_test();
 }
--- a/b2g/components/test/unit/xpcshell.ini
+++ b/b2g/components/test/unit/xpcshell.ini
@@ -1,15 +1,14 @@
 [DEFAULT]
 head =
 tail =
 
 support-files =
   data/test_logger_file
-  data/test_properties
 
 [test_bug793310.js]
 
 [test_bug832946.js]
 
 [test_fxaccounts.js]
 [test_signintowebsite.js]
 head = head_identity.js
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3ab0d9c70f0b2e1ededc679112c392303f037361">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="ae3a84acaab80a5b35d5542d63e68462273c8a1b"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="4aee256937afe9db2520752650685ba61ce6097d"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="11ad0ea69796915552c9bae148d81fddf9856ddb"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,21 +14,21 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ae3a84acaab80a5b35d5542d63e68462273c8a1b"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="4aee256937afe9db2520752650685ba61ce6097d"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
-  <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
-  <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="67f2907bc340bad250b4ea6ce2902b52896c9ef0"/>
+  <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
+  <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="a47dd04f8f66e42fd331711140f2c3e2fed0767d"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="11ad0ea69796915552c9bae148d81fddf9856ddb"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="ae3a84acaab80a5b35d5542d63e68462273c8a1b"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="4aee256937afe9db2520752650685ba61ce6097d"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="11ad0ea69796915552c9bae148d81fddf9856ddb"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3ab0d9c70f0b2e1ededc679112c392303f037361">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="ae3a84acaab80a5b35d5542d63e68462273c8a1b"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="4aee256937afe9db2520752650685ba61ce6097d"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="11ad0ea69796915552c9bae148d81fddf9856ddb"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,21 +14,21 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ae3a84acaab80a5b35d5542d63e68462273c8a1b"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="4aee256937afe9db2520752650685ba61ce6097d"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
-  <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
-  <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="67f2907bc340bad250b4ea6ce2902b52896c9ef0"/>
+  <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
+  <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="a47dd04f8f66e42fd331711140f2c3e2fed0767d"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="11ad0ea69796915552c9bae148d81fddf9856ddb"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3ab0d9c70f0b2e1ededc679112c392303f037361">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="ae3a84acaab80a5b35d5542d63e68462273c8a1b"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="4aee256937afe9db2520752650685ba61ce6097d"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="11ad0ea69796915552c9bae148d81fddf9856ddb"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="ae3a84acaab80a5b35d5542d63e68462273c8a1b"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="4aee256937afe9db2520752650685ba61ce6097d"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="11ad0ea69796915552c9bae148d81fddf9856ddb"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "587d98bf26625137015c17d5b937bf06bd055dd0", 
+    "revision": "67a3857cc29aaa2b2f890b4ed575065f6e5a7691", 
     "repo_path": "integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ae3a84acaab80a5b35d5542d63e68462273c8a1b"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="4aee256937afe9db2520752650685ba61ce6097d"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="11ad0ea69796915552c9bae148d81fddf9856ddb"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ae3a84acaab80a5b35d5542d63e68462273c8a1b"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="4aee256937afe9db2520752650685ba61ce6097d"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/mozconfigs/ics_armv7a_gecko/debug
+++ b/b2g/config/mozconfigs/ics_armv7a_gecko/debug
@@ -5,17 +5,16 @@ mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/ob
 ac_add_options --enable-application=b2g
 ac_add_options --enable-b2g-camera
 
 ac_add_options --target=arm-linux-androideabi
 ac_add_options --with-gonk="$topsrcdir/gonk-toolchain"
 export TOOLCHAIN_HOST=linux-x86
 export GONK_PRODUCT=generic
 ac_add_options --with-gonk-toolchain-prefix="$topsrcdir/gonk-toolchain/prebuilt/$TOOLCHAIN_HOST/toolchain/arm-linux-androideabi-4.4.x/bin/arm-linux-androideabi-"
-ac_add_options --disable-elf-hack
 ac_add_options --enable-debug-symbols
 ac_add_options --enable-debug
 #. "$topsrcdir/build/mozconfig.cache"
 ENABLE_MARIONETTE=1
 
 # Enable dump() from JS.
 export CXXFLAGS="-DMOZ_ENABLE_JS_DUMP -include $topsrcdir/gonk-toolchain/gonk-misc/Unicode.h -include $topsrcdir/gonk-toolchain/system/vold/ResponseCode.h"
 
--- a/b2g/config/mozconfigs/ics_armv7a_gecko/nightly
+++ b/b2g/config/mozconfigs/ics_armv7a_gecko/nightly
@@ -6,17 +6,16 @@ ac_add_options --enable-application=b2g
 ac_add_options --enable-b2g-camera
 ac_add_options --enable-updater
 
 ac_add_options --target=arm-linux-androideabi
 ac_add_options --with-gonk="$topsrcdir/gonk-toolchain"
 export TOOLCHAIN_HOST=linux-x86
 export GONK_PRODUCT=generic
 ac_add_options --with-gonk-toolchain-prefix="$topsrcdir/gonk-toolchain/prebuilt/$TOOLCHAIN_HOST/toolchain/arm-linux-androideabi-4.4.x/bin/arm-linux-androideabi-"
-ac_add_options --disable-elf-hack
 ac_add_options --enable-debug-symbols
 # ac_add_options --enable-profiling
 #. "$topsrcdir/build/mozconfig.cache"
 ENABLE_MARIONETTE=1
 
 # Enable dump() from JS.
 export CXXFLAGS="-DMOZ_ENABLE_JS_DUMP -include $topsrcdir/gonk-toolchain/gonk-misc/Unicode.h -include $topsrcdir/gonk-toolchain/system/vold/ResponseCode.h"
 
--- a/b2g/config/mozconfigs/linux32_gecko/debug
+++ b/b2g/config/mozconfigs/linux32_gecko/debug
@@ -24,17 +24,16 @@ export MOZ_TELEMETRY_REPORTING=1
 
 # Use sccache
 no_sccache=
 . "$topsrcdir/build/mozconfig.cache"
 
 #B2G options
 ac_add_options --enable-application=b2g
 ENABLE_MARIONETTE=1
-ac_add_options --disable-elf-hack
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
 
 GAIADIR=$topsrcdir/gaia
 
 # Include Firefox OS fonts.
 MOZTTDIR=$topsrcdir/moztt
 
 . "$topsrcdir/b2g/config/mozconfigs/common.override"
--- a/b2g/config/mozconfigs/linux32_gecko/nightly
+++ b/b2g/config/mozconfigs/linux32_gecko/nightly
@@ -22,17 +22,16 @@ export MOZ_TELEMETRY_REPORTING=1
 # DISABLED WHILE NOT ON TRY ac_add_options --enable-warnings-as-errors
 
 # Use sccache
 no_sccache=
 . "$topsrcdir/build/mozconfig.cache"
 
 #B2G options
 ac_add_options --enable-application=b2g
-ac_add_options --disable-elf-hack
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
 
 GAIADIR=$topsrcdir/gaia
 
 # Include Firefox OS fonts.
 MOZTTDIR=$topsrcdir/moztt
 
 # Build simulator xpi and phone tweaks for b2g-desktop
--- a/b2g/config/mozconfigs/linux64_gecko/debug
+++ b/b2g/config/mozconfigs/linux64_gecko/debug
@@ -24,17 +24,16 @@ export MOZ_TELEMETRY_REPORTING=1
 
 # Use sccache
 no_sccache=
 . "$topsrcdir/build/mozconfig.cache"
 
 #B2G options
 ac_add_options --enable-application=b2g
 ENABLE_MARIONETTE=1
-ac_add_options --disable-elf-hack
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
 
 GAIADIR=$topsrcdir/gaia
 
 # Include Firefox OS fonts.
 MOZTTDIR=$topsrcdir/moztt
 
 . "$topsrcdir/b2g/config/mozconfigs/common.override"
--- a/b2g/config/mozconfigs/linux64_gecko/nightly
+++ b/b2g/config/mozconfigs/linux64_gecko/nightly
@@ -22,17 +22,16 @@ export MOZ_TELEMETRY_REPORTING=1
 # DISABLED WHILE NOT ON TRY ac_add_options --enable-warnings-as-errors
 
 # Use sccache
 no_sccache=
 . "$topsrcdir/build/mozconfig.cache"
 
 #B2G options
 ac_add_options --enable-application=b2g
-ac_add_options --disable-elf-hack
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
 
 GAIADIR=$topsrcdir/gaia
 
 # Include Firefox OS fonts.
 MOZTTDIR=$topsrcdir/moztt
 
 # Build simulator xpi and phone tweaks for b2g-desktop
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="ae3a84acaab80a5b35d5542d63e68462273c8a1b"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="4aee256937afe9db2520752650685ba61ce6097d"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="11ad0ea69796915552c9bae148d81fddf9856ddb"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ae3a84acaab80a5b35d5542d63e68462273c8a1b"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="4aee256937afe9db2520752650685ba61ce6097d"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="11ad0ea69796915552c9bae148d81fddf9856ddb"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/b2g/installer/Makefile.in
+++ b/b2g/installer/Makefile.in
@@ -78,19 +78,16 @@ endif
 ifneq (,$(filter rtsp,$(NECKO_PROTOCOLS)))
 DEFINES += -DMOZ_RTSP
 endif
 
 ifdef GKMEDIAS_SHARED_LIBRARY
 DEFINES += -DGKMEDIAS_SHARED_LIBRARY
 endif
 
-ifdef MOZ_REPLACE_MALLOC
-DEFINES += -DMOZ_REPLACE_MALLOC
-endif
 ifdef MOZ_JEMALLOC3
 DEFINES += -DMOZ_JEMALLOC3
 endif
 
 ifdef MOZ_WIDGET_GTK
 DEFINES += -DMOZ_GTK=1
 ifdef MOZ_ENABLE_GTK3
 DEFINES += -DMOZ_GTK3=1
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -127,17 +127,16 @@
 #endif
 @BINPATH@/components/accessibility.xpt
 #endif
 @BINPATH@/components/appshell.xpt
 @BINPATH@/components/appstartup.xpt
 @BINPATH@/components/autocomplete.xpt
 @BINPATH@/components/autoconfig.xpt
 @BINPATH@/components/browsercompsbase.xpt
-@BINPATH@/components/browser-element.xpt
 @BINPATH@/components/browser-feeds.xpt
 @BINPATH@/components/caps.xpt
 @BINPATH@/components/chardet.xpt
 @BINPATH@/components/chrome.xpt
 @BINPATH@/components/commandhandler.xpt
 @BINPATH@/components/commandlines.xpt
 @BINPATH@/components/composer.xpt
 @BINPATH@/components/content_events.xpt
--- a/browser/base/content/test/newtab/browser.ini
+++ b/browser/base/content/test/newtab/browser.ini
@@ -16,16 +16,17 @@ skip-if = os == "mac" # Intermittent fai
 [browser_newtab_bug752841.js]
 [browser_newtab_bug765628.js]
 [browser_newtab_bug876313.js]
 [browser_newtab_bug991111.js]
 [browser_newtab_bug991210.js]
 [browser_newtab_bug998387.js]
 [browser_newtab_disable.js]
 [browser_newtab_drag_drop.js]
+skip-if = os == "win" && debug # bug 1097056; test fails in --run-by-dir mode on win8 x64 debug
 [browser_newtab_drag_drop_ext.js]
 [browser_newtab_drop_preview.js]
 [browser_newtab_enhanced.js]
 [browser_newtab_focus.js]
 [browser_newtab_intro.js]
 [browser_newtab_perwindow_private_browsing.js]
 [browser_newtab_reportLinkAction.js]
 [browser_newtab_reflow_load.js]
--- a/browser/components/search/test/browser.ini
+++ b/browser/components/search/test/browser.ini
@@ -31,9 +31,9 @@ skip-if = e10s # Bug ?????? - some issue
 skip-if = e10s # Bug ?????? - some issue with progress listeners [JavaScript Error: "req.originalURI is null" {file: "chrome://mochitests/content/browser/browser/components/search/test/browser_bing_behavior.js" line: 127}]
 [browser_healthreport.js]
 [browser_private_search_perwindowpb.js]
 skip-if = e10s # Bug ?????? - Test uses load event and checks event.target.
 [browser_yahoo.js]
 [browser_yahoo_behavior.js]
 skip-if = e10s # Bug ?????? - some issue with progress listeners [JavaScript Error: "req.originalURI is null" {file: "chrome://mochitests/content/browser/browser/components/search/test/browser_bing_behavior.js" line: 127}]
 [browser_abouthome_behavior.js]
-skip-if = e10s # Bug ???????
+skip-if = e10s || true # Bug ??????, Bug 1100301 - leaks windows until shutdown when --run-by-dir
--- a/browser/components/tabview/test/browser.ini
+++ b/browser/components/tabview/test/browser.ini
@@ -14,17 +14,17 @@ support-files =
 [browser_tabview_alltabs.js]
 [browser_tabview_apptabs.js]
 [browser_tabview_bug580412.js]
 [browser_tabview_bug586553.js]
 [browser_tabview_bug587043.js]
 [browser_tabview_bug587231.js]
 skip-if = buildapp == 'mulet'
 [browser_tabview_bug587276.js]
-skip-if = e10s # Bug 1091200
+skip-if = e10s || true # Bug 1091200, bug 1096285
 [browser_tabview_bug587351.js]
 [browser_tabview_bug587503.js]
 [browser_tabview_bug587990.js]
 [browser_tabview_bug588265.js]
 [browser_tabview_bug589324.js]
 skip-if = e10s # Bug 1086190
 [browser_tabview_bug590606.js]
 [browser_tabview_bug591706.js]
--- a/browser/config/mozconfigs/linux32/nightly
+++ b/browser/config/mozconfigs/linux32/nightly
@@ -1,13 +1,12 @@
 . "$topsrcdir/browser/config/mozconfigs/linux32/common-opt"
 
 ac_add_options --enable-signmar
 ac_add_options --enable-profiling
-ac_add_options --disable-elf-hack # --enable-elf-hack conflicts with --enable-profiling
 
 # Nightlies only since this has a cost in performance
 ac_add_options --enable-js-diagnostics
 
 # This will overwrite the default of stripping everything and keep the symbol table.
 # This is useful for profiling and debugging and only increases the package size
 # by 2 MBs.
 STRIP_FLAGS="--strip-debug"
--- a/browser/config/mozconfigs/linux32/valgrind
+++ b/browser/config/mozconfigs/linux32/valgrind
@@ -1,14 +1,13 @@
 no_tooltool=1
 no_sccache=1
 
 . $topsrcdir/browser/config/mozconfigs/linux32/nightly
 
 ac_add_options --enable-valgrind
 ac_add_options --disable-jemalloc
-ac_add_options --disable-elf-hack
 ac_add_options --enable-optimize="-g -O -freorder-blocks"
 ac_add_options --disable-install-strip
 
 # Include the override mozconfig again (even though the above includes it)
 # since it's supposed to override everything.
 . "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/linux64/nightly
+++ b/browser/config/mozconfigs/linux64/nightly
@@ -1,13 +1,12 @@
 . "$topsrcdir/browser/config/mozconfigs/linux64/common-opt"
 
 ac_add_options --enable-signmar
 ac_add_options --enable-profiling
-ac_add_options --disable-elf-hack # --enable-elf-hack conflicts with --enable-profiling
 
 # Nightlies only since this has a cost in performance
 ac_add_options --enable-js-diagnostics
 
 # This will overwrite the default of stripping everything and keep the symbol table.
 # This is useful for profiling and debugging and only increases the package size
 # by 2 MBs.
 STRIP_FLAGS="--strip-debug"
--- a/browser/config/mozconfigs/linux64/valgrind
+++ b/browser/config/mozconfigs/linux64/valgrind
@@ -1,14 +1,13 @@
 no_tooltool=1
 no_sccache=1
 
 . $topsrcdir/browser/config/mozconfigs/linux64/nightly
 
 ac_add_options --enable-valgrind
 ac_add_options --disable-jemalloc
-ac_add_options --disable-elf-hack
 ac_add_options --enable-optimize="-g -O -freorder-blocks"
 ac_add_options --disable-install-strip
 
 # Include the override mozconfig again (even though the above includes it)
 # since it's supposed to override everything.
 . "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/whitelist
+++ b/browser/config/mozconfigs/whitelist
@@ -29,27 +29,25 @@ whitelist['nightly']['linux32'] += [
     'CC="ccache $REAL_CC"',
     'mk_add_options PROFILE_GEN_SCRIPT=@TOPSRCDIR@/build/profile_pageloader.pl',
     'ac_add_options --with-ccache=/usr/bin/ccache',
     '. "$topsrcdir/build/mozconfig.cache"',
     'export MOZILLA_OFFICIAL=1',
     'export MOZ_TELEMETRY_REPORTING=1',
     "mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) @MOZ_OBJDIR@/_profile/pgo/profileserver.py 10'",
     'STRIP_FLAGS="--strip-debug"',
-    'ac_add_options --disable-elf-hack # --enable-elf-hack conflicts with --enable-profiling',
 ]
 
 whitelist['nightly']['linux64'] += [
     'export MOZILLA_OFFICIAL=1',
     'export MOZ_TELEMETRY_REPORTING=1',
     "mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) @MOZ_OBJDIR@/_profile/pgo/profileserver.py 10'",
     'STRIP_FLAGS="--strip-debug"',
     'ac_add_options --with-ccache=/usr/bin/ccache',
     '. "$topsrcdir/build/mozconfig.cache"',
-    'ac_add_options --disable-elf-hack # --enable-elf-hack conflicts with --enable-profiling',
 ]
 
 whitelist['nightly']['macosx-universal'] += [
     'if test "${MOZ_UPDATE_CHANNEL}" = "nightly"; then',
     'ac_add_options --with-macbundlename-prefix=Firefox',
     'fi',
     'mk_add_options MOZ_MAKE_FLAGS="-j12"',
     'ac_add_options --with-ccache',
--- a/browser/devtools/debugger/test/browser.ini
+++ b/browser/devtools/debugger/test/browser.ini
@@ -349,53 +349,53 @@ skip-if = e10s
 skip-if = e10s
 [browser_dbg_scripts-switching-01.js]
 skip-if = e10s
 [browser_dbg_scripts-switching-02.js]
 skip-if = e10s
 [browser_dbg_scripts-switching-03.js]
 skip-if = e10s
 [browser_dbg_search-autofill-identifier.js]
-skip-if = e10s
+skip-if = e10s && debug
 [browser_dbg_search-basic-01.js]
-skip-if = e10s
+skip-if = e10s && debug
 [browser_dbg_search-basic-02.js]
-skip-if = e10s
+skip-if = e10s && debug
 [browser_dbg_search-basic-03.js]
-skip-if = e10s
+skip-if = e10s && debug
 [browser_dbg_search-basic-04.js]
-skip-if = e10s
+skip-if = e10s && debug
 [browser_dbg_search-global-01.js]
-skip-if = e10s
+skip-if = e10s && debug
 [browser_dbg_search-global-02.js]
-skip-if = e10s
+skip-if = e10s && debug
 [browser_dbg_search-global-03.js]
-skip-if = e10s
+skip-if = e10s # Bug 1093535
 [browser_dbg_search-global-04.js]
-skip-if = e10s
+skip-if = e10s && debug
 [browser_dbg_search-global-05.js]
-skip-if = e10s
+skip-if = e10s && debug
 [browser_dbg_search-global-06.js]
-skip-if = e10s
+skip-if = e10s && debug
 [browser_dbg_search-popup-jank.js]
-skip-if = e10s
+skip-if = e10s && debug
 [browser_dbg_search-sources-01.js]
-skip-if = e10s
+skip-if = e10s && debug
 [browser_dbg_search-sources-02.js]
-skip-if = e10s
+skip-if = e10s && debug
 [browser_dbg_search-sources-03.js]
-skip-if = e10s
+skip-if = e10s && debug
 [browser_dbg_search-symbols.js]
-skip-if = e10s
+skip-if = e10s && debug
 [browser_dbg_searchbox-help-popup-01.js]
-skip-if = e10s
+skip-if = e10s && debug
 [browser_dbg_searchbox-help-popup-02.js]
-skip-if = e10s
+skip-if = e10s && debug
 [browser_dbg_searchbox-parse.js]
-skip-if = e10s
+skip-if = e10s && debug
 [browser_dbg_source-maps-01.js]
 skip-if = e10s && debug
 [browser_dbg_source-maps-02.js]
 skip-if = e10s && debug
 [browser_dbg_source-maps-03.js]
 skip-if = e10s && debug
 [browser_dbg_source-maps-04.js]
 skip-if = e10s # Bug 1093535
--- a/browser/devtools/debugger/test/browser_dbg_search-autofill-identifier.js
+++ b/browser/devtools/debugger/test/browser_dbg_search-autofill-identifier.js
@@ -5,17 +5,17 @@
  * Tests that Debugger Search uses the identifier under cursor if nothing is
  * selected or manually passed and searching using certain operators.
  */
 "use strict";
 
 function test() {
   const TAB_URL = EXAMPLE_URL + "doc_function-search.html";
 
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
     let Source = 'code_function-search-01.js';
     let Debugger = aPanel.panelWin;
     let Editor = Debugger.DebuggerView.editor;
     let Filtering = Debugger.DebuggerView.Filtering;
 
     function doSearch(aOperator) {
       Editor.dropSelection();
       Filtering._doSearch(aOperator);
--- a/browser/devtools/debugger/test/browser_dbg_search-basic-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_search-basic-01.js
@@ -2,23 +2,22 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Tests basic search functionality (find token and jump to line).
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
 
-let gTab, gDebuggee, gPanel, gDebugger;
+let gTab, gPanel, gDebugger;
 let gEditor, gSources, gFiltering, gSearchBox;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
     gTab = aTab;
-    gDebuggee = aDebuggee;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gFiltering = gDebugger.DebuggerView.Filtering;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
     waitForSourceShown(gPanel, ".html").then(performTest);
@@ -304,16 +303,15 @@ function performTest() {
     "The search field has the right initial value (2).");
 
 
   closeDebuggerAndFinish(gPanel);
 }
 
 registerCleanupFunction(function() {
   gTab = null;
-  gDebuggee = null;
   gPanel = null;
   gDebugger = null;
   gEditor = null;
   gSources = null;
   gFiltering = null;
   gSearchBox = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_search-basic-02.js
+++ b/browser/devtools/debugger/test/browser_dbg_search-basic-02.js
@@ -2,23 +2,22 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Tests basic file search functionality.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
-let gTab, gDebuggee, gPanel, gDebugger;
+let gTab, gPanel, gDebugger;
 let gSources, gSearchBox;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
     gTab = aTab;
-    gDebuggee = aDebuggee;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
     waitForSourceAndCaretAndScopes(gPanel, "-02.js", 1)
       .then(performSimpleSearch)
       .then(() => verifySourceAndCaret("-01.js", 1, 1, [1, 1]))
@@ -28,17 +27,17 @@ function test() {
       .then(() => verifySourceAndCaret("-01.js", 2, 48, [96, 100]))
       .then(combineWithTokenColonSearch)
       .then(() => verifySourceAndCaret("-01.js", 2, 11, [56, 63]))
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
 
-    gDebuggee.firstCall();
+    callInTab(gTab, "firstCall");
   });
 }
 
 function performSimpleSearch() {
   let finished = promise.all([
     ensureSourceIs(gPanel, "-02.js"),
     ensureCaretAt(gPanel, 1),
     waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FILE_SEARCH_MATCH_FOUND),
@@ -111,14 +110,13 @@ function verifySourceAndCaret(aUrl, aLin
   ok(isCaretPos(gPanel, aLine, aColumn),
     "The current caret position appears to be correct.");
   ok(isEditorSel(gPanel, aSelection),
     "The current editor selection appears to be correct.");
 }
 
 registerCleanupFunction(function() {
   gTab = null;
-  gDebuggee = null;
   gPanel = null;
   gDebugger = null;
   gSources = null;
   gSearchBox = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_search-basic-03.js
+++ b/browser/devtools/debugger/test/browser_dbg_search-basic-03.js
@@ -3,23 +3,22 @@
 
 /**
  * Tests that searches which cause a popup to be shown properly handle the
  * ESCAPE key.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
-let gTab, gDebuggee, gPanel, gDebugger;
+let gTab, gPanel, gDebugger;
 let gSources, gSearchBox;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
     gTab = aTab;
-    gDebuggee = aDebuggee;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
     waitForSourceAndCaretAndScopes(gPanel, "-02.js", 1)
       .then(performFileSearch)
       .then(escapeAndHide)
@@ -32,17 +31,17 @@ function test() {
       .then(performGlobalSearch)
       .then(escapeAndClear)
       .then(() => verifySourceAndCaret("-01.js", 4, 10))
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
 
-    gDebuggee.firstCall();
+    callInTab(gTab, "firstCall");
   });
 }
 
 function performFileSearch() {
   let finished = promise.all([
     ensureSourceIs(gPanel, "-02.js"),
     ensureCaretAt(gPanel, 1),
     once(gDebugger, "popupshown"),
@@ -107,14 +106,13 @@ function verifySourceAndCaret(aUrl, aLin
   ok(gSources.selectedItem.value.contains(aUrl),
     "The selected item's value appears to be correct.");
   ok(isCaretPos(gPanel, aLine, aColumn),
     "The current caret position appears to be correct.");
 }
 
 registerCleanupFunction(function() {
   gTab = null;
-  gDebuggee = null;
   gPanel = null;
   gDebugger = null;
   gSources = null;
   gSearchBox = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_search-basic-04.js
+++ b/browser/devtools/debugger/test/browser_dbg_search-basic-04.js
@@ -3,23 +3,22 @@
 
 /**
  * Tests that the selection is dropped for line and token searches, after
  * pressing backspace enough times.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
-let gTab, gDebuggee, gPanel, gDebugger;
+let gTab, gPanel, gDebugger;
 let gEditor, gSources, gSearchBox;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
     gTab = aTab;
-    gDebuggee = aDebuggee;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
     waitForSourceShown(gPanel, "-01.js")
       .then(testLineSearch)
@@ -118,15 +117,14 @@ function testTokenSearch() {
   is(gEditor.getSelection(), "",
     "The editor selected text appears to be correct (2.5).");
   is(gSearchBox.value, "",
     "The searchbox should have been cleared.");
 }
 
 registerCleanupFunction(function() {
   gTab = null;
-  gDebuggee = null;
   gPanel = null;
   gDebugger = null;
   gEditor = null;
   gSources = null;
   gSearchBox = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_search-global-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_search-global-01.js
@@ -3,40 +3,39 @@
 
 /**
  * Tests basic functionality of global search (lowercase + upper case, expected
  * UI behavior, number of results found etc.)
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
-let gTab, gDebuggee, gPanel, gDebugger;
+let gTab, gPanel, gDebugger;
 let gEditor, gSources, gSearchView, gSearchBox;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
     gTab = aTab;
-    gDebuggee = aDebuggee;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gSearchView = gDebugger.DebuggerView.GlobalSearch;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
     waitForSourceAndCaretAndScopes(gPanel, "-02.js", 1)
       .then(firstSearch)
       .then(secondSearch)
       .then(clearSearch)
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
 
-    gDebuggee.firstCall();
+    callInTab(gTab, "firstCall");
   });
 }
 
 function firstSearch() {
   let deferred = promise.defer();
 
   is(gSearchView.itemCount, 0,
     "The global search pane shouldn't have any entries yet.");
@@ -259,16 +258,15 @@ function clearSearch() {
   is(gSearchView.widget._parent.hidden, true,
     "The global search pane shouldn't be visible after clearing.");
   is(gSearchView._splitter.hidden, true,
     "The global search pane splitter shouldn't be visible after clearing.");
 }
 
 registerCleanupFunction(function() {
   gTab = null;
-  gDebuggee = null;
   gPanel = null;
   gDebugger = null;
   gEditor = null;
   gSources = null;
   gSearchView = null;
   gSearchBox = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_search-global-02.js
+++ b/browser/devtools/debugger/test/browser_dbg_search-global-02.js
@@ -3,23 +3,22 @@
 
 /**
  * Tests if the global search results switch back and forth, and wrap around
  * when switching between them.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
-let gTab, gDebuggee, gPanel, gDebugger;
+let gTab, gPanel, gDebugger;
 let gEditor, gSources, gSearchView, gSearchBox;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
     gTab = aTab;
-    gDebuggee = aDebuggee;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gSearchView = gDebugger.DebuggerView.GlobalSearch;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
     waitForSourceAndCaretAndScopes(gPanel, "-02.js", 1)
@@ -29,17 +28,17 @@ function test() {
       .then(doWrapAroundJump)
       .then(doBackwardsWrapAroundJump)
       .then(testSearchTokenEmpty)
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
 
-    gDebuggee.firstCall();
+    callInTab(gTab, "firstCall");
   });
 }
 
 function firstSearch() {
   let deferred = promise.defer();
 
   is(gSearchView.itemCount, 0,
     "The global search pane shouldn't have any entries yet.");
@@ -203,16 +202,15 @@ function testSearchTokenEmpty() {
   is(gSearchView.widget._parent.hidden, true,
     "The global search pane shouldn't be visible after clearing.");
   is(gSearchView._splitter.hidden, true,
     "The global search pane splitter shouldn't be visible after clearing.");
 }
 
 registerCleanupFunction(function() {
   gTab = null;
-  gDebuggee = null;
   gPanel = null;
   gDebugger = null;
   gEditor = null;
   gSources = null;
   gSearchView = null;
   gSearchBox = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_search-global-03.js
+++ b/browser/devtools/debugger/test/browser_dbg_search-global-03.js
@@ -3,39 +3,38 @@
 
 /**
  * Tests if the global search results are cleared on location changes, and
  * the expected UI behaviors are triggered.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
-let gTab, gDebuggee, gPanel, gDebugger;
+let gTab, gPanel, gDebugger;
 let gEditor, gSources, gSearchView, gSearchBox;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
     gTab = aTab;
-    gDebuggee = aDebuggee;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gSearchView = gDebugger.DebuggerView.GlobalSearch;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
     waitForSourceAndCaretAndScopes(gPanel, "-02.js", 1)
       .then(firstSearch)
       .then(performTest)
       .then(() => closeDebuggerAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
 
-    gDebuggee.firstCall();
+    callInTab(gTab, "firstCall");
   });
 }
 
 function firstSearch() {
   let deferred = promise.defer();
 
   is(gSearchView.itemCount, 0,
     "The global search pane shouldn't have any entries yet.");
@@ -91,16 +90,15 @@ function performTest() {
     deferred.resolve();
   });
 
   return deferred.promise;
 }
 
 registerCleanupFunction(function() {
   gTab = null;
-  gDebuggee = null;
   gPanel = null;
   gDebugger = null;
   gEditor = null;
   gSources = null;
   gSearchView = null;
   gSearchBox = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_search-global-04.js
+++ b/browser/devtools/debugger/test/browser_dbg_search-global-04.js
@@ -3,39 +3,38 @@
 
 /**
  * Tests if the global search results trigger MatchFound and NoMatchFound events
  * properly, and triggers the expected UI behavior.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
-let gTab, gDebuggee, gPanel, gDebugger;
+let gTab, gPanel, gDebugger;
 let gEditor, gSources, gSearchView, gSearchBox;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
     gTab = aTab;
-    gDebuggee = aDebuggee;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gSearchView = gDebugger.DebuggerView.GlobalSearch;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
     waitForSourceAndCaretAndScopes(gPanel, "-02.js", 1)
       .then(firstSearch)
       .then(secondSearch)
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
 
-    gDebuggee.firstCall();
+    callInTab(gTab, "firstCall");
   });
 }
 
 function firstSearch() {
   let deferred = promise.defer();
 
   gDebugger.once(gDebugger.EVENTS.GLOBAL_SEARCH_MATCH_FOUND, () => {
     // Some operations are synchronously dispatched on the main thread,
@@ -79,16 +78,15 @@ function secondSearch() {
 
   typeText(gSearchBox, "/");
 
   return deferred.promise;
 }
 
 registerCleanupFunction(function() {
   gTab = null;
-  gDebuggee = null;
   gPanel = null;
   gDebugger = null;
   gEditor = null;
   gSources = null;
   gSearchView = null;
   gSearchBox = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_search-global-05.js
+++ b/browser/devtools/debugger/test/browser_dbg_search-global-05.js
@@ -4,23 +4,22 @@
 /**
  * Tests if the global search results are expanded/collapsed on click, and
  * clicking matches makes the source editor shows the correct source and
  * makes a selection based on the match.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
-let gTab, gDebuggee, gPanel, gDebugger;
+let gTab, gPanel, gDebugger;
 let gEditor, gSources, gSearchView, gSearchBox;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
     gTab = aTab;
-    gDebuggee = aDebuggee;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gSearchView = gDebugger.DebuggerView.GlobalSearch;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
     waitForSourceAndCaretAndScopes(gPanel, "-02.js", 1)
@@ -28,17 +27,17 @@ function test() {
       .then(testExpandCollapse)
       .then(testClickLineToJump)
       .then(testClickMatchToJump)
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
 
-    gDebuggee.firstCall();
+    callInTab(gTab, "firstCall");
   });
 }
 
 function doSearch() {
   let deferred = promise.defer();
 
   gDebugger.once(gDebugger.EVENTS.GLOBAL_SEARCH_MATCH_FOUND, () => {
     // Some operations are synchronously dispatched on the main thread,
@@ -141,16 +140,15 @@ function testClickMatchToJump() {
 
   EventUtils.sendMouseEvent({ type: "click" }, lastMatch);
 
   return deferred.promise;
 }
 
 registerCleanupFunction(function() {
   gTab = null;
-  gDebuggee = null;
   gPanel = null;
   gDebugger = null;
   gEditor = null;
   gSources = null;
   gSearchView = null;
   gSearchBox = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_search-global-06.js
+++ b/browser/devtools/debugger/test/browser_dbg_search-global-06.js
@@ -3,23 +3,22 @@
 
 /**
  * Tests if the global search results are hidden when they're supposed to
  * (after a focus lost, or when ESCAPE is pressed).
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
-let gTab, gDebuggee, gPanel, gDebugger;
+let gTab, gPanel, gDebugger;
 let gEditor, gSources, gSearchView, gSearchBox;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
     gTab = aTab;
-    gDebuggee = aDebuggee;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gSearchView = gDebugger.DebuggerView.GlobalSearch;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
     waitForSourceAndCaretAndScopes(gPanel, "-02.js", 1)
@@ -27,17 +26,17 @@ function test() {
       .then(testFocusLost)
       .then(doSearch)
       .then(testEscape)
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
 
-    gDebuggee.firstCall();
+    callInTab(gTab, "firstCall");
   });
 }
 
 function doSearch() {
   let deferred = promise.defer();
 
   is(gSearchView.itemCount, 0,
     "The global search pane shouldn't have any entries yet.");
@@ -106,16 +105,15 @@ function testEscape() {
   is(gSearchView.widget._parent.hidden, true,
     "The global search pane shouldn't be visible after clearing.");
   is(gSearchView._splitter.hidden, true,
     "The global search pane splitter shouldn't be visible after clearing.");
 }
 
 registerCleanupFunction(function() {
   gTab = null;
-  gDebuggee = null;
   gPanel = null;
   gDebugger = null;
   gEditor = null;
   gSources = null;
   gSearchView = null;
   gSearchBox = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_search-popup-jank.js
+++ b/browser/devtools/debugger/test/browser_dbg_search-popup-jank.js
@@ -2,23 +2,22 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Tests that sources aren't selected by default when finding a match.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_editor-mode.html";
 
-let gTab, gDebuggee, gPanel, gDebugger;
+let gTab, gPanel, gDebugger;
 let gSearchBox;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
     gTab = aTab;
-    gDebuggee = aDebuggee;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
     gDebugger.DebuggerView.FilteredSources._autoSelectFirstItem = false;
     gDebugger.DebuggerView.FilteredFunctions._autoSelectFirstItem = false;
 
     waitForSourceShown(gPanel, "-01.js")
@@ -106,13 +105,12 @@ function pressKey(aKey) {
 function pressKeyToHide(aKey) {
   let finished = waitForResultsHidden();
   EventUtils.sendKey(aKey, gDebugger);
   return finished;
 }
 
 registerCleanupFunction(function() {
   gTab = null;
-  gDebuggee = null;
   gPanel = null;
   gDebugger = null;
   gSearchBox = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_search-sources-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_search-sources-01.js
@@ -2,26 +2,25 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Tests basic functionality of sources filtering (file search).
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
-let gTab, gDebuggee, gPanel, gDebugger;
+let gTab, gPanel, gDebugger;
 let gSources, gSearchView, gSearchBox;
 
 function test() {
   // Debug test slaves are a bit slow at this test.
   requestLongerTimeout(3);
 
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
     gTab = aTab;
-    gDebuggee = aDebuggee;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
     gSearchView = gDebugger.DebuggerView.FilteredSources;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
     waitForSourceShown(gPanel, "-01.js")
       .then(bogusSearch)
@@ -221,15 +220,14 @@ function verifyContents(aArgs) {
   is(gSearchView.itemCount, aArgs.itemCount,
     "No sources should be displayed in the sources container after a bogus search.");
   is(gSearchView.hidden, aArgs.hidden,
     "No sources should be displayed in the sources container after a bogus search.");
 }
 
 registerCleanupFunction(function() {
   gTab = null;
-  gDebuggee = null;
   gPanel = null;
   gDebugger = null;
   gSources = null;
   gSearchView = null;
   gSearchBox = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_search-sources-02.js
+++ b/browser/devtools/debugger/test/browser_dbg_search-sources-02.js
@@ -2,26 +2,25 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Tests more complex functionality of sources filtering (file search).
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_editor-mode.html";
 
-let gTab, gDebuggee, gPanel, gDebugger;
+let gTab, gPanel, gDebugger;
 let gSources, gSourceUtils, gSearchView, gSearchBox;
 
 function test() {
   // Debug test slaves are a bit slow at this test.
   requestLongerTimeout(3);
 
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
     gTab = aTab;
-    gDebuggee = aDebuggee;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
     gSourceUtils = gDebugger.SourceUtils;
     gSearchView = gDebugger.DebuggerView.FilteredSources;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
     waitForSourceShown(gPanel, "-01.js")
@@ -263,16 +262,15 @@ function verifyContents(aMatches) {
       "The filtered sources view should have the correct source labels.");
     ok(gSearchView.widget._parent.querySelector(".results-panel-item-label-below[value=\"" + trimmedLocation + "\"]"),
       "The filtered sources view should have the correct source locations.");
   }
 }
 
 registerCleanupFunction(function() {
   gTab = null;
-  gDebuggee = null;
   gPanel = null;
   gDebugger = null;
   gSources = null;
   gSourceUtils = null;
   gSearchView = null;
   gSearchBox = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_search-sources-03.js
+++ b/browser/devtools/debugger/test/browser_dbg_search-sources-03.js
@@ -2,23 +2,22 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Tests that while searching for files, the sources list remains unchanged.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_editor-mode.html";
 
-let gTab, gDebuggee, gPanel, gDebugger;
+let gTab, gPanel, gDebugger;
 let gSources, gSearchBox;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
     gTab = aTab;
-    gDebuggee = aDebuggee;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
 
     waitForSourceShown(gPanel, "-01.js")
       .then(superGenericSearch)
       .then(verifySourcesPane)
@@ -87,14 +86,13 @@ function verifySourcesPane() {
   ok(gSources.getItemForAttachment(e => e.label == "code_test-editor-mode"),
     "The second source's label should be correct.");
   ok(gSources.getItemForAttachment(e => e.label == "doc_editor-mode.html"),
     "The third source's label should be correct.");
 }
 
 registerCleanupFunction(function() {
   gTab = null;
-  gDebuggee = null;
   gPanel = null;
   gDebugger = null;
   gSources = null;
   gSearchBox = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_search-symbols.js
+++ b/browser/devtools/debugger/test/browser_dbg_search-symbols.js
@@ -2,23 +2,22 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Tests if the function searching works properly.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_function-search.html";
 
-let gTab, gDebuggee, gPanel, gDebugger;
+let gTab, gPanel, gDebugger;
 let gEditor, gSources, gSearchBox, gFilteredFunctions;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
     gTab = aTab;
-    gDebuggee = aDebuggee;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSources = gDebugger.DebuggerView.Sources;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
     gFilteredFunctions = gDebugger.DebuggerView.FilteredFunctions;
 
     waitForSourceShown(gPanel, "-01.js")
@@ -454,16 +453,15 @@ function saveSearch() {
 
 function writeInfo() {
   info("Current source url:\n" + gSources.selectedValue);
   info("Debugger editor text:\n" + gEditor.getText());
 }
 
 registerCleanupFunction(function() {
   gTab = null;
-  gDebuggee = null;
   gPanel = null;
   gDebugger = null;
   gEditor = null;
   gSources = null;
   gSearchBox = null;
   gFilteredFunctions = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_searchbox-help-popup-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_searchbox-help-popup-01.js
@@ -3,37 +3,36 @@
 
 /**
  * Make sure that the searchbox popup is displayed when focusing the searchbox,
  * and hidden when the user starts typing.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
-let gTab, gDebuggee, gPanel, gDebugger;
+let gTab, gPanel, gDebugger;
 let gSearchBox, gSearchBoxPanel;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
     gTab = aTab;
-    gDebuggee = aDebuggee;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
     gSearchBoxPanel = gDebugger.DebuggerView.Filtering._searchboxHelpPanel;
 
     waitForSourceAndCaretAndScopes(gPanel, "-02.js", 1)
       .then(showPopup)
       .then(hidePopup)
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
 
-    gDebuggee.firstCall();
+    callInTab(gTab, "firstCall");
   });
 }
 
 function showPopup() {
   is(gSearchBoxPanel.state, "closed",
     "The search box panel shouldn't be visible yet.");
 
   let finished = once(gSearchBoxPanel, "popupshown");
@@ -47,14 +46,13 @@ function hidePopup() {
 
   let finished = once(gSearchBoxPanel, "popuphidden");
   setText(gSearchBox, "#");
   return finished;
 }
 
 registerCleanupFunction(function() {
   gTab = null;
-  gDebuggee = null;
   gPanel = null;
   gDebugger = null;
   gSearchBox = null;
   gSearchBoxPanel = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_searchbox-help-popup-02.js
+++ b/browser/devtools/debugger/test/browser_dbg_searchbox-help-popup-02.js
@@ -3,23 +3,22 @@
 
 /**
  * Make sure that the searchbox popup isn't displayed when there's some text
  * already present.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
 
-let gTab, gDebuggee, gPanel, gDebugger;
+let gTab, gPanel, gDebugger;
 let gEditor, gSearchBox, gSearchBoxPanel;
 
 function test() {
-  initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+  initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
     gTab = aTab;
-    gDebuggee = aDebuggee;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gEditor = gDebugger.DebuggerView.editor;
     gSearchBox = gDebugger.DebuggerView.Filtering._searchbox;
     gSearchBoxPanel = gDebugger.DebuggerView.Filtering._searchboxHelpPanel;
 
     once(gSearchBoxPanel, "popupshown").then(() => {
       ok(false, "Damn it, this shouldn't have happened.");
@@ -29,17 +28,17 @@ function test() {
       .then(tryShowPopup)
       .then(focusEditor)
       .then(testFocusLost)
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, aError => {
         ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
       });
 
-    gDebuggee.firstCall();
+    callInTab(gTab, "firstCall");
   });
 }
 
 function tryShowPopup() {
   setText(gSearchBox, "#call()");
   ok(isCaretPos(gPanel, 4, 22),
     "The editor caret position appears to be correct.");
   ok(isEditorSel(gPanel, [125, 131]),
@@ -72,15 +71,14 @@ function testFocusLost() {
     "The editor selected text appears to be correct after gaining focus.");
 
   is(gSearchBoxPanel.state, "closed",
     "The search box panel should still not be visible.");
 }
 
 registerCleanupFunction(function() {
   gTab = null;
-  gDebuggee = null;
   gPanel = null;
   gDebugger = null;
   gEditor = null;
   gSearchBox = null;
   gSearchBoxPanel = null;
 });
--- a/browser/devtools/debugger/test/browser_dbg_searchbox-parse.js
+++ b/browser/devtools/debugger/test/browser_dbg_searchbox-parse.js
@@ -1,17 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Tests that text entered in the debugger's searchbox is properly parsed.
  */
 
 function test() {
-  initDebugger("about:blank").then(([aTab, aDebuggee, aPanel]) => {
+  initDebugger("about:blank").then(([aTab,, aPanel]) => {
     let filterView = aPanel.panelWin.DebuggerView.Filtering;
     let searchbox = aPanel.panelWin.DebuggerView.Filtering._searchbox;
 
     setText(searchbox, "");
     is(filterView.searchData.toSource(), '["", [""]]',
       "The searchbox data wasn't parsed correctly (1).");
 
     setText(searchbox, "#token");
--- a/browser/installer/Makefile.in
+++ b/browser/installer/Makefile.in
@@ -125,19 +125,16 @@ DEFINES += -DAB=$(AB)
 
 DEFINES += -DMOZ_ICU_VERSION=$(MOZ_ICU_VERSION)
 ifdef MOZ_NATIVE_ICU
 DEFINES += -DMOZ_NATIVE_ICU
 endif
 ifdef MOZ_SHARED_ICU
 DEFINES += -DMOZ_SHARED_ICU
 endif
-ifdef MOZ_REPLACE_MALLOC
-DEFINES += -DMOZ_REPLACE_MALLOC
-endif
 ifdef MOZ_JEMALLOC3
 DEFINES += -DMOZ_JEMALLOC3
 endif
 DEFINES += -DMOZ_ICU_DBG_SUFFIX=$(MOZ_ICU_DBG_SUFFIX)
 ifdef CLANG_CXX
 DEFINES += -DCLANG_CXX
 endif
 ifdef CLANG_CL
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -172,17 +172,16 @@
 @BINPATH@/AccessibleMarshal.dll
 #endif
 @BINPATH@/components/accessibility.xpt
 #endif
 @BINPATH@/components/appshell.xpt
 @BINPATH@/components/appstartup.xpt
 @BINPATH@/components/autocomplete.xpt
 @BINPATH@/components/autoconfig.xpt
-@BINPATH@/components/browser-element.xpt
 @BINPATH@/browser/components/browsercompsbase.xpt
 @BINPATH@/browser/components/browser-feeds.xpt
 @BINPATH@/components/caps.xpt
 @BINPATH@/components/chrome.xpt
 @BINPATH@/components/commandhandler.xpt
 @BINPATH@/components/commandlines.xpt
 @BINPATH@/components/composer.xpt
 @BINPATH@/components/content_events.xpt
--- a/browser/themes/shared/devtools/dark-theme.css
+++ b/browser/themes/shared/devtools/dark-theme.css
@@ -98,17 +98,17 @@
 }
 
 .CodeMirror-Tern-completion-object:before {
   background-color: #3689b2;
 }
 
 .cm-s-mozilla .cm-unused-line {
   text-decoration: line-through;
-  -moz-text-decoration-color: #5f88b0;
+  text-decoration-color: #5f88b0;
 }
 
 .cm-s-mozilla .cm-executed-line {
   background-color: #133c26;
 }
 
 .theme-fg-color3,
 .cm-s-mozilla .cm-builtin,
--- a/browser/themes/shared/devtools/light-theme.css
+++ b/browser/themes/shared/devtools/light-theme.css
@@ -71,17 +71,17 @@
 }
 
 .theme-separator { /* grey */
   border-color: #cddae5;
 }
 
 .cm-s-mozilla .cm-unused-line {
   text-decoration: line-through;
-  -moz-text-decoration-color: #5f88b0;
+  text-decoration-color: #5f88b0;
 }
 
 .cm-s-mozilla .cm-executed-line {
   background-color: #fcfffc;
 }
 
 .theme-fg-color1,
 .cm-s-mozilla .cm-number,
--- a/browser/themes/shared/devtools/ruleview.css
+++ b/browser/themes/shared/devtools/ruleview.css
@@ -193,17 +193,17 @@
   }
 }
 
 .ruleview-overridden {
   text-decoration: line-through;
 }
 
 .theme-light .ruleview-overridden {
-  -moz-text-decoration-color: #667380; /*  Content (Text) - Dark Grey */
+  text-decoration-color: #667380; /*  Content (Text) - Dark Grey */
 }
 
 .styleinspector-propertyeditor {
   border: 1px solid #CCC;
   padding: 0;
 }
 
 .ruleview-property {
--- a/configure.in
+++ b/configure.in
@@ -7156,16 +7156,17 @@ if test "$NS_TRACE_MALLOC" -a "$MOZ_REPL
     AC_MSG_ERROR([--enable-trace-malloc and --enable-replace-malloc are conflicting options])
 fi
 
 if test -n "$MOZ_REPLACE_MALLOC" -a -z "$MOZ_MEMORY"; then
     dnl We don't want to enable jemalloc unconditionally because it may be a
     dnl deliberate choice not to enable it (bug 702250, for instance)
     AC_MSG_ERROR([--enable-replace-malloc requires --enable-jemalloc])
 elif test -n "$MOZ_REPLACE_MALLOC"; then
+    AC_DEFINE(MOZ_REPLACE_MALLOC)
     MOZ_NATIVE_JEMALLOC=
 
     dnl Replace-malloc Mac linkage quirks
     if test -n "$MACOSX_DEPLOYMENT_TARGET"; then
         AC_CACHE_CHECK([how to do weak dynamic linking],
             ac_cv_weak_dynamic_linking,
             [echo 'extern void foo() __attribute__((weak_import));int bar() { if (foo) foo(); return 0; }' > conftest.c
              if AC_TRY_COMMAND([${CC-cc} -o conftest${DLL_SUFFIX} $CFLAGS -dynamiclib $LDFLAGS -Wl,-U,_foo conftest.c $LIBS 1>&5]) &&
@@ -7378,27 +7379,17 @@ MOZ_ARG_ENABLE_BOOL(install-strip,
 dnl ========================================================
 dnl = --disable-elf-hack
 dnl ========================================================
 
 USE_ELF_HACK=1
 MOZ_ARG_DISABLE_BOOL(elf-hack,
 [  --disable-elf-hack      Disable elf hacks],
     [USE_ELF_HACK=],
-    [USE_ELF_HACK=F # Force enable elf-hack])
-
-# Disable elf hack for profiling because the built in profiler
-# doesn't read the segments properly with elf hack. This is
-# temporary and should be fixed soon in the profiler.
-if test "$MOZ_PROFILING" = 1; then
-  if test "$USE_ELF_HACK" = F; then
-    AC_ERROR([--enable-elf-hack is not compatible with --enable-profiling])
-  fi
-  USE_ELF_HACK=
-fi
+    [USE_ELF_HACK=1])
 
 # Only enable elfhack where supported
 if test "$USE_ELF_HACK" = 1; then
     case "${HOST_OS_ARCH},${OS_ARCH}" in
     Linux,Linux)
         case "${CPU_ARCH}" in
         arm | x86 | x86_64)
             USE_ELF_HACK=1
deleted file mode 100644
--- a/dom/apps/tests/file_test_widget.js
+++ /dev/null
@@ -1,231 +0,0 @@
-var gWidgetManifestURL = 'http://test/tests/dom/apps/tests/file_app.sjs?apptype=widget&getmanifest=true';
-var gInvalidWidgetManifestURL = 'http://test/tests/dom/apps/tests/file_app.sjs?apptype=invalidWidget&getmanifest=true';
-var gApp;
-var gHasBrowserPermission;
-
-function onError() {
-  ok(false, "Error callback invoked");
-  finish();
-}
-
-function installApp(path) {
-  var request = navigator.mozApps.install(path);
-  request.onerror = onError;
-  request.onsuccess = function() {
-    gApp = request.result;
-
-    runTest();
-  }
-}
-
-function uninstallApp() {
-  // Uninstall the app.
-  var request = navigator.mozApps.mgmt.uninstall(gApp);
-  request.onerror = onError;
-  request.onsuccess = function() {
-    // All done.
-    info("All done");
-
-    runTest();
-  }
-}
-
-function testApp(isValidWidget) {
-  info("Test widget feature. IsValidWidget: " + isValidWidget);
-
-  var ifr = document.createElement('iframe');
-  ifr.setAttribute('mozbrowser', 'true');
-  ifr.setAttribute('mozwidget', gApp.manifestURL);
-  ifr.setAttribute('src', gApp.origin+gApp.manifest.launch_path);
-
-  var domParent = document.getElementById('container');
-  domParent.appendChild(ifr);
-
-  var mm = SpecialPowers.getBrowserFrameMessageManager(ifr);
-  mm.addMessageListener('OK', function(msg) {
-    ok(isValidWidget, "Message from widget: " + SpecialPowers.wrap(msg).json);
-  });
-  mm.addMessageListener('KO', function(msg) {
-    ok(!isValidWidget, "Message from widget: " + SpecialPowers.wrap(msg).json);
-  });
-  mm.addMessageListener('DONE', function(msg) {
-    ok(true, "Message from widget complete: "+SpecialPowers.wrap(msg).json);
-    domParent.removeChild(ifr);
-    runTest();
-  });
-
-  ifr.addEventListener('mozbrowserloadend', function() {
-    ok(true, "receive mozbrowserloadend");
-
-    // Test limited browser API feature only for valid widget case
-    if (isValidWidget) {
-      testLimitedBrowserAPI(ifr);
-    }
-    SimpleTest.executeSoon(()=>loadFrameScript(mm));
-  }, false);
-
-  // Test limited browser API feature only for valid widget case
-  if (!isValidWidget) {
-    return;
-  }
-
-  [
-    'mozbrowsertitlechange',
-    'mozbrowseropenwindow',
-    'mozbrowserscroll',
-    'mozbrowserasyncscroll'
-  ].forEach( function(topic) {
-    ifr.addEventListener(topic, function() {
-      ok(false, topic + " should be hidden");
-    }, false);
-  });
-}
-
-function testLimitedBrowserAPI(ifr) {
-  var securitySensitiveCalls = [
-    { api: 'sendMouseEvent'      , args: ['mousedown', 0, 0, 0, 0, 0] },
-    { api: 'sendTouchEvent'      , args: ['touchstart', [0], [0], [0], [1], [1], [0], [1], 1, 0] },
-    { api: 'goBack'              , args: [] },
-    { api: 'goForward'           , args: [] },
-    { api: 'reload'              , args: [] },
-    { api: 'stop'                , args: [] },
-    { api: 'download'            , args: ['http://example.org'] },
-    { api: 'purgeHistory'        , args: [] },
-    { api: 'getScreenshot'       , args: [0, 0] },
-    { api: 'zoom'                , args: [0.1] },
-    { api: 'getCanGoBack'        , args: [] },
-    { api: 'getCanGoForward'     , args: [] },
-    { api: 'getContentDimensions', args: [] }
-  ];
-  securitySensitiveCalls.forEach( function(call) {
-    if (gHasBrowserPermission) {
-      isnot(typeof ifr[call.api], "undefined", call.api + " should be defined");
-      var didThrow;
-      try {
-        ifr[call.api].apply(ifr, call.args);
-      } catch (e) {
-        ok(e instanceof DOMException, "throw right exception type");
-        didThrow = e.code;
-      }
-      is(didThrow, DOMException.INVALID_NODE_TYPE_ERR, "call " + call.api + " should throw exception");
-    } else {
-      is(typeof ifr[call.api], "undefined", call.api + " should be hidden for widget");
-    }
-  });
-}
-
-function loadFrameScript(mm) {
-  var script = 'data:,\
-  function ok(p, msg) { \
-  if (p) { \
-  sendAsyncMessage("OK", msg); \
-} else { \
-  sendAsyncMessage("KO", msg); \
-} \
-} \
-  \
-  function is(a, b, msg) { \
-  if (a == b) { \
-  sendAsyncMessage("OK", a + " == " + b + " - " + msg); \
-} else { \
-  sendAsyncMessage("KO", a + " != " + b + " - " + msg); \
-} \
-} \
-  \
-  function finish() { \
-  sendAsyncMessage("DONE",""); \
-} \
-  \
-  function onError() { \
-  ok(false, "Error callback invoked"); \
-  finish(); \
-} \
-  \
-  function checkWidget(widget) { \
-  /*For invalid widget case, ignore the following check*/\
-  if (widget) { \
-  var widgetName = "Really Rapid Release (APPTYPETOKEN)"; \
-  is(widget.origin, "http://test", "Widget origin should be correct"); \
-  is(widget.installOrigin, "http://mochi.test:8888", "Install origin should be correct"); \
-} \
-  finish(); \
-} \
-  \
-  var request = content.window.navigator.mozApps.getSelf(); \
-  request.onsuccess = function() { \
-  var widget = request.result; \
-  ok(widget,"Should be a widget"); \
-  checkWidget(widget); \
-}; \
-  request.onerror = onError; \
-  content.window.open("about:blank"); /*test mozbrowseropenwindow*/ \
-  content.window.scrollTo(4000, 4000); /*test mozbrowser(async)scroll*/ \
-  ';
-  mm.loadFrameScript(script, /* allowDelayedLoad = */ false);
-}
-
-var tests = [
-  // Permissions
-  function() {
-    SpecialPowers.pushPermissions(
-      [{ "type": "browser", "allow": gHasBrowserPermission ? 1 : 0, "context": document },
-       { "type": "embed-widgets", "allow": 1, "context": document },
-       { "type": "webapps-manage", "allow": 1, "context": document }], runTest);
-  },
-
-  // Preferences
-  function() {
-    SpecialPowers.pushPrefEnv({"set": [["dom.mozBrowserFramesEnabled", true],
-                                       ["dom.enable_widgets", true],
-                                       ["dom.datastore.sysMsgOnChangeShortTimeoutSec", 1],
-                                       ["dom.datastore.sysMsgOnChangeLongTimeoutSec", 3]]}, runTest);
-  },
-
-  function() {
-    if (SpecialPowers.isMainProcess()) {
-      SpecialPowers.Cu.import("resource://gre/modules/DataStoreChangeNotifier.jsm");
-    }
-
-    SpecialPowers.setAllAppsLaunchable(true);
-    runTest();
-  },
-
-  // No confirmation needed when an app is installed
-  function() {
-    SpecialPowers.autoConfirmAppInstall(() => {
-      SpecialPowers.autoConfirmAppUninstall(runTest);
-    });
-  },
-
-  // Installing the app
-  ()=>installApp(gWidgetManifestURL),
-
-  // Run tests in app
-  ()=>testApp(true),
-
-  // Uninstall the app
-  uninstallApp,
-
-  // Installing the app for invalid widget case
-  ()=>installApp(gInvalidWidgetManifestURL),
-
-  // Run tests in app for invalid widget case
-  ()=>testApp(false),
-
-  // Uninstall the app
-  uninstallApp
-];
-
-function runTest() {
-  if (!tests.length) {
-    finish();
-    return;
-  }
-
-  var test = tests.shift();
-  test();
-}
-
-function finish() {
-  SimpleTest.finish();
-}
--- a/dom/apps/tests/mochitest.ini
+++ b/dom/apps/tests/mochitest.ini
@@ -12,17 +12,16 @@ support-files =
   file_manifest.json^headers^
   file_trusted_app.template.webapp
   file_invalidWidget_app.template.webapp
   file_packaged_app.sjs
   file_packaged_app.template.html
   file_packaged_app.template.webapp
   file_widget_app.template.webapp
   file_widget_app.template.html
-  file_test_widget.js
   signed_app.sjs
   signed_app_template.webapp
   signed/*
   test_packaged_app_common.js
   marketplace/*
   pkg_install_iframe.html
 
 [test_app_enabled.html]
@@ -40,10 +39,8 @@ skip-if = (toolkit == 'android' && proce
 skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
 [test_receipt_operations.html]
 [test_signed_pkg_install.html]
 [test_uninstall_errors.html]
 [test_theme_role.html]
 [test_web_app_install.html]
 [test_widget.html]
 skip-if = os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
-[test_widget_browser.html]
-skip-if = os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
--- a/dom/apps/tests/test_widget.html
+++ b/dom/apps/tests/test_widget.html
@@ -1,18 +1,235 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <meta charset="utf-8">
   <title>Test for DataStore - basic operation on a readonly db</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="application/javascript" src="file_test_widget.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body>
 <div id="container"></div>
   <script type="application/javascript;version=1.7">
+
+  var gWidgetManifestURL = 'http://test/tests/dom/apps/tests/file_app.sjs?apptype=widget&getmanifest=true';
+  var gInvalidWidgetManifestURL = 'http://test/tests/dom/apps/tests/file_app.sjs?apptype=invalidWidget&getmanifest=true';
+  var gApp;
+
+  function onError() {
+    ok(false, "Error callback invoked");
+    finish();
+  }
+
+  function installApp(path) {
+    var request = navigator.mozApps.install(path);
+    request.onerror = onError;
+    request.onsuccess = function() {
+      gApp = request.result;
+
+      runTest();
+    }
+  }
+
+  function uninstallApp() {
+    // Uninstall the app.
+    var request = navigator.mozApps.mgmt.uninstall(gApp);
+    request.onerror = onError;
+    request.onsuccess = function() {
+      // All done.
+      info("All done");
+
+      runTest();
+    }
+  }
+
+  function testApp(isValidWidget) {
+    info("Test widget feature. IsValidWidget: " + isValidWidget);
+
+    var ifr = document.createElement('iframe');
+    ifr.setAttribute('mozbrowser', 'true');
+    ifr.setAttribute('mozwidget', gApp.manifestURL);
+    ifr.setAttribute('src', gApp.origin+gApp.manifest.launch_path);
+
+    var domParent = document.getElementById('container');
+    domParent.appendChild(ifr);
+
+    var mm = SpecialPowers.getBrowserFrameMessageManager(ifr);
+    mm.addMessageListener('OK', function(msg) {
+      ok(isValidWidget, "Message from widget: " + SpecialPowers.wrap(msg).json);
+    });
+    mm.addMessageListener('KO', function(msg) {
+      ok(!isValidWidget, "Message from widget: " + SpecialPowers.wrap(msg).json);
+    });
+    mm.addMessageListener('DONE', function(msg) {
+      ok(true, "Message from widget complete: "+SpecialPowers.wrap(msg).json);
+      domParent.removeChild(ifr);
+      runTest();
+    });
+
+    ifr.addEventListener('mozbrowserloadend', function() {
+      ok(true, "receive mozbrowserloadend");
+
+      // Test limited browser API feature only for valid widget case
+      if (isValidWidget) {
+        testLimitedBrowserAPI(ifr);
+      }
+      SimpleTest.executeSoon(()=>loadFrameScript(mm));
+    }, false);
+
+    // Test limited browser API feature only for valid widget case
+    if (!isValidWidget) {
+      return;
+    }
+
+    [
+      'mozbrowsertitlechange',
+      'mozbrowseropenwindow',
+      'mozbrowserscroll',
+      'mozbrowserasyncscroll'
+    ].forEach( function(topic) {
+      ifr.addEventListener(topic, function() {
+        ok(false, topic + " should be hidden");
+      }, false);
+    });
+  }
+
+  function testLimitedBrowserAPI(ifr) {
+    var securitySensitiveCalls = [
+      'sendMouseEvent',
+      'sendTouchEvent',
+      'goBack',
+      'goForward',
+      'reload',
+      'stop',
+      'download',
+      'purgeHistory',
+      'getScreenshot',
+      'zoom',
+      'getCanGoBack',
+      'getCanGoForward'
+    ];
+    securitySensitiveCalls.forEach( function(call) {
+      is(typeof ifr[call], "undefined", call + " should be hidden for widget");
+    });
+  }
+
+  function loadFrameScript(mm) {
+    var script = 'data:,\
+      function ok(p, msg) { \
+        if (p) { \
+          sendAsyncMessage("OK", msg); \
+        } else { \
+          sendAsyncMessage("KO", msg); \
+        } \
+      } \
+      \
+      function is(a, b, msg) { \
+        if (a == b) { \
+          sendAsyncMessage("OK", a + " == " + b + " - " + msg); \
+        } else { \
+          sendAsyncMessage("KO", a + " != " + b + " - " + msg); \
+        } \
+      } \
+      \
+      function finish() { \
+          sendAsyncMessage("DONE",""); \
+      } \
+      \
+      function onError() { \
+        ok(false, "Error callback invoked"); \
+        finish(); \
+      } \
+      \
+      function checkWidget(widget) { \
+        /*For invalid widget case, ignore the following check*/\
+        if (widget) { \
+          var widgetName = "Really Rapid Release (APPTYPETOKEN)"; \
+          is(widget.origin, "http://test", "Widget origin should be correct"); \
+          is(widget.installOrigin, "http://mochi.test:8888", "Install origin should be correct"); \
+        } \
+        finish(); \
+      } \
+      \
+      var request = content.window.navigator.mozApps.getSelf(); \
+      request.onsuccess = function() { \
+        var widget = request.result; \
+        ok(widget,"Should be a widget"); \
+        checkWidget(widget); \
+      }; \
+      request.onerror = onError; \
+      content.window.open("about:blank"); /*test mozbrowseropenwindow*/ \
+      content.window.scrollTo(4000, 4000); /*test mozbrowser(async)scroll*/ \
+      ';
+    mm.loadFrameScript(script, /* allowDelayedLoad = */ false);
+  }
+
+  var tests = [
+    // Permissions
+    function() {
+      SpecialPowers.pushPermissions(
+        [{ "type": "browser", "allow": 1, "context": document },
+         { "type": "embed-widgets", "allow": 1, "context": document },
+         { "type": "webapps-manage", "allow": 1, "context": document }], runTest);
+    },
+
+    // Preferences
+    function() {
+      SpecialPowers.pushPrefEnv({"set": [["dom.mozBrowserFramesEnabled", true],
+                                         ["dom.enable_widgets", true],
+                                         ["dom.datastore.sysMsgOnChangeShortTimeoutSec", 1],
+                                         ["dom.datastore.sysMsgOnChangeLongTimeoutSec", 3]]}, runTest);
+    },
+
+    function() {
+      if (SpecialPowers.isMainProcess()) {
+        SpecialPowers.Cu.import("resource://gre/modules/DataStoreChangeNotifier.jsm");
+      }
+
+      SpecialPowers.setAllAppsLaunchable(true);
+      runTest();
+    },
+
+    // No confirmation needed when an app is installed
+    function() {
+      SpecialPowers.autoConfirmAppInstall(() => {
+        SpecialPowers.autoConfirmAppUninstall(runTest);
+      });
+    },
+
+    // Installing the app
+    ()=>installApp(gWidgetManifestURL),
+
+    // Run tests in app
+    ()=>testApp(true),
+
+    // Uninstall the app
+    uninstallApp,
+
+    // Installing the app for invalid widget case
+    ()=>installApp(gInvalidWidgetManifestURL),
+
+    // Run tests in app for invalid widget case
+    ()=>testApp(false),
+
+    // Uninstall the app
+    uninstallApp
+  ];
+
+  function runTest() {
+    if (!tests.length) {
+      finish();
+      return;
+    }
+
+    var test = tests.shift();
+    test();
+  }
+
+  function finish() {
+    SimpleTest.finish();
+  }
+
   SimpleTest.waitForExplicitFinish();
-  gHasBrowserPermission = false;
   runTest();
   </script>
 </body>
 </html>
deleted file mode 100644
--- a/dom/apps/tests/test_widget_browser.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <meta charset="utf-8">
-  <title>Test for DataStore - basic operation on a readonly db</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="application/javascript" src="file_test_widget.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<div id="container"></div>
-  <script type="application/javascript;version=1.7">
-  SimpleTest.waitForExplicitFinish();
-  gHasBrowserPermission = true;
-  runTest();
-  </script>
-</body>
-</html>
--- a/dom/base/EventSource.cpp
+++ b/dom/base/EventSource.cpp
@@ -57,17 +57,16 @@ namespace dom {
 EventSource::EventSource(nsPIDOMWindow* aOwnerWindow) :
   DOMEventTargetHelper(aOwnerWindow),
   mStatus(PARSE_STATE_OFF),
   mFrozen(false),
   mErrorLoadOnRedirect(false),
   mGoingToDispatchAllMessages(false),
   mWithCredentials(false),
   mWaitingForOnStopRequest(false),
-  mInterrupted(false),
   mLastConvertionResult(NS_OK),
   mReadyState(CONNECTING),
   mScriptLine(0),
   mInnerWindowID(0)
 {
 }
 
 EventSource::~EventSource()
@@ -336,39 +335,40 @@ EventSource::OnStartRequest(nsIRequest *
                             nsISupports *ctxt)
 {
   nsresult rv = CheckHealthOfRequestCallback(aRequest);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  bool requestSucceeded;
-  rv = httpChannel->GetRequestSucceeded(&requestSucceeded);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsAutoCString contentType;
-  rv = httpChannel->GetContentType(contentType);
+  nsresult status;
+  rv = aRequest->GetStatus(&status);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsresult status;
-  aRequest->GetStatus(&status);
-
-  if (NS_FAILED(status) || !requestSucceeded ||
-      !contentType.EqualsLiteral(TEXT_EVENT_STREAM)) {
-    DispatchFailConnection();
-    return NS_ERROR_NOT_AVAILABLE;
+  if (NS_FAILED(status)) {
+    // EventSource::OnStopRequest will evaluate if it shall either reestablish
+    // or fail the connection
+    return NS_ERROR_ABORT;
   }
 
   uint32_t httpStatus;
   rv = httpChannel->GetResponseStatus(&httpStatus);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (httpStatus != 200) {
-    mInterrupted = true;
+    DispatchFailConnection();
+    return NS_ERROR_ABORT;
+  }
+
+  nsAutoCString contentType;
+  rv = httpChannel->GetContentType(contentType);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!contentType.EqualsLiteral(TEXT_EVENT_STREAM)) {
     DispatchFailConnection();
     return NS_ERROR_ABORT;
   }
 
   nsCOMPtr<nsIRunnable> event =
     NS_NewRunnableMethod(this, &EventSource::AnnounceConnection);
   NS_ENSURE_STATE(event);
 
@@ -449,40 +449,48 @@ EventSource::OnStopRequest(nsIRequest *a
                            nsresult aStatusCode)
 {
   mWaitingForOnStopRequest = false;
 
   if (mReadyState == CLOSED) {
     return NS_ERROR_ABORT;
   }
 
-  if (NS_FAILED(aStatusCode)) {
+  // "Network errors that prevents the connection from being established in the
+  //  first place (e.g. DNS errors), must cause the user agent to asynchronously
+  //  reestablish the connection.
+  //
+  //  (...) the cancelation of the fetch algorithm by the user agent (e.g. in
+  //  response to window.stop() or the user canceling the network connection
+  //  manually) must cause the user agent to fail the connection.
+
+  if (NS_FAILED(aStatusCode) &&
+      aStatusCode != NS_ERROR_CONNECTION_REFUSED &&
+      aStatusCode != NS_ERROR_NET_TIMEOUT &&
+      aStatusCode != NS_ERROR_NET_RESET &&
+      aStatusCode != NS_ERROR_NET_INTERRUPT &&
+      aStatusCode != NS_ERROR_PROXY_CONNECTION_REFUSED &&
+      aStatusCode != NS_ERROR_DNS_LOOKUP_QUEUE_FULL) {
     DispatchFailConnection();
-    return aStatusCode;
+    return NS_ERROR_ABORT;
   }
 
-  nsresult rv;
-  nsresult healthOfRequestResult = CheckHealthOfRequestCallback(aRequest);
-  if (NS_SUCCEEDED(healthOfRequestResult) &&
-      mLastConvertionResult == NS_PARTIAL_MORE_INPUT) {
-    // we had an incomplete UTF8 char at the end of the stream
-    rv = ParseCharacter(REPLACEMENT_CHAR);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
+  nsresult rv = CheckHealthOfRequestCallback(aRequest);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   ClearFields();
 
   nsCOMPtr<nsIRunnable> event =
     NS_NewRunnableMethod(this, &EventSource::ReestablishConnection);
   NS_ENSURE_STATE(event);
 
   rv = NS_DispatchToMainThread(event);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  return healthOfRequestResult;
+  return NS_OK;
 }
 
 /**
  * Simple helper class that just forwards the redirect callback back
  * to the EventSource.
  */
 class AsyncVerifyRedirectCallbackFwr MOZ_FINAL : public nsIAsyncVerifyRedirectCallback
 {
@@ -864,21 +872,16 @@ EventSource::ResetConnection()
 
 void
 EventSource::ReestablishConnection()
 {
   if (mReadyState == CLOSED) {
     return;
   }
 
-  if (mReadyState != OPEN) {
-    NS_WARNING("Unexpected mReadyState!!!");
-    return;
-  }
-
   nsresult rv = ResetConnection();
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to reset the connection!!!");
     return;
   }
 
   rv = CheckInnerWindowCorrectness();
   if (NS_FAILED(rv)) {
@@ -989,17 +992,17 @@ EventSource::ConsoleError()
 {
   nsAutoCString targetSpec;
   nsresult rv = mSrc->GetSpec(targetSpec);
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ConvertUTF8toUTF16 specUTF16(targetSpec);
   const char16_t *formatStrings[] = { specUTF16.get() };
 
-  if (mReadyState == CONNECTING && !mInterrupted) {
+  if (mReadyState == CONNECTING) {
     rv = PrintErrorOnConsole("chrome://global/locale/appstrings.properties",
                              MOZ_UTF16("connectionFailure"),
                              formatStrings, ArrayLength(formatStrings));
   } else {
     rv = PrintErrorOnConsole("chrome://global/locale/appstrings.properties",
                              MOZ_UTF16("netInterrupt"),
                              formatStrings, ArrayLength(formatStrings));
   }
--- a/dom/base/EventSource.h
+++ b/dom/base/EventSource.h
@@ -216,17 +216,16 @@ protected:
   };
   ParserStatus mStatus;
 
   bool mFrozen;
   bool mErrorLoadOnRedirect;
   bool mGoingToDispatchAllMessages;
   bool mWithCredentials;
   bool mWaitingForOnStopRequest;
-  bool mInterrupted;
 
   // used while reading the input streams
   nsCOMPtr<nsIUnicodeDecoder> mUnicodeDecoder;
   nsresult mLastConvertionResult;
   nsString mLastFieldName;
   nsString mLastFieldValue;
 
   nsCOMPtr<nsILoadGroup> mLoadGroup;
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -14089,18 +14089,22 @@ nsGlobalWindow::GetSidebar(OwningExterna
   aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
 #endif
 }
 
 void
 nsGlobalWindow::ClearDocumentDependentSlots(JSContext* aCx)
 {
   MOZ_ASSERT(IsInnerWindow());
-  WindowBinding::ClearCachedDocumentValue(aCx, this);
-  WindowBinding::ClearCachedPerformanceValue(aCx, this);
+
+  // If JSAPI OOMs here, there is basically nothing we can do to recover safely.
+  if (!WindowBinding::ClearCachedDocumentValue(aCx, this) ||
+      !WindowBinding::ClearCachedPerformanceValue(aCx, this)) {
+    MOZ_CRASH("Unhandlable OOM while clearing document dependent slots.");
+  }
 }
 
 /* static */
 JSObject*
 nsGlobalWindow::CreateNamedPropertiesObject(JSContext *aCx,
                                             JS::Handle<JSObject*> aProto)
 {
   return WindowNamedPropertiesHandler::Create(aCx, aProto);
--- a/dom/base/nsImageLoadingContent.cpp
+++ b/dom/base/nsImageLoadingContent.cpp
@@ -177,17 +177,17 @@ nsImageLoadingContent::Notify(imgIReques
           = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
 
         nsIDocument *doc = GetOurOwnerDoc();
         doc->AddBlockedTrackingNode(thisNode);
       }
     }
     nsresult status =
         reqStatus & imgIRequest::STATUS_ERROR ? NS_ERROR_FAILURE : NS_OK;
-    return OnStopRequest(aRequest, status);
+    return OnLoadComplete(aRequest, status);
   }
 
   if (aType == imgINotificationObserver::DECODE_COMPLETE) {
     if (mFireEventsOnDecode) {
       mFireEventsOnDecode = false;
 
       uint32_t reqStatus;
       aRequest->GetImageStatus(&reqStatus);
@@ -200,18 +200,17 @@ nsImageLoadingContent::Notify(imgIReques
 
     UpdateImageState(true);
   }
 
   return NS_OK;
 }
 
 nsresult
-nsImageLoadingContent::OnStopRequest(imgIRequest* aRequest,
-                                     nsresult aStatus)
+nsImageLoadingContent::OnLoadComplete(imgIRequest* aRequest, nsresult aStatus)
 {
   uint32_t oldStatus;
   aRequest->GetImageStatus(&oldStatus);
 
   //XXXjdm This occurs when we have a pending request created, then another
   //       pending request replaces it before the first one is finished.
   //       This begs the question of what the correct behaviour is; we used
   //       to not have to care because we ran this code in OnStopDecode which
--- a/dom/base/nsImageLoadingContent.h
+++ b/dom/base/nsImageLoadingContent.h
@@ -204,17 +204,17 @@ protected:
    */
   virtual mozilla::CORSMode GetCORSMode();
 
   // Subclasses are *required* to call BindToTree/UnbindFromTree.
   void BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                   nsIContent* aBindingParent, bool aCompileEventHandlers);
   void UnbindFromTree(bool aDeep, bool aNullParent);
 
-  nsresult OnStopRequest(imgIRequest* aRequest, nsresult aStatus);
+  nsresult OnLoadComplete(imgIRequest* aRequest, nsresult aStatus);
   void OnUnlockedDraw();
   nsresult OnImageIsAnimated(imgIRequest *aRequest);
 
   // The nsContentPolicyType we would use for this ImageLoadType
   static nsContentPolicyType PolicyTypeForLoad(ImageLoadType aImageLoadType);
 
 private:
   /**
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -2407,24 +2407,16 @@ DOMGCSliceCallback(JSRuntime *aRt, JS::G
     nsCycleCollector_dispatchDeferredDeletion();
   }
 
   if (sPrevGCSliceCallback)
     (*sPrevGCSliceCallback)(aRt, aProgress, aDesc);
 }
 
 void
-nsJSContext::ReportPendingException()
-{
-  if (mIsInitialized) {
-    nsJSUtils::ReportPendingException(mContext);
-  }
-}
-
-void
 nsJSContext::SetWindowProxy(JS::Handle<JSObject*> aWindowProxy)
 {
   mWindowProxy = aWindowProxy;
 }
 
 JSObject*
 nsJSContext::GetWindowProxy()
 {
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -141,21 +141,16 @@ protected:
 
   // Helper to convert xpcom datatypes to jsvals.
   nsresult ConvertSupportsTojsvals(nsISupports *aArgs,
                                    JS::Handle<JSObject*> aScope,
                                    JS::AutoValueVector &aArgsOut);
 
   nsresult AddSupportsPrimitiveTojsvals(nsISupports *aArg, JS::Value *aArgv);
 
-  // Report the pending exception on our mContext, if any.  This
-  // function will set aside the frame chain on mContext before
-  // reporting.
-  void ReportPendingException();
-
 private:
   void DestroyJSContext();
 
   nsrefcnt GetCCRefcnt();
 
   JSContext *mContext;
   JS::Heap<JSObject*> mWindowProxy;
 
--- a/dom/base/nsNodeInfoManager.cpp
+++ b/dom/base/nsNodeInfoManager.cpp
@@ -23,16 +23,17 @@
 #include "nsReadableUtils.h"
 #include "nsGkAtoms.h"
 #include "nsComponentManagerUtils.h"
 #include "nsLayoutStatics.h"
 #include "nsBindingManager.h"
 #include "nsHashKeys.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsNameSpaceManager.h"
+#include "nsDocument.h"
 
 using namespace mozilla;
 using mozilla::dom::NodeInfo;
 
 #include "prlog.h"
 
 #ifdef PR_LOGGING
 static PRLogModuleInfo* gNodeInfoManagerLeakPRLog;
@@ -148,30 +149,43 @@ nsNodeInfoManager::~nsNodeInfoManager()
 
   nsLayoutStatics::Release();
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsNodeInfoManager)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsNodeInfoManager)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsNodeInfoManager)
-  if (tmp->mDocument &&
-      nsCCUncollectableMarker::InGeneration(cb,
-                                            tmp->mDocument->GetMarkedCCGeneration())) {
-    return NS_SUCCESS_INTERRUPTED_TRAVERSE;
-  }
   if (tmp->mNonDocumentNodeInfos) {
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mDocument)
   }
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBindingManager)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsNodeInfoManager, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsNodeInfoManager, Release)
 
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsNodeInfoManager)
+  if (tmp->mDocument) {
+    return NS_CYCLE_COLLECTION_PARTICIPANT(nsDocument)->CanSkip(tmp->mDocument, aRemovingAllowed);
+  }
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsNodeInfoManager)
+  if (tmp->mDocument) {
+    return NS_CYCLE_COLLECTION_PARTICIPANT(nsDocument)->CanSkipInCC(tmp->mDocument);
+  }
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsNodeInfoManager)
+  if (tmp->mDocument) {
+    return NS_CYCLE_COLLECTION_PARTICIPANT(nsDocument)->CanSkipThis(tmp->mDocument);
+  }
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
+
 nsresult
 nsNodeInfoManager::Init(nsIDocument *aDocument)
 {
   NS_ENSURE_TRUE(mNodeInfoHash, NS_ERROR_OUT_OF_MEMORY);
 
   NS_PRECONDITION(!mPrincipal,
                   "Being inited when we already have a principal?");
   nsresult rv;
--- a/dom/base/nsNodeInfoManager.h
+++ b/dom/base/nsNodeInfoManager.h
@@ -35,17 +35,17 @@ class NodeInfo;
 class nsNodeInfoManager MOZ_FINAL
 {
 private:
   ~nsNodeInfoManager();
 
 public:
   nsNodeInfoManager();
 
-  NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsNodeInfoManager)
+  NS_DECL_CYCLE_COLLECTION_SKIPPABLE_NATIVE_CLASS(nsNodeInfoManager)
 
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsNodeInfoManager)
 
   /**
    * Initialize the nodeinfo manager with a document.
    */
   nsresult Init(nsIDocument *aDocument);
 
--- a/dom/base/test/test_bug338583.html
+++ b/dom/base/test/test_bug338583.html
@@ -348,39 +348,39 @@ https://bugzilla.mozilla.org/show_bug.cg
       ok(gEventSourceObj3_g.hits['fn_onmessage'] == 0, "Test 3.g failed");
       gEventSourceObj3_g.close();
       setTestHasFinished(test_id);
     }, parseInt(1500*stress_factor));
   }
 
   function fnMessageListenerTest3h(e) {
     fnMessageListenerTest3h.msg_ok = (fnMessageListenerTest3h.msg_ok && e.data == "ok");
-    fnMessageListenerTest3h.id_ok = (fnMessageListenerTest3h.msg_ok && e.lastEventId == "");
+    fnMessageListenerTest3h.id_ok = (fnMessageListenerTest3h.id_ok && e.lastEventId == "");
   }
 
   function doTest3_h(test_id) {
     gEventSourceObj3_h = new EventSource("badMessageEvent2.eventsource");
 
-    gEventSourceObj3_h.addEventListener('message event', fnMessageListenerTest3h, true);
+    gEventSourceObj3_h.addEventListener('message', fnMessageListenerTest3h, true);
     fnMessageListenerTest3h.msg_ok = true;
     fnMessageListenerTest3h.id_ok = true;
 
     gEventSourceObj3_h.onmessage = fn_onmessage;
     gEventSourceObj3_h.hits = [];
     gEventSourceObj3_h.hits['fn_onmessage'] = 0;
 
     setTimeout(function() {
       ok(gEventSourceObj3_h.hits['fn_onmessage'] > 1, "Test 3.h.1 failed");
       if (gEventSourceObj3_h.hits['fn_onmessage'] > 1) {
         ok(fnMessageListenerTest3h.msg_ok, "Test 3.h.2 failed");
         ok(fnMessageListenerTest3h.id_ok, "Test 3.h.3 failed");
       }
       gEventSourceObj3_h.close();
       setTestHasFinished(test_id);
-    }, parseInt(3000*stress_factor));
+    }, parseInt(6000*stress_factor));
   }
 
 // in order to test (4)
 //   a) close the object when it is in use, which is being processed and that is expected
 //      to dispatch more eventlisteners
 //   b) remove an eventlistener in use
 
   function fn_onmessage4_a(e)
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -3469,17 +3469,16 @@ class CGClearCachedValueMethod(CGAbstrac
                 slotIndex)
             regetMember = fill(
                 """
                 JS::Rooted<JS::Value> temp(aCx);
                 JSJitGetterCallArgs args(&temp);
                 JSAutoCompartment ac(aCx, obj);
                 if (!get_${name}(aCx, obj, aObject, args)) {
                   js::SetReservedSlot(obj, ${slotIndex}, oldValue);
-                  nsJSUtils::ReportPendingException(aCx);
                   return false;
                 }
                 return true;
                 """,
                 name=self.member.identifier.name,
                 slotIndex=slotIndex)
         else:
             declObj = "JSObject* obj;\n"
--- a/dom/browser-element/BrowserElementParent.js
+++ b/dom/browser-element/BrowserElementParent.js
@@ -1,913 +1,129 @@
 /* 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";
 
-let Cu = Components.utils;
-let Ci = Components.interfaces;
-let Cc = Components.classes;
-let Cr = Components.results;
-
-/* BrowserElementParent injects script to listen for certain events in the
- * child.  We then listen to messages from the child script and take
- * appropriate action here in the parent.
- */
+const {utils: Cu, interfaces: Ci} = Components;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/BrowserElementPromptService.jsm");
+
+const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
+const BROWSER_FRAMES_ENABLED_PREF = "dom.mozBrowserFramesEnabled";
 
-XPCOMUtils.defineLazyGetter(this, "DOMApplicationRegistry", function () {
-  Cu.import("resource://gre/modules/Webapps.jsm");
-  return DOMApplicationRegistry;
-});
+XPCOMUtils.defineLazyModuleGetter(this, "BrowserElementParentBuilder",
+                                  "resource://gre/modules/BrowserElementParent.jsm",
+                                  "BrowserElementParentBuilder");
 
 function debug(msg) {
-  //dump("BrowserElementParent - " + msg + "\n");
-}
-
-function getIntPref(prefName, def) {
-  try {
-    return Services.prefs.getIntPref(prefName);
-  }
-  catch(err) {
-    return def;
-  }
-}
-
-function visibilityChangeHandler(e) {
-  // The visibilitychange event's target is the document.
-  let win = e.target.defaultView;
-
-  if (!win._browserElementParents) {
-    return;
-  }
-
-  let beps = Cu.nondeterministicGetWeakMapKeys(win._browserElementParents);
-  if (beps.length == 0) {
-    win.removeEventListener('visibilitychange', visibilityChangeHandler);
-    return;
-  }
-
-  for (let i = 0; i < beps.length; i++) {
-    beps[i]._ownerVisibilityChange();
-  }
+  //dump("BrowserElementParent.js - " + msg + "\n");
 }
 
-function defineNoReturnMethod(fn) {
-  return function method() {
-    if (!this._domRequestReady) {
-      // Remote browser haven't been created, we just queue the API call.
-      let args = Array.slice(arguments);
-      args.unshift(this);
-      this._pendingAPICalls.push(method.bind.apply(fn, args));
-      return;
-    }
-    if (this._isAlive()) {
-      fn.apply(this, arguments);
-    }
-  };
-}
+/**
+ * BrowserElementParent implements one half of <iframe mozbrowser>.  (The other
+ * half is, unsurprisingly, BrowserElementChild.)
+ *
+ * BrowserElementParentFactory detects when we create a windows or docshell
+ * contained inside a <iframe mozbrowser> and creates a BrowserElementParent
+ * object for that window.
+ *
+ * It creates a BrowserElementParent that injects script to listen for
+ * certain event.
+ */
 
-function defineDOMRequestMethod(msgName) {
-  return function() {
-    return this._sendDOMRequest(msgName);
-  };
+function BrowserElementParentFactory() {
+  this._initialized = false;
 }
 
-function BrowserElementParent() {
-  debug("Creating new BrowserElementParent object");
-  this._domRequestCounter = 0;
-  this._domRequestReady = false;
-  this._pendingAPICalls = [];
-  this._pendingDOMRequests = {};
-  this._pendingSetInputMethodActive = [];
-  this._nextPaintListeners = [];
-
-  Services.obs.addObserver(this, 'ask-children-to-exit-fullscreen', /* ownsWeak = */ true);
-  Services.obs.addObserver(this, 'oop-frameloader-crashed', /* ownsWeak = */ true);
-  Services.obs.addObserver(this, 'copypaste-docommand', /* ownsWeak = */ true);
-}
-
-BrowserElementParent.prototype = {
-
-  classDescription: "BrowserElementAPI implementation",
-  classID: Components.ID("{9f171ac4-0939-4ef8-b360-3408aedc3060}"),
-  contractID: "@mozilla.org/dom/browser-element-api;1",
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIBrowserElementAPI,
-                                         Ci.nsIObserver,
+BrowserElementParentFactory.prototype = {
+  classID: Components.ID("{ddeafdac-cb39-47c4-9cb8-c9027ee36d26}"),
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
                                          Ci.nsISupportsWeakReference]),
 
-  setFrameLoader: function(frameLoader) {
-    this._frameLoader = frameLoader;
-    this._frameElement = frameLoader.QueryInterface(Ci.nsIFrameLoader).ownerElement;
-    if (!this._frameElement) {
-      debug("No frame element?");
-      return;
-    }
-    // Listen to visibilitychange on the iframe's owner window, and forward
-    // changes down to the child.  We want to do this while registering as few
-    // visibilitychange listeners on _window as possible, because such a listener
-    // may live longer than this BrowserElementParent object.
-    //
-    // To accomplish this, we register just one listener on the window, and have
-    // it reference a WeakMap whose keys are all the BrowserElementParent objects
-    // on the window.  Then when the listener fires, we iterate over the
-    // WeakMap's keys (which we can do, because we're chrome) to notify the
-    // BrowserElementParents.
-    if (!this._window._browserElementParents) {
-      this._window._browserElementParents = new WeakMap();
-      this._window.addEventListener('visibilitychange',
-                                    visibilityChangeHandler,
-                                    /* useCapture = */ false,
-                                    /* wantsUntrusted = */ false);
-    }
-
-    this._window._browserElementParents.set(this, null);
-
-    // Insert ourself into the prompt service.
-    BrowserElementPromptService.mapFrameToBrowserElementParent(this._frameElement, this);
-    this._setupMessageListener();
-    this._registerAppManifest();
-  },
-
-  _runPendingAPICall: function() {
-    if (!this._pendingAPICalls) {
-      return;
-    }
-    for (let i = 0; i < this._pendingAPICalls.length; i++) {
-      try {
-        this._pendingAPICalls[i]();
-      } catch (e) {
-        // throw the expections from pending functions.
-        debug('Exception when running pending API call: ' +  e);
-      }
-    }
-    delete this._pendingAPICalls;
-  },
-
-  _registerAppManifest: function() {
-    // If this browser represents an app then let the Webapps module register for
-    // any messages that it needs.
-    let appManifestURL =
-          this._frameElement.QueryInterface(Ci.nsIMozBrowserFrame).appManifestURL;
-    if (appManifestURL) {
-      let inParent = Cc["@mozilla.org/xre/app-info;1"]
-                       .getService(Ci.nsIXULRuntime)
-                       .processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
-      if (inParent) {
-        DOMApplicationRegistry.registerBrowserElementParentForApp(
-          { manifestURL: appManifestURL }, this._mm);
-      } else {
-        this._mm.sendAsyncMessage("Webapps:RegisterBEP",
-                                  { manifestURL: appManifestURL });
-      }
-    }
-  },
-
-  _setupMessageListener: function() {
-    this._mm = this._frameLoader.messageManager;
-    let self = this;
-    let isWidget = this._frameLoader
-                       .QueryInterface(Ci.nsIFrameLoader)
-                       .ownerIsWidget;
-
-    // Messages we receive are handed to functions which take a (data) argument,
-    // where |data| is the message manager's data object.
-    // We use a single message and dispatch to various function based
-    // on data.msg_name
-    let mmCalls = {
-      "hello": this._recvHello,
-      "loadstart": this._fireProfiledEventFromMsg,
-      "loadend": this._fireProfiledEventFromMsg,
-      "close": this._fireEventFromMsg,
-      "error": this._fireEventFromMsg,
-      "firstpaint": this._fireProfiledEventFromMsg,
-      "documentfirstpaint": this._fireProfiledEventFromMsg,
-      "nextpaint": this._recvNextPaint,
-      "got-purge-history": this._gotDOMRequestResult,
-      "got-screenshot": this._gotDOMRequestResult,
-      "got-contentdimensions": this._gotDOMRequestResult,
-      "got-can-go-back": this._gotDOMRequestResult,
-      "got-can-go-forward": this._gotDOMRequestResult,
-      "fullscreen-origin-change": this._remoteFullscreenOriginChange,
-      "rollback-fullscreen": this._remoteFrameFullscreenReverted,
-      "exit-fullscreen": this._exitFullscreen,
-      "got-visible": this._gotDOMRequestResult,
-      "visibilitychange": this._childVisibilityChange,
-      "got-set-input-method-active": this._gotDOMRequestResult,
-      "selectionchange": this._handleSelectionChange,
-      "scrollviewchange": this._handleScrollViewChange,
-      "touchcarettap": this._handleTouchCaretTap
-    };
-
-    let mmSecuritySensitiveCalls = {
-      "showmodalprompt": this._handleShowModalPrompt,
-      "contextmenu": this._fireCtxMenuEvent,
-      "securitychange": this._fireEventFromMsg,
-      "locationchange": this._fireEventFromMsg,
-      "iconchange": this._fireEventFromMsg,
-      "scrollareachanged": this._fireEventFromMsg,
-      "titlechange": this._fireProfiledEventFromMsg,
-      "opensearch": this._fireEventFromMsg,
-      "manifestchange": this._fireEventFromMsg,
-      "metachange": this._fireEventFromMsg,
-      "resize": this._fireEventFromMsg,
-      "activitydone": this._fireEventFromMsg,
-      "scroll": this._fireEventFromMsg
-    };
-
-    this._mm.addMessageListener('browser-element-api:call', function(aMsg) {
-      if (!self._isAlive()) {
-        return;
-      }
-
-      if (aMsg.data.msg_name in mmCalls) {
-        return mmCalls[aMsg.data.msg_name].apply(self, arguments);
-      } else if (!isWidget && aMsg.data.msg_name in mmSecuritySensitiveCalls) {
-        return mmSecuritySensitiveCalls[aMsg.data.msg_name]
-                 .apply(self, arguments);
-      }
-    });
-  },
-
   /**
-   * You shouldn't touch this._frameElement or this._window if _isAlive is
-   * false.  (You'll likely get an exception if you do.)
+   * Called on app startup, and also when the browser frames enabled pref is
+   * changed.
    */
-  _isAlive: function() {
-    return !Cu.isDeadWrapper(this._frameElement) &&
-           !Cu.isDeadWrapper(this._frameElement.ownerDocument) &&
-           !Cu.isDeadWrapper(this._frameElement.ownerDocument.defaultView);
-  },
-
-  get _window() {
-    return this._frameElement.ownerDocument.defaultView;
-  },
-
-  get _windowUtils() {
-    return this._window.QueryInterface(Ci.nsIInterfaceRequestor)
-                       .getInterface(Ci.nsIDOMWindowUtils);
-  },
-
-  promptAuth: function(authDetail, callback) {
-    let evt;
-    let self = this;
-    let callbackCalled = false;
-    let cancelCallback = function() {
-      if (!callbackCalled) {
-        callbackCalled = true;
-        callback(false, null, null);
-      }
-    };
-
-    // 1. We don't handle password-only prompts.
-    // 2. We don't handle for widget case because of security concern.
-    if (authDetail.isOnlyPassword ||
-        this._frameLoader.QueryInterface(Ci.nsIFrameLoader).ownerIsWidget) {
-      cancelCallback();
+  _init: function() {
+    if (this._initialized) {
       return;
     }
 
-    /* username and password */
-    let detail = {
-      host:     authDetail.host,
-      realm:    authDetail.realm
-    };
-
-    evt = this._createEvent('usernameandpasswordrequired', detail,
-                            /* cancelable */ true);
-    Cu.exportFunction(function(username, password) {
-      if (callbackCalled)
-        return;
-      callbackCalled = true;
-      callback(true, username, password);
-    }, evt.detail, { defineAs: 'authenticate' });
-
-    Cu.exportFunction(cancelCallback, evt.detail, { defineAs: 'cancel' });
-
-    this._frameElement.dispatchEvent(evt);
-
-    if (!evt.defaultPrevented) {
-      cancelCallback();
-    }
-  },
-
-  _sendAsyncMsg: function(msg, data) {
-    try {
-      if (!data) {
-        data = { };
-      }
-
-      data.msg_name = msg;
-      this._mm.sendAsyncMessage('browser-element-api:call', data);
-    } catch (e) {
-      return false;
-    }
-    return true;
-  },
-
-  _recvHello: function() {
-    debug("recvHello");
-
-    // Inform our child if our owner element's document is invisible.  Note
-    // that we must do so here, rather than in the BrowserElementParent
-    // constructor, because the BrowserElementChild may not be initialized when
-    // we run our constructor.
-    if (this._window.document.hidden) {
-      this._ownerVisibilityChange();
-    }
-
-    if (!this._domRequestReady) {
-      // At least, one message listener such as for hello is registered.
-      // So we can use sendAsyncMessage now.
-      this._domRequestReady = true;
-      this._runPendingAPICall();
-    }
-
-    return {
-      name: this._frameElement.getAttribute('name'),
-      fullscreenAllowed:
-        this._frameElement.hasAttribute('allowfullscreen') ||
-        this._frameElement.hasAttribute('mozallowfullscreen'),
-      isPrivate: this._frameElement.hasAttribute('mozprivatebrowsing')
-    };
-  },
-
-  _fireCtxMenuEvent: function(data) {
-    let detail = data.json;
-    let evtName = detail.msg_name;
-
-    debug('fireCtxMenuEventFromMsg: ' + evtName + ' ' + detail);
-    let evt = this._createEvent(evtName, detail, /* cancellable */ true);
-
-    if (detail.contextmenu) {
-      var self = this;
-      Cu.exportFunction(function(id) {
-        self._sendAsyncMsg('fire-ctx-callback', {menuitem: id});
-      }, evt.detail, { defineAs: 'contextMenuItemSelected' });
+    // If the pref is disabled, do nothing except wait for the pref to change.
+    // (This is important for tests, if nothing else.)
+    if (!this._browserFramesPrefEnabled()) {
+      Services.prefs.addObserver(BROWSER_FRAMES_ENABLED_PREF, this, /* ownsWeak = */ true);
+      return;
     }
 
-    // The embedder may have default actions on context menu events, so
-    // we fire a context menu event even if the child didn't define a
-    // custom context menu
-    return !this._frameElement.dispatchEvent(evt);
-  },
-
-  /**
-   * add profiler marker for each event fired.
-   */
-  _fireProfiledEventFromMsg: function(data) {
-    if (Services.profiler !== undefined) {
-      Services.profiler.AddMarker(data.json.msg_name);
-    }
-    this._fireEventFromMsg(data);
-  },
+    debug("_init");
+    this._initialized = true;
 
-  /**
-   * Fire either a vanilla or a custom event, depending on the contents of
-   * |data|.
-   */
-  _fireEventFromMsg: function(data) {
-    let detail = data.json;
-    let name = detail.msg_name;
+    // Maps frame elements to BrowserElementParent objects.  We never look up
+    // anything in this map; the purpose is to keep the BrowserElementParent
+    // alive for as long as its frame element lives.
+    this._bepMap = new WeakMap();
 
-    // For events that send a "_payload_" property, we just want to transmit
-    // this in the event.
-    if ("_payload_" in detail) {
-      detail = detail._payload_;
-    }
-
-    debug('fireEventFromMsg: ' + name + ', ' + JSON.stringify(detail));
-    let evt = this._createEvent(name, detail,
-                                /* cancelable = */ false);
-    this._frameElement.dispatchEvent(evt);
+    Services.obs.addObserver(this, 'remote-browser-pending', /* ownsWeak = */ true);
+    Services.obs.addObserver(this, 'inprocess-browser-shown', /* ownsWeak = */ true);
   },
 
-  _handleShowModalPrompt: function(data) {
-    // Fire a showmodalprmopt event on the iframe.  When this method is called,
-    // the child is spinning in a nested event loop waiting for an
-    // unblock-modal-prompt message.
-    //
-    // If the embedder calls preventDefault() on the showmodalprompt event,
-    // we'll block the child until event.detail.unblock() is called.
-    //
-    // Otherwise, if preventDefault() is not called, we'll send the
-    // unblock-modal-prompt message to the child as soon as the event is done
-    // dispatching.
-
-    let detail = data.json;
-    debug('handleShowPrompt ' + JSON.stringify(detail));
-
-    // Strip off the windowID property from the object we send along in the
-    // event.
-    let windowID = detail.windowID;
-    delete detail.windowID;
-    debug("Event will have detail: " + JSON.stringify(detail));
-    let evt = this._createEvent('showmodalprompt', detail,
-                                /* cancelable = */ true);
-
-    let self = this;
-    let unblockMsgSent = false;
-    function sendUnblockMsg() {
-      if (unblockMsgSent) {
-        return;
-      }
-      unblockMsgSent = true;
-
-      // We don't need to sanitize evt.detail.returnValue (e.g. converting the
-      // return value of confirm() to a boolean); Gecko does that for us.
-
-      let data = { windowID: windowID,
-                   returnValue: evt.detail.returnValue };
-      self._sendAsyncMsg('unblock-modal-prompt', data);
+  _browserFramesPrefEnabled: function() {
+    try {
+      return Services.prefs.getBoolPref(BROWSER_FRAMES_ENABLED_PREF);
     }
-
-    Cu.exportFunction(sendUnblockMsg, evt.detail, { defineAs: 'unblock' });
-
-    this._frameElement.dispatchEvent(evt);
-
-    if (!evt.defaultPrevented) {
-      // Unblock the inner frame immediately.  Otherwise we'll unblock upon
-      // evt.detail.unblock().
-      sendUnblockMsg();
+    catch(e) {
+      return false;
     }
   },
 
-  _handleSelectionChange: function(data) {
-    let evt = this._createEvent('selectionchange', data.json,
-                                /* cancelable = */ false);
-    this._frameElement.dispatchEvent(evt);
-  },
-
-  _handleScrollViewChange: function(data) {
-    let evt = this._createEvent("scrollviewchange", data.json,
-                                /* cancelable = */ false);
-    this._frameElement.dispatchEvent(evt);
-  },
-
-  _handleTouchCaretTap: function(data) {
-    let evt = this._createEvent("touchcarettap", data.json,
-                                /* cancelable = */ false);
-    this._frameElement.dispatchEvent(evt);
-  },
-
-  _createEvent: function(evtName, detail, cancelable) {
-    // This will have to change if we ever want to send a CustomEvent with null
-    // detail.  For now, it's OK.
-    if (detail !== undefined && detail !== null) {
-      detail = Cu.cloneInto(detail, this._window);
-      return new this._window.CustomEvent('mozbrowser' + evtName,
-                                          { bubbles: true,
-                                            cancelable: cancelable,
-                                            detail: detail });
+  _observeInProcessBrowserFrameShown: function(frameLoader) {
+    // Ignore notifications that aren't from a BrowserOrApp
+    if (!frameLoader.QueryInterface(Ci.nsIFrameLoader).ownerIsBrowserOrAppFrame) {
+      return;
     }
-
-    return new this._window.Event('mozbrowser' + evtName,
-                                  { bubbles: true,
-                                    cancelable: cancelable });
-  },
-
-  /**
-   * Kick off a DOMRequest in the child process.
-   *
-   * We'll fire an event called |msgName| on the child process, passing along
-   * an object with two fields:
-   *
-   *  - id:  the ID of this request.
-   *  - arg: arguments to pass to the child along with this request.
-   *
-   * We expect the child to pass the ID back to us upon completion of the
-   * request.  See _gotDOMRequestResult.
-   */
-  _sendDOMRequest: function(msgName, args) {
-    let id = 'req_' + this._domRequestCounter++;
-    let req = Services.DOMRequest.createRequest(this._window);
-    let self = this;
-    let send = function() {
-      if (!self._isAlive()) {
-        return;
-      }
-      if (self._sendAsyncMsg(msgName, {id: id, args: args})) {
-        self._pendingDOMRequests[id] = req;
-      } else {
-        Services.DOMRequest.fireErrorAsync(req, "fail");
-      }
-    };
-    if (this._domRequestReady) {
-      send();
-    } else {
-      // Child haven't been loaded.
-      this._pendingAPICalls.push(send);
-    }
-    return req;
-  },
-
-  /**
-   * Called when the child process finishes handling a DOMRequest.  data.json
-   * must have the fields [id, successRv], if the DOMRequest was successful, or
-   * [id, errorMsg], if the request was not successful.
-   *
-   * The fields have the following meanings:
-   *
-   *  - id:        the ID of the DOM request (see _sendDOMRequest)
-   *  - successRv: the request's return value, if the request succeeded
-   *  - errorMsg:  the message to pass to DOMRequest.fireError(), if the request
-   *               failed.
-   *
-   */
-  _gotDOMRequestResult: function(data) {
-    let req = this._pendingDOMRequests[data.json.id];
-    delete this._pendingDOMRequests[data.json.id];
-
-    if ('successRv' in data.json) {
-      debug("Successful gotDOMRequestResult.");
-      let clientObj = Cu.cloneInto(data.json.successRv, this._window);
-      Services.DOMRequest.fireSuccess(req, clientObj);
-    }
-    else {
-      debug("Got error in gotDOMRequestResult.");
-      Services.DOMRequest.fireErrorAsync(req,
-        Cu.cloneInto(data.json.errorMsg, this._window));
-    }
-  },
-
-  setVisible: defineNoReturnMethod(function(visible) {
-    this._sendAsyncMsg('set-visible', {visible: visible});
-    this._frameLoader.visible = visible;
-  }),
-
-  getVisible: defineDOMRequestMethod('get-visible'),
-
-  setActive: defineNoReturnMethod(function(active) {
-    this._frameLoader.visible = active;
-  }),
-
-  getActive: function() {
-    if (!this._isAlive()) {
-      throw Components.Exception("Dead content process",
-                                 Cr.NS_ERROR_DOM_INVALID_STATE_ERR);
-    }
-
-    return this._frameLoader.visible;
+    debug("In-process browser frame shown " + frameLoader);
+    this._createBrowserElementParent(frameLoader,
+                                     /* hasRemoteFrame = */ false,
+                                     /* pending frame */ false);
   },
 
-  sendMouseEvent: defineNoReturnMethod(function(type, x, y, button, clickCount, modifiers) {
-    this._sendAsyncMsg("send-mouse-event", {
-      "type": type,
-      "x": x,
-      "y": y,
-      "button": button,
-      "clickCount": clickCount,
-      "modifiers": modifiers
-    });
-  }),
-
-  sendTouchEvent: defineNoReturnMethod(function(type, identifiers, touchesX, touchesY,
-                                                radiisX, radiisY, rotationAngles, forces,
-                                                count, modifiers) {
-
-    let tabParent = this._frameLoader.tabParent;
-    if (tabParent && tabParent.useAsyncPanZoom) {
-      tabParent.injectTouchEvent(type,
-                                 identifiers,
-                                 touchesX,
-                                 touchesY,
-                                 radiisX,
-                                 radiisY,
-                                 rotationAngles,
-                                 forces,
-                                 count,
-                                 modifiers);
-    } else {
-      this._sendAsyncMsg("send-touch-event", {
-        "type": type,
-        "identifiers": identifiers,
-        "touchesX": touchesX,
-        "touchesY": touchesY,
-        "radiisX": radiisX,
-        "radiisY": radiisY,
-        "rotationAngles": rotationAngles,
-        "forces": forces,
-        "count": count,
-        "modifiers": modifiers
-      });
-    }
-  }),
-
-  getCanGoBack: defineDOMRequestMethod('get-can-go-back'),
-  getCanGoForward: defineDOMRequestMethod('get-can-go-forward'),
-  getContentDimensions: defineDOMRequestMethod('get-contentdimensions'),
-
-  goBack: defineNoReturnMethod(function() {
-    this._sendAsyncMsg('go-back');
-  }),
-
-  goForward: defineNoReturnMethod(function() {
-    this._sendAsyncMsg('go-forward');
-  }),
-
-  reload: defineNoReturnMethod(function(hardReload) {
-    this._sendAsyncMsg('reload', {hardReload: hardReload});
-  }),
-
-  stop: defineNoReturnMethod(function() {
-    this._sendAsyncMsg('stop');
-  }),
-
-  /*
-   * The valid range of zoom scale is defined in preference "zoom.maxPercent" and "zoom.minPercent".
-   */
-  zoom: defineNoReturnMethod(function(zoom) {
-    zoom *= 100;
-    zoom = Math.min(getIntPref("zoom.maxPercent", 300), zoom);
-    zoom = Math.max(getIntPref("zoom.minPercent", 50), zoom);
-    this._sendAsyncMsg('zoom', {zoom: zoom / 100.0});
-  }),
-
-  purgeHistory: defineDOMRequestMethod('purge-history'),
-
-
-  download: function(_url, _options) {
-    if (!this._isAlive()) {
-      return null;
-    }
-    let ioService =
-      Cc['@mozilla.org/network/io-service;1'].getService(Ci.nsIIOService);
-    let uri = ioService.newURI(_url, null, null);
-    let url = uri.QueryInterface(Ci.nsIURL);
-
-    // Ensure we have _options, we always use it to send the filename.
-    _options = _options || {};
-    if (!_options.filename) {
-      _options.filename = url.fileName;
-    }
-
-    debug('_options = ' + uneval(_options));
-
-    // Ensure we have a filename.
-    if (!_options.filename) {
-      throw Components.Exception("Invalid argument", Cr.NS_ERROR_INVALID_ARG);
+  _observeRemoteBrowserFramePending: function(frameLoader) {
+    // Ignore notifications that aren't from a BrowserOrApp
+    if (!frameLoader.QueryInterface(Ci.nsIFrameLoader).ownerIsBrowserOrAppFrame) {
+      return;
     }
-
-    let interfaceRequestor =
-      this._frameLoader.loadContext.QueryInterface(Ci.nsIInterfaceRequestor);
-    let req = Services.DOMRequest.createRequest(this._window);
-
-    function DownloadListener() {
-      debug('DownloadListener Constructor');
-    }
-    DownloadListener.prototype = {
-      extListener: null,
-      onStartRequest: function(aRequest, aContext) {
-        debug('DownloadListener - onStartRequest');
-        let extHelperAppSvc =
-          Cc['@mozilla.org/uriloader/external-helper-app-service;1'].
-          getService(Ci.nsIExternalHelperAppService);
-        let channel = aRequest.QueryInterface(Ci.nsIChannel);
-
-        // First, we'll ensure the filename doesn't have any leading
-        // periods. We have to do it here to avoid ending up with a filename
-        // that's only an extension with no extension (e.g. Sending in
-        // '.jpeg' without stripping the '.' would result in a filename of
-        // 'jpeg' where we want 'jpeg.jpeg'.
-        _options.filename = _options.filename.replace(/^\.+/, "");
-
-        let ext = null;
-        let mimeSvc = extHelperAppSvc.QueryInterface(Ci.nsIMIMEService);
-        try {
-          ext = '.' + mimeSvc.getPrimaryExtension(channel.contentType, '');
-        } catch (e) { ext = null; }
-
-        // Check if we need to add an extension to the filename.
-        if (ext && !_options.filename.endsWith(ext)) {
-          _options.filename += ext;
-        }
-        // Set the filename to use when saving to disk.
-        channel.contentDispositionFilename = _options.filename;
-
-        this.extListener =
-          extHelperAppSvc.doContent(
-              channel.contentType,
-              aRequest,
-              interfaceRequestor,
-              true);
-        this.extListener.onStartRequest(aRequest, aContext);
-      },
-      onStopRequest: function(aRequest, aContext, aStatusCode) {
-        debug('DownloadListener - onStopRequest (aStatusCode = ' +
-               aStatusCode + ')');
-        if (aStatusCode == Cr.NS_OK) {
-          // Everything looks great.
-          debug('DownloadListener - Download Successful.');
-          Services.DOMRequest.fireSuccess(req, aStatusCode);
-        }
-        else {
-          // In case of failure, we'll simply return the failure status code.
-          debug('DownloadListener - Download Failed!');
-          Services.DOMRequest.fireError(req, aStatusCode);
-        }
-
-        if (this.extListener) {
-          this.extListener.onStopRequest(aRequest, aContext, aStatusCode);
-        }
-      },
-      onDataAvailable: function(aRequest, aContext, aInputStream,
-                                aOffset, aCount) {
-        this.extListener.onDataAvailable(aRequest, aContext, aInputStream,
-                                         aOffset, aCount);
-      },
-      QueryInterface: XPCOMUtils.generateQI([Ci.nsIStreamListener,
-                                             Ci.nsIRequestObserver])
-    };
-
-    let channel = ioService.newChannelFromURI(url);
-
-    // XXX We would set private browsing information prior to calling this.
-    channel.notificationCallbacks = interfaceRequestor;
-
-    // Since we're downloading our own local copy we'll want to bypass the
-    // cache and local cache if the channel let's us specify this.
-    let flags = Ci.nsIChannel.LOAD_CALL_CONTENT_SNIFFERS |
-                Ci.nsIChannel.LOAD_BYPASS_CACHE;
-    if (channel instanceof Ci.nsICachingChannel) {
-      debug('This is a caching channel. Forcing bypass.');
-      flags |= Ci.nsICachingChannel.LOAD_BYPASS_LOCAL_CACHE_IF_BUSY;
-    }
-
-    channel.loadFlags |= flags;
-
-    if (channel instanceof Ci.nsIHttpChannel) {
-      debug('Setting HTTP referrer = ' + this._window.document.documentURIObject);
-      channel.referrer = this._window.document.documentURIObject;
-      if (channel instanceof Ci.nsIHttpChannelInternal) {
-        channel.forceAllowThirdPartyCookie = true;
-      }
-    }
-
-    // Set-up complete, let's get things started.
-    channel.asyncOpen(new DownloadListener(), null);
-
-    return req;
+    debug("Remote browser frame shown " + frameLoader);
+    this._createBrowserElementParent(frameLoader,
+                                     /* hasRemoteFrame = */ true,
+                                     /* pending frame */ true);
   },
 
-  getScreenshot: function(_width, _height, _mimeType) {
-    if (!this._isAlive()) {
-      throw Components.Exception("Dead content process",
-                                 Cr.NS_ERROR_DOM_INVALID_STATE_ERR);
-    }
-
-    let width = parseInt(_width);
-    let height = parseInt(_height);
-    let mimeType = (typeof _mimeType === 'string') ?
-      _mimeType.trim().toLowerCase() : 'image/jpeg';
-    if (isNaN(width) || isNaN(height) || width < 0 || height < 0) {
-      throw Components.Exception("Invalid argument",
-                                 Cr.NS_ERROR_INVALID_ARG);
-    }
-
-    return this._sendDOMRequest('get-screenshot',
-                                {width: width, height: height,
-                                 mimeType: mimeType});
-  },
-
-  _recvNextPaint: function(data) {
-    let listeners = this._nextPaintListeners;
-    this._nextPaintListeners = [];
-    for (let listener of listeners) {
-      try {
-        listener.recvNextPaint();
-      } catch (e) {
-        // If a listener throws we'll continue.
-      }
-    }
-  },
-
-  addNextPaintListener: function(listener) {
-    if (!this._isAlive()) {
-      throw Components.Exception("Dead content process",
-                                 Cr.NS_ERROR_DOM_INVALID_STATE_ERR);
-    }
-
-    let self = this;
-    let run = function() {
-      if (self._nextPaintListeners.push(listener) == 1)
-        self._sendAsyncMsg('activate-next-paint-listener');
-    };
-    if (!this._domRequestReady) {
-      this._pendingAPICalls.push(run);
-    } else {
-      run();
-    }
-  },
-
-  removeNextPaintListener: function(listener) {
-    if (!this._isAlive()) {
-      throw Components.Exception("Dead content process",
-                                 Cr.NS_ERROR_DOM_INVALID_STATE_ERR);
-    }
-
-    let self = this;
-    let run = function() {
-      for (let i = self._nextPaintListeners.length - 1; i >= 0; i--) {
-        if (self._nextPaintListeners[i] == listener) {
-          self._nextPaintListeners.splice(i, 1);
-          break;
-        }
-      }
-
-      if (self._nextPaintListeners.length == 0)
-        self._sendAsyncMsg('deactivate-next-paint-listener');
-    };
-    if (!this._domRequestReady) {
-      this._pendingAPICalls.push(run);
-    } else {
-      run();
-    }
-  },
-
-  setInputMethodActive: function(isActive) {
-    if (!this._isAlive()) {
-      throw Components.Exception("Dead content process",
-                                 Cr.NS_ERROR_DOM_INVALID_STATE_ERR);
-    }
-
-    if (typeof isActive !== 'boolean') {
-      throw Components.Exception("Invalid argument",
-                                 Cr.NS_ERROR_INVALID_ARG);
-    }
-
-    return this._sendDOMRequest('set-input-method-active',
-                                {isActive: isActive});
-  },
-
-  /**
-   * Called when the visibility of the window which owns this iframe changes.
-   */
-  _ownerVisibilityChange: function() {
-    this._sendAsyncMsg('owner-visibility-change',
-                       {visible: !this._window.document.hidden});
-  },
-
-  /*
-   * Called when the child notices that its visibility has changed.
-   *
-   * This is sometimes redundant; for example, the child's visibility may
-   * change in response to a setVisible request that we made here!  But it's
-   * not always redundant; for example, the child's visibility may change in
-   * response to its parent docshell being hidden.
-   */
-  _childVisibilityChange: function(data) {
-    debug("_childVisibilityChange(" + data.json.visible + ")");
-    this._frameLoader.visible = data.json.visible;
-
-    this._fireEventFromMsg(data);
-  },
-
-  _exitFullscreen: function() {
-    this._windowUtils.exitFullscreen();
-  },
-
-  _remoteFullscreenOriginChange: function(data) {
-    let origin = data.json._payload_;
-    this._windowUtils.remoteFrameFullscreenChanged(this._frameElement, origin);
-  },
-
-  _remoteFrameFullscreenReverted: function(data) {
-    this._windowUtils.remoteFrameFullscreenReverted();
-  },
-
-  _fireFatalError: function() {
-    let evt = this._createEvent('error', {type: 'fatal'},
-                                /* cancelable = */ false);
-    this._frameElement.dispatchEvent(evt);
+  _createBrowserElementParent: function(frameLoader, hasRemoteFrame, isPendingFrame) {
+    let frameElement = frameLoader.QueryInterface(Ci.nsIFrameLoader).ownerElement;
+    this._bepMap.set(frameElement, BrowserElementParentBuilder.create(
+      frameLoader, hasRemoteFrame, isPendingFrame));
   },
 
   observe: function(subject, topic, data) {
     switch(topic) {
-    case 'oop-frameloader-crashed':
-      if (this._isAlive() && subject == this._frameLoader) {
-        this._fireFatalError();
+    case 'app-startup':
+      this._init();
+      break;
+    case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID:
+      if (data == BROWSER_FRAMES_ENABLED_PREF) {
+        this._init();
       }
       break;
-    case 'ask-children-to-exit-fullscreen':
-      if (this._isAlive() &&
-          this._frameElement.ownerDocument == subject &&
-          this._frameLoader.QueryInterface(Ci.nsIFrameLoader).tabParent) {
-        this._sendAsyncMsg('exit-fullscreen');
-      }
+    case 'remote-browser-pending':
+      this._observeRemoteBrowserFramePending(subject);
       break;
-    case 'copypaste-docommand':
-      if (this._isAlive() && this._frameElement.isEqualNode(subject.wrappedJSObject)) {
-        this._sendAsyncMsg('do-command', { command: data });
-      }
+    case 'inprocess-browser-shown':
+      this._observeInProcessBrowserFrameShown(subject);
       break;
-    default:
-      debug('Unknown topic: ' + topic);
-      break;
-    };
+    }
   },
 };
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([BrowserElementParent]);
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([BrowserElementParentFactory]);
copy from dom/browser-element/BrowserElementParent.js
copy to dom/browser-element/BrowserElementParent.jsm
--- a/dom/browser-element/BrowserElementParent.js
+++ b/dom/browser-element/BrowserElementParent.jsm
@@ -9,27 +9,31 @@ let Ci = Components.interfaces;
 let Cc = Components.classes;
 let Cr = Components.results;
 
 /* BrowserElementParent injects script to listen for certain events in the
  * child.  We then listen to messages from the child script and take
  * appropriate action here in the parent.
  */
 
+this.EXPORTED_SYMBOLS = ["BrowserElementParentBuilder"];
+
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/BrowserElementPromptService.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "DOMApplicationRegistry", function () {
   Cu.import("resource://gre/modules/Webapps.jsm");
   return DOMApplicationRegistry;
 });
 
+const TOUCH_EVENTS_ENABLED_PREF = "dom.w3c_touch_events.enabled";
+
 function debug(msg) {
-  //dump("BrowserElementParent - " + msg + "\n");
+  //dump("BrowserElementParent.jsm - " + msg + "\n");
 }
 
 function getIntPref(prefName, def) {
   try {
     return Services.prefs.getIntPref(prefName);
   }
   catch(err) {
     return def;
@@ -50,93 +54,148 @@ function visibilityChangeHandler(e) {
     return;
   }
 
   for (let i = 0; i < beps.length; i++) {
     beps[i]._ownerVisibilityChange();
   }
 }
 
-function defineNoReturnMethod(fn) {
-  return function method() {
-    if (!this._domRequestReady) {
-      // Remote browser haven't been created, we just queue the API call.
-      let args = Array.slice(arguments);
-      args.unshift(this);
-      this._pendingAPICalls.push(method.bind.apply(fn, args));
-      return;
-    }
-    if (this._isAlive()) {
-      fn.apply(this, arguments);
-    }
-  };
+this.BrowserElementParentBuilder = {
+  create: function create(frameLoader, hasRemoteFrame, isPendingFrame) {
+    return new BrowserElementParent(frameLoader, hasRemoteFrame);
+  }
 }
 
-function defineDOMRequestMethod(msgName) {
-  return function() {
-    return this._sendDOMRequest(msgName);
-  };
-}
-
-function BrowserElementParent() {
-  debug("Creating new BrowserElementParent object");
+function BrowserElementParent(frameLoader, hasRemoteFrame, isPendingFrame) {
+  debug("Creating new BrowserElementParent object for " + frameLoader);
   this._domRequestCounter = 0;
   this._domRequestReady = false;
   this._pendingAPICalls = [];
   this._pendingDOMRequests = {};
   this._pendingSetInputMethodActive = [];
+  this._hasRemoteFrame = hasRemoteFrame;
   this._nextPaintListeners = [];
 
+  this._frameLoader = frameLoader;
+  this._frameElement = frameLoader.QueryInterface(Ci.nsIFrameLoader).ownerElement;
+  let self = this;
+  if (!this._frameElement) {
+    debug("No frame element?");
+    return;
+  }
+
   Services.obs.addObserver(this, 'ask-children-to-exit-fullscreen', /* ownsWeak = */ true);
   Services.obs.addObserver(this, 'oop-frameloader-crashed', /* ownsWeak = */ true);
   Services.obs.addObserver(this, 'copypaste-docommand', /* ownsWeak = */ true);
+
+  let defineMethod = function(name, fn) {
+    XPCNativeWrapper.unwrap(self._frameElement)[name] = Cu.exportFunction(function() {
+      if (self._isAlive()) {
+        return fn.apply(self, arguments);
+      }
+    }, self._frameElement);
+  }
+
+  let defineNoReturnMethod = function(name, fn) {
+    XPCNativeWrapper.unwrap(self._frameElement)[name] = Cu.exportFunction(function method() {
+      if (!self._domRequestReady) {
+        // Remote browser haven't been created, we just queue the API call.
+        let args = Array.slice(arguments);
+        args.unshift(self);
+        self._pendingAPICalls.push(method.bind.apply(fn, args));
+        return;
+      }
+      if (self._isAlive()) {
+        fn.apply(self, arguments);
+      }
+    }, self._frameElement);
+  };
+
+  let defineDOMRequestMethod = function(domName, msgName) {
+    XPCNativeWrapper.unwrap(self._frameElement)[domName] = Cu.exportFunction(function() {
+      return self._sendDOMRequest(msgName);
+    }, self._frameElement);
+  }
+
+  // Define methods on the frame element.
+  defineNoReturnMethod('setVisible', this._setVisible);
+  defineDOMRequestMethod('getVisible', 'get-visible');
+
+  // Not expose security sensitive browser API for widgets
+  if (!this._frameLoader.QueryInterface(Ci.nsIFrameLoader).ownerIsWidget) {
+    defineNoReturnMethod('sendMouseEvent', this._sendMouseEvent);
+
+    // 0 = disabled, 1 = enabled, 2 - auto detect
+    if (getIntPref(TOUCH_EVENTS_ENABLED_PREF, 0) != 0) {
+      defineNoReturnMethod('sendTouchEvent', this._sendTouchEvent);
+    }
+    defineNoReturnMethod('goBack', this._goBack);
+    defineNoReturnMethod('goForward', this._goForward);
+    defineNoReturnMethod('reload', this._reload);
+    defineNoReturnMethod('stop', this._stop);
+    defineMethod('download', this._download);
+    defineDOMRequestMethod('purgeHistory', 'purge-history');
+    defineMethod('getScreenshot', this._getScreenshot);
+    defineNoReturnMethod('zoom', this._zoom);
+
+    defineDOMRequestMethod('getCanGoBack', 'get-can-go-back');
+    defineDOMRequestMethod('getCanGoForward', 'get-can-go-forward');
+    defineDOMRequestMethod('getContentDimensions', 'get-contentdimensions');
+  }
+
+  defineMethod('addNextPaintListener', this._addNextPaintListener);
+  defineMethod('removeNextPaintListener', this._removeNextPaintListener);
+  defineNoReturnMethod('setActive', this._setActive);
+  defineMethod('getActive', 'this._getActive');
+
+  let principal = this._frameElement.ownerDocument.nodePrincipal;
+  let perm = Services.perms
+             .testExactPermissionFromPrincipal(principal, "input-manage");
+  if (perm === Ci.nsIPermissionManager.ALLOW_ACTION) {
+    defineMethod('setInputMethodActive', this._setInputMethodActive);
+  }
+
+  // Listen to visibilitychange on the iframe's owner window, and forward
+  // changes down to the child.  We want to do this while registering as few
+  // visibilitychange listeners on _window as possible, because such a listener
+  // may live longer than this BrowserElementParent object.
+  //
+  // To accomplish this, we register just one listener on the window, and have
+  // it reference a WeakMap whose keys are all the BrowserElementParent objects
+  // on the window.  Then when the listener fires, we iterate over the
+  // WeakMap's keys (which we can do, because we're chrome) to notify the
+  // BrowserElementParents.
+  if (!this._window._browserElementParents) {
+    this._window._browserElementParents = new WeakMap();
+    this._window.addEventListener('visibilitychange',
+                                  visibilityChangeHandler,
+                                  /* useCapture = */ false,
+                                  /* wantsUntrusted = */ false);
+  }
+
+  this._window._browserElementParents.set(this, null);
+
+  // Insert ourself into the prompt service.
+  BrowserElementPromptService.mapFrameToBrowserElementParent(this._frameElement, this);
+  if (!isPendingFrame) {
+    this._setupMessageListener();
+    this._registerAppManifest();
+  } else {
+    // if we are a pending frame, we setup message manager after
+    // observing remote-browser-frame-shown
+    Services.obs.addObserver(this, 'remote-browser-frame-shown', /* ownsWeak = */ true);
+  }
 }
 
 BrowserElementParent.prototype = {
 
-  classDescription: "BrowserElementAPI implementation",
-  classID: Components.ID("{9f171ac4-0939-4ef8-b360-3408aedc3060}"),
-  contractID: "@mozilla.org/dom/browser-element-api;1",
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIBrowserElementAPI,
-                                         Ci.nsIObserver,
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
                                          Ci.nsISupportsWeakReference]),
 
-  setFrameLoader: function(frameLoader) {
-    this._frameLoader = frameLoader;
-    this._frameElement = frameLoader.QueryInterface(Ci.nsIFrameLoader).ownerElement;
-    if (!this._frameElement) {
-      debug("No frame element?");
-      return;
-    }
-    // Listen to visibilitychange on the iframe's owner window, and forward
-    // changes down to the child.  We want to do this while registering as few
-    // visibilitychange listeners on _window as possible, because such a listener
-    // may live longer than this BrowserElementParent object.
-    //
-    // To accomplish this, we register just one listener on the window, and have
-    // it reference a WeakMap whose keys are all the BrowserElementParent objects
-    // on the window.  Then when the listener fires, we iterate over the
-    // WeakMap's keys (which we can do, because we're chrome) to notify the
-    // BrowserElementParents.
-    if (!this._window._browserElementParents) {
-      this._window._browserElementParents = new WeakMap();
-      this._window.addEventListener('visibilitychange',
-                                    visibilityChangeHandler,
-                                    /* useCapture = */ false,
-                                    /* wantsUntrusted = */ false);
-    }
-
-    this._window._browserElementParents.set(this, null);
-
-    // Insert ourself into the prompt service.
-    BrowserElementPromptService.mapFrameToBrowserElementParent(this._frameElement, this);
-    this._setupMessageListener();
-    this._registerAppManifest();
-  },
-
   _runPendingAPICall: function() {
     if (!this._pendingAPICalls) {
       return;
     }
     for (let i = 0; i < this._pendingAPICalls.length; i++) {
       try {
         this._pendingAPICalls[i]();
       } catch (e) {
@@ -528,50 +587,43 @@ BrowserElementParent.prototype = {
     }
     else {
       debug("Got error in gotDOMRequestResult.");
       Services.DOMRequest.fireErrorAsync(req,
         Cu.cloneInto(data.json.errorMsg, this._window));
     }
   },
 
-  setVisible: defineNoReturnMethod(function(visible) {
+  _setVisible: function(visible) {
     this._sendAsyncMsg('set-visible', {visible: visible});
     this._frameLoader.visible = visible;
-  }),
+  },
 
-  getVisible: defineDOMRequestMethod('get-visible'),
-
-  setActive: defineNoReturnMethod(function(active) {
+  _setActive: function(active) {
     this._frameLoader.visible = active;
-  }),
+  },
 
-  getActive: function() {
-    if (!this._isAlive()) {
-      throw Components.Exception("Dead content process",
-                                 Cr.NS_ERROR_DOM_INVALID_STATE_ERR);
-    }
-
+  _getActive: function() {
     return this._frameLoader.visible;
   },
 
-  sendMouseEvent: defineNoReturnMethod(function(type, x, y, button, clickCount, modifiers) {
+  _sendMouseEvent: function(type, x, y, button, clickCount, modifiers) {
     this._sendAsyncMsg("send-mouse-event", {
       "type": type,
       "x": x,
       "y": y,
       "button": button,
       "clickCount": clickCount,
       "modifiers": modifiers
     });
-  }),
+  },
 
-  sendTouchEvent: defineNoReturnMethod(function(type, identifiers, touchesX, touchesY,
-                                                radiisX, radiisY, rotationAngles, forces,
-                                                count, modifiers) {
+  _sendTouchEvent: function(type, identifiers, touchesX, touchesY,
+                            radiisX, radiisY, rotationAngles, forces,
+                            count, modifiers) {
 
     let tabParent = this._frameLoader.tabParent;
     if (tabParent && tabParent.useAsyncPanZoom) {
       tabParent.injectTouchEvent(type,
                                  identifiers,
                                  touchesX,
                                  touchesY,
                                  radiisX,
@@ -589,55 +641,45 @@ BrowserElementParent.prototype = {
         "radiisX": radiisX,
         "radiisY": radiisY,
         "rotationAngles": rotationAngles,
         "forces": forces,
         "count": count,
         "modifiers": modifiers
       });
     }
-  }),
+  },
 
-  getCanGoBack: defineDOMRequestMethod('get-can-go-back'),
-  getCanGoForward: defineDOMRequestMethod('get-can-go-forward'),
-  getContentDimensions: defineDOMRequestMethod('get-contentdimensions'),
-
-  goBack: defineNoReturnMethod(function() {
+  _goBack: function() {
     this._sendAsyncMsg('go-back');
-  }),
+  },
 
-  goForward: defineNoReturnMethod(function() {
+  _goForward: function() {
     this._sendAsyncMsg('go-forward');
-  }),
+  },
 
-  reload: defineNoReturnMethod(function(hardReload) {
+  _reload: function(hardReload) {
     this._sendAsyncMsg('reload', {hardReload: hardReload});
-  }),
+  },
 
-  stop: defineNoReturnMethod(function() {
+  _stop: function() {
     this._sendAsyncMsg('stop');
-  }),
+  },
 
   /*
    * The valid range of zoom scale is defined in preference "zoom.maxPercent" and "zoom.minPercent".
    */
-  zoom: defineNoReturnMethod(function(zoom) {
+  _zoom: function(zoom) {
     zoom *= 100;
     zoom = Math.min(getIntPref("zoom.maxPercent", 300), zoom);
     zoom = Math.max(getIntPref("zoom.minPercent", 50), zoom);
     this._sendAsyncMsg('zoom', {zoom: zoom / 100.0});
-  }),
-
-  purgeHistory: defineDOMRequestMethod('purge-history'),
-
+  },
 
-  download: function(_url, _options) {
-    if (!this._isAlive()) {
-      return null;
-    }
+  _download: function(_url, _options) {
     let ioService =
       Cc['@mozilla.org/network/io-service;1'].getService(Ci.nsIIOService);
     let uri = ioService.newURI(_url, null, null);
     let url = uri.QueryInterface(Ci.nsIURL);
 
     // Ensure we have _options, we always use it to send the filename.
     _options = _options || {};
     if (!_options.filename) {
@@ -713,17 +755,17 @@ BrowserElementParent.prototype = {
           this.extListener.onStopRequest(aRequest, aContext, aStatusCode);
         }
       },
       onDataAvailable: function(aRequest, aContext, aInputStream,
                                 aOffset, aCount) {
         this.extListener.onDataAvailable(aRequest, aContext, aInputStream,
                                          aOffset, aCount);
       },
-      QueryInterface: XPCOMUtils.generateQI([Ci.nsIStreamListener,
+      QueryInterface: XPCOMUtils.generateQI([Ci.nsIStreamListener, 
                                              Ci.nsIRequestObserver])
     };
 
     let channel = ioService.newChannelFromURI(url);
 
     // XXX We would set private browsing information prior to calling this.
     channel.notificationCallbacks = interfaceRequestor;
 
@@ -747,22 +789,17 @@ BrowserElementParent.prototype = {
     }
 
     // Set-up complete, let's get things started.
     channel.asyncOpen(new DownloadListener(), null);
 
     return req;
   },
 
-  getScreenshot: function(_width, _height, _mimeType) {
-    if (!this._isAlive()) {
-      throw Components.Exception("Dead content process",
-                                 Cr.NS_ERROR_DOM_INVALID_STATE_ERR);
-    }
-
+  _getScreenshot: function(_width, _height, _mimeType) {
     let width = parseInt(_width);
     let height = parseInt(_height);
     let mimeType = (typeof _mimeType === 'string') ?
       _mimeType.trim().toLowerCase() : 'image/jpeg';
     if (isNaN(width) || isNaN(height) || width < 0 || height < 0) {
       throw Components.Exception("Invalid argument",
                                  Cr.NS_ERROR_INVALID_ARG);
     }
@@ -772,46 +809,42 @@ BrowserElementParent.prototype = {
                                  mimeType: mimeType});
   },
 
   _recvNextPaint: function(data) {
     let listeners = this._nextPaintListeners;
     this._nextPaintListeners = [];
     for (let listener of listeners) {
       try {
-        listener.recvNextPaint();
+        listener();
       } catch (e) {
         // If a listener throws we'll continue.
       }
     }
   },
 
-  addNextPaintListener: function(listener) {
-    if (!this._isAlive()) {
-      throw Components.Exception("Dead content process",
-                                 Cr.NS_ERROR_DOM_INVALID_STATE_ERR);
-    }
+  _addNextPaintListener: function(listener) {
+    if (typeof listener != 'function')
+      throw Components.Exception("Invalid argument", Cr.NS_ERROR_INVALID_ARG);
 
     let self = this;
     let run = function() {
       if (self._nextPaintListeners.push(listener) == 1)
         self._sendAsyncMsg('activate-next-paint-listener');
     };
     if (!this._domRequestReady) {
       this._pendingAPICalls.push(run);
     } else {
       run();
     }
   },
 
-  removeNextPaintListener: function(listener) {
-    if (!this._isAlive()) {
-      throw Components.Exception("Dead content process",
-                                 Cr.NS_ERROR_DOM_INVALID_STATE_ERR);
-    }
+  _removeNextPaintListener: function(listener) {
+    if (typeof listener != 'function')
+      throw Components.Exception("Invalid argument", Cr.NS_ERROR_INVALID_ARG);
 
     let self = this;
     let run = function() {
       for (let i = self._nextPaintListeners.length - 1; i >= 0; i--) {
         if (self._nextPaintListeners[i] == listener) {
           self._nextPaintListeners.splice(i, 1);
           break;
         }
@@ -822,22 +855,17 @@ BrowserElementParent.prototype = {
     };
     if (!this._domRequestReady) {
       this._pendingAPICalls.push(run);
     } else {
       run();
     }
   },
 
-  setInputMethodActive: function(isActive) {
-    if (!this._isAlive()) {
-      throw Components.Exception("Dead content process",
-                                 Cr.NS_ERROR_DOM_INVALID_STATE_ERR);
-    }
-
+  _setInputMethodActive: function(isActive) {
     if (typeof isActive !== 'boolean') {
       throw Components.Exception("Invalid argument",
                                  Cr.NS_ERROR_INVALID_ARG);
     }
 
     return this._sendDOMRequest('set-input-method-active',
                                 {isActive: isActive});
   },
@@ -889,25 +917,31 @@ BrowserElementParent.prototype = {
     case 'oop-frameloader-crashed':
       if (this._isAlive() && subject == this._frameLoader) {
         this._fireFatalError();
       }
       break;
     case 'ask-children-to-exit-fullscreen':
       if (this._isAlive() &&
           this._frameElement.ownerDocument == subject &&
-          this._frameLoader.QueryInterface(Ci.nsIFrameLoader).tabParent) {
+          this._hasRemoteFrame) {
         this._sendAsyncMsg('exit-fullscreen');
       }
       break;
+    case 'remote-browser-frame-shown':
+      if (this._frameLoader == subject) {
+        if (!this._mm) {
+          this._setupMessageListener();
+          this._registerAppManifest();
+        }
+        Services.obs.removeObserver(this, 'remote-browser-frame-shown');
+      }
     case 'copypaste-docommand':
       if (this._isAlive() && this._frameElement.isEqualNode(subject.wrappedJSObject)) {
         this._sendAsyncMsg('do-command', { command: data });
       }
       break;
     default:
       debug('Unknown topic: ' + topic);
       break;
     };
   },
 };
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([BrowserElementParent]);
--- a/dom/browser-element/BrowserElementParent.manifest
+++ b/dom/browser-element/BrowserElementParent.manifest
@@ -1,2 +1,3 @@
-component {9f171ac4-0939-4ef8-b360-3408aedc3060} BrowserElementParent.js
-contract @mozilla.org/dom/browser-element-api;1 {9f171ac4-0939-4ef8-b360-3408aedc3060}
+component {ddeafdac-cb39-47c4-9cb8-c9027ee36d26} BrowserElementParent.js
+contract @mozilla.org/browser-element-parent-factory;1 {ddeafdac-cb39-47c4-9cb8-c9027ee36d26}
+category app-startup BrowserElementParentFactory service,@mozilla.org/browser-element-parent-factory;1
--- a/dom/browser-element/moz.build
+++ b/dom/browser-element/moz.build
@@ -7,28 +7,23 @@
 EXPORTS.mozilla += [
     'BrowserElementParent.h',
 ]
 
 SOURCES += [
     'BrowserElementParent.cpp',
 ]
 
-XPIDL_SOURCES += [
-    'nsIBrowserElementAPI.idl',
-]
-
-XPIDL_MODULE = 'browser-element'
-
 EXTRA_COMPONENTS += [
     'BrowserElementParent.js',
     'BrowserElementParent.manifest',
 ]
 
 EXTRA_JS_MODULES += [
+    'BrowserElementParent.jsm',
     'BrowserElementPromptService.jsm',
 ]
 
 FAIL_ON_WARNINGS = True
 
 LOCAL_INCLUDES += [
     '../bluetooth',
     '/dom/html',
deleted file mode 100644
--- a/dom/browser-element/nsIBrowserElementAPI.idl
+++ /dev/null
@@ -1,74 +0,0 @@
-/* -*- Mode: IDL; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsISupports.idl"
-
-interface nsIDOMDOMRequest;
-interface nsIFrameLoader;
-
-[scriptable, function, uuid(c0c2dd9b-41ef-42dd-a4c1-e456619c1941)]
-interface nsIBrowserElementNextPaintListener : nsISupports
-{
-  void recvNextPaint();
-};
-
-%{C++
-#define BROWSER_ELEMENT_API_CONTRACTID "@mozilla.org/dom/browser-element-api;1"
-#define BROWSER_ELEMENT_API_CID                                 \
-    { 0x651db7e3, 0x1734, 0x4536,                               \
-      { 0xb1, 0x5a, 0x5b, 0x3a, 0xe6, 0x44, 0x13, 0x4c } }
-%}
-
-/**
- * Interface to the BrowserElementParent implementation. All methods
- * but setFrameLoader throw when the remote process is dead.
- */
-[scriptable, uuid(abae4fb1-7d6f-4e3f-b435-6501f1d4c659)]
-interface nsIBrowserElementAPI : nsISupports
-{
-  void setFrameLoader(in nsIFrameLoader frameLoader);
-
-  void setVisible(in boolean visible);
-  nsIDOMDOMRequest getVisible();
-  void setActive(in boolean active);
-  boolean getActive();
-
-  void sendMouseEvent(in DOMString type,
-                      in uint32_t x,
-                      in uint32_t y,
-                      in uint32_t button,
-                      in uint32_t clickCount,
-                      in uint32_t mifiers);
-  void sendTouchEvent(in DOMString aType,
-                      [const, array, size_is(count)] in uint32_t aIdentifiers,
-                      [const, array, size_is(count)] in int32_t aXs,
-                      [const, array, size_is(count)] in int32_t aYs,
-                      [const, array, size_is(count)] in uint32_t aRxs,
-                      [const, array, size_is(count)] in uint32_t aRys,
-                      [const, array, size_is(count)] in float aRotationAngles,
-                      [const, array, size_is(count)] in float aForces,
-                      in uint32_t count,
-                      in long aModifiers);
-  void goBack();
-  void goForward();
-  void reload(in boolean hardReload);
-  void stop();
-  nsIDOMDOMRequest download(in DOMString url,
-                            [optional] in jsval options);
-  nsIDOMDOMRequest purgeHistory();
-  nsIDOMDOMRequest getScreenshot(in uint32_t width,
-                                 in uint32_t height,
-                                 [optional] in DOMString mimeType);
-  void zoom(in float zoom);
-  nsIDOMDOMRequest getCanGoBack();
-  nsIDOMDOMRequest getCanGoForward();
-  nsIDOMDOMRequest getContentDimensions();
-
-  void addNextPaintListener(in nsIBrowserElementNextPaintListener listener);
-  void removeNextPaintListener(in nsIBrowserElementNextPaintListener listener);
-
-  nsIDOMDOMRequest setInputMethodActive(in boolean isActive);
-};
--- a/dom/canvas/WebGL1Context.cpp
+++ b/dom/canvas/WebGL1Context.cpp
@@ -1,50 +1,51 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WebGL1Context.h"
+
 #include "mozilla/dom/WebGLRenderingContextBinding.h"
-
 #include "mozilla/Telemetry.h"
 
-using namespace mozilla;
+namespace mozilla {
 
-// -----------------------------------------------------------------------------
-// CONSTRUCTOR & DESTRUCTOR
+/*static*/ WebGL1Context*
+WebGL1Context::Create()
+{
+    return new WebGL1Context();
+}
 
 WebGL1Context::WebGL1Context()
     : WebGLContext()
 {
-
 }
 
 WebGL1Context::~WebGL1Context()
 {
-
 }
 
-
-// -----------------------------------------------------------------------------
-// IMPLEMENT nsWrapperCache
+////////////////////////////////////////
+// nsWrapperCache
 
 JSObject*
-WebGL1Context::WrapObject(JSContext *cx)
+WebGL1Context::WrapObject(JSContext* cx)
 {
     return dom::WebGLRenderingContextBinding::Wrap(cx, this);
 }
 
+} // namespace mozilla
 
-// -----------------------------------------------------------------------------
-// INSTANCING nsIDOMWebGLRenderingContext
+////////////////////////////////////////
+// nsIDOMWebGLRenderingContext
 
 nsresult
-NS_NewCanvasRenderingContextWebGL(nsIDOMWebGLRenderingContext** aResult)
+NS_NewCanvasRenderingContextWebGL(nsIDOMWebGLRenderingContext** out_result)
 {
-    Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1);
-    nsIDOMWebGLRenderingContext* ctx = new WebGL1Context();
+    mozilla::Telemetry::Accumulate(mozilla::Telemetry::CANVAS_WEBGL_USED, 1);
 
-    NS_ADDREF(*aResult = ctx);
+    nsIDOMWebGLRenderingContext* ctx = mozilla::WebGL1Context::Create();
+
+    NS_ADDREF(*out_result = ctx);
     return NS_OK;
 }
-
--- a/dom/canvas/WebGL1Context.h
+++ b/dom/canvas/WebGL1Context.h
@@ -1,46 +1,35 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef WEBGL1CONTEXT_H_
-#define WEBGL1CONTEXT_H_
+#ifndef WEBGL_1_CONTEXT_H_
+#define WEBGL_1_CONTEXT_H_
 
 #include "WebGLContext.h"
 
 namespace mozilla {
 
 class WebGL1Context
     : public WebGLContext
 {
-// -----------------------------------------------------------------------------
-// PUBLIC
 public:
+    static WebGL1Context* Create();
 
-    // -------------------------------------------------------------------------
-    // CONSTRUCTOR & DESTRUCTOR
+private:
+    WebGL1Context();
 
-    WebGL1Context();
+public:
     virtual ~WebGL1Context();
 
-
-    // -------------------------------------------------------------------------
-    // IMPLEMENT WebGLContext
-
-    virtual bool IsWebGL2() const MOZ_OVERRIDE
-    {
+    virtual bool IsWebGL2() const MOZ_OVERRIDE {
         return false;
     }
 
-
-    // -------------------------------------------------------------------------
-    // IMPLEMENT nsWrapperCache
-
-    virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE;
-
-
+    // nsWrapperCache
+    virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE;
 };
 
 } // namespace mozilla
 
-#endif
+#endif // WEBGL_1_CONTEXT_H_
--- a/dom/canvas/WebGL2ContextSamplers.cpp
+++ b/dom/canvas/WebGL2ContextSamplers.cpp
@@ -1,78 +1,218 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WebGL2Context.h"
+#include "WebGLSampler.h"
 #include "GLContext.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 already_AddRefed<WebGLSampler>
 WebGL2Context::CreateSampler()
 {
-    MOZ_CRASH("Not Implemented.");
-    return nullptr;
+    if (IsContextLost())
+        return nullptr;
+
+    GLuint sampler;
+    MakeContextCurrent();
+    gl->fGenSamplers(1, &sampler);
+
+    nsRefPtr<WebGLSampler> globj = new WebGLSampler(this, sampler);
+    return globj.forget();
 }
 
 void
 WebGL2Context::DeleteSampler(WebGLSampler* sampler)
 {
-    MOZ_CRASH("Not Implemented.");
+    if (IsContextLost())
+        return;
+
+    if (!ValidateObjectAllowDeletedOrNull("deleteSampler", sampler))
+        return;
+
+    if (!sampler || sampler->IsDeleted())
+        return;
+
+    sampler->RequestDelete();
 }
 
 bool
 WebGL2Context::IsSampler(WebGLSampler* sampler)
 {
-    MOZ_CRASH("Not Implemented.");
-    return false;
+    if (IsContextLost())
+        return false;
+
+    if (!sampler)
+        return false;
+
+    if (!ValidateObjectAllowDeleted("isSampler", sampler))
+        return false;
+
+    if (sampler->IsDeleted())
+        return false;
+
+    return !sampler->HasEverBeenBound();
 }
 
 void
 WebGL2Context::BindSampler(GLuint unit, WebGLSampler* sampler)
 {
-    MOZ_CRASH("Not Implemented.");
+    if (IsContextLost())
+        return;
+
+    if (!ValidateObjectAllowDeletedOrNull("bindSampler", sampler))
+        return;
+
+    if (GLint(unit) >= mGLMaxTextureUnits)
+        return ErrorInvalidValue("bindSampler: unit must be < %d", mGLMaxTextureUnits);
+
+    if (sampler && sampler->IsDeleted())
+        return ErrorInvalidOperation("bindSampler: binding deleted sampler");
+
+    WebGLContextUnchecked::BindSampler(unit, sampler);
 }
 
 void
 WebGL2Context::SamplerParameteri(WebGLSampler* sampler, GLenum pname, GLint param)
 {
-    MOZ_CRASH("Not Implemented.");
+    if (IsContextLost())
+        return;
+
+    if (!sampler || sampler->IsDeleted())
+        return ErrorInvalidOperation("samplerParameteri: invalid sampler");
+
+    if (!ValidateSamplerParameterParams(pname, WebGLIntOrFloat(param), "samplerParameteri"))
+        return;
+
+    WebGLContextUnchecked::SamplerParameteri(sampler, pname, param);
 }
 
 void
 WebGL2Context::SamplerParameteriv(WebGLSampler* sampler, GLenum pname, const dom::Int32Array& param)
 {
-    MOZ_CRASH("Not Implemented.");
+    if (IsContextLost())
+        return;
+
+    if (!sampler || sampler->IsDeleted())
+        return ErrorInvalidOperation("samplerParameteriv: invalid sampler");
+
+    param.ComputeLengthAndData();
+    if (param.Length() < 1)
+        return /* TODO(djg): Error message */;
+
+    /* TODO(djg): All of these calls in ES3 only take 1 param */
+    if (!ValidateSamplerParameterParams(pname, WebGLIntOrFloat(param.Data()[0]), "samplerParameteriv"))
+        return;
+
+    WebGLContextUnchecked::SamplerParameteriv(sampler, pname, param.Data());
 }
 
 void
 WebGL2Context::SamplerParameteriv(WebGLSampler* sampler, GLenum pname, const dom::Sequence<GLint>& param)
 {
-    MOZ_CRASH("Not Implemented.");
+    if (IsContextLost())
+        return;
+
+    if (!sampler || sampler->IsDeleted())
+        return ErrorInvalidOperation("samplerParameteriv: invalid sampler");
+
+    if (param.Length() < 1)
+        return /* TODO(djg): Error message */;
+
+    /* TODO(djg): All of these calls in ES3 only take 1 param */
+    if (!ValidateSamplerParameterParams(pname, WebGLIntOrFloat(param[0]), "samplerParameteriv"))
+        return;
+
+    WebGLContextUnchecked::SamplerParameteriv(sampler, pname, param.Elements());
 }
 
 void
 WebGL2Context::SamplerParameterf(WebGLSampler* sampler, GLenum pname, GLfloat param)
 {
-    MOZ_CRASH("Not Implemented.");
+    if (IsContextLost())
+        return;
+
+    if (!sampler || sampler->IsDeleted())
+        return ErrorInvalidOperation("samplerParameterf: invalid sampler");
+
+    if (!ValidateSamplerParameterParams(pname, WebGLIntOrFloat(param), "samplerParameterf"))
+        return;
+
+    WebGLContextUnchecked::SamplerParameterf(sampler, pname, param);
 }
 
 void
 WebGL2Context::SamplerParameterfv(WebGLSampler* sampler, GLenum pname, const dom::Float32Array& param)
 {
-    MOZ_CRASH("Not Implemented.");
+    if (IsContextLost())
+        return;
+
+    if (!sampler || sampler->IsDeleted())
+        return ErrorInvalidOperation("samplerParameterfv: invalid sampler");
+
+    param.ComputeLengthAndData();
+    if (param.Length() < 1)
+        return /* TODO(djg): Error message */;
+
+    /* TODO(djg): All of these calls in ES3 only take 1 param */
+    if (!ValidateSamplerParameterParams(pname, WebGLIntOrFloat(param.Data()[0]), "samplerParameterfv"))
+        return;
+
+    WebGLContextUnchecked::SamplerParameterfv(sampler, pname, param.Data());
 }
 
 void
 WebGL2Context::SamplerParameterfv(WebGLSampler* sampler, GLenum pname, const dom::Sequence<GLfloat>& param)
 {
-    MOZ_CRASH("Not Implemented.");
+    if (IsContextLost())
+        return;
+
+    if (!sampler || sampler->IsDeleted())
+        return ErrorInvalidOperation("samplerParameterfv: invalid sampler");
+
+    if (param.Length() < 1)
+        return /* TODO(djg): Error message */;
+
+    /* TODO(djg): All of these calls in ES3 only take 1 param */
+    if (!ValidateSamplerParameterParams(pname, WebGLIntOrFloat(param[0]), "samplerParameterfv"))
+        return;
+
+    WebGLContextUnchecked::SamplerParameterfv(sampler, pname, param.Elements());
 }
 
 void
 WebGL2Context::GetSamplerParameter(JSContext*, WebGLSampler* sampler, GLenum pname, JS::MutableHandleValue retval)
 {
-    MOZ_CRASH("Not Implemented.");
+    if (IsContextLost())
+        return;
+
+    if (!sampler || sampler->IsDeleted())
+        return ErrorInvalidOperation("getSamplerParameter: invalid sampler");
+
+    if (!ValidateSamplerParameterName(pname, "getSamplerParameter"))
+        return;
+
+    retval.set(JS::NullValue());
+
+    switch (pname) {
+    case LOCAL_GL_TEXTURE_MIN_FILTER:
+    case LOCAL_GL_TEXTURE_MAG_FILTER:
+    case LOCAL_GL_TEXTURE_WRAP_S:
+    case LOCAL_GL_TEXTURE_WRAP_T:
+    case LOCAL_GL_TEXTURE_WRAP_R:
+    case LOCAL_GL_TEXTURE_COMPARE_MODE:
+    case LOCAL_GL_TEXTURE_COMPARE_FUNC:
+        retval.set(JS::Int32Value(
+            WebGLContextUnchecked::GetSamplerParameteriv(sampler, pname)));
+        return;
+
+    case LOCAL_GL_TEXTURE_MIN_LOD:
+    case LOCAL_GL_TEXTURE_MAX_LOD:
+        retval.set(JS::Float32Value(
+            WebGLContextUnchecked::GetSamplerParameterfv(sampler, pname)));
+        return;
+    }
 }
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -2,25 +2,26 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WebGLContext.h"
 
 #include "WebGLContextLossHandler.h"
 #include "WebGL1Context.h"
-#include "WebGLObjectModel.h"
+#include "WebGLBuffer.h"
+#include "WebGLContextUtils.h"
 #include "WebGLExtensions.h"
-#include "WebGLContextUtils.h"
-#include "WebGLBuffer.h"
+#include "WebGLFramebuffer.h"
+#include "WebGLMemoryTracker.h"
+#include "WebGLObjectModel.h"
+#include "WebGLQuery.h"
+#include "WebGLSampler.h"
+#include "WebGLVertexArray.h"
 #include "WebGLVertexAttribData.h"
-#include "WebGLMemoryTracker.h"
-#include "WebGLFramebuffer.h"
-#include "WebGLVertexArray.h"
-#include "WebGLQuery.h"
 
 #include "GLBlitHelper.h"
 #include "AccessCheck.h"
 #include "nsIConsoleService.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIClassInfoImpl.h"
 #include "nsContentUtils.h"
 #include "nsIXPConnect.h"
@@ -221,17 +222,17 @@ WebGLContextOptions::WebGLContextOptions
       preserveDrawingBuffer(false)
 {
     // Set default alpha state based on preference.
     if (Preferences::GetBool("webgl.default-no-alpha", false))
         alpha = false;
 }
 
 WebGLContext::WebGLContext()
-    : gl(nullptr)
+    : WebGLContextUnchecked(nullptr)
     , mNeedsFakeNoAlpha(false)
 {
     mGeneration = 0;
     mInvalidated = false;
     mShouldPresent = true;
     mResetLayer = true;
     mOptionsFrozen = false;
 
@@ -366,16 +367,18 @@ WebGLContext::DestroyResourcesAndContext
     while (!mFramebuffers.isEmpty())
         mFramebuffers.getLast()->DeleteOnce();
     while (!mShaders.isEmpty())
         mShaders.getLast()->DeleteOnce();
     while (!mPrograms.isEmpty())
         mPrograms.getLast()->DeleteOnce();
     while (!mQueries.isEmpty())
         mQueries.getLast()->DeleteOnce();
+    while (!mSamplers.isEmpty())
+        mSamplers.getLast()->DeleteOnce();
 
     mBlackOpaqueTexture2D = nullptr;
     mBlackOpaqueTextureCubeMap = nullptr;
     mBlackTransparentTexture2D = nullptr;
     mBlackTransparentTextureCubeMap = nullptr;
 
     if (mFakeVertexAttrib0BufferObject) {
         gl->fDeleteBuffers(1, &mFakeVertexAttrib0BufferObject);
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -10,16 +10,17 @@
 #include "mozilla/CheckedInt.h"
 #include "mozilla/EnumeratedArray.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/WeakPtr.h"
 
 #include "GLDefs.h"
 #include "WebGLActiveInfo.h"
+#include "WebGLContextUnchecked.h"
 #include "WebGLObjectModel.h"
 #include "WebGLRenderbuffer.h"
 #include "WebGLTexture.h"
 #include "WebGLStrongTypes.h"
 #include <stdarg.h>
 
 #include "nsTArray.h"
 #include "nsCycleCollectionNoteChild.h"
@@ -73,20 +74,22 @@ class WebGLExtensionBase;
 class WebGLBuffer;
 struct WebGLVertexAttribData;
 class WebGLShader;
 class WebGLProgram;
 class WebGLQuery;
 class WebGLUniformLocation;
 class WebGLFramebuffer;
 class WebGLRenderbuffer;
+class WebGLSampler;
 class WebGLShaderPrecisionFormat;
 class WebGLTexture;
 class WebGLVertexArray;
 
+
 namespace dom {
 class ImageData;
 class Element;
 
 struct WebGLContextAttributes;
 template<typename> struct Nullable;
 }
 
@@ -122,20 +125,39 @@ struct WebGLContextOptions {
     bool premultipliedAlpha;
     bool antialias;
     bool preserveDrawingBuffer;
 };
 
 // From WebGLContextUtils
 TexTarget TexImageTargetToTexTarget(TexImageTarget texImageTarget);
 
+class WebGLIntOrFloat {
+    enum {
+        Int,
+        Float
+    } mType;
+    union {
+        GLint i;
+        GLfloat f;
+    } mValue;
+
+public:
+    explicit WebGLIntOrFloat(GLint i) : mType(Int) { mValue.i = i; }
+    explicit WebGLIntOrFloat(GLfloat f) : mType(Float) { mValue.f = f; }
+
+    GLint AsInt() const { return (mType == Int) ? mValue.i : NS_lroundf(mValue.f); }
+    GLfloat AsFloat() const { return (mType == Float) ? mValue.f : GLfloat(mValue.i); }
+};
+
 class WebGLContext :
     public nsIDOMWebGLRenderingContext,
     public nsICanvasRenderingContextInternal,
     public nsSupportsWeakReference,
+    public WebGLContextUnchecked,
     public WebGLRectangleObject,
     public nsWrapperCache,
     public SupportsWeakPtr<WebGLContext>
 {
     friend class WebGLContextUserData;
     friend class WebGLExtensionCompressedTextureATC;
     friend class WebGLExtensionCompressedTextureETC1;
     friend class WebGLExtensionCompressedTexturePVRTC;
@@ -1000,18 +1022,16 @@ protected:
 
     virtual JS::Value GetTexParameterInternal(const TexTarget& target, GLenum pname);
 
     // Returns x rounded to the next highest multiple of y.
     static CheckedUint32 RoundedToNextMultipleOf(CheckedUint32 x, CheckedUint32 y) {
         return ((x + y - 1) / y) * y;
     }
 
-    nsRefPtr<gl::GLContext> gl;
-
     CheckedUint32 mGeneration;
 
     WebGLContextOptions mOptions;
 
     bool mInvalidated;
     bool mResetLayer;
     bool mOptionsFrozen;
     bool mMinCapability;
@@ -1133,16 +1153,20 @@ protected:
 
     bool ValidateGLSLVariableName(const nsAString& name, const char *info);
     bool ValidateGLSLCharacter(char16_t c);
     bool ValidateGLSLString(const nsAString& string, const char *info);
 
     bool ValidateCopyTexImage(GLenum internalformat,
                               WebGLTexImageFunc func,
                               WebGLTexDimensions dims);
+
+    bool ValidateSamplerParameterName(GLenum pname, const char* info);
+    bool ValidateSamplerParameterParams(GLenum pname, const WebGLIntOrFloat& param, const char* info);
+
     bool ValidateTexImage(TexImageTarget texImageTarget,
                           GLint level, GLenum internalFormat,
                           GLint xoffset, GLint yoffset, GLint zoffset,
                           GLint width, GLint height, GLint depth,
                           GLint border, GLenum format, GLenum type,
                           WebGLTexImageFunc func,
                           WebGLTexDimensions dims);
     bool ValidateTexImageTarget(GLenum target,
@@ -1320,16 +1344,19 @@ protected:
     LinkedList<WebGLBuffer> mBuffers;
     LinkedList<WebGLProgram> mPrograms;
     LinkedList<WebGLQuery> mQueries;
     LinkedList<WebGLShader> mShaders;
     LinkedList<WebGLRenderbuffer> mRenderbuffers;
     LinkedList<WebGLFramebuffer> mFramebuffers;
     LinkedList<WebGLVertexArray> mVertexArrays;
 
+    // TODO(djg): Does this need a rethink? Should it be WebGL2Context?
+    LinkedList<WebGLSampler> mSamplers;
+
     WebGLRefPtr<WebGLVertexArray> mDefaultVertexArray;
 
     // PixelStore parameters
     uint32_t mPixelStorePackAlignment, mPixelStoreUnpackAlignment, mPixelStoreColorspaceConversion;
     bool mPixelStoreFlipY, mPixelStorePremultiplyAlpha;
 
     WebGLContextFakeBlackStatus mFakeBlackStatus;
 
@@ -1435,16 +1462,17 @@ public:
     void GenerateWarning(const char *fmt, va_list ap);
 
     friend class WebGLTexture;
     friend class WebGLFramebuffer;
     friend class WebGLRenderbuffer;
     friend class WebGLProgram;
     friend class WebGLQuery;
     friend class WebGLBuffer;
+    friend class WebGLSampler;
     friend class WebGLShader;
     friend class WebGLUniformLocation;
     friend class WebGLVertexArray;
     friend class WebGLVertexArrayFake;
     friend class WebGLVertexArrayGL;
 };
 
 // used by DOM bindings in conjunction with GetParentObject
new file mode 100644
--- /dev/null
+++ b/dom/canvas/WebGLContextUnchecked.cpp
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=4 et sw=4 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WebGLContextUnchecked.h"
+
+#include "GLContext.h"
+#include "WebGLSampler.h"
+
+namespace mozilla {
+
+WebGLContextUnchecked::WebGLContextUnchecked(gl::GLContext* gl)
+    : gl(gl)
+{ }
+
+
+// -----------------------------------------------------------------------------
+// Sampler Objects
+
+void
+WebGLContextUnchecked::BindSampler(GLuint unit, WebGLSampler* sampler)
+{
+    gl->MakeCurrent();
+    gl->fBindSampler(unit, sampler ? sampler->GLName() : 0);
+    if (sampler)
+        sampler->BindTo(LOCAL_GL_SAMPLER_BINDING);
+}
+
+GLint
+WebGLContextUnchecked::GetSamplerParameteriv(WebGLSampler* sampler,
+                                             GLenum pname)
+{
+    MOZ_ASSERT(sampler, "Did you validate?");
+
+    GLint param = 0;
+    gl->MakeCurrent();
+    gl->fGetSamplerParameteriv(sampler->GLName(), pname, &param);
+
+    return param;
+}
+
+GLfloat
+WebGLContextUnchecked::GetSamplerParameterfv(WebGLSampler* sampler,
+                                             GLenum pname)
+{
+    MOZ_ASSERT(sampler, "Did you validate?");
+
+    GLfloat param = 0.0f;
+    gl->MakeCurrent();
+    gl->fGetSamplerParameterfv(sampler->GLName(), pname, &param);
+    return param;
+}
+
+void
+WebGLContextUnchecked::SamplerParameteri(WebGLSampler* sampler,
+                                         GLenum pname,
+                                         GLint param)
+{
+    MOZ_ASSERT(sampler, "Did you validate?");
+    gl->MakeCurrent();
+    gl->fSamplerParameteri(sampler->GLName(), pname, param);
+}
+
+void
+WebGLContextUnchecked::SamplerParameteriv(WebGLSampler* sampler,
+                                          GLenum pname,
+                                          const GLint* param)
+{
+    MOZ_ASSERT(sampler, "Did you validate?");
+    gl->MakeCurrent();
+    gl->fSamplerParameteriv(sampler->GLName(), pname, param);
+}
+
+void
+WebGLContextUnchecked::SamplerParameterf(WebGLSampler* sampler,
+                                         GLenum pname,
+                                         GLfloat param)
+{
+    MOZ_ASSERT(sampler, "Did you validate?");
+    gl->MakeCurrent();
+    gl->fSamplerParameterf(sampler->GLName(), pname, param);
+}
+
+void
+WebGLContextUnchecked::SamplerParameterfv(WebGLSampler* sampler,
+                                          GLenum pname,
+                                          const GLfloat* param)
+{
+    MOZ_ASSERT(sampler, "Did you validate?");
+    gl->MakeCurrent();
+    gl->fSamplerParameterfv(sampler->GLName(), pname, param);
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/canvas/WebGLContextUnchecked.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=4 et sw=4 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef WEBGLCONTEXTUNCHECKED_H
+#define WEBGLCONTEXTUNCHECKED_H
+
+#include "GLDefs.h"
+#include "WebGLTypes.h"
+#include "nsAutoPtr.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+
+class WebGLSampler;
+namespace gl {
+    class GLContext;
+}
+
+class WebGLContextUnchecked
+{
+public:
+    explicit WebGLContextUnchecked(gl::GLContext* gl);
+
+    // -------------------------------------------------------------------------
+    // Sampler Objects
+    void BindSampler(GLuint unit, WebGLSampler* sampler);
+
+    GLint   GetSamplerParameteriv(WebGLSampler* sampler, GLenum pname);
+    GLfloat GetSamplerParameterfv(WebGLSampler* sampler, GLenum pname);
+
+    void SamplerParameteri(WebGLSampler* sampler, GLenum pname, GLint param);
+    void SamplerParameteriv(WebGLSampler* sampler, GLenum pname, const GLint* param);
+    void SamplerParameterf(WebGLSampler* sampler, GLenum pname, GLfloat param);
+    void SamplerParameterfv(WebGLSampler* sampler, GLenum pname, const GLfloat* param);
+
+protected: // data
+    nsRefPtr<gl::GLContext> gl;
+};
+
+} // namespace mozilla
+
+#endif // !WEBGLCONTEXTUNCHECKED_H
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -374,16 +374,128 @@ WebGLContext::ValidateFramebufferAttachm
         return true;
     }
 
     ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x.", funcName, attachment);
     return false;
 }
 
 /**
+ * Return true if pname is valid for GetSamplerParameter calls.
+ */
+bool
+WebGLContext::ValidateSamplerParameterName(GLenum pname, const char* info)
+{
+    switch (pname) {
+    case LOCAL_GL_TEXTURE_MIN_FILTER:
+    case LOCAL_GL_TEXTURE_MAG_FILTER:
+    case LOCAL_GL_TEXTURE_WRAP_S:
+    case LOCAL_GL_TEXTURE_WRAP_T:
+    case LOCAL_GL_TEXTURE_WRAP_R:
+    case LOCAL_GL_TEXTURE_MIN_LOD:
+    case LOCAL_GL_TEXTURE_MAX_LOD:
+    case LOCAL_GL_TEXTURE_COMPARE_MODE:
+    case LOCAL_GL_TEXTURE_COMPARE_FUNC:
+        return true;
+
+    default:
+        ErrorInvalidEnum("%s: invalid pname: %s", info, EnumName(pname));
+        return false;
+    }
+}
+
+/**
+ * Return true if pname and param are valid combination for SamplerParameter calls.
+ */
+bool
+WebGLContext::ValidateSamplerParameterParams(GLenum pname, const WebGLIntOrFloat& param, const char* info)
+{
+    const GLenum p = param.AsInt();
+
+    switch (pname) {
+    case LOCAL_GL_TEXTURE_MIN_FILTER:
+        switch (p) {
+        case LOCAL_GL_NEAREST:
+        case LOCAL_GL_LINEAR:
+        case LOCAL_GL_NEAREST_MIPMAP_NEAREST:
+        case LOCAL_GL_NEAREST_MIPMAP_LINEAR:
+        case LOCAL_GL_LINEAR_MIPMAP_NEAREST:
+        case LOCAL_GL_LINEAR_MIPMAP_LINEAR:
+            return true;
+
+        default:
+            ErrorInvalidEnum("%s: invalid param: %s", info, EnumName(p));
+            return false;
+        }
+
+    case LOCAL_GL_TEXTURE_MAG_FILTER:
+        switch (p) {
+        case LOCAL_GL_NEAREST:
+        case LOCAL_GL_LINEAR:
+            return true;
+
+        default:
+            ErrorInvalidEnum("%s: invalid param: %s", info, EnumName(p));
+            return false;
+        }
+
+    case LOCAL_GL_TEXTURE_WRAP_S:
+    case LOCAL_GL_TEXTURE_WRAP_T:
+    case LOCAL_GL_TEXTURE_WRAP_R:
+        switch (p) {
+        case LOCAL_GL_CLAMP_TO_EDGE:
+        case LOCAL_GL_REPEAT:
+        case LOCAL_GL_MIRRORED_REPEAT:
+            return true;
+
+        default:
+            ErrorInvalidEnum("%s: invalid param: %s", info, EnumName(p));
+            return false;
+        }
+
+    case LOCAL_GL_TEXTURE_MIN_LOD:
+    case LOCAL_GL_TEXTURE_MAX_LOD:
+        return true;
+
+    case LOCAL_GL_TEXTURE_COMPARE_MODE:
+        switch (param.AsInt()) {
+        case LOCAL_GL_NONE:
+        case LOCAL_GL_COMPARE_REF_TO_TEXTURE:
+            return true;
+
+        default:
+            ErrorInvalidEnum("%s: invalid param: %s", info, EnumName(p));
+            return false;
+        }
+
+    case LOCAL_GL_TEXTURE_COMPARE_FUNC:
+        switch (p) {
+        case LOCAL_GL_LEQUAL:
+        case LOCAL_GL_GEQUAL:
+        case LOCAL_GL_LESS:
+        case LOCAL_GL_GREATER:
+        case LOCAL_GL_EQUAL:
+        case LOCAL_GL_NOTEQUAL:
+        case LOCAL_GL_ALWAYS:
+        case LOCAL_GL_NEVER:
+            return true;
+
+        default:
+            ErrorInvalidEnum("%s: invalid param: %s", info, EnumName(p));
+            return false;
+        }
+
+    default:
+        ErrorInvalidEnum("%s: invalid pname: %s", info, EnumName(pname));
+        return false;
+    }
+}
+
+
+/**
  * Return true if format is a valid texture image format for source,
  * taking into account enabled WebGL extensions.
  */
 bool
 WebGLContext::ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func, WebGLTexDimensions dims)
 {
     /* Core WebGL texture formats */
     if (format == LOCAL_GL_ALPHA ||
@@ -1713,18 +1825,17 @@ WebGLContext::InitAndValidateGL()
         // Note that this used to cause crashes on old ATI drivers... hopefully not a significant
         // problem anymore. See bug 602183.
         gl->fEnable(LOCAL_GL_POINT_SPRITE);
     }
 
 #ifdef XP_MACOSX
     if (gl->WorkAroundDriverBugs() &&
         gl->Vendor() == gl::GLVendor::ATI &&
-        nsCocoaFeatures::OSXVersionMajor() == 10 &&
-        nsCocoaFeatures::OSXVersionMinor() < 9)
+        !nsCocoaFeatures::IsAtLeastVersion(10,9))
     {
         // The Mac ATI driver, in all known OSX version up to and including 10.8,
         // renders points sprites upside-down. Apple bug 11778921
         gl->fPointParameterf(LOCAL_GL_POINT_SPRITE_COORD_ORIGIN, LOCAL_GL_LOWER_LEFT);
     }
 #endif
 
     // Check the shader validator pref
--- a/dom/canvas/WebGLFramebuffer.cpp
+++ b/dom/canvas/WebGLFramebuffer.cpp
@@ -368,17 +368,17 @@ WebGLFramebuffer::Attachment::FinalizeAt
                                          LOCAL_GL_RENDERBUFFER, 0);
         }
 
         return;
     }
     MOZ_ASSERT(HasImage());
 
     if (Texture()) {
-        MOZ_ASSERT(gl == Texture()->Context()->gl);
+        MOZ_ASSERT(gl == Texture()->Context()->GL());
 
         const GLenum imageTarget = ImageTarget().get();
         const GLint mipLevel = MipLevel();
         const GLuint glName = Texture()->GLName();
 
         if (attachmentLoc == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
             gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT,
                                       imageTarget, glName, mipLevel);
--- a/dom/canvas/WebGLSampler.cpp
+++ b/dom/canvas/WebGLSampler.cpp
@@ -7,42 +7,45 @@
 #include "WebGLSampler.h"
 
 #include "GLContext.h"
 
 #include "mozilla/dom/WebGL2RenderingContextBinding.h"
 
 using namespace mozilla;
 
-WebGLSampler::WebGLSampler(WebGLContext* context)
-    : WebGLBindableName<GLenum>(0),
+WebGLSampler::WebGLSampler(WebGLContext* context, GLuint sampler)
+    : WebGLBindableName<GLenum>(sampler),
       WebGLContextBoundObject(context)
 {
-    MOZ_CRASH("Not Implemented.");
+    mContext->mSamplers.insertBack(this);
 }
 
 WebGLSampler::~WebGLSampler()
-{}
+{
+    DeleteOnce();
+}
 
 void
 WebGLSampler::Delete()
 {
-    MOZ_CRASH("Not Implemented.");
+    mContext->MakeContextCurrent();
+    mContext->gl->fDeleteSamplers(1, &mGLName);
+
+    removeFrom(mContext->mSamplers);
 }
 
 WebGLContext*
 WebGLSampler::GetParentObject() const
 {
-    MOZ_CRASH("Not Implemented.");
-    return nullptr;
+    return Context();
 }
 
 JSObject*
 WebGLSampler::WrapObject(JSContext* cx)
 {
-    MOZ_CRASH("Not Implemented.");
     return dom::WebGLSamplerBinding::Wrap(cx, this);
 }
 
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLSampler)
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLSampler, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLSampler, Release)
--- a/dom/canvas/WebGLSampler.h
+++ b/dom/canvas/WebGLSampler.h
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef WEBGL2SAMPLER_H_
-#define WEBGL2SAMPLER_H_
+#ifndef WEBGLSAMPLER_H_
+#define WEBGLSAMPLER_H_
 
 #include "WebGLBindableName.h"
 #include "WebGLObjectModel.h"
 
 #include "nsWrapperCache.h"
 
 #include "mozilla/LinkedList.h"
 
@@ -21,26 +21,28 @@ class WebGLSampler MOZ_FINAL
     , public WebGLRefCountedObject<WebGLSampler>
     , public LinkedListElement<WebGLSampler>
     , public WebGLContextBoundObject
 {
     friend class WebGLContext2;
 
 public:
 
-    explicit WebGLSampler(WebGLContext* aContext);
+    explicit WebGLSampler(WebGLContext* aContext, GLuint sampler);
 
     void Delete();
     WebGLContext* GetParentObject() const;
 
     virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE;
 
+private:
+
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLSampler)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLSampler)
 
 private:
 
     ~WebGLSampler();
 };
 
 } // namespace mozilla
 
-#endif // !WEBGL2SAMPLER_H_
+#endif // !WEBGLSAMPLER_H_
--- a/dom/canvas/moz.build
+++ b/dom/canvas/moz.build
@@ -59,16 +59,17 @@ UNIFIED_SOURCES += [
     'WebGLContextBuffers.cpp',
     'WebGLContextDraw.cpp',
     'WebGLContextExtensions.cpp',
     'WebGLContextFramebufferOperations.cpp',
     'WebGLContextGL.cpp',
     'WebGLContextLossHandler.cpp',
     'WebGLContextReporter.cpp',
     'WebGLContextState.cpp',
+    'WebGLContextUnchecked.cpp',
     'WebGLContextUtils.cpp',
     'WebGLContextValidate.cpp',
     'WebGLContextVertexArray.cpp',
     'WebGLContextVertices.cpp',
     'WebGLElementArrayCache.cpp',
     'WebGLExtensionBase.cpp',
     'WebGLExtensionBlendMinMax.cpp',
     'WebGLExtensionColorBufferFloat.cpp',
--- a/dom/canvas/test/webgl-mochitest/test_webgl_request_mismatch.html
+++ b/dom/canvas/test/webgl-mochitest/test_webgl_request_mismatch.html
@@ -1,35 +1,90 @@
 <!DOCTYPE HTML>
-<title>WebGL test: Mismatched 'webgl' and 'experimental-webgl' context requests</title>
+<html>
+<head>
 <script src="/tests/SimpleTest/SimpleTest.js"></script>
 <link rel="stylesheet" href="/tests/SimpleTest/test.css">
+</head>
 <body>
-<canvas id="c1"></canvas>
-<canvas id="c2"></canvas>
-<canvas id="c3"></canvas>
-<canvas id="c4"></canvas>
 <script>
 
-function testContextRetrieval(canvasId, creationId, requestId) {
-  var canvas = document.getElementById(canvasId);
-  ok(canvas, 'Invalid `canvasId`: ' + canvasId);
+WEBGL_TYPES = {};
+WEBGL_TYPES['experimental-webgl'] = true;
+WEBGL_TYPES['webgl'] = true;
 
-  var createdGL = canvas.getContext(creationId);
-  if (!createdGL)
-    return; // No WebGL on this machine?
+function AreBothIn(a, b, set) {
+    return (a in set) && (b in set);
+}
 
-  var requestedGL = canvas.getContext(requestId);
-  if (creationId == requestId) {
-    ok(requestedGL, 'Request for \'' + requestId + '\' on from \'' + creationId + '\' should succeed.');
-    ok(requestedGL == createdGL, 'Request for \'' + requestId + '\' on from \'' + creationId + '\' should match.');
-  } else {
-    ok(!requestedGL, 'Request for \'' + requestId + '\' on from \'' + creationId + '\' should fail.');
-  }
+function IsAlias(typeA, typeB) {
+    if (typeA == typeB)
+        return true;
+
+    if (AreBothIn(typeA, typeB, WEBGL_TYPES))
+        return true;
+
+    return false;
 }
 
-testContextRetrieval('c1', 'experimental-webgl', 'webgl');
-testContextRetrieval('c2', 'webgl', 'experimental-webgl');
-testContextRetrieval('c3', 'experimental-webgl', 'experimental-webgl');
-testContextRetrieval('c4', 'webgl', 'webgl');
+function TestContextRetrieval(creationType, requestType, functionalTypeSet) {
+    var canvas = document.createElement('canvas');
+    var createdGL = canvas.getContext(creationType);
+
+    var didCreationSucceed = (createdGL != null);
+    if (creationType in functionalTypeSet) {
+        ok(createdGL, 'Context creation should succeed for type \'' +
+                      creationType + '\'');
+    } else {
+        ok(!createdGL, 'Context creation should fail for type \'' +
+                       creationType + '\'');
+        return;
+    }
+
+    var requestedGL = canvas.getContext(requestType);
+
+    if (requestType in functionalTypeSet &&
+        IsAlias(creationType, requestType))
+    {
+        ok(requestedGL, 'Request for \'' + requestType + '\' from \'' +
+                        creationType + '\' should succeed.');
+        ok(requestedGL == createdGL, 'Request for \'' + requestType +
+                                     '\' from \'' + creationType +
+                                     '\' should match.');
+    } else {
+        ok(!requestedGL, 'Request for \'' + requestType + '\' from \'' +
+                         creationType + '\' should fail.');
+    }
+}
+
+function IsWebGLFunctional() {
+    var canvas = document.createElement('canvas');
+    return canvas.getContext('experimental-webgl') != null;
+}
+
+function IsWebGLConformant() {
+    var canvas = document.createElement('canvas');
+    return canvas.getContext('webgl') != null;
+}
+
+var typeList = ['2d', 'experimental-webgl', 'webgl'];
+var functionalTypeSet = {};
+functionalTypeSet['2d'] = true;
+
+if (IsWebGLFunctional())
+    functionalTypeSet['experimental-webgl'] = true;
+
+if (IsWebGLConformant())
+    functionalTypeSet['webgl'] = true;
+
+for (var i in typeList) {
+    var creationType = typeList[i];
+
+    for (var j in typeList) {
+        var requestType = typeList[j];
+
+        TestContextRetrieval(creationType, requestType, functionalTypeSet);
+    }
+}
 
 </script>
-
+</body>
+</html>
--- a/dom/html/HTMLCanvasElement.cpp
+++ b/dom/html/HTMLCanvasElement.cpp
@@ -29,16 +29,17 @@
 #include "nsIWritablePropertyBag2.h"
 #include "nsIXPConnect.h"
 #include "nsJSUtils.h"
 #include "nsLayoutUtils.h"
 #include "nsMathUtils.h"
 #include "nsNetUtil.h"
 #include "nsStreamUtils.h"
 #include "ActiveLayerTracker.h"
+#include "WebGL1Context.h"
 #include "WebGL2Context.h"
 
 using namespace mozilla::layers;
 using namespace mozilla::gfx;
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Canvas)
 
 namespace {
@@ -643,147 +644,131 @@ HTMLCanvasElement::MozGetAsFileImpl(cons
   nsRefPtr<File> file =
     File::CreateMemoryFile(win, imgData, (uint32_t)imgSize, aName, type,
                            PR_Now());
 
   file.forget(aResult);
   return NS_OK;
 }
 
-nsresult
-HTMLCanvasElement::GetContextHelper(const nsAString& aContextId,
-                                    nsICanvasRenderingContextInternal **aContext)
+static bool
+GetCanvasContextType(const nsAString& str, CanvasContextType* const out_type)
 {
-  NS_ENSURE_ARG(aContext);
+  if (str.EqualsLiteral("2d")) {
+    *out_type = CanvasContextType::Canvas2D;
+    return true;
+  }
 
-  if (aContextId.EqualsLiteral("2d")) {
-    Telemetry::Accumulate(Telemetry::CANVAS_2D_USED, 1);
-    nsRefPtr<CanvasRenderingContext2D> ctx =
-      new CanvasRenderingContext2D();
-
-    ctx->SetCanvasElement(this);
-    ctx.forget(aContext);
-    return NS_OK;
+  if (str.EqualsLiteral("experimental-webgl")) {
+    *out_type = CanvasContextType::WebGL1;
+    return true;
   }
 
-  if (WebGL2Context::IsSupported() &&
-      aContextId.EqualsLiteral("experimental-webgl2"))
-  {
-    Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1);
-    nsRefPtr<WebGL2Context> ctx = WebGL2Context::Create();
-
-    if (ctx == nullptr) {
-      return NS_ERROR_NOT_IMPLEMENTED;
-    }
-
-    ctx->SetCanvasElement(this);
-    ctx.forget(aContext);
-    return NS_OK;
+#ifdef MOZ_WEBGL_CONFORMANT
+  if (str.EqualsLiteral("webgl")) {
+    /* WebGL 1.0, $2.1 "Context Creation":
+     *   If the user agent supports both the webgl and experimental-webgl
+     *   canvas context types, they shall be treated as aliases.
+     */
+    *out_type = CanvasContextType::WebGL1;
+    return true;
   }
-
-  NS_ConvertUTF16toUTF8 ctxId(aContextId);
+#endif
 
-  // check that ctxId is clamped to A-Za-z0-9_-
-  for (uint32_t i = 0; i < ctxId.Length(); i++) {
-    if ((ctxId[i] < 'A' || ctxId[i] > 'Z') &&
-        (ctxId[i] < 'a' || ctxId[i] > 'z') &&
-        (ctxId[i] < '0' || ctxId[i] > '9') &&
-        (ctxId[i] != '-') &&
-        (ctxId[i] != '_'))
-    {
-      // XXX ERRMSG we need to report an error to developers here! (bug 329026)
-      return NS_OK;
+  if (WebGL2Context::IsSupported()) {
+    if (str.EqualsLiteral("experimental-webgl2")) {
+      *out_type = CanvasContextType::WebGL2;
+      return true;
     }
   }
 
-  nsCString ctxString("@mozilla.org/content/canvas-rendering-context;1?id=");
-  ctxString.Append(ctxId);
+  return false;
+}
+
+static already_AddRefed<nsICanvasRenderingContextInternal>
+CreateContextForCanvas(CanvasContextType contextType, HTMLCanvasElement* canvas)
+{
+  nsRefPtr<nsICanvasRenderingContextInternal> ret;
+
+  switch (contextType) {
+  case CanvasContextType::Canvas2D:
+    Telemetry::Accumulate(Telemetry::CANVAS_2D_USED, 1);
+    ret = new CanvasRenderingContext2D();
+    break;
 
-  nsresult rv;
-  nsCOMPtr<nsICanvasRenderingContextInternal> ctx =
-    do_CreateInstance(ctxString.get(), &rv);
-  if (rv == NS_ERROR_OUT_OF_MEMORY) {
-    *aContext = nullptr;
-    return NS_ERROR_OUT_OF_MEMORY;
+  case CanvasContextType::WebGL1:
+    Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1);
+
+    ret = WebGL1Context::Create();
+    if (!ret)
+      return nullptr;
+    break;
+
+  case CanvasContextType::WebGL2:
+    Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1);
+
+    ret = WebGL2Context::Create();
+    if (!ret)
+      return nullptr;
+    break;
   }
-  if (NS_FAILED(rv)) {
-    *aContext = nullptr;
-    // XXX ERRMSG we need to report an error to developers here! (bug 329026)
-    return NS_OK;
-  }
+  MOZ_ASSERT(ret);
 
-  ctx->SetCanvasElement(this);
-  ctx.forget(aContext);
-  return NS_OK;
+  ret->SetCanvasElement(canvas);
+  return ret.forget();
 }
 
 nsresult
 HTMLCanvasElement::GetContext(const nsAString& aContextId,
                               nsISupports** aContext)
 {
   ErrorResult rv;
-  *aContext =
-    GetContext(nullptr, aContextId, JS::NullHandleValue, rv).take();
+  *aContext = GetContext(nullptr, aContextId, JS::NullHandleValue, rv).take();
   return rv.ErrorCode();
 }
 
-static bool
-IsContextIdWebGL(const nsAString& str)
-{
-  return str.EqualsLiteral("webgl") ||
-         str.EqualsLiteral("experimental-webgl");
-}
-
 already_AddRefed<nsISupports>
 HTMLCanvasElement::GetContext(JSContext* aCx,
                               const nsAString& aContextId,
                               JS::Handle<JS::Value> aContextOptions,
                               ErrorResult& rv)
 {
-  if (mCurrentContextId.IsEmpty()) {
-    rv = GetContextHelper(aContextId, getter_AddRefs(mCurrentContext));
-    if (rv.Failed() || !mCurrentContext) {
+  CanvasContextType contextType;
+  if (!GetCanvasContextType(aContextId, &contextType))
+    return nullptr;
+
+  if (!mCurrentContext) {
+    // This canvas doesn't have a context yet.
+
+    nsRefPtr<nsICanvasRenderingContextInternal> context;
+    context = CreateContextForCanvas(contextType, this);
+    if (!context)
       return nullptr;
-    }
 
     // Ensure that the context participates in CC.  Note that returning a
     // CC participant from QI doesn't addref.
-    nsXPCOMCycleCollectionParticipant *cp = nullptr;
-    CallQueryInterface(mCurrentContext, &cp);
+    nsXPCOMCycleCollectionParticipant* cp = nullptr;
+    CallQueryInterface(context, &cp);
     if (!cp) {
-      mCurrentContext = nullptr;
       rv.Throw(NS_ERROR_FAILURE);
       return nullptr;
     }
 
+    mCurrentContext = context.forget();
+    mCurrentContextType = contextType;
+
     rv = UpdateContext(aCx, aContextOptions);
     if (rv.Failed()) {
       rv = NS_OK; // See bug 645792
       return nullptr;
     }
-    mCurrentContextId.Assign(aContextId);
-  }
-
-  if (!mCurrentContextId.Equals(aContextId)) {
-    if (IsContextIdWebGL(aContextId) &&
-        IsContextIdWebGL(mCurrentContextId))
-    {
-      // Warn when we get a request for a webgl context with an id that differs
-      // from the id it was created with.
-      nsCString creationId = NS_LossyConvertUTF16toASCII(mCurrentContextId);
-      nsCString requestId = NS_LossyConvertUTF16toASCII(aContextId);
-      JS_ReportWarning(aCx, "WebGL: Retrieving a WebGL context from a canvas "
-                            "via a request id ('%s') different from the id used "
-                            "to create the context ('%s') is not allowed.",
-                            requestId.get(),
-                            creationId.get());
-    }
-    
-    //XXX eventually allow for more than one active context on a given canvas
-    return nullptr;
+  } else {
+    // We already have a context of some type.
+    if (contextType != mCurrentContextType)
+      return nullptr;
   }
 
   nsCOMPtr<nsICanvasRenderingContextInternal> context = mCurrentContext;
   return context.forget();
 }
 
 NS_IMETHODIMP
 HTMLCanvasElement::MozGetIPCContext(const nsAString& aContextId,
@@ -793,32 +778,38 @@ HTMLCanvasElement::MozGetIPCContext(cons
     // XXX ERRMSG we need to report an error to developers here! (bug 329026)
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   // We only support 2d shmem contexts for now.
   if (!aContextId.EqualsLiteral("2d"))
     return NS_ERROR_INVALID_ARG;
 
-  if (mCurrentContextId.IsEmpty()) {
-    nsresult rv = GetContextHelper(aContextId, getter_AddRefs(mCurrentContext));
-    NS_ENSURE_SUCCESS(rv, rv);
-    if (!mCurrentContext) {
+  CanvasContextType contextType = CanvasContextType::Canvas2D;
+
+  if (!mCurrentContext) {
+    // This canvas doesn't have a context yet.
+
+    nsRefPtr<nsICanvasRenderingContextInternal> context;
+    context = CreateContextForCanvas(contextType, this);
+    if (!context) {
+      *aContext = nullptr;
       return NS_OK;
     }
 
+    mCurrentContext = context;
     mCurrentContext->SetIsIPC(true);
-
-    rv = UpdateContext(nullptr, JS::NullHandleValue);
-    NS_ENSURE_SUCCESS(rv, rv);
+    mCurrentContextType = contextType;
 
-    mCurrentContextId.Assign(aContextId);
-  } else if (!mCurrentContextId.Equals(aContextId)) {
-    //XXX eventually allow for more than one active context on a given canvas
-    return NS_ERROR_INVALID_ARG;
+    nsresult rv = UpdateContext(nullptr, JS::NullHandleValue);
+    NS_ENSURE_SUCCESS(rv, rv);
+  } else {
+    // We already have a context of some type.
+    if (contextType != mCurrentContextType)
+      return NS_ERROR_INVALID_ARG;
   }
 
   NS_ADDREF (*aContext = mCurrentContext);
   return NS_OK;
 }
 
 nsresult
 HTMLCanvasElement::UpdateContext(JSContext* aCx, JS::Handle<JS::Value> aNewContextOptions)
@@ -826,31 +817,28 @@ HTMLCanvasElement::UpdateContext(JSConte
   if (!mCurrentContext)
     return NS_OK;
 
   nsIntSize sz = GetWidthHeight();
 
   nsresult rv = mCurrentContext->SetIsOpaque(HasAttr(kNameSpaceID_None, nsGkAtoms::moz_opaque));
   if (NS_FAILED(rv)) {
     mCurrentContext = nullptr;
-    mCurrentContextId.Truncate();
     return rv;
   }
 
   rv = mCurrentContext->SetContextOptions(aCx, aNewContextOptions);
   if (NS_FAILED(rv)) {
     mCurrentContext = nullptr;
-    mCurrentContextId.Truncate();
     return rv;
   }
 
   rv = mCurrentContext->SetDimensions(sz.width, sz.height);
   if (NS_FAILED(rv)) {
     mCurrentContext = nullptr;
-    mCurrentContextId.Truncate();
     return rv;
   }
 
   return rv;
 }
 
 nsIntSize
 HTMLCanvasElement::GetSize()
--- a/dom/html/HTMLCanvasElement.h
+++ b/dom/html/HTMLCanvasElement.h
@@ -2,16 +2,17 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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/. */
 #if !defined(mozilla_dom_HTMLCanvasElement_h)
 #define mozilla_dom_HTMLCanvasElement_h
 
 #include "mozilla/Attributes.h"
+#include "mozilla/TypedEnum.h"
 #include "nsIDOMHTMLCanvasElement.h"
 #include "nsGenericHTMLElement.h"
 #include "nsGkAtoms.h"
 #include "nsSize.h"
 #include "nsError.h"
 
 #include "mozilla/gfx/Rect.h"
 
@@ -30,16 +31,22 @@ class SourceSurface;
 
 namespace dom {
 
 class File;
 class FileCallback;
 class HTMLCanvasPrintState;
 class PrintCallback;
 
+MOZ_BEGIN_ENUM_CLASS(CanvasContextType, uint8_t)
+  Canvas2D,
+  WebGL1,
+  WebGL2
+MOZ_END_ENUM_CLASS(CanvasContextType)
+
 class HTMLCanvasElement MOZ_FINAL : public nsGenericHTMLElement,
                                     public nsIDOMHTMLCanvasElement
 {
   enum {
     DEFAULT_CANVAS_WIDTH = 300,
     DEFAULT_CANVAS_HEIGHT = 150
   };
 
@@ -224,21 +231,19 @@ protected:
                        nsIInputStream** aStream);
   nsresult ToDataURLImpl(JSContext* aCx,
                          const nsAString& aMimeType,
                          const JS::Value& aEncoderOptions,
                          nsAString& aDataURL);
   nsresult MozGetAsFileImpl(const nsAString& aName,
                             const nsAString& aType,
                             nsIDOMFile** aResult);
-  nsresult GetContextHelper(const nsAString& aContextId,
-                            nsICanvasRenderingContextInternal **aContext);
   void CallPrintCallback();
 
-  nsString mCurrentContextId;
+  CanvasContextType mCurrentContextType;
   nsRefPtr<HTMLCanvasElement> mOriginalCanvas;
   nsRefPtr<PrintCallback> mPrintCallback;
   nsCOMPtr<nsICanvasRenderingContextInternal> mCurrentContext;
   nsRefPtr<HTMLCanvasPrintState> mPrintState;
 
 public:
   // Record whether this canvas should be write-only or not.
   // We set this when script paints an image from a different origin.
--- a/dom/html/ImageDocument.cpp
+++ b/dom/html/ImageDocument.cpp
@@ -454,70 +454,48 @@ ImageDocument::DOMToggleImageSize()
 }
 
 NS_IMETHODIMP
 ImageDocument::Notify(imgIRequest* aRequest, int32_t aType, const nsIntRect* aData)
 {
   if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
     nsCOMPtr<imgIContainer> image;
     aRequest->GetImage(getter_AddRefs(image));
-    return OnStartContainer(aRequest, image);
+    return OnSizeAvailable(aRequest, image);
   }
 
-  // Do these two off a script runner because decode complete notifications often
-  // come during painting and these will trigger invalidation.
-  if (aType == imgINotificationObserver::DECODE_COMPLETE) {
+  // Run this using a script runner because HAS_TRANSPARENCY notifications can
+  // come during painting and this will trigger invalidation.
+  if (aType == imgINotificationObserver::HAS_TRANSPARENCY) {
     nsCOMPtr<nsIRunnable> runnable =
-      NS_NewRunnableMethod(this, &ImageDocument::AddDecodedClass);
-    nsContentUtils::AddScriptRunner(runnable);
-  }
-
-  if (aType == imgINotificationObserver::DISCARD) {
-    nsCOMPtr<nsIRunnable> runnable =
-      NS_NewRunnableMethod(this, &ImageDocument::RemoveDecodedClass);
+      NS_NewRunnableMethod(this, &ImageDocument::OnHasTransparency);
     nsContentUtils::AddScriptRunner(runnable);
   }
 
   if (aType == imgINotificationObserver::LOAD_COMPLETE) {
     uint32_t reqStatus;
     aRequest->GetImageStatus(&reqStatus);
     nsresult status =
         reqStatus & imgIRequest::STATUS_ERROR ? NS_ERROR_FAILURE : NS_OK;
-    return OnStopRequest(aRequest, status);
+    return OnLoadComplete(aRequest, status);
   }
 
   return NS_OK;
 }
 
 void
-ImageDocument::AddDecodedClass()
+ImageDocument::OnHasTransparency()
 {
   if (!mImageContent || nsContentUtils::IsChildOfSameType(this)) {
     return;
   }
 
   nsDOMTokenList* classList = mImageContent->AsElement()->ClassList();
   mozilla::ErrorResult rv;
-  // Update the background-color of the image only after the
-  // image has been decoded to prevent flashes of just the
-  // background-color.
-  classList->Add(NS_LITERAL_STRING("decoded"), rv);
-}
-
-void
-ImageDocument::RemoveDecodedClass()
-{
-  if (!mImageContent || nsContentUtils::IsChildOfSameType(this)) {
-    return;
-  }
-
-  nsDOMTokenList* classList = mImageContent->AsElement()->ClassList();
-  mozilla::ErrorResult rv;
-  // Remove any decoded-related styling when the image is unloaded.
-  classList->Remove(NS_LITERAL_STRING("decoded"), rv);
+  classList->Add(NS_LITERAL_STRING("transparent"), rv);
 }
 
 void
 ImageDocument::SetModeClass(eModeClasses mode)
 {
   nsDOMTokenList* classList = mImageContent->AsElement()->ClassList();
   mozilla::ErrorResult rv;
 
@@ -530,34 +508,33 @@ ImageDocument::SetModeClass(eModeClasses
   if (mode == eOverflowing) {
     classList->Add(NS_LITERAL_STRING("overflowing"), rv);
   } else {
     classList->Remove(NS_LITERAL_STRING("overflowing"), rv);
   }
 }
 
 nsresult
-ImageDocument::OnStartContainer(imgIRequest* aRequest, imgIContainer* aImage)
+ImageDocument::OnSizeAvailable(imgIRequest* aRequest, imgIContainer* aImage)
 {
   // Styles have not yet been applied, so we don't know the final size. For now,
   // default to the image's intrinsic size.
   aImage->GetWidth(&mImageWidth);
   aImage->GetHeight(&mImageHeight);
 
   nsCOMPtr<nsIRunnable> runnable =
     NS_NewRunnableMethod(this, &ImageDocument::DefaultCheckOverflowing);
   nsContentUtils::AddScriptRunner(runnable);
   UpdateTitleAndCharset();
 
   return NS_OK;
 }
 
 nsresult
-ImageDocument::OnStopRequest(imgIRequest *aRequest,
-                             nsresult aStatus)
+ImageDocument::OnLoadComplete(imgIRequest* aRequest, nsresult aStatus)
 {
   UpdateTitleAndCharset();
 
   // mImageContent can be null if the document is already destroyed
   if (NS_FAILED(aStatus) && mStringBundle && mImageContent) {
     nsAutoCString src;
     mDocumentURI->GetSpec(src);
     NS_ConvertUTF8toUTF16 srcString(src);
--- a/dom/html/ImageDocument.h
+++ b/dom/html/ImageDocument.h
@@ -46,19 +46,16 @@ public:
   NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) MOZ_OVERRIDE;
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ImageDocument, MediaDocument)
 
   friend class ImageListener;
 
   void DefaultCheckOverflowing() { CheckOverflowing(mResizeImageByDefault); }
 
-  void AddDecodedClass();
-  void RemoveDecodedClass();
-
   // WebIDL API
   virtual JSObject* WrapNode(JSContext* aCx)
     MOZ_OVERRIDE;
 
   bool ImageResizingEnabled() const
   {
     return true;
   }
@@ -102,18 +99,19 @@ protected:
 
   enum eModeClasses {
     eNone,
     eShrinkToFit,
     eOverflowing
   };
   void SetModeClass(eModeClasses mode);
 
-  nsresult OnStartContainer(imgIRequest* aRequest, imgIContainer* aImage);
-  nsresult OnStopRequest(imgIRequest *aRequest, nsresult aStatus);
+  nsresult OnSizeAvailable(imgIRequest* aRequest, imgIContainer* aImage);
+  nsresult OnLoadComplete(imgIRequest* aRequest, nsresult aStatus);
+  void OnHasTransparency();
 
   nsCOMPtr<nsIContent>          mImageContent;
 
   float                         mVisibleWidth;
   float                         mVisibleHeight;
   int32_t                       mImageWidth;
   int32_t                       mImageHeight;
 
--- a/dom/html/moz.build
+++ b/dom/html/moz.build
@@ -107,17 +107,16 @@ EXPORTS.mozilla.dom += [
     'HTMLTextAreaElement.h',
     'HTMLTimeElement.h',
     'HTMLTitleElement.h',
     'HTMLTrackElement.h',
     'HTMLUnknownElement.h',
     'HTMLVideoElement.h',
     'ImageDocument.h',
     'MediaError.h',
-    'nsBrowserElement.h',
     'RadioNodeList.h',
     'TextTrackManager.h',
     'TimeRanges.h',
     'UndoManager.h',
     'ValidityState.h',
 ]
 
 UNIFIED_SOURCES += [
@@ -186,17 +185,16 @@ UNIFIED_SOURCES += [
     'HTMLTimeElement.cpp',
     'HTMLTitleElement.cpp',
     'HTMLTrackElement.cpp',
     'HTMLUnknownElement.cpp',
     'HTMLVideoElement.cpp',
     'ImageDocument.cpp',
     'MediaDocument.cpp',
     'MediaError.cpp',
-    'nsBrowserElement.cpp',
     'nsDOMStringMap.cpp',
     'nsFormSubmission.cpp',
     'nsGenericHTMLElement.cpp',
     'nsGenericHTMLFrameElement.cpp',
     'nsHTMLContentSink.cpp',
     'nsHTMLDNSPrefetch.cpp',
     'nsHTMLDocument.cpp',
     'nsIConstraintValidation.cpp',
deleted file mode 100644
--- a/dom/html/nsBrowserElement.cpp
+++ /dev/null
@@ -1,545 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsBrowserElement.h"
-
-#include "mozilla/Preferences.h"
-#include "mozilla/Services.h"
-#include "mozilla/dom/BrowserElementBinding.h"
-#include "mozilla/dom/DOMRequest.h"
-#include "mozilla/dom/ScriptSettings.h"
-#include "mozilla/dom/ToJSValue.h"
-
-#include "nsComponentManagerUtils.h"
-#include "nsContentUtils.h"
-#include "nsFrameLoader.h"
-#include "nsIDOMDOMRequest.h"
-#include "nsIDOMElement.h"
-#include "nsINode.h"
-#include "nsIObserver.h"
-#include "nsIObserverService.h"
-#include "nsIPrincipal.h"
-#include "nsWeakReference.h"
-
-using namespace mozilla::dom;
-
-namespace mozilla {
-
-static const char kRemoteBrowserPending[] = "remote-browser-pending";
-static const char kInprocessBrowserShown[] = "inprocess-browser-shown";
-
-class nsBrowserElement::BrowserShownObserver : public nsIObserver
-                                             , public nsSupportsWeakReference
-{
-public:
-  BrowserShownObserver(nsBrowserElement* aBrowserElement);
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIOBSERVER
-  void AddObserver();
-  void RemoveObserver();
-private:
-  virtual ~BrowserShownObserver();
-
-  // Weak reference to the browser element. nsBrowserElement has a
-  // reference to us. nsBrowserElement's destructor is responsible to
-  // null out this weak reference via RemoveObserver()
-  nsBrowserElement* mBrowserElement;
-};
-
-NS_IMPL_ISUPPORTS(nsBrowserElement::BrowserShownObserver, nsIObserver, nsISupportsWeakReference)
-
-nsBrowserElement::BrowserShownObserver::BrowserShownObserver(nsBrowserElement* aBrowserElement)
-  : mBrowserElement(aBrowserElement)
-{
-}
-
-nsBrowserElement::BrowserShownObserver::~BrowserShownObserver()
-{
-  RemoveObserver();
-}
-
-NS_IMETHODIMP
-nsBrowserElement::BrowserShownObserver::Observe(nsISupports* aSubject,
-                                                const char* aTopic,
-                                                const char16_t* aData)
-{
-  NS_ENSURE_TRUE(mBrowserElement, NS_OK);
-
-  if (!strcmp(aTopic, kRemoteBrowserPending) ||
-      !strcmp(aTopic, kInprocessBrowserShown)) {
-    nsCOMPtr<nsIFrameLoader> frameLoader = do_QueryInterface(aSubject);
-    nsCOMPtr<nsIFrameLoader> myFrameLoader = mBrowserElement->GetFrameLoader();
-    // The browser element API needs the frameloader to
-    // initialize. We still use the observer to get notified when the
-    // frameloader is created. So we check if the frameloader created
-    // is ours, then initialize the browser element API.
-    if (frameLoader && frameLoader == myFrameLoader) {
-      mBrowserElement->InitBrowserElementAPI();
-    }
-  }
-  return NS_OK;
-}
-
-void
-nsBrowserElement::BrowserShownObserver::AddObserver()
-{
-  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
-  if (obs) {
-    obs->AddObserver(this, kRemoteBrowserPending, true);
-    obs->AddObserver(this, kInprocessBrowserShown, true);
-  }
-}
-
-void
-nsBrowserElement::BrowserShownObserver::RemoveObserver()
-{
-  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
-  if (obs) {
-    obs->RemoveObserver(this, kRemoteBrowserPending);
-    obs->RemoveObserver(this, kInprocessBrowserShown);
-  }
-  mBrowserElement = nullptr;
-}
-
-bool
-nsBrowserElement::IsBrowserElementOrThrow(ErrorResult& aRv)
-{
-  if (mBrowserElementAPI) {
-    return true;
-  }
-  aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
-  return false;
-}
-
-bool
-nsBrowserElement::IsNotWidgetOrThrow(ErrorResult& aRv)
-{
-  if (!mOwnerIsWidget) {
-    return true;
-  }
-  aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
-  return false;
-}
-
-void
-nsBrowserElement::InitBrowserElementAPI()
-{
-  bool isBrowserOrApp;
-  nsCOMPtr<nsIFrameLoader> frameLoader = GetFrameLoader();
-  NS_ENSURE_TRUE_VOID(frameLoader);
-  nsresult rv = frameLoader->GetOwnerIsBrowserOrAppFrame(&isBrowserOrApp);
-  NS_ENSURE_SUCCESS_VOID(rv);
-  rv = frameLoader->GetOwnerIsWidget(&mOwnerIsWidget);
-  NS_ENSURE_SUCCESS_VOID(rv);
-
-  if (!isBrowserOrApp) {
-    return;
-  }
-
-  mBrowserElementAPI = do_CreateInstance("@mozilla.org/dom/browser-element-api;1");
-  if (mBrowserElementAPI) {
-    mBrowserElementAPI->SetFrameLoader(frameLoader);
-  }
-}
-
-nsBrowserElement::nsBrowserElement()
-  : mOwnerIsWidget(false)
-{
-  mObserver = new BrowserShownObserver(this);
-  mObserver->AddObserver();
-}
-
-nsBrowserElement::~nsBrowserElement()
-{
-  mObserver->RemoveObserver();
-}
-
-void
-nsBrowserElement::SetVisible(bool aVisible, ErrorResult& aRv)
-{
-  NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
-
-  nsresult rv = mBrowserElementAPI->SetVisible(aVisible);
-
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-  }
-}
-
-already_AddRefed<DOMRequest>
-nsBrowserElement::GetVisible(ErrorResult& aRv)
-{
-  NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr);
-
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  nsresult rv = mBrowserElementAPI->GetVisible(getter_AddRefs(req));
-
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return nullptr;
-  }
-
-  return req.forget().downcast<DOMRequest>();
-}
-
-void
-nsBrowserElement::SetActive(bool aVisible, ErrorResult& aRv)
-{
-  NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
-
-  nsresult rv = mBrowserElementAPI->SetActive(aVisible);
-
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-  }
-}
-
-bool
-nsBrowserElement::GetActive(ErrorResult& aRv)
-{
-  NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), false);
-
-  bool isActive;
-  nsresult rv = mBrowserElementAPI->GetActive(&isActive);
-
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return false;
-  }
-
-  return isActive;
-}
-
-void
-nsBrowserElement::SendMouseEvent(const nsAString& aType,
-                                 uint32_t aX,
-                                 uint32_t aY,
-                                 uint32_t aButton,
-                                 uint32_t aClickCount,
-                                 uint32_t aModifiers,
-                                 ErrorResult& aRv)
-{
-  NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
-  NS_ENSURE_TRUE_VOID(IsNotWidgetOrThrow(aRv));
-
-  nsresult rv = mBrowserElementAPI->SendMouseEvent(aType,
-                                                   aX,
-                                                   aY,
-                                                   aButton,
-                                                   aClickCount,
-                                                   aModifiers);
-
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-  }
-}
-
-void
-nsBrowserElement::SendTouchEvent(const nsAString& aType,
-                                 const Sequence<uint32_t>& aIdentifiers,
-                                 const Sequence<int32_t>& aXs,
-                                 const Sequence<int32_t>& aYs,
-                                 const Sequence<uint32_t>& aRxs,
-                                 const Sequence<uint32_t>& aRys,
-                                 const Sequence<float>& aRotationAngles,
-                                 const Sequence<float>& aForces,
-                                 uint32_t aCount,
-                                 uint32_t aModifiers,
-                                 ErrorResult& aRv)
-{
-  NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
-  NS_ENSURE_TRUE_VOID(IsNotWidgetOrThrow(aRv));
-
-  if (aIdentifiers.Length() != aCount ||
-      aXs.Length() != aCount ||
-      aYs.Length() != aCount ||
-      aRxs.Length() != aCount ||
-      aRys.Length() != aCount ||
-      aRotationAngles.Length() != aCount ||
-      aForces.Length() != aCount) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
-    return;
-  }
-
-  nsresult rv = mBrowserElementAPI->SendTouchEvent(aType,
-                                                   aIdentifiers.Elements(),
-                                                   aXs.Elements(),
-                                                   aYs.Elements(),
-                                                   aRxs.Elements(),
-                                                   aRys.Elements(),
-                                                   aRotationAngles.Elements(),
-                                                   aForces.Elements(),
-                                                   aCount,
-                                                   aModifiers);
-
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-  }
-}
-
-void
-nsBrowserElement::GoBack(ErrorResult& aRv)
-{
-  NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
-  NS_ENSURE_TRUE_VOID(IsNotWidgetOrThrow(aRv));
-
-  nsresult rv = mBrowserElementAPI->GoBack();
-
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-  }
-}
-
-void
-nsBrowserElement::GoForward(ErrorResult& aRv)
-{
-  NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
-  NS_ENSURE_TRUE_VOID(IsNotWidgetOrThrow(aRv));
-
-  nsresult rv = mBrowserElementAPI->GoForward();
-
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-  }
-}
-
-void
-nsBrowserElement::Reload(bool aHardReload, ErrorResult& aRv)
-{
-  NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
-  NS_ENSURE_TRUE_VOID(IsNotWidgetOrThrow(aRv));
-
-  nsresult rv = mBrowserElementAPI->Reload(aHardReload);
-
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-  }
-}
-
-void
-nsBrowserElement::Stop(ErrorResult& aRv)
-{
-  NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
-  NS_ENSURE_TRUE_VOID(IsNotWidgetOrThrow(aRv));
-
-  nsresult rv = mBrowserElementAPI->Stop();
-
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-  }
-}
-
-already_AddRefed<DOMRequest>
-nsBrowserElement::Download(const nsAString& aUrl,
-                           const BrowserElementDownloadOptions& aOptions,
-                           ErrorResult& aRv)
-{
-  NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr);
-  NS_ENSURE_TRUE(IsNotWidgetOrThrow(aRv), nullptr);
-
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  nsCOMPtr<nsIXPConnectWrappedJS> wrappedObj = do_QueryInterface(mBrowserElementAPI);
-  MOZ_ASSERT(wrappedObj, "Failed to get wrapped JS from XPCOM component.");
-  AutoJSAPI jsapi;
-  jsapi.Init(wrappedObj->GetJSObject());
-  JSContext* cx = jsapi.cx();
-  JS::Rooted<JS::Value> options(cx);
-  if (!ToJSValue(cx, aOptions, &options)) {
-    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
-    return nullptr;
-  }
-  nsresult rv = mBrowserElementAPI->Download(aUrl, options, getter_AddRefs(req));
-
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return nullptr;
-  }
-
-  return req.forget().downcast<DOMRequest>();
-}
-
-already_AddRefed<DOMRequest>
-nsBrowserElement::PurgeHistory(ErrorResult& aRv)
-{
-  NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr);
-  NS_ENSURE_TRUE(IsNotWidgetOrThrow(aRv), nullptr);
-
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  nsresult rv = mBrowserElementAPI->PurgeHistory(getter_AddRefs(req));
-
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return nullptr;
-  }
-
-  return req.forget().downcast<DOMRequest>();
-}
-
-already_AddRefed<DOMRequest>
-nsBrowserElement::GetScreenshot(uint32_t aWidth,
-                                uint32_t aHeight,
-                                const nsAString& aMimeType,
-                                ErrorResult& aRv)
-{
-  NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr);
-  NS_ENSURE_TRUE(IsNotWidgetOrThrow(aRv), nullptr);
-
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  nsresult rv = mBrowserElementAPI->GetScreenshot(aWidth, aHeight, aMimeType,
-                                                  getter_AddRefs(req));
-
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    if (rv == NS_ERROR_INVALID_ARG) {
-      aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
-    } else {
-      aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-    }
-    return nullptr;
-  }
-
-  return req.forget().downcast<DOMRequest>();
-}
-
-void
-nsBrowserElement::Zoom(float aZoom, ErrorResult& aRv)
-{
-  NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
-  NS_ENSURE_TRUE_VOID(IsNotWidgetOrThrow(aRv));
-
-  nsresult rv = mBrowserElementAPI->Zoom(aZoom);
-
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-  }
-}
-
-already_AddRefed<DOMRequest>
-nsBrowserElement::GetCanGoBack(ErrorResult& aRv)
-{
-  NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr);
-  NS_ENSURE_TRUE(IsNotWidgetOrThrow(aRv), nullptr);
-
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  nsresult rv = mBrowserElementAPI->GetCanGoBack(getter_AddRefs(req));
-
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return nullptr;
-  }
-
-  return req.forget().downcast<DOMRequest>();
-}
-
-already_AddRefed<DOMRequest>
-nsBrowserElement::GetCanGoForward(ErrorResult& aRv)
-{
-  NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr);
-  NS_ENSURE_TRUE(IsNotWidgetOrThrow(aRv), nullptr);
-
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  nsresult rv = mBrowserElementAPI->GetCanGoForward(getter_AddRefs(req));
-
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return nullptr;
-  }
-
-  return req.forget().downcast<DOMRequest>();
-}
-
-already_AddRefed<DOMRequest>
-nsBrowserElement::GetContentDimensions(ErrorResult& aRv)
-{
-  NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr);
-  NS_ENSURE_TRUE(IsNotWidgetOrThrow(aRv), nullptr);
-
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  nsresult rv = mBrowserElementAPI->GetContentDimensions(getter_AddRefs(req));
-
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return nullptr;
-  }
-
-  return req.forget().downcast<DOMRequest>();
-}
-
-void
-nsBrowserElement::AddNextPaintListener(BrowserElementNextPaintEventCallback& aListener,
-                                       ErrorResult& aRv)
-{
-  NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
-
-  CallbackObjectHolder<BrowserElementNextPaintEventCallback,
-                       nsIBrowserElementNextPaintListener> holder(&aListener);
-  nsCOMPtr<nsIBrowserElementNextPaintListener> listener = holder.ToXPCOMCallback();
-
-  nsresult rv = mBrowserElementAPI->AddNextPaintListener(listener);
-
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-  }
-}
-
-void
-nsBrowserElement::RemoveNextPaintListener(BrowserElementNextPaintEventCallback& aListener,
-                                          ErrorResult& aRv)
-{
-  NS_ENSURE_TRUE_VOID(IsBrowserElementOrThrow(aRv));
-
-  CallbackObjectHolder<BrowserElementNextPaintEventCallback,
-                       nsIBrowserElementNextPaintListener> holder(&aListener);
-  nsCOMPtr<nsIBrowserElementNextPaintListener> listener = holder.ToXPCOMCallback();
-
-  nsresult rv = mBrowserElementAPI->RemoveNextPaintListener(listener);
-
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-  }
-}
-
-already_AddRefed<DOMRequest>
-nsBrowserElement::SetInputMethodActive(bool aIsActive,
-                                       ErrorResult& aRv)
-{
-  NS_ENSURE_TRUE(IsBrowserElementOrThrow(aRv), nullptr);
-
-  nsCOMPtr<nsIFrameLoader> frameLoader = GetFrameLoader();
-  if (!frameLoader) {
-    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
-    return nullptr;
-  }
-
-  nsCOMPtr<nsIDOMElement> ownerElement;
-  nsresult rv = frameLoader->GetOwnerElement(getter_AddRefs(ownerElement));
-  if (NS_FAILED(rv)) {
-    aRv.Throw(rv);
-    return nullptr;
-  }
-
-  nsCOMPtr<nsINode> node = do_QueryInterface(ownerElement);
-  nsCOMPtr<nsIPrincipal> principal = node->NodePrincipal();
-  if (!nsContentUtils::IsExactSitePermAllow(principal, "input-manage")) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
-    return nullptr;
-  }
-
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  rv = mBrowserElementAPI->SetInputMethodActive(aIsActive,
-                                                getter_AddRefs(req));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    if (rv == NS_ERROR_INVALID_ARG) {
-      aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
-    } else {
-      aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-    }
-    return nullptr;
-  }
-
-  return req.forget().downcast<DOMRequest>();
-}
-
-} // namespace mozilla
deleted file mode 100644
--- a/dom/html/nsBrowserElement.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef nsBrowserElement_h
-#define nsBrowserElement_h
-
-#include "mozilla/dom/BindingDeclarations.h"
-
-#include "nsCOMPtr.h"
-#include "nsIBrowserElementAPI.h"
-
-class nsFrameLoader;
-class nsIObserver;
-
-namespace mozilla {
-
-namespace dom {
-struct BrowserElementDownloadOptions;
-class BrowserElementNextPaintEventCallback;
-class DOMRequest;
-} // namespace dom
-
-class ErrorResult;
-
-/**
- * A helper class for browser-element frames
- */
-class nsBrowserElement
-{
-public:
-  nsBrowserElement();
-  virtual ~nsBrowserElement();
-
-  void SetVisible(bool aVisible, ErrorResult& aRv);
-  already_AddRefed<dom::DOMRequest> GetVisible(ErrorResult& aRv);
-  void SetActive(bool aActive, ErrorResult& aRv);
-  bool GetActive(ErrorResult& aRv);
-
-  void SendMouseEvent(const nsAString& aType,
-                      uint32_t aX,
-                      uint32_t aY,
-                      uint32_t aButton,
-                      uint32_t aClickCount,
-                      uint32_t aModifiers,
-                      ErrorResult& aRv);
-  void SendTouchEvent(const nsAString& aType,
-                      const dom::Sequence<uint32_t>& aIdentifiers,
-                      const dom::Sequence<int32_t>& aX,
-                      const dom::Sequence<int32_t>& aY,
-                      const dom::Sequence<uint32_t>& aRx,
-                      const dom::Sequence<uint32_t>& aRy,
-                      const dom::Sequence<float>& aRotationAngles,
-                      const dom::Sequence<float>& aForces,
-                      uint32_t aCount,
-                      uint32_t aModifiers,
-                      ErrorResult& aRv);
-  void GoBack(ErrorResult& aRv);
-  void GoForward(ErrorResult& aRv);
-  void Reload(bool aHardReload, ErrorResult& aRv);
-  void Stop(ErrorResult& aRv);
-
-  already_AddRefed<dom::DOMRequest>
-  Download(const nsAString& aUrl,
-           const dom::BrowserElementDownloadOptions& options,
-           ErrorResult& aRv);
-
-  already_AddRefed<dom::DOMRequest> PurgeHistory(ErrorResult& aRv);
-
-  already_AddRefed<dom::DOMRequest>
-  GetScreenshot(uint32_t aWidth,
-                uint32_t aHeight,
-                const nsAString& aMimeType,
-                ErrorResult& aRv);
-
-  void Zoom(float aZoom, ErrorResult& aRv);
-
-  already_AddRefed<dom::DOMRequest> GetCanGoBack(ErrorResult& aRv);
-  already_AddRefed<dom::DOMRequest> GetCanGoForward(ErrorResult& aRv);
-  already_AddRefed<dom::DOMRequest> GetContentDimensions(ErrorResult& aRv);
-
-  void AddNextPaintListener(dom::BrowserElementNextPaintEventCallback& listener,
-                            ErrorResult& aRv);
-  void RemoveNextPaintListener(dom::BrowserElementNextPaintEventCallback& listener,
-                               ErrorResult& aRv);
-
-  already_AddRefed<dom::DOMRequest> SetInputMethodActive(bool isActive,
-                                                         ErrorResult& aRv);
-
-protected:
-  NS_IMETHOD_(already_AddRefed<nsFrameLoader>) GetFrameLoader() = 0;
-  nsCOMPtr<nsIBrowserElementAPI> mBrowserElementAPI;
-
-private:
-  void InitBrowserElementAPI();
-  bool IsBrowserElementOrThrow(ErrorResult& aRv);
-  bool IsNotWidgetOrThrow(ErrorResult& aRv);
-  bool mOwnerIsWidget;
-
-  class BrowserShownObserver;
-  friend class BrowserShownObserver;
-  nsRefPtr<BrowserShownObserver> mObserver;
-};
-
-} // namespace mozilla
-
-#endif // nsBrowserElement_h
--- a/dom/html/nsGenericHTMLFrameElement.cpp
+++ b/dom/html/nsGenericHTMLFrameElement.cpp
@@ -29,17 +29,16 @@
 using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericHTMLFrameElement)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGenericHTMLFrameElement,
                                                   nsGenericHTMLElement)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameLoader)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserElementAPI)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_ADDREF_INHERITED(nsGenericHTMLFrameElement, nsGenericHTMLElement)
 NS_IMPL_RELEASE_INHERITED(nsGenericHTMLFrameElement, nsGenericHTMLElement)
 
 NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsGenericHTMLFrameElement)
   NS_INTERFACE_TABLE_INHERITED(nsGenericHTMLFrameElement,
                                nsIDOMMozBrowserFrame,
@@ -302,20 +301,16 @@ nsGenericHTMLFrameElement::GetReallyIsBr
   nsIPrincipal *principal = NodePrincipal();
   nsCOMPtr<nsIPermissionManager> permMgr =
     services::GetPermissionManager();
   NS_ENSURE_TRUE(permMgr, NS_OK);
 
   uint32_t permission = nsIPermissionManager::DENY_ACTION;
   nsresult rv = permMgr->TestPermissionFromPrincipal(principal, "browser", &permission);
   NS_ENSURE_SUCCESS(rv, NS_OK);
-  if (permission != nsIPermissionManager::ALLOW_ACTION) {
-    rv = permMgr->TestPermissionFromPrincipal(principal, "embed-widgets", &permission);
-    NS_ENSURE_SUCCESS(rv, NS_OK);
-  }
   *aOut = permission == nsIPermissionManager::ALLOW_ACTION;
   return NS_OK;
 }
 
 /* [infallible] */ NS_IMETHODIMP
 nsGenericHTMLFrameElement::GetReallyIsApp(bool *aOut)
 {
   nsAutoString manifestURL;
--- a/dom/html/nsGenericHTMLFrameElement.h
+++ b/dom/html/nsGenericHTMLFrameElement.h
@@ -4,42 +4,39 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsGenericHTMLFrameElement_h
 #define nsGenericHTMLFrameElement_h
 
 #include "mozilla/Attributes.h"
-#include "mozilla/ErrorResult.h"
-#include "mozilla/dom/nsBrowserElement.h"
-
 #include "nsElementFrameLoaderOwner.h"
-#include "nsFrameLoader.h"
 #include "nsGenericHTMLElement.h"
-#include "nsIDOMEventListener.h"
 #include "nsIFrameLoader.h"
 #include "nsIMozBrowserFrame.h"
+#include "nsIDOMEventListener.h"
+#include "mozilla/ErrorResult.h"
+
+#include "nsFrameLoader.h"
 
 class nsXULElement;
 
 /**
  * A helper class for frame elements
  */
 class nsGenericHTMLFrameElement : public nsGenericHTMLElement,
                                   public nsElementFrameLoaderOwner,
-                                  public mozilla::nsBrowserElement,
                                   public nsIMozBrowserFrame
 {
 public:
   nsGenericHTMLFrameElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
                             mozilla::dom::FromParser aFromParser)
     : nsGenericHTMLElement(aNodeInfo)
     , nsElementFrameLoaderOwner(aFromParser)
-    , nsBrowserElement()
   {
   }
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_NSIDOMMOZBROWSERFRAME
   NS_DECL_NSIMOZBROWSERFRAME
 
@@ -70,29 +67,16 @@ public:
   virtual int32_t TabIndexDefault() MOZ_OVERRIDE;
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsGenericHTMLFrameElement,
                                                      nsGenericHTMLElement)
 
   static bool BrowserFramesEnabled();
 
   /**
-   * nsIFrameLoaderOwner defines two GetFrameLoader() overloads. One
-   * is XPCOM style interface, the other one is C++ only.  "using" pulls
-   * them both in, now GetFrameLoader() is ambiguous because
-   * nsBrowserElement also has GetFrameLoader(). Explicit redefine
-   * GetFrameLoader() to choose nsElementFrameLoaderOwner::GetFrameLoader()
-   */
-  using nsElementFrameLoaderOwner::GetFrameLoader;
-  NS_IMETHOD_(already_AddRefed<nsFrameLoader>) GetFrameLoader() MOZ_OVERRIDE
-  {
-    return nsElementFrameLoaderOwner::GetFrameLoader();
-  }
-
-  /**
    * Helper method to map a HTML 'scrolling' attribute value to a nsIScrollable
    * enum value.  scrolling="no" (and its synonyms) maps to
    * nsIScrollable::Scrollbar_Never, and anything else (including nullptr) maps
    * to nsIScrollable::Scrollbar_Auto.
    * @param aValue the attribute value to map or nullptr
    * @return nsIScrollable::Scrollbar_Never or nsIScrollable::Scrollbar_Auto
    */
   static int32_t MapScrollingAttribute(const nsAttrValue* aValue);
--- a/dom/identity/nsDOMIdentity.js
+++ b/dom/identity/nsDOMIdentity.js
@@ -96,32 +96,35 @@ nsDOMIdentity.prototype = {
     let message = this.DOMIdentityMessage(aOptions);
 
     // loggedInUser vs loggedInEmail
     // https://developer.mozilla.org/en-US/docs/DOM/navigator.id.watch
     // This parameter, loggedInUser, was renamed from loggedInEmail in early
     // September, 2012. Both names will continue to work for the time being,
     // but code should be changed to use loggedInUser instead.
     checkRenamed(aOptions, "loggedInEmail", "loggedInUser");
-    message["loggedInUser"] = aOptions["loggedInUser"];
 
-    let emailType = typeof(aOptions["loggedInUser"]);
-    if (aOptions["loggedInUser"] && aOptions["loggedInUser"] !== "undefined") {
-      if (emailType !== "string") {
+    // Bad IPC or IDL converts null and undefined to "null" and "undefined".
+    // We can't assign to aOptions, which complicates the workaround.
+    message["loggedInUser"] = aOptions["loggedInUser"];
+    if (message.loggedInUser == "null" || message.loggedInUser == "undefined") {
+      message.loggedInUser = null;
+    }
+
+    if (message.loggedInUser) {
+      if (typeof(message.loggedInUser) !== "string") {
         throw new Error("loggedInUser must be a String or null");
       }
 
       // TODO: Bug 767610 - check email format.
       // See HTMLInputElement::IsValidEmailAddress
       if (aOptions["loggedInUser"].indexOf("@") == -1
           || aOptions["loggedInUser"].length > MAX_STRING_LENGTH) {
         throw new Error("loggedInUser is not valid");
       }
-      // Set loggedInUser in this block that "undefined" doesn't get through.
-      message.loggedInUser = aOptions.loggedInUser;
     }
     this._log("loggedInUser: " + message.loggedInUser);
 
     this._rpWatcher = aOptions;
     this._rpWatcher.audience = message.audience;
 
     if (message.errors.length) {
       this.reportErrors(message);
--- a/dom/imptests/editing/implementation.js
+++ b/dom/imptests/editing/implementation.js
@@ -1968,19 +1968,19 @@ function isSimpleModifiableElement(node)
 	//
 	// The weird extra node.style.length check is for Firefox, which as of
 	// 8.0a2 has annoying and weird behavior here.
 	if (["A", "FONT", "S", "SPAN", "STRIKE", "U"].indexOf(node.tagName) != -1
 	&& node.hasAttribute("style")
 	&& (node.style.length == 1
 	|| (node.style.length == 4
 		&& "MozTextBlink" in node.style
-		&& "MozTextDecorationColor" in node.style
-		&& "MozTextDecorationLine" in node.style
-		&& "MozTextDecorationStyle" in node.style)
+		&& "textDecorationColor" in node.style
+		&& "textDecorationLine" in node.style
+		&& "textDecorationStyle" in node.style)
 	)
 	&& (node.style.textDecoration == "line-through"
 	|| node.style.textDecoration == "underline"
 	|| node.style.textDecoration == "overline"
 	|| node.style.textDecoration == "none")) {
 		return true;
 	}
 
--- a/dom/ipc/ScreenManagerParent.cpp
+++ b/dom/ipc/ScreenManagerParent.cpp
@@ -116,16 +116,21 @@ ScreenManagerParent::RecvScreenForRect(c
 }
 
 bool
 ScreenManagerParent::RecvScreenForBrowser(PBrowserParent* aBrowser,
                                           ScreenDetails* aRetVal,
                                           bool* aSuccess)
 {
   *aSuccess = false;
+#ifdef MOZ_VALGRIND
+  // Zero this so that Valgrind doesn't complain when we send it to another
+  // process.
+  memset(aRetVal, 0, sizeof(ScreenDetails));
+#endif
 
   // Find the mWidget associated with the tabparent, and then return
   // the nsIScreen it's on.
   TabParent* tabParent = static_cast<TabParent*>(aBrowser);
   nsCOMPtr<nsIWidget> widget = tabParent->GetWidget();
   if (!widget) {
     return true;
   }
--- a/dom/media/MediaRecorder.cpp
+++ b/dom/media/MediaRecorder.cpp
@@ -174,31 +174,56 @@ class MediaRecorder::Session: public nsI
       LOG(PR_LOG_DEBUG, ("Session.PushBlobRunnable s=(%p)", mSession.get()));
       MOZ_ASSERT(NS_IsMainThread());
 
       nsRefPtr<MediaRecorder> recorder = mSession->mRecorder;
       if (!recorder) {
         return NS_OK;
       }
 
-      if (mSession->IsEncoderError()) {
-        recorder->NotifyError(NS_ERROR_UNEXPECTED);
-      }
       nsresult rv = recorder->CreateAndDispatchBlobEvent(mSession->GetEncodedData());
       if (NS_FAILED(rv)) {
         recorder->NotifyError(rv);
       }
 
       return NS_OK;
     }
 
   private:
     nsRefPtr<Session> mSession;
   };
 
+  // Notify encoder error, run in main thread task. (Bug 1095381)
+  class EncoderErrorNotifierRunnable : public nsRunnable
+  {
+  public:
+    explicit EncoderErrorNotifierRunnable(Session* aSession)
+      : mSession(aSession)
+    { }
+
+    NS_IMETHODIMP Run()
+    {
+      LOG(PR_LOG_DEBUG, ("Session.ErrorNotifyRunnable s=(%p)", mSession.get()));
+      MOZ_ASSERT(NS_IsMainThread());
+
+      nsRefPtr<MediaRecorder> recorder = mSession->mRecorder;
+      if (!recorder) {
+        return NS_OK;
+      }
+
+      if (mSession->IsEncoderError()) {
+        recorder->NotifyError(NS_ERROR_UNEXPECTED);
+      }
+      return NS_OK;
+    }
+
+  private:
+    nsRefPtr<Session> mSession;
+  };
+
   // Fire start event and set mimeType, run in main thread task.
   class DispatchStartEventRunnable : public nsRunnable
   {
   public:
     DispatchStartEventRunnable(Session* aSession, const nsAString & aEventName)
       : mSession(aSession)
       , mEventName(aEventName)
     { }
@@ -331,16 +356,17 @@ class MediaRecorder::Session: public nsI
       return NS_OK;
     }
 
   private:
     // Call mSession::Release automatically while DestroyRunnable be destroy.
     nsRefPtr<Session> mSession;
   };
 
+  friend class EncoderErrorNotifierRunnable;
   friend class PushBlobRunnable;
   friend class ExtractRunnable;
   friend class DestroyRunnable;
   friend class TracksAvailableCallback;
 
 public:
   Session(MediaRecorder* aRecorder, int32_t aTimeSlice)
     : mRecorder(aRecorder),
@@ -394,17 +420,18 @@ public:
     return NS_OK;
   }
 
   nsresult RequestData()
   {
     LOG(PR_LOG_DEBUG, ("Session.RequestData"));
     MOZ_ASSERT(NS_IsMainThread());
 
-    if (NS_FAILED(NS_DispatchToMainThread(new PushBlobRunnable(this)))) {
+    if (NS_FAILED(NS_DispatchToMainThread(new EncoderErrorNotifierRunnable(this))) ||
+        NS_FAILED(NS_DispatchToMainThread(new PushBlobRunnable(this)))) {
       MOZ_ASSERT(false, "RequestData NS_DispatchToMainThread failed");
       return NS_ERROR_FAILURE;
     }
 
     return NS_OK;
   }
 
   already_AddRefed<nsIDOMBlob> GetEncodedData()
@@ -475,16 +502,19 @@ private:
     // Whether push encoded data back to onDataAvailable automatically or we
     // need a flush.
     bool pushBlob = false;
     if ((mTimeSlice > 0) &&
         ((TimeStamp::Now()-mLastBlobTimeStamp).ToMilliseconds() > mTimeSlice)) {
       pushBlob = true;
     }
     if (pushBlob || aForceFlush) {
+      if (NS_FAILED(NS_DispatchToMainThread(new EncoderErrorNotifierRunnable(this)))) {
+        MOZ_ASSERT(false, "NS_DispatchToMainThread EncoderErrorNotifierRunnable failed");
+      }
       if (NS_FAILED(NS_DispatchToMainThread(new PushBlobRunnable(this)))) {
         MOZ_ASSERT(false, "NS_DispatchToMainThread PushBlobRunnable failed");
       } else {
         mLastBlobTimeStamp = TimeStamp::Now();
       }
     }
   }
 
@@ -571,16 +601,19 @@ private:
   void DoSessionEndTask(nsresult rv)
   {
     MOZ_ASSERT(NS_IsMainThread());
     if (NS_FAILED(rv)) {
       mRecorder->NotifyError(rv);
     }
 
     CleanupStreams();
+    if (NS_FAILED(NS_DispatchToMainThread(new EncoderErrorNotifierRunnable(this)))) {
+      MOZ_ASSERT(false, "NS_DispatchToMainThread EncoderErrorNotifierRunnable failed");
+    }
     if (NS_FAILED(NS_DispatchToMainThread(new PushBlobRunnable(this)))) {
       MOZ_ASSERT(false, "NS_DispatchToMainThread PushBlobRunnable failed");
     }
     if (NS_FAILED(NS_DispatchToMainThread(new DestroyRunnable(this)))) {
       MOZ_ASSERT(false, "NS_DispatchToMainThread DestroyRunnable failed");
     }
   }
   void CleanupStreams()
--- a/dom/media/MediaStreamGraph.cpp
+++ b/dom/media/MediaStreamGraph.cpp
@@ -60,17 +60,17 @@ PRLogModuleInfo* gMediaStreamGraphLog;
 #  endif
 #else
 #  define LIFECYCLE_LOG(...)
 #endif
 
 /**
  * The singleton graph instance.
  */
-static MediaStreamGraphImpl* gGraph;
+static nsDataHashtable<nsUint32HashKey, MediaStreamGraphImpl*> gGraphs;
 
 MediaStreamGraphImpl::~MediaStreamGraphImpl()
 {
   NS_ASSERTION(IsEmpty(),
                "All streams should have been destroyed by messages from the main thread");
   STREAM_LOG(PR_LOG_DEBUG, ("MediaStreamGraph %p destroyed", this));
   LIFECYCLE_LOG("MediaStreamGraphImpl::~MediaStreamGraphImpl\n");
 }
@@ -1631,19 +1631,20 @@ MediaStreamGraphImpl::RunInStableState(b
         // synchronously because it spins the event loop waiting for threads
         // to shut down, and we don't want to do that in a stable state handler.
         mLifecycleState = LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN;
         LIFECYCLE_LOG("Sending MediaStreamGraphShutDownRunnable %p", this);
         nsCOMPtr<nsIRunnable> event = new MediaStreamGraphShutDownRunnable(this );
         NS_DispatchToMainThread(event);
 
         LIFECYCLE_LOG("Disconnecting MediaStreamGraph %p", this);
-        if (this == gGraph) {
+        MediaStreamGraphImpl* graph;
+        if (gGraphs.Get(mAudioChannel, &graph) && graph == this) {
           // null out gGraph if that's the graph being shut down
-          gGraph = nullptr;
+          gGraphs.Remove(mAudioChannel);
         }
       }
     } else {
       if (mLifecycleState <= LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP) {
         MessageBlock* block = mBackMessageQueue.AppendElement();
         block->mMessages.SwapElements(mCurrentTaskMessageQueue);
         block->mGraphUpdateIndex = mNextGraphUpdateIndex;
         ++mNextGraphUpdateIndex;
@@ -1784,19 +1785,22 @@ MediaStreamGraphImpl::AppendMessage(Cont
 #endif
     aMessage->RunDuringShutdown();
 #ifdef DEBUG
     mCanRunMessagesSynchronously = true;
 #endif
     delete aMessage;
     if (IsEmpty() &&
         mLifecycleState >= LIFECYCLE_WAITING_FOR_STREAM_DESTRUCTION) {
-      if (gGraph == this) {
-        gGraph = nullptr;
+
+      MediaStreamGraphImpl* graph;
+      if (gGraphs.Get(mAudioChannel, &graph) && graph == this) {
+        gGraphs.Remove(mAudioChannel);
       }
+
       Destroy();
     }
     return;
   }
 
   mCurrentTaskMessageQueue.AppendElement(aMessage);
   EnsureRunInStableState();
 }
@@ -2736,16 +2740,17 @@ MediaStreamGraphImpl::MediaStreamGraphIm
 #endif
   , mMemoryReportMonitor("MSGIMemory")
   , mSelfRef(MOZ_THIS_IN_INITIALIZER_LIST())
   , mAudioStreamSizes()
   , mNeedsMemoryReport(false)
 #ifdef DEBUG
   , mCanRunMessagesSynchronously(false)
 #endif
+  , mAudioChannel(static_cast<uint32_t>(aChannel))
 {
 #ifdef PR_LOGGING
   if (!gMediaStreamGraphLog) {
     gMediaStreamGraphLog = PR_NewLogModule("MediaStreamGraph");
   }
 #endif
 
   if (mRealtime) {
@@ -2774,50 +2779,65 @@ MediaStreamGraphImpl::Destroy()
   // Clear the self reference which will destroy this instance.
   mSelfRef = nullptr;
 }
 
 NS_IMPL_ISUPPORTS(MediaStreamGraphShutdownObserver, nsIObserver)
 
 static bool gShutdownObserverRegistered = false;
 
+namespace {
+
+PLDHashOperator
+ForceShutdownEnumerator(const uint32_t& /* aAudioChannel */,
+                        MediaStreamGraphImpl* aGraph,
+                        void* /* aUnused */)
+{
+  aGraph->ForceShutDown();
+  return PL_DHASH_NEXT;
+}
+
+} // anonymous namespace
+
 NS_IMETHODIMP
 MediaStreamGraphShutdownObserver::Observe(nsISupports *aSubject,
                                           const char *aTopic,
                                           const char16_t *aData)
 {
   if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
-    if (gGraph) {
-      gGraph->ForceShutDown();
-    }
+    gGraphs.EnumerateRead(ForceShutdownEnumerator, nullptr);
     nsContentUtils::UnregisterShutdownObserver(this);
     gShutdownObserverRegistered = false;
   }
   return NS_OK;
 }
 
 MediaStreamGraph*
 MediaStreamGraph::GetInstance(DOMMediaStream::TrackTypeHints aHint, dom::AudioChannel aChannel)
 {
   NS_ASSERTION(NS_IsMainThread(), "Main thread only");
 
-  if (!gGraph) {
+  uint32_t channel = static_cast<uint32_t>(aChannel);
+  MediaStreamGraphImpl* graph = nullptr;
+
+  if (!gGraphs.Get(channel, &graph)) {
     if (!gShutdownObserverRegistered) {
       gShutdownObserverRegistered = true;
       nsContentUtils::RegisterShutdownObserver(new MediaStreamGraphShutdownObserver());
     }
 
     CubebUtils::InitPreferredSampleRate();
 
-    gGraph = new MediaStreamGraphImpl(true, CubebUtils::PreferredSampleRate(), aHint, aChannel);
+    graph = new MediaStreamGraphImpl(true, CubebUtils::PreferredSampleRate(), aHint, aChannel);
+    gGraphs.Put(channel, graph);
 
-    STREAM_LOG(PR_LOG_DEBUG, ("Starting up MediaStreamGraph %p", gGraph));
+    STREAM_LOG(PR_LOG_DEBUG, ("Starting up MediaStreamGraph %p", graph));
   }
 
-  return gGraph;
+  return graph;
 }
 
 MediaStreamGraph*
 MediaStreamGraph::CreateNonRealtimeInstance(TrackRate aSampleRate)
 {
   NS_ASSERTION(NS_IsMainThread(), "Main thread only");
 
   MediaStreamGraphImpl* graph = new MediaStreamGraphImpl(false, aSampleRate);
@@ -2990,17 +3010,20 @@ MediaStreamGraph::CreateAudioNodeStream(
   }
   graph->AppendMessage(new CreateMessage(stream));
   return stream;
 }
 
 bool
 MediaStreamGraph::IsNonRealtime() const
 {
-  return this != gGraph;
+  const MediaStreamGraphImpl* impl = static_cast<const MediaStreamGraphImpl*>(this);
+  MediaStreamGraphImpl* graph;
+
+  return !gGraphs.Get(impl->AudioChannel(), &graph) || graph != impl;
 }
 
 void
 MediaStreamGraph::StartNonRealtimeProcessing(TrackRate aRate, uint32_t aTicksToProcess)
 {
   NS_ASSERTION(NS_IsMainThread(), "main thread only");
 
   MediaStreamGraphImpl* graph = static_cast<MediaStreamGraphImpl*>(this);
--- a/dom/media/MediaStreamGraphImpl.h
+++ b/dom/media/MediaStreamGraphImpl.h
@@ -656,16 +656,18 @@ public:
    * Hold a ref to the Latency logger
    */
   nsRefPtr<AsyncLatencyLogger> mLatencyLog;
   AudioMixer mMixer;
 #ifdef MOZ_WEBRTC
   nsRefPtr<AudioOutputObserver> mFarendObserverRef;
 #endif
 
+  uint32_t AudioChannel() const { return mAudioChannel; }
+
 private:
   virtual ~MediaStreamGraphImpl();
 
   MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
 
   /**
    * Used to signal that a memory report has been requested.
    */
@@ -689,13 +691,16 @@ private:
 
 #ifdef DEBUG
   /**
    * Used to assert when AppendMessage() runs ControlMessages synchronously.
    */
   bool mCanRunMessagesSynchronously;
 #endif
 
+  // We use uint32_t instead AudioChannel because this is just used as key for
+  // the hashtable gGraphs.
+  uint32_t mAudioChannel;
 };
 
 }
 
 #endif /* MEDIASTREAMGRAPHIMPL_H_ */
--- a/dom/media/fmp4/android/AndroidDecoderModule.cpp
+++ b/dom/media/fmp4/android/AndroidDecoderModule.cpp
@@ -53,17 +53,17 @@ public:
       printf_stderr("Failed to create SurfaceTexture for video decode\n");
       return NS_ERROR_FAILURE;
     }
 
     return InitDecoder(mSurfaceTexture->JavaSurface());
   }
 
   virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE {
-    mp4_demuxer::AnnexB::ConvertSample(aSample, mConfig.annex_b);
+    mp4_demuxer::AnnexB::ConvertSample(aSample);
     return MediaCodecDataDecoder::Input(aSample);
   }
 
   virtual nsresult PostOutput(BufferInfo* aInfo, MediaFormat* aFormat, Microseconds aDuration) MOZ_OVERRIDE {
     VideoInfo videoInfo;
     videoInfo.mDisplay = nsIntSize(mConfig.display_width, mConfig.display_height);
 
     bool isSync = false;
--- a/dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp
+++ b/dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp
@@ -48,17 +48,16 @@ enum {
   kNotifyCodecReserved = 'core',
   kNotifyCodecCanceled = 'coca',
 };
 
 GonkVideoDecoderManager::GonkVideoDecoderManager(
                            mozilla::layers::ImageContainer* aImageContainer,
 		           const mp4_demuxer::VideoDecoderConfig& aConfig)
   : mImageContainer(aImageContainer)
-  , mConfig(aConfig)
   , mReaderCallback(nullptr)
   , mColorConverterBufferSize(0)
   , mNativeWindow(nullptr)
   , mPendingVideoBuffersLock("GonkVideoDecoderManager::mPendingVideoBuffersLock")
 {
   NS_ASSERTION(!NS_IsMainThread(), "Should not be on main thread.");
   MOZ_ASSERT(mImageContainer);
   MOZ_COUNT_CTOR(GonkVideoDecoderManager);
@@ -391,17 +390,17 @@ GonkVideoDecoderManager::Input(mp4_demux
 {
   if (mDecoder == nullptr) {
     ALOG("Decoder is not inited");
     return NS_ERROR_UNEXPECTED;
   }
   status_t rv;
   if (aSample != nullptr) {
     // We must prepare samples in AVC Annex B.
-    mp4_demuxer::AnnexB::ConvertSample(aSample, mConfig.annex_b);
+    mp4_demuxer::AnnexB::ConvertSample(aSample);
     // Forward sample data to the decoder.
 
     const uint8_t* data = reinterpret_cast<const uint8_t*>(aSample->data);
     uint32_t length = aSample->size;
     rv = mDecoder->Input(data, length, aSample->composition_timestamp, 0);
   }
   else {
     // Inputted data is null, so it is going to notify decoder EOS
--- a/dom/media/fmp4/gonk/GonkVideoDecoderManager.h
+++ b/dom/media/fmp4/gonk/GonkVideoDecoderManager.h
@@ -110,17 +110,16 @@ private:
   // For codec resource management
   void codecReserved();
   void codecCanceled();
   void onMessageReceived(const sp<AMessage> &aMessage);
 
   void ReleaseAllPendingVideoBuffersLocked();
   void PostReleaseVideoBuffer(android::MediaBuffer *aBuffer);
 
-  const mp4_demuxer::VideoDecoderConfig& mConfig;
   uint32_t mVideoWidth;
   uint32_t mVideoHeight;
   uint32_t mDisplayWidth;
   uint32_t mDisplayHeight;
   nsIntRect mPicture;
   nsIntSize mInitialFrame;
 
   android::sp<MediaCodecProxy> mDecoder;
--- a/dom/media/fmp4/wmf/WMFVideoMFTManager.cpp
+++ b/dom/media/fmp4/wmf/WMFVideoMFTManager.cpp
@@ -35,17 +35,16 @@ namespace mozilla {
 WMFVideoMFTManager::WMFVideoMFTManager(
                             const mp4_demuxer::VideoDecoderConfig& aConfig,
                             mozilla::layers::LayersBackend aLayersBackend,
                             mozilla::layers::ImageContainer* aImageContainer,
                             bool aDXVAEnabled)
   : mVideoStride(0)
   , mVideoWidth(0)
   , mVideoHeight(0)
-  , mConfig(aConfig)
   , mImageContainer(aImageContainer)
   , mDXVAEnabled(aDXVAEnabled)
   , mLayersBackend(aLayersBackend)
   , mUseHwAccel(false)
 {
   NS_ASSERTION(!NS_IsMainThread(), "Should not be on main thread.");
   MOZ_ASSERT(mImageContainer);
   MOZ_COUNT_CTOR(WMFVideoMFTManager);
@@ -142,17 +141,17 @@ WMFVideoMFTManager::Init()
 
   return decoder.forget();
 }
 
 HRESULT
 WMFVideoMFTManager::Input(mp4_demuxer::MP4Sample* aSample)
 {
   // We must prepare samples in AVC Annex B.
-  mp4_demuxer::AnnexB::ConvertSample(aSample, mConfig.annex_b);
+  mp4_demuxer::AnnexB::ConvertSample(aSample);
   // Forward sample data to the decoder.
   const uint8_t* data = reinterpret_cast<const uint8_t*>(aSample->data);
   uint32_t length = aSample->size;
   return mDecoder->Input(data, length, aSample->composition_timestamp);
 }
 
 HRESULT
 WMFVideoMFTManager::ConfigureVideoFrameGeometry()
--- a/dom/media/fmp4/wmf/WMFVideoMFTManager.h
+++ b/dom/media/fmp4/wmf/WMFVideoMFTManager.h
@@ -51,18 +51,16 @@ private:
 
   // Video frame geometry.
   VideoInfo mVideoInfo;
   uint32_t mVideoStride;
   uint32_t mVideoWidth;
   uint32_t mVideoHeight;
   nsIntRect mPictureRegion;
 
-  const mp4_demuxer::VideoDecoderConfig& mConfig;
-
   RefPtr<MFTDecoder> mDecoder;
   RefPtr<layers::ImageContainer> mImageContainer;
   nsAutoPtr<DXVA2Manager> mDXVA2Manager;
   RefPtr<MediaTaskQueue> mTaskQueue;
   MediaDataDecoderCallback* mCallback;
 
   const bool mDXVAEnabled;
   const layers::LayersBackend mLayersBackend;
--- a/dom/media/omx/MediaCodecReader.cpp
+++ b/dom/media/omx/MediaCodecReader.cpp
@@ -277,20 +277,16 @@ MediaCodecReader::ProcessCachedDataTask:
   MOZ_ASSERT(mReader, "Should have a valid MediaCodecReader.");
   MOZ_ASSERT(mOffset >= INT64_C(0), "Should have a valid offset.");
 }
 
 void
 MediaCodecReader::ProcessCachedDataTask::Run()
 {
   mReader->ProcessCachedData(mOffset, nullptr);
-  nsRefPtr<ReferenceKeeperRunnable<MediaCodecReader>> runnable(
-      new ReferenceKeeperRunnable<MediaCodecReader>(mReader));
-  mReader = nullptr;
-  NS_DispatchToMainThread(runnable.get());
 }
 
 MediaCodecReader::MediaCodecReader(AbstractMediaDecoder* aDecoder)
   : MediaOmxCommonReader(aDecoder)
   , mExtractor(nullptr)
   , mIsWaitingResources(false)
   , mTextureClientIndexesLock("MediaCodecReader::mTextureClientIndexesLock")
   , mColorConverterBufferSize(0)
@@ -300,17 +296,16 @@ MediaCodecReader::MediaCodecReader(Abstr
   , mParsedDataLength(INT64_C(0))
 {
   mHandler = new MessageHandler(this);
   mVideoListener = new VideoResourceListener(this);
 }
 
 MediaCodecReader::~MediaCodecReader()
 {
-  MOZ_ASSERT(NS_IsMainThread(), "Should be on main thread.");
 }
 
 nsresult
 MediaCodecReader::Init(MediaDecoderReader* aCloneDonor)
 {
   return NS_OK;
 }
 
--- a/dom/media/omx/MediaCodecReader.h
+++ b/dom/media/omx/MediaCodecReader.h
@@ -333,47 +333,16 @@ private:
     ProcessCachedDataTask(const ProcessCachedDataTask &rhs) MOZ_DELETE;
     const ProcessCachedDataTask &operator=(const ProcessCachedDataTask &rhs) MOZ_DELETE;
 
     nsRefPtr<MediaCodecReader> mReader;
     int64_t mOffset;
   };
   friend class ProcessCachedDataTask;
 
-  // This class is used to keep one reference count of T in it. And this class
-  // can make sure the stored reference count will be released on the dispatched
-  // thread. By using this class properly (ex. passing the pointer into this
-  // runnable first, then releasing the original pointer held by ourselves, and
-  // then dispatching this runnable onto the desired thread), we can avoid
-  // running the destructor of the referenced object on any other threads
-  // unexpectedly before this runnable has been executed.
-  template<class T>
-  class ReferenceKeeperRunnable : public nsRunnable
-  {
-  public:
-    ReferenceKeeperRunnable(nsRefPtr<T> aPointer)
-      : mPointer(aPointer)
-    {
-    }
-
-    NS_IMETHOD Run() MOZ_OVERRIDE
-    {
-      mPointer = nullptr;
-      return NS_OK;
-    }
-
-  private:
-    // Forbidden
-    ReferenceKeeperRunnable() MOZ_DELETE;
-    ReferenceKeeperRunnable(const ReferenceKeeperRunnable &rhs) MOZ_DELETE;
-    const ReferenceKeeperRunnable &operator=(const ReferenceKeeperRunnable &rhs) MOZ_DELETE;
-
-    nsRefPtr<T> mPointer;
-  };
-
   // Forbidden
   MediaCodecReader() MOZ_DELETE;
   const MediaCodecReader& operator=(const MediaCodecReader& rhs) MOZ_DELETE;
 
   bool ReallocateResources();
   void ReleaseCriticalResources();
   void ReleaseResources();
 
--- a/dom/media/tests/mochitest/pc.js
+++ b/dom/media/tests/mochitest/pc.js
@@ -2578,16 +2578,58 @@ PeerConnectionWrapper.prototype = {
       ok(numRemoteCandidates, "Have remotecandidate stat(s)");
     } else {
       is(numLocalCandidates, 0, "Have no localcandidate stats");
       is(numRemoteCandidates, 0, "Have no remotecandidate stats");
     }
   },
 
   /**
+   * Compares the Ice server configured for this PeerConnectionWrapper
+   * with the ICE candidates received in the RTCP stats.
+   *
+   * @param {object} stats
+   *        The stats to be verified for relayed vs. direct connection.
+   */
+  checkStatsIceConnectionType : function PCW_checkStatsIceConnectionType(stats)
+  {
+    var lId;
+    var rId;
+    Object.keys(stats).forEach(function(name) {
+      if ((stats[name].type === "candidatepair") &&
+          (stats[name].selected)) {
+        lId = stats[name].localCandidateId;
+        rId = stats[name].remoteCandidateId;
+      }
+    });
+    info("checkStatsIceConnectionType verifying: local=" +
+         JSON.stringify(stats[lId]) + " remote=" + JSON.stringify(stats[rId]));
+    if ((typeof stats[lId] === 'undefined') ||
+        (typeof stats[rId] === 'undefined')) {
+      info("checkStatsIceConnectionType failed to find candidatepair IDs");
+      return;
+    }
+    var lType = stats[lId].candidateType;
+    var rType = stats[rId].candidateType;
+    var lIp = stats[lId].ipAddress;
+    var rIp = stats[rId].ipAddress;
+    if ((this.configuration) && (typeof this.configuration.iceServers !== 'undefined')) {
+      info("Ice Server configured");
+      // Note: the IP comparising is a workaround for bug 1097333
+      //       And this will fail if a TURN server address is a DNS name!
+      var serverIp = this.configuration.iceServers[0].url.split(':')[1];
+      ok((lType === "relayed" || rType === "relayed") ||
+         (lIp === serverIp || rIp === serverIp), "One peer uses a relay");
+    } else {
+      info("P2P configured");
+      ok(((lType !== "relayed") && (rType !== "relayed")), "Pure peer to peer call without a relay");
+    }
+  },
+
+  /**
    * Property-matching function for finding a certain stat in passed-in stats
    *
    * @param {object} stats
    *        The stats to check from this PeerConnectionWrapper
    * @param {object} props
    *        The properties to look for
    * @returns {boolean} Whether an entry containing all match-props was found.
    */
--- a/dom/media/tests/mochitest/templates.js
+++ b/dom/media/tests/mochitest/templates.js
@@ -19,16 +19,27 @@ function deltaSeconds(date1, date2) {
 function dumpSdp(test) {
   if (typeof test._local_offer !== 'undefined') {
     dump("ERROR: SDP offer: " + test._local_offer.sdp.replace(/[\r]/g, ''));
   }
   if (typeof test._remote_answer !== 'undefined') {
     dump("ERROR: SDP answer: " + test._remote_answer.sdp.replace(/[\r]/g, ''));
   }
 
+  if ((test.pcLocal) && (typeof test.pcLocal._local_ice_candidates !== 'undefined')) {
+    dump("pcLocal._local_ice_candidates: " + JSON.stringify(test.pcLocal._local_ice_candidates) + "\n");
+    dump("pcLocal._remote_ice_candidates: " + JSON.stringify(test.pcLocal._remote_ice_candidates) + "\n");
+    dump("pcLocal._ice_candidates_to_add: " + JSON.stringify(test.pcLocal._ice_candidates_to_add) + "\n");
+  }
+  if ((test.pcRemote) && (typeof test.pcRemote._local_ice_candidates !== 'undefined')) {
+    dump("pcRemote._local_ice_candidates: " + JSON.stringify(test.pcRemote._local_ice_candidates) + "\n");
+    dump("pcRemote._remote_ice_candidates: " + JSON.stringify(test.pcRemote._remote_ice_candidates) + "\n");
+    dump("pcRemote._ice_candidates_to_add: " + JSON.stringify(test.pcRemote._ice_candidates_to_add) + "\n");
+  }
+
   if ((test.pcLocal) && (typeof test.pcLocal.iceConnectionLog !== 'undefined')) {
     dump("pcLocal ICE connection state log: " + test.pcLocal.iceConnectionLog + "\n");
   }
   if ((test.pcRemote) && (typeof test.pcRemote.iceConnectionLog !== 'undefined')) {
     dump("pcRemote ICE connection state log: " + test.pcRemote.iceConnectionLog + "\n");
   }
 
   if ((test.pcLocal) && (test.pcRemote) &&
@@ -488,16 +499,34 @@ var commandsPeerConnection = [
     function (test) {
       test.pcRemote.getStats(null, function(stats) {
         test.pcRemote.checkStats(stats, test.steeplechase);
         test.next();
       });
     }
   ],
   [
+    'PC_LOCAL_CHECK_ICE_CONNECTION_TYPE',
+    function (test) {
+      test.pcLocal.getStats(null, function(stats) {
+        test.pcLocal.checkStatsIceConnectionType(stats);
+        test.next();
+      });
+    }
+  ],
+  [
+    'PC_REMOTE_CHECK_ICE_CONNECTION_TYPE',
+    function (test) {
+      test.pcRemote.getStats(null, function(stats) {
+        test.pcRemote.checkStatsIceConnectionType(stats);
+        test.next();
+      });
+    }
+  ],
+  [
     'PC_LOCAL_CHECK_GETSTATS_AUDIOTRACK_OUTBOUND',
     function (test) {
       var pc = test.pcLocal;
       var stream = pc._pc.getLocalStreams()[0];
       var track = stream && stream.getAudioTracks()[0];
       if (track) {
         var msg = "pcLocal.HasStat outbound audio rtp ";
         pc.getStats(track, function(stats) {
--- a/dom/media/tests/mochitest/turnConfig.js
+++ b/dom/media/tests/mochitest/turnConfig.js
@@ -1,12 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* An example of how to specify two TURN server configs:
+ *
+ * Note: If turn URL uses FQDN rather then an IP address the TURN relay
+ *       verification step in checkStatsIceConnectionType might fail.
+ *
  * var turnServers = {
  *   local: { iceServers: [{"username":"mozilla","credential":"mozilla","url":"turn:10.0.0.1"}] },
  *   remote: { iceServers: [{"username":"firefox","credential":"firefox","url":"turn:10.0.0.2"}] }
  * };
   */
 
 var turnServers = { };
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -664,22 +664,16 @@ AudioContext::Unmute() const
 }
 
 AudioChannel
 AudioContext::MozAudioChannelType() const
 {
   return mDestination->MozAudioChannelType();
 }
 
-void
-AudioContext::SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv)
-{
-  mDestination->SetMozAudioChannelType(aValue, aRv);
-}
-
 AudioChannel
 AudioContext::TestAudioChannelInAudioNodeStream()
 {
   MediaStream* stream = mDestination->Stream();
   MOZ_ASSERT(stream);
 
   return stream->AudioChannelType();
 }
--- a/dom/media/webaudio/AudioContext.h
+++ b/dom/media/webaudio/AudioContext.h
@@ -219,17 +219,16 @@ public:
   uint32_t MaxChannelCount() const;
 
   void Mute() const;
   void Unmute() const;
 
   JSObject* GetGlobalJSObject() const;
 
   AudioChannel MozAudioChannelType() const;
-  void SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv);
 
   AudioChannel TestAudioChannelInAudioNodeStream();
 
   void UpdateNodeCount(int32_t aDelta);
 
   double DOMTimeToStreamTime(double aTime) const
   {
     return aTime - ExtraCurrentTime();
--- a/dom/media/webaudio/test/test_mozaudiochannel.html
+++ b/dom/media/webaudio/test/test_mozaudiochannel.html
@@ -13,37 +13,33 @@
 
 function test_basic() {
   var ac = new AudioContext();
   ok(ac, "AudioContext created");
 
   // Default
   is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
 
-  // random wrong channel
-  ac.mozAudioChannelType = "foo";
+  // Unpermitted channels
+  ac = new AudioContext("content");
   is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
 
-  // Unpermitted channels
-  ac.mozAudioChannelType = "content";
-  is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
-
-  ac.mozAudioChannelType = "notification";
+  ac = new AudioContext("notification");
   is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
 
-  ac.mozAudioChannelType = "alarm";
+  ac = new AudioContext("alarm");
   is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
 
-  ac.mozAudioChannelType = "telephony";
+  ac = new AudioContext("telephony");
   is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
 
-  ac.mozAudioChannelType = "ringer";
+  ac = new AudioContext("ringer");
   is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
 
-  ac.mozAudioChannelType = "publicnotification";
+  ac = new AudioContext("publicnotification");
   is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
 
   runTest();
 }
 
 function test_permission(aChannel) {
   var ac = new AudioContext();
   ok(ac, "AudioContext created");
@@ -51,17 +47,17 @@ function test_permission(aChannel) {
   is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
 
   var channel = SpecialPowers.wrap(ac).testAudioChannelInAudioNodeStream();
   is(channel, "normal", "AudioNodeStream is using the correct default audio channel.");
 
   SpecialPowers.pushPermissions(
     [{ "type": "audio-channel-" + aChannel, "allow": true, "context": document }],
     function() {
-      ac.mozAudioChannelType = aChannel;
+      var ac = new AudioContext(aChannel);
       is(ac.mozAudioChannelType, aChannel, "Default ac channel == '" + aChannel + "'");
 
       var channel = SpecialPowers.wrap(ac).testAudioChannelInAudioNodeStream();
       is(channel, aChannel, "AudioNodeStream is using the correct new audio channel.");
 
       runTest();
     }
   );
@@ -142,13 +138,14 @@ function runTest() {
   }
 
   var test = tests.shift();
   test();
 }
 
 SpecialPowers.pushPrefEnv({"set": [["media.useAudioChannelService", true ]]}, runTest);
 SimpleTest.waitForExplicitFinish();
+SimpleTest.requestLongerTimeout(5);
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/mobileconnection/Assertions.cpp
+++ b/dom/mobileconnection/Assertions.cpp
@@ -52,10 +52,22 @@ ASSERT_PREFERRED_NETWORK_TYPE_EQUALITY(L
                 "MobileRoamingMode::" #webidlState " should equal to nsIMobileConnection::" #xpidlState)
 
 ASSERT_MOBILE_ROAMING_MODE_EQUALITY(Home, CDMA_ROAMING_PREFERENCE_HOME);
 ASSERT_MOBILE_ROAMING_MODE_EQUALITY(Affiliated, CDMA_ROAMING_PREFERENCE_AFFILIATED);
 ASSERT_MOBILE_ROAMING_MODE_EQUALITY(Any, CDMA_ROAMING_PREFERENCE_ANY);
 
 #undef ASSERT_MOBILE_ROAMING_MODE_EQUALITY
 
+#define ASSERT_MOBILE_NETWORK_TYPE_EQUALITY(webidlState, xpidlState) \
+  static_assert(static_cast<int32_t>(MobileNetworkType::webidlState) == nsIMobileConnection::xpidlState, \
+                "MobileNetworkType::" #webidlState " should equal to nsIMobileConnection::" #xpidlState)
+
+ASSERT_MOBILE_NETWORK_TYPE_EQUALITY(Gsm, MOBILE_NETWORK_TYPE_GSM);
+ASSERT_MOBILE_NETWORK_TYPE_EQUALITY(Wcdma, MOBILE_NETWORK_TYPE_WCDMA);
+ASSERT_MOBILE_NETWORK_TYPE_EQUALITY(Cdma, MOBILE_NETWORK_TYPE_CDMA);
+ASSERT_MOBILE_NETWORK_TYPE_EQUALITY(Evdo, MOBILE_NETWORK_TYPE_EVDO);
+ASSERT_MOBILE_NETWORK_TYPE_EQUALITY(Lte, MOBILE_NETWORK_TYPE_LTE);
+
+#undef ASSERT_MOBILE_NETWORK_TYPE_EQUALITY
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/mobileconnection/MobileConnection.cpp
+++ b/dom/mobileconnection/MobileConnection.cpp
@@ -373,33 +373,30 @@ MobileConnection::GetRadioState() const
 
 void
 MobileConnection::GetSupportedNetworkTypes(nsTArray<MobileNetworkType>& aTypes) const
 {
   if (!mMobileConnection) {
     return;
   }
 
-  char16_t** types = nullptr;
+  int32_t* types = nullptr;
   uint32_t length = 0;
 
   nsresult rv = mMobileConnection->GetSupportedNetworkTypes(&types, &length);
   NS_ENSURE_SUCCESS_VOID(rv);
 
   for (uint32_t i = 0; i < length; ++i) {
-    nsDependentString rawType(types[i]);
-    Nullable<MobileNetworkType> type = Nullable<MobileNetworkType>();
-    CONVERT_STRING_TO_NULLABLE_ENUM(rawType, MobileNetworkType, type);
+    int32_t type = types[i];
 
-    if (!type.IsNull()) {
-      aTypes.AppendElement(type.Value());
-    }
+    MOZ_ASSERT(type < static_cast<int32_t>(MobileNetworkType::EndGuard_));
+    aTypes.AppendElement(static_cast<MobileNetworkType>(type));
   }
 
-  NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(length, types);
+  nsMemory::Free(types);
 }
 
 already_AddRefed<DOMRequest>
 MobileConnection::GetNetworks(ErrorResult& aRv)
 {
   if (!mMobileConnection) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
--- a/dom/mobileconnection/gonk/MobileConnectionService.js
+++ b/dom/mobileconnection/gonk/MobileConnectionService.js
@@ -393,32 +393,36 @@ MobileConnectionProvider.prototype = {
       if (DEBUG) this._debug("Fallback to " + key + ": " + index);
 
       let networkTypes = RIL.RIL_PREFERRED_NETWORK_TYPE_TO_GECKO[index];
       supportedNetworkTypes = networkTypes ?
         networkTypes.replace("-auto", "", "g").split("/") :
         RIL.GECKO_SUPPORTED_NETWORK_TYPES_DEFAULT.split(",");
     }
 
+    let enumNetworkTypes = [];
     for (let type of supportedNetworkTypes) {
       // If the value in system property is not valid, use the default one which
       // is defined in ril_consts.js.
       if (RIL.GECKO_SUPPORTED_NETWORK_TYPES.indexOf(type) < 0) {
         if (DEBUG) {
           this._debug("Unknown network type: " + type);
         }
-        supportedNetworkTypes =
-          RIL.GECKO_SUPPORTED_NETWORK_TYPES_DEFAULT.split(",");
+        RIL.GECKO_SUPPORTED_NETWORK_TYPES_DEFAULT.split(",").forEach(aType => {
+          enumNetworkTypes.push(RIL.GECKO_SUPPORTED_NETWORK_TYPES.indexOf(aType));
+        });
         break;
       }
+      enumNetworkTypes.push(RIL.GECKO_SUPPORTED_NETWORK_TYPES.indexOf(type));
     }
     if (DEBUG) {
-      this._debug("Supported Network Types: " + supportedNetworkTypes);
+      this._debug("Supported Network Types: " + enumNetworkTypes);
     }
-    return supportedNetworkTypes;
+
+    return enumNetworkTypes;
   },
 
   /**
    * Helper for guarding us against invalid mode for clir.
    */
   _isValidClirMode: function(aMode) {
     switch (aMode) {
       case Ci.nsIMobileConnection.CLIR_DEFAULT:
--- a/dom/mobileconnection/interfaces/nsIMobileConnectionService.idl
+++ b/dom/mobileconnection/interfaces/nsIMobileConnectionService.idl
@@ -230,17 +230,17 @@ interface nsIMobileConnectionService : n
 
 %{C++
 template<typename T> struct already_AddRefed;
 
 already_AddRefed<nsIMobileConnectionService>
 NS_CreateMobileConnectionService();
 %}
 
-[scriptable, uuid(5250a0ba-19a2-4e5b-a5ee-1e69ba2897a9)]
+[scriptable, uuid(99e43353-5fc4-497e-88a2-5fa6862ee64c)]
 interface nsIMobileConnection : nsISupports
 {
   /*
    * ICC service class.
    */
   const long ICC_SERVICE_CLASS_NONE       = 0; // not available
   const long ICC_SERVICE_CLASS_VOICE      = (1 << 0);
   const long ICC_SERVICE_CLASS_DATA       = (1 << 1);
@@ -330,16 +330,25 @@ interface nsIMobileConnection : nsISuppo
 
   /**
    * CDMA roaming preference.
    */
   const long CDMA_ROAMING_PREFERENCE_HOME       = 0;
   const long CDMA_ROAMING_PREFERENCE_AFFILIATED = 1;
   const long CDMA_ROAMING_PREFERENCE_ANY        = 2;
 
+  /**
+   * Supported network type.
+   */
+  const long MOBILE_NETWORK_TYPE_GSM   = 0;
+  const long MOBILE_NETWORK_TYPE_WCDMA = 1;
+  const long MOBILE_NETWORK_TYPE_CDMA  = 2;
+  const long MOBILE_NETWORK_TYPE_EVDO  = 3;
+  const long MOBILE_NETWORK_TYPE_LTE   = 4;
+
   readonly attribute unsigned long serviceId;
 
   /**
    * Called when any one who is interested in receiving unsolicited messages
    * from this nsIMobileConnection instance.
    */
   void registerListener(in nsIMobileConnectionListener listener);
   void unregisterListener(in nsIMobileConnectionListener listener);
@@ -381,20 +390,19 @@ interface nsIMobileConnection : nsISuppo
    * Current radio state. One of the nsIMobileConnection.MOBILE_RADIO_STATE_*
    * values.
    */
   readonly attribute long radioState;
 
   /**
    * The network types supported by this radio.
    *
-   * @return an array of DOMString
-   *         Possible values: 'gsm', 'wcdma', 'cdma', 'evdo', 'lte'.
+   * @return an array of nsIMobileConnection.MOBILE_NETWORK_TYPE_* values.
    */
-  void getSupportedNetworkTypes([array, size_is(length)] out wstring types,
+  void getSupportedNetworkTypes([array, size_is(length)] out long types,
                                 [retval] out unsigned long length);
 
   /**
    * Search for available networks.
    *
    * @param requestCallback
    *        Called when request is finished.
    *
--- a/dom/mobileconnection/ipc/MobileConnectionChild.cpp
+++ b/dom/mobileconnection/ipc/MobileConnectionChild.cpp
@@ -108,29 +108,29 @@ MobileConnectionChild::GetIccId(nsAStrin
 NS_IMETHODIMP
 MobileConnectionChild::GetRadioState(int32_t* aRadioState)
 {
   *aRadioState = mRadioState;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-MobileConnectionChild::GetSupportedNetworkTypes(char16_t*** aTypes,
+MobileConnectionChild::GetSupportedNetworkTypes(int32_t** aTypes,
                                                 uint32_t* aLength)
 {
   NS_ENSURE_ARG(aTypes);
   NS_ENSURE_ARG(aLength);
 
   *aLength = mSupportedNetworkTypes.Length();
   *aTypes =
-    static_cast<char16_t**>(nsMemory::Alloc((*aLength) * sizeof(char16_t*)));
+    static_cast<int32_t*>(nsMemory::Alloc((*aLength) * sizeof(int32_t)));
   NS_ENSURE_TRUE(*aTypes, NS_ERROR_OUT_OF_MEMORY);
 
   for (uint32_t i = 0; i < *aLength; i++) {
-    (*aTypes)[i] = ToNewUnicode(mSupportedNetworkTypes[i]);
+    (*aTypes)[i] = mSupportedNetworkTypes[i];
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 MobileConnectionChild::GetLastKnownNetwork(nsAString& aNetwork)
 {
--- a/dom/mobileconnection/ipc/MobileConnectionChild.h
+++ b/dom/mobileconnection/ipc/MobileConnectionChild.h
@@ -112,17 +112,17 @@ private:
   nsCOMArray<nsIMobileConnectionListener> mListeners;
   nsRefPtr<MobileConnectionInfo> mVoice;
   nsRefPtr<MobileConnectionInfo> mData;
   nsString mIccId;
   int32_t mRadioState;
   nsString mLastNetwork;
   nsString mLastHomeNetwork;
   int32_t mNetworkSelectionMode;
-  nsTArray<nsString> mSupportedNetworkTypes;
+  nsTArray<int32_t> mSupportedNetworkTypes;
 };
 
 /******************************************************************************
  * PMobileConnectionRequestChild
  ******************************************************************************/
 
 /**
  * Child actor of PMobileConnectionRequest. The object is created when an
--- a/dom/mobileconnection/ipc/MobileConnectionParent.cpp
+++ b/dom/mobileconnection/ipc/MobileConnectionParent.cpp
@@ -126,40 +126,39 @@ MobileConnectionParent::DeallocPMobileCo
 bool
 MobileConnectionParent::RecvInit(nsMobileConnectionInfo* aVoice,
                                  nsMobileConnectionInfo* aData,
                                  nsString* aLastKnownNetwork,
                                  nsString* aLastKnownHomeNetwork,
                                  nsString* aIccId,
                                  int32_t* aNetworkSelectionMode,
                                  int32_t* aRadioState,
-                                 nsTArray<nsString>* aSupportedNetworkTypes)
+                                 nsTArray<int32_t>* aSupportedNetworkTypes)
 {
   NS_ENSURE_TRUE(mMobileConnection, false);
 
   NS_ENSURE_SUCCESS(mMobileConnection->GetVoice(aVoice), false);
   NS_ENSURE_SUCCESS(mMobileConnection->GetData(aData), false);
   NS_ENSURE_SUCCESS(mMobileConnection->GetLastKnownNetwork(*aLastKnownNetwork), false);
   NS_ENSURE_SUCCESS(mMobileConnection->GetLastKnownHomeNetwork(*aLastKnownHomeNetwork), false);
   NS_ENSURE_SUCCESS(mMobileConnection->GetIccId(*aIccId), false);
   NS_ENSURE_SUCCESS(mMobileConnection->GetNetworkSelectionMode(aNetworkSelectionMode), false);
   NS_ENSURE_SUCCESS(mMobileConnection->GetRadioState(aRadioState), false);
 
-  char16_t** types = nullptr;
+  int32_t* types = nullptr;
   uint32_t length = 0;
 
   nsresult rv = mMobileConnection->GetSupportedNetworkTypes(&types, &length);
   NS_ENSURE_SUCCESS(rv, false);
 
   for (uint32_t i = 0; i < length; ++i) {
-    nsDependentString type(types[i]);
-    aSupportedNetworkTypes->AppendElement(type);
+    aSupportedNetworkTypes->AppendElement(types[i]);
   }
 
-  NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(length, types);
+  nsMemory::Free(types);
 
   return true;
 }
 
 // nsIMobileConnectionListener
 
 NS_IMPL_ISUPPORTS(MobileConnectionParent, nsIMobileConnectionListener)
 
--- a/dom/mobileconnection/ipc/MobileConnectionParent.h
+++ b/dom/mobileconnection/ipc/MobileConnectionParent.h
@@ -47,17 +47,17 @@ protected:
 
   virtual bool
   DeallocPMobileConnectionRequestParent(PMobileConnectionRequestParent* aActor) MOZ_OVERRIDE;
 
   virtual bool
   RecvInit(nsMobileConnectionInfo* aVoice, nsMobileConnectionInfo* aData,
            nsString* aLastKnownNetwork, nsString* aLastKnownHomeNetwork,
            nsString* aIccId, int32_t* aNetworkSelectionMode,
-           int32_t* aRadioState, nsTArray<nsString>* aSupportedNetworkTypes) MOZ_OVERRIDE;
+           int32_t* aRadioState, nsTArray<int32_t>* aSupportedNetworkTypes) MOZ_OVERRIDE;
 
 private:
   nsCOMPtr<nsIMobileConnection> mMobileConnection;
   bool mLive;
 };
 
 /******************************************************************************
  * PMobileConnectionRequestParent
--- a/dom/mobileconnection/ipc/PMobileConnection.ipdl
+++ b/dom/mobileconnection/ipc/PMobileConnection.ipdl
@@ -46,17 +46,17 @@ parent:
 
   /**
    * Sync call only be called once per child actor for initialization.
    */
   sync Init()
     returns (nsMobileConnectionInfo aVoice, nsMobileConnectionInfo aData,
              nsString aLastKnownNetwork, nsString aLastKnownHomeNetwork,
              nsString aIccId, int32_t aNetworkSelectionMode,
-             int32_t aRadioState, nsString[] aSupportedNetworkTypes);
+             int32_t aRadioState, int32_t[] aSupportedNetworkTypes);
 };
 
 /**
  * MobileConnectionRequest
  */
 struct GetNetworksRequest
 {
 };
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/Promise.h"
 
 #include "jsfriendapi.h"
+#include "js/Debug.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/DOMError.h"
 #include "mozilla/dom/OwningNonNull.h"
 #include "mozilla/dom/PromiseBinding.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/MediaStreamError.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
 #include "mozilla/Preferences.h"
@@ -319,31 +320,34 @@ Promise::CreateWrapper(ErrorResult& aRv)
 {
   AutoJSAPI jsapi;
   if (!jsapi.Init(mGlobal)) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return;
   }
   JSContext* cx = jsapi.cx();
 
-  JS::Rooted<JS::Value> ignored(cx);
-  if (!WrapNewBindingObject(cx, this, &ignored)) {
+  JS::Rooted<JS::Value> wrapper(cx);
+  if (!WrapNewBindingObject(cx, this, &wrapper)) {
     JS_ClearPendingException(cx);
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
 
   dom::PreserveWrapper(this);
 
   // Now grab our allocation stack
   if (!CaptureStack(cx, mAllocationStack)) {
     JS_ClearPendingException(cx);
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
+
+  JS::RootedObject obj(cx, &wrapper.toObject());
+  JS::dbg::onNewPromise(cx, obj);
 }
 
 void
 Promise::MaybeResolve(JSContext* aCx,
                       JS::Handle<JS::Value> aValue)
 {
   MaybeResolveInternal(aCx, aValue);
 }
@@ -1108,29 +1112,29 @@ Promise::RejectInternal(JSContext* aCx,
                         JS::Handle<JS::Value> aValue)
 {
   mResolvePending = true;
 
   MaybeSettle(aValue, Rejected);
 }
 
 void
-Promise::MaybeSettle(JS::Handle<JS::Value> aValue,
-                     PromiseState aState)
+Promise::Settle(JS::Handle<JS::Value> aValue, PromiseState aState)
 {
-  // Promise.all() or Promise.race() implementations will repeatedly call
-  // Resolve/RejectInternal rather than using the Maybe... forms. Stop SetState
-  // from asserting.
-  if (mState != Pending) {
-    return;
-  }
-
+  mSettlementTimestamp = TimeStamp::Now();
   SetResult(aValue);
   SetState(aState);
-  mSettlementTimestamp = TimeStamp::Now();
+
+  AutoJSAPI jsapi;
+  jsapi.Init();
+  JSContext* cx = jsapi.cx();
+  JS::RootedObject wrapper(cx, GetWrapper());
+  MOZ_ASSERT(wrapper); // We preserved it
+  JSAutoCompartment ac(cx, wrapper);
+  JS::dbg::onPromiseSettled(cx, wrapper);
 
   // If the Promise was rejected, and there is no reject handler already setup,
   // watch for thread shutdown.
   if (aState == PromiseState::Rejected &&
       !mHadRejectCallback &&
       !NS_IsMainThread()) {
     WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
     MOZ_ASSERT(worker);
@@ -1145,16 +1149,30 @@ Promise::MaybeSettle(JS::Handle<JS::Valu
       MaybeReportRejectedOnce();
     }
   }
 
   EnqueueCallbackTasks();
 }
 
 void
+Promise::MaybeSettle(JS::Handle<JS::Value> aValue,
+                     PromiseState aState)
+{
+  // Promise.all() or Promise.race() implementations will repeatedly call
+  // Resolve/RejectInternal rather than using the Maybe... forms. Stop SetState
+  // from asserting.
+  if (mState != Pending) {
+    return;
+  }
+
+  Settle(aValue, aState);
+}
+
+void
 Promise::EnqueueCallbackTasks()
 {
   nsTArray<nsRefPtr<PromiseCallback>> callbacks;
   callbacks.SwapElements(mState == Resolved ? mResolveCallbacks
                                             : mRejectCallbacks);
   mResolveCallbacks.Clear();
   mRejectCallbacks.Clear();
 
--- a/dom/promise/Promise.h
+++ b/dom/promise/Promise.h
@@ -220,18 +220,18 @@ private:
   }
 
   // This method enqueues promise's resolve/reject callbacks with promise's
   // result. It's executed when the resolver.resolve() or resolver.reject() is
   // called or when the promise already has a result and new callbacks are
   // appended by then(), catch() or done().
   void EnqueueCallbackTasks();
 
-  void MaybeSettle(JS::Handle<JS::Value> aValue,
-                   Promise::PromiseState aState);
+  void Settle(JS::Handle<JS::Value> aValue, Promise::PromiseState aState);
+  void MaybeSettle(JS::Handle<JS::Value> aValue, Promise::PromiseState aState);
 
   void AppendCallbacks(PromiseCallback* aResolveCallback,
                        PromiseCallback* aRejectCallback);
 
   // If we have been rejected and our mResult is a JS exception,
   // report it to the error console.
   // Use MaybeReportRejectedOnce() for actual calls.
   void MaybeReportRejected();
--- a/dom/promise/tests/chrome.ini
+++ b/dom/promise/tests/chrome.ini
@@ -1,3 +1,6 @@
 [DEFAULT]
 
 [test_dependentPromises.html]
+[test_on_new_promise.html]
+[test_on_promise_settled.html]
+[test_on_promise_settled_duplicates.html]
new file mode 100644
--- /dev/null
+++ b/dom/promise/tests/test_on_new_promise.html
@@ -0,0 +1,45 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+
+<!--
+Bug 1083210 - Sanity test for interaction between DOM promises and
+Debugger.prototype.onNewPromise.
+-->
+
+<html>
+<head>
+  <title>Test for interaction with SpiderMonkey's Debugger.prototype.onNewPromise</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+  <script type="application/javascript">
+  is(Object.prototype.toString.call(new Promise(function () {})),
+     "[object Promise]",
+     "We should have the native DOM promise implementation.");
+
+  var Cu = Components.utils;
+  Cu.import("resource://gre/modules/jsdebugger.jsm");
+  var dbgGlobal = new Cu.Sandbox(document.nodePrincipal);
+  addDebuggerToGlobal(dbgGlobal);
+  var dbg = new dbgGlobal.Debugger(this);
+
+  var wrappedPromise;
+  dbg.onNewPromise = function (wp) { wrappedPromise = wp; };
+
+  var promise = new Promise(function () {});
+  debugger;
+  ok(wrappedPromise);
+  is(wrappedPromise.unsafeDereference(), promise);
+  </script>
+</pre>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/dom/promise/tests/test_on_promise_settled.html
@@ -0,0 +1,54 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+
+<!--
+Bug 1084065 - Sanity test for interaction between DOM promises and
+Debugger.prototype.onPromiseResolved.
+-->
+
+<html>
+<head>
+  <title>Test for interaction with SpiderMonkey's Debugger.prototype.onNewPromise</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+  <script type="application/javascript">
+  SimpleTest.waitForExplicitFinish();
+
+  is(Object.prototype.toString.call(new Promise(function () {})),
+     "[object Promise]",
+     "We should have the native DOM promise implementation.");
+
+  var Cu = Components.utils;
+  Cu.import("resource://gre/modules/jsdebugger.jsm");
+  var dbgGlobal = new Cu.Sandbox(document.nodePrincipal);
+  addDebuggerToGlobal(dbgGlobal);
+  var dbg = new dbgGlobal.Debugger(this);
+
+  var wrappedPromise;
+  dbg.onPromiseSettled = function (wp) { wrappedPromise = wp; };
+
+  var promise = Promise.resolve();
+  promise
+    .then(function () {
+      ok(wrappedPromise);
+      is(wrappedPromise.unsafeDereference(), promise);
+      dbg.onPromiseSettled = undefined;
+    })
+    .then(null, function (e) {
+      ok(false, "Got an unexpected error: " + e);
+    })
+    .then(SimpleTest.finish);
+  </script>
+</pre>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/dom/promise/tests/test_on_promise_settled_duplicates.html
@@ -0,0 +1,59 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+
+<!--
+Bug 1084065 - Test that Debugger.prototype.onPromiseResolved doesn't get dupes.
+-->
+
+<html>
+<head>
+  <title>Test for interaction with SpiderMonkey's Debugger.prototype.onNewPromise</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+  <script type="application/javascript">
+  SimpleTest.waitForExplicitFinish();
+
+  is(Object.prototype.toString.call(new Promise(function () {})),
+     "[object Promise]",
+     "We should have the native DOM promise implementation.");
+
+  var Cu = Components.utils;
+  Cu.import("resource://gre/modules/jsdebugger.jsm");
+  var dbgGlobal = new Cu.Sandbox(document.nodePrincipal);
+  addDebuggerToGlobal(dbgGlobal);
+  var dbg = new dbgGlobal.Debugger(this);
+
+  var seen = new Set();
+  dbg.onPromiseSettled = function (wp) {
+    is(seen.has(wp), false);
+    seen.add(wp);
+  };
+
+  var promise = new Promise(function (fulfill, reject) {
+    fulfill(1);
+    fulfill(2);
+    fulfill(3);
+  });
+
+  promise
+    .then(function () {
+      dbg.onPromiseSettled = undefined;
+    })
+    .then(null, function (e) {
+      ok(false, "Got an unexpected error: " + e);
+    })
+    .then(SimpleTest.finish);
+  </script>
+</pre>
+</body>
+</html>
+
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -422,16 +422,17 @@ this.RIL_PREFERRED_NETWORK_TYPE_TO_GECKO
   GECKO_PREFERRED_NETWORK_TYPE_WCDMA_GSM_CDMA_EVDO,
   GECKO_PREFERRED_NETWORK_TYPE_LTE_CDMA_EVDO,
   GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA_GSM,
   GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA_GSM_CDMA_EVDO,
   GECKO_PREFERRED_NETWORK_TYPE_LTE_ONLY
 ];
 
 this.GECKO_SUPPORTED_NETWORK_TYPES_DEFAULT = "gsm,wcdma";
+// Index-item pair must be in sync with nsIMobileConnection.MOBILE_NETWORK_TYPE_*
 this.GECKO_SUPPORTED_NETWORK_TYPES = [
   "gsm",
   "wcdma",
   "cdma",
   "evdo",
   "lte"
 ];
 
--- a/dom/webidl/AudioContext.webidl
+++ b/dom/webidl/AudioContext.webidl
@@ -73,18 +73,18 @@ interface AudioContext : EventTarget {
     [NewObject, Throws]
     PeriodicWave createPeriodicWave(Float32Array real, Float32Array imag);
 
 };
 
 // Mozilla extensions
 partial interface AudioContext {
   // Read AudioChannel.webidl for more information about this attribute.
-  [Pref="media.useAudioChannelService", SetterThrows]
-  attribute AudioChannel mozAudioChannelType;
+  [Pref="media.useAudioChannelService"]
+  readonly attribute AudioChannel mozAudioChannelType;
 
   // These 2 events are dispatched when the AudioContext object is muted by
   // the AudioChannelService. It's call 'interrupt' because when this event is
   // dispatched on a HTMLMediaElement, the audio stream is paused.
   [Pref="media.useAudioChannelService"]
   attribute EventHandler onmozinterruptbegin;
 
   [Pref="media.useAudioChannelService"]
deleted file mode 100644
--- a/dom/webidl/BrowserElement.webidl
+++ /dev/null
@@ -1,142 +0,0 @@
-/* -*- Mode: IDL; 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/.
- */
-
-callback BrowserElementNextPaintEventCallback = void ();
-
-dictionary BrowserElementDownloadOptions {
-  DOMString? filename;
-};
-
-[NoInterfaceObject]
-interface BrowserElement {
-};
-
-BrowserElement implements BrowserElementCommon;
-BrowserElement implements BrowserElementPrivileged;
-
-[NoInterfaceObject]
-interface BrowserElementCommon {
-  [Throws,
-   Pref="dom.mozBrowserFramesEnabled",
-   CheckPermissions="browser embed-widgets"]
-  void setVisible(boolean visible);
-
-  [Throws,
-   Pref="dom.mozBrowserFramesEnabled",
-   CheckPermissions="browser embed-widgets"]
-  DOMRequest getVisible();
-
-  [Throws,
-   Pref="dom.mozBrowserFramesEnabled",
-   CheckPermissions="browser embed-widgets"]
-  void setActive(boolean active);
-
-  [Throws,
-   Pref="dom.mozBrowserFramesEnabled",
-   CheckPermissions="browser embed-widgets"]
-  boolean getActive();
-
-  [Throws,
-   Pref="dom.mozBrowserFramesEnabled",
-   CheckPermissions="browser embed-widgets"]
-  void addNextPaintListener(BrowserElementNextPaintEventCallback listener);
-
-  [Throws,
-   Pref="dom.mozBrowserFramesEnabled",
-   CheckPermissions="browser embed-widgets"]
-  void removeNextPaintListener(BrowserElementNextPaintEventCallback listener);
-};
-
-[NoInterfaceObject]
-interface BrowserElementPrivileged {
-  [Throws,
-   Pref="dom.mozBrowserFramesEnabled",
-   CheckPermissions="browser"]
-  void sendMouseEvent(DOMString type,
-                      unsigned long x,
-                      unsigned long y,
-                      unsigned long button,
-                      unsigned long clickCount,
-                      unsigned long modifiers);
-
-  [Throws,
-   Pref="dom.mozBrowserFramesEnabled",
-   Func="TouchEvent::PrefEnabled",
-   CheckPermissions="browser"]
-  void sendTouchEvent(DOMString type,
-                      sequence<unsigned long> identifiers,
-                      sequence<long> x,
-                      sequence<long> y,
-                      sequence<unsigned long> rx,
-                      sequence<unsigned long> ry,
-                      sequence<float> rotationAngles,
-                      sequence<float> forces,
-                      unsigned long count,
-                      unsigned long modifiers);
-
-  [Throws,
-   Pref="dom.mozBrowserFramesEnabled",
-   CheckPermissions="browser"]
-  void goBack();
-
-  [Throws,
-   Pref="dom.mozBrowserFramesEnabled",
-   CheckPermissions="browser"]
-  void goForward();
-
-  [Throws,
-   Pref="dom.mozBrowserFramesEnabled",
-   CheckPermissions="browser"]
-  void reload(optional boolean hardReload = false);
-
-  [Throws,
-   Pref="dom.mozBrowserFramesEnabled",
-   CheckPermissions="browser"]
-  void stop();
-
-  [Throws,
-   Pref="dom.mozBrowserFramesEnabled",
-   CheckPermissions="browser"]
-  DOMRequest download(DOMString url,
-                      optional BrowserElementDownloadOptions options);
-
-  [Throws,
-   Pref="dom.mozBrowserFramesEnabled",
-   CheckPermissions="browser"]
-  DOMRequest purgeHistory();
-
-  [Throws,
-   Pref="dom.mozBrowserFramesEnabled",
-   CheckPermissions="browser"]
-  DOMRequest getScreenshot([EnforceRange] unsigned long width,
-                           [EnforceRange] unsigned long height,
-                           optional DOMString mimeType="");
-
-  [Throws,
-   Pref="dom.mozBrowserFramesEnabled",
-   CheckPermissions="browser"]
-  void zoom(float zoom);
-
-  [Throws,
-   Pref="dom.mozBrowserFramesEnabled",
-   CheckPermissions="browser"]
-  DOMRequest getCanGoBack();
-
-  [Throws,
-   Pref="dom.mozBrowserFramesEnabled",
-   CheckPermissions="browser"]
-  DOMRequest getCanGoForward();
-
-  [Throws,
-   Pref="dom.mozBrowserFramesEnabled",
-   CheckPermissions="browser"]
-  DOMRequest getContentDimensions();
-
-  [Throws,
-   Pref="dom.mozBrowserFramesEnabled",
-   CheckPermissions="browser"]
-  DOMRequest setInputMethodActive(boolean isActive);
-};
--- a/dom/webidl/HTMLIFrameElement.webidl
+++ b/dom/webidl/HTMLIFrameElement.webidl
@@ -58,9 +58,8 @@ partial interface HTMLIFrameElement {
 
 partial interface HTMLIFrameElement {
   // nsIMozBrowserFrame
   [ChromeOnly]
   readonly attribute DOMString appManifestURL;
 };
 
 HTMLIFrameElement implements MozFrameLoaderOwner;
-HTMLIFrameElement implements BrowserElement;
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -50,17 +50,16 @@ WEBIDL_FILES = [
     'AutocompleteInfo.webidl',
     'BarProp.webidl',
     'BatteryManager.webidl',
     'BeforeAfterKeyboardEvent.webidl',
     'BeforeUnloadEvent.webidl',
     'BiquadFilterNode.webidl',
     'Blob.webidl',
     'BoxObject.webidl',
-    'BrowserElement.webidl',
     'BrowserElementDictionaries.webidl',
     'CallsList.webidl',
     'CameraCapabilities.webidl',
     'CameraControl.webidl',
     'CameraManager.webidl',
     'CameraUtil.webidl',
     'CanvasRenderingContext2D.webidl',
     'CaretPosition.webidl',
--- a/editor/reftests/reftest.list
+++ b/editor/reftests/reftest.list
@@ -93,22 +93,22 @@ skip-if(Android||B2G) needs-focus == 462
 == readonly-editable.html readonly-editable-ref.html
 == dynamic-overflow-change.html dynamic-overflow-change-ref.html
 == 694880-1.html 694880-ref.html
 == 694880-2.html 694880-ref.html
 == 694880-3.html 694880-ref.html
 == 388980-1.html 388980-1-ref.html
 needs-focus == spellcheck-superscript-1.html spellcheck-superscript-1-ref.html
 skip-if(B2G) fails-if(Android) needs-focus != spellcheck-superscript-2.html spellcheck-superscript-2-ref.html # bug 783658
-needs-focus == 824080-1.html 824080-1-ref.html
+needs-focus pref(selectioncaret.enabled,false) == 824080-1.html 824080-1-ref.html
 needs-focus == 824080-2.html 824080-2-ref.html
-needs-focus test-pref(selectioncaret.enabled,false) == 824080-3.html 824080-3-ref.html
+needs-focus pref(selectioncaret.enabled,false) == 824080-3.html 824080-3-ref.html
 needs-focus != 824080-2.html 824080-3.html
-needs-focus == 824080-4.html 824080-4-ref.html
-needs-focus test-pref(selectioncaret.enabled,false) == 824080-5.html 824080-5-ref.html
+needs-focus pref(selectioncaret.enabled,false) == 824080-4.html 824080-4-ref.html
+needs-focus pref(selectioncaret.enabled,false) == 824080-5.html 824080-5-ref.html
 needs-focus != 824080-4.html 824080-5.html
 needs-focus == 824080-6.html 824080-6-ref.html
 needs-focus pref(selectioncaret.enabled,false) == 824080-7.html 824080-7-ref.html
 needs-focus != 824080-6.html 824080-7.html
 # Bug 674927: copy spellcheck-textarea tests to contenteditable
 == spellcheck-contenteditable-attr.html spellcheck-contenteditable-nofocus-ref.html
 fails-if(Android||B2G) needs-focus != spellcheck-contenteditable-attr.html spellcheck-contenteditable-ref.html # B2G no spellcheck underline
 needs-focus == spellcheck-contenteditable-focused.html spellcheck-contenteditable-ref.html
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -678,21 +678,22 @@ GLContext::InitWithPrefix(const char *pr
 
             if (Renderer() == GLRenderer::MicrosoftBasicRenderDriver) {
                 // Bug 978966: on Microsoft's "Basic Render Driver" (software renderer)
                 // multisampling hardcodes blending with the default blendfunc, which breaks WebGL.
                 MarkUnsupported(GLFeature::framebuffer_multisample);
             }
 
 #ifdef XP_MACOSX
-            // The Mac Nvidia driver, for versions up to and including 10.8, don't seem
-            // to properly support this.  See 814839
+            // The Mac Nvidia driver, for versions up to and including 10.8,
+            // don't seem to properly support this.  See 814839
             // this has been fixed in Mac OS X 10.9. See 907946
+            // and it also works in 10.8.3 and higher.  See 1094338.
             if (Vendor() == gl::GLVendor::NVIDIA &&
-                !nsCocoaFeatures::OnMavericksOrLater())
+                !nsCocoaFeatures::IsAtLeastVersion(10,8,3))
             {
                 MarkUnsupported(GLFeature::depth_texture);
             }
 #endif
         }
 
         NS_ASSERTION(!IsExtensionSupported(GLContext::ARB_pixel_buffer_object) ||
                      (mSymbols.fMapBuffer && mSymbols.fUnmapBuffer),
--- a/gfx/ipc/GfxMessageUtils.h
+++ b/gfx/ipc/GfxMessageUtils.h
@@ -389,20 +389,20 @@ struct ParamTraits<nsIntPoint>
 
   static bool Read(const Message* msg, void** iter, paramType* result)
   {
     return (ReadParam(msg, iter, &result->x) &&
             ReadParam(msg, iter, &result->y));
   }
 };
 
-template<>
-struct ParamTraits<mozilla::gfx::IntSize>
+template<typename T>
+struct ParamTraits<mozilla::gfx::IntSizeTyped<T> >
 {
-  typedef mozilla::gfx::IntSize paramType;
+  typedef mozilla::gfx::IntSizeTyped<T> paramType;
 
   static void Write(Message* msg, const paramType& param)
   {
     WriteParam(msg, param.width);
     WriteParam(msg, param.height);
   }
 
   static bool Read(const Message* msg, void** iter, paramType* result)
@@ -751,16 +751,17 @@ struct ParamTraits<mozilla::layers::Fram
     WriteParam(aMsg, aParam.mIsRoot);
     WriteParam(aMsg, aParam.mHasScrollgrab);
     WriteParam(aMsg, aParam.mUpdateScrollOffset);
     WriteParam(aMsg, aParam.mScrollGeneration);
     WriteParam(aMsg, aParam.mExtraResolution);
     WriteParam(aMsg, aParam.mBackgroundColor);
     WriteParam(aMsg, aParam.mDoSmoothScroll);
     WriteParam(aMsg, aParam.mSmoothScrollOffset);
+    WriteParam(aMsg, aParam.GetLineScrollAmount());
     WriteParam(aMsg, aParam.GetContentDescription());
   }
 
   static bool ReadContentDescription(const Message* aMsg, void** aIter, paramType* aResult)
   {
     nsCString str;
     if (!ReadParam(aMsg, aIter, &str)) {
       return false;
@@ -792,16 +793,17 @@ struct ParamTraits<mozilla::layers::Fram
             ReadParam(aMsg, aIter, &aResult->mIsRoot) &&
             ReadParam(aMsg, aIter, &aResult->mHasScrollgrab) &&
             ReadParam(aMsg, aIter, &aResult->mUpdateScrollOffset) &&
             ReadParam(aMsg, aIter, &aResult->mScrollGeneration) &&
             ReadParam(aMsg, aIter, &aResult->mExtraResolution) &&
             ReadParam(aMsg, aIter, &aResult->mBackgroundColor) &&
             ReadParam(aMsg, aIter, &aResult->mDoSmoothScroll) &&
             ReadParam(aMsg, aIter, &aResult->mSmoothScrollOffset) &&
+            ReadParam(aMsg, aIter, &aResult->mLineScrollAmount) &&
             ReadContentDescription(aMsg, aIter, aResult));
   }
 };
 
 template<>
 struct ParamTraits<mozilla::layers::TextureFactoryIdentifier>
 {
   typedef mozilla::layers::TextureFactoryIdentifier paramType;
--- a/gfx/layers/FrameMetrics.h
+++ b/gfx/layers/FrameMetrics.h
@@ -60,16 +60,17 @@ public:
     , mSmoothScrollOffset(0, 0)
     , mRootCompositionSize(0, 0)
     , mDisplayPortMargins(0, 0, 0, 0)
     , mUseDisplayPortMargins(false)
     , mPresShellId(-1)
     , mViewport(0, 0, 0, 0)
     , mExtraResolution(1)
     , mBackgroundColor(0, 0, 0, 0)
+    , mLineScrollAmount(0, 0)
   {
   }
 
   // Default copy ctor and operator= are fine
 
   bool operator==(const FrameMetrics& aOther) const
   {
     return mCompositionBounds.IsEqualEdges(aOther.mCompositionBounds) &&
@@ -90,17 +91,18 @@ public:
            mScrollId == aOther.mScrollId &&
            mScrollParentId == aOther.mScrollParentId &&
            mScrollOffset == aOther.mScrollOffset &&
            mSmoothScrollOffset == aOther.mSmoothScrollOffset &&
            mHasScrollgrab == aOther.mHasScrollgrab &&
            mUpdateScrollOffset == aOther.mUpdateScrollOffset &&
            mExtraResolution == aOther.mExtraResolution &&
            mBackgroundColor == aOther.mBackgroundColor &&
-           mDoSmoothScroll == aOther.mDoSmoothScroll;
+           mDoSmoothScroll == aOther.mDoSmoothScroll &&
+           mLineScrollAmount == aOther.mLineScrollAmount;
   }
   bool operator!=(const FrameMetrics& aOther) const
   {
     return !operator==(aOther);
   }
 
   bool IsDefault() const
   {
@@ -509,16 +511,26 @@ public:
     return mMayHaveTouchListeners;
   }
 
   void SetMayHaveTouchListeners(bool aMayHaveTouchListeners)
   {
     mMayHaveTouchListeners = aMayHaveTouchListeners;
   }
 
+  const LayoutDeviceIntSize& GetLineScrollAmount() const
+  {
+    return mLineScrollAmount;
+  }
+
+  void SetLineScrollAmount(const LayoutDeviceIntSize& size)
+  {
+    mLineScrollAmount = size;
+  }
+
 private:
   // New fields from now on should be made private and old fields should
   // be refactored to be private.
 
   // Whether or not this frame may have a touch listeners.
   bool mMayHaveTouchListeners;
 
   // Whether or not this frame may have a touch caret.
@@ -600,16 +612,19 @@ private:
 
   // The background color to use when overscrolling.
   gfxRGBA mBackgroundColor;
 
   // A description of the content element corresponding to this frame.
   // This is empty unless this is a scrollable layer and the
   // apz.printtree pref is turned on.
   nsCString mContentDescription;
+
+  // The value of GetLineScrollAmount(), for scroll frames.
+  LayoutDeviceIntSize mLineScrollAmount;
 };
 
 /**
  * This class allows us to uniquely identify a scrollable layer. The
  * mLayersId identifies the layer tree (corresponding to a child process
  * and/or tab) that the scrollable layer belongs to. The mPresShellId
  * is a temporal identifier (corresponding to the document loaded that
  * contains the scrollable layer, which may change over time). The
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -606,16 +606,39 @@ APZCTreeManager::ReceiveInputEvent(Input
   nsEventStatus result = nsEventStatus_eIgnore;
   Matrix4x4 transformToApzc;
   HitTestResult hitResult = NoApzcHit;
   switch (aEvent.mInputType) {
     case MULTITOUCH_INPUT: {
       MultiTouchInput& touchInput = aEvent.AsMultiTouchInput();
       result = ProcessTouchInput(touchInput, aOutTargetGuid, aOutInputBlockId);
       break;
+    } case SCROLLWHEEL_INPUT: {
+      ScrollWheelInput& wheelInput = aEvent.AsScrollWheelInput();
+      nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(wheelInput.mOrigin,
+                                                            &hitResult);
+      if (apzc) {
+        MOZ_ASSERT(hitResult == ApzcHitRegion || hitResult == ApzcContentRegion);
+
+        transformToApzc = GetScreenToApzcTransform(apzc);
+        wheelInput.mLocalOrigin =
+          TransformTo<ParentLayerPixel>(transformToApzc, wheelInput.mOrigin);
+
+        result = mInputQueue->ReceiveInputEvent(
+          apzc,
+          /* aTargetConfirmed = */ hitResult,
+          wheelInput, aOutInputBlockId);
+
+        // Update the out-parameters so they are what the caller expects.
+        apzc->GetGuid(aOutTargetGuid);
+        Matrix4x4 transformToGecko = transformToApzc * GetApzcToGeckoTransform(apzc);
+        wheelInput.mOrigin =
+          TransformTo<ScreenPixel>(transformToGecko, wheelInput.mLocalOrigin);
+      }
+      break;
     } case PANGESTURE_INPUT: {
       PanGestureInput& panInput = aEvent.AsPanGestureInput();
       nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(panInput.mPanStartPoint,
                                                             &hitResult);
       if (apzc) {
         MOZ_ASSERT(hitResult == ApzcHitRegion || hitResult == ApzcContentRegion);
         transformToApzc = GetScreenToApzcTransform(apzc);
         panInput.mLocalPanStartPoint = TransformTo<ParentLayerPixel>(
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -528,31 +528,19 @@ public:
   }
 
   /**
    * Advances a fling by an interpolated amount based on the passed in |aDelta|.
    * This should be called whenever sampling the content transform for this
    * frame. Returns true if the fling animation should be advanced by one frame,
    * or false if there is no fling or the fling has ended.
    */
-  virtual bool Sample(FrameMetrics& aFrameMetrics,
-                      const TimeDuration& aDelta) MOZ_OVERRIDE
+  virtual bool DoSample(FrameMetrics& aFrameMetrics,
+                        const TimeDuration& aDelta) MOZ_OVERRIDE
   {
-    // If the fling is handed off to our APZC from a child, on the first call to
-    // Sample() aDelta might be negative because it's computed as the sample time
-    // from SampleContentTransformForFrame() minus our APZC's mLastSampleTime
-    // which is the time the child handed off the fling from its call to
-    // SampleContentTransformForFrame() with the same sample time. If we allow
-    // the negative aDelta to be processed, it will yield a displacement in the
-    // direction opposite to the fling, which can cause us to overscroll and
-    // hand off the fling to _our_ parent, which effectively kills the fling.
-    if (aDelta.ToMilliseconds() <= 0) {
-      return true;
-    }
-
     float friction = gfxPrefs::APZFlingFriction();
     float threshold = gfxPrefs::APZFlingStoppedThreshold();
 
     bool shouldContinueFlingX = mApzc.mX.FlingApplyFrictionOrCancel(aDelta, friction, threshold),
          shouldContinueFlingY = mApzc.mY.FlingApplyFrictionOrCancel(aDelta, friction, threshold);
     // If we shouldn't continue the fling, let's just stop and repaint.
     if (!shouldContinueFlingX && !shouldContinueFlingY) {
       APZC_LOG("%p ending fling animation. overscrolled=%d\n", &mApzc, mApzc.IsOverscrolled());
@@ -650,18 +638,18 @@ public:
                 CSSPoint aEndOffset, CSSToParentLayerScale aEndZoom)
     : mTotalDuration(TimeDuration::FromMilliseconds(gfxPrefs::APZZoomAnimationDuration()))
     , mStartOffset(aStartOffset)
     , mStartZoom(aStartZoom)
     , mEndOffset(aEndOffset)
     , mEndZoom(aEndZoom)
   {}
 
-  virtual bool Sample(FrameMetrics& aFrameMetrics,
-                      const TimeDuration& aDelta) MOZ_OVERRIDE
+  virtual bool DoSample(FrameMetrics& aFrameMetrics,
+                        const TimeDuration& aDelta) MOZ_OVERRIDE
   {
     mDuration += aDelta;
     double animPosition = mDuration / mTotalDuration;
 
     if (animPosition >= 1.0) {
       aFrameMetrics.SetZoom(mEndZoom);
       aFrameMetrics.SetScrollOffset(mEndOffset);
       return false;
@@ -707,18 +695,18 @@ class OverscrollAnimation: public AsyncP
 public:
   explicit OverscrollAnimation(AsyncPanZoomController& aApzc, const ParentLayerPoint& aVelocity)
     : mApzc(aApzc)
   {
     mApzc.mX.SetVelocity(aVelocity.x);
     mApzc.mY.SetVelocity(aVelocity.y);
   }
 
-  virtual bool Sample(FrameMetrics& aFrameMetrics,
-                      const TimeDuration& aDelta) MOZ_OVERRIDE
+  virtual bool DoSample(FrameMetrics& aFrameMetrics,
+                        const TimeDuration& aDelta) MOZ_OVERRIDE
   {
     // Can't inline these variables due to short-circuit evaluation.
     bool continueX = mApzc.mX.SampleOverscrollAnimation(aDelta);
     bool continueY = mApzc.mY.SampleOverscrollAnimation(aDelta);
     return continueX || continueY;
   }
 private:
   AsyncPanZoomController& mApzc;
@@ -742,22 +730,17 @@ public:
   }
 
   /**
    * Advances a smooth scroll simulation based on the time passed in |aDelta|.
    * This should be called whenever sampling the content transform for this
    * frame. Returns true if the smooth scroll should be advanced by one frame,
    * or false if the smooth scroll has ended.
    */
-  bool Sample(FrameMetrics& aFrameMetrics, const TimeDuration& aDelta) {
-
-    if (aDelta.ToMilliseconds() <= 0) {
-      return true;
-    }
-
+  bool DoSample(FrameMetrics& aFrameMetrics, const TimeDuration& aDelta) {
     if (mXAxisModel.IsFinished() && mYAxisModel.IsFinished()) {
       return false;
     }
 
     mXAxisModel.Simulate(aDelta);
     mYAxisModel.Simulate(aDelta);
 
     CSSPoint position = CSSPoint::FromAppUnits(nsPoint(mXAxisModel.GetPosition(),
@@ -1082,16 +1065,21 @@ nsEventStatus AsyncPanZoomController::Ha
       case PanGestureInput::PANGESTURE_END: rv = OnPanEnd(panGestureInput); break;
       case PanGestureInput::PANGESTURE_MOMENTUMSTART: rv = OnPanMomentumStart(panGestureInput); break;
       case PanGestureInput::PANGESTURE_MOMENTUMPAN: rv = OnPan(panGestureInput, false); break;
       case PanGestureInput::PANGESTURE_MOMENTUMEND: rv = OnPanMomentumEnd(panGestureInput); break;
       default: NS_WARNING("Unhandled pan gesture"); break;
     }
     break;
   }
+  case SCROLLWHEEL_INPUT: {
+    const ScrollWheelInput& scrollInput = aEvent.AsScrollWheelInput();
+    rv = OnScrollWheel(scrollInput);
+    break;
+  }
   default: return HandleGestureEvent(aEvent);
   }
 
   return rv;
 }
 
 nsEventStatus AsyncPanZoomController::HandleGestureEvent(const InputData& aEvent)
 {
@@ -1465,16 +1453,82 @@ AsyncPanZoomController::ConvertToGecko(c
       ReentrantMonitorAutoEnter lock(mMonitor);
       *aOut = layoutPoint / mFrameMetrics.mDevPixelsPerCSSPixel;
     }
     return true;
   }
   return false;
 }
 
+nsEventStatus AsyncPanZoomController::OnScrollWheel(const ScrollWheelInput& aEvent)
+{
+  double deltaX = aEvent.mDeltaX;
+  double deltaY = aEvent.mDeltaY;
+  switch (aEvent.mDeltaType) {
+    case ScrollWheelInput::SCROLLDELTA_LINE: {
+      LayoutDeviceIntSize scrollAmount = mFrameMetrics.GetLineScrollAmount();
+      deltaX *= scrollAmount.width;
+      deltaY *= scrollAmount.height;
+      break;
+    }
+    default:
+      MOZ_ASSERT_UNREACHABLE("unexpected scroll delta type");
+      return nsEventStatus_eConsumeNoDefault;
+  }
+
+  switch (aEvent.mScrollMode) {
+    case ScrollWheelInput::SCROLLMODE_INSTANT: {
+      // Decompose into pan events for simplicity.
+      PanGestureInput start(PanGestureInput::PANGESTURE_START, aEvent.mTime, aEvent.mTimeStamp,
+                            aEvent.mOrigin, ScreenPoint(0, 0), aEvent.modifiers);
+      start.mLocalPanStartPoint = aEvent.mLocalOrigin;
+      OnPanBegin(start);
+
+      // Pan gestures use natural directions which are inverted from scroll
+      // wheel and touchpad scroll gestures, so we invert x/y here. Since the
+      // zoom includes any device : css pixel zoom, we convert to CSS pixels
+      // before applying the zoom.
+      LayoutDevicePoint devicePixelDelta(-deltaX, -deltaY);
+      ParentLayerPoint delta = (devicePixelDelta / mFrameMetrics.mDevPixelsPerCSSPixel) *
+                               mFrameMetrics.GetZoom();
+
+      PanGestureInput move(PanGestureInput::PANGESTURE_PAN, aEvent.mTime, aEvent.mTimeStamp,
+                           aEvent.mOrigin,
+                           ToScreenCoordinates(delta, aEvent.mLocalOrigin),
+                           aEvent.modifiers);
+      move.mLocalPanStartPoint = aEvent.mLocalOrigin;
+      move.mLocalPanDisplacement = delta;
+      OnPan(move, false);
+
+      PanGestureInput end(PanGestureInput::PANGESTURE_END, aEvent.mTime, aEvent.mTimeStamp,
+                            aEvent.mOrigin, ScreenPoint(0, 0), aEvent.modifiers);
+      end.mLocalPanStartPoint = aEvent.mLocalOrigin;
+      OnPanEnd(start);
+      break;
+    }
+
+    case ScrollWheelInput::SCROLLMODE_SMOOTH: {
+      CSSPoint delta = LayoutDevicePoint(deltaX, deltaY) / mFrameMetrics.mDevPixelsPerCSSPixel;
+
+      // If we're already in a smooth scroll animation, don't cancel it. This
+      // lets us preserve the existing scrolling velocity.
+      if (mState != SMOOTH_SCROLL) {
+        CancelAnimation();
+        mFrameMetrics.SetSmoothScrollOffset(mFrameMetrics.GetScrollOffset() + delta);
+      } else {
+        mFrameMetrics.SetSmoothScrollOffset(mFrameMetrics.GetSmoothScrollOffset() + delta);
+      }
+      StartSmoothScroll();
+      break;
+    }
+  }
+
+  return nsEventStatus_eConsumeNoDefault;
+}
+
 nsEventStatus AsyncPanZoomController::OnPanMayBegin(const PanGestureInput& aEvent) {
   APZC_LOG("%p got a pan-maybegin in state %d\n", this, mState);
 
   mX.StartTouch(aEvent.mLocalPanStartPoint.x, aEvent.mTime);
   mY.StartTouch(aEvent.mLocalPanStartPoint.y, aEvent.mTime);
   if (mPanGestureState) {
     mPanGestureState->GetOverscrollHandoffChain()->CancelAnimations();
   } else {
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -410,16 +410,21 @@ protected:
   nsEventStatus OnPanCancelled(const PanGestureInput& aEvent);
   nsEventStatus OnPanBegin(const PanGestureInput& aEvent);
   nsEventStatus OnPan(const PanGestureInput& aEvent, bool aFingersOnTouchpad);
   nsEventStatus OnPanEnd(const PanGestureInput& aEvent);
   nsEventStatus OnPanMomentumStart(const PanGestureInput& aEvent);
   nsEventStatus OnPanMomentumEnd(const PanGestureInput& aEvent);
 
   /**
+   * Helper methods for handling scroll wheel events.
+   */
+  nsEventStatus OnScrollWheel(const ScrollWheelInput& aEvent);
+
+  /**
    * Helper methods for long press gestures.
    */
   nsEventStatus OnLongPress(const TapGestureInput& aEvent);
   nsEventStatus OnLongPressUp(const TapGestureInput& aEvent);
 
   /**
    * Helper method for single tap gestures.
    */
@@ -1120,18 +1125,30 @@ class AsyncPanZoomAnimation {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncPanZoomAnimation)
 
 public:
   explicit AsyncPanZoomAnimation(const TimeDuration& aRepaintInterval =
                                  TimeDuration::Forever())
     : mRepaintInterval(aRepaintInterval)
   { }
 
-  virtual bool Sample(FrameMetrics& aFrameMetrics,
-                      const TimeDuration& aDelta) = 0;
+  virtual bool DoSample(FrameMetrics& aFrameMetrics,
+                        const TimeDuration& aDelta) = 0;
+
+  bool Sample(FrameMetrics& aFrameMetrics,
+              const TimeDuration& aDelta) {
+    // In some situations, particularly when handoff is involved, it's possible
+    // for |aDelta| to be negative on the first call to sample. Ignore such a
+    // sample here, to avoid each derived class having to deal with this case.
+    if (aDelta.ToMilliseconds() <= 0) {
+      return true;
+    }
+
+    return DoSample(aFrameMetrics, aDelta);
+  }
 
   /**
    * Get the deferred tasks in |mDeferredTasks|. See |mDeferredTasks|
    * for more information.
    * Clears |mDeferredTasks|.
    */
   Vector<Task*> TakeDeferredTasks() {
     Vector<Task*> result;
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -524,18 +524,16 @@ ClientLayerManager::StopFrameTimeRecordi
   if (renderer) {
     renderer->SendStopFrameTimeRecording(aStartIndex, &aFrameIntervals);
   }
 }
 
 void
 ClientLayerManager::ForwardTransaction(bool aScheduleComposite)
 {
-  gfxPlatform::GetPlatform()->FenceContentDrawing();
-
   mPhase = PHASE_FORWARD;
 
   mLatestTransactionId = mTransactionIdAllocator->GetTransactionId();
   TimeStamp transactionStart;
   if (!mTransactionIdAllocator->GetTransactionStart().IsNull()) {
     transactionStart = mTransactionIdAllocator->GetTransactionStart();
   } else {
     transactionStart = mTransactionStart;
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -824,18 +824,16 @@ CompositorD3D11::BeginFrame(const nsIntR
   NS_ASSERTION(mHwnd, "Couldn't find an HWND when initialising?");
   if (::IsIconic(mHwnd)) {
     *aRenderBoundsOut = Rect();
     return;
   }
 
   UpdateRenderTarget();
 
-  gfxPlatform::GetPlatform()->WaitContentDrawing();
-
   // Failed to create a render target or the view.
   if (!mDefaultRT || !mDefaultRT->mRTView ||
       mSize.width == 0 || mSize.height == 0) {
     *aRenderBoundsOut = Rect();
     return;
   }
 
   mContext->IASetInputLayout(mAttachments->mInputLayout);
--- a/gfx/layers/d3d11/TextureD3D11.cpp
+++ b/gfx/layers/d3d11/TextureD3D11.cpp
@@ -352,29 +352,29 @@ TextureClientD3D11::AllocateForSurface(g
   ID3D11Device* d3d11device = gfxWindowsPlatform::GetPlatform()->GetD3D11ContentDevice();
 
   if (gfxPrefs::Direct2DUse1_1() && d3d11device) {
 
     CD3D11_TEXTURE2D_DESC newDesc(mFormat == SurfaceFormat::A8 ? DXGI_FORMAT_A8_UNORM : DXGI_FORMAT_B8G8R8A8_UNORM,
                                   aSize.width, aSize.height, 1, 1,
                                   D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE);
 
-    newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
+    newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
 
     hr = d3d11device->CreateTexture2D(&newDesc, nullptr, byRef(mTexture));
   } else
 #endif
   {
     ID3D10Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
 
     CD3D10_TEXTURE2D_DESC newDesc(DXGI_FORMAT_B8G8R8A8_UNORM,
       aSize.width, aSize.height, 1, 1,
       D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE);
 
-    newDesc.MiscFlags = D3D10_RESOURCE_MISC_SHARED;
+    newDesc.MiscFlags = D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX;
 
     hr = device->CreateTexture2D(&newDesc, nullptr, byRef(mTexture10));
   }
 
   if (FAILED(hr)) {
     gfx::gfxCriticalError() << "[D3D11] CreateTexture2D failure " << aSize << " Code: " << gfx::hexa(hr);
     return false;
   }
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -242,18 +242,16 @@ public:
      * rendering to offscreen surfaces on this platform, making it safe to
      * render content to data surfaces. This is generally false on platforms
      * which use different backends for each type of DrawTarget.
      */
     virtual bool CanRenderContentToDataSurface() const {
       return false;
     }
 
-    virtual void FenceContentDrawing() {}
-    virtual void WaitContentDrawing() {}
     /**
      * Returns true if we should use Azure to render content with aTarget. For
      * example, it is possible that we are using Direct2D for rendering and thus
      * using Azure. But we want to render to a CairoDrawTarget, in which case
      * SupportsAzureContent will return true but SupportsAzureContentForDrawTarget
      * will return false.
      */
     bool SupportsAzureContentForDrawTarget(mozilla::gfx::DrawTarget* aTarget);
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -1429,116 +1429,16 @@ gfxWindowsPlatform::GetD3D9DeviceManager
       NS_WARNING("Could not initialise device manager");
       mDeviceManager = nullptr;
     }
   }
 
   return mDeviceManager;
 }
 
-ID3D11Texture2D*
-gfxWindowsPlatform::GetD3D11Texture()
-{
-  if (mD3D11Texture) {
-    return mD3D11Texture;
-  }
-
-  MOZ_ASSERT(mD3D10Texture || mD3D11ContentTexture);
-
-  RefPtr<IDXGIResource> resource;
-  if (mD3D10Texture) {
-    mD3D10Texture->QueryInterface((IDXGIResource**)byRef(resource));
-  } else {
-    mD3D11ContentTexture->QueryInterface((IDXGIResource**)byRef(resource));
-  }
-  HANDLE sharedHandle;
-  HRESULT hr = resource->GetSharedHandle(&sharedHandle);
-
-  hr = GetD3D11Device()->OpenSharedResource(sharedHandle,
-    __uuidof(ID3D11Texture2D),
-    (void**)(ID3D11Texture2D**)byRef(mD3D11Texture));
-
-  return mD3D11Texture;
-}
-
-ID3D11Texture2D*
-gfxWindowsPlatform::GetD3D11ContentTexture()
-{
-  if (mD3D11ContentTexture) {
-    return mD3D11ContentTexture;
-  }
-  ID3D11Device* device = GetD3D11ContentDevice();
-
-  CD3D11_TEXTURE2D_DESC newDesc(DXGI_FORMAT_B8G8R8A8_UNORM,
-    1, 1, 1, 1,
-    D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE);
-
-  newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
-
-  HRESULT hr = device->CreateTexture2D(&newDesc, nullptr, byRef(mD3D11ContentTexture));
-  return mD3D11ContentTexture;
-}
-
-ID3D10Texture2D*
-gfxWindowsPlatform::GetD3D10Texture()
-{
-  if (mD3D10Texture) {
-    return mD3D10Texture;
-  }
-  ID3D10Device* device = GetD3D10Device();
-
-  CD3D10_TEXTURE2D_DESC newDesc(DXGI_FORMAT_B8G8R8A8_UNORM,
-    1, 1, 1, 1,
-    D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE);
-
-  newDesc.MiscFlags = D3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX;
-
-  HRESULT hr = device->CreateTexture2D(&newDesc, nullptr, byRef(mD3D10Texture));
-  return mD3D10Texture;
-}
-
-void
-gfxWindowsPlatform::FenceContentDrawing()
-{
-#ifdef USE_D2D1_1
-  if (gfxPrefs::Direct2DUse1_1() && GetD3D11ContentDevice()) {
-    ID3D11Texture2D* tex = GetD3D11ContentTexture();
-    RefPtr<IDXGIKeyedMutex> mutex;
-    tex->QueryInterface((IDXGIKeyedMutex**)byRef(mutex));
-    mutex->AcquireSync(0, INFINITE);
-    RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForD3D11Texture(tex, SurfaceFormat::B8G8R8A8);
-    dt->ClearRect(Rect(0, 0, 1, 1));
-    dt->Flush();
-    dt = nullptr;
-    mutex->ReleaseSync(0);
-  } else
-#endif
-  if (GetD3D10Device()) {
-    ID3D10Texture2D* tex = GetD3D10Texture();
-    RefPtr<IDXGIKeyedMutex> mutex;
-    tex->QueryInterface((IDXGIKeyedMutex**)byRef(mutex));
-    mutex->AcquireSync(0, INFINITE);
-    RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForD3D10Texture(tex, SurfaceFormat::B8G8R8A8);
-    dt->ClearRect(Rect(0, 0, 1, 1));
-    dt->Flush();
-    dt = nullptr;
-    mutex->ReleaseSync(0);
-  }
-}
-
-void
-gfxWindowsPlatform::WaitContentDrawing()
-{
-  ID3D11Texture2D *sentinelTexture = GetD3D11Texture();
-  RefPtr<IDXGIKeyedMutex> mutex;
-  sentinelTexture->QueryInterface((IDXGIKeyedMutex**)byRef(mutex));
-  mutex->AcquireSync(0, INFINITE);
-  mutex->ReleaseSync(0);
-}
-
 ID3D11Device*
 gfxWindowsPlatform::GetD3D11Device()
 {
   if (mD3D11DeviceInitialized) {
     return mD3D11Device;
   }
 
   InitD3D11Devices();
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -50,17 +50,16 @@ class DrawTarget;
 namespace layers {
 class DeviceManagerD3D9;
 class ReadbackManagerD3D11;
 }
 }
 struct IDirect3DDevice9;
 struct ID3D11Device;
 struct IDXGIAdapter1;
-struct ID3D11Texture2D;
 
 class nsIMemoryReporter;
 
 /**
  * Utility to get a Windows HDC from a Moz2D DrawTarget.  If the DrawTarget is
  * not backed by a HDC this will get the HDC for the screen device context
  * instead.
  */
@@ -251,23 +250,16 @@ public:
     IDirect3DDevice9* GetD3D9Device();
 #ifdef CAIRO_HAS_D2D_SURFACE
     cairo_device_t *GetD2DDevice() { return mD2DDevice; }
     ID3D10Device1 *GetD3D10Device() { return mD2DDevice ? cairo_d2d_device_get_device(mD2DDevice) : nullptr; }
 #endif
     ID3D11Device *GetD3D11Device();
     ID3D11Device *GetD3D11ContentDevice();
 
-    ID3D10Texture2D* GetD3D10Texture();
-    ID3D11Texture2D* GetD3D11Texture();
-    ID3D11Texture2D* GetD3D11ContentTexture();
-
-    virtual void FenceContentDrawing();
-    virtual void WaitContentDrawing();
-
     mozilla::layers::ReadbackManagerD3D11* GetReadbackManager();
 
     static bool IsOptimus();
 
 protected:
     RenderMode mRenderMode;
 
     int8_t mUseClearTypeForDownloadableFonts;
@@ -292,21 +284,16 @@ private:
 #endif
     mozilla::RefPtr<IDXGIAdapter1> mAdapter;
     nsRefPtr<mozilla::layers::DeviceManagerD3D9> mDeviceManager;
     mozilla::RefPtr<ID3D11Device> mD3D11Device;
     mozilla::RefPtr<ID3D11Device> mD3D11ContentDevice;
     bool mD3D11DeviceInitialized;
     mozilla::RefPtr<mozilla::layers::ReadbackManagerD3D11> mD3D11ReadbackManager;
 
-    mozilla::RefPtr<ID3D10Texture2D> mD3D10Texture;
-    mozilla::RefPtr<ID3D11Texture2D> mD3D11Texture;
-    mozilla::RefPtr<ID3D11Texture2D> mD3D11ContentTexture;
-
-
     virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size);
 
     // TODO: unify this with mPrefFonts (NB: holds families, not fonts) in gfxPlatformFontList
     nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<gfxFontEntry> > > mPrefFonts;
 };
 
 bool DoesD3D11DeviceWork(ID3D11Device *device);
 
--- a/image/decoders/nsBMPDecoder.cpp
+++ b/image/decoders/nsBMPDecoder.cpp
@@ -7,16 +7,17 @@
 
 // This is a Cross-Platform BMP Decoder, which should work everywhere, including
 // Big-Endian machines like the PowerPC.
 
 #include <stdlib.h>
 
 #include "ImageLogging.h"
 #include "mozilla/Endian.h"
+#include "mozilla/Likely.h"
 #include "nsBMPDecoder.h"
 
 #include "nsIInputStream.h"
 #include "RasterImage.h"
 #include <algorithm>
 
 namespace mozilla {
 namespace image {
@@ -653,20 +654,20 @@ nsBMPDecoder::WriteInternal(const char* 
                                       (mCurLine - 1);
                     uint32_t heightDifference = GetHeight() -
                                                 mCurLine + 1;
                     uint32_t pixelCount = GetWidth() *
                                           heightDifference;
 
                     memset(start, 0, pixelCount * sizeof(uint32_t));
 
+                    PostHasTransparency();
                     mHaveAlphaData = true;
                   }
-                  SetPixel(d, p[2], p[1], p[0], mHaveAlphaData ?
-                           p[3] : 0xFF);
+                  SetPixel(d, p[2], p[1], p[0], mHaveAlphaData ?  p[3] : 0xFF);
                 } else {
                   SetPixel(d, p[2], p[1], p[0]);
                 }
                 p += 4;
                 --lpos;
               }
               break;
             default:
@@ -784,31 +785,37 @@ nsBMPDecoder::WriteInternal(const char* 
 
           case eRLEStateNeedXDelta:
             // Handle the XDelta and proceed to get Y Delta
             byte = *aBuffer++;
             aCount--;
             mCurPos += byte;
             // Delta encoding makes it possible to skip pixels
             // making the image transparent.
+            if (MOZ_UNLIKELY(!mHaveAlphaData)) {
+                PostHasTransparency();
+            }
             mUseAlphaData = mHaveAlphaData = true;
             if (mCurPos > mBIH.width) {
                 mCurPos = mBIH.width;
             }
 
             mState = eRLEStateNeedYDelta;
             continue;
 
           case eRLEStateNeedYDelta:
             // Get the Y Delta and then "handle" the move
             byte = *aBuffer++;
             aCount--;
             mState = eRLEStateInitial;
             // Delta encoding makes it possible to skip pixels
             // making the image transparent.
+            if (MOZ_UNLIKELY(!mHaveAlphaData)) {
+                PostHasTransparency();
+            }
             mUseAlphaData = mHaveAlphaData = true;
             mCurLine -= std::min<int32_t>(byte, mCurLine);
             break;
 
           case eRLEStateAbsoluteMode: // Absolute Mode
           case eRLEStateAbsoluteModePadded:
             if (mStateData) {