Merge m-c to fx-team. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 26 Aug 2014 16:12:08 -0400
changeset 223320 2e9bbd03df15c5fc0bd25326a6c322eb82302764
parent 223319 c7ee261eed1b5c4a4e65f1f53a506d8c23adfbf3 (current diff)
parent 223310 f9bfe115fee5f0ee933bbd4876daa7bb45f9d1c2 (diff)
child 223321 11930a45d9a7754b4ee63cdb20d960ba848cfab6
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone34.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to fx-team. a=merge
browser/themes/linux/aboutPrivateBrowsing.css
browser/themes/osx/aboutPrivateBrowsing.css
browser/themes/windows/aboutPrivateBrowsing.css
js/src/assembler/assembler/MacroAssemblerX86Common.cpp
js/src/assembler/assembler/MacroAssemblerX86Common.h
netwerk/test/unit/test_bug952927.js
parser/htmlparser/public/moz.build
parser/htmlparser/public/nsHTMLTagList.h
parser/htmlparser/public/nsHTMLTags.h
parser/htmlparser/public/nsIContentSink.h
parser/htmlparser/public/nsIDTD.h
parser/htmlparser/public/nsIExpatSink.idl
parser/htmlparser/public/nsIExtendedExpatSink.idl
parser/htmlparser/public/nsIFragmentContentSink.h
parser/htmlparser/public/nsIHTMLContentSink.h
parser/htmlparser/public/nsIParser.h
parser/htmlparser/public/nsIParserService.h
parser/htmlparser/public/nsITokenizer.h
parser/htmlparser/public/nsParserBase.h
parser/htmlparser/public/nsParserCIID.h
parser/htmlparser/public/nsParserConstants.h
parser/htmlparser/public/nsScannerString.h
parser/htmlparser/public/nsToken.h
parser/htmlparser/src/CNavDTD.cpp
parser/htmlparser/src/CNavDTD.h
parser/htmlparser/src/CParserContext.cpp
parser/htmlparser/src/CParserContext.h
parser/htmlparser/src/moz.build
parser/htmlparser/src/nsElementTable.cpp
parser/htmlparser/src/nsElementTable.h
parser/htmlparser/src/nsExpatDriver.cpp
parser/htmlparser/src/nsExpatDriver.h
parser/htmlparser/src/nsHTMLEntities.cpp
parser/htmlparser/src/nsHTMLEntities.h
parser/htmlparser/src/nsHTMLEntityList.h
parser/htmlparser/src/nsHTMLTags.cpp
parser/htmlparser/src/nsHTMLTokenizer.cpp
parser/htmlparser/src/nsHTMLTokenizer.h
parser/htmlparser/src/nsParser.cpp
parser/htmlparser/src/nsParser.h
parser/htmlparser/src/nsParserModule.cpp
parser/htmlparser/src/nsParserMsgUtils.cpp
parser/htmlparser/src/nsParserMsgUtils.h
parser/htmlparser/src/nsParserService.cpp
parser/htmlparser/src/nsParserService.h
parser/htmlparser/src/nsScanner.cpp
parser/htmlparser/src/nsScanner.h
parser/htmlparser/src/nsScannerString.cpp
parser/xml/public/moz.build
parser/xml/public/nsIMozSAXXMLDeclarationHandler.idl
parser/xml/public/nsISAXAttributes.idl
parser/xml/public/nsISAXContentHandler.idl
parser/xml/public/nsISAXDTDHandler.idl
parser/xml/public/nsISAXErrorHandler.idl
parser/xml/public/nsISAXLexicalHandler.idl
parser/xml/public/nsISAXLocator.idl
parser/xml/public/nsISAXMutableAttributes.idl
parser/xml/public/nsISAXXMLFilter.idl
parser/xml/public/nsISAXXMLReader.idl
parser/xml/src/moz.build
parser/xml/src/nsSAXAttributes.cpp
parser/xml/src/nsSAXAttributes.h
parser/xml/src/nsSAXLocator.cpp
parser/xml/src/nsSAXLocator.h
parser/xml/src/nsSAXXMLReader.cpp
parser/xml/src/nsSAXXMLReader.h
testing/mozbase/docs/mozlog.rst
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -1008,8 +1008,11 @@ pref("identity.fxaccounts.enabled", true
 
 // Mobile Identity API.
 pref("services.mobileid.server.uri", "https://msisdn.services.mozilla.com");
 
 // Enable mapped array buffer.
 #ifndef XP_WIN
 pref("dom.mapped_arraybuffer.enabled", true);
 #endif
+
+// UDPSocket API
+pref("dom.udpsocket.enabled", true);
new file mode 100644
--- /dev/null
+++ b/b2g/components/B2GAppMigrator.js
@@ -0,0 +1,98 @@
+/* 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';
+
+function debug(s) {
+  dump("-*- B2GAppMigrator.js: " + s + "\n");
+}
+const DEBUG = false;
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+const kMigrationMessageName = "webapps-before-update-merge";
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/FileUtils.jsm");
+
+XPCOMUtils.defineLazyServiceGetter(this, "appsService",
+                                   "@mozilla.org/AppsService;1",
+                                   "nsIAppsService");
+
+function B2GAppMigrator() {
+  Services.obs.addObserver(this, kMigrationMessageName, false);
+  Services.obs.addObserver(this, "xpcom-shutdown", false);
+}
+
+B2GAppMigrator.prototype = {
+  classID:         Components.ID('{7211ece0-b458-4635-9afc-f8d7f376ee95}'),
+  QueryInterface:  XPCOMUtils.generateQI([Ci.nsIObserver,
+                                          Ci.nsISupportsWeakReference]),
+  executeBrowserMigration: function() {
+    // The browser db name is hashed the same way everywhere, so it
+    // should be the same on all systems. We should be able to just
+    // hardcode it.
+    let browserDBFileName = "2959517650brreosw.sqlite";
+
+    // Storage directories need to be prefixed with the local id of
+    // the app
+    let browserLocalAppId = appsService.getAppLocalIdByManifestURL("app://browser.gaiamobile.org/manifest.webapp");
+    let browserAppStorageDirName = browserLocalAppId + "+f+app+++browser.gaiamobile.org";
+    let browserDBFile = FileUtils.getFile("ProfD",
+                                          ["storage",
+                                           "persistent",
+                                           browserAppStorageDirName,
+                                           "idb",
+                                           browserDBFileName], true);
+
+    if (!browserDBFile.exists()) {
+      if (DEBUG) debug("Browser DB file does not exist, nothing to copy");
+      return;
+    }
+
+    let systemLocalAppId = appsService.getAppLocalIdByManifestURL("app://system.gaiamobile.org/manifest.webapp");
+    let systemAppStorageDirName = systemLocalAppId + "+f+app+++system.gaiamobile.org";
+    let systemDBDir = FileUtils.getDir("ProfD",
+                                       ["storage",
+                                        "persistent",
+                                        systemAppStorageDirName,
+                                        "idb"], false, true);
+
+    if (DEBUG) {
+      debug("Browser DB file exists, copying");
+      debug("Browser local id: " + browserLocalAppId + "");
+      debug("System local id: " + systemLocalAppId + "");
+      debug("Browser DB file path: " + browserDBFile.path + "");
+      debug("System DB directory path: " + systemDBDir.path + "");
+    }
+
+    try {
+      browserDBFile.copyTo(systemDBDir, browserDBFileName);
+    } catch (e) {
+      debug("File copy caused error! " + e.name);
+    }
+    if (DEBUG) debug("Browser DB copied successfully");
+  },
+
+  observe: function(subject, topic, data) {
+    switch (topic) {
+      case kMigrationMessageName:
+        this.executeBrowserMigration();
+        Services.obs.removeObserver(this, kMigrationMessageName);
+        break;
+      case "xpcom-shutdown":
+        Services.obs.removeObserver(this, kMigrationMessageName);
+        Services.obs.removeObserver(this, "xpcom-shutdown");
+        break;
+      default:
+        debug("Unhandled topic: " + topic);
+        break;
+    }
+  }
+};
+
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([B2GAppMigrator]);
--- a/b2g/components/B2GComponents.manifest
+++ b/b2g/components/B2GComponents.manifest
@@ -96,8 +96,13 @@ category profile-after-change SimulatorS
 component {e30b0e13-2d12-4cb0-bc4c-4e617a1bf76e} OopCommandLine.js
 contract @mozilla.org/commandlinehandler/general-startup;1?type=b2goop {e30b0e13-2d12-4cb0-bc4c-4e617a1bf76e}
 category command-line-handler m-b2goop @mozilla.org/commandlinehandler/general-startup;1?type=b2goop
 #endif
 
 # MobileIdentityUIGlue.js
 component {83dbe26a-81f3-4a75-9541-3d0b7ca496b5} MobileIdentityUIGlue.js
 contract @mozilla.org/services/mobileid-ui-glue;1 {83dbe26a-81f3-4a75-9541-3d0b7ca496b5}
+
+# B2GAppMigrator.js
+component {7211ece0-b458-4635-9afc-f8d7f376ee95} B2GAppMigrator.js
+contract @mozilla.org/b2g-app-migrator;1 {7211ece0-b458-4635-9afc-f8d7f376ee95}
+category profile-after-change B2GAppMigrator @mozilla.org/b2g-app-migrator;1
\ No newline at end of file
--- a/b2g/components/moz.build
+++ b/b2g/components/moz.build
@@ -5,16 +5,17 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DIRS += ['test']
 
 EXTRA_COMPONENTS += [
     'ActivitiesGlue.js',
     'AlertsService.js',
     'B2GAboutRedirector.js',
+    'B2GAppMigrator.js',
     'ContentPermissionPrompt.js',
     'FilePicker.js',
     'FxAccountsUIGlue.js',
     'HelperAppDialog.js',
     'InterAppCommUIGlue.js',
     'MailtoProtocolHandler.js',
     'MobileIdentityUIGlue.js',
     'OMAContentHandler.js',
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,25 +10,25 @@
   <!--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="53a59364ce4f14068034c8d6fe01f4f6b9f78f23">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="4d1d0ea5a82cddeeab497774cfa1703639e3c7d9"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="ea93363a8c424d65a9ad91438ce6961377a20f98"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <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="d59843c1d66bd8d93c6012efda47fa447b99813c"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="193c5b27148f44e3960fa5484c149866f4e9fe65"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="83760d213fb3bec7b4117d266fcfbf6fe2ba14ab"/>
   <project name="device/common" path="device/common" revision="6a2995683de147791e516aae2ccb31fdfbe2ad30"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,23 +14,23 @@
   <!--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="0d616942c300d9fb142483210f1dda9096c9a9fc">
     <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="4d1d0ea5a82cddeeab497774cfa1703639e3c7d9"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ea93363a8c424d65a9ad91438ce6961377a20f98"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <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="a567a787b5ac3e0cb663aa6464b18a24ec764409"/>
+  <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="d59843c1d66bd8d93c6012efda47fa447b99813c"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="193c5b27148f44e3960fa5484c149866f4e9fe65"/>
   <!-- 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"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,20 +12,20 @@
   <!--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="7eef86294cd794ab9e6a53d218c238bfc63c3a6d">
     <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="4d1d0ea5a82cddeeab497774cfa1703639e3c7d9"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="ea93363a8c424d65a9ad91438ce6961377a20f98"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="d59843c1d66bd8d93c6012efda47fa447b99813c"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="193c5b27148f44e3960fa5484c149866f4e9fe65"/>
   <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"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,25 +10,25 @@
   <!--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="53a59364ce4f14068034c8d6fe01f4f6b9f78f23">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="4d1d0ea5a82cddeeab497774cfa1703639e3c7d9"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="ea93363a8c424d65a9ad91438ce6961377a20f98"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <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="d59843c1d66bd8d93c6012efda47fa447b99813c"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="193c5b27148f44e3960fa5484c149866f4e9fe65"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="1950e4760fa14688b83cdbb5acaa1af9f82ef434"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="ac6eb97a37035c09fb5ede0852f0881e9aadf9ad"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="737f591c5f95477148d26602c7be56cbea0cdeb9"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="51da9b1981be481b92a59a826d4d78dc73d0989a"/>
   <project name="device/common" path="device/common" revision="798a3664597e6041985feab9aef42e98d458bc3d"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,23 +14,23 @@
   <!--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="0d616942c300d9fb142483210f1dda9096c9a9fc">
     <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="4d1d0ea5a82cddeeab497774cfa1703639e3c7d9"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ea93363a8c424d65a9ad91438ce6961377a20f98"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <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="a567a787b5ac3e0cb663aa6464b18a24ec764409"/>
+  <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="d59843c1d66bd8d93c6012efda47fa447b99813c"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="193c5b27148f44e3960fa5484c149866f4e9fe65"/>
   <!-- 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"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,20 +12,20 @@
   <!--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="7eef86294cd794ab9e6a53d218c238bfc63c3a6d">
     <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="4d1d0ea5a82cddeeab497774cfa1703639e3c7d9"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="ea93363a8c424d65a9ad91438ce6961377a20f98"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="d59843c1d66bd8d93c6012efda47fa447b99813c"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="193c5b27148f44e3960fa5484c149866f4e9fe65"/>
   <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"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "0ce5a025c89f6120b55498528323a8a973dd117e", 
+    "revision": "c6e222c3d86410830558dcf89436313b431da418", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,22 +12,22 @@
   <!--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="0d616942c300d9fb142483210f1dda9096c9a9fc">
     <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="4d1d0ea5a82cddeeab497774cfa1703639e3c7d9"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ea93363a8c424d65a9ad91438ce6961377a20f98"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <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="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="d59843c1d66bd8d93c6012efda47fa447b99813c"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="193c5b27148f44e3960fa5484c149866f4e9fe65"/>
   <!-- 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"/>
   <project name="platform/development" path="development" revision="2460485184bc8535440bb63876d4e63ec1b4770c"/>
   <project name="device/common" path="device/common" revision="0dcc1e03659db33b77392529466f9eb685cdd3c7"/>
   <project name="device/sample" path="device/sample" revision="68b1cb978a20806176123b959cb05d4fa8adaea4"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
--- 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="0d616942c300d9fb142483210f1dda9096c9a9fc">
     <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="4d1d0ea5a82cddeeab497774cfa1703639e3c7d9"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ea93363a8c424d65a9ad91438ce6961377a20f98"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <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="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <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/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,20 +12,20 @@
   <!--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="7eef86294cd794ab9e6a53d218c238bfc63c3a6d">
     <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="4d1d0ea5a82cddeeab497774cfa1703639e3c7d9"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="ea93363a8c424d65a9ad91438ce6961377a20f98"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="d59843c1d66bd8d93c6012efda47fa447b99813c"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="193c5b27148f44e3960fa5484c149866f4e9fe65"/>
   <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"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,22 +12,22 @@
   <!--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="0d616942c300d9fb142483210f1dda9096c9a9fc">
     <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="4d1d0ea5a82cddeeab497774cfa1703639e3c7d9"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ea93363a8c424d65a9ad91438ce6961377a20f98"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <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="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="d59843c1d66bd8d93c6012efda47fa447b99813c"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="193c5b27148f44e3960fa5484c149866f4e9fe65"/>
   <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="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="e0a9ac010df3afaa47ba107192c05ac8b5516435"/>
   <project name="platform/development" path="development" revision="a384622f5fcb1d2bebb9102591ff7ae91fe8ed2d"/>
   <project name="device/common" path="device/common" revision="7c65ea240157763b8ded6154a17d3c033167afb7"/>
   <project name="device/sample" path="device/sample" revision="c328f3d4409db801628861baa8d279fb8855892f"/>
--- a/b2g/confvars.sh
+++ b/b2g/confvars.sh
@@ -43,17 +43,16 @@ if test "$LIBXUL_SDK"; then
 MOZ_XULRUNNER=1
 else
 MOZ_XULRUNNER=
 fi
 
 MOZ_MEDIA_NAVIGATOR=1
 
 MOZ_APP_ID={3c2e2abc-06d4-11e1-ac3b-374f68613e61}
-MOZ_EXTENSION_MANAGER=1
 
 MOZ_TIME_MANAGER=1
 
 MOZ_PAY=1
 MOZ_TOOLKIT_SEARCH=
 MOZ_PLACES=
 MOZ_B2G=1
 
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -826,16 +826,17 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DL
 @BINPATH@/components/SmsProtocolHandler.js
 @BINPATH@/components/TelProtocolHandler.js
 @BINPATH@/components/B2GAboutRedirector.js
 @BINPATH@/components/FilePicker.js
 @BINPATH@/components/HelperAppDialog.js
 @BINPATH@/components/DownloadsUI.js
 @BINPATH@/components/InterAppCommUIGlue.js
 @BINPATH@/components/SystemMessageGlue.js
+@BINPATH@/components/B2GAppMigrator.js
 
 #ifndef MOZ_WIDGET_GONK
 @BINPATH@/components/SimulatorScreen.js
 #endif
 
 @BINPATH@/components/FxAccountsUIGlue.js
 @BINPATH@/components/services_fxaccounts.xpt
 
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.css
@@ -0,0 +1,61 @@
+%if 0
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+%endif
+
+@import url("chrome://global/skin/in-content/common.css");
+
+body {
+  display: flex;
+  box-sizing: padding-box;
+  min-height: 100vh;
+  padding: 0 48px;
+  align-items: center;
+  justify-content: center;
+}
+
+body.normal .showPrivate,
+body.private .showNormal {
+  display: none;
+}
+
+#pageContainer {
+  min-width: 320px;
+  max-width: 512px;
+}
+
+.titleText {
+  background: url("chrome://browser/skin/mask.png") left 0 no-repeat;
+  background-size: 45px;
+  -moz-margin-start: -2em;
+  -moz-padding-start: 2em;
+}
+
+.titleText:-moz-dir(rtl) {
+  background-position: right 0;
+}
+
+@media (min-resolution: 2dppx) {
+  .titleText {
+    background-image: url("chrome://browser/skin/mask@2x.png");
+  }
+}
+
+@media (max-width: 675px) {
+  .titleText {
+    padding-top: 0;
+    background-image: none;
+    -moz-margin-start: 0;
+    -moz-padding-start: 0;
+  }
+}
+
+a {
+  font-size: 1rem;
+}
+
+button {
+  margin-top: 1.2em;
+  -moz-margin-start: 0;
+}
--- a/browser/components/privatebrowsing/content/aboutPrivateBrowsing.xhtml
+++ b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.xhtml
@@ -8,42 +8,34 @@
   <!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
   %htmlDTD;
   <!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
   %globalDTD;
   <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
   %brandDTD;
   <!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
   %browserDTD;
-  <!ENTITY % privatebrowsingpageDTD SYSTEM "chrome://browser/locale/aboutPrivateBrowsing.dtd">
-  %privatebrowsingpageDTD;
+  <!ENTITY % aboutPrivateBrowsingDTD SYSTEM "chrome://browser/locale/aboutPrivateBrowsing.dtd">
+  %aboutPrivateBrowsingDTD;
 ]>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
   <head>
-    <link rel="stylesheet" href="chrome://global/skin/netError.css" type="text/css" media="all"/>
-    <link rel="stylesheet" href="chrome://browser/skin/aboutPrivateBrowsing.css" type="text/css" media="all"/>
-    <style type="text/css"><![CDATA[
-      body.normal .showPrivate,
-      body.private .showNormal {
-        display: none;
-      }
-    ]]></style>
+    <link rel="stylesheet" href="chrome://browser/content/aboutPrivateBrowsing.css" type="text/css" media="all"/>
     <script type="application/javascript;version=1.7"><![CDATA[
-      const Cc = Components.classes;
-      const Ci = Components.interfaces;
+      const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
-      Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
+      Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
 
       if (!PrivateBrowsingUtils.isWindowPrivate(window)) {
-        document.title = "]]>&privatebrowsingpage.title.normal;<![CDATA[";
+        document.title = "]]>&aboutPrivateBrowsing.title.normal;<![CDATA[";
         setFavIcon("chrome://global/skin/icons/question-16.png");
       } else {
 #ifndef XP_MACOSX
-        document.title = "]]>&privatebrowsingpage.title;<![CDATA[";
+        document.title = "]]>&aboutPrivateBrowsing.title;<![CDATA[";
 #endif
         setFavIcon("chrome://browser/skin/Privacy-16.png");
       }
 
       var mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
                              .getInterface(Ci.nsIWebNavigation)
                              .QueryInterface(Ci.nsIDocShellTreeItem)
                              .rootTreeItem
@@ -60,76 +52,47 @@
       }
 
       document.addEventListener("DOMContentLoaded", function () {
         if (!PrivateBrowsingUtils.isWindowPrivate(window)) {
           document.body.setAttribute("class", "normal");
         }
 
         // Set up the help link
-        let moreInfoURL = Cc["@mozilla.org/toolkit/URLFormatterService;1"].
-                          getService(Ci.nsIURLFormatter).
-                          formatURLPref("app.support.baseURL");
-        let moreInfoLink = document.getElementById("moreInfoLink");
-        if (moreInfoLink)
-          moreInfoLink.setAttribute("href", moreInfoURL + "private-browsing");
+        let learnMoreURL = Cc["@mozilla.org/toolkit/URLFormatterService;1"]
+                           .getService(Ci.nsIURLFormatter)
+                           .formatURLPref("app.support.baseURL");
+        let learnMore = document.getElementById("learnMore");
+        if (learnMore) {
+          learnMore.setAttribute("href", learnMoreURL + "private-browsing");
+        }
       }, false);
 
       function openPrivateWindow() {
         mainWindow.OpenBrowserWindow({private: true});
       }
     ]]></script>
   </head>
 
-  <body dir="&locale.dir;"
-        class="private">
-
-    <!-- PAGE CONTAINER (for styling purposes only) -->
-    <div id="errorPageContainer">
+  <body dir="&locale.dir;" class="private">
+    <div id="pageContainer">
+      <h1 class="titleText showPrivate">&aboutPrivateBrowsing.title;</h1>
+      <h1 class="titleText showNormal">&aboutPrivateBrowsing.title.normal;</h1>
 
-      <!-- Error Title -->
-      <div id="errorTitle">
-        <h1 id="errorTitleText" class="showPrivate">&privatebrowsingpage.title;</h1>
-        <h1 id="errorTitleTextNormal" class="showNormal">&privatebrowsingpage.title.normal;</h1>
-      </div>
+      <p class="showPrivate">&aboutPrivateBrowsing.subtitle;</p>
+      <p class="showNormal">&aboutPrivateBrowsing.subtitle.normal;</p>
 
-      <!-- LONG CONTENT (the section most likely to require scrolling) -->
-      <div id="errorLongContent">
-
-        <!-- Short Description -->
-        <div id="errorShortDesc">
-          <p id="errorShortDescText" class="showPrivate">&privatebrowsingpage.perwindow.issueDesc;</p>
-          <p id="errorShortDescTextNormal" class="showNormal">&privatebrowsingpage.perwindow.issueDesc.normal;</p>
-        </div>
+      <p>&aboutPrivateBrowsing.description;</p>
 
-        <!-- Long Description -->
-        <div id="errorLongDesc">
-          <p id="errorLongDescText">&privatebrowsingpage.perwindow.description;</p>
-        </div>
-
-        <!-- Start Private Browsing -->
-        <div id="startPrivateBrowsingDesc" class="showNormal">
-          <button xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-                  id="startPrivateBrowsing" label="&privatebrowsingpage.openPrivateWindow.label;"
-                  accesskey="&privatebrowsingpage.openPrivateWindow.accesskey;"
-                  oncommand="openPrivateWindow();"/>
-        </div>
+      <p class="showNormal">&aboutPrivateBrowsing.notPrivate;</p>
 
-        <!-- Footer -->
-        <div id="footerDesc">
-          <p id="footerText" class="showPrivate">&privatebrowsingpage.howToStop3;</p>
-          <p id="footerTextNormal" class="showNormal">&privatebrowsingpage.howToStart4;</p>
-        </div>
-
-        <!-- More Info -->
-        <div id="moreInfo" class="showPrivate">
-          <p id="moreInfoText">
-            &privatebrowsingpage.moreInfo;
-          </p>
-          <p id="moreInfoLinkContainer">
-            <a id="moreInfoLink" target="_blank">&privatebrowsingpage.learnMore;</a>
-          </p>
-        </div>
+      <button xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+              class="showNormal"
+              label="&privatebrowsingpage.openPrivateWindow.label;"
+              accesskey="&privatebrowsingpage.openPrivateWindow.accesskey;"
+              oncommand="openPrivateWindow();"/>
+      <div class="showPrivate">
+        <p>&aboutPrivateBrowsing.moreInfo;</p>
+        <p><a id="learnMore" target="_blank">&aboutPrivateBrowsing.learnMore;</a></p>
       </div>
     </div>
-
   </body>
 </html>
--- a/browser/components/privatebrowsing/jar.mn
+++ b/browser/components/privatebrowsing/jar.mn
@@ -1,6 +1,7 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 browser.jar:
+*   content/browser/aboutPrivateBrowsing.css              (content/aboutPrivateBrowsing.css)
 *   content/browser/aboutPrivateBrowsing.xhtml            (content/aboutPrivateBrowsing.xhtml) 
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_windowtitle.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_windowtitle.js
@@ -19,28 +19,28 @@ function test() {
   let page_without_title;
   let about_pb_title;
   let pb_page_with_title;
   let pb_page_without_title;
   let pb_about_pb_title;
   if (isOSX) {
     page_with_title = test_title;
     page_without_title = app_name;
-    about_pb_title = "Would you like to start Private Browsing?";
+    about_pb_title = "Open a private window?";
     pb_page_with_title = test_title + " - (Private Browsing)";
     pb_page_without_title = app_name + " - (Private Browsing)";
     pb_about_pb_title = pb_page_without_title;
   }
   else {
     page_with_title = test_title + " - " + app_name;
     page_without_title = app_name;
-    about_pb_title = "Would you like to start Private Browsing?" + " - " + app_name;
+    about_pb_title = "Open a private window?" + " - " + app_name;
     pb_page_with_title = test_title + " - " + app_name + " (Private Browsing)";
     pb_page_without_title = app_name + " (Private Browsing)";
-    pb_about_pb_title = "Private Browsing - " + app_name + " (Private Browsing)";
+    pb_about_pb_title = "You're browsing privately - " + app_name + " (Private Browsing)";
   }
 
   function testTabTitle(aWindow, url, insidePB, expected_title, funcNext) {
     executeSoon(function () {
       let tab = aWindow.gBrowser.selectedTab = aWindow.gBrowser.addTab();
       let browser = aWindow.gBrowser.selectedBrowser;
       browser.stop();
       // ensure that the test is run after the titlebar has been updated
--- a/browser/components/selfsupport/SelfSupportService.js
+++ b/browser/components/selfsupport/SelfSupportService.js
@@ -22,28 +22,22 @@ XPCOMUtils.defineLazyGetter(this, "repor
 
 function MozSelfSupportInterface() {
 }
 
 MozSelfSupportInterface.prototype = {
   classDescription: "MozSelfSupport",
   classID: Components.ID("{d30aae8b-f352-4de3-b936-bb9d875df0bb}"),
   contractID: "@mozilla.org/mozselfsupport;1",
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
-                                         Ci.nsIObserver]),
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer]),
 
   _window: null,
 
   init: function (window) {
     this._window = window;
-
-    // FIXME: Remove this hack after static attributes work for JS-implemented
-    // WebIDL (see bug 863952). For a detailed description of how this works,
-    // see the comment accompanying the init function of amInstallTrigger.js.
-    return window.MozSelfSupportImpl._create(this._window, this);
   },
 
   get healthReportDataSubmissionEnabled() {
     return policy.healthReportUploadEnabled;
   },
 
   set healthReportDataSubmissionEnabled(enabled) {
     let reason = "Self-support interface sent " +
--- a/browser/components/selfsupport/SelfSupportService.manifest
+++ b/browser/components/selfsupport/SelfSupportService.manifest
@@ -1,4 +1,2 @@
 component {d30aae8b-f352-4de3-b936-bb9d875df0bb} SelfSupportService.js
 contract @mozilla.org/mozselfsupport;1 {d30aae8b-f352-4de3-b936-bb9d875df0bb}
-
-category JavaScript-global-privileged-property MozSelfSupport @mozilla.org/mozselfsupport;1
--- a/browser/confvars.sh
+++ b/browser/confvars.sh
@@ -46,17 +46,16 @@ MOZ_OFFICIAL_BRANDING_DIRECTORY=browser/
 MOZ_APP_ID={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
 # This should usually be the same as the value MAR_CHANNEL_ID.
 # If more than one ID is needed, then you should use a comma separated list
 # of values.
 ACCEPTED_MAR_CHANNEL_IDS=firefox-mozilla-central
 # The MAR_CHANNEL_ID must not contain the following 3 characters: ",\t "
 MAR_CHANNEL_ID=firefox-mozilla-central
 MOZ_PROFILE_MIGRATOR=1
-MOZ_EXTENSION_MANAGER=1
 MOZ_APP_STATIC_INI=1
 MOZ_WEBAPP_RUNTIME=1
 MOZ_MEDIA_NAVIGATOR=1
 if test "$OS_TARGET" = "WINNT" -o "$OS_TARGET" = "Darwin"; then
   MOZ_FOLD_LIBS=1
 fi
 MOZ_WEBGL_CONFORMANT=1
 # Enable navigator.mozPay
--- a/browser/locales/en-US/chrome/browser/aboutPrivateBrowsing.dtd
+++ b/browser/locales/en-US/chrome/browser/aboutPrivateBrowsing.dtd
@@ -1,26 +1,23 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
-<!ENTITY privatebrowsingpage.title                 "Private Browsing">
-<!ENTITY privatebrowsingpage.title.normal          "Would you like to start Private Browsing?">
+<!ENTITY aboutPrivateBrowsing.title            "You're browsing privately">
+<!ENTITY aboutPrivateBrowsing.title.normal     "Open a private window?">
+
+<!ENTITY aboutPrivateBrowsing.subtitle         "&brandShortName; won't remember any history for this window.">
+<!ENTITY aboutPrivateBrowsing.subtitle.normal  "&brandShortName; won't remember any history for private windows.">
 
-<!ENTITY privatebrowsingpage.perwindow.issueDesc        "&brandShortName; won't remember any history for this window.">
-<!ENTITY privatebrowsingpage.perwindow.issueDesc.normal "You are not currently in a private window.">
+<!ENTITY aboutPrivateBrowsing.description      "That includes browsing history, search history, download history, web form history, cookies, and temporary internet files. However, files you download and bookmarks you make will be kept.">
 
-<!ENTITY privatebrowsingpage.perwindow.description     "In a Private Browsing window, &brandShortName; won't keep any browser history, search history, download history, web form history, cookies, or temporary internet files.  However, files you download and bookmarks you make will be kept.">
+<!ENTITY aboutPrivateBrowsing.notPrivate       "You are currently not in a private window.">
+
+<!ENTITY aboutPrivateBrowsing.moreInfo         "While this computer won't have a record of your browsing history, your employer or internet service provider can still track the pages you visit.">
+<!ENTITY aboutPrivateBrowsing.learnMore        "Learn More.">
 
 <!ENTITY privatebrowsingpage.openPrivateWindow.label "Open a Private Window">
 <!ENTITY privatebrowsingpage.openPrivateWindow.accesskey "P">
 
-<!-- LOCALIZATION NOTE (privatebrowsingpage.howToStart4): please leave &newPrivateWindow.label; intact in the translation -->
-<!ENTITY privatebrowsingpage.howToStart4               "To start Private Browsing, you can also select &newPrivateWindow.label; from the menu.">
-<!ENTITY privatebrowsingpage.howToStop3                "To stop Private Browsing, you can close this window.">
-
-<!ENTITY privatebrowsingpage.moreInfo                  "While this computer won't have a record of your browsing history, your internet service provider or employer can still track the pages you visit.">
-<!ENTITY privatebrowsingpage.learnMore                 "Learn More">
-
-
 <!-- TO BE REMOVED POST-AUSTRALIS --> 
 <!-- LOCALIZATION NOTE (privatebrowsingpage.howToStart3): please leave &basePBMenu.label; intact in the translation -->
 <!ENTITY privatebrowsingpage.howToStart3               "To start Private Browsing, you can also select &basePBMenu.label; &gt; &newPrivateWindow.label;.">
--- a/browser/metro/metroapp.ini.in
+++ b/browser/metro/metroapp.ini.in
@@ -7,16 +7,15 @@ Version=@GRE_MILESTONE@
 BuildID=@GRE_BUILDID@
 ID={99bceaaa-e3c6-48c1-b981-ef9b46b67d60}
 
 [Gecko]
 MinVersion=@GRE_MILESTONE@
 MaxVersion=@GRE_MILESTONE@
 
 [XRE]
-EnableExtensionManager=0
 EnableProfileMigrator=0
 
 [Crash Reporter]
 #if MOZILLA_OFFICIAL
 Enabled=1
 #endif
 ServerURL=https://crash-reports.mozilla.com/submit?id={99bceaaa-e3c6-48c1-b981-ef9b46b67d60}&version=@GRE_MILESTONE@&buildid=@GRE_BUILDID@
deleted file mode 100644
--- a/browser/themes/linux/aboutPrivateBrowsing.css
+++ /dev/null
@@ -1,47 +0,0 @@
-%if 0
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-%endif
-
-body.private > #errorPageContainer {
-  background-image: url("chrome://browser/skin/Privacy-48.png");
-}
-
-body.normal > #errorPageContainer {
-  background-image: url("moz-icon://stock/gtk-dialog-question?size=dialog");
-}
-
-#clearRecentHistoryDesc {
-  margin-top: 2em;
-}
-
-#clearRecentHistoryDesc > p {
-  font-size: 110%; /* to match the value set in chrome://global/skin/netError.css */
-}
-
-#startPrivateBrowsingDesc > button {
-  -moz-margin-start: 0;
-}
-
-#footerDesc > p {
-  font-size: 110%; /* to match the value set in chrome://global/skin/netError.css */
-}
-
-#moreInfo {
-  font-size: 110%; /* to match the value set in chrome://global/skin/netError.css */
-  -moz-padding-start: 25px;
-  background: url("moz-icon://stock/gtk-dialog-info?size=menu") no-repeat top left;
-}
-
-#moreInfo:-moz-dir(rtl) {
-  background-position: top right;
-}
-
-#moreInfoText {
-  margin-bottom: 0;
-}
-
-#moreInfoLinkContainer {
-  margin-top: 0.5em;
-}
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -1,17 +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/.
 
 browser.jar:
 % skin browser classic/1.0 %skin/classic/browser/
 % override chrome://global/skin/icons/warning-16.png moz-icon://stock/gtk-dialog-warning?size=menu
   skin/classic/browser/sanitizeDialog.css
-* skin/classic/browser/aboutPrivateBrowsing.css
 * skin/classic/browser/aboutSessionRestore.css
   skin/classic/browser/aboutSessionRestore-window-icon.png
   skin/classic/browser/aboutWelcomeBack.css                     (../shared/aboutWelcomeBack.css)
   skin/classic/browser/aboutCertError.css
   skin/classic/browser/aboutCertError_sectionCollapsed.png
   skin/classic/browser/aboutCertError_sectionCollapsed-rtl.png
   skin/classic/browser/aboutCertError_sectionExpanded.png
   skin/classic/browser/aboutSocialError.css
@@ -30,16 +29,18 @@ browser.jar:
   skin/classic/browser/Geolocation-64.png
   skin/classic/browser/identity.png
   skin/classic/browser/identity-icons-generic.png
   skin/classic/browser/identity-icons-https.png
   skin/classic/browser/identity-icons-https-ev.png
   skin/classic/browser/identity-icons-https-mixed-active.png
   skin/classic/browser/identity-icons-https-mixed-display.png
   skin/classic/browser/Info.png
+  skin/classic/browser/mask.png                             (../shared/mask.png)
+  skin/classic/browser/mask@2x.png                          (../shared/mask@2x.png)
   skin/classic/browser/menuPanel.png
   skin/classic/browser/menuPanel-customize.png
   skin/classic/browser/menuPanel-exit.png
   skin/classic/browser/menuPanel-help.png
   skin/classic/browser/menuPanel-small.png
   skin/classic/browser/bad-content-blocked-16.png
   skin/classic/browser/bad-content-blocked-64.png
   skin/classic/browser/bad-content-unblocked-16.png
@@ -50,17 +51,16 @@ browser.jar:
 * skin/classic/browser/pageInfo.css
   skin/classic/browser/pageInfo.png
   skin/classic/browser/page-livemarks.png
   skin/classic/browser/pluginInstall-16.png
   skin/classic/browser/pluginInstall-64.png
   skin/classic/browser/pointerLock-16.png
   skin/classic/browser/pointerLock-64.png
   skin/classic/browser/Privacy-16.png
-  skin/classic/browser/Privacy-48.png
   skin/classic/browser/privatebrowsing-mask.png
   skin/classic/browser/reload-stop-go.png
   skin/classic/browser/searchbar.css
   skin/classic/browser/Secure.png
   skin/classic/browser/Security-broken.png
   skin/classic/browser/setDesktopBackground.css
   skin/classic/browser/slowStartup-16.png
   skin/classic/browser/Toolbar.png
--- a/browser/themes/linux/preferences/preferences.css
+++ b/browser/themes/linux/preferences/preferences.css
@@ -69,28 +69,16 @@ label.small {
 #BrowserPreferences[animated="true"] #handlersView {
   height: 25em;
 }
 
 #BrowserPreferences[animated="false"] #handlersView {
   -moz-box-flex: 1;
 }
 
-/* Privacy Pane */
-
-/* styles for the link elements copied from .text-link in global.css */
-.inline-link {
-  color: -moz-nativehyperlinktext;
-  text-decoration: none;
-}
-
-.inline-link:hover {
-  text-decoration: underline;
-}
-
 /* Modeless Window Dialogs */
 .windowDialog,
 .windowDialog prefpane {
   padding: 0px;
 }
 
 .contentPane {
   margin: 9px 8px 5px 8px;
deleted file mode 100644
--- a/browser/themes/osx/aboutPrivateBrowsing.css
+++ /dev/null
@@ -1,47 +0,0 @@
-%if 0
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-%endif
-
-body.private > #errorPageContainer {
-  background-image: url("chrome://browser/skin/Privacy-48.png");
-}
-
-body.normal > #errorPageContainer {
-  background-image: url("chrome://global/skin/icons/question-64.png");
-}
-
-#clearRecentHistoryDesc {
-  margin-top: 2em;
-}
-
-#clearRecentHistoryDesc > p {
-  font-size: 110%; /* to match the value set in chrome://global/skin/netError.css */
-}
-
-#startPrivateBrowsingDesc > button {
-  -moz-margin-start: 0;
-}
-
-#footerDesc > p {
-  font-size: 110%; /* to match the value set in chrome://global/skin/netError.css */
-}
-
-#moreInfo {
-  font-size: 110%; /* to match the value set in chrome://global/skin/netError.css */
-  -moz-padding-start: 25px;
-  background: url("chrome://global/skin/icons/information-16.png") no-repeat top left;
-}
-
-#moreInfo:-moz-dir(rtl) {
-  background-position: top right;
-}
-
-#moreInfoText {
-  margin-bottom: 0;
-}
-
-#moreInfoLinkContainer {
-  margin-top: 0.5em;
-}
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -1,16 +1,15 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 browser.jar:
 % skin browser classic/1.0 %skin/classic/browser/
   skin/classic/browser/sanitizeDialog.css                   (sanitizeDialog.css)
-* skin/classic/browser/aboutPrivateBrowsing.css             (aboutPrivateBrowsing.css)
 * skin/classic/browser/aboutSessionRestore.css              (aboutSessionRestore.css)
   skin/classic/browser/aboutSessionRestore-window-icon.png
   skin/classic/browser/aboutWelcomeBack.css                 (../shared/aboutWelcomeBack.css)
   skin/classic/browser/aboutCertError.css
   skin/classic/browser/aboutCertError_sectionCollapsed.png
   skin/classic/browser/aboutCertError_sectionCollapsed-rtl.png
   skin/classic/browser/aboutCertError_sectionExpanded.png
   skin/classic/browser/aboutSocialError.css
@@ -48,16 +47,18 @@ browser.jar:
   skin/classic/browser/KUI-background.png
   skin/classic/browser/subtle-pattern.png
   skin/classic/browser/menu-back.png
   skin/classic/browser/menu-forward.png
   skin/classic/browser/notification-16.png
   skin/classic/browser/notification-16@2x.png
   skin/classic/browser/notification-64.png
   skin/classic/browser/notification-64@2x.png
+  skin/classic/browser/mask.png                             (../shared/mask.png)
+  skin/classic/browser/mask@2x.png                          (../shared/mask@2x.png)
   skin/classic/browser/menuPanel.png
   skin/classic/browser/menuPanel@2x.png
   skin/classic/browser/menuPanel-customize.png
   skin/classic/browser/menuPanel-customize@2x.png
   skin/classic/browser/menuPanel-exit.png
   skin/classic/browser/menuPanel-exit@2x.png
   skin/classic/browser/menuPanel-help.png
   skin/classic/browser/menuPanel-help@2x.png
@@ -81,17 +82,16 @@ browser.jar:
   skin/classic/browser/pluginInstall-16@2x.png
   skin/classic/browser/pluginInstall-64.png
   skin/classic/browser/pluginInstall-64@2x.png
   skin/classic/browser/pointerLock-16.png
   skin/classic/browser/pointerLock-16@2x.png
   skin/classic/browser/pointerLock-64.png
   skin/classic/browser/pointerLock-64@2x.png
   skin/classic/browser/Privacy-16.png
-  skin/classic/browser/Privacy-48.png
   skin/classic/browser/privatebrowsing-mask.png
   skin/classic/browser/privatebrowsing-mask@2x.png
   skin/classic/browser/privatebrowsing-mask-short.png
   skin/classic/browser/privatebrowsing-mask-short@2x.png
   skin/classic/browser/reload-stop-go.png
   skin/classic/browser/reload-stop-go@2x.png
   skin/classic/browser/searchbar-dropmarker.png
   skin/classic/browser/searchbar-dropmarker@2x.png
--- a/browser/themes/osx/preferences/preferences.css
+++ b/browser/themes/osx/preferences/preferences.css
@@ -169,34 +169,16 @@ caption {
 
 /* General Pane */
 
 #isNotDefaultLabel {
   font-weight: bold;
 }
 
 /**
- * Privacy Pane
- */
-
-html|a.inline-link {
-  color: -moz-nativehyperlinktext;
-  text-decoration: none;
-}
-
-html|a.inline-link:hover {
-  text-decoration: underline;
-}
-
-html|a.inline-link:-moz-focusring {
-  outline-width: 0;
-  box-shadow: @focusRingShadow@;
-}
-
-/**
  * Update Preferences
  */
 #autoInstallOptions {
   -moz-margin-start: 20px;
 }
 
 .updateControls {
   -moz-margin-start: 10px;
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f48d176ee2826efac48b3119a7e5dd215f113919
GIT binary patch
literal 1286
zc$@(S1^N1kP)<h;3K|Lk000e1NJLTq001oj001or1^@s6IvV1d0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzxM@^abXZMHI%98bE@5PEVr4FPZEyeq
z0000ujeU~eZrdOf#$N@|n@yUHah;|{^(x1XwO)9tvPj!4!L&gse*|Q4^J=@;BkdK2
z(>k3dxkyNy!}o)8;Jdl)4P`s-!G=EyRlq;LenTL-0)C&hNoy*;6<>~)e>;9%v*V8C
z9lZSvZhF#7Be|!bmru%(zJRpT8&1M{NFxYN62B{8Ic$I*?LDZp<zN=iB9^2W%<~w}
zvK-@2AWiTk!U;<A2xF4X3BCfa1BTmd_dr&4^Lkf^3b^&&5QGkgLwvZ5wS7c5&vTTd
zC{3fFh}^UCw2zd#7*D9VV^$b1v;sp+H+t_22*(zrIUlQBd}=3VTB4pBgyRJLBW&CE
zrBa^N&ae2x`)ap-HXN<E(|gN!kY5b2A(iFSYrEF^X?(@|t@he&wE<NHKD3kxHN+oJ
zK--c#<vdl4-_->SnOKO9;AM@=tf?_xF2c+f^Lk#EWrLflzDl#}k*zh`ORoILc5m!*
zk{!J8LUSvA@~*L3f>X~#OxLoQuH}X8rfaDtSrm#v|NZos3icV6XWxe4?0l|*-EHvo
zU#tD|)@H?@1ONa6<Vi$9RA}Dq*iT54aTo{ipRn+<gMYvd(IGlGyoDf2j37FQ7$}IC
z2@WgM4TcL9M+S<S(*#pW!U#bM8s!ciJK3d!9mSnG80bL{qa8-F(#P*_Jd^qQ{@(Xh
zC%uFB@Zn{?zvugWPj2rkh)5I~;gohtJEfh{PHB6Wo_x1_1%ySlFbzK-1q9ph5=u>G
zOZnV3&!sp==G9s)Ec=Sc!sk`E0Yae!`XCNuU=ykp8P$B>Xg<z+N>qip=c<@^8(o6~
zh(Q~8;5szIBBX#UN<s~Y95wuRs~IWY+sHjU+$+XC*TnezrzlV!?Z8zKeBH@&epHOT
z`4|Dpvv1(yYreB1Vq|V90CWMqUQlj8Jeyf;1u7t|;_38zFHiyTilNDcN+638unBvo
zm@%@)d5KfZREqu=^W{JWe#0nS1HoM2g%5CGGOu;Ob8_C5{U6NvqrA^(zFdUH=8Azd
zlJEt3zzxDcJ*0Iq^rZRx(Y*Exg!lFE{-jPuu?UX5l1O70ius-u-8vb1y0x>aZ$I9@
ztIf##_V5o+OZz|?Q+&^gBG}N$$hE=ej?Jn{^L}l{ex`JHI3jHU>6n5`e8$Y6A|q>1
zZ%$j5_f07>wlbw33_O=sfE0d0050=cm74|`#P?6kWy^AYfcL2~Rx+hKpNvR;APeFU
zg&7D#AN0cn#7t&me6FA8!kiQ3Tr2zinbIA>VW|SrKsF}(Rb)!v3k+o~0omBn(UVI{
z&p?(3{sGyL?BzKs-TWw&YZl0cW{*81-t7wJa>Fkm8<Bn7$4WPJ`nBpH4P*ndN8O31
z@%sCZ_4t6!VI5xc^*lK~-B$>A+8(O(0-ZqwT%6(J&u7W$RlfJQ-P&cO9sU4W6jJ1b
zPLUz^wHv;yxz*w`Qw86F3?!h*B&Uhb8Rf`5Ri<y4yv-d}6hQ+l!wwMqg>@K*GK)E7
we14thiSw2@zsPw3>6CU#JEfh{PU-*R5a~MgMq6@nFaQ7m07*qoM6N<$f@kY#=l}o!
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e284af03309d6994b328f2c410e0c24750a3c760
GIT binary patch
literal 2438
zc$|G!2~bm677c_&1Ox#=z`&od$d-+;B|@`>O$ahEEg(V>k{^<REGEGOT4~utK`@8}
zWl>o~7DXDg1ft^7je-FMT%cW$773^bf-RzAPom;XO^yAk-oNkOI_JLo?mPAB?~4cz
z(p_n`5(0tfh6EEx3cFP~S7<1{9`(Me3S%k=h!Sk(&;>#Y4}|#AI0+yS!lERCB#=T&
z-QELwLLg8pCOJwFMGV7JIV>bai9w23T!?abdW*OeY7!^_62L?z+Y3G;?ScbLnio9M
zm53&C{XqsZIE@ExP75bf(~_t-8r=H_z*B@*Bw&F83Ls)7v-x<D7yNTxyke~kqu{`2
zh#<)e{-vlWVg%sN;emiF(iK5PJ7WNM91`Q|g2P~(0B1A?i^8B$&Nu`HgLiSqW88qR
z1FqPON2B9Ogut(RDLgMYLm=SdQ7EBMh!kRx99|*{gTvuaXlInOGeUtt@Kf0WiU`5x
zTP<fGfP5;C$rUg;Y(VK#5;!RWFF1Vp2rTZmv~2#@HYpm05>dD)3=)m{FCdZl_fQt=
z8=5a5f%Lye^U0}P5Jdv{oD?2aadC7jC7Fx&=YbRfhezgcl9#&}!Qcoud<KUL`1=EP
zL<*J3R{Hjz2}B}3gv}RF*i<lt;00GikW3~Gj|m`Pd|d(+jSlcrOcy_Qg1fJ;Zy+Yn
zpWx=~;<3ynaHuIPkS$o|(*DEs{VrFjg)eN7$J_zZ0(l%3@cGPm=J#uH|9&lBxU}!r
z;_+QBN>L2ze{Om?q>ztt`AxS9=bQ3DwnFYag|6q5gT^2b^~Df^FIn{a^uy3Fa-xyu
z?1qC3l4Y^JL4mEU8xd`dJPTI+QgUx&!#R!THC6XAqjtvV&xUBh;U`K~MV!_n<^Q$?
z(cWTiNIm-x+q33OOv84Y!5m$p8P%-1M)baG2wSWzdn#Q>H>n(VN-saMcxm4IFBs+3
zS^{mwOo$fgtP!G?VZSv`VxTm^1ImDn(uk{1C;}Umh9aHZb5A=iG-EMB1I9JCP`yHJ
z*Pfm=-aq6aTsJz>kF}VW<yKT>Vf*C!3nzx{I<b~IeJwP3g2yVTPhNVilkR-mJLKIC
zXhjMpG4kjMQtQYsuSa?cE$meNv!)`{cljV)u81_}ug^!jw|x-hPB~x=OJtAUuKja;
z`h^v0m1skq@||LJ*lhO9;8^19gBxRVZ0CgcSY@l|dOe@IMi#qcF4m;r{Zo1Q?qMrN
zPUPj_c#W6Y4<z%QOB&3T(Sz^W;-0nlN&DC0ej;D_OL)IGcF!$$)7-*JlzLvZW%%n4
zsbXkTm2rB(_HONoQ~Tn7MZY#3Z+M2}wU?7#HF|d+A=SKk!SC?7)uH_aN>#J$TDTy;
z<+{pZiGqwUs8^w8ms$7xaNmPF{(*el8m*RpIX?g0Ioge*|GKj?rTY!UPV3DzqkG4!
zk631ZiXR!BtDG{9ILM&)99-B^Kl!|Fs4mGTBw?>j=;NfS>L%6EvVK*qO%=LpmZnNi
zhN%E!`+Vvrcjb0rrd14%4jVe8&B#yJsVc&m5d%{5@WZ^_+3R_J0W+t(>1CR=Jyw&M
zfx{{}E$WS9a2-a)vpbN)hKb~yigQJ6-h&=VarKjV{z1gH-P<}<a-PUHP+wnBWn>-S
z)6tme$yZ6-TRLz{`tUYdsHm(pD=3WVv+7SD<S6xiKDXz$<R42#lH&ax7ixw^m{rxn
zbqov<LUK`auUc)Kd0>Xy>)AEhy;J%&skdD$ywn4$??0yR&{<oD+i!H|s<s4+ziUr#
zsp+pdh2olMVF{mb(u;Wgz?Gd&$L{xOMjG+!+ph}KO3sJc1l3NS{;_~kYxjT`c)k>1
zScN+IUb@*-G13?f58yO>ggdRMJ+4PW$OTD}velcUxr?L@Xvw-O!2{+CuGx=NNN=>?
zAre!1&lXup!Va`9rV8(_6T$;bW*YQfsJ4#T*2eU|5ZtF5H%TqPjq=KA+Ekv=#q`M7
zD6E*66`@{?SeWDv`bt`g%i6*wV45%*v(PA({7-X<-uUfZ^;sj54-bc*z;9|0P3iOD
z3$e7G14gk?afWVdj;eOtf#y<7!`dElt{a%lmwHs-3b2+Fu!nEsci>z}Z-O>7o^FOR
z-?|H~r7|+i?6OGt8&_O5ZC|;tO(wlAtQgzi7$kFes)ML#D91j3{Na5Ir??r>(CVOK
zu=S9RV_M(ajZNgWY6i`RVRfq<@jpL!T=e_yY)4kjrM;KZZoVpVeqt}?{`wM0B@Z;Y
zP4AyrC+3cCyA$NNCE4kKEzAO{6(j2(tTA4S+aB$t0#HJMiEDlxmZjZ)<aX`OHfVGF
zSynxYcyE35nU7!3T>F78M9g_aksGi&GUlpWXViYU?1uF_XfOfXfwiX$aLznB1&4l8
zH@J4Vl4j?HD{rG0H=aPNS^LS55(n?<3*%Y3JB*-SRtr@sl2(oM>F8$|X~fUQANxKg
zNP9E7hc}6hZ9>hu-0!9KUNb$EANTQ7+Ilx=L6L3nzG9mkZ|s&-w-~vj$x`=o_{l9-
z0dcNF@_56n$4y|yGr5^JaOTWbdH2oRnzbW_c0BRPy|<qC4_%iQmNjg9Q(cn7CT0xz
zlzoJbAm?cFu+F)P30O`4X5{;GYt%bw{wT3_WPIHoC+s59JvuG*WP978{B&2&>2UiN
zjn0hZ$sEsFrtFWW8-8NZrzT(|@`RnqMf8mS8Cgaw*YuT-{@x|6$SMtIFPXlir>%MJ
zCASbrl**#z!xv-HZNkzEiFwA~-q!!Sid)n>pRcDCXtv<2{4)v(2q!fA#b^E-<SPH{
deleted file mode 100644
--- a/browser/themes/windows/aboutPrivateBrowsing.css
+++ /dev/null
@@ -1,47 +0,0 @@
-%if 0
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-%endif
-
-body.private > #errorPageContainer {
-  background-image: url("chrome://browser/skin/Privacy-48.png");
-}
-
-body.normal > #errorPageContainer {
-  background-image: url("chrome://global/skin/icons/question-48.png");
-}
-
-#clearRecentHistoryDesc {
-  margin-top: 2em;
-}
-
-#clearRecentHistoryDesc > p {
-  font-size: 110%; /* to match the value set in chrome://global/skin/netError.css */
-}
-
-#startPrivateBrowsingDesc > button {
-  -moz-margin-start: 0;
-}
-
-#footerDesc > p {
-  font-size: 110%; /* to match the value set in chrome://global/skin/netError.css */
-}
-
-#moreInfo {
-  font-size: 110%; /* to match the value set in chrome://global/skin/netError.css */
-  -moz-padding-start: 25px;
-  background: url("chrome://global/skin/icons/information-16.png") no-repeat top left;
-}
-
-#moreInfo:-moz-dir(rtl) {
-  background-position: top right;
-}
-
-#moreInfoText {
-  margin-bottom: 0;
-}
-
-#moreInfoLinkContainer {
-  margin-top: 0.5em;
-}
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -3,17 +3,16 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 browser.jar:
 % skin browser classic/1.0 %skin/classic/browser/ os=WINNT osversion<6
 % skin browser classic/1.0 %skin/classic/browser/ os!=WINNT
 # NOTE: If you add a new file here, you'll need to add it to the aero
 # section at the bottom of this file
         skin/classic/browser/sanitizeDialog.css
-*       skin/classic/browser/aboutPrivateBrowsing.css
 *       skin/classic/browser/aboutSessionRestore.css
         skin/classic/browser/aboutSessionRestore-window-icon.png     (preferences/application.png)
         skin/classic/browser/aboutWelcomeBack.css                    (../shared/aboutWelcomeBack.css)
         skin/classic/browser/aboutCertError.css
         skin/classic/browser/aboutCertError_sectionCollapsed.png
         skin/classic/browser/aboutCertError_sectionCollapsed-rtl.png
         skin/classic/browser/aboutCertError_sectionExpanded.png
         skin/classic/browser/aboutSocialError.css
@@ -35,16 +34,18 @@ browser.jar:
         skin/classic/browser/identity-icons-generic.png
         skin/classic/browser/identity-icons-https.png
         skin/classic/browser/identity-icons-https-ev.png
         skin/classic/browser/identity-icons-https-mixed-active.png
         skin/classic/browser/identity-icons-https-mixed-display.png
         skin/classic/browser/keyhole-forward-mask.svg
         skin/classic/browser/KUI-background.png
         skin/classic/browser/livemark-folder.png
+        skin/classic/browser/mask.png                               (../shared/mask.png)
+        skin/classic/browser/mask@2x.png                            (../shared/mask@2x.png)
         skin/classic/browser/menu-back.png
         skin/classic/browser/menu-forward.png
         skin/classic/browser/menuPanel.png
         skin/classic/browser/menuPanel-customize.png
         skin/classic/browser/menuPanel-exit.png
         skin/classic/browser/menuPanel-help.png
         skin/classic/browser/menuPanel-small.png
         skin/classic/browser/Metro_Glyph.png                        (Metro_Glyph-aero.png)
@@ -411,17 +412,16 @@ browser.jar:
         skin/classic/browser/devtools/tooltip/arrow-horizontal-light@2x.png   (../shared/devtools/tooltip/arrow-horizontal-light@2x.png)
         skin/classic/browser/devtools/tooltip/arrow-vertical-light.png   (../shared/devtools/tooltip/arrow-vertical-light.png)
         skin/classic/browser/devtools/tooltip/arrow-vertical-light@2x.png   (../shared/devtools/tooltip/arrow-vertical-light@2x.png)
 
 #ifdef XP_WIN
 browser.jar:
 % skin browser classic/1.0 %skin/classic/aero/browser/ os=WINNT osversion>=6
         skin/classic/aero/browser/sanitizeDialog.css                       (sanitizeDialog.css)
-*       skin/classic/aero/browser/aboutPrivateBrowsing.css           (aboutPrivateBrowsing.css)
 *       skin/classic/aero/browser/aboutSessionRestore.css            (aboutSessionRestore.css)
         skin/classic/aero/browser/aboutSessionRestore-window-icon.png (aboutSessionRestore-window-icon-aero.png)
         skin/classic/aero/browser/aboutCertError.css
         skin/classic/aero/browser/aboutCertError_sectionCollapsed.png
         skin/classic/aero/browser/aboutCertError_sectionCollapsed-rtl.png
         skin/classic/aero/browser/aboutCertError_sectionExpanded.png
         skin/classic/aero/browser/aboutSocialError.css
 #ifdef MOZ_SERVICES_SYNC
@@ -443,16 +443,18 @@ browser.jar:
         skin/classic/aero/browser/identity-icons-generic.png
         skin/classic/aero/browser/identity-icons-https.png
         skin/classic/aero/browser/identity-icons-https-ev.png
         skin/classic/aero/browser/identity-icons-https-mixed-active.png
         skin/classic/aero/browser/identity-icons-https-mixed-display.png
         skin/classic/aero/browser/keyhole-forward-mask.svg
         skin/classic/aero/browser/KUI-background.png
         skin/classic/aero/browser/livemark-folder.png                (livemark-folder-aero.png)
+        skin/classic/aero/browser/mask.png                           (../shared/mask.png)
+        skin/classic/aero/browser/mask@2x.png                        (../shared/mask@2x.png)
         skin/classic/aero/browser/menu-back.png                      (menu-back-aero.png)
         skin/classic/aero/browser/menu-forward.png                   (menu-forward-aero.png)
         skin/classic/aero/browser/menuPanel.png
         skin/classic/aero/browser/menuPanel-aero.png
         skin/classic/aero/browser/menuPanel-customize.png
         skin/classic/aero/browser/menuPanel-exit.png
         skin/classic/aero/browser/menuPanel-help.png
         skin/classic/aero/browser/menuPanel-small.png
@@ -471,17 +473,16 @@ browser.jar:
         skin/classic/aero/browser/pageInfo.png                       (pageInfo-aero.png)
         skin/classic/aero/browser/page-livemarks.png                 (feeds/feedIcon16-aero.png)
         skin/classic/aero/browser/pluginInstall-16.png
         skin/classic/aero/browser/pluginInstall-64.png
         skin/classic/aero/browser/pointerLock-16.png
         skin/classic/aero/browser/pointerLock-64.png
         skin/classic/aero/browser/Privacy-16.png                     (Privacy-16-aero.png)
         skin/classic/aero/browser/Privacy-32.png                     (Privacy-32-aero.png)
-        skin/classic/aero/browser/Privacy-48.png                     (Privacy-48-aero.png)
         skin/classic/aero/browser/privatebrowsing-mask-tabstrip.png
         skin/classic/aero/browser/privatebrowsing-mask-tabstrip-XPVista7.png
         skin/classic/aero/browser/privatebrowsing-mask-titlebar.png
         skin/classic/aero/browser/privatebrowsing-mask-titlebar-XPVista7.png
         skin/classic/aero/browser/privatebrowsing-mask-titlebar-XPVista7-tall.png
         skin/classic/aero/browser/reload-stop-go.png
         skin/classic/aero/browser/searchbar.css
         skin/classic/aero/browser/searchbar-dropdown-arrow.png       (searchbar-dropdown-arrow-aero.png)
--- a/browser/themes/windows/preferences/preferences.css
+++ b/browser/themes/windows/preferences/preferences.css
@@ -69,28 +69,16 @@ label.small {
 #BrowserPreferences[animated="true"] #handlersView {
   height: 25em;
 }
 
 #BrowserPreferences[animated="false"] #handlersView {
   -moz-box-flex: 1;
 }
 
-/* Privacy Pane */
-
-/* styles for the link elements copied from .text-link in global.css */
-.inline-link {
-  color: -moz-nativehyperlinktext;
-  text-decoration: none;
-}
-
-.inline-link:hover {
-  text-decoration: underline;
-}
-
 /* Modeless Window Dialogs */
 .windowDialog,
 .windowDialog prefpane {
   padding: 0;
 }
 
 .contentPane {
   margin: 9px 8px 5px;
--- a/build/appini_header.py
+++ b/build/appini_header.py
@@ -8,20 +8,16 @@
 import ConfigParser
 import sys
 
 def main(file):
     config = ConfigParser.RawConfigParser()
     config.read(file)
     flags = set()
     try:
-        if config.getint('XRE', 'EnableExtensionManager') == 1:
-            flags.add('NS_XRE_ENABLE_EXTENSION_MANAGER')
-    except: pass
-    try:
         if config.getint('XRE', 'EnableProfileMigrator') == 1:
             flags.add('NS_XRE_ENABLE_PROFILE_MIGRATOR')
     except: pass
     try:
         if config.getint('Crash Reporter', 'Enabled') == 1:
             flags.add('NS_XRE_ENABLE_CRASH_REPORTER')
     except: pass
     appdata = dict(("%s:%s" % (s, o), config.get(s, o)) for s in config.sections() for o in config.options(s))
--- a/build/application.ini
+++ b/build/application.ini
@@ -37,17 +37,14 @@ ID=@MOZ_APP_ID@
 [Gecko]
 MinVersion=@GRE_MILESTONE@
 MaxVersion=@GRE_MILESTONE@
 
 [XRE]
 #ifdef MOZ_PROFILE_MIGRATOR
 EnableProfileMigrator=1
 #endif
-#ifdef MOZ_EXTENSION_MANAGER
-EnableExtensionManager=1
-#endif
 
 #if MOZ_CRASHREPORTER
 [Crash Reporter]
 Enabled=1
 ServerURL=https://crash-reports.mozilla.com/submit?id=@MOZ_APP_ID@&version=@MOZ_APP_VERSION@&buildid=@APP_BUILDID@
 #endif
--- a/build/moz.build
+++ b/build/moz.build
@@ -35,16 +35,16 @@ if CONFIG['MOZ_APP_DISPLAYNAME'] != CONF
 
 if CONFIG['MOZ_BUILD_APP'] == 'browser':
     DEFINES['MOZ_BUILD_APP_IS_BROWSER'] = True
 
 if CONFIG['MOZ_APP_PROFILE']:
     DEFINES['MOZ_APP_PROFILE'] = CONFIG['MOZ_APP_PROFILE']
 
 for var in ('MOZ_CRASHREPORTER', 'MOZ_PROFILE_MIGRATOR',
-            'MOZ_EXTENSION_MANAGER', 'MOZ_APP_STATIC_INI'):
+            'MOZ_APP_STATIC_INI'):
     if CONFIG[var]:
         DEFINES[var] = True
 
 if CONFIG['MOZ_BUILD_APP'] == 'browser':
     PYTHON_UNIT_TESTS += [
         'compare-mozconfig/compare-mozconfigs-wrapper.py',
     ]
--- a/config/external/ffi/moz.build
+++ b/config/external/ffi/moz.build
@@ -4,15 +4,15 @@
 # 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/.
 
 LIBRARY_NAME = 'ffi'
 
 if CONFIG['MOZ_NATIVE_FFI']:
     OS_LIBS += CONFIG['MOZ_FFI_LIBS']
 else:
-    if CONFIG['OS_ARCH'] == 'WINNT':
+    if CONFIG['_MSC_VER']:
         prefix = 'lib'
     else:
         prefix = ''
     USE_LIBS += [
         'static:/js/src/ctypes/libffi/.libs/%sffi' % prefix,
     ]
--- a/config/recurse.mk
+++ b/config/recurse.mk
@@ -145,16 +145,20 @@ define CREATE_SUBTIER_TRAVERSAL_RULE
 
 $(1):: $$(SUBMAKEFILES)
 	$$(LOOP_OVER_DIRS)
 
 endef
 
 $(foreach subtier,export libs tools,$(eval $(call CREATE_SUBTIER_TRAVERSAL_RULE,$(subtier))))
 
+ifndef TOPLEVEL_BUILD
+libs:: target host
+endif
+
 endif # ifdef TIERS
 
 endif # ifeq ($(NO_RECURSE_MAKELEVEL),$(MAKELEVEL))
 
 endif # ifeq (.,$(DEPTH))
 
 recurse:
 	@$(RECURSED_COMMAND)
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -692,17 +692,17 @@ ifdef MSMANIFEST_TOOL
 	fi
 endif	# MSVC with manifest tool
 ifdef MOZ_PROFILE_GENERATE
 # touch it a few seconds into the future to work around FAT's
 # 2-second granularity
 	touch -t `date +%Y%m%d%H%M.%S -d 'now+5seconds'` pgo.relink
 endif
 else # !WINNT || GNU_CC
-	$(EXPAND_CCC) -o $@ $(CXXFLAGS) $(PROGOBJS) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(MOZ_GLUE_PROGRAM_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(EXE_DEF_FILE) $(STLPORT_LIBS)
+	$(EXPAND_CCC) -o $@ $(CXXFLAGS) $(PROGOBJS) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_GLUE_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(EXE_DEF_FILE) $(STLPORT_LIBS)
 	$(call CHECK_BINARY,$@)
 endif # WINNT && !GNU_CC
 
 ifdef ENABLE_STRIP
 	$(STRIP) $(STRIP_FLAGS) $@
 endif
 ifdef MOZ_POST_PROGRAM_COMMAND
 	$(MOZ_POST_PROGRAM_COMMAND) $@
@@ -748,17 +748,17 @@ ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH))
 	$(EXPAND_LD) -nologo -out:$@ -pdb:$(LINK_PDBFILE) $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_GLUE_PROGRAM_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS)
 ifdef MSMANIFEST_TOOL
 	@if test -f $@.manifest; then \
 		mt.exe -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \
 		rm -f $@.manifest; \
 	fi
 endif	# MSVC with manifest tool
 else
-	$(EXPAND_CCC) $(CXXFLAGS) -o $@ $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(MOZ_GLUE_PROGRAM_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(STLPORT_LIBS)
+	$(EXPAND_CCC) $(CXXFLAGS) -o $@ $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_GLUE_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(STLPORT_LIBS)
 	$(call CHECK_BINARY,$@)
 endif # WINNT && !GNU_CC
 
 ifdef ENABLE_STRIP
 	$(STRIP) $(STRIP_FLAGS) $@
 endif
 ifdef MOZ_POST_PROGRAM_COMMAND
 	$(MOZ_POST_PROGRAM_COMMAND) $@
--- a/configure.in
+++ b/configure.in
@@ -8480,17 +8480,16 @@ AC_SUBST(MOZ_CHILD_PROCESS_BUNDLE)
 # - MOZ_APP_VERSION: Defines the application version number.
 # - MOZ_APP_NAME: Used for e.g. the binary program file name. If not set,
 # defaults to a lowercase form of MOZ_APP_BASENAME.
 # - MOZ_APP_PROFILE: When set, used for application.ini's
 # "Profile" field, which controls profile location.
 # - MOZ_APP_ID: When set, used for application.ini's "ID" field, and
 # crash reporter server url.
 # - MOZ_PROFILE_MIGRATOR: When set, enables profile migrator.
-# - MOZ_EXTENSION_MANAGER: When set, enabled extension manager.
 
 if test -z "$MOZ_APP_NAME"; then
    MOZ_APP_NAME=`echo $MOZ_APP_BASENAME | tr A-Z a-z`
 fi
 
 # For extensions and langpacks, we require a max version that is compatible
 # across security releases. MOZ_APP_MAXVERSION is our method for doing that.
 # 24.0a1 and 24.0a2 aren't affected
@@ -8513,17 +8512,16 @@ AC_SUBST(MOZ_APP_NAME)
 AC_SUBST(MOZ_APP_DISPLAYNAME)
 AC_SUBST(MOZ_APP_BASENAME)
 AC_SUBST(MOZ_APP_VENDOR)
 AC_SUBST(MOZ_APP_PROFILE)
 AC_SUBST(MOZ_APP_ID)
 AC_SUBST(MAR_CHANNEL_ID)
 AC_SUBST(ACCEPTED_MAR_CHANNEL_IDS)
 AC_SUBST(MOZ_PROFILE_MIGRATOR)
-AC_SUBST(MOZ_EXTENSION_MANAGER)
 AC_DEFINE_UNQUOTED(MOZ_APP_UA_NAME, "$MOZ_APP_UA_NAME")
 AC_SUBST(MOZ_APP_UA_NAME)
 AC_DEFINE_UNQUOTED(MOZ_APP_UA_VERSION, "$MOZ_APP_VERSION")
 AC_SUBST(MOZ_APP_VERSION)
 AC_SUBST(MOZ_APP_MAXVERSION)
 AC_DEFINE_UNQUOTED(FIREFOX_VERSION,$FIREFOX_VERSION)
 AC_SUBST(FIREFOX_VERSION)
 AC_SUBST(MOZ_UA_OS_AGNOSTIC)
--- a/content/base/public/Element.h
+++ b/content/base/public/Element.h
@@ -30,16 +30,17 @@
 #include "mozilla/Attributes.h"
 #include "nsIScrollableFrame.h"
 #include "mozilla/dom/Attr.h"
 #include "nsISMILAttr.h"
 #include "mozilla/dom/DOMRect.h"
 #include "nsAttrValue.h"
 #include "mozilla/EventForwards.h"
 #include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/WindowBinding.h"
 #include "Units.h"
 
 class nsIDOMEventListener;
 class nsIFrame;
 class nsIDOMMozNamedAttrMap;
 class nsIDOMCSSStyleDeclaration;
 class nsIURI;
 class nsIControllers;
@@ -715,21 +716,18 @@ public:
                                             ErrorResult& aError);
 
   already_AddRefed<DOMRectList> GetClientRects();
   already_AddRefed<DOMRect> GetBoundingClientRect();
 
   already_AddRefed<ShadowRoot> CreateShadowRoot(ErrorResult& aError);
   already_AddRefed<DestinationInsertionPointList> GetDestinationInsertionPoints();
 
-  void ScrollIntoView()
-  {
-    ScrollIntoView(true);
-  }
-  void ScrollIntoView(bool aTop);
+  void ScrollIntoView();
+  void ScrollIntoView(bool aTop, const ScrollOptions &aOptions);
   int32_t ScrollTop()
   {
     nsIScrollableFrame* sf = GetScrollFrame();
     return sf ? sf->GetScrollPositionCSSPixels().y.value : 0;
   }
   void SetScrollTop(int32_t aScrollTop)
   {
     nsIScrollableFrame* sf = GetScrollFrame();
--- a/content/base/src/Attr.cpp
+++ b/content/base/src/Attr.cpp
@@ -98,17 +98,17 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(Attr)
   return tmp->IsBlack();
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
 
 // QueryInterface implementation for Attr
 NS_INTERFACE_TABLE_HEAD(Attr)
-  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
   NS_INTERFACE_TABLE(Attr, nsINode, nsIDOMAttr, nsIAttribute, nsIDOMNode,
                      nsIDOMEventTarget, EventTarget)
   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(Attr)
   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsISupportsWeakReference,
                                  new nsNodeSupportsWeakRefTearoff(this))
   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMXPathNSResolver,
                                  new nsNode3Tearoff(this))
 NS_INTERFACE_MAP_END
--- a/content/base/src/DOMRect.cpp
+++ b/content/base/src/DOMRect.cpp
@@ -70,17 +70,17 @@ DOMRect::Constructor(const GlobalObject&
   return obj.forget();
 }
 
 // -----------------------------------------------------------------------------
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMRectList, mParent, mArray)
 
 NS_INTERFACE_TABLE_HEAD(DOMRectList)
-  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
   NS_INTERFACE_TABLE(DOMRectList, nsIDOMClientRectList)
   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(DOMRectList)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMRectList)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMRectList)
 
 
--- a/content/base/src/Element.cpp
+++ b/content/base/src/Element.cpp
@@ -581,38 +581,49 @@ Element::GetScrollFrame(nsIFrame **aStyl
     // the root scrollable frame.
     return frame->PresContext()->PresShell()->GetRootScrollFrameAsScrollable();
   }
 
   return nullptr;
 }
 
 void
-Element::ScrollIntoView(bool aTop)
+Element::ScrollIntoView()
+{
+  ScrollIntoView(true, ScrollOptions());
+}
+
+void
+Element::ScrollIntoView(bool aTop, const ScrollOptions &aOptions)
 {
   nsIDocument *document = GetCurrentDoc();
   if (!document) {
     return;
   }
 
   // Get the presentation shell
   nsCOMPtr<nsIPresShell> presShell = document->GetShell();
   if (!presShell) {
     return;
   }
 
   int16_t vpercent = aTop ? nsIPresShell::SCROLL_TOP :
     nsIPresShell::SCROLL_BOTTOM;
 
+  uint32_t flags = nsIPresShell::SCROLL_OVERFLOW_HIDDEN;
+  if (aOptions.mBehavior == ScrollBehavior::Smooth) {
+    flags |= nsIPresShell::SCROLL_SMOOTH;
+  }
+
   presShell->ScrollContentIntoView(this,
                                    nsIPresShell::ScrollAxis(
                                      vpercent,
                                      nsIPresShell::SCROLL_ALWAYS),
                                    nsIPresShell::ScrollAxis(),
-                                   nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
+                                   flags);
 }
 
 bool
 Element::ScrollByNoFlush(int32_t aDx, int32_t aDy)
 {
   nsIScrollableFrame* sf = GetScrollFrame(nullptr, false);
   if (!sf) {
     return false;
--- a/content/base/src/FragmentOrElement.cpp
+++ b/content/base/src/FragmentOrElement.cpp
@@ -389,17 +389,17 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_
   return tmp->IsBlackAndDoesNotNeedTracing(tmp);
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
 
 // CanSkipThis returns false to avoid problems with incomplete unlinking.
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsChildContentList)
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
 
 NS_INTERFACE_TABLE_HEAD(nsChildContentList)
-  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
   NS_INTERFACE_TABLE(nsChildContentList, nsINodeList, nsIDOMNodeList)
   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsChildContentList)
 NS_INTERFACE_MAP_END
 
 JSObject*
 nsChildContentList::WrapObject(JSContext *cx)
 {
   return NodeListBinding::Wrap(cx, this);
--- a/content/base/src/nsContentList.cpp
+++ b/content/base/src/nsContentList.cpp
@@ -80,17 +80,17 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_B
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
 
 #define NS_CONTENT_LIST_INTERFACES(_class)                                    \
     NS_INTERFACE_TABLE_ENTRY(_class, nsINodeList)                             \
     NS_INTERFACE_TABLE_ENTRY(_class, nsIDOMNodeList)
 
 // QueryInterface implementation for nsBaseContentList
 NS_INTERFACE_TABLE_HEAD(nsBaseContentList)
-  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
   NS_INTERFACE_TABLE(nsBaseContentList, nsINodeList, nsIDOMNodeList)
   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsBaseContentList)
 NS_INTERFACE_MAP_END
 
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsBaseContentList)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsBaseContentList)
 
--- a/content/base/src/nsDOMAttributeMap.cpp
+++ b/content/base/src/nsDOMAttributeMap.cpp
@@ -111,17 +111,17 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsDOMAttributeMap)
   return tmp->IsBlack();
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
 
 // QueryInterface implementation for nsDOMAttributeMap
 NS_INTERFACE_TABLE_HEAD(nsDOMAttributeMap)
   NS_INTERFACE_TABLE(nsDOMAttributeMap, nsIDOMMozNamedAttrMap)
   NS_INTERFACE_TABLE_TO_MAP_SEGUE
-  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsDOMAttributeMap)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMAttributeMap)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMAttributeMap)
 
 PLDHashOperator
 SetOwnerDocumentFunc(nsAttrHashKey::KeyType aKey,
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -1732,17 +1732,17 @@ nsDocument::~nsDocument()
   // unlocked state, and then clear the table.
   SetImageLockingState(false);
   mImageTracker.Clear();
 
   mPlugins.Clear();
 }
 
 NS_INTERFACE_TABLE_HEAD(nsDocument)
-  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
   NS_INTERFACE_TABLE_BEGIN
     NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(nsDocument, nsISupports, nsINode)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsINode)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDocument)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMDocument)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMNode)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMDocumentXBL)
     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIScriptObjectPrincipal)
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -462,23 +462,16 @@ nsFrameLoader::ReallyStartLoadingInterna
       if (!mPendingFrameSent) {
         nsCOMPtr<nsIObserverService> os = services::GetObserverService();
         if (os && !mRemoteBrowserInitialized) {
           os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
                               "remote-browser-pending", nullptr);
           mPendingFrameSent = true;
         }
       }
-      if (Preferences::GetBool("dom.ipc.processPrelaunch.enabled", false) &&
-          !ContentParent::PreallocatedProcessReady()) {
-
-        ContentParent::RunAfterPreallocatedProcessReady(
-            new DelayedStartLoadingRunnable(this));
-        return NS_ERROR_FAILURE;
-      }
 
       TryRemoteBrowser();
 
       if (!mRemoteBrowser) {
         NS_WARNING("Couldn't create child process for iframe.");
         return NS_ERROR_FAILURE;
       }
     }
--- a/content/html/content/src/HTMLFormControlsCollection.cpp
+++ b/content/html/content/src/HTMLFormControlsCollection.cpp
@@ -131,17 +131,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(HTMLFormControlsCollection)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 // XPConnect interface list for HTMLFormControlsCollection
 NS_INTERFACE_TABLE_HEAD(HTMLFormControlsCollection)
-  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
   NS_INTERFACE_TABLE(HTMLFormControlsCollection,
                      nsIHTMLCollection,
                      nsIDOMHTMLCollection)
   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(HTMLFormControlsCollection)
 NS_INTERFACE_MAP_END
 
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(HTMLFormControlsCollection)
--- a/content/html/content/src/HTMLOptionsCollection.cpp
+++ b/content/html/content/src/HTMLOptionsCollection.cpp
@@ -90,17 +90,17 @@ HTMLOptionsCollection::GetOptionIndex(El
 
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(HTMLOptionsCollection, mElements)
 
 // nsISupports
 
 // QueryInterface implementation for HTMLOptionsCollection
 NS_INTERFACE_TABLE_HEAD(HTMLOptionsCollection)
-  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
   NS_INTERFACE_TABLE(HTMLOptionsCollection,
                      nsIHTMLCollection,
                      nsIDOMHTMLOptionsCollection,
                      nsIDOMHTMLCollection)
   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(HTMLOptionsCollection)
 NS_INTERFACE_MAP_END
 
 
--- a/content/html/content/src/HTMLPropertiesCollection.cpp
+++ b/content/html/content/src/HTMLPropertiesCollection.cpp
@@ -56,17 +56,17 @@ HTMLPropertiesCollection::HTMLProperties
 HTMLPropertiesCollection::~HTMLPropertiesCollection()
 {
   if (mDoc) {
     mDoc->RemoveMutationObserver(this);
   }
 }
 
 NS_INTERFACE_TABLE_HEAD(HTMLPropertiesCollection)
-    NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+    NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
     NS_INTERFACE_TABLE(HTMLPropertiesCollection,
                        nsIDOMHTMLCollection,
                        nsIHTMLCollection,
                        nsIMutationObserver)
     NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(HTMLPropertiesCollection)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(HTMLPropertiesCollection)
@@ -403,17 +403,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(PropertyNodeList)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(PropertyNodeList)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(PropertyNodeList)
 
 NS_INTERFACE_TABLE_HEAD(PropertyNodeList)
-    NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+    NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
     NS_INTERFACE_TABLE(PropertyNodeList,
                        nsIDOMNodeList,
                        nsINodeList,
                        nsIMutationObserver)
     NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(PropertyNodeList)
 NS_INTERFACE_MAP_END
 
 void
--- a/content/html/content/src/HTMLTableElement.cpp
+++ b/content/html/content/src/HTMLTableElement.cpp
@@ -90,17 +90,17 @@ TableRowsCollection::WrapObject(JSContex
   return HTMLCollectionBinding::Wrap(aCx, this);
 }
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TableRowsCollection, mOrphanRows)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(TableRowsCollection)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(TableRowsCollection)
 
 NS_INTERFACE_TABLE_HEAD(TableRowsCollection)
-  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
   NS_INTERFACE_TABLE(TableRowsCollection, nsIHTMLCollection,
                      nsIDOMHTMLCollection)
   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(TableRowsCollection)
 NS_INTERFACE_MAP_END
 
 // Macro that can be used to avoid copy/pasting code to iterate over the
 // rowgroups.  _code should be the code to execute for each rowgroup.  The
 // rowgroup's rows will be in the nsIDOMHTMLCollection* named "rows".  Note
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -464,17 +464,17 @@ public:
     return rv.ErrorCode();
   }                                                                            \
   NS_IMETHOD InsertAdjacentHTML(const nsAString& position,
                                 const nsAString& text) MOZ_FINAL;
   NS_IMETHOD ScrollIntoView(bool top, uint8_t _argc) MOZ_FINAL {
     if (!_argc) {
       top = true;
     }
-    mozilla::dom::Element::ScrollIntoView(top);
+    mozilla::dom::Element::ScrollIntoView(top, mozilla::dom::ScrollOptions());
     return NS_OK;
   }
   NS_IMETHOD GetOffsetParent(nsIDOMElement** aOffsetParent) MOZ_FINAL {
     mozilla::dom::Element* offsetParent = GetOffsetParent();
     if (!offsetParent) {
       *aOffsetParent = nullptr;
       return NS_OK;
     }
--- a/content/html/content/test/file_fullscreen-ancestor-stacking-context.html
+++ b/content/html/content/test/file_fullscreen-ancestor-stacking-context.html
@@ -31,16 +31,17 @@ https://bugzilla.mozilla.org/show_bug.cg
    Both lists should include every property that is able to induce an element
    to form a stacking context. */
 const gPropertyTestDecls = {
 //"domPropName": "prop-name: some-non-initial-value",
   "zIndex":      "z-index: 5",
   "opacity":     "opacity: 0.8",
   "mask":        "mask: url(#mymask)",
   "clip":        "clip: rect(0 0 0 0)",
+  "clipPath":    "clip-path: url(#mypath)",
   "filter":      "filter: url(#myfilter)",
   "transform":   "transform: translate(0)",
 // XXXdholbert The "will-change" line in full-screen-override.css is only
 // parsed and honored if "layout.css.will-change.enabled" is turned on
 // *at startup time* (so, flipping it here with SpecialPowers wouldn't be
 // sufficient). So, we won't get the right behavior for 'will-change' here
 // until it's enabled by default (bug 961871). This line can be uncommented
 // when that happens:
--- a/content/media/MediaDecoderStateMachine.cpp
+++ b/content/media/MediaDecoderStateMachine.cpp
@@ -175,17 +175,17 @@ static int64_t DurationToUsecs(TimeDurat
 MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
                                                    MediaDecoderReader* aReader,
                                                    bool aRealTime) :
   mDecoder(aDecoder),
   mScheduler(new MediaDecoderStateMachineScheduler(
       aDecoder->GetReentrantMonitor(),
       &MediaDecoderStateMachine::TimeoutExpired,
       MOZ_THIS_IN_INITIALIZER_LIST(), aRealTime)),
-  mState(DECODER_STATE_DECODING_METADATA),
+  mState(DECODER_STATE_DECODING_NONE),
   mSyncPointInMediaStream(-1),
   mSyncPointInDecodedStream(-1),
   mPlayDuration(0),
   mStartTime(-1),
   mEndTime(-1),
   mFragmentEndTime(-1),
   mReader(aReader),
   mCurrentFrameTime(0),
@@ -204,17 +204,16 @@ MediaDecoderStateMachine::MediaDecoderSt
   mPositionChangeQueued(false),
   mAudioCompleted(false),
   mGotDurationFromMetaData(false),
   mDispatchedEventToDecode(false),
   mStopAudioThread(true),
   mQuickBuffering(false),
   mMinimizePreroll(false),
   mDecodeThreadWaiting(false),
-  mDispatchedDecodeMetadataTask(false),
   mDropAudioUntilNextDiscontinuity(false),
   mDropVideoUntilNextDiscontinuity(false),
   mDecodeToSeekTarget(false),
   mCurrentTimeBeforeSeek(0),
   mLastFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED)
 {
   MOZ_COUNT_CTOR(MediaDecoderStateMachine);
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
@@ -353,32 +352,36 @@ static void WriteVideoToMediaStream(laye
 }
 
 static const TrackID TRACK_AUDIO = 1;
 static const TrackID TRACK_VIDEO = 2;
 static const TrackRate RATE_VIDEO = USECS_PER_S;
 
 void MediaDecoderStateMachine::SendStreamData()
 {
-  NS_ASSERTION(OnDecodeThread() ||
-               OnStateMachineThread(), "Should be on decode thread or state machine thread");
+  NS_ASSERTION(OnDecodeThread() || OnStateMachineThread(),
+               "Should be on decode thread or state machine thread");
   AssertCurrentThreadInMonitor();
+  MOZ_ASSERT(mState != DECODER_STATE_DECODING_NONE);
 
   DecodedStreamData* stream = mDecoder->GetDecodedStream();
-  if (!stream)
+  if (!stream) {
     return;
-
-  if (mState == DECODER_STATE_DECODING_METADATA)
+  }
+
+  if (mState == DECODER_STATE_DECODING_METADATA) {
     return;
+  }
 
   // If there's still an audio sink alive, then we can't send any stream
   // data yet since both SendStreamData and the audio sink want to be in
   // charge of popping the audio queue. We're waiting for the audio sink
-  if (mAudioSink)
+  if (mAudioSink) {
     return;
+  }
 
   int64_t minLastAudioPacketTime = INT64_MAX;
   bool finished =
       (!mInfo.HasAudio() || AudioQueue().IsFinished()) &&
       (!mInfo.HasVideo() || VideoQueue().IsFinished());
   if (mDecoder->IsSameOriginMedia()) {
     SourceMediaStream* mediaStream = stream->mStream;
     StreamTime endPosition = 0;
@@ -1325,17 +1328,17 @@ void MediaDecoderStateMachine::SetDorman
   if (aDormant) {
     ScheduleStateMachine();
     mState = DECODER_STATE_DORMANT;
     mDecoder->GetReentrantMonitor().NotifyAll();
   } else if ((aDormant != true) && (mState == DECODER_STATE_DORMANT)) {
     ScheduleStateMachine();
     mStartTime = 0;
     mCurrentFrameTime = 0;
-    mState = DECODER_STATE_DECODING_METADATA;
+    mState = DECODER_STATE_DECODING_NONE;
     mDecoder->GetReentrantMonitor().NotifyAll();
   }
 }
 
 void MediaDecoderStateMachine::Shutdown()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
 
@@ -1394,18 +1397,18 @@ void MediaDecoderStateMachine::NotifyWai
   AssertCurrentThreadInMonitor();
   if (mState != DECODER_STATE_WAIT_FOR_RESOURCES ||
       mReader->IsWaitingMediaResources()) {
     return;
   }
   DECODER_LOG("NotifyWaitingForResourcesStatusChanged");
   // The reader is no longer waiting for resources (say a hardware decoder),
   // we can now proceed to decode metadata.
-  mState = DECODER_STATE_DECODING_METADATA;
-  EnqueueDecodeMetadataTask();
+  mState = DECODER_STATE_DECODING_NONE;
+  ScheduleStateMachine();
 }
 
 void MediaDecoderStateMachine::Play()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   // When asked to play, switch to decoding state only if
   // we are currently buffering. In other cases, we'll start playing anyway
   // when the state machine notices the decoder's state change to PLAYING.
@@ -1526,31 +1529,23 @@ void MediaDecoderStateMachine::StopAudio
     SendStreamData();
   }
 }
 
 nsresult
 MediaDecoderStateMachine::EnqueueDecodeMetadataTask()
 {
   AssertCurrentThreadInMonitor();
-
-  if (mState != DECODER_STATE_DECODING_METADATA ||
-      mDispatchedDecodeMetadataTask) {
-    return NS_OK;
-  }
-
-  mDispatchedDecodeMetadataTask = true;
+  MOZ_ASSERT(mState == DECODER_STATE_DECODING_METADATA);
+
   RefPtr<nsIRunnable> task(
     NS_NewRunnableMethod(this, &MediaDecoderStateMachine::CallDecodeMetadata));
   nsresult rv = mDecodeTaskQueue->Dispatch(task);
-  if (NS_FAILED(rv)) {
-    DECODER_WARN("Dispatch ReadMetadata task failed.");
-    mDispatchedDecodeMetadataTask = false;
-  }
-  return rv;
+  NS_ENSURE_SUCCESS(rv, rv);
+  return NS_OK;
 }
 
 void
 MediaDecoderStateMachine::SetReaderIdle()
 {
 #ifdef PR_LOGGING
   {
     ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
@@ -1867,35 +1862,32 @@ MediaDecoderStateMachine::CallDecodeMeta
     DecodeError();
   }
 }
 
 nsresult MediaDecoderStateMachine::DecodeMetadata()
 {
   AssertCurrentThreadInMonitor();
   NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
+  MOZ_ASSERT(mState == DECODER_STATE_DECODING_METADATA);
   DECODER_LOG("Decoding Media Headers");
-  if (mState != DECODER_STATE_DECODING_METADATA) {
-    return NS_ERROR_FAILURE;
-  }
 
   nsresult res;
   MediaInfo info;
   {
     ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
     res = mReader->ReadMetadata(&info, getter_Transfers(mMetadataTags));
   }
 
   if (NS_SUCCEEDED(res)) {
     if (mState == DECODER_STATE_DECODING_METADATA &&
         mReader->IsWaitingMediaResources()) {
       // change state to DECODER_STATE_WAIT_FOR_RESOURCES
       StartWaitForResources();
       // affect values only if ReadMetadata succeeds
-      mDispatchedDecodeMetadataTask = false;
       return NS_OK;
     }
   }
 
   if (NS_SUCCEEDED(res)) {
     mDecoder->SetMediaSeekable(mReader->IsMediaSeekable());
   }
 
@@ -2007,17 +1999,16 @@ MediaDecoderStateMachine::FinishDecodeMe
 
   if ((mState == DECODER_STATE_DECODING || mState == DECODER_STATE_COMPLETED) &&
       mDecoder->GetState() == MediaDecoder::PLAY_STATE_PLAYING &&
       !IsPlaying())
   {
     StartPlayback();
   }
 
-  mDispatchedDecodeMetadataTask = false;
   return NS_OK;
 }
 
 void MediaDecoderStateMachine::DecodeSeek()
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
   if (mState != DECODER_STATE_SEEKING) {
@@ -2138,16 +2129,18 @@ MediaDecoderStateMachine::SeekCompleted(
         RenderVideoFrame(video, TimeStamp::Now());
       }
       nsCOMPtr<nsIRunnable> event =
         NS_NewRunnableMethod(mDecoder, &MediaDecoder::Invalidate);
       NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
     }
   }
 
+  MOZ_ASSERT(mState != DECODER_STATE_DECODING_NONE);
+
   mDecoder->StartProgressUpdates();
   if (mState == DECODER_STATE_DECODING_METADATA ||
       mState == DECODER_STATE_DORMANT ||
       mState == DECODER_STATE_SHUTDOWN) {
     return;
   }
 
   // Change state to DECODING or COMPLETED now. SeekingStopped will
@@ -2324,21 +2317,26 @@ nsresult MediaDecoderStateMachine::RunSt
       }
       return NS_OK;
     }
 
     case DECODER_STATE_WAIT_FOR_RESOURCES: {
       return NS_OK;
     }
 
-    case DECODER_STATE_DECODING_METADATA: {
+    case DECODER_STATE_DECODING_NONE: {
+      mState = DECODER_STATE_DECODING_METADATA;
       // Ensure we have a decode thread to decode metadata.
       return EnqueueDecodeMetadataTask();
     }
 
+    case DECODER_STATE_DECODING_METADATA: {
+      return NS_OK;
+    }
+
     case DECODER_STATE_DECODING: {
       if (mDecoder->GetState() != MediaDecoder::PLAY_STATE_PLAYING &&
           IsPlaying())
       {
         // We're playing, but the element/decoder is in paused state. Stop
         // playing!
         StopPlayback();
       }
--- a/content/media/MediaDecoderStateMachine.h
+++ b/content/media/MediaDecoderStateMachine.h
@@ -130,16 +130,17 @@ public:
   MediaDecoderStateMachine(MediaDecoder* aDecoder,
                                MediaDecoderReader* aReader,
                                bool aRealTime = false);
 
   nsresult Init(MediaDecoderStateMachine* aCloneDonor);
 
   // Enumeration for the valid decoding states
   enum State {
+    DECODER_STATE_DECODING_NONE,
     DECODER_STATE_DECODING_METADATA,
     DECODER_STATE_WAIT_FOR_RESOURCES,
     DECODER_STATE_DORMANT,
     DECODER_STATE_DECODING,
     DECODER_STATE_SEEKING,
     DECODER_STATE_BUFFERING,
     DECODER_STATE_COMPLETED,
     DECODER_STATE_SHUTDOWN
@@ -888,21 +889,16 @@ protected:
   // memory and CPU overhead.
   bool mMinimizePreroll;
 
   // True if the decode thread has gone filled its buffers and is now
   // waiting to be awakened before it continues decoding. Synchronized
   // by the decoder monitor.
   bool mDecodeThreadWaiting;
 
-  // True if we've dispatched a task to the decode task queue to call
-  // ReadMetadata on the reader. We maintain a flag to ensure that we don't
-  // dispatch multiple tasks to re-do the metadata loading.
-  bool mDispatchedDecodeMetadataTask;
-
   // These two flags are true when we need to drop decoded samples that
   // we receive up to the next discontinuity. We do this when we seek;
   // the first sample in each stream after the seek is marked as being
   // a "discontinuity".
   bool mDropAudioUntilNextDiscontinuity;
   bool mDropVideoUntilNextDiscontinuity;
 
   // True if we need to decode forwards to the seek target inside
--- a/content/media/MediaResource.h
+++ b/content/media/MediaResource.h
@@ -149,16 +149,19 @@ public:
   }
 
   bool Contains(const MediaByteRange& aByteRange) const {
     return aByteRange.mStart >= mStart && aByteRange.mEnd <= mEnd;
   }
 
   MediaByteRange Extents(const MediaByteRange& aByteRange) const
   {
+    if (IsNull()) {
+      return aByteRange;
+    }
     return MediaByteRange(std::min(mStart, aByteRange.mStart),
                           std::max(mEnd, aByteRange.mEnd));
   }
 
   int64_t mStart, mEnd;
 };
 
 // Represents a section of contiguous media, with a start and end offset, and
--- a/content/media/MediaStreamGraph.h
+++ b/content/media/MediaStreamGraph.h
@@ -850,16 +850,17 @@ protected:
   };
 
   bool NeedsMixing();
 
   void ResampleAudioToGraphSampleRate(TrackData* aTrackData, MediaSegment* aSegment);
 
   TrackData* FindDataForTrack(TrackID aID)
   {
+    mMutex.AssertCurrentThreadOwns();
     for (uint32_t i = 0; i < mUpdateTracks.Length(); ++i) {
       if (mUpdateTracks[i].mID == aID) {
         return &mUpdateTracks[i];
       }
     }
     return nullptr;
   }
 
--- a/content/media/StreamBuffer.h
+++ b/content/media/StreamBuffer.h
@@ -19,16 +19,17 @@ const StreamTime STREAM_TIME_MAX = MEDIA
 
 /**
  * Unique ID for track within a StreamBuffer. Tracks from different
  * StreamBuffers may have the same ID; this matters when appending StreamBuffers,
  * since tracks with the same ID are matched. Only IDs greater than 0 are allowed.
  */
 typedef int32_t TrackID;
 const TrackID TRACK_NONE = 0;
+const TrackID TRACK_INVALID = -1;
 
 inline TrackTicks RateConvertTicksRoundDown(TrackRate aOutRate,
                                             TrackRate aInRate,
                                             TrackTicks aTicks)
 {
   NS_ASSERTION(0 < aOutRate && aOutRate <= TRACK_RATE_MAX, "Bad out rate");
   NS_ASSERTION(0 < aInRate && aInRate <= TRACK_RATE_MAX, "Bad in rate");
   NS_WARN_IF_FALSE(0 <= aTicks && aTicks <= TRACK_TICKS_MAX, "Bad ticks"); // bug 957691
--- a/content/media/mediasource/MediaSource.cpp
+++ b/content/media/mediasource/MediaSource.cpp
@@ -261,16 +261,17 @@ MediaSource::EndOfStream(const Optional<
   if (mReadyState != MediaSourceReadyState::Open ||
       mSourceBuffers->AnyUpdating()) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
   SetReadyState(MediaSourceReadyState::Ended);
   mSourceBuffers->Ended();
+  mDecoder->Ended();
   if (!aError.WasPassed()) {
     DurationChange(mSourceBuffers->GetHighestBufferedEndTime(), aRv);
     if (aRv.Failed()) {
       return;
     }
     // TODO:
     //   Notify media element that all data is now available.
     return;
--- a/content/media/mediasource/MediaSourceDecoder.cpp
+++ b/content/media/mediasource/MediaSourceDecoder.cpp
@@ -124,16 +124,24 @@ MediaSourceDecoder::DetachMediaSource()
 already_AddRefed<SourceBufferDecoder>
 MediaSourceDecoder::CreateSubDecoder(const nsACString& aType)
 {
   MOZ_ASSERT(mReader);
   return mReader->CreateSubDecoder(aType);
 }
 
 void
+MediaSourceDecoder::Ended()
+{
+  ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
+  mReader->Ended();
+  mon.NotifyAll();
+}
+
+void
 MediaSourceDecoder::SetMediaSourceDuration(double aDuration)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!mMediaSource) {
     return;
   }
   ErrorResult dummy;
   mMediaSource->SetDuration(aDuration, dummy);
--- a/content/media/mediasource/MediaSourceDecoder.h
+++ b/content/media/mediasource/MediaSourceDecoder.h
@@ -42,16 +42,18 @@ public:
 
   static already_AddRefed<MediaResource> CreateResource();
 
   void AttachMediaSource(dom::MediaSource* aMediaSource);
   void DetachMediaSource();
 
   already_AddRefed<SourceBufferDecoder> CreateSubDecoder(const nsACString& aType);
 
+  void Ended();
+
   void SetMediaSourceDuration(double aDuration);
 
   // Provide a mechanism for MediaSourceReader to block waiting on data from a SourceBuffer.
   void WaitForData();
 
   // Called whenever a SourceBuffer has new data appended.
   void NotifyGotData();
 
--- a/content/media/mediasource/MediaSourceReader.cpp
+++ b/content/media/mediasource/MediaSourceReader.cpp
@@ -35,16 +35,17 @@ extern PRLogModuleInfo* GetMediaSourceAP
 
 namespace mozilla {
 
 MediaSourceReader::MediaSourceReader(MediaSourceDecoder* aDecoder)
   : MediaDecoderReader(aDecoder)
   , mTimeThreshold(-1)
   , mDropAudioBeforeThreshold(false)
   , mDropVideoBeforeThreshold(false)
+  , mEnded(false)
 {
 }
 
 bool
 MediaSourceReader::IsWaitingMediaResources()
 {
   return mDecoders.IsEmpty() && mPendingDecoders.IsEmpty();
 }
@@ -128,21 +129,26 @@ void
 MediaSourceReader::OnVideoEOS()
 {
   // End of stream. See if we can switch to another video decoder.
   MSE_DEBUG("MediaSourceReader(%p)::OnVideoEOS reader=%p (readers=%u)",
             this, mVideoReader.get(), mDecoders.Length());
   if (SwitchReaders(SWITCH_FORCED)) {
     // Success! Resume decoding with next video decoder.
     RequestVideoData(false, mTimeThreshold);
-  } else {
+  } else if (IsEnded()) {
     // End of stream.
     MSE_DEBUG("MediaSourceReader(%p)::OnVideoEOS reader=%p EOS (readers=%u)",
               this, mVideoReader.get(), mDecoders.Length());
     GetCallback()->OnVideoEOS();
+  } else {
+    // If a new decoder isn't ready to respond with frames yet, we're going to
+    // keep hitting this path at 1/frame_duration Hz. Bug 1058422 is raised to
+    // address this issue.
+    RequestVideoData(false, mTimeThreshold);
   }
 }
 
 void
 MediaSourceReader::OnDecodeError()
 {
   GetCallback()->OnDecodeError();
 }
@@ -204,19 +210,23 @@ MediaSourceReader::SwitchVideoReader(Med
   MSE_DEBUG("MediaDecoderReader(%p)::SwitchVideoReader(%p) switching video reader",
             this, mVideoReader.get());
   return true;
 }
 
 bool
 MediaSourceReader::SwitchReaders(SwitchType aType)
 {
-  ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
+  InitializePendingDecoders();
 
-  InitializePendingDecoders();
+  // This monitor must be held after the call to InitializePendingDecoders
+  // as that method also obtains the lock, and then attempts to exit it
+  // to call ReadMetadata on the readers. If we hold it before the call then
+  // it remains held during the ReadMetadata call causing a deadlock.
+  ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
 
   bool didSwitch = false;
   double decodeTarget = double(mTimeThreshold) / USECS_PER_S;
 
   for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
     SourceBufferDecoder* decoder = mDecoders[i];
     const MediaInfo& info = decoder->GetReader()->GetMediaInfo();
 
@@ -407,24 +417,24 @@ MediaSourceReader::Seek(int64_t aTime, i
     MSE_DEBUG("MediaSourceReader(%p)::Seek no active buffer contains target=%f", this, target);
     NS_DispatchToMainThread(new ChangeToHaveMetadata(mDecoder));
   }
 
   // Loop until we have the requested time range in the source buffers.
   // This is a workaround for our lack of async functionality in the
   // MediaDecoderStateMachine. Bug 979104 implements what we need and
   // we'll remove this for an async approach based on that in bug XXXXXXX.
-  while (!DecodersContainTime(target) && !IsShutdown()) {
+  while (!DecodersContainTime(target) && !IsShutdown() && !IsEnded()) {
     MSE_DEBUG("MediaSourceReader(%p)::Seek waiting for target=%f", this, target);
     static_cast<MediaSourceDecoder*>(mDecoder)->WaitForData();
     SwitchReaders(SWITCH_FORCED);
   }
 
   if (IsShutdown()) {
-    return NS_OK;
+    return NS_ERROR_FAILURE;
   }
 
   ResetDecode();
   if (mAudioReader) {
     nsresult rv = mAudioReader->Seek(aTime, aStartTime, aEndTime, aCurrentTime);
     MSE_DEBUG("MediaSourceReader(%p)::Seek audio reader=%p rv=%xf", this, mAudioReader.get(), rv);
     if (NS_FAILED(rv)) {
       return rv;
@@ -489,9 +499,23 @@ MediaSourceReader::ReadMetadata(MediaInf
   }
 
   *aInfo = mInfo;
   *aTags = nullptr; // TODO: Handle metadata.
 
   return NS_OK;
 }
 
+void
+MediaSourceReader::Ended()
+{
+  mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
+  mEnded = true;
+}
+
+bool
+MediaSourceReader::IsEnded()
+{
+  ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
+  return mEnded;
+}
+
 } // namespace mozilla
--- a/content/media/mediasource/MediaSourceReader.h
+++ b/content/media/mediasource/MediaSourceReader.h
@@ -82,16 +82,22 @@ public:
   {
     ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
     return mDecoder->IsShutdown();
   }
 
   // Return true if any of the active decoders contain data for the given time
   bool DecodersContainTime(double aTime);
 
+  // Mark the reader to indicate that EndOfStream has been called on our MediaSource
+  void Ended();
+
+  // Return true if the Ended method has been called
+  bool IsEnded();
+
 private:
   enum SwitchType {
     SWITCH_OPTIONAL,
     SWITCH_FORCED
   };
 
   bool SwitchReaders(SwitchType aType);
 
@@ -103,13 +109,15 @@ private:
   bool mDropAudioBeforeThreshold;
   bool mDropVideoBeforeThreshold;
 
   nsTArray<nsRefPtr<SourceBufferDecoder>> mPendingDecoders;
   nsTArray<nsRefPtr<SourceBufferDecoder>> mDecoders;
 
   nsRefPtr<MediaDecoderReader> mAudioReader;
   nsRefPtr<MediaDecoderReader> mVideoReader;
+
+  bool mEnded;
 };
 
 } // namespace mozilla
 
 #endif /* MOZILLA_MEDIASOURCEREADER_H_ */
--- a/content/media/mediasource/SourceBuffer.cpp
+++ b/content/media/mediasource/SourceBuffer.cpp
@@ -11,16 +11,18 @@
 #include "MediaSourceDecoder.h"
 #include "MediaSourceUtils.h"
 #include "SourceBufferResource.h"
 #include "mozilla/Endian.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/dom/MediaSourceBinding.h"
 #include "mozilla/dom/TimeRanges.h"
+#include "mp4_demuxer/BufferStream.h"
+#include "mp4_demuxer/MoofParser.h"
 #include "nsError.h"
 #include "nsIEventTarget.h"
 #include "nsIRunnable.h"
 #include "nsThreadUtils.h"
 #include "prlog.h"
 #include "SourceBufferDecoder.h"
 #include "mozilla/Preferences.h"
 
@@ -80,16 +82,18 @@ public:
       return true;
     }
     return false;
   }
 };
 
 class MP4ContainerParser : public ContainerParser {
 public:
+  MP4ContainerParser() : mTimescale(0) {}
+
   bool IsInitSegmentPresent(const uint8_t* aData, uint32_t aLength)
   {
     ContainerParser::IsInitSegmentPresent(aData, aLength);
     // Each MP4 atom has a chunk size and chunk type. The root chunk in an MP4
     // file is the 'ftyp' atom followed by a file type. We just check for a
     // vaguely valid 'ftyp' atom.
 
     if (aLength < 8) {
@@ -106,16 +110,43 @@ public:
           aData[7] == 'v') {
         return true;
       }
     }
 
     return aData[4] == 'f' && aData[5] == 't' && aData[6] == 'y' &&
            aData[7] == 'p';
   }
+
+  virtual bool ParseStartAndEndTimestamps(const uint8_t* aData, uint32_t aLength,
+                                          double& aStart, double& aEnd)
+  {
+    mp4_demuxer::MoofParser parser(new mp4_demuxer::BufferStream(aData, aLength), 0);
+    parser.mMdhd.mTimescale = mTimescale;
+
+    nsTArray<MediaByteRange> byteRanges;
+    byteRanges.AppendElement(MediaByteRange(0, aLength));
+    parser.RebuildFragmentedIndex(byteRanges);
+
+    // Persist the timescale for when it is absent in later chunks
+    mTimescale = parser.mMdhd.mTimescale;
+
+    mp4_demuxer::Interval<mp4_demuxer::Microseconds> compositionRange =
+        parser.GetCompositionRange();
+
+    if (compositionRange.IsNull()) {
+      return false;
+    }
+    aStart = static_cast<double>(compositionRange.start) / USECS_PER_S;
+    aEnd = static_cast<double>(compositionRange.end) / USECS_PER_S;
+    return true;
+  }
+
+  private:
+    uint32_t mTimescale;
 };
 
 
 /*static*/ ContainerParser*
 ContainerParser::CreateForMIMEType(const nsACString& aType)
 {
   if (aType.LowerCaseEqualsLiteral("video/webm") || aType.LowerCaseEqualsLiteral("audio/webm")) {
     return new WebMContainerParser();
--- a/content/media/omx/MediaCodecReader.cpp
+++ b/content/media/omx/MediaCodecReader.cpp
@@ -125,17 +125,18 @@ MediaCodecReader::TrackInputCopier::Copy
   memcpy(aCodecBuffer->data(),
          (uint8_t*)aSourceBuffer->data() + aSourceBuffer->range_offset(),
          aSourceBuffer->range_length());
 
   return true;
 }
 
 MediaCodecReader::Track::Track()
-  : mDurationUs(INT64_C(0))
+  : mSourceIsStopped(true)
+  , mDurationUs(INT64_C(0))
   , mInputIndex(sInvalidInputIndex)
   , mInputEndOfStream(false)
   , mOutputEndOfStream(false)
   , mSeekTimeUs(sInvalidTimestampUs)
   , mFlushed(false)
   , mDiscontinuity(false)
   , mTaskQueue(nullptr)
 {
@@ -215,22 +216,32 @@ bool
 MediaCodecReader::IsWaitingMediaResources()
 {
   return mVideoTrack.mCodec != nullptr && !mVideoTrack.mCodec->allocated();
 }
 
 bool
 MediaCodecReader::IsDormantNeeded()
 {
-  return mVideoTrack.mCodec != nullptr;
+  return mVideoTrack.mSource != nullptr;
 }
 
 void
 MediaCodecReader::ReleaseMediaResources()
 {
+  // Stop the mSource because we are in the dormant state and the stop function
+  // will rewind the mSource to the beginning of the stream.
+  if (mVideoTrack.mSource != nullptr) {
+    mVideoTrack.mSource->stop();
+    mVideoTrack.mSourceIsStopped = true;
+  }
+  if (mAudioTrack.mSource != nullptr) {
+    mAudioTrack.mSource->stop();
+    mAudioTrack.mSourceIsStopped = true;
+  }
   ReleaseCriticalResources();
 }
 
 void
 MediaCodecReader::Shutdown()
 {
   ReleaseResources();
 }
@@ -831,25 +842,27 @@ MediaCodecReader::CreateMediaSources()
     NS_WARNING("OMX decoder could not find audio or video tracks");
     return false;
   }
 
   if (audioTrackIndex != invalidTrackIndex && mAudioTrack.mSource == nullptr) {
     sp<MediaSource> audioSource = mExtractor->getTrack(audioTrackIndex);
     if (audioSource != nullptr && audioSource->start() == OK) {
       mAudioTrack.mSource = audioSource;
+      mAudioTrack.mSourceIsStopped = false;
     }
     // Get one another track instance for audio offload playback.
     mAudioOffloadTrack.mSource = mExtractor->getTrack(audioTrackIndex);
   }
 
   if (videoTrackIndex != invalidTrackIndex && mVideoTrack.mSource == nullptr) {
     sp<MediaSource> videoSource = mExtractor->getTrack(videoTrackIndex);
     if (videoSource != nullptr && videoSource->start() == OK) {
       mVideoTrack.mSource = videoSource;
+      mVideoTrack.mSourceIsStopped = false;
     }
   }
 
   return
     (audioTrackIndex == invalidTrackIndex || mAudioTrack.mSource != nullptr) &&
     (videoTrackIndex == invalidTrackIndex || mVideoTrack.mSource != nullptr);
 }
 
@@ -1224,16 +1237,24 @@ MediaCodecReader::FillCodecInputData(Tra
   size_t index = 0;
   while (aTrack.mInputIndex.isValid() ||
          aTrack.mCodec->dequeueInputBuffer(&index) == OK) {
     if (!aTrack.mInputIndex.isValid()) {
       aTrack.mInputIndex = index;
     }
     MOZ_ASSERT(aTrack.mInputIndex.isValid(), "aElement.mInputIndex should be valid");
 
+    // Start the mSource before we read it.
+    if (aTrack.mSourceIsStopped) {
+      if (aTrack.mSource->start() == OK) {
+        aTrack.mSourceIsStopped = false;
+      } else {
+        return UNKNOWN_ERROR;
+      }
+    }
     MediaBuffer* source_buffer = nullptr;
     status_t status = OK;
     if (IsValidTimestampUs(aTrack.mSeekTimeUs)) {
       MediaSource::ReadOptions options;
       options.setSeekTo(aTrack.mSeekTimeUs);
       status = aTrack.mSource->read(&source_buffer, &options);
     } else {
       status = aTrack.mSource->read(&source_buffer);
@@ -1306,17 +1327,17 @@ MediaCodecReader::GetCodecOutputData(Tra
     if (!IsValidDurationUs(duration)) {
       return -EAGAIN;
     }
 
     status = aTrack.mCodec->dequeueOutputBuffer(&info.mIndex, &info.mOffset,
       &info.mSize, &info.mTimeUs, &info.mFlags, duration);
     // Check EOS first.
     if (status == ERROR_END_OF_STREAM ||
-        info.mFlags & MediaCodec::BUFFER_FLAG_EOS) {
+        (info.mFlags & MediaCodec::BUFFER_FLAG_EOS)) {
       aBuffer = info;
       aBuffer.mBuffer = aTrack.mOutputBuffers[info.mIndex];
       aTrack.mOutputEndOfStream = true;
       return ERROR_END_OF_STREAM;
     }
 
     if (status == OK) {
       if (!IsValidTimestampUs(aThreshold) || info.mTimeUs >= aThreshold) {
--- a/content/media/omx/MediaCodecReader.h
+++ b/content/media/omx/MediaCodecReader.h
@@ -95,16 +95,17 @@ protected:
   };
 
   struct Track
   {
     Track();
 
     // pipeline parameters
     android::sp<android::MediaSource> mSource;
+    bool mSourceIsStopped;
     android::sp<android::MediaCodecProxy> mCodec;
     android::Vector<android::sp<android::ABuffer> > mInputBuffers;
     android::Vector<android::sp<android::ABuffer> > mOutputBuffers;
 
     // pipeline copier
     nsAutoPtr<TrackInputCopier> mInputCopier;
 
     // media parameters
--- a/content/media/test/test_can_play_type_mpeg.html
+++ b/content/media/test/test_can_play_type_mpeg.html
@@ -16,39 +16,51 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 <video id="v"></video>
 
 <pre id="test">
 <script src="can_play_type_mpeg.js"></script>
 <script>
 
 function IsWindowsVistaOrLater() {
-  var re = /Windows NT (\d.\d)/;
+  var re = /Windows NT (\d+\.\d)/;
   var winver = navigator.userAgent.match(re);
   return winver && winver.length == 2 && parseFloat(winver[1]) >= 6.0;
 }
 
-function IsWindowsXPOrEarlier() {
-  var re = /Windows NT (\d.\d)/;
-  var winver = navigator.userAgent.match(re);
-  return winver && winver.length == 2 && parseFloat(winver[1]) < 6.0;
+function IsMacOSLionOrLater() {
+  var re = /Mac OS X (\d+)\.(\d+)/;
+  var ver = navigator.userAgent.match(re);
+  if (!ver || ver.length != 3) {
+    return false;
+  }
+  var major = ver[1] | 0;
+  var minor = ver[2] | 0;
+  return major == 10 && minor >= 7;
 }
 
 function getPref(name) {
   var pref = false;
   try {
     pref = SpecialPowers.getBoolPref(name);
   } catch(ex) { }
   return pref;
 }
 
+// Check whether we should expect the new MP4Reader-based support to work.
+function IsMP4ReaderAvailable() {
+  var prefs = getPref("media.fragmented-mp4.enabled") &&
+              getPref("media.fragmented-mp4.exposed");
+  return prefs && (IsWindowsVistaOrLater() || IsMacOSLionOrLater());
+}
+
 var haveMp4 = (getPref("media.windows-media-foundation.enabled") && IsWindowsVistaOrLater()) ||
                getPref("media.omx.enabled") ||
                getPref("media.gstreamer.enabled") ||
-               (getPref("media.fragmented-mp4.exposed") && !IsWindowsXPOrEarlier());
+               IsMP4ReaderAvailable();
 // TODO:  Add "getPref("media.plugins.enabled")" once MP4 works on Gingerbread.
              
 check_mp4(document.getElementById('v'), haveMp4);
 
 var haveMp3 = getPref("media.directshow.enabled") ||
               (getPref("media.windows-media-foundation.enabled") && IsWindowsVistaOrLater()) ||
                getPref("media.omx.enabled") ||
                getPref("media.gstreamer.enabled") ||
--- a/content/media/webspeech/synth/SpeechSynthesisUtterance.cpp
+++ b/content/media/webspeech/synth/SpeechSynthesisUtterance.cpp
@@ -15,17 +15,16 @@
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(SpeechSynthesisUtterance,
                                    DOMEventTargetHelper, mVoice);
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(SpeechSynthesisUtterance)
-  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(SpeechSynthesisUtterance, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(SpeechSynthesisUtterance, DOMEventTargetHelper)
 
 SpeechSynthesisUtterance::SpeechSynthesisUtterance(nsPIDOMWindow* aOwnerWindow,
                                                    const nsAString& text)
   : DOMEventTargetHelper(aOwnerWindow)
--- a/dom/apps/src/PermissionsTable.jsm
+++ b/dom/apps/src/PermissionsTable.jsm
@@ -47,16 +47,21 @@ this.PermissionsTable =  { geolocation: 
                              privileged: ALLOW_ACTION,
                              certified: ALLOW_ACTION
                            },
                            "tcp-socket": {
                              app: DENY_ACTION,
                              privileged: ALLOW_ACTION,
                              certified: ALLOW_ACTION
                            },
+                           "udp-socket": {
+                             app: DENY_ACTION,
+                             privileged: ALLOW_ACTION,
+                             certified: ALLOW_ACTION
+                           },
                            "network-events": {
                              app: DENY_ACTION,
                              privileged: DENY_ACTION,
                              certified: ALLOW_ACTION
                            },
                            contacts: {
                              app: DENY_ACTION,
                              privileged: PROMPT_ACTION,
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -624,16 +624,20 @@ this.DOMApplicationRegistry = {
 
   loadAndUpdateApps: function() {
     return Task.spawn(function() {
       let runUpdate = AppsUtils.isFirstRun(Services.prefs);
 
       yield this.loadCurrentRegistry();
 
       if (runUpdate) {
+
+        // Run migration before uninstall of core apps happens.
+        Services.obs.notifyObservers(null, "webapps-before-update-merge", null);        
+
 #ifdef MOZ_WIDGET_GONK
         yield this.installSystemApps();
 #endif
 
         // At first run, install preloaded apps and set up their permissions.
         for (let id in this.webapps) {
           let isPreinstalled = this.installPreinstalledApp(id);
           this.removeIfHttpsDuplicate(id);
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -208,16 +208,17 @@
 #include "prrng.h"
 #include "nsSandboxFlags.h"
 #include "TimeChangeObserver.h"
 #include "mozilla/dom/AudioContext.h"
 #include "mozilla/dom/BrowserElementDictionariesBinding.h"
 #include "mozilla/dom/Console.h"
 #include "mozilla/dom/FunctionBinding.h"
 #include "mozilla/dom/HashChangeEvent.h"
+#include "mozilla/dom/MozSelfSupportBinding.h"
 #include "mozilla/dom/PopStateEvent.h"
 #include "mozilla/dom/PopupBlockedEvent.h"
 #include "mozilla/dom/WindowBinding.h"
 #include "nsITabChild.h"
 #include "mozilla/dom/MediaQueryList.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/NavigatorBinding.h"
 #ifdef HAVE_SIDEBAR
@@ -1462,16 +1463,18 @@ nsGlobalWindow::CleanUp()
   mWindowUtils = nullptr;
   mApplicationCache = nullptr;
   mIndexedDB = nullptr;
 
   mConsole = nullptr;
 
   mExternal = nullptr;
 
+  mMozSelfSupport = nullptr;
+
   mPerformance = nullptr;
 
 #ifdef MOZ_WEBSPEECH
   mSpeechSynthesis = nullptr;
 #endif
 
   ClearControllers();
 
@@ -1781,16 +1784,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mToolbar)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocationbar)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPersonalbar)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStatusbar)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScrollbars)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCrypto)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExternal)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMozSelfSupport)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
   nsGlobalWindow::CleanupCachedXBLHandlers(tmp);
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)
 
@@ -1841,16 +1845,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mToolbar)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocationbar)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPersonalbar)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mStatusbar)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mScrollbars)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCrypto)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mExternal)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mMozSelfSupport)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 #ifdef DEBUG
 void
 nsGlobalWindow::RiskyUnlink()
 {
   NS_CYCLE_COLLECTION_INNERNAME.Unlink(this);
@@ -4060,16 +4065,29 @@ NS_IMETHODIMP
 nsGlobalWindow::GetContent(nsIDOMWindow** aContent)
 {
   ErrorResult rv;
   *aContent = GetContentInternal(rv).take();
 
   return rv.ErrorCode();
 }
 
+MozSelfSupport*
+nsGlobalWindow::GetMozSelfSupport(ErrorResult& aError)
+{
+  if (mMozSelfSupport) {
+    return mMozSelfSupport;
+  }
+
+  AutoSafeJSContext cx;
+  GlobalObject global(cx, FastGetGlobalJSObject());
+  mMozSelfSupport = MozSelfSupport::Constructor(global, cx, aError);
+  return mMozSelfSupport;
+}
+
 NS_IMETHODIMP
 nsGlobalWindow::GetScriptableContent(JSContext* aCx, JS::MutableHandle<JS::Value> aVal)
 {
   ErrorResult rv;
   JS::Rooted<JSObject*> content(aCx);
   GetContent(aCx, &content, rv);
   if (!rv.Failed()) {
     aVal.setObjectOrNull(content);
@@ -7184,32 +7202,47 @@ nsGlobalWindow::GetTopWindowRoot()
   if (!piWin) {
     return nullptr;
   }
 
   nsCOMPtr<nsPIWindowRoot> window = do_QueryInterface(piWin->GetChromeEventHandler());
   return window.forget();
 }
 
+void
+nsGlobalWindow::Scroll(int32_t aXScroll, int32_t aYScroll,
+                       const ScrollOptions& aOptions)
+{
+  ScrollTo(CSSIntPoint(aXScroll, aYScroll), aOptions);
+}
+
+void
+nsGlobalWindow::ScrollTo(int32_t aXScroll, int32_t aYScroll,
+                         const ScrollOptions& aOptions)
+{
+  ScrollTo(CSSIntPoint(aXScroll, aYScroll), aOptions);
+}
+
 NS_IMETHODIMP
 nsGlobalWindow::Scroll(int32_t aXScroll, int32_t aYScroll)
 {
-  ScrollTo(CSSIntPoint(aXScroll, aYScroll));
+  ScrollTo(CSSIntPoint(aXScroll, aYScroll), ScrollOptions());
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::ScrollTo(int32_t aXScroll, int32_t aYScroll)
 {
-  ScrollTo(CSSIntPoint(aXScroll, aYScroll));
+  ScrollTo(CSSIntPoint(aXScroll, aYScroll), ScrollOptions());
   return NS_OK;
 }
 
 void
-nsGlobalWindow::ScrollTo(const CSSIntPoint& aScroll)
+nsGlobalWindow::ScrollTo(const CSSIntPoint& aScroll,
+                         const ScrollOptions& aOptions)
 {
   FlushPendingNotifications(Flush_Layout);
   nsIScrollableFrame *sf = GetScrollFrame();
 
   if (sf) {
     // Here we calculate what the max pixel value is that we can
     // scroll to, we do this by dividing maxint with the pixel to
     // twips conversion factor, and subtracting 4, the 4 comes from
@@ -7220,17 +7253,96 @@ nsGlobalWindow::ScrollTo(const CSSIntPoi
     CSSIntPoint scroll(aScroll);
     if (scroll.x > maxpx) {
       scroll.x = maxpx;
     }
 
     if (scroll.y > maxpx) {
       scroll.y = maxpx;
     }
-    sf->ScrollToCSSPixels(scroll);
+
+    sf->ScrollToCSSPixels(scroll,
+                          aOptions.mBehavior == ScrollBehavior::Smooth
+                            ? nsIScrollableFrame::SMOOTH_MSD
+                            : nsIScrollableFrame::INSTANT);
+  }
+}
+
+NS_IMETHODIMP
+nsGlobalWindow::ScrollBy(int32_t aXScrollDif, int32_t aYScrollDif)
+{
+  ScrollBy(aXScrollDif, aYScrollDif, ScrollOptions());
+
+  return NS_OK;
+}
+
+void
+nsGlobalWindow::ScrollBy(int32_t aXScrollDif, int32_t aYScrollDif,
+                         const ScrollOptions& aOptions)
+{
+  FlushPendingNotifications(Flush_Layout);
+  nsIScrollableFrame *sf = GetScrollFrame();
+
+  if (sf) {
+    CSSIntPoint scrollPos =
+      sf->GetScrollPositionCSSPixels() + CSSIntPoint(aXScrollDif, aYScrollDif);
+    // It seems like it would make more sense for ScrollBy to use
+    // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
+    // Perhaps Web content does too.
+    ScrollTo(scrollPos, aOptions);
+  }
+}
+
+NS_IMETHODIMP
+nsGlobalWindow::ScrollByLines(int32_t numLines)
+{
+  ScrollByLines(numLines, ScrollOptions());
+
+  return NS_OK;
+}
+
+void
+nsGlobalWindow::ScrollByLines(int32_t numLines,
+                              const ScrollOptions& aOptions)
+{
+  FlushPendingNotifications(Flush_Layout);
+  nsIScrollableFrame *sf = GetScrollFrame();
+  if (sf) {
+    // It seems like it would make more sense for ScrollByLines to use
+    // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
+    // Perhaps Web content does too.
+    sf->ScrollBy(nsIntPoint(0, numLines), nsIScrollableFrame::LINES,
+                 aOptions.mBehavior == ScrollBehavior::Smooth
+                   ? nsIScrollableFrame::SMOOTH_MSD
+                   : nsIScrollableFrame::INSTANT);
+  }
+}
+
+NS_IMETHODIMP
+nsGlobalWindow::ScrollByPages(int32_t numPages)
+{
+  ScrollByPages(numPages, ScrollOptions());
+
+  return NS_OK;
+}
+
+void
+nsGlobalWindow::ScrollByPages(int32_t numPages,
+                              const ScrollOptions& aOptions)
+{
+  FlushPendingNotifications(Flush_Layout);
+  nsIScrollableFrame *sf = GetScrollFrame();
+  if (sf) {
+    // It seems like it would make more sense for ScrollByPages to use
+    // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
+    // Perhaps Web content does too.
+    sf->ScrollBy(nsIntPoint(0, numPages), nsIScrollableFrame::PAGES,
+                 aOptions.mBehavior == ScrollBehavior::Smooth
+                   ? nsIScrollableFrame::SMOOTH_MSD
+                   : nsIScrollableFrame::INSTANT);
   }
 }
 
 void
 nsGlobalWindow::MozRequestOverfill(OverfillCallback& aCallback,
                                    mozilla::ErrorResult& aError)
 {
   nsIWidget* widget = nsContentUtils::WidgetForDocument(mDoc);
@@ -7240,66 +7352,16 @@ nsGlobalWindow::MozRequestOverfill(Overf
       manager->RequestOverfill(&aCallback);
       return;
     }
   }
 
   aError.Throw(NS_ERROR_NOT_AVAILABLE);
 }
 
-NS_IMETHODIMP
-nsGlobalWindow::ScrollBy(int32_t aXScrollDif, int32_t aYScrollDif)
-{
-  FlushPendingNotifications(Flush_Layout);
-  nsIScrollableFrame *sf = GetScrollFrame();
-
-  if (sf) {
-    CSSIntPoint scrollPos =
-      sf->GetScrollPositionCSSPixels() + CSSIntPoint(aXScrollDif, aYScrollDif);
-    // It seems like it would make more sense for ScrollBy to use
-    // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
-    // Perhaps Web content does too.
-    ScrollTo(scrollPos);
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsGlobalWindow::ScrollByLines(int32_t numLines)
-{
-  FlushPendingNotifications(Flush_Layout);
-  nsIScrollableFrame *sf = GetScrollFrame();
-  if (sf) {
-    // It seems like it would make more sense for ScrollByLines to use
-    // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
-    // Perhaps Web content does too.
-    sf->ScrollBy(nsIntPoint(0, numLines), nsIScrollableFrame::LINES,
-                 nsIScrollableFrame::INSTANT);
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsGlobalWindow::ScrollByPages(int32_t numPages)
-{
-  FlushPendingNotifications(Flush_Layout);
-  nsIScrollableFrame *sf = GetScrollFrame();
-  if (sf) {
-    // It seems like it would make more sense for ScrollByPages to use
-    // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
-    // Perhaps Web content does too.
-    sf->ScrollBy(nsIntPoint(0, numPages), nsIScrollableFrame::PAGES,
-                 nsIScrollableFrame::INSTANT);
-  }
-
-  return NS_OK;
-}
-
 void
 nsGlobalWindow::ClearTimeout(int32_t aHandle, ErrorResult& aError)
 {
   if (aHandle > 0) {
     ClearTimeoutOrInterval(aHandle, aError);
   }
 }
 
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -44,16 +44,17 @@
 #include "mozilla/LinkedList.h"
 #include "mozilla/TimeStamp.h"
 #include "nsIInlineEventHandlers.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsIIdleObserver.h"
 #include "nsIDocument.h"
 #include "nsIDOMTouchEvent.h"
 #include "mozilla/dom/EventTarget.h"
+#include "mozilla/dom/WindowBinding.h"
 #include "Units.h"
 #include "nsComponentManagerUtils.h"
 
 #ifdef MOZ_B2G
 #include "nsIDOMWindowB2G.h"
 #endif // MOZ_B2G
 
 #ifdef MOZ_WEBSPEECH
@@ -108,16 +109,17 @@ namespace mozilla {
 class DOMEventTargetHelper;
 namespace dom {
 class BarProp;
 class Console;
 class External;
 class Function;
 class Gamepad;
 class MediaQueryList;
+class MozSelfSupport;
 class Navigator;
 class OwningExternalOrWindowProxy;
 class Selection;
 class SpeechSynthesis;
 class WakeLock;
 namespace indexedDB {
 class IDBFactory;
 } // namespace indexedDB
@@ -930,16 +932,26 @@ public:
                                                             mozilla::ErrorResult& aError);
   nsScreen* GetScreen(mozilla::ErrorResult& aError);
   void MoveTo(int32_t aXPos, int32_t aYPos, mozilla::ErrorResult& aError);
   void MoveBy(int32_t aXDif, int32_t aYDif, mozilla::ErrorResult& aError);
   void ResizeTo(int32_t aWidth, int32_t aHeight,
                 mozilla::ErrorResult& aError);
   void ResizeBy(int32_t aWidthDif, int32_t aHeightDif,
                 mozilla::ErrorResult& aError);
+  void Scroll(int32_t aXScroll, int32_t aYScroll,
+              const mozilla::dom::ScrollOptions& aOptions);
+  void ScrollTo(int32_t aXScroll, int32_t aYScroll,
+                const mozilla::dom::ScrollOptions& aOptions);
+  void ScrollBy(int32_t aXScrollDif, int32_t aYScrollDif,
+                const mozilla::dom::ScrollOptions& aOptions);
+  void ScrollByLines(int32_t numLines,
+                     const mozilla::dom::ScrollOptions& aOptions);
+  void ScrollByPages(int32_t numPages,
+                     const mozilla::dom::ScrollOptions& aOptions);
   int32_t GetInnerWidth(mozilla::ErrorResult& aError);
   void SetInnerWidth(int32_t aInnerWidth, mozilla::ErrorResult& aError);
   int32_t GetInnerHeight(mozilla::ErrorResult& aError);
   void SetInnerHeight(int32_t aInnerHeight, mozilla::ErrorResult& aError);
   int32_t GetScrollX(mozilla::ErrorResult& aError);
   int32_t GetPageXOffset(mozilla::ErrorResult& aError)
   {
     return GetScrollX(aError);
@@ -1000,16 +1012,19 @@ public:
   void SetFullScreen(bool aFullScreen, mozilla::ErrorResult& aError);
   void Back(mozilla::ErrorResult& aError);
   void Forward(mozilla::ErrorResult& aError);
   void Home(mozilla::ErrorResult& aError);
   bool Find(const nsAString& aString, bool aCaseSensitive, bool aBackwards,
             bool aWrapAround, bool aWholeWord, bool aSearchInFrames,
             bool aShowDialog, mozilla::ErrorResult& aError);
   uint64_t GetMozPaintCount(mozilla::ErrorResult& aError);
+
+  mozilla::dom::MozSelfSupport* GetMozSelfSupport(mozilla::ErrorResult& aError);
+
   already_AddRefed<nsIDOMWindow> OpenDialog(JSContext* aCx,
                                             const nsAString& aUrl,
                                             const nsAString& aName,
                                             const nsAString& aOptions,
                                             const mozilla::dom::Sequence<JS::Value>& aExtraArgument,
                                             mozilla::ErrorResult& aError);
   void GetContent(JSContext* aCx,
                   JS::MutableHandle<JSObject*> aRetval,
@@ -1307,17 +1322,18 @@ public:
 
   // Outer windows only.
   nsresult GetInnerSize(mozilla::CSSIntSize& aSize);
   nsIntSize GetOuterSize(mozilla::ErrorResult& aError);
   void SetOuterSize(int32_t aLengthCSSPixels, bool aIsWidth,
                     mozilla::ErrorResult& aError);
   nsRect GetInnerScreenRect();
 
-  void ScrollTo(const mozilla::CSSIntPoint& aScroll);
+  void ScrollTo(const mozilla::CSSIntPoint& aScroll,
+                const mozilla::dom::ScrollOptions& aOptions);
 
   bool IsFrame()
   {
     return GetParentInternal() != nullptr;
   }
 
   // Outer windows only.
   // If aLookForCallerOnJSStack is true, this method will look at the JS stack
@@ -1545,16 +1561,18 @@ protected:
   nsCOMPtr<nsIDOMCrypto>        mCrypto;
   nsRefPtr<mozilla::dom::Console> mConsole;
   // We need to store an nsISupports pointer to this object because the
   // mozilla::dom::External class doesn't exist on b2g and using the type
   // forward declared here means that ~nsGlobalWindow wouldn't compile because
   // it wouldn't see the ~External function's declaration.
   nsCOMPtr<nsISupports>         mExternal;
 
+  nsRefPtr<mozilla::dom::MozSelfSupport> mMozSelfSupport;
+
   nsRefPtr<mozilla::dom::DOMStorage> mLocalStorage;
   nsRefPtr<mozilla::dom::DOMStorage> mSessionStorage;
 
   // These member variable are used only on inner windows.
   nsRefPtr<mozilla::EventListenerManager> mListenerManager;
   // mTimeouts is generally sorted by mWhen, unless mTimeoutInsertionPoint is
   // non-null.  In that case, the dummy timeout pointed to by
   // mTimeoutInsertionPoint may have a later mWhen than some of the timeouts
--- a/dom/base/nsWrapperCache.h
+++ b/dom/base/nsWrapperCache.h
@@ -308,22 +308,26 @@ private:
   JS::Heap<JSObject*> mWrapper;
   FlagsType           mFlags;
 };
 
 enum { WRAPPER_CACHE_FLAGS_BITS_USED = 2 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsWrapperCache, NS_WRAPPERCACHE_IID)
 
-#define NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY                                   \
+#define NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY                                 \
   if ( aIID.Equals(NS_GET_IID(nsWrapperCache)) ) {                            \
     *aInstancePtr = static_cast<nsWrapperCache*>(this);                       \
     return NS_OK;                                                             \
   }
 
+#define NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY                                   \
+  NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY                                       \
+  else
+
 
 // Cycle collector macros for wrapper caches.
 
 #define NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER \
   tmp->TraceWrapper(aCallbacks, aClosure);
 
 #define NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \
   tmp->ReleaseWrapper(p);
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -2950,12 +2950,35 @@ MOZ_ALWAYS_INLINE bool
 CallerSubsumes(JS::Handle<JS::Value> aValue)
 {
   if (!aValue.isObject()) {
     return true;
   }
   return CallerSubsumes(&aValue.toObject());
 }
 
+template<class T>
+inline bool
+WrappedJSToDictionary(nsISupports* aObject, T& aDictionary)
+{
+  nsCOMPtr<nsIXPConnectWrappedJS> wrappedObj = do_QueryInterface(aObject);
+  if (!wrappedObj) {
+    return false;
+  }
+
+  AutoJSAPI jsapi;
+  jsapi.Init();
+
+  JSContext* cx = jsapi.cx();
+  JS::Rooted<JSObject*> obj(cx, wrappedObj->GetJSObject());
+  if (!obj) {
+    return false;
+  }
+
+  JSAutoCompartment ac(cx, obj);
+  JS::Rooted<JS::Value> v(cx, OBJECT_TO_JSVAL(obj));
+  return aDictionary.Init(cx, v);
+}
+
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_BindingUtils_h__ */
--- a/dom/bluetooth/BluetoothAdapter.cpp
+++ b/dom/bluetooth/BluetoothAdapter.cpp
@@ -118,20 +118,20 @@ public:
   {
     BluetoothReplyRunnable::ReleaseMembers();
     mAdapterPtr = nullptr;
   }
 private:
   nsRefPtr<BluetoothAdapter> mAdapterPtr;
 };
 
-class GetScoConnectionStatusTask : public BluetoothReplyRunnable
+class GetConnectionStatusTask : public BluetoothReplyRunnable
 {
 public:
-  GetScoConnectionStatusTask(nsIDOMDOMRequest* aReq) :
+  GetConnectionStatusTask(nsIDOMDOMRequest* aReq) :
     BluetoothReplyRunnable(aReq)
   {
     MOZ_ASSERT(aReq);
   }
 
   virtual bool ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue)
   {
     aValue.setUndefined();
@@ -678,17 +678,17 @@ BluetoothAdapter::SetPairingConfirmation
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 BluetoothAdapter::Connect(BluetoothDevice& aDevice,
-                          const Optional<short unsigned int>& aServiceUuid,
+                          const Optional<uint16_t>& aServiceUuid,
                           ErrorResult& aRv)
 {
   nsCOMPtr<nsPIDOMWindow> win = GetOwner();
   if (!win) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
@@ -711,17 +711,17 @@ BluetoothAdapter::Connect(BluetoothDevic
   }
   bs->Connect(address, deviceClass, serviceUuid, results);
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 BluetoothAdapter::Disconnect(BluetoothDevice& aDevice,
-                             const Optional<short unsigned int>& aServiceUuid,
+                             const Optional<uint16_t>& aServiceUuid,
                              ErrorResult& aRv)
 {
   nsCOMPtr<nsPIDOMWindow> win = GetOwner();
   if (!win) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
@@ -742,16 +742,39 @@ BluetoothAdapter::Disconnect(BluetoothDe
     return nullptr;
   }
   bs->Disconnect(address, serviceUuid, results);
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
+BluetoothAdapter::IsConnected(const uint16_t aServiceUuid, ErrorResult& aRv)
+{
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
+  if (!win) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsRefPtr<DOMRequest> request = new DOMRequest(win);
+  nsRefPtr<BluetoothReplyRunnable> results =
+    new GetConnectionStatusTask(request);
+
+  BluetoothService* bs = BluetoothService::Get();
+  if (!bs) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+  bs->IsConnected(aServiceUuid, results);
+
+  return request.forget();
+}
+
+already_AddRefed<DOMRequest>
 BluetoothAdapter::SendFile(const nsAString& aDeviceAddress,
                            nsIDOMBlob* aBlob, ErrorResult& aRv)
 {
   nsCOMPtr<nsPIDOMWindow> win = GetOwner();
   if (!win) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
@@ -887,17 +910,17 @@ BluetoothAdapter::IsScoConnected(ErrorRe
   nsCOMPtr<nsPIDOMWindow> win = GetOwner();
   if (!win) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(win);
   nsRefPtr<BluetoothReplyRunnable> results =
-    new GetScoConnectionStatusTask(request);
+    new GetConnectionStatusTask(request);
 
   BluetoothService* bs = BluetoothService::Get();
   if (!bs) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
   bs->IsScoConnected(results);
 
--- a/dom/bluetooth/BluetoothAdapter.h
+++ b/dom/bluetooth/BluetoothAdapter.h
@@ -114,21 +114,26 @@ public:
     SetPairingConfirmation(const nsAString& aDeviceAddress, bool aConfirmation,
                            ErrorResult& aRv);
   already_AddRefed<DOMRequest>
     SetAuthorization(const nsAString& aDeviceAddress, bool aAllow,
                      ErrorResult& aRv);
 
   already_AddRefed<DOMRequest>
     Connect(BluetoothDevice& aDevice,
-            const Optional<short unsigned int>& aServiceUuid, ErrorResult& aRv);
+            const Optional<uint16_t>& aServiceUuid, ErrorResult& aRv);
   already_AddRefed<DOMRequest>
     Disconnect(BluetoothDevice& aDevice,
-               const Optional<short unsigned int>& aServiceUuid,
+               const Optional<uint16_t>& aServiceUuid,
                ErrorResult& aRv);
+
+  already_AddRefed<DOMRequest>
+    IsConnected(const uint16_t aServiceUuid,
+                ErrorResult& aRv);
+
   already_AddRefed<DOMRequest>
     GetConnectedDevices(uint16_t aServiceUuid, ErrorResult& aRv);
 
   already_AddRefed<DOMRequest>
     SendFile(const nsAString& aDeviceAddress, nsIDOMBlob* aBlob,
              ErrorResult& aRv);
   already_AddRefed<DOMRequest>
     StopSendingFile(const nsAString& aDeviceAddress, ErrorResult& aRv);
--- a/dom/bluetooth/BluetoothManager.cpp
+++ b/dom/bluetooth/BluetoothManager.cpp
@@ -205,25 +205,13 @@ BluetoothManager::Notify(const Bluetooth
     nsCString warningMsg;
     warningMsg.AssignLiteral("Not handling manager signal: ");
     warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
     BT_WARNING(warningMsg.get());
 #endif
   }
 }
 
-bool
-BluetoothManager::IsConnected(uint16_t aProfileId, ErrorResult& aRv)
-{
-  BluetoothService* bs = BluetoothService::Get();
-  if (!bs) {
-    aRv.Throw(NS_ERROR_FAILURE);
-    return false;
-  }
-
-  return bs->IsConnected(aProfileId);
-}
-
 JSObject*
 BluetoothManager::WrapObject(JSContext* aCx)
 {
   return BluetoothManagerBinding::Wrap(aCx, this);
 }
--- a/dom/bluetooth/BluetoothManager.h
+++ b/dom/bluetooth/BluetoothManager.h
@@ -34,17 +34,16 @@ public:
   // Never returns null
   static already_AddRefed<BluetoothManager>
     Create(nsPIDOMWindow* aWindow);
   static bool CheckPermission(nsPIDOMWindow* aWindow);
   void Notify(const BluetoothSignal& aData);
   virtual void SetPropertyByValue(const BluetoothNamedValue& aValue) MOZ_OVERRIDE;
 
   bool GetEnabled(ErrorResult& aRv);
-  bool IsConnected(uint16_t aProfileId, ErrorResult& aRv);
 
   already_AddRefed<DOMRequest> GetDefaultAdapter(ErrorResult& aRv);
 
   IMPL_EVENT_HANDLER(enabled);
   IMPL_EVENT_HANDLER(disabled);
   IMPL_EVENT_HANDLER(adapteradded);
 
   nsPIDOMWindow* GetParentObject() const
--- a/dom/bluetooth/BluetoothService.h
+++ b/dom/bluetooth/BluetoothService.h
@@ -224,18 +224,18 @@ public:
   virtual void
   Connect(const nsAString& aDeviceAddress, uint32_t aCod, uint16_t aServiceUuid,
           BluetoothReplyRunnable* aRunnable) = 0;
 
   virtual void
   Disconnect(const nsAString& aDeviceAddress, uint16_t aServiceUuid,
              BluetoothReplyRunnable* aRunnable) = 0;
 
-  virtual bool
-  IsConnected(uint16_t aServiceUuid) = 0;
+  virtual void
+  IsConnected(const uint16_t aServiceUuid, BluetoothReplyRunnable* aRunnable) = 0;
 
   virtual void
   SendFile(const nsAString& aDeviceAddress,
            BlobParent* aBlobParent,
            BlobChild* aBlobChild,
            BluetoothReplyRunnable* aRunnable) = 0;
 
   virtual void
--- a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
@@ -999,31 +999,42 @@ void
 BluetoothServiceBluedroid::Connect(const nsAString& aDeviceAddress,
                                    uint32_t aCod,
                                    uint16_t aServiceUuid,
                                    BluetoothReplyRunnable* aRunnable)
 {
   ConnectDisconnect(true, aDeviceAddress, aRunnable, aServiceUuid, aCod);
 }
 
-bool
-BluetoothServiceBluedroid::IsConnected(uint16_t aProfileId)
-{
-  return true;
-}
-
 void
 BluetoothServiceBluedroid::Disconnect(
   const nsAString& aDeviceAddress, uint16_t aServiceUuid,
   BluetoothReplyRunnable* aRunnable)
 {
   ConnectDisconnect(false, aDeviceAddress, aRunnable, aServiceUuid);
 }
 
 void
+BluetoothServiceBluedroid::IsConnected(const uint16_t aServiceUuid,
+                                       BluetoothReplyRunnable* aRunnable)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aRunnable);
+
+  BluetoothProfileManagerBase* profile =
+    BluetoothUuidHelper::GetBluetoothProfileManager(aServiceUuid);
+  if (profile) {
+    DispatchBluetoothReply(aRunnable, profile->IsConnected(), EmptyString());
+  } else {
+    BT_WARNING("Can't find profile manager with uuid: %x", aServiceUuid);
+    DispatchBluetoothReply(aRunnable, false, EmptyString());
+  }
+}
+
+void
 BluetoothServiceBluedroid::SendFile(const nsAString& aDeviceAddress,
                                     BlobParent* aBlobParent,
                                     BlobChild* aBlobChild,
                                     BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // Currently we only support one device sending one file at a time,
--- a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.h
+++ b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.h
@@ -79,24 +79,25 @@ public:
   PrepareAdapterInternal();
 
   virtual void
   Connect(const nsAString& aDeviceAddress,
           uint32_t aCod,
           uint16_t aServiceUuid,
           BluetoothReplyRunnable* aRunnable);
 
-  virtual bool
-  IsConnected(uint16_t aProfileId);
-
   virtual void
   Disconnect(const nsAString& aDeviceAddress, uint16_t aServiceUuid,
              BluetoothReplyRunnable* aRunnable);
 
   virtual void
+  IsConnected(const uint16_t aServiceUuid,
+              BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
+
+  virtual void
   SendFile(const nsAString& aDeviceAddress,
            BlobParent* aBlobParent,
            BlobChild* aBlobChild,
            BluetoothReplyRunnable* aRunnable);
 
   virtual void
   SendFile(const nsAString& aDeviceAddress,
            nsIDOMBlob* aBlob,
--- a/dom/bluetooth/bluez/BluetoothDBusService.cpp
+++ b/dom/bluetooth/bluez/BluetoothDBusService.cpp
@@ -3452,30 +3452,31 @@ BluetoothDBusService::Connect(const nsAS
 void
 BluetoothDBusService::Disconnect(const nsAString& aDeviceAddress,
                                  uint16_t aServiceUuid,
                                  BluetoothReplyRunnable* aRunnable)
 {
   ConnectDisconnect(false, aDeviceAddress, aRunnable, aServiceUuid);
 }
 
-bool
-BluetoothDBusService::IsConnected(const uint16_t aServiceUuid)
+void
+BluetoothDBusService::IsConnected(const uint16_t aServiceUuid,
+                                  BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aRunnable);
 
   BluetoothProfileManagerBase* profile =
     BluetoothUuidHelper::GetBluetoothProfileManager(aServiceUuid);
-  if (!profile) {
-    BT_WARNING(ERR_UNKNOWN_PROFILE);
-    return false;
+  if (profile) {
+    DispatchBluetoothReply(aRunnable, profile->IsConnected(), EmptyString());
+  } else {
+    BT_WARNING("Can't find profile manager with uuid: %x", aServiceUuid);
+    DispatchBluetoothReply(aRunnable, false, EmptyString());
   }
-
-  NS_ENSURE_TRUE(profile, false);
-  return profile->IsConnected();
 }
 
 #ifdef MOZ_B2G_RIL
 void
 BluetoothDBusService::AnswerWaitingCall(BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
--- a/dom/bluetooth/bluez/BluetoothDBusService.h
+++ b/dom/bluetooth/bluez/BluetoothDBusService.h
@@ -101,18 +101,19 @@ public:
                                  BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual void
   Connect(const nsAString& aDeviceAddress,
           uint32_t aCod,
           uint16_t aServiceUuid,
           BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
-  virtual bool
-  IsConnected(uint16_t aServiceUuid) MOZ_OVERRIDE;
+  virtual void
+  IsConnected(const uint16_t aServiceUuid,
+              BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual void
   Disconnect(const nsAString& aDeviceAddress, uint16_t aServiceUuid,
              BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual void
   SendFile(const nsAString& aDeviceAddress,
            BlobParent* aBlobParent,
--- a/dom/bluetooth/ipc/BluetoothParent.cpp
+++ b/dom/bluetooth/ipc/BluetoothParent.cpp
@@ -213,16 +213,18 @@ BluetoothParent::RecvPBluetoothRequestCo
     case Request::TConfirmPairingConfirmationRequest:
       return actor->DoRequest(aRequest.get_ConfirmPairingConfirmationRequest());
     case Request::TDenyPairingConfirmationRequest:
       return actor->DoRequest(aRequest.get_DenyPairingConfirmationRequest());
     case Request::TConnectRequest:
       return actor->DoRequest(aRequest.get_ConnectRequest());
     case Request::TDisconnectRequest:
       return actor->DoRequest(aRequest.get_DisconnectRequest());
+    case Request::TIsConnectedRequest:
+      return actor->DoRequest(aRequest.get_IsConnectedRequest());
     case Request::TSendFileRequest:
       return actor->DoRequest(aRequest.get_SendFileRequest());
     case Request::TStopSendingFileRequest:
       return actor->DoRequest(aRequest.get_StopSendingFileRequest());
     case Request::TConfirmReceivingFileRequest:
       return actor->DoRequest(aRequest.get_ConfirmReceivingFileRequest());
     case Request::TDenyReceivingFileRequest:
       return actor->DoRequest(aRequest.get_DenyReceivingFileRequest());
@@ -505,16 +507,28 @@ BluetoothRequestParent::DoRequest(const 
   mService->Disconnect(aRequest.address(),
                        aRequest.serviceUuid(),
                        mReplyRunnable.get());
 
   return true;
 }
 
 bool
+BluetoothRequestParent::DoRequest(const IsConnectedRequest& aRequest)
+{
+  MOZ_ASSERT(mService);
+  MOZ_ASSERT(mRequestType == Request::TIsConnectedRequest);
+
+  mService->IsConnected(aRequest.serviceUuid(),
+                        mReplyRunnable.get());
+
+  return true;
+}
+
+bool
 BluetoothRequestParent::DoRequest(const SendFileRequest& aRequest)
 {
   MOZ_ASSERT(mService);
   MOZ_ASSERT(mRequestType == Request::TSendFileRequest);
 
   mService->SendFile(aRequest.devicePath(),
                      (BlobParent*)aRequest.blobParent(),
                      (BlobChild*)aRequest.blobChild(),
--- a/dom/bluetooth/ipc/BluetoothParent.h
+++ b/dom/bluetooth/ipc/BluetoothParent.h
@@ -165,16 +165,19 @@ protected:
 
   bool
   DoRequest(const ConnectRequest& aRequest);
 
   bool
   DoRequest(const DisconnectRequest& aRequest);
 
   bool
+  DoRequest(const IsConnectedRequest& aRequest);
+
+  bool
   DoRequest(const SendFileRequest& aRequest);
 
   bool
   DoRequest(const StopSendingFileRequest& aRequest);
 
   bool
   DoRequest(const ConfirmReceivingFileRequest& aRequest);
 
--- a/dom/bluetooth/ipc/BluetoothServiceChildProcess.cpp
+++ b/dom/bluetooth/ipc/BluetoothServiceChildProcess.cpp
@@ -241,16 +241,24 @@ BluetoothServiceChildProcess::Disconnect
   uint16_t aServiceUuid,
   BluetoothReplyRunnable* aRunnable)
 {
   SendRequest(aRunnable,
               DisconnectRequest(nsString(aDeviceAddress), aServiceUuid));
 }
 
 void
+BluetoothServiceChildProcess::IsConnected(
+  const uint16_t aServiceUuid,
+  BluetoothReplyRunnable* aRunnable)
+{
+  SendRequest(aRunnable, IsConnectedRequest(aServiceUuid));
+}
+
+void
 BluetoothServiceChildProcess::SendFile(
   const nsAString& aDeviceAddress,
   BlobParent* aBlobParent,
   BlobChild* aBlobChild,
   BluetoothReplyRunnable* aRunnable)
 {
   SendRequest(aRunnable,
               SendFileRequest(nsString(aDeviceAddress), nullptr, aBlobChild));
@@ -384,22 +392,16 @@ BluetoothServiceChildProcess::StartInter
 }
 
 nsresult
 BluetoothServiceChildProcess::StopInternal()
 {
   MOZ_CRASH("This should never be called!");
 }
 
-bool
-BluetoothServiceChildProcess::IsConnected(uint16_t aServiceUuid)
-{
-  MOZ_CRASH("This should never be called!");
-}
-
 nsresult
 BluetoothServiceChildProcess::SendSinkMessage(const nsAString& aDeviceAddresses,
                                               const nsAString& aMessage)
 {
   MOZ_CRASH("This should never be called!");
 }
 
 nsresult
--- a/dom/bluetooth/ipc/BluetoothServiceChildProcess.h
+++ b/dom/bluetooth/ipc/BluetoothServiceChildProcess.h
@@ -106,18 +106,19 @@ public:
           uint16_t aServiceUuid,
           BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual void
   Disconnect(const nsAString& aDeviceAddress,
              uint16_t aServiceUuid,
              BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
-  virtual bool
-  IsConnected(uint16_t aServiceUuid) MOZ_OVERRIDE;
+  virtual void
+  IsConnected(const uint16_t aServiceUuid,
+              BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual void
   SendFile(const nsAString& aDeviceAddress,
            BlobParent* aBlobParent,
            BlobChild* aBlobChild,
            BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual void
--- a/dom/bluetooth/ipc/PBluetooth.ipdl
+++ b/dom/bluetooth/ipc/PBluetooth.ipdl
@@ -96,16 +96,21 @@ struct ConnectRequest
 };
 
 struct DisconnectRequest
 {
   nsString address;
   uint16_t serviceUuid;
 };
 
+struct IsConnectedRequest
+{
+  uint16_t serviceUuid;
+};
+
 struct SendFileRequest
 {
   nsString devicePath;
   PBlob blob;
 };
 
 struct StopSendingFileRequest
 {
@@ -175,16 +180,17 @@ union Request
   SetPinCodeRequest;
   SetPasskeyRequest;
   ConfirmPairingConfirmationRequest;
   DenyPairingConfirmationRequest;
   ConnectedDevicePropertiesRequest;
   PairedDevicePropertiesRequest;
   ConnectRequest;
   DisconnectRequest;
+  IsConnectedRequest;
   SendFileRequest;
   StopSendingFileRequest;
   ConfirmReceivingFileRequest;
   DenyReceivingFileRequest;
   ConnectScoRequest;
   DisconnectScoRequest;
   IsScoConnectedRequest;
   AnswerWaitingCallRequest;
--- a/dom/browser-element/BrowserElementParent.jsm
+++ b/dom/browser-element/BrowserElementParent.jsm
@@ -163,21 +163,24 @@ function BrowserElementParent(frameLoade
   if (!this._window._browserElementParents) {
     this._window._browserElementParents = new WeakMap();
     this._window.addEventListener('visibilitychange',
                                   visibilityChangeHandler,
                                   /* useCapture = */ false,
                                   /* wantsUntrusted = */ false);
   }
 
+  this._doCommandHandlerBinder = this._doCommandHandler.bind(this);
   this._frameElement.addEventListener('mozdocommand',
-                                      this._doCommandHandler.bind(this),
+                                      this._doCommandHandlerBinder,
                                       /* useCapture = */ false,
                                       /* wantsUntrusted = */ false);
 
+  Services.obs.addObserver(this, 'ipc:browser-destroyed', /* ownsWeak = */ true);
+
   this._window._browserElementParents.set(this, null);
 
   // Insert ourself into the prompt service.
   BrowserElementPromptService.mapFrameToBrowserElementParent(this._frameElement, this);
   if (!isPendingFrame) {
     this._setupMessageListener();
     this._registerAppManifest();
   } else {
@@ -914,14 +917,21 @@ BrowserElementParent.prototype = {
     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 'ipc:browser-destroyed':
+      if (this._isAlive() && subject == this._frameLoader) {
+        Services.obs.removeObserver(this, 'ipc:browser-destroyed');
+        this._frameElement.removeEventListener('mozdocommand',
+                                               this._doCommandHandlerBinder)
+      }
+      break;
     default:
       debug('Unknown topic: ' + topic);
       break;
     };
   },
 };
--- a/dom/datastore/DataStoreImpl.js
+++ b/dom/datastore/DataStoreImpl.js
@@ -167,17 +167,17 @@ DataStore.prototype = {
       aCallback();
     }
   },
 
   getInternal: function(aStore, aIds, aCallback) {
     debug("GetInternal: " + aIds.toSource());
 
     // Creation of the results array.
-    let results = new Array(aIds.length);
+    let results = new this._window.Array(aIds.length);
 
     // We're going to create this amount of requests.
     let pendingIds = aIds.length;
     let indexPos = 0;
 
     let self = this;
 
     function getInternalSuccess(aEvent, aPos) {
@@ -414,16 +414,20 @@ DataStore.prototype = {
   get: function() {
     let ids = Array.prototype.slice.call(arguments);
     for (let i = 0; i < ids.length; ++i) {
       if (!validateId(ids[i])) {
         return throwInvalidArg(this._window);
       }
     }
 
+    if (ids.length == 0) {
+      return this._window.Promise.resolve(new this._window.Array());
+    }
+
     let self = this;
 
     // Promise<Object>
     return this.newDBPromise("readonly",
       function(aResolve, aReject, aTxn, aStore, aRevisionStore) {
                self.getInternal(aStore, ids,
                                 function(aResults) {
           aResolve(ids.length > 1 ? aResults : aResults[0]);
new file mode 100644
--- /dev/null
+++ b/dom/datastore/tests/file_bug1058108.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for DataStore - basic operation on a readonly db</title>
+  <script type="text/javascript" src="file_basic_common.js"></script>
+</head>
+<body>
+<div id="container"></div>
+  <script type="application/javascript;version=1.7">
+
+function is(a, b, msg) {
+  ok(a === b, msg);
+}
+
+function ok(a, msg) {
+  alert((a ? 'OK' : 'KO') + ' ' + msg)
+}
+
+function finish() {
+  alert('DONE');
+}
+
+navigator.getDataStores('foo').then(function(stores) {
+  is(stores.length, 1, "getDataStores('foo') returns 1 element");
+  is(stores[0].name, 'foo', 'The dataStore.name is foo');
+  is(stores[0].readOnly, false, 'The dataStore foo is not in readonly');
+
+  var store = stores[0];
+  store.get.apply(store, []).then(function(a) {
+    ok(Array.isArray(a), "bug 1058108");
+    is(a.length, 0, "bug 1058108");
+    finish();
+  });
+});
+
+  </script>
+</body>
+</html>
+
--- a/dom/datastore/tests/mochitest.ini
+++ b/dom/datastore/tests/mochitest.ini
@@ -18,16 +18,17 @@ support-files =
   file_bug924104.html
   file_certifiedApp.html
   file_keys.html
   file_duplicate.html
   file_bug976311.html
   file_bug976311.template.webapp
   file_bug986056.html
   file_bug986056.template.webapp
+  file_bug1058108.html
   file_event_maker.html
   file_event_receiver.html
   file_transactions.html
   file_basic_common.js
   file_sync_common.js
   file_bug1008044.html
   file_bug957086.html
   file_notify_system_message.html
@@ -46,10 +47,11 @@ support-files =
 [test_keys.html]
 [test_duplicate.html]
 [test_bug976311.html]
 [test_bug986056.html]
 [test_oop_events.html]
 [test_transactions.html]
 [test_bug1008044.html]
 [test_bug957086.html]
+[test_bug1058108.html]
 [test_notify_system_message.html]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || toolkit == 'win' #bug 1053662 - Timeout prone
copy from dom/datastore/tests/test_basic.html
copy to dom/datastore/tests/test_bug1058108.html
--- a/dom/datastore/tests/test_basic.html
+++ b/dom/datastore/tests/test_bug1058108.html
@@ -1,21 +1,21 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <meta charset="utf-8">
-  <title>Test for DataStore - basic operation on a readonly db</title>
+  <title>Test for DataStore - bug 1058108</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.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 gHostedManifestURL = 'http://test/tests/dom/datastore/tests/file_app.sjs?testToken=file_basic.html';
+  var gHostedManifestURL = 'http://test/tests/dom/datastore/tests/file_app.sjs?testToken=file_bug1058108.html';
   var gApp;
 
   function cbError() {
     ok(false, "Error callback invoked");
     finish();
   }
 
   function installApp() {
--- a/dom/events/PaintRequest.cpp
+++ b/dom/events/PaintRequest.cpp
@@ -14,17 +14,17 @@ namespace dom {
 
 /******************************************************************************
  * mozilla::dom::PaintRequest
  *****************************************************************************/
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PaintRequest, mParent)
 
 NS_INTERFACE_TABLE_HEAD(PaintRequest)
-  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
   NS_INTERFACE_TABLE(PaintRequest, nsIDOMPaintRequest)
   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(PaintRequest)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(PaintRequest)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(PaintRequest)
 
 /* virtual */ JSObject*
--- a/dom/interfaces/base/nsIServiceWorkerManager.idl
+++ b/dom/interfaces/base/nsIServiceWorkerManager.idl
@@ -3,17 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "domstubs.idl"
 
 interface nsIDocument;
 interface nsIURI;
 
-[uuid(c7132f91-c46c-4e01-b75a-43babb254d93)]
+[uuid(91b9d3fc-1654-44da-b438-15123cdbe7aa)]
 interface nsIServiceWorkerManager : nsISupports
 {
   /**
    * Registers a ServiceWorker with script loaded from `aScriptURI` to act as
    * the ServiceWorker for aScope.  Requires a valid entry settings object on
    * the stack. This means you must call this from content code 'within'
    * a window.
    *
@@ -31,16 +31,22 @@ interface nsIServiceWorkerManager : nsIS
   nsISupports unregister(in DOMString aScope);
 
   // Returns a Promise
   nsISupports getRegistrations(in nsIDOMWindow aWindow);
 
   // Returns a Promise
   nsISupports getRegistration(in nsIDOMWindow aWindow, in DOMString aScope);
 
+  // Returns a Promise
+  nsISupports getReadyPromise(in nsIDOMWindow aWindow);
+
+  // Remove ready pending Promise
+  void removeReadyPromise(in nsIDOMWindow aWindow);
+
   // aTarget MUST be a ServiceWorkerRegistration.
   [noscript] void AddRegistrationEventListener(in nsIURI aPageURI, in nsIDOMEventTarget aTarget);
   [noscript] void RemoveRegistrationEventListener(in nsIURI aPageURI, in nsIDOMEventTarget aTarget);
 
   /**
    * Call this to request that document `aDoc` be controlled by a ServiceWorker
    * if a registration exists for it's scope.
    *
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -848,24 +848,16 @@ ContentParent::PreallocatedProcessReady(
 {
 #ifdef MOZ_NUWA_PROCESS
     return PreallocatedProcessManager::PreallocatedProcessReady();
 #else
     return true;
 #endif
 }
 
-void
-ContentParent::RunAfterPreallocatedProcessReady(nsIRunnable* aRequest)
-{
-#ifdef MOZ_NUWA_PROCESS
-    PreallocatedProcessManager::RunAfterPreallocatedProcessReady(aRequest);
-#endif
-}
-
 typedef std::map<ContentParent*, std::set<ContentParent*> > GrandchildMap;
 static GrandchildMap sGrandchildProcessMap;
 
 std::map<uint64_t, ContentParent*> sContentParentMap;
 
 bool
 ContentParent::RecvCreateChildProcess(const IPCTabContext& aContext,
                                       const hal::ProcessPriority& aPriority,
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -95,17 +95,16 @@ public:
      * Ensure that all subprocesses are terminated and their OS
      * resources have been reaped.  This is synchronous and can be
      * very expensive in general.  It also bypasses the normal
      * shutdown process.
      */
     static void JoinAllSubprocesses();
 
     static bool PreallocatedProcessReady();
-    static void RunAfterPreallocatedProcessReady(nsIRunnable* aRequest);
 
     /**
      * Get or create a content process for:
      * 1. browser iframe
      * 2. remote xul <browser>
      * 3. normal iframe
      */
     static already_AddRefed<ContentParent>
--- a/dom/ipc/PreallocatedProcessManager.cpp
+++ b/dom/ipc/PreallocatedProcessManager.cpp
@@ -53,30 +53,27 @@ public:
   void ScheduleDelayedNuwaFork();
   void DelayedNuwaFork();
   void PublishSpareProcess(ContentParent* aContent);
   void MaybeForgetSpare(ContentParent* aContent);
   bool IsNuwaReady();
   void OnNuwaReady();
   bool PreallocatedProcessReady();
   already_AddRefed<ContentParent> GetSpareProcess();
-  void RunAfterPreallocatedProcessReady(nsIRunnable* aRunnable);
 
 private:
   void NuwaFork();
 
   // initialization off the critical path of app startup.
   CancelableTask* mPreallocateAppProcessTask;
 
   // The array containing the preallocated processes. 4 as the inline storage size
   // should be enough so we don't need to grow the nsAutoTArray.
   nsAutoTArray<nsRefPtr<ContentParent>, 4> mSpareProcesses;
 
-  nsTArray<nsCOMPtr<nsIRunnable> > mDelayedContentParentRequests;
-
   // Nuwa process is ready for creating new process.
   bool mIsNuwaReady;
 #endif
 
 private:
   static mozilla::StaticRefPtr<PreallocatedProcessManagerImpl> sSingleton;
 
   PreallocatedProcessManagerImpl();
@@ -220,26 +217,16 @@ PreallocatedProcessManagerImpl::Allocate
   }
 
   mPreallocatedAppProcess = ContentParent::PreallocateAppProcess();
 }
 
 #ifdef MOZ_NUWA_PROCESS
 
 void
-PreallocatedProcessManagerImpl::RunAfterPreallocatedProcessReady(nsIRunnable* aRequest)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  mDelayedContentParentRequests.AppendElement(aRequest);
-
-  // This is an urgent NuwaFork() request. Request to fork at once.
-  DelayedNuwaFork();
-}
-
-void
 PreallocatedProcessManagerImpl::ScheduleDelayedNuwaFork()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mPreallocateAppProcessTask) {
     // Make sure there is only one request running.
     return;
   }
@@ -306,36 +293,23 @@ PreallocatedProcessManagerImpl::PublishS
     nsCOMPtr<nsIMessageBroadcaster> ppmm =
       do_GetService("@mozilla.org/parentprocessmessagemanager;1");
     nsresult rv = ppmm->BroadcastAsyncMessage(
       NS_LITERAL_STRING("TEST-ONLY:nuwa-add-new-process"),
       JS::NullHandleValue, JS::NullHandleValue, cx, 1);
   }
 
   mSpareProcesses.AppendElement(aContent);
-
-  if (!mDelayedContentParentRequests.IsEmpty()) {
-    nsCOMPtr<nsIRunnable> runnable = mDelayedContentParentRequests[0];
-    mDelayedContentParentRequests.RemoveElementAt(0);
-    NS_DispatchToMainThread(runnable);
-  }
 }
 
 void
 PreallocatedProcessManagerImpl::MaybeForgetSpare(ContentParent* aContent)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  if (!mDelayedContentParentRequests.IsEmpty()) {
-    if (!mPreallocateAppProcessTask) {
-      // This NuwaFork request is urgent. Don't delay it.
-      DelayedNuwaFork();
-    }
-  }
-
   if (mSpareProcesses.RemoveElement(aContent)) {
     return;
   }
 
   if (aContent == mPreallocatedAppProcess) {
     mPreallocatedAppProcess = nullptr;
     mIsNuwaReady = false;
     while (mSpareProcesses.Length() > 0) {
@@ -502,17 +476,11 @@ PreallocatedProcessManager::IsNuwaReady(
 }
 
 /*static */ bool
 PreallocatedProcessManager::PreallocatedProcessReady()
 {
   return GetPPMImpl()->PreallocatedProcessReady();
 }
 
-/* static */ void
-PreallocatedProcessManager::RunAfterPreallocatedProcessReady(nsIRunnable* aRequest)
-{
-  GetPPMImpl()->RunAfterPreallocatedProcessReady(aRequest);
-}
-
 #endif
 
 } // namespace mozilla
--- a/dom/ipc/PreallocatedProcessManager.h
+++ b/dom/ipc/PreallocatedProcessManager.h
@@ -81,17 +81,16 @@ public:
   static already_AddRefed<ContentParent> Take();
 
 #ifdef MOZ_NUWA_PROCESS
   static void PublishSpareProcess(ContentParent* aContent);
   static void MaybeForgetSpare(ContentParent* aContent);
   static bool IsNuwaReady();
   static void OnNuwaReady();
   static bool PreallocatedProcessReady();
-  static void RunAfterPreallocatedProcessReady(nsIRunnable* aRunnable);
 #endif
 
 private:
   PreallocatedProcessManager();
   DISALLOW_EVIL_CONSTRUCTORS(PreallocatedProcessManager);
 };
 
 } // namespace mozilla
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -298,16 +298,19 @@ function RTCPeerConnection() {
   this._closed = false;
 
   this._onCreateOfferSuccess = null;
   this._onCreateOfferFailure = null;
   this._onCreateAnswerSuccess = null;
   this._onCreateAnswerFailure = null;
   this._onGetStatsSuccess = null;
   this._onGetStatsFailure = null;
+  this._onReplaceTrackSender = null;
+  this._onReplaceTrackSuccess = null;
+  this._onReplaceTrackFailure = null;
 
   this._pendingType = null;
   this._localType = null;
   this._remoteType = null;
   this._trickleIce = false;
   this._peerIdentity = null;
 
   /**
@@ -807,26 +810,45 @@ RTCPeerConnection.prototype = {
       throw new this._win.DOMError("", "invalid stream.");
     }
     if (stream.getTracks().indexOf(track) == -1) {
       throw new this._win.DOMError("", "track is not in stream.");
     }
     this._checkClosed();
     this._impl.addTrack(track, stream);
     let sender = this._win.RTCRtpSender._create(this._win,
-                                                new RTCRtpSender(this, track));
+                                                new RTCRtpSender(this, track,
+                                                                 stream));
     this._senders.push({ sender: sender, stream: stream });
     return sender;
   },
 
   removeTrack: function(sender) {
      // Bug 844295: Not implementing this functionality.
      throw new this._win.DOMError("", "removeTrack not yet implemented");
   },
 
+  _replaceTrack: function(sender, withTrack, onSuccess, onError) {
+    // TODO: Do a (sender._stream.getTracks().indexOf(track) == -1) check
+    //       on both track args someday.
+    //
+    // The proposed API will be that both tracks must already be in the same
+    // stream. However, since our MediaStreams currently are limited to one
+    // track per type, we allow replacement with an outside track not already
+    // in the same stream.
+    //
+    // Since a track may be replaced more than once, the track being replaced
+    // may not be in the stream either, so we check neither arg right now.
+
+    this._onReplaceTrackSender = sender;
+    this._onReplaceTrackSuccess = onSuccess;
+    this._onReplaceTrackFailure = onError;
+    this._impl.replaceTrack(sender.track, withTrack, sender._stream);
+  },
+
   close: function() {
     if (this._closed) {
       return;
     }
     this.changeIceConnectionState("closed");
     this._queueOrRun({ func: this._close, args: [false], wait: false });
     this._closed = true;
   },
@@ -1301,16 +1323,25 @@ PeerConnectionObserver.prototype = {
     this._dompc.dispatchEvent(ev);
   },
 
   onRemoveTrack: function(track, type) {
     this.dispatchEvent(new this._dompc._win.MediaStreamTrackEvent("removetrack",
                                                                   { track: track }));
   },
 
+  onReplaceTrackSuccess: function() {
+    this._dompc.callCB(this._dompc._onReplaceTrackSuccess);
+  },
+
+  onReplaceTrackError: function(code, message) {
+    this._dompc.callCB(this._dompc._onReplaceTrackError,
+                       new RTCError(code, message));
+  },
+
   foundIceCandidate: function(cand) {
     this.dispatchEvent(new this._dompc._win.RTCPeerConnectionIceEvent("icecandidate",
                                                                       { candidate: cand } ));
   },
 
   notifyDataChannel: function(channel) {
     this.dispatchEvent(new this._dompc._win.RTCDataChannelEvent("datachannel",
                                                                 { channel: channel }));
@@ -1332,25 +1363,35 @@ RTCPeerConnectionStatic.prototype = {
       .getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
   },
 
   registerPeerConnectionLifecycleCallback: function(cb) {
     _globalPCList._registerPeerConnectionLifecycleCallback(this._winID, cb);
   },
 };
 
-function RTCRtpSender(pc, track) {
-  this.pc = pc;
+function RTCRtpSender(pc, track, stream) {
+  this._pc = pc;
   this.track = track;
+  this._stream = stream;
 }
 RTCRtpSender.prototype = {
   classDescription: "RTCRtpSender",
   classID: PC_SENDER_CID,
   contractID: PC_SENDER_CONTRACT,
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
+
+  replaceTrack: function(withTrack, onSuccess, onError) {
+    this._pc._checkClosed();
+    this._pc._queueOrRun({
+      func: this._pc._replaceTrack,
+      args: [this, withTrack, onSuccess, onError],
+      wait: false
+    });
+  }
 };
 
 function RTCRtpReceiver(pc, track) {
   this.pc = pc;
   this.track = track;
 }
 RTCRtpReceiver.prototype = {
   classDescription: "RTCRtpReceiver",
--- a/dom/media/gmp-plugin/gmp-fake.cpp
+++ b/dom/media/gmp-plugin/gmp-fake.cpp
@@ -165,20 +165,22 @@ class FakeVideoEncoder : public GMPVideo
     GMPErr err = host_->CreateFrame (kGMPEncodedVideoFrame, &ftmp);
     if (err != GMPNoErr) {
       GMPLOG (GL_ERROR, "Error creating encoded frame");
       return;
     }
 
     GMPVideoEncodedFrame* f = static_cast<GMPVideoEncodedFrame*> (ftmp);
 
+    // Encode this in a frame that looks a little bit like H.264.
+    // Note that we don't do PPS or SPS.
     // Copy the data. This really should convert this to network byte order.
     EncodedFrame eframe;
     eframe.length_ = sizeof(eframe) - sizeof(uint32_t);
-    eframe.h264_compat_ = 'g';
+    eframe.h264_compat_ = 5; // Emulate a H.264 IDR NAL.
     eframe.magic_ = ENCODED_FRAME_MAGIC;
     eframe.width_ = inputImage->Width();
     eframe.height_ = inputImage->Height();
     eframe.y_ = AveragePlane(inputImage->Buffer(kGMPYPlane),
                              inputImage->AllocatedSize(kGMPYPlane));
     eframe.u_ = AveragePlane(inputImage->Buffer(kGMPUPlane),
                              inputImage->AllocatedSize(kGMPUPlane));
     eframe.v_ = AveragePlane(inputImage->Buffer(kGMPVPlane),
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -82,16 +82,18 @@ skip-if = buildapp == 'b2g' || os == 'an
 [test_peerConnection_close.html]
 [test_peerConnection_errorCallbacks.html]
 [test_peerConnection_offerRequiresReceiveAudio.html]
 skip-if = toolkit == 'gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_offerRequiresReceiveVideo.html]
 skip-if = toolkit == 'gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_offerRequiresReceiveVideoAudio.html]
 skip-if = toolkit == 'gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
+[test_peerConnection_replaceTrack.html]
+skip-if = toolkit == 'gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_setLocalAnswerInHaveLocalOffer.html]
 [test_peerConnection_setLocalAnswerInStable.html]
 [test_peerConnection_setLocalOfferInHaveRemoteOffer.html]
 [test_peerConnection_setRemoteAnswerInHaveRemoteOffer.html]
 [test_peerConnection_setRemoteAnswerInStable.html]
 [test_peerConnection_setRemoteOfferInHaveLocalOffer.html]
 [test_peerConnection_throwInCallbacks.html]
 skip-if = toolkit == 'gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
new file mode 100644
--- /dev/null
+++ b/dom/media/tests/mochitest/test_peerConnection_replaceTrack.html
@@ -0,0 +1,64 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="head.js"></script>
+  <script type="application/javascript" src="mediaStreamPlayback.js"></script>
+  <script type="application/javascript" src="pc.js"></script>
+  <script type="application/javascript" src="templates.js"></script>
+  <script type="application/javascript" src="turnConfig.js"></script>
+</head>
+<body>
+<pre id="test">
+<script type="application/javascript;version=1.8">
+  createHTML({
+    bug: "1032839",
+    title: "Replace video track",
+    visible: true
+  });
+
+  function isSenderOfTrack(sender) {
+    return sender.track == this;
+  }
+
+  // Test basically just verifies that success callback is called at this point
+
+  var test;
+  runNetworkTest(function () {
+    test = new PeerConnectionTest();
+    test.setMediaConstraints([{video: true}], [{video: true}]);
+    test.chain.removeAfter("PC_REMOTE_CHECK_MEDIA_FLOW_PRESENT");
+    var flowtest = test.chain.remove("PC_REMOTE_CHECK_MEDIA_FLOW_PRESENT");
+    test.chain.append(flowtest);
+    test.chain.append([["PC_LOCAL_REPLACE_VIDEOTRACK",
+      function (test) {
+        var stream = test.pcLocal._pc.getLocalStreams()[0];
+        var track = stream.getVideoTracks()[0];
+        var sender = test.pcLocal._pc.getSenders().find(isSenderOfTrack, track);
+        ok(sender, "track has a sender");
+        navigator.mozGetUserMedia({video:true, fake: true}, function(newStream) {
+          sender.replaceTrack(newStream.getVideoTracks()[0],
+            function() {
+              ok(true, "replaceTrack success callback is called");
+              test.next();
+            },
+            function(err) {
+              ok(false, "replaceTrack failed with error = " + err);
+              test.next();
+            });
+        },
+        function(err) {
+          ok(false, "mozGetUserMedia failed. error = " + err);
+          test.next();
+        });
+      }
+    ]]);
+    test.chain.append(flowtest);
+
+    test.run();
+  });
+</script>
+</pre>
+</body>
+</html>
--- a/dom/network/interfaces/nsIUDPSocketChild.idl
+++ b/dom/network/interfaces/nsIUDPSocketChild.idl
@@ -1,58 +1,67 @@
 /* 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"
 #include "nsINetAddr.idl"
 
 interface nsIUDPSocketInternal;
+interface nsIInputStream;
 
 %{ C++
 namespace mozilla {
 namespace net {
 union NetAddr;
 }
 }
 %}
 native NetAddr(mozilla::net::NetAddr);
 [ptr] native NetAddrPtr(mozilla::net::NetAddr);
 
-[scriptable, uuid(B47E5A0F-D384-48EF-8885-4259793D9CF0)]
+[scriptable, uuid(5bb7de5a-8766-4c13-b9ed-14e63168dabf)]
 interface nsIUDPSocketChild : nsISupports
 {
   readonly attribute unsigned short localPort;
   readonly attribute AUTF8String localAddress;
   attribute AUTF8String filterName;
 
   // Tell the chrome process to bind the UDP socket to a given local host and port
-  void bind(in nsIUDPSocketInternal socket, in AUTF8String host, in unsigned short port);
+  void bind(in nsIUDPSocketInternal socket, in AUTF8String host, in unsigned short port,
+            in bool addressReuse, in bool loopback);
 
   // Tell the chrome process to perform equivalent operations to all following methods
   void send(in AUTF8String host, in unsigned short port,
             [const, array, size_is(byteLength)] in uint8_t bytes,
             in unsigned long byteLength);
   // Send without DNS query
   void sendWithAddr(in nsINetAddr addr,
                     [const, array, size_is(byteLength)] in uint8_t bytes,
                     in unsigned long byteLength);
   [noscript] void sendWithAddress([const] in NetAddrPtr addr,
                                   [const, array, size_is(byteLength)] in uint8_t bytes,
                                   in unsigned long byteLength);
+  // Send input stream. This must be a buffered stream implementation.
+  void sendBinaryStream(in AUTF8String host, in unsigned short port, in nsIInputStream stream);
+
   void close();
+  void joinMulticast(in AUTF8String multicastAddress, in AUTF8String iface);
+  void leaveMulticast(in AUTF8String multicastAddress, in AUTF8String iface);
 };
 
 /*
  * Internal interface for callback from chrome process
  */
-[scriptable, uuid(1E27E9B3-C1C8-4B05-A415-1A2C1A641C60)]
+[scriptable, uuid(44cd9ad5-d574-4169-baf9-e1af0648a143)]
 interface nsIUDPSocketInternal : nsISupports
 {
-  void callListenerError(in AUTF8String type, in AUTF8String message, in AUTF8String filename,
-                         in uint32_t lineNumber, in uint32_t columnNumber);
-  void callListenerReceivedData(in AUTF8String type, in AUTF8String host, in unsigned short port,
-                                [array, size_is(dataLength)] in uint8_t data,
+  // callback while socket is opened. localPort and localAddress is ready until this time.
+  void callListenerOpened();
+  // callback while socket is closed.
+  void callListenerClosed();
+  // callback while incoming packet is received.
+  void callListenerReceivedData(in AUTF8String host, in unsigned short port,
+                                [const, array, size_is(dataLength)] in uint8_t data,
                                 in unsigned long dataLength);
-  void callListenerVoid(in AUTF8String type);
-  void callListenerSent(in AUTF8String type, in nsresult status);
-  void updateReadyState(in AUTF8String readyState);
+  // callback while any error happened.
+  void callListenerError(in AUTF8String message, in AUTF8String filename, in uint32_t lineNumber);
 };
--- a/dom/network/src/PUDPSocket.ipdl
+++ b/dom/network/src/PUDPSocket.ipdl
@@ -1,69 +1,65 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
 
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PNecko;
+include protocol PBlob;
+include InputStreamParams;
 
 include "mozilla/net/NeckoMessageUtils.h";
 include "mozilla/net/DNS.h";
 include "prio.h";
 
 using mozilla::net::NetAddr from "mozilla/net/DNS.h";
 using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
 
-struct UDPError {
-  nsCString message;
-  nsCString filename;
-  uint32_t lineNumber;
-  uint32_t columnNumber;
-};
-
-struct UDPMessage {
-  nsCString fromAddr;
-  uint16_t port;
-  uint8_t[] data;
-};
-
 struct UDPAddressInfo {
-  nsCString local;
+  nsCString addr;
   uint16_t port;
 };
 
-struct UDPSendResult {
-  nsresult value;
+union UDPSocketAddr {
+  UDPAddressInfo;
+  NetAddr;
 };
 
-union UDPCallbackData {
-  void_t;
-  UDPMessage;
-  UDPAddressInfo;
-  UDPSendResult;
-  UDPError;
+union UDPData {
+  uint8_t[];
+  InputStreamParams;
 };
 
 namespace mozilla {
 namespace net {
 
 //-------------------------------------------------------------------
 protocol PUDPSocket
 {
   manager PNecko;
 
 parent:
-  Data(uint8_t[] data, nsCString remoteAddress, uint16_t port);
-  DataWithAddress(uint8_t[] data, NetAddr addr);
+  Bind(UDPAddressInfo addressInfo, bool addressReuse, bool loopback);
+
+  OutgoingData(UDPData data, UDPSocketAddr addr);
+
+  JoinMulticast(nsCString multicastAddress, nsCString iface);
+  LeaveMulticast(nsCString multicastAddress, nsCString iface);
+
   Close();
+
   RequestDelete();
 
 child:
-  Callback(nsCString type, UDPCallbackData data, nsCString aState);
+  CallbackOpened(UDPAddressInfo addressInfo);
+  CallbackClosed();
+  CallbackReceivedData(UDPAddressInfo addressInfo, uint8_t[] data);
+  CallbackError(nsCString message, nsCString filename, uint32_t lineNumber);
   __delete__();
 };
 
 
 } // namespace net
 } // namespace mozilla
 
new file mode 100644
--- /dev/null
+++ b/dom/network/src/UDPSocket.cpp
@@ -0,0 +1,705 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "UDPSocket.h"
+#include "mozilla/AsyncEventDispatcher.h"
+#include "mozilla/dom/ErrorEvent.h"
+#include "mozilla/dom/UDPMessageEvent.h"
+#include "mozilla/dom/UDPSocketBinding.h"
+#include "mozilla/dom/UnionTypes.h"
+#include "mozilla/net/DNS.h"
+#include "nsComponentManagerUtils.h"
+#include "nsContentUtils.h"
+#include "nsIDOMFile.h"
+#include "nsINetAddr.h"
+#include "nsStringStream.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(UDPSocket)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(UDPSocket, DOMEventTargetHelper)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOpened)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mClosed)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(UDPSocket, DOMEventTargetHelper)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mOpened)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mClosed)
+  tmp->CloseWithReason(NS_OK);
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_ADDREF_INHERITED(UDPSocket, DOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(UDPSocket, DOMEventTargetHelper)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(UDPSocket)
+  NS_INTERFACE_MAP_ENTRY(nsIUDPSocketListener)
+  NS_INTERFACE_MAP_ENTRY(nsIUDPSocketInternal)
+NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
+
+/* static */ already_AddRefed<UDPSocket>
+UDPSocket::Constructor(const GlobalObject& aGlobal,
+                       const UDPOptions& aOptions,
+                       ErrorResult& aRv)
+{
+  nsCOMPtr<nsPIDOMWindow> ownerWindow = do_QueryInterface(aGlobal.GetAsSupports());
+  if (!ownerWindow) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  bool addressReuse = aOptions.mAddressReuse;
+  bool loopback = aOptions.mLoopback;
+
+  nsCString remoteAddress;
+  if (aOptions.mRemoteAddress.WasPassed()) {
+    remoteAddress = NS_ConvertUTF16toUTF8(aOptions.mRemoteAddress.Value());
+  } else {
+    remoteAddress.SetIsVoid(true);
+  }
+
+  Nullable<uint16_t> remotePort;
+  if (aOptions.mRemotePort.WasPassed()) {
+    remotePort.SetValue(aOptions.mRemotePort.Value());
+
+    if (remotePort.Value() == 0) {
+      aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
+      return nullptr;
+    }
+  }
+
+  nsString localAddress;
+  if (aOptions.mLocalAddress.WasPassed()) {
+    localAddress = aOptions.mLocalAddress.Value();
+
+    // check if localAddress is a valid IPv4/6 address
+    NS_ConvertUTF16toUTF8 address(localAddress);
+    PRNetAddr prAddr;
+    PRStatus status = PR_StringToNetAddr(address.BeginReading(), &prAddr);
+    if (status != PR_SUCCESS) {
+      aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
+      return nullptr;
+    }
+  } else {
+    SetDOMStringToNull(localAddress);
+  }
+
+  Nullable<uint16_t> localPort;
+  if (aOptions.mLocalPort.WasPassed()) {
+    localPort.SetValue(aOptions.mLocalPort.Value());
+
+    if (localPort.Value() == 0) {
+      aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
+      return nullptr;
+    }
+  }
+
+  nsRefPtr<UDPSocket> socket = new UDPSocket(ownerWindow, remoteAddress, remotePort);
+  aRv = socket->Init(localAddress, localPort, addressReuse, loopback);
+
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+
+  return socket.forget();
+}
+
+UDPSocket::UDPSocket(nsPIDOMWindow* aOwner,
+                     const nsCString& aRemoteAddress,
+                     const Nullable<uint16_t>& aRemotePort)
+  : DOMEventTargetHelper(aOwner)
+  , mRemoteAddress(aRemoteAddress)
+  , mRemotePort(aRemotePort)
+  , mReadyState(SocketReadyState::Opening)
+{
+  MOZ_ASSERT(aOwner);
+  MOZ_ASSERT(aOwner->IsInnerWindow());
+
+  nsIDocument* aDoc = aOwner->GetExtantDoc();
+  if (aDoc) {
+    aDoc->DisallowBFCaching();
+  }
+}
+
+UDPSocket::~UDPSocket()
+{
+  CloseWithReason(NS_OK);
+}
+
+JSObject*
+UDPSocket::WrapObject(JSContext* aCx)
+{
+  return UDPSocketBinding::Wrap(aCx, this);
+}
+
+void
+UDPSocket::DisconnectFromOwner()
+{
+  DOMEventTargetHelper::DisconnectFromOwner();
+  CloseWithReason(NS_OK);
+}
+
+already_AddRefed<Promise>
+UDPSocket::Close()
+{
+  MOZ_ASSERT(mClosed);
+
+  nsRefPtr<Promise> promise = mClosed;
+
+  if (mReadyState == SocketReadyState::Closed) {
+    return promise.forget();
+  }
+
+  CloseWithReason(NS_OK);
+  return promise.forget();
+}
+
+void
+UDPSocket::CloseWithReason(nsresult aReason)
+{
+  if (mReadyState == SocketReadyState::Closed) {
+    return;
+  }
+
+  if (mOpened) {
+    if (mReadyState == SocketReadyState::Opening) {
+      // reject openedPromise with AbortError if socket is closed without error
+      nsresult openFailedReason = NS_FAILED(aReason) ? aReason : NS_ERROR_DOM_ABORT_ERR;
+      mOpened->MaybeReject(openFailedReason);
+    }
+  }
+
+  mReadyState = SocketReadyState::Closed;
+
+  if (mSocket) {
+    mSocket->Close();
+    mSocket = nullptr;
+  }
+
+  if (mSocketChild) {
+    mSocketChild->Close();
+    mSocketChild = nullptr;
+  }
+
+  if (mClosed) {
+    if (NS_SUCCEEDED(aReason)) {
+      mClosed->MaybeResolve(JS::UndefinedHandleValue);
+    } else {
+      mClosed->MaybeReject(aReason);
+    }
+  }
+
+  mPendingMcastCommands.Clear();
+}
+
+void
+UDPSocket::JoinMulticastGroup(const nsAString& aMulticastGroupAddress,
+                              ErrorResult& aRv)
+{
+  if (mReadyState == SocketReadyState::Closed) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return;
+  }
+
+  if (mReadyState == SocketReadyState::Opening) {
+    MulticastCommand joinCommand(MulticastCommand::Join, aMulticastGroupAddress);
+    mPendingMcastCommands.AppendElement(joinCommand);
+    return;
+  }
+
+  MOZ_ASSERT(mSocket || mSocketChild);
+
+  NS_ConvertUTF16toUTF8 address(aMulticastGroupAddress);
+
+  if (mSocket) {
+    MOZ_ASSERT(!mSocketChild);
+
+    aRv = mSocket->JoinMulticast(address, EmptyCString());
+    NS_WARN_IF(aRv.Failed());
+
+    return;
+  }
+
+  MOZ_ASSERT(mSocketChild);
+
+  aRv = mSocketChild->JoinMulticast(address, EmptyCString());
+  NS_WARN_IF(aRv.Failed());
+}
+
+void
+UDPSocket::LeaveMulticastGroup(const nsAString& aMulticastGroupAddress,
+                               ErrorResult& aRv)
+{
+  if (mReadyState == SocketReadyState::Closed) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return;
+  }
+
+  if (mReadyState == SocketReadyState::Opening) {
+    MulticastCommand leaveCommand(MulticastCommand::Leave, aMulticastGroupAddress);
+    mPendingMcastCommands.AppendElement(leaveCommand);
+    return;
+  }
+
+  MOZ_ASSERT(mSocket || mSocketChild);
+
+  nsCString address = NS_ConvertUTF16toUTF8(aMulticastGroupAddress);
+  if (mSocket) {
+    MOZ_ASSERT(!mSocketChild);
+
+    aRv = mSocket->LeaveMulticast(address, EmptyCString());
+    NS_WARN_IF(aRv.Failed());
+    return;
+  }
+
+  MOZ_ASSERT(mSocketChild);
+
+  aRv = mSocketChild->LeaveMulticast(address, EmptyCString());
+  NS_WARN_IF(aRv.Failed());
+}
+
+nsresult
+UDPSocket::DoPendingMcastCommand()
+{
+  MOZ_ASSERT(mReadyState == SocketReadyState::Open, "Multicast command can only be executed after socket opened");
+
+  for (uint32_t i = 0; i < mPendingMcastCommands.Length(); ++i) {
+    MulticastCommand& command = mPendingMcastCommands[i];
+    ErrorResult rv;
+
+    switch (command.mCommand) {
+      case MulticastCommand::Join: {
+        JoinMulticastGroup(command.mAddress, rv);
+        break;
+      }
+      case MulticastCommand::Leave: {
+        LeaveMulticastGroup(command.mAddress, rv);
+        break;
+      }
+    }
+
+    if (NS_WARN_IF(rv.Failed())) {
+      return rv.ErrorCode();
+    }
+  }
+
+  mPendingMcastCommands.Clear();
+  return NS_OK;
+}
+
+bool
+UDPSocket::Send(const StringOrBlobOrArrayBufferOrArrayBufferView& aData,
+                const Optional<nsAString>& aRemoteAddress,
+                const Optional<Nullable<uint16_t>>& aRemotePort,
+                ErrorResult& aRv)
+{
+  if (mReadyState != SocketReadyState::Open) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return false;
+  }
+
+  MOZ_ASSERT(mSocket || mSocketChild);
+
+  // If the remote address and port were not specified in the constructor or as arguments,
+  // throw InvalidAccessError.
+  nsCString remoteAddress;
+  if (aRemoteAddress.WasPassed()) {
+    remoteAddress = NS_ConvertUTF16toUTF8(aRemoteAddress.Value());
+  } else if (!mRemoteAddress.IsVoid()) {
+    remoteAddress = mRemoteAddress;
+  } else {
+    aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
+    return false;
+  }
+
+  uint16_t remotePort;
+  if (aRemotePort.WasPassed() && !aRemotePort.Value().IsNull()) {
+    remotePort = aRemotePort.Value().Value();
+  } else if (!mRemotePort.IsNull()) {
+    remotePort = mRemotePort.Value();
+  } else {
+    aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
+    return false;
+  }
+
+  nsCOMPtr<nsIInputStream> stream;
+  if (aData.IsBlob()) {
+    nsCOMPtr<nsIDOMBlob> blob = aData.GetAsBlob();
+
+    aRv = blob->GetInternalStream(getter_AddRefs(stream));
+    if (NS_WARN_IF(aRv.Failed())) {
+      return false;
+    }
+  } else {
+    nsresult rv;
+    nsCOMPtr<nsIStringInputStream> strStream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      aRv.Throw(rv);
+      return false;
+    }
+
+    if (aData.IsString()) {
+      NS_ConvertUTF16toUTF8 data(aData.GetAsString());
+      aRv = strStream->SetData(data.BeginReading(), data.Length());
+    } else if (aData.IsArrayBuffer()) {
+      const ArrayBuffer& data = aData.GetAsArrayBuffer();
+      data.ComputeLengthAndData();
+      aRv = strStream->SetData(reinterpret_cast<const char*>(data.Data()), data.Length());
+    } else {
+      const ArrayBufferView& data = aData.GetAsArrayBufferView();
+      data.ComputeLengthAndData();
+      aRv = strStream->SetData(reinterpret_cast<const char*>(data.Data()), data.Length());
+    }
+
+    if (NS_WARN_IF(aRv.Failed())) {
+      return false;
+    }
+
+    stream = strStream;
+  }
+
+  if (mSocket) {
+    aRv = mSocket->SendBinaryStream(remoteAddress, remotePort, stream);
+  } else if (mSocketChild) {
+    aRv = mSocketChild->SendBinaryStream(remoteAddress, remotePort, stream);
+  }
+
+  if (NS_WARN_IF(aRv.Failed())) {
+    return false;
+  }
+
+  return true;
+}
+
+nsresult
+UDPSocket::InitLocal(const nsAString& aLocalAddress,
+                     const uint16_t& aLocalPort)
+{
+  nsresult rv;
+
+  nsCOMPtr<nsIUDPSocket> sock =
+      do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  if (aLocalAddress.IsEmpty()) {
+    rv = sock->Init(aLocalPort, /* loopback = */ false, mAddressReuse, /* optionalArgc = */ 1);
+  } else {
+    PRNetAddr prAddr;
+    PR_InitializeNetAddr(PR_IpAddrAny, aLocalPort, &prAddr);
+    PR_StringToNetAddr(NS_ConvertUTF16toUTF8(aLocalAddress).BeginReading(), &prAddr);
+
+    mozilla::net::NetAddr addr;
+    PRNetAddrToNetAddr(&prAddr, &addr);
+    rv = sock->InitWithAddress(&addr, mAddressReuse, /* optionalArgc = */ 1);
+  }
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  rv = sock->SetMulticastLoopback(mLoopback);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  mSocket = sock;
+
+  // Get real local address and local port
+  nsCOMPtr<nsINetAddr> localAddr;
+  rv = mSocket->GetLocalAddr(getter_AddRefs(localAddr));
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  nsCString localAddress;
+  rv = localAddr->GetAddress(localAddress);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  mLocalAddress = NS_ConvertUTF8toUTF16(localAddress);
+
+  uint16_t localPort;
+  rv = localAddr->GetPort(&localPort);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  mLocalPort.SetValue(localPort);
+
+  rv = mSocket->AsyncListen(this);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  mReadyState = SocketReadyState::Open;
+  rv = DoPendingMcastCommand();
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  mOpened->MaybeResolve(JS::UndefinedHandleValue);
+
+  return NS_OK;
+}
+
+nsresult
+UDPSocket::InitRemote(const nsAString& aLocalAddress,
+                      const uint16_t& aLocalPort)
+{
+  nsresult rv;
+
+  nsCOMPtr<nsIUDPSocketChild> sock =
+    do_CreateInstance("@mozilla.org/udp-socket-child;1", &rv);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  rv = sock->Bind(this, NS_ConvertUTF16toUTF8(aLocalAddress), aLocalPort, mAddressReuse, mLoopback);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  mSocketChild = sock;
+
+  return NS_OK;
+}
+
+nsresult
+UDPSocket::Init(const nsString& aLocalAddress,
+                const Nullable<uint16_t>& aLocalPort,
+                const bool& aAddressReuse,
+                const bool& aLoopback)
+{
+  MOZ_ASSERT(!mSocket && !mSocketChild);
+
+  mLocalAddress = aLocalAddress;
+  mLocalPort = aLocalPort;
+  mAddressReuse = aAddressReuse;
+  mLoopback = aLoopback;
+
+  ErrorResult rv;
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
+
+  mOpened = Promise::Create(global, rv);
+  if (NS_WARN_IF(rv.Failed())) {
+    return rv.ErrorCode();
+  }
+
+  mClosed = Promise::Create(global, rv);
+  if (NS_WARN_IF(rv.Failed())) {
+    return rv.ErrorCode();
+  }
+
+  class OpenSocketRunnable MOZ_FINAL : public nsRunnable
+  {
+  public:
+    OpenSocketRunnable(UDPSocket* aSocket) : mSocket(aSocket)
+    { }
+
+    NS_IMETHOD Run() MOZ_OVERRIDE
+    {
+      MOZ_ASSERT(mSocket);
+
+      if (mSocket->mReadyState != SocketReadyState::Opening) {
+        return NS_OK;
+      }
+
+      uint16_t localPort = 0;
+      if (!mSocket->mLocalPort.IsNull()) {
+        localPort = mSocket->mLocalPort.Value();
+      }
+
+      nsresult rv;
+      if (XRE_GetProcessType() != GeckoProcessType_Default) {
+        rv = mSocket->InitRemote(mSocket->mLocalAddress, localPort);
+      } else {
+        rv = mSocket->InitLocal(mSocket->mLocalAddress, localPort);
+      }
+
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        mSocket->CloseWithReason(NS_ERROR_DOM_NETWORK_ERR);
+      }
+
+      return NS_OK;
+    }
+
+  private:
+    nsRefPtr<UDPSocket> mSocket;
+  };
+
+  nsCOMPtr<nsIRunnable> runnable = new OpenSocketRunnable(this);
+
+  return NS_DispatchToMainThread(runnable);
+}
+
+void
+UDPSocket::HandleReceivedData(const nsACString& aRemoteAddress,
+                              const uint16_t& aRemotePort,
+                              const uint8_t* aData,
+                              const uint32_t& aDataLength)
+{
+  if (mReadyState != SocketReadyState::Open) {
+    return;
+  }
+
+  if (NS_FAILED(CheckInnerWindowCorrectness())) {
+    return;
+  }
+
+  if (NS_FAILED(DispatchReceivedData(aRemoteAddress, aRemotePort, aData, aDataLength))) {
+    CloseWithReason(NS_ERROR_TYPE_ERR);
+  }
+}
+
+nsresult
+UDPSocket::DispatchReceivedData(const nsACString& aRemoteAddress,
+                                const uint16_t& aRemotePort,
+                                const uint8_t* aData,
+                                const uint32_t& aDataLength)
+{
+  AutoJSAPI jsapi;
+
+  if (NS_WARN_IF(!jsapi.Init(GetOwner()))) {
+    return NS_ERROR_FAILURE;
+  }
+
+  JSContext* cx = jsapi.cx();
+
+  // Copy packet data to ArrayBuffer
+  JS::Rooted<JSObject*> arrayBuf(cx, ArrayBuffer::Create(cx, aDataLength, aData));
+
+  if (NS_WARN_IF(!arrayBuf)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  JS::Rooted<JS::Value> jsData(cx, JS::ObjectValue(*arrayBuf));
+
+  // Create DOM event
+  RootedDictionary<UDPMessageEventInit> init(cx);
+  init.mRemoteAddress = NS_ConvertUTF8toUTF16(aRemoteAddress);
+  init.mRemotePort = aRemotePort;
+  init.mData = jsData;
+
+  nsRefPtr<UDPMessageEvent> udpEvent =
+    UDPMessageEvent::Constructor(this, NS_LITERAL_STRING("message"), init);
+
+  if (NS_WARN_IF(!udpEvent)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  udpEvent->SetTrusted(true);
+
+  nsRefPtr<AsyncEventDispatcher> asyncDispatcher = new AsyncEventDispatcher(this, udpEvent);
+
+  return asyncDispatcher->PostDOMEvent();
+}
+
+// nsIUDPSocketListener
+
+NS_IMETHODIMP
+UDPSocket::OnPacketReceived(nsIUDPSocket* aSocket, nsIUDPMessage* aMessage)
+{
+  // nsIUDPSocketListener callbacks should be invoked on main thread.
+  MOZ_ASSERT(NS_IsMainThread(), "Not running on main thread");
+
+  // Create appropriate JS object for message
+  FallibleTArray<uint8_t>& buffer = aMessage->GetDataAsTArray();
+
+  nsCOMPtr<nsINetAddr> addr;
+  if (NS_WARN_IF(NS_FAILED(aMessage->GetFromAddr(getter_AddRefs(addr))))) {
+    return NS_OK;
+  }
+
+  nsCString remoteAddress;
+  if (NS_WARN_IF(NS_FAILED(addr->GetAddress(remoteAddress)))) {
+    return NS_OK;
+  }
+
+  uint16_t remotePort;
+  if (NS_WARN_IF(NS_FAILED(addr->GetPort(&remotePort)))) {
+    return NS_OK;
+  }
+
+  HandleReceivedData(remoteAddress, remotePort, buffer.Elements(), buffer.Length());
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+UDPSocket::OnStopListening(nsIUDPSocket* aSocket, nsresult aStatus)
+{
+  // nsIUDPSocketListener callbacks should be invoked on main thread.
+  MOZ_ASSERT(NS_IsMainThread(), "Not running on main thread");
+
+  CloseWithReason(aStatus);
+
+  return NS_OK;
+}
+
+// nsIUDPSocketInternal
+
+NS_IMETHODIMP
+UDPSocket::CallListenerError(const nsACString& aMessage,
+                             const nsACString& aFilename,
+                             uint32_t aLineNumber)
+{
+  CloseWithReason(NS_ERROR_DOM_NETWORK_ERR);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+UDPSocket::CallListenerReceivedData(const nsACString& aRemoteAddress,
+                                    uint16_t aRemotePort,
+                                    const uint8_t* aData,
+                                    uint32_t aDataLength)
+{
+  HandleReceivedData(aRemoteAddress, aRemotePort, aData, aDataLength);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+UDPSocket::CallListenerOpened()
+{
+  if (mReadyState != SocketReadyState::Opening) {
+    return NS_OK;
+  }
+
+  MOZ_ASSERT(mSocketChild);
+
+  // Get real local address and local port
+  nsCString localAddress;
+  mSocketChild->GetLocalAddress(localAddress);
+  mLocalAddress = NS_ConvertUTF8toUTF16(localAddress);
+
+  uint16_t localPort;
+  mSocketChild->GetLocalPort(&localPort);
+  mLocalPort.SetValue(localPort);
+
+  mReadyState = SocketReadyState::Open;
+  nsresult rv = DoPendingMcastCommand();
+
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    CloseWithReason(rv);
+    return NS_OK;
+  }
+
+  mOpened->MaybeResolve(JS::UndefinedHandleValue);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+UDPSocket::CallListenerClosed()
+{
+  CloseWithReason(NS_OK);
+
+  return NS_OK;
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/network/src/UDPSocket.h
@@ -0,0 +1,197 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#ifndef mozilla_dom_UDPSocket_h__
+#define mozilla_dom_UDPSocket_h__
+
+#include "mozilla/Attributes.h"
+#include "mozilla/DOMEventTargetHelper.h"
+#include "mozilla/ErrorResult.h"
+#include "mozilla/dom/Promise.h"
+#include "mozilla/dom/SocketCommonBinding.h"
+#include "nsIUDPSocket.h"
+#include "nsIUDPSocketChild.h"
+#include "nsTArray.h"
+
+struct JSContext;
+
+namespace mozilla {
+namespace dom {
+
+struct UDPOptions;
+class StringOrBlobOrArrayBufferOrArrayBufferView;
+
+class UDPSocket MOZ_FINAL : public DOMEventTargetHelper
+                          , public nsIUDPSocketListener
+                          , public nsIUDPSocketInternal
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(UDPSocket, DOMEventTargetHelper)
+  NS_DECL_NSIUDPSOCKETLISTENER
+  NS_DECL_NSIUDPSOCKETINTERNAL
+  NS_REALLY_FORWARD_NSIDOMEVENTTARGET(DOMEventTargetHelper)
+
+public:
+  nsPIDOMWindow*
+  GetParentObject() const
+  {
+    return GetOwner();
+  }
+
+  virtual JSObject*
+  WrapObject(JSContext* aCx) MOZ_OVERRIDE;
+
+  virtual void
+  DisconnectFromOwner() MOZ_OVERRIDE;
+
+  static already_AddRefed<UDPSocket>
+  Constructor(const GlobalObject& aGlobal, const UDPOptions& aOptions, ErrorResult& aRv);
+
+  void
+  GetLocalAddress(nsString& aRetVal) const
+  {
+    aRetVal = mLocalAddress;
+  }
+
+  Nullable<uint16_t>
+  GetLocalPort() const
+  {
+    return mLocalPort;
+  }
+
+  void
+  GetRemoteAddress(nsString& aRetVal) const
+  {
+    if (mRemoteAddress.IsVoid()) {
+      SetDOMStringToNull(aRetVal);
+      return;
+    }
+
+    aRetVal = NS_ConvertUTF8toUTF16(mRemoteAddress);
+  }
+
+  Nullable<uint16_t>
+  GetRemotePort() const
+  {
+    return mRemotePort;
+  }
+
+  bool
+  AddressReuse() const
+  {
+    return mAddressReuse;
+  }
+
+  bool
+  Loopback() const
+  {
+    return mLoopback;
+  }
+
+  SocketReadyState
+  ReadyState() const
+  {
+    return mReadyState;
+  }
+
+  Promise*
+  Opened() const
+  {
+    return mOpened;
+  }
+
+  Promise*
+  Closed() const
+  {
+    return mClosed;
+  }
+
+  IMPL_EVENT_HANDLER(message)
+
+  already_AddRefed<Promise>
+  Close();
+
+  void
+  JoinMulticastGroup(const nsAString& aMulticastGroupAddress, ErrorResult& aRv);
+
+  void
+  LeaveMulticastGroup(const nsAString& aMulticastGroupAddress, ErrorResult& aRv);
+
+  bool
+  Send(const StringOrBlobOrArrayBufferOrArrayBufferView& aData,
+       const Optional<nsAString>& aRemoteAddress,
+       const Optional<Nullable<uint16_t>>& aRemotePort,
+       ErrorResult& aRv);
+
+private:
+  UDPSocket(nsPIDOMWindow* aOwner,
+            const nsCString& aRemoteAddress,
+            const Nullable<uint16_t>& aRemotePort);
+
+  virtual ~UDPSocket();
+
+  nsresult
+  Init(const nsString& aLocalAddress,
+       const Nullable<uint16_t>& aLocalPort,
+       const bool& aAddressReuse,
+       const bool& aLoopback);
+
+  nsresult
+  InitLocal(const nsAString& aLocalAddress, const uint16_t& aLocalPort);
+
+  nsresult
+  InitRemote(const nsAString& aLocalAddress, const uint16_t& aLocalPort);
+
+  void
+  HandleReceivedData(const nsACString& aRemoteAddress,
+                     const uint16_t& aRemotePort,
+                     const uint8_t* aData,
+                     const uint32_t& aDataLength);
+
+  nsresult
+  DispatchReceivedData(const nsACString& aRemoteAddress,
+                       const uint16_t& aRemotePort,
+                       const uint8_t* aData,
+                       const uint32_t& aDataLength);
+
+  void
+  CloseWithReason(nsresult aReason);
+
+  nsresult
+  DoPendingMcastCommand();
+
+  nsString mLocalAddress;
+  Nullable<uint16_t> mLocalPort;
+  nsCString mRemoteAddress;
+  Nullable<uint16_t> mRemotePort;
+  bool mAddressReuse;
+  bool mLoopback;
+  SocketReadyState mReadyState;
+  nsRefPtr<Promise> mOpened;
+  nsRefPtr<Promise> mClosed;
+
+  nsCOMPtr<nsIUDPSocket> mSocket;
+  nsCOMPtr<nsIUDPSocketChild> mSocketChild;
+
+  struct MulticastCommand {
+    enum CommandType { Join, Leave };
+
+    MulticastCommand(CommandType aCommand, const nsAString& aAddress)
+      : mCommand(aCommand), mAddress(aAddress)
+    { }
+
+    CommandType mCommand;
+    nsString mAddress;
+  };
+
+  nsTArray<MulticastCommand> mPendingMcastCommands;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_UDPSocket_h__
--- a/dom/network/src/UDPSocketChild.cpp
+++ b/dom/network/src/UDPSocketChild.cpp
@@ -1,13 +1,15 @@
 /* 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 "UDPSocketChild.h"
+#include "mozilla/unused.h"
+#include "mozilla/ipc/InputStreamUtils.h"
 #include "mozilla/net/NeckoChild.h"
 
 using mozilla::net::gNeckoChild;
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_ISUPPORTS(UDPSocketChildBase, nsIUDPSocketChild)
@@ -54,158 +56,203 @@ UDPSocketChild::UDPSocketChild()
 
 UDPSocketChild::~UDPSocketChild()
 {
 }
 
 // nsIUDPSocketChild Methods
 
 NS_IMETHODIMP
-UDPSocketChild::Bind(nsIUDPSocketInternal *aSocket,
+UDPSocketChild::Bind(nsIUDPSocketInternal* aSocket,
                      const nsACString& aHost,
-                     uint16_t aPort)
+                     uint16_t aPort,
+                     bool aAddressReuse,
+                     bool aLoopback)
 {
   NS_ENSURE_ARG(aSocket);
 
   mSocket = aSocket;
   AddIPDLReference();
 
-  gNeckoChild->SendPUDPSocketConstructor(this, nsCString(aHost), aPort, mFilterName);
+  gNeckoChild->SendPUDPSocketConstructor(this, mFilterName);
 
+  SendBind(UDPAddressInfo(nsCString(aHost), aPort), aAddressReuse, aLoopback);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 UDPSocketChild::Close()
 {
   SendClose();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 UDPSocketChild::Send(const nsACString& aHost,
                      uint16_t aPort,
-                     const uint8_t *aData,
+                     const uint8_t* aData,
                      uint32_t aByteLength)
 {
   NS_ENSURE_ARG(aData);
 
+  return SendDataInternal(UDPSocketAddr(UDPAddressInfo(nsCString(aHost), aPort)),
+                          aData, aByteLength);
+}
+
+NS_IMETHODIMP
+UDPSocketChild::SendWithAddr(nsINetAddr* aAddr,
+                             const uint8_t* aData,
+                             uint32_t aByteLength)
+{
+  NS_ENSURE_ARG(aAddr);
+  NS_ENSURE_ARG(aData);
+
+  NetAddr addr;
+  aAddr->GetNetAddr(&addr);
+
+  return SendDataInternal(UDPSocketAddr(addr), aData, aByteLength);
+}
+
+NS_IMETHODIMP
+UDPSocketChild::SendWithAddress(const NetAddr* aAddr,
+                                const uint8_t* aData,
+                                uint32_t aByteLength)
+{
+  NS_ENSURE_ARG(aAddr);
+  NS_ENSURE_ARG(aData);
+
+  return SendDataInternal(UDPSocketAddr(*aAddr), aData, aByteLength);
+}
+
+nsresult
+UDPSocketChild::SendDataInternal(const UDPSocketAddr& aAddr,
+                                 const uint8_t* aData,
+                                 const uint32_t aByteLength)
+{
+  NS_ENSURE_ARG(aData);
+
   FallibleTArray<uint8_t> fallibleArray;
   if (!fallibleArray.InsertElementsAt(0, aData, aByteLength)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   InfallibleTArray<uint8_t> array;
   array.SwapElements(fallibleArray);
-  SendData(array, nsCString(aHost), aPort);
+
+  SendOutgoingData(array, aAddr);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-UDPSocketChild::SendWithAddr(nsINetAddr *aAddr,
-                             const uint8_t *aData,
-                             uint32_t aByteLength)
+UDPSocketChild::SendBinaryStream(const nsACString& aHost,
+                                 uint16_t aPort,
+                                 nsIInputStream* aStream)
 {
-  NS_ENSURE_ARG(aAddr);
-  NS_ENSURE_ARG(aData);
-
-  NetAddr addr;
-  aAddr->GetNetAddr(&addr);
-
-  return SendWithAddress(&addr, aData, aByteLength);
-}
+  NS_ENSURE_ARG(aStream);
 
-NS_IMETHODIMP
-UDPSocketChild::SendWithAddress(const NetAddr *aAddr,
-                                const uint8_t *aData,
-                                uint32_t aByteLength)
-{
-  NS_ENSURE_ARG(aAddr);
-  NS_ENSURE_ARG(aData);
+  OptionalInputStreamParams stream;
+  nsTArray<mozilla::ipc::FileDescriptor> fds;
+  SerializeInputStream(aStream, stream, fds);
 
-  FallibleTArray<uint8_t> fallibleArray;
-  if (!fallibleArray.InsertElementsAt(0, aData, aByteLength)) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
+  MOZ_ASSERT(fds.IsEmpty());
 
-  InfallibleTArray<uint8_t> array;
-  array.SwapElements(fallibleArray);
-  SendDataWithAddress(array, *aAddr);
+  SendOutgoingData(UDPData(stream), UDPSocketAddr(UDPAddressInfo(nsCString(aHost), aPort)));
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-UDPSocketChild::GetLocalPort(uint16_t *aLocalPort)
+UDPSocketChild::JoinMulticast(const nsACString& aMulticastAddress,
+                              const nsACString& aInterface)
+{
+  SendJoinMulticast(nsCString(aMulticastAddress), nsCString(aInterface));
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+UDPSocketChild::LeaveMulticast(const nsACString& aMulticastAddress,
+                               const nsACString& aInterface)
+{
+  SendLeaveMulticast(nsCString(aMulticastAddress), nsCString(aInterface));
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+UDPSocketChild::GetLocalPort(uint16_t* aLocalPort)
 {
   NS_ENSURE_ARG_POINTER(aLocalPort);
 
   *aLocalPort = mLocalPort;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-UDPSocketChild::GetLocalAddress(nsACString &aLocalAddress)
+UDPSocketChild::GetLocalAddress(nsACString& aLocalAddress)
 {
   aLocalAddress = mLocalAddress;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-UDPSocketChild::SetFilterName(const nsACString &aFilterName)
+UDPSocketChild::SetFilterName(const nsACString& aFilterName)
 {
   if (!mFilterName.IsEmpty()) {
     // filter name can only be set once.
     return NS_ERROR_FAILURE;
   }
   mFilterName = aFilterName;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-UDPSocketChild::GetFilterName(nsACString &aFilterName)
+UDPSocketChild::GetFilterName(nsACString& aFilterName)
 {
   aFilterName = mFilterName;
   return NS_OK;
 }
 
 // PUDPSocketChild Methods
 bool
-UDPSocketChild::RecvCallback(const nsCString &aType,
-                             const UDPCallbackData &aData,
-                             const nsCString &aState)
+UDPSocketChild::RecvCallbackOpened(const UDPAddressInfo& aAddressInfo)
 {
-  if (NS_FAILED(mSocket->UpdateReadyState(aState)))
-    NS_ERROR("Shouldn't fail!");
+  mLocalAddress = aAddressInfo.addr();
+  mLocalPort = aAddressInfo.port();
+
+  nsresult rv = mSocket->CallListenerOpened();
+  mozilla::unused << NS_WARN_IF(NS_FAILED(rv));
+
+  return true;
+}
+
+bool
+UDPSocketChild::RecvCallbackClosed()
+{
+  nsresult rv = mSocket->CallListenerClosed();
+  mozilla::unused << NS_WARN_IF(NS_FAILED(rv));
 
-  nsresult rv = NS_ERROR_FAILURE;
-  if (aData.type() == UDPCallbackData::Tvoid_t) {
-    rv = mSocket->CallListenerVoid(aType);
-  } else if (aData.type() == UDPCallbackData::TUDPError) {
-    const UDPError& err(aData.get_UDPError());
-    rv = mSocket->CallListenerError(aType, err.message(), err.filename(),
-                                    err.lineNumber(), err.columnNumber());
-  } else if (aData.type() == UDPCallbackData::TUDPMessage) {
-    const UDPMessage& message(aData.get_UDPMessage());
-    InfallibleTArray<uint8_t> data(message.data());
-    rv = mSocket->CallListenerReceivedData(aType, message.fromAddr(), message.port(),
-                                           data.Elements(), data.Length());
-  } else if (aData.type() == UDPCallbackData::TUDPAddressInfo) {
-    //update local address and port.
-    const UDPAddressInfo& addressInfo(aData.get_UDPAddressInfo());
-    mLocalAddress = addressInfo.local();
-    mLocalPort = addressInfo.port();
-    rv = mSocket->CallListenerVoid(aType);
-  } else if (aData.type() == UDPCallbackData::TUDPSendResult) {
-    const UDPSendResult& returnValue(aData.get_UDPSendResult());
-    rv = mSocket->CallListenerSent(aType, returnValue.value());
-  } else {
-    MOZ_ASSERT(false, "Invalid callback type!");
-  }
+  return true;
+}
+
+bool
+UDPSocketChild::RecvCallbackReceivedData(const UDPAddressInfo& aAddressInfo,
+                                         const InfallibleTArray<uint8_t>& aData)
+{
+  nsresult rv = mSocket->CallListenerReceivedData(aAddressInfo.addr(), aAddressInfo.port(),
+                                                  aData.Elements(), aData.Length());
+  mozilla::unused << NS_WARN_IF(NS_FAILED(rv));
 
-  NS_ENSURE_SUCCESS(rv, true);
+  return true;
+}
+
+bool
+UDPSocketChild::RecvCallbackError(const nsCString& aMessage,
+                                  const nsCString& aFilename,
+                                  const uint32_t& aLineNumber)
+{
+  nsresult rv = mSocket->CallListenerError(aMessage, aFilename, aLineNumber);
+  mozilla::unused << NS_WARN_IF(NS_FAILED(rv));
 
   return true;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/network/src/UDPSocketChild.h
+++ b/dom/network/src/UDPSocketChild.h
@@ -35,20 +35,29 @@ class UDPSocketChild : public mozilla::n
 {
 public:
   NS_DECL_NSIUDPSOCKETCHILD
   NS_IMETHOD_(MozExternalRefCountType) Release() MOZ_OVERRIDE;
 
   UDPSocketChild();
   virtual ~UDPSocketChild();
 
-  virtual bool RecvCallback(const nsCString& aType,
-                            const UDPCallbackData& aData,
-                            const nsCString& aState) MOZ_OVERRIDE;
+  virtual bool RecvCallbackOpened(const UDPAddressInfo& aAddressInfo) MOZ_OVERRIDE;
+  virtual bool RecvCallbackClosed() MOZ_OVERRIDE;
+  virtual bool RecvCallbackReceivedData(const UDPAddressInfo& aAddressInfo,
+                                        const InfallibleTArray<uint8_t>& aData) MOZ_OVERRIDE;
+  virtual bool RecvCallbackError(const nsCString& aMessage,
+                                 const nsCString& aFilename,
+                                 const uint32_t& aLineNumber) MOZ_OVERRIDE;
+
 private:
+  nsresult SendDataInternal(const UDPSocketAddr& aAddr,
+                            const uint8_t* aData,
+                            const uint32_t aByteLength);
+
   uint16_t mLocalPort;
   nsCString mLocalAddress;
   nsCString mFilterName;
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/network/src/UDPSocketParent.cpp
+++ b/dom/network/src/UDPSocketParent.cpp
@@ -4,83 +4,68 @@
  * 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 "nsIServiceManager.h"
 #include "UDPSocketParent.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIUDPSocket.h"
 #include "nsINetAddr.h"
+#include "mozilla/AppProcessChecker.h"
 #include "mozilla/unused.h"
+#include "mozilla/ipc/InputStreamUtils.h"
 #include "mozilla/net/DNS.h"
+#include "mozilla/net/NeckoCommon.h"
 #include "nsNetUtil.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/net/PNeckoParent.h"
 
 namespace mozilla {
 namespace dom {
 
-static void
-FireInternalError(mozilla::net::PUDPSocketParent *aActor, uint32_t aLineNo)
-{
-  mozilla::unused <<
-      aActor->SendCallback(NS_LITERAL_CSTRING("onerror"),
-                          UDPError(NS_LITERAL_CSTRING("Internal error"),
-                                   NS_LITERAL_CSTRING(__FILE__), aLineNo, 0),
-                          NS_LITERAL_CSTRING("connecting"));
-}
-
-static nsresult
-ConvertNetAddrToString(mozilla::net::NetAddr &netAddr, nsACString *address, uint16_t *port)
-{
-  NS_ENSURE_ARG_POINTER(address);
-  NS_ENSURE_ARG_POINTER(port);
-
-  *port = 0;
-  uint32_t bufSize = 0;
-
-  switch(netAddr.raw.family) {
-  case AF_INET:
-    *port = PR_ntohs(netAddr.inet.port);
-    bufSize = mozilla::net::kIPv4CStrBufSize;
-    break;
-  case AF_INET6:
-    *port = PR_ntohs(netAddr.inet6.port);
-    bufSize = mozilla::net::kIPv6CStrBufSize;
-    break;
-  default:
-    //impossible
-    MOZ_ASSERT(false, "Unexpected address family");
-    return NS_ERROR_INVALID_ARG;
-  }
-
-  address->SetCapacity(bufSize);
-  NetAddrToString(&netAddr, address->BeginWriting(), bufSize);
-  address->SetLength(strlen(address->BeginReading()));
-
-  return NS_OK;
-}
-
 NS_IMPL_ISUPPORTS(UDPSocketParent, nsIUDPSocketListener)
 
-UDPSocketParent::UDPSocketParent(nsIUDPSocketFilter *filter)
+UDPSocketParent::UDPSocketParent()
   : mIPCOpen(true)
-  , mFilter(filter)
 {
   mObserver = new mozilla::net::OfflineObserver(this);
 }
 
 UDPSocketParent::~UDPSocketParent()
 {
   if (mObserver) {
     mObserver->RemoveObserver();
   }
 }
 
+bool
+UDPSocketParent::Init(const nsACString& aFilter)
+{
+  if (!aFilter.IsEmpty()) {
+    nsAutoCString contractId(NS_NETWORK_UDP_SOCKET_FILTER_HANDLER_PREFIX);
+    contractId.Append(aFilter);
+    nsCOMPtr<nsIUDPSocketFilterHandler> filterHandler =
+      do_GetService(contractId.get());
+    if (filterHandler) {
+      nsresult rv = filterHandler->NewFilter(getter_AddRefs(mFilter));
+      if (NS_FAILED(rv)) {
+        printf_stderr("Cannot create filter that content specified. "
+                      "filter name: %s, error code: %d.", aFilter.BeginReading(), rv);
+        return false;
+      }
+    } else {
+      printf_stderr("Content doesn't have a valid filter. "
+                    "filter name: %s.", aFilter.BeginReading());
+      return false;
+    }
+  }
+  return true;
+}
+
 uint32_t
 UDPSocketParent::GetAppId()
 {
   uint32_t appId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
   const PContentParent *content = Manager()->Manager();
   const InfallibleTArray<PBrowserParent*>& browsers = content->ManagedPBrowserParent();
   if (browsers.Length() > 0) {
     TabParent *tab = static_cast<TabParent*>(browsers[0]);
@@ -114,135 +99,246 @@ UDPSocketParent::OfflineNotification(nsI
 
   return NS_OK;
 }
 
 
 // PUDPSocketParent methods
 
 bool
-UDPSocketParent::Init(const nsCString &aHost, const uint16_t aPort)
+UDPSocketParent::RecvBind(const UDPAddressInfo& aAddressInfo,
+                          const bool& aAddressReuse, const bool& aLoopback)
+{
+  // We don't have browser actors in xpcshell, and hence can't run automated
+  // tests without this loophole.
+  if (net::UsingNeckoIPCSecurity() && !mFilter &&
+      !AssertAppProcessPermission(Manager()->Manager(), "udp-socket")) {
+    FireInternalError(__LINE__);
+    return false;
+  }
+
+  if (NS_FAILED(BindInternal(aAddressInfo.addr(), aAddressInfo.port(), aAddressReuse, aLoopback))) {
+    FireInternalError(__LINE__);
+    return true;
+  }
+
+  nsCOMPtr<nsINetAddr> localAddr;
+  mSocket->GetLocalAddr(getter_AddRefs(localAddr));
+
+  nsCString addr;
+  if (NS_FAILED(localAddr->GetAddress(addr))) {
+    FireInternalError(__LINE__);
+    return true;
+  }
+
+  uint16_t port;
+  if (NS_FAILED(localAddr->GetPort(&port))) {
+    FireInternalError(__LINE__);
+    return true;
+  }
+
+  mozilla::unused << SendCallbackOpened(UDPAddressInfo(addr, port));
+
+  return true;
+}
+
+nsresult
+UDPSocketParent::BindInternal(const nsCString& aHost, const uint16_t& aPort,
+                              const bool& aAddressReuse, const bool& aLoopback)
 {
   nsresult rv;
-  NS_ASSERTION(mFilter, "No packet filter");
 
   nsCOMPtr<nsIUDPSocket> sock =
       do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv);
-  if (NS_FAILED(rv)) {
-    FireInternalError(this, __LINE__);
-    return true;
+
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
   }
 
   if (aHost.IsEmpty()) {
-    rv = sock->Init(aPort, false);
+    rv = sock->Init(aPort, false, aAddressReuse, /* optional_argc = */ 1);
   } else {
     PRNetAddr prAddr;
     PR_InitializeNetAddr(PR_IpAddrAny, aPort, &prAddr);
     PRStatus status = PR_StringToNetAddr(aHost.BeginReading(), &prAddr);
     if (status != PR_SUCCESS) {
-      FireInternalError(this, __LINE__);
-      return true;
+      return NS_ERROR_FAILURE;
     }
 
     mozilla::net::NetAddr addr;
     PRNetAddrToNetAddr(&prAddr, &addr);
-    rv = sock->InitWithAddress(&addr);
+    rv = sock->InitWithAddress(&addr, aAddressReuse, /* optional_argc = */ 1);
+  }
+
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
   }
 
-  if (NS_FAILED(rv)) {
-    FireInternalError(this, __LINE__);
-    return true;
+  rv = sock->SetMulticastLoopback(aLoopback);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  // register listener
+  rv = sock->AsyncListen(this);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
   }
 
   mSocket = sock;
 
-  net::NetAddr localAddr;
-  mSocket->GetAddress(&localAddr);
+  return NS_OK;
+}
+
+bool
+UDPSocketParent::RecvOutgoingData(const UDPData& aData,
+                                  const UDPSocketAddr& aAddr)
+{
+  MOZ_ASSERT(mSocket);
+
+  nsresult rv;
+  if (mFilter) {
+    // TODO, Bug 933102, filter packets that are sent with hostname.
+    // Until then we simply throw away packets that are sent to a hostname.
+    if (aAddr.type() != UDPSocketAddr::TNetAddr) {
+      return true;
+    }
+
+    // TODO, Packet filter doesn't support input stream yet.
+    if (aData.type() != UDPData::TArrayOfuint8_t) {
+      return true;
+    }
+
+    bool allowed;
+    const InfallibleTArray<uint8_t>& data(aData.get_ArrayOfuint8_t());
+    rv = mFilter->FilterPacket(&aAddr.get_NetAddr(), data.Elements(),
+                               data.Length(), nsIUDPSocketFilter::SF_OUTGOING,
+                               &allowed);
+
+    // Sending unallowed data, kill content.
+    if (NS_WARN_IF(NS_FAILED(rv)) || !allowed) {
+      return false;
+    }
+  }
+
+  switch(aData.type()) {
+    case UDPData::TArrayOfuint8_t:
+      Send(aData.get_ArrayOfuint8_t(), aAddr);
+      break;
+    case UDPData::TInputStreamParams:
+      Send(aData.get_InputStreamParams(), aAddr);
+      break;
+    default:
+      MOZ_ASSERT(false, "Invalid data type!");
+      return true;
+  }
+
+  return true;
+}
 
-  uint16_t port;
-  nsCString addr;
-  rv = ConvertNetAddrToString(localAddr, &addr, &port);
+void
+UDPSocketParent::Send(const InfallibleTArray<uint8_t>& aData,
+                      const UDPSocketAddr& aAddr)
+{
+  nsresult rv;
+  uint32_t count;
+  switch(aAddr.type()) {
+    case UDPSocketAddr::TUDPAddressInfo: {
+      const UDPAddressInfo& addrInfo(aAddr.get_UDPAddressInfo());
+      rv = mSocket->Send(addrInfo.addr(), addrInfo.port(),
+                         aData.Elements(), aData.Length(), &count);
+      break;
+    }
+    case UDPSocketAddr::TNetAddr: {
+      const NetAddr& addr(aAddr.get_NetAddr());
+      rv = mSocket->SendWithAddress(&addr, aData.Elements(),
+                                    aData.Length(), &count);
+      break;
+    }
+    default:
+      MOZ_ASSERT(false, "Invalid address type!");
+      return;
+  }
+
+  if (NS_WARN_IF(NS_FAILED(rv)) || count == 0) {
+    FireInternalError(__LINE__);
+  }
+}
+
+void
+UDPSocketParent::Send(const InputStreamParams& aStream,
+                      const UDPSocketAddr& aAddr)
+{
+  nsTArray<mozilla::ipc::FileDescriptor> fds;
+  nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(aStream, fds);
+
+  if (NS_WARN_IF(!stream)) {
+    return;
+  }
+
+  nsresult rv;
+  switch(aAddr.type()) {
+    case UDPSocketAddr::TUDPAddressInfo: {
+      const UDPAddressInfo& addrInfo(aAddr.get_UDPAddressInfo());
+      rv = mSocket->SendBinaryStream(addrInfo.addr(), addrInfo.port(), stream);
+      break;
+    }
+    case UDPSocketAddr::TNetAddr: {
+      const NetAddr& addr(aAddr.get_NetAddr());
+      rv = mSocket->SendBinaryStreamWithAddress(&addr, stream);
+      break;
+    }
+    default:
+      MOZ_ASSERT(false, "Invalid address type!");
+      return;
+  }
 
   if (NS_FAILED(rv)) {
-    FireInternalError(this, __LINE__);
-    return true;
+    FireInternalError(__LINE__);
   }
+}
 
-  // register listener
-  mSocket->AsyncListen(this);
-  mozilla::unused <<
-      PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onopen"),
-                                     UDPAddressInfo(addr, port),
-                                     NS_LITERAL_CSTRING("connected"));
+bool
+UDPSocketParent::RecvJoinMulticast(const nsCString& aMulticastAddress,
+                                   const nsCString& aInterface)
+{
+  nsresult rv = mSocket->JoinMulticast(aMulticastAddress, aInterface);
+
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    FireInternalError(__LINE__);
+  }
 
   return true;
 }
 
 bool
-UDPSocketParent::RecvData(const InfallibleTArray<uint8_t> &aData,
-                          const nsCString& aRemoteAddress,
-                          const uint16_t& aPort)
+UDPSocketParent::RecvLeaveMulticast(const nsCString& aMulticastAddress,
+                                    const nsCString& aInterface)
 {
-  NS_ENSURE_TRUE(mSocket, true);
-  NS_ASSERTION(mFilter, "No packet filter");
-  // TODO, Bug 933102, filter packets that are sent with hostname.
-  // Until then we simply throw away packets that are sent to a hostname.
-  return true;
-
-#if 0
-  // Enable this once we have filtering working with hostname delivery.
-  uint32_t count;
-  nsresult rv = mSocket->Send(aRemoteAddress,
-                              aPort, aData.Elements(),
-                              aData.Length(), &count);
-  mozilla::unused <<
-      PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onsent"),
-                                     UDPSendResult(rv),
-                                     NS_LITERAL_CSTRING("connected"));
-  NS_ENSURE_SUCCESS(rv, true);
-  NS_ENSURE_TRUE(count > 0, true);
-  return true;
-#endif
-}
+  nsresult rv = mSocket->LeaveMulticast(aMulticastAddress, aInterface);
 
-bool
-UDPSocketParent::RecvDataWithAddress(const InfallibleTArray<uint8_t>& aData,
-                                     const mozilla::net::NetAddr& aAddr)
-{
-  NS_ENSURE_TRUE(mSocket, true);
-  NS_ASSERTION(mFilter, "No packet filter");
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    FireInternalError(__LINE__);
+  }
 
-  uint32_t count;
-  nsresult rv;
-  bool allowed;
-  rv = mFilter->FilterPacket(&aAddr, aData.Elements(),
-                             aData.Length(), nsIUDPSocketFilter::SF_OUTGOING,
-                             &allowed);
-  // Sending unallowed data, kill content.
-  NS_ENSURE_SUCCESS(rv, false);
-  NS_ENSURE_TRUE(allowed, false);
-
-  rv = mSocket->SendWithAddress(&aAddr, aData.Elements(),
-                                aData.Length(), &count);
-  mozilla::unused <<
-      PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onsent"),
-                                     UDPSendResult(rv),
-                                     NS_LITERAL_CSTRING("connected"));
-  NS_ENSURE_SUCCESS(rv, true);
-  NS_ENSURE_TRUE(count > 0, true);
   return true;
 }
 
 bool
 UDPSocketParent::RecvClose()
 {
-  NS_ENSURE_TRUE(mSocket, true);
+  if (!mSocket) {
+    return true;
+  }
+
   nsresult rv = mSocket->Close();
   mSocket = nullptr;
-  NS_ENSURE_SUCCESS(rv, true);
+
+  mozilla::unused << NS_WARN_IF(NS_FAILED(rv));
+
   return true;
 }
 
 bool
 UDPSocketParent::RecvRequestDelete()
 {
   mozilla::unused << Send__delete__(this);
   return true;
@@ -263,66 +359,73 @@ UDPSocketParent::ActorDestroy(ActorDestr
 
 NS_IMETHODIMP
 UDPSocketParent::OnPacketReceived(nsIUDPSocket* aSocket, nsIUDPMessage* aMessage)
 {
   // receiving packet from remote host, forward the message content to child process
   if (!mIPCOpen) {
     return NS_OK;
   }
-  NS_ASSERTION(mFilter, "No packet filter");
 
   uint16_t port;
   nsCString ip;
   nsCOMPtr<nsINetAddr> fromAddr;
   aMessage->GetFromAddr(getter_AddRefs(fromAddr));
   fromAddr->GetPort(&port);
   fromAddr->GetAddress(ip);
 
   nsCString data;
   aMessage->GetData(data);
 
   const char* buffer = data.get();
   uint32_t len = data.Length();
 
-  bool allowed;
-  mozilla::net::NetAddr addr;
-  fromAddr->GetNetAddr(&addr);
-  nsresult rv = mFilter->FilterPacket(&addr,
-                                      (const uint8_t*)buffer, len,
-                                      nsIUDPSocketFilter::SF_INCOMING,
-                                      &allowed);
-  // Receiving unallowed data, drop.
-  NS_ENSURE_SUCCESS(rv, NS_OK);
-  NS_ENSURE_TRUE(allowed, NS_OK);
+  if (mFilter) {
+    bool allowed;
+    mozilla::net::NetAddr addr;
+    fromAddr->GetNetAddr(&addr);
+    nsresult rv = mFilter->FilterPacket(&addr,
+                                        (const uint8_t*)buffer, len,
+                                        nsIUDPSocketFilter::SF_INCOMING,
+                                        &allowed);
+    // Receiving unallowed data, drop.
+    if (NS_WARN_IF(NS_FAILED(rv)) || !allowed) {
+      return NS_OK;
+    }
+  }
 
   FallibleTArray<uint8_t> fallibleArray;
   if (!fallibleArray.InsertElementsAt(0, buffer, len)) {
-    FireInternalError(this, __LINE__);
+    FireInternalError(__LINE__);
     return NS_ERROR_OUT_OF_MEMORY;
   }
   InfallibleTArray<uint8_t> infallibleArray;
   infallibleArray.SwapElements(fallibleArray);
 
   // compose callback
-  mozilla::unused <<
-      PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("ondata"),
-                                     UDPMessage(ip, port, infallibleArray),
-                                     NS_LITERAL_CSTRING("connected"));
+  mozilla::unused << SendCallbackReceivedData(UDPAddressInfo(ip, port), infallibleArray);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 UDPSocketParent::OnStopListening(nsIUDPSocket* aSocket, nsresult aStatus)
 {
   // underlying socket is dead, send state update to child process
   if (mIPCOpen) {
-    mozilla::unused <<
-        PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onclose"),
-                                       mozilla::void_t(),
-                                       NS_LITERAL_CSTRING("closed"));
+    mozilla::unused << SendCallbackClosed();
   }
   return NS_OK;
 }
 
+void
+UDPSocketParent::FireInternalError(uint32_t aLineNo)
+{
+  if (!mIPCOpen) {
+    return;
+  }
+
+  mozilla::unused << SendCallbackError(NS_LITERAL_CSTRING("Internal error"),
+                                       NS_LITERAL_CSTRING(__FILE__), aLineNo);
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/network/src/UDPSocketParent.h
+++ b/dom/network/src/UDPSocketParent.h
@@ -19,34 +19,45 @@ namespace dom {
 class UDPSocketParent : public mozilla::net::PUDPSocketParent
                       , public nsIUDPSocketListener
                       , public mozilla::net::DisconnectableParent
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIUDPSOCKETLISTENER
 
-  explicit UDPSocketParent(nsIUDPSocketFilter* filter);
+  explicit UDPSocketParent();
+
+  bool Init(const nsACString& aFilter);
 
-  bool Init(const nsCString& aHost, const uint16_t aPort);
+  virtual bool RecvBind(const UDPAddressInfo& aAddressInfo,
+                        const bool& aAddressReuse, const bool& aLoopback) MOZ_OVERRIDE;
+
+  virtual bool RecvOutgoingData(const UDPData& aData, const UDPSocketAddr& aAddr) MOZ_OVERRIDE;
 
   virtual bool RecvClose() MOZ_OVERRIDE;
-  virtual bool RecvData(const InfallibleTArray<uint8_t>& aData,
-                        const nsCString& aRemoteAddress,
-                        const uint16_t& aPort) MOZ_OVERRIDE;
-  virtual bool RecvDataWithAddress( const InfallibleTArray<uint8_t>& data,
-                                    const mozilla::net::NetAddr& addr);
+
   virtual bool RecvRequestDelete() MOZ_OVERRIDE;
+  virtual bool RecvJoinMulticast(const nsCString& aMulticastAddress,
+                                 const nsCString& aInterface) MOZ_OVERRIDE;
+  virtual bool RecvLeaveMulticast(const nsCString& aMulticastAddress,
+                                  const nsCString& aInterface) MOZ_OVERRIDE;
 
   virtual nsresult OfflineNotification(nsISupports *) MOZ_OVERRIDE;
   virtual uint32_t GetAppId() MOZ_OVERRIDE;
 private:
   virtual ~UDPSocketParent();
 
   virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
+  void Send(const InfallibleTArray<uint8_t>& aData, const UDPSocketAddr& aAddr);
+  void Send(const InputStreamParams& aStream, const UDPSocketAddr& aAddr);
+  nsresult BindInternal(const nsCString& aHost, const uint16_t& aPort,
+                        const bool& aAddressReuse, const bool& aLoopback);
+
+  void FireInternalError(uint32_t aLineNo);
 
   bool mIPCOpen;
   nsCOMPtr<nsIUDPSocket> mSocket;
   nsCOMPtr<nsIUDPSocketFilter> mFilter;
   nsRefPtr<mozilla::net::OfflineObserver> mObserver;
 };
 
 } // namespace dom
--- a/dom/network/src/moz.build
+++ b/dom/network/src/moz.build
@@ -1,14 +1,18 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
+EXPORTS.mozilla.dom += [
+    'UDPSocket.h',
+]
+
 EXPORTS.mozilla.dom.network += [
     'Connection.h',
     'Constants.h',
     'TCPServerSocketChild.h',
     'TCPServerSocketParent.h',
     'TCPSocketChild.h',
     'TCPSocketParent.h',
     'Types.h',
@@ -17,16 +21,17 @@ EXPORTS.mozilla.dom.network += [
 ]
 
 UNIFIED_SOURCES += [
     'Connection.cpp',
     'TCPServerSocketChild.cpp',
     'TCPServerSocketParent.cpp',
     'TCPSocketChild.cpp',
     'TCPSocketParent.cpp',
+    'UDPSocket.cpp',
     'UDPSocketChild.cpp',
     'UDPSocketParent.cpp',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     EXTRA_JS_MODULES += [
         'NetworkStatsDB.jsm',
         'NetworkStatsService.jsm',
new file mode 100644
--- /dev/null
+++ b/dom/network/tests/file_udpsocket_iframe.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test UDPSocket BFCache</title>
+</head>
+<body>
+<script type="application/javascript;version=1.8">
+'use strict';
+window.addEventListener('load', function onload() {
+  window.removeEventListener('load', onload);
+  let remotePort = parseInt(window.location.search.substring(1), 10);
+  let socket = new UDPSocket();
+  socket.addEventListener('message', function () {
+    socket.send('fail', '127.0.0.1', remotePort);
+  });
+
+  socket.opened.then(function() {
+    socket.send('ready', '127.0.0.1', remotePort);
+  });
+});
+</script>
+</body>
+</html>
--- a/dom/network/tests/mochitest.ini
+++ b/dom/network/tests/mochitest.ini
@@ -1,8 +1,12 @@
+[DEFAULT]
+support-files =
+  file_udpsocket_iframe.html
+
 [test_network_basics.html]
 skip-if = toolkit == "gonk" || toolkit == 'android'
 [test_tcpsocket_default_permissions.html]
 skip-if = toolkit == "gonk"
 [test_tcpsocket_enabled_no_perm.html]
 skip-if = toolkit == "gonk"
 [test_tcpsocket_enabled_with_perm.html]
 skip-if = toolkit == "gonk" || e10s
@@ -11,8 +15,9 @@ skip-if = toolkit != "gonk"
 [test_networkstats_basics.html]
 skip-if = toolkit != "gonk" || (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(Will be fixed in bug 858005) b2g-desktop(Will be fixed in bug 858005)
 [test_networkstats_disabled.html]
 skip-if = toolkit != "gonk"
 [test_networkstats_enabled_no_perm.html]
 skip-if = toolkit != "gonk"
 [test_networkstats_enabled_perm.html]
 skip-if = toolkit != "gonk"
+[test_udpsocket.html]
new file mode 100644
--- /dev/null
+++ b/dom/network/tests/test_udpsocket.html
@@ -0,0 +1,409 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test UDPSocket API</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<iframe id="iframe"></iframe>
+<pre id="test">
+<script type="application/javascript;version=1.8">
+'use strict';
+SimpleTest.waitForExplicitFinish();
+
+const HELLO_WORLD = 'hlo wrld. ';
+const DATA_ARRAY = [0, 255, 254, 0, 1, 2, 3, 0, 255, 255, 254, 0];
+const DATA_ARRAY_BUFFER = new ArrayBuffer(DATA_ARRAY.length);
+const TYPED_DATA_ARRAY = new Uint8Array(DATA_ARRAY_BUFFER);
+const BIG_ARRAY = new Array(4096);
+const BIG_ARRAY_BUFFER = new ArrayBuffer(BIG_ARRAY.length);
+const BIG_TYPED_ARRAY = new Uint8Array(BIG_ARRAY_BUFFER);
+
+for (let i = 0; i < BIG_ARRAY.length; i++) {
+  BIG_ARRAY[i] = Math.floor(Math.random() * 256);
+}
+
+TYPED_DATA_ARRAY.set(DATA_ARRAY);
+BIG_TYPED_ARRAY.set(BIG_ARRAY);
+
+function is_same_buffer(recv_data, expect_data) {
+  let recv_dataview = new Uint8Array(recv_data);
+  let expected_dataview = new Uint8Array(expect_data);
+
+  if (recv_dataview.length !== expected_dataview.length) {
+    return false;
+  }
+
+  for (let i = 0; i < recv_dataview.length; i++) {
+    if (recv_dataview[i] != expected_dataview[i]) {
+      info('discover byte differenct at ' + i);
+      return false;
+    }
+  }
+  return true;
+}
+
+function testOpen() {
+  info('test for creating an UDP Socket');
+  let socket = new UDPSocket();
+  is(socket.localPort, null, 'expect no local port before socket opened');
+  is(socket.localAddress, null, 'expect no local address before socket opened');
+  is(socket.remotePort, null, 'expected no default remote port');
+  is(socket.remoteAddress, null, 'expected no default remote address');
+  is(socket.readyState, 'opening', 'expected ready state = opening');
+  is(socket.loopback, false, 'expected no loopback');
+  is(socket.addressReuse, true, 'expect to reuse address');
+
+  return socket.opened.then(function() {
+    ok(true, 'expect openedPromise to be resolved after successful socket binding');
+    ok(!(socket.localPort === 0), 'expect allocated a local port');
+    is(socket.localAddress, '0.0.0.0', 'expect assigned to default address');
+    is(socket.readyState, 'open', 'expected ready state = open');
+
+    return socket;
+  });
+}
+
+function testSendString(socket) {
+  info('test for sending string data');
+
+  socket.send(HELLO_WORLD, '127.0.0.1', socket.localPort);
+
+  return new Promise(function(resolve, reject) {
+    socket.addEventListener('message', function recv_callback(msg) {
+      socket.removeEventListener('message', recv_callback);
+      let recvData= String.fromCharCode.apply(null, new Uint8Array(msg.data));
+      is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
+      is(recvData, HELLO_WORLD, 'expected same string data');
+      resolve(socket);
+    });
+  });
+}
+
+function testSendArrayBuffer(socket) {
+  info('test for sending ArrayBuffer');
+
+  socket.send(DATA_ARRAY_BUFFER, '127.0.0.1', socket.localPort);
+
+  return new Promise(function(resolve, reject) {
+    socket.addEventListener('message', function recv_callback(msg) {
+      socket.removeEventListener('message', recv_callback);
+      is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
+      ok(is_same_buffer(msg.data, DATA_ARRAY_BUFFER), 'expected same buffer data');
+      resolve(socket);
+    });
+  });
+}
+
+function testSendArrayBufferView(socket) {
+  info('test for sending ArrayBufferView');
+
+  socket.send(TYPED_DATA_ARRAY, '127.0.0.1', socket.localPort);
+
+  return new Promise(function(resolve, reject) {
+    socket.addEventListener('message', function recv_callback(msg) {
+      socket.removeEventListener('message', recv_callback);
+      is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
+      ok(is_same_buffer(msg.data, TYPED_DATA_ARRAY), 'expected same buffer data');
+      resolve(socket);
+    });
+  });
+}
+
+function testSendBlob(socket) {
+  info('test for sending Blob');
+
+  let blob = new Blob([HELLO_WORLD], {type : 'text/plain'});
+  socket.send(blob, '127.0.0.1', socket.localPort);
+
+  return new Promise(function(resolve, reject) {
+    socket.addEventListener('message', function recv_callback(msg) {
+      socket.removeEventListener('message', recv_callback);
+      let recvData= String.fromCharCode.apply(null, new Uint8Array(msg.data));
+      is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
+      is(recvData, HELLO_WORLD, 'expected same string data');
+      resolve(socket);
+    });
+  });
+}
+
+function testSendBigArray(socket) {
+  info('test for sending Big ArrayBuffer');
+
+  socket.send(BIG_TYPED_ARRAY, '127.0.0.1', socket.localPort);
+
+  return new Promise(function(resolve, reject) {
+    let byteReceived = 0;
+    socket.addEventListener('message', function recv_callback(msg) {
+      let byteBegin = byteReceived;
+      byteReceived += msg.data.byteLength;
+      is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
+      ok(is_same_buffer(msg.data, BIG_TYPED_ARRAY.subarray(byteBegin, byteReceived)), 'expected same buffer data [' + byteBegin+ '-' + byteReceived + ']');
+      if (byteReceived >= BIG_TYPED_ARRAY.length) {
+        socket.removeEventListener('message', recv_callback);
+        clearTimeout(timeout);
+        resolve(socket);
+      }
+    });
+
+    let timeout = setTimeout(function() {
+      ok(false, 'timeout for sending big array');
+      resolve(socket);
+    }, 5000);
+  });
+}
+
+function testSendBigBlob(socket) {
+  info('test for sending Big Blob');
+
+  let blob = new Blob([BIG_TYPED_ARRAY]);
+  socket.send(blob, '127.0.0.1', socket.localPort);
+
+  return new Promise(function(resolve, reject) {
+    let byteReceived = 0;
+    socket.addEventListener('message', function recv_callback(msg) {
+      let byteBegin = byteReceived;
+      byteReceived += msg.data.byteLength;
+      is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
+      ok(is_same_buffer(msg.data, BIG_TYPED_ARRAY.subarray(byteBegin, byteReceived)), 'expected same buffer data [' + byteBegin+ '-' + byteReceived + ']');
+      if (byteReceived >= BIG_TYPED_ARRAY.length) {
+        socket.removeEventListener('message', recv_callback);
+        clearTimeout(timeout);
+        resolve(socket);
+      }
+    });
+
+    let timeout = setTimeout(function() {
+      ok(false, 'timeout for sending big blob');
+      resolve(socket);
+    }, 5000);
+  });
+}
+
+function testUDPOptions(socket) {
+  info('test for UDP init options');
+
+  let remoteSocket = new UDPSocket({addressReuse: false,
+                                    loopback: true,
+                                    localAddress: '127.0.0.1',
+                                    remoteAddress: '127.0.0.1',
+                                    remotePort: socket.localPort});
+  is(remoteSocket.localAddress, '127.0.0.1', 'expected local address');
+  is(remoteSocket.remoteAddress, '127.0.0.1', 'expected remote address');
+  is(remoteSocket.remotePort, socket.localPort, 'expected remote port');
+  is(remoteSocket.addressReuse, false, 'expected address not reusable');
+  is(remoteSocket.loopback, true, 'expected loopback mode is on');
+
+  return remoteSocket.opened.then(function() {
+    remoteSocket.send(HELLO_WORLD);
+    return new Promise(function(resolve, reject) {
+      socket.addEventListener('message', function recv_callback(msg) {
+        socket.removeEventListener('message', recv_callback);
+        let recvData= String.fromCharCode.apply(null, new Uint8Array(msg.data));
+        is(msg.remotePort, remoteSocket.localPort, 'expected packet from ' + remoteSocket.localPort);
+        is(recvData, HELLO_WORLD, 'expected same string data');
+        resolve(socket);
+      });
+    });
+  });
+}
+
+function testClose(socket) {
+  info('test for close');
+
+  socket.close();
+  is(socket.readyState, 'closed', 'expect ready state to be "closed"');
+  try {
+    socket.send(HELLO_WORLD, '127.0.0.1', socket.localPort);
+    ok(false, 'unexpect to send successfully');
+  } catch (e) {
+    ok(true, 'expected send fail after socket closed');
+  }
+
+  return socket.closed.then(function() {
+    ok(true, 'expected closedPromise is resolved after socket.close()');
+  });
+}
+
+function testMulticast() {
+  info('test for multicast');
+
+  let socket = new UDPSocket({loopback: true});
+
+  const MCAST_ADDRESS = '224.0.0.255';
+  socket.joinMulticastGroup(MCAST_ADDRESS);
+
+  return socket.opened.then(function() {
+    socket.send(HELLO_WORLD, MCAST_ADDRESS, socket.localPort);
+
+    return new Promise(function(resolve, reject) {
+      socket.addEventListener('message', function recv_callback(msg) {
+        socket.removeEventListener('message', recv_callback);
+        let recvData= String.fromCharCode.apply(null, new Uint8Array(msg.data));
+        is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
+        is(recvData, HELLO_WORLD, 'expected same string data');
+        socket.leaveMulticastGroup(MCAST_ADDRESS);
+        resolve();
+      });
+    });
+  });
+}
+
+function testInvalidUDPOptions() {
+  info('test for invalid UDPOptions');
+  try {
+    let socket = new UDPSocket({localAddress: 'not-a-valid-address'});
+    ok(false, 'should not create an UDPSocket with an invalid localAddress');
+  } catch (e) {
+    is(e.name, 'InvalidAccessError', 'expected InvalidAccessError will be thrown if localAddress is not a valid IPv4/6 address');
+  }
+
+  try {
+    let socket = new UDPSocket({localPort: 0});
+    ok(false, 'should not create an UDPSocket with an invalid localPort');
+  } catch (e) {
+    is(e.name, 'InvalidAccessError', 'expected InvalidAccessError will be thrown if localPort is not a valid port number');
+  }
+
+  try {
+    let socket = new UDPSocket({remotePort: 0});
+    ok(false, 'should not create an UDPSocket with an invalid remotePort');
+  } catch (e) {
+    is(e.name, 'InvalidAccessError', 'expected InvalidAccessError will be thrown if localPort is not a valid port number');
+  }
+}
+
+function testOpenFailed() {
+  info('test for falied on open');
+
+  //according to RFC5737, address block 192.0.2.0/24 should not be used in both local and public contexts
+  let socket = new UDPSocket({localAddress: '192.0.2.0'});
+
+  return socket.opened.then(function() {
+    ok(false, 'should not resolve openedPromise while fail to bind socket');
+  }).catch(function(reason) {
+    is(reason.name, 'NetworkError', 'expected openedPromise to be rejected while fail to bind socket');
+  });
+}
+
+function testSendBeforeOpen() {
+  info('test for send before open');
+
+  let socket = new UDPSocket();
+
+  try {
+    socket.send(HELLO_WORLD, '127.0.0.1', 9);
+    ok(false, 'unexpect to send successfully');
+  } catch (e) {
+    ok(true, 'expected send fail before openedPromise is resolved');
+  }
+
+  return socket.opened;
+}
+
+function testCloseBeforeOpened() {
+  info('test for close socket before opened');
+
+  let socket = new UDPSocket();
+  socket.opened.then(function() {
+    ok(false, 'should not resolve openedPromise if it has already been closed');
+  }).catch(function(reason) {
+    is(reason.name, 'AbortError', 'expected openedPromise to be rejected while socket is closed during opening');
+  });
+
+  return socket.close().then(function() {
+    ok(true, 'expected closedPromise to be resolved');
+  }).then(socket.opened);
+}
+
+function testOpenWithoutClose() {
+  info('test for open without close');
+
+  let opened = [];
+  for (let i = 0; i < 50; i++) {
+    let socket = new UDPSocket();
+    opened.push(socket.opened);
+  }
+
+  return Promise.all(opened);
+}
+
+function testBFCache() {
+  info('test for bfcache behavior');
+
+  let socket = new UDPSocket();
+
+  return socket.opened.then(function() {
+    let iframe = document.getElementById('iframe');
+    SpecialPowers.wrap(iframe).mozbrowser = true;
+    iframe.src = 'file_udpsocket_iframe.html?' + socket.localPort;
+
+    return new Promise(function(resolve, reject) {
+      socket.addEventListener('message', function recv_callback(msg) {
+        socket.removeEventListener('message', recv_callback);
+        iframe.src = 'about:blank';
+        iframe.addEventListener('load', function onload() {
+          iframe.removeEventListener('load', onload);
+          socket.send(HELLO_WORLD, '127.0.0.1', msg.remotePort);
+
+          function recv_again_callback(msg) {
+            socket.removeEventListener('message', recv_again_callback);
+            ok(false, 'should not receive packet after page unload');
+          }
+
+          socket.addEventListener('message', recv_again_callback);
+
+          let timeout = setTimeout(function() {
+            socket.removeEventListener('message', recv_again_callback);
+            socket.close();
+            resolve();
+          }, 5000);
+        });
+      });
+    });
+  });
+}
+
+function runTest() {
+  testOpen()
+  .then(testSendString)
+  .then(testSendArrayBuffer)
+  .then(testSendArrayBufferView)
+  .then(testSendBlob)
+  .then(testSendBigArray)
+  .then(testSendBigBlob)
+  .then(testUDPOptions)
+  .then(testClose)
+  .then(testMulticast)
+  .then(testInvalidUDPOptions)
+  .then(testOpenFailed)
+  .then(testSendBeforeOpen)
+  .then(testCloseBeforeOpened)
+  .then(testOpenWithoutClose)
+  .then(testBFCache)
+  .then(function() {
+    info('test finished');
+    SimpleTest.finish();
+  });
+}
+
+window.addEventListener('load', function () {
+  SpecialPowers.pushPermissions([
+    {type: 'udp-socket', allow: true, context: document}], function() {
+    SpecialPowers.pushPrefEnv({
+      'set': [
+        ['dom.udpsocket.enabled', true],
+        ['browser.sessionhistory.max_total_viewers', 10]
+      ]
+    }, runTest);
+  });
+});
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/permission/tests/mochitest.ini
+++ b/dom/permission/tests/mochitest.ini
@@ -11,16 +11,17 @@ skip-if = ((buildapp == 'mulet' || build
 [test_idle.html]
 skip-if = (toolkit == 'gonk' && debug) #debug-only failure
 [test_permission_basics.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' # b2g(https not working, bug 907770) b2g-debug(https not working, bug 907770) b2g-desktop(Bug 907770)
 [test_permissions.html]
 [test_power.html]
 [test_systemXHR.html]
 [test_tcp-socket.html]
+[test_udp-socket.html]
 [test_webapps-manage.html]
 [test_camera.html]
 disabled = disabled until bug 859593 is fixed
 [test_keyboard.html]
 skip-if = toolkit == 'android'
 [test_input-manage.html]
 skip-if = toolkit == 'android'
 [test_wifi-manage.html]
new file mode 100644
--- /dev/null
+++ b/dom/permission/tests/test_udp-socket.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=745283
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 745283 </title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=745283">Mozilla Bug 745283 </a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test">
+<script type="application/javascript;version=1.8" src="file_framework.js"></script>
+<script type="application/javascript;version=1.8">
+function verifier(success, failure) {
+  try {
+    var socket = new UDPSocket();
+
+    if (socket) {
+      success("Opened socket");
+    } else {
+      failure("failed to open socket");
+    }
+  } catch (e) {
+    failure("Got an exception " + e);
+  }
+}
+
+var gData = [
+  {
+    perm: ["udp-socket"],
+    needParentPerm: true,
+    obj: "UDPSocket",
+    webidl: "UDPSocket",
+    settings: [["dom.udpsocket.enabled", true]],
+    verifier: verifier.toSource(),
+  }
+]
+</script>
+</pre>
+</body>
+</html>
+
--- a/dom/settings/SettingsChangeNotifier.jsm
+++ b/dom/settings/SettingsChangeNotifier.jsm
@@ -32,16 +32,19 @@ this.SettingsChangeNotifier = {
     this.children = [];
     this._messages = ["Settings:Changed", "Settings:RegisterForMessages", "child-process-shutdown"];
     this._messages.forEach((function(msgName) {
       ppmm.addMessageListener(msgName, this);
     }).bind(this));
 
     Services.obs.addObserver(this, kXpcomShutdownObserverTopic, false);
     Services.obs.addObserver(this, kMozSettingsChangedObserverTopic, false);
+
+    // Broadcast when SettingChangeNotifier finishes init process.
+    ppmm.broadcastAsyncMessage("Settings:Notifier:Init:OK");
   },
 
   observe: function(aSubject, aTopic, aData) {
     if (DEBUG) debug("observe");
     switch (aTopic) {
       case kXpcomShutdownObserverTopic:
         this._messages.forEach((function(msgName) {
           ppmm.removeMessageListener(msgName, this);
--- a/dom/settings/SettingsManager.js
+++ b/dom/settings/SettingsManager.js
@@ -314,25 +314,32 @@ SettingsManager.prototype = {
           if (DEBUG) debug("observe callback called! " + msg.key + " " + this._callbacks[msg.key].length);
           this._callbacks[msg.key].forEach(function(cb) {
             cb(this._wrap({settingName: msg.key, settingValue: msg.value}));
           }.bind(this));
         } else {
           if (DEBUG) debug("no observers stored!");
         }
         break;
+      case "Settings:Notifier:Init:OK":
+        // If SettingManager receives this message means SettingChangeNotifier
+        // might not receive the Settings:RegisterForMessage message. We should
+        // send it again after SettingChangeNotifier is ready.
+        if (this.hasReadPrivileges) {
+          cpmm.sendAsyncMessage("Settings:RegisterForMessages");
+        }
+        break;
       default:
         if (DEBUG) debug("Wrong message: " + aMessage.name);
     }
   },
 
   addObserver: function addObserver(aName, aCallback) {
     if (DEBUG) debug("addObserver " + aName);
     if (!this._callbacks) {
-      cpmm.sendAsyncMessage("Settings:RegisterForMessages");
       this._callbacks = {};
     }
     if (!this._callbacks[aName]) {
       this._callbacks[aName] = [aCallback];
     } else {
       this._callbacks[aName].push(aCallback);
     }
   },
@@ -349,16 +356,17 @@ SettingsManager.prototype = {
     } else {
       if (DEBUG) debug("No observers stored for " + aName);
     }
   },
 
   init: function(aWindow) {
     mrm.registerStrongReporter(this);
     cpmm.addMessageListener("Settings:Change:Return:OK", this);
+    cpmm.addMessageListener("Settings:Notifier:Init:OK", this);
     this._window = aWindow;
     Services.obs.addObserver(this, "inner-window-destroyed", false);
     let util = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
     this.innerWindowID = util.currentInnerWindowID;
 
     let readPerm = Services.perms.testExactPermissionFromPrincipal(aWindow.document.nodePrincipal, "settings-read");
     let writePerm = Services.perms.testExactPermissionFromPrincipal(aWindow.document.nodePrincipal, "settings-write");
     this.hasReadPrivileges = readPerm == Ci.nsIPermissionManager.ALLOW_ACTION;
@@ -406,16 +414,17 @@ SettingsManager.prototype = {
                          "The number of settings observers for this topic.",
                          aData);
     }
   },
 
   cleanup: function() {
     Services.obs.removeObserver(this, "inner-window-destroyed");
     cpmm.removeMessageListener("Settings:Change:Return:OK", this);
+    cpmm.removeMessageListener("Settings:Notifier:Init:OK", this);
     mrm.unregisterStrongReporter(this);
     this._requests = null;
     this._window = null;
     this._innerWindowID = null;
     this._settingsDB.close();
   },
 
   classID: Components.ID("{c40b1c70-00fb-11e2-a21f-0800200c9a66}"),
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -1164,16 +1164,20 @@ var interfaceNamesInGlobalScope =
     {name: "TreeColumns", xbl: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "TreeContentView", xbl: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "TreeSelection", xbl: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "TreeWalker",
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "UDPMessageEvent", pref: "dom.udpsocket.enabled", permission: "udp-socket"},
+// IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "UDPSocket", pref: "dom.udpsocket.enabled", permission: "udp-socket"},
+// IMPORTANT: Do not change this list without review from a DOM peer!
     "UIEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "UndoManager",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "URL",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "URLSearchParams",
 // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/webidl/BluetoothAdapter.webidl
+++ b/dom/webidl/BluetoothAdapter.webidl
@@ -112,16 +112,19 @@ interface BluetoothAdapter : EventTarget
    * @param profile 2-octets service UUID. This is optional.
    */
   [NewObject, Throws]
   DOMRequest connect(BluetoothDevice device, optional unsigned short serviceUuid);
 
   [NewObject, Throws]
   DOMRequest disconnect(BluetoothDevice device, optional unsigned short serviceUuid);
 
+  [NewObject, Throws]
+  DOMRequest isConnected(unsigned short serviceUuid);
+
   // One device can only send one file at a time
   [NewObject, Throws]
   DOMRequest sendFile(DOMString deviceAddress, Blob blob);
   [NewObject, Throws]
   DOMRequest stopSendingFile(DOMString deviceAddress);
   [NewObject, Throws]
   DOMRequest confirmReceivingFile(DOMString deviceAddress, boolean confirmation);
 
--- a/dom/webidl/BluetoothManager.webidl
+++ b/dom/webidl/BluetoothManager.webidl
@@ -7,13 +7,11 @@
 interface BluetoothManager : EventTarget {
   [Throws]
   readonly attribute boolean      enabled;
 
            attribute EventHandler onenabled;
            attribute EventHandler ondisabled;
            attribute EventHandler onadapteradded;
 
-  [Throws]
-  boolean     isConnected(unsigned short aProfile);
   [NewObject, Throws]
   DOMRequest? getDefaultAdapter();
 };
--- a/dom/webidl/Element.webidl
+++ b/dom/webidl/Element.webidl
@@ -151,17 +151,17 @@ interface Element : Node {
 
 // http://dev.w3.org/csswg/cssom-view/#extensions-to-the-element-interface
 partial interface Element {
   DOMRectList getClientRects();
   DOMRect getBoundingClientRect();
 
   // scrolling
   void scrollIntoView();
-  void scrollIntoView(boolean top);
+  void scrollIntoView(boolean top, optional ScrollOptions options);
   // None of the CSSOM attributes are [Pure], because they flush
            attribute long scrollTop;   // scroll on setting
            attribute long scrollLeft;  // scroll on setting
   readonly attribute long scrollWidth;
   readonly attribute long scrollHeight;
 
   readonly attribute long clientTop;
   readonly attribute long clientLeft;
--- a/dom/webidl/MozSelfSupport.webidl
+++ b/dom/webidl/MozSelfSupport.webidl
@@ -6,18 +6,19 @@
  * The MozSelfSupport interface allows external Mozilla support sites such as
  * FHR and SUMO to access data and control settings that are not otherwise
  * exposed to external content.
  *
  * At the moment, this is a ChromeOnly interface, but the plan is to allow
  * specific Mozilla domains to access it directly.
  */
 [ChromeOnly,
- JSImplementation="@mozilla.org/mozselfsupport;1"]
-interface MozSelfSupportImpl
+ JSImplementation="@mozilla.org/mozselfsupport;1",
+ Constructor()]
+interface MozSelfSupport
 {
   /**
    * Controls whether uploading FHR data is allowed.
    */
   attribute boolean healthReportDataSubmissionEnabled;
 
   /**
    * Retrieves the FHR payload object, which is of the form:
--- a/dom/webidl/PeerConnectionImpl.webidl
+++ b/dom/webidl/PeerConnectionImpl.webidl
@@ -39,16 +39,19 @@ interface PeerConnectionImpl  {
   void getStats(MediaStreamTrack? selector);
 
   /* Adds the tracks created by GetUserMedia */
   [Throws]
   void addTrack(MediaStreamTrack track, MediaStream... streams);
   [Throws]
   void removeTrack(MediaStreamTrack track);
   [Throws]
+  void replaceTrack(MediaStreamTrack thisTrack, MediaStreamTrack withTrack,
+                    MediaStream stream);
+  [Throws]
   void closeStreams();
 
   sequence<MediaStream> getLocalStreams();
   sequence<MediaStream> getRemoteStreams();
 
   /* As the ICE candidates roll in this one should be called each time
    * in order to keep the candidate list up-to-date for the next SDP-related
    * call PeerConnectionImpl does not parse ICE candidates, just sticks them
--- a/dom/webidl/PeerConnectionObserver.webidl
+++ b/dom/webidl/PeerConnectionObserver.webidl
@@ -23,16 +23,20 @@ interface PeerConnectionObserver
   void onAddIceCandidateSuccess();
   void onAddIceCandidateError(unsigned long name, DOMString message);
   void onIceCandidate(unsigned short level, DOMString mid, DOMString candidate);
 
   /* Stats callbacks */
   void onGetStatsSuccess(optional RTCStatsReportInternal report);
   void onGetStatsError(unsigned long name, DOMString message);
 
+  /* replaceTrack callbacks */
+  void onReplaceTrackSuccess();
+  void onReplaceTrackError(unsigned long name, DOMString message);
+
   /* Data channel callbacks */
   void notifyDataChannel(DataChannel channel);
 
   /* Notification of one of several types of state changed */
   void onStateChange(PCObserverStateType state);
 
   /* Changes to MediaStreamTracks */
   void onAddStream(MediaStream stream);
--- a/dom/webidl/RTCRtpSender.webidl
+++ b/dom/webidl/RTCRtpSender.webidl
@@ -6,9 +6,13 @@
  * The origin of this IDL file is
  * http://lists.w3.org/Archives/Public/public-webrtc/2014May/0067.html
  */
 
 [Pref="media.peerconnection.enabled",
  JSImplementation="@mozilla.org/dom/rtpsender;1"]
 interface RTCRtpSender {
   readonly attribute MediaStreamTrack track;
+
+  void replaceTrack(MediaStreamTrack track,
+                    VoidFunction successCallback,
+                    RTCPeerConnectionErrorCallback failureCallback);
 };
new file mode 100644
--- /dev/null
+++ b/dom/webidl/SocketCommon.webidl
@@ -0,0 +1,16 @@
+/* -*- 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/.
+ *
+ * The origin of this IDL file is
+ * http://www.w3.org/2012/sysapps/tcp-udp-sockets/#readystate
+ */
+
+enum SocketReadyState {
+    "opening",
+    "open",
+    "closing",
+    "closed",
+    "halfclosed"
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/UDPMessageEvent.webidl
@@ -0,0 +1,24 @@
+/* -*- 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/.
+ *
+ * The origin of this IDL file is
+ * http://www.w3.org/TR/raw-sockets/#interface-udpmessageevent
+ */
+
+//Bug 1056444: This interface should be removed after UDPSocket.input/UDPSocket.output are ready.
+[Constructor(DOMString type, optional UDPMessageEventInit eventInitDict),
+ Pref="dom.udpsocket.enabled",
+ CheckPermissions="udp-socket"]
+interface UDPMessageEvent : Event {
+    readonly    attribute DOMString      remoteAddress;
+    readonly    attribute unsigned short remotePort;
+    readonly    attribute any            data;
+};
+
+dictionary UDPMessageEventInit : EventInit {
+  DOMString remoteAddress = "";
+  unsigned short remotePort = 0;
+  any data = null;
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/UDPSocket.webidl
@@ -0,0 +1,40 @@
+/* -*- 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/.
+ *
+ * The origin of this IDL file is
+ * http://www.w3.org/2012/sysapps/tcp-udp-sockets/#interface-udpsocket
+ * http://www.w3.org/2012/sysapps/tcp-udp-sockets/#dictionary-udpoptions
+ */
+
+dictionary UDPOptions {
+    DOMString      localAddress;
+    unsigned short localPort;
+    DOMString      remoteAddress;
+    unsigned short remotePort;
+    boolean        addressReuse = true;
+    boolean        loopback = false;
+};
+
+[Constructor (optional UDPOptions options),
+ Pref="dom.udpsocket.enabled",
+ CheckPermissions="udp-socket"]
+interface UDPSocket : EventTarget {
+    readonly    attribute DOMString?       localAddress;
+    readonly    attribute unsigned short?  localPort;
+    readonly    attribute DOMString?       remoteAddress;
+    readonly    attribute unsigned short?  remotePort;
+    readonly    attribute boolean          addressReuse;
+    readonly    attribute boolean          loopback;
+    readonly    attribute SocketReadyState readyState;
+    readonly    attribute Promise<void>    opened;
+    readonly    attribute Promise<void>    closed;
+//    readonly    attribute ReadableStream   input; //Bug 1056444: Stream API is not ready
+//    readonly    attribute WriteableStream  output; //Bug 1056444: Stream API is not ready
+                attribute EventHandler     onmessage; //Bug 1056444: use event interface before Stream API is ready
+    Promise<void> close ();
+    [Throws] void    joinMulticastGroup (DOMString multicastGroupAddress);
+    [Throws] void    leaveMulticastGroup (DOMString multicastGroupAddress);
+    [Throws] boolean send ((DOMString or Blob or ArrayBuffer or ArrayBufferView) data, optional DOMString? remoteAddress, optional unsigned short? remotePort); //Bug 1056444: use send method before Stream API is ready
+};
--- a/dom/webidl/Window.webidl
+++ b/dom/webidl/Window.webidl
@@ -174,26 +174,23 @@ partial interface Window {
   [Throws] attribute long innerWidth;
   [Throws] attribute long innerHeight;
 
   // viewport scrolling
   //[Throws] readonly attribute double scrollX;
   //[Throws] readonly attribute double pageXOffset;
   //[Throws] readonly attribute double scrollY;
   //[Throws] readonly attribute double pageYOffset;
-  //void scroll(double x, double y, optional ScrollOptions options);
-  //void scrollTo(double x, double y, optional ScrollOptions options);
-  //void scrollBy(double x, double y, optional ScrollOptions options);
+  void scroll(double x, double y, optional ScrollOptions options);
+  void scrollTo(double x, double y, optional ScrollOptions options);
+  void scrollBy(double x, double y, optional ScrollOptions options);
   [Replaceable, Throws] readonly attribute long scrollX;
   [Throws] readonly attribute long pageXOffset;
   [Replaceable, Throws] readonly attribute long scrollY;
   [Throws] readonly attribute long pageYOffset;
-  void scroll(long x, long y);
-  void scrollTo(long x, long y);
-  void scrollBy(long x, long y);
 
   // client
   //[Throws] readonly attribute double screenX;
   //[Throws] readonly attribute double screenY;
   //[Throws] readonly attribute double outerWidth;
   //[Throws] readonly attribute double outerHeight;
   [Throws] attribute long screenX;
   [Throws] attribute long screenY;
@@ -266,22 +263,22 @@ partial interface Window {
    * The current animation start time in milliseconds since the epoch.
    */
   [Throws] readonly attribute long long mozAnimationStartTime;
 
   // Mozilla extensions
   /**
    * Method for scrolling this window by a number of lines.
    */
-  void                      scrollByLines(long numLines);
+  void                      scrollByLines(long numLines, optional ScrollOptions options);
 
   /**
    * Method for scrolling this window by a number of pages.
    */
-  void                      scrollByPages(long numPages);
+  void                      scrollByPages(long numPages, optional ScrollOptions options);
 
   /**
    * Method for sizing this window to the content in the window.
    */
   [Throws] void             sizeToContent();
 
   // XXX Shouldn't this be in nsIDOMChromeWindow?
   [ChromeOnly, Replaceable, Throws] readonly attribute MozControllers controllers;
@@ -326,16 +323,24 @@ partial interface Window {
                                  optional boolean showDialog = false);
 
   /**
    * Returns the number of times this document for this window has
    * been painted to the screen.
    */
   [Throws] readonly attribute unsigned long long mozPaintCount;
 
+  /**
+   * This property exists because static attributes don't yet work for
+   * JS-implemented WebIDL (see bugs 1058606 and 863952). With this hack, we
+   * can use `MozSelfSupport.something(...)`, which will continue to work
+   * after we ditch this property and switch to static attributes. See 
+   */
+  [ChromeOnly, Throws] readonly attribute MozSelfSupport MozSelfSupport;
+
   [Pure]
            attribute EventHandler onwheel;
 
            attribute EventHandler ondevicemotion;
            attribute EventHandler ondeviceorientation;
            attribute EventHandler ondeviceproximity;
            attribute EventHandler onuserproximity;
            attribute EventHandler ondevicelight;
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -328,16 +328,17 @@ WEBIDL_FILES = [
     'ServiceWorkerContainer.webidl',
     'ServiceWorkerGlobalScope.webidl',
     'ServiceWorkerRegistration.webidl',
     'SettingsManager.webidl',
     'ShadowRoot.webidl',
     'SharedWorker.webidl',
     'SharedWorkerGlobalScope.webidl',
     'SimpleGestureEvent.webidl',
+    'SocketCommon.webidl',
     'SourceBuffer.webidl',
     'SourceBufferList.webidl',
     'Storage.webidl',
     'StorageEvent.webidl',
     'StorageType.webidl',
     'StyleSheet.webidl',
     'StyleSheetList.webidl',
     'SubtleCrypto.webidl',
@@ -463,16 +464,18 @@ WEBIDL_FILES = [
     'TimeEvent.webidl',
     'TimeRanges.webidl',
     'Touch.webidl',
     'TouchEvent.webidl',
     'TouchList.webidl',
     'TransitionEvent.webidl',
     'TreeColumns.webidl',
     'TreeWalker.webidl',
+    'UDPMessageEvent.webidl',
+    'UDPSocket.webidl',
     'UIEvent.webidl',
     'UndoManager.webidl',
     'URL.webidl',
     'URLSearchParams.webidl',
     'URLUtils.webidl',
     'URLUtilsReadOnly.webidl',
     'ValidityState.webidl',
     'VideoPlaybackQuality.webidl',
@@ -671,16 +674,17 @@ GENERATED_EVENTS_WEBIDL_FILES = [
     'RTCPeerConnectionIceEvent.webidl',
     'RTCPeerConnectionIdentityErrorEvent.webidl',
     'RTCPeerConnectionIdentityEvent.webidl',
     'SelectionChangeEvent.webidl',
     'StyleRuleChangeEvent.webidl',
     'StyleSheetApplicableStateChangeEvent.webidl',
     'StyleSheetChangeEvent.webidl',
     'TrackEvent.webidl',
+    'UDPMessageEvent.webidl',
     'UserProximityEvent.webidl',
     'USSDReceivedEvent.webidl',
 ]
 
 if CONFIG['MOZ_WEBSPEECH']:
     GENERATED_EVENTS_WEBIDL_FILES += [
         'SpeechRecognitionEvent.webidl',
         'SpeechSynthesisEvent.webidl',
--- a/dom/workers/ServiceWorkerContainer.cpp
+++ b/dom/workers/ServiceWorkerContainer.cpp
@@ -25,28 +25,38 @@ namespace dom {
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ServiceWorkerContainer)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(ServiceWorkerContainer, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(ServiceWorkerContainer, DOMEventTargetHelper)
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(ServiceWorkerContainer, DOMEventTargetHelper,
-                                   mControllerWorker)
+                                   mControllerWorker, mReadyPromise)
 
 ServiceWorkerContainer::ServiceWorkerContainer(nsPIDOMWindow* aWindow)
-  : mWindow(aWindow)
+  : DOMEventTargetHelper(aWindow)
 {
-  SetIsDOMBinding();
 }
 
 ServiceWorkerContainer::~ServiceWorkerContainer()
 {
 }
 
+void
+ServiceWorkerContainer::DisconnectFromOwner()
+{
+  nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
+  MOZ_ASSERT(swm);
+
+  swm->RemoveReadyPromise(GetOwner());
+
+  DOMEventTargetHelper::DisconnectFromOwner();
+}
+
 JSObject*
 ServiceWorkerContainer::WrapObject(JSContext* aCx)
 {
   return ServiceWorkerContainerBinding::Wrap(aCx, this);
 }
 
 already_AddRefed<Promise>
 ServiceWorkerContainer::Register(const nsAString& aScriptURL,
@@ -77,17 +87,17 @@ ServiceWorkerContainer::GetController()
   if (!mControllerWorker) {
     nsresult rv;
     nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
     if (!swm) {
       return nullptr;
     }
 
     nsCOMPtr<nsISupports> serviceWorker;
-    rv = swm->GetDocumentController(mWindow, getter_AddRefs(serviceWorker));
+    rv = swm->GetDocumentController(GetOwner(), getter_AddRefs(serviceWorker));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return nullptr;
     }
 
     mControllerWorker =
       static_cast<workers::ServiceWorker*>(serviceWorker.get());
   }
 
@@ -101,17 +111,17 @@ ServiceWorkerContainer::GetRegistrations
   nsresult rv;
   nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID, &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   nsCOMPtr<nsISupports> promise;
-  aRv = swm->GetRegistrations(mWindow, getter_AddRefs(promise));
+  aRv = swm->GetRegistrations(GetOwner(), getter_AddRefs(promise));
   if (aRv.Failed()) {
     return nullptr;
   }
 
   nsRefPtr<Promise> ret = static_cast<Promise*>(promise.get());
   MOZ_ASSERT(ret);
   return ret.forget();
 }
@@ -123,32 +133,44 @@ ServiceWorkerContainer::GetRegistration(
   nsresult rv;
   nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID, &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   nsCOMPtr<nsISupports> promise;
-  aRv = swm->GetRegistration(mWindow, aDocumentURL, getter_AddRefs(promise));
+  aRv = swm->GetRegistration(GetOwner(), aDocumentURL, getter_AddRefs(promise));
   if (aRv.Failed()) {
     return nullptr;
   }
 
   nsRefPtr<Promise> ret = static_cast<Promise*>(promise.get());
   MOZ_ASSERT(ret);
   return ret.forget();
 }
 
-already_AddRefed<Promise>
+Promise*
 ServiceWorkerContainer::GetReady(ErrorResult& aRv)
 {
-  // FIXME(nsm): Bug 1025077
-  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mWindow);
-  return Promise::Create(global, aRv);
+  if (mReadyPromise) {
+    return mReadyPromise;
+  }
+
+  nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
+  if (!swm) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsCOMPtr<nsISupports> promise;
+  aRv = swm->GetReadyPromise(GetOwner(), getter_AddRefs(promise));
+
+  mReadyPromise = static_cast<Promise*>(promise.get());
+  return mReadyPromise;
 }
 
 // Testing only.
 already_AddRefed<Promise>
 ServiceWorkerContainer::ClearAllServiceWorkerData(ErrorResult& aRv)
 {
   aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
   return nullptr;
--- a/dom/workers/ServiceWorkerContainer.h
+++ b/dom/workers/ServiceWorkerContainer.h
@@ -29,22 +29,16 @@ public:
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServiceWorkerContainer, DOMEventTargetHelper)
 
   IMPL_EVENT_HANDLER(controllerchange)
   IMPL_EVENT_HANDLER(reloadpage)
   IMPL_EVENT_HANDLER(error)
 
   explicit ServiceWorkerContainer(nsPIDOMWindow* aWindow);
 
-  nsPIDOMWindow*
-  GetParentObject() const
-  {
-    return mWindow;
-  }
-
   JSObject*
   WrapObject(JSContext* aCx);
 
   already_AddRefed<Promise>
   Register(const nsAString& aScriptURL,
            const RegistrationOptionList& aOptions,
            ErrorResult& aRv);
 
@@ -53,39 +47,43 @@ public:
 
   already_AddRefed<Promise>
   GetRegistration(const nsAString& aDocumentURL,
                   ErrorResult& aRv);
 
   already_AddRefed<Promise>
   GetRegistrations(ErrorResult& aRv);
 
-  already_AddRefed<Promise>
+  Promise*
   GetReady(ErrorResult& aRv);
 
   // Testing only.
   already_AddRefed<Promise>
   ClearAllServiceWorkerData(ErrorResult& aRv);
 
   // Testing only.
   void
   GetScopeForUrl(const nsAString& aUrl, nsString& aScope, ErrorResult& aRv);
 
   // Testing only.
   void
   GetControllingWorkerScriptURLForPath(const nsAString& aPath,
                                        nsString& aScriptURL,
                                        ErrorResult& aRv);
+
+  // DOMEventTargetHelper
+  void DisconnectFromOwner() MOZ_OVERRIDE;
+
 private:
   ~ServiceWorkerContainer();
 
-  nsCOMPtr<nsPIDOMWindow> mWindow;
-
   // This only changes when a worker hijacks everything in its scope by calling
   // replace().
   // FIXME(nsm): Bug 982711. Provide API to let SWM invalidate this.
   nsRefPtr<workers::ServiceWorker> mControllerWorker;
+
+  nsRefPtr<Promise> mReadyPromise;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_workers_serviceworkercontainer_h__ */
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -550,20 +550,17 @@ ServiceWorkerManager::Register(const nsA
 {
   AssertIsOnMainThread();
 
   // XXXnsm Don't allow chrome callers for now, we don't support chrome
   // ServiceWorkers.
   MOZ_ASSERT(!nsContentUtils::IsCallerChrome());
 
   nsCOMPtr<nsIGlobalObject> sgo = GetEntryGlobal();
-  if (!sgo) {
-    MOZ_CRASH("Register() should only be called from a valid entry settings object!");
-    return NS_ERROR_FAILURE;
-  }
+  MOZ_ASSERT(sgo, "Register() should only be called from a valid entry settings object!");
 
   ErrorResult result;
   nsRefPtr<Promise> promise = Promise::Create(sgo, result);
   if (result.Failed()) {
     return result.ErrorCode();
   }
 
   nsCOMPtr<nsIDocument> doc = GetEntryDocument();
@@ -818,16 +815,152 @@ ServiceWorkerManager::GetRegistration(ns
   }
 
   nsRefPtr<nsIRunnable> runnable =
     new GetRegistrationRunnable(window, promise, aDocumentURL);
   promise.forget(aPromise);
   return NS_DispatchToCurrentThread(runnable);
 }
 
+class GetReadyPromiseRunnable : public nsRunnable
+{
+  nsCOMPtr<nsPIDOMWindow> mWindow;
+  nsRefPtr<Promise> mPromise;
+
+public:
+  GetReadyPromiseRunnable(nsPIDOMWindow* aWindow, Promise* aPromise)
+    : mWindow(aWindow), mPromise(aPromise)
+  { }
+
+  NS_IMETHODIMP
+  Run()
+  {
+    nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+
+    nsIDocument* doc = mWindow->GetExtantDoc();
+    if (!doc) {
+      mPromise->MaybeReject(NS_ERROR_UNEXPECTED);
+      return NS_OK;
+    }
+
+    nsCOMPtr<nsIURI> docURI = doc->GetDocumentURI();
+    if (!docURI) {
+      mPromise->MaybeReject(NS_ERROR_UNEXPECTED);
+      return NS_OK;
+    }
+
+    if (!swm->CheckReadyPromise(mWindow, docURI, mPromise)) {
+      swm->StorePendingReadyPromise(mWindow, docURI, mPromise);
+    }
+
+    return NS_OK;
+  }
+};
+
+NS_IMETHODIMP
+ServiceWorkerManager::GetReadyPromise(nsIDOMWindow* aWindow,
+                                      nsISupports** aPromise)
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(aWindow);
+
+  // XXXnsm Don't allow chrome callers for now, we don't support chrome
+  // ServiceWorkers.
+  MOZ_ASSERT(!nsContentUtils::IsCallerChrome());
+
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
+  if (!window) {
+    return NS_ERROR_FAILURE;
+  }
+
+  MOZ_ASSERT(!mPendingReadyPromises.Contains(window));
+
+  nsCOMPtr<nsIGlobalObject> sgo = do_QueryInterface(window);
+  ErrorResult result;
+  nsRefPtr<Promise> promise = Promise::Create(sgo, result);
+  if (result.Failed()) {
+    return result.ErrorCode();
+  }
+
+  nsRefPtr<nsIRunnable> runnable =
+    new GetReadyPromiseRunnable(window, promise);
+  promise.forget(aPromise);
+  return NS_DispatchToCurrentThread(runnable);
+}
+
+NS_IMETHODIMP
+ServiceWorkerManager::RemoveReadyPromise(nsIDOMWindow* aWindow)
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(aWindow);
+
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
+  if (!window) {
+    return NS_ERROR_FAILURE;
+  }
+
+  mPendingReadyPromises.Remove(aWindow);
+  return NS_OK;
+}
+
+void
+ServiceWorkerManager::StorePendingReadyPromise(nsPIDOMWindow* aWindow,
+                                               nsIURI* aURI,
+                                               Promise* aPromise)
+{
+  PendingReadyPromise* data;
+
+  // We should not have 2 pending promises for the same window.
+  MOZ_ASSERT(!mPendingReadyPromises.Get(aWindow, &data));
+
+  data = new PendingReadyPromise(aURI, aPromise);
+  mPendingReadyPromises.Put(aWindow, data);
+}
+
+void
+ServiceWorkerManager::CheckPendingReadyPromises()
+{
+  mPendingReadyPromises.Enumerate(CheckPendingReadyPromisesEnumerator, this);
+}
+
+PLDHashOperator
+ServiceWorkerManager::CheckPendingReadyPromisesEnumerator(
+                                          nsISupports* aSupports,
+                                          nsAutoPtr<PendingReadyPromise>& aData,
+                                          void* aPtr)
+{
+  ServiceWorkerManager* aSwm = static_cast<ServiceWorkerManager*>(aPtr);
+
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aSupports);
+
+  if (aSwm->CheckReadyPromise(window, aData->mURI, aData->mPromise)) {
+    return PL_DHASH_REMOVE;
+  }
+
+  return PL_DHASH_NEXT;
+}
+
+bool
+ServiceWorkerManager::CheckReadyPromise(nsPIDOMWindow* aWindow,
+                                        nsIURI* aURI, Promise* aPromise)
+{
+  nsRefPtr<ServiceWorkerRegistrationInfo> registration =
+    GetServiceWorkerRegistrationInfo(aURI);
+
+  if (registration && registration->mCurrentWorker) {
+    NS_ConvertUTF8toUTF16 scope(registration->mScope);
+    nsRefPtr<ServiceWorkerRegistration> swr =
+      new ServiceWorkerRegistration(aWindow, scope);
+    aPromise->MaybeResolve(swr);
+    return true;
+  }
+
+  return false;
+}
+
 void
 ServiceWorkerManager::RejectUpdatePromiseObservers(ServiceWorkerRegistrationInfo* aRegistration,
                                                    nsresult aRv)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aRegistration->HasUpdatePromise());
   aRegistration->mUpdatePromise->RejectAllPromises(aRv);
   aRegistration->mUpdatePromise = nullptr;
@@ -1404,16 +1537,18 @@ public:
     nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     swm->InvalidateServiceWorkerRegistrationWorker(mRegistration,
                                                    WhichServiceWorker::ACTIVE_WORKER | WhichServiceWorker::WAITING_WORKER);
     if (!mRegistration->mCurrentWorker) {
       // FIXME(nsm): Just got unregistered!
       return NS_OK;
     }
 
+    swm->CheckPendingReadyPromises();
+
     // FIXME(nsm): Steps 7 of the algorithm.
 
     swm->FireEventOnServiceWorkerRegistrations(mRegistration,
                                                NS_LITERAL_STRING("controllerchange"));
 
     MOZ_ASSERT(mRegistration->mCurrentWorker);
     nsRefPtr<ServiceWorker> serviceWorker;
     nsresult rv =
--- a/dom/workers/ServiceWorkerManager.h
+++ b/dom/workers/ServiceWorkerManager.h
@@ -15,16 +15,17 @@
 #include "mozilla/TypedEnumBits.h"
 #include "mozilla/WeakPtr.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/ServiceWorkerCommon.h"
 #include "nsRefPtrHashtable.h"
 #include "nsTArrayForwardDeclare.h"
 #include "nsTObserverArray.h"
+#include "nsClassHashtable.h"
 
 class nsIScriptError;
 
 namespace mozilla {
 namespace dom {
 
 class ServiceWorkerRegistration;
 
@@ -194,16 +195,17 @@ public:
 class ServiceWorkerManager MOZ_FINAL : public nsIServiceWorkerManager
 {
   friend class ActivationRunnable;
   friend class RegisterRunnable;
   friend class CallInstallRunnable;
   friend class CancelServiceWorkerInstallationRunnable;
   friend class ServiceWorkerRegistrationInfo;
   friend class ServiceWorkerUpdateInstance;
+  friend class GetReadyPromiseRunnable;
   friend class GetRegistrationsRunnable;
   friend class GetRegistrationRunnable;
   friend class UnregisterRunnable;
 
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSISERVICEWORKERMANAGER
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_SERVICEWORKERMANAGER_IMPL_IID)
@@ -384,16 +386,41 @@ private:
 
   static void
   RemoveScope(nsTArray<nsCString>& aList, const nsACString& aScope);
 
   void
   FireEventOnServiceWorkerRegistrations(ServiceWorkerRegistrationInfo* aRegistration,
                                         const nsAString& aName);
 
+  void
+  StorePendingReadyPromise(nsPIDOMWindow* aWindow, nsIURI* aURI, Promise* aPromise);
+
+  void
+  CheckPendingReadyPromises();
+
+  bool
+  CheckReadyPromise(nsPIDOMWindow* aWindow, nsIURI* aURI, Promise* aPromise);
+
+  struct PendingReadyPromise
+  {
+    PendingReadyPromise(nsIURI* aURI, Promise* aPromise)
+      : mURI(aURI), mPromise(aPromise)
+    { }
+
+    nsCOMPtr<nsIURI> mURI;
+    nsRefPtr<Promise> mPromise;
+  };
+
+  static PLDHashOperator
+  CheckPendingReadyPromisesEnumerator(nsISupports* aSupports,
+                                      nsAutoPtr<PendingReadyPromise>& aData,
+                                      void* aUnused);
+
+  nsClassHashtable<nsISupportsHashKey, PendingReadyPromise> mPendingReadyPromises;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(ServiceWorkerManager,
                               NS_SERVICEWORKERMANAGER_IMPL_IID);
 
 } // namespace workers
 } // namespace dom
 } // namespace mozilla
--- a/dom/workers/ServiceWorkerRegistration.cpp
+++ b/dom/workers/ServiceWorkerRegistration.cpp
@@ -8,64 +8,57 @@
 
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/ServiceWorkerRegistrationBinding.h"
 #include "mozilla/Services.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsServiceManagerUtils.h"
 #include "ServiceWorker.h"
 
-#include "nsIObserverService.h"
 #include "nsIServiceWorkerManager.h"
 #include "nsISupportsPrimitives.h"
 #include "nsPIDOMWindow.h"
 
 using namespace mozilla::dom::workers;
 
 namespace mozilla {
 namespace dom {
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ServiceWorkerRegistration)
-  NS_INTERFACE_MAP_ENTRY(nsIObserver)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(ServiceWorkerRegistration, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(ServiceWorkerRegistration, DOMEventTargetHelper)
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(ServiceWorkerRegistration,
                                    DOMEventTargetHelper,
-                                   mWindow,
                                    mInstallingWorker,
                                    mWaitingWorker,
                                    mActiveWorker)
 
 ServiceWorkerRegistration::ServiceWorkerRegistration(nsPIDOMWindow* aWindow,
                                                      const nsAString& aScope)
-  : mWindow(aWindow)
+  : DOMEventTargetHelper(aWindow)
   , mScope(aScope)
-  , mInnerID(0)
-  , mIsListeningForEvents(false)
 {
   MOZ_ASSERT(aWindow);
   MOZ_ASSERT(aWindow->IsInnerWindow());
 
-  SetIsDOMBinding();
   StartListeningForEvents();
-
-  mInnerID = aWindow->WindowID();
-
-  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
-  if (obs) {
-    obs->AddObserver(this, "inner-window-destroyed", false);
-  }
 }
 
 ServiceWorkerRegistration::~ServiceWorkerRegistration()
 {
+}
+
+void
+ServiceWorkerRegistration::DisconnectFromOwner()
+{
   StopListeningForEvents();
+  DOMEventTargetHelper::DisconnectFromOwner();
 }
 
 JSObject*
 ServiceWorkerRegistration::WrapObject(JSContext* aCx)
 {
   return ServiceWorkerRegistrationBinding::Wrap(aCx, this);
 }
 
@@ -133,23 +126,23 @@ ServiceWorkerRegistration::GetWorkerRefe
     do_GetService(SERVICEWORKERMANAGER_CONTRACTID, &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return nullptr;
   }
 
   nsCOMPtr<nsISupports> serviceWorker;
   switch(aWhichOne) {
     case WhichServiceWorker::INSTALLING_WORKER:
-      rv = swm->GetInstalling(mWindow, getter_AddRefs(serviceWorker));
+      rv = swm->GetInstalling(GetOwner(), getter_AddRefs(serviceWorker));
       break;
     case WhichServiceWorker::WAITING_WORKER:
-      rv = swm->GetWaiting(mWindow, getter_AddRefs(serviceWorker));
+      rv = swm->GetWaiting(GetOwner(), getter_AddRefs(serviceWorker));
       break;
     case WhichServiceWorker::ACTIVE_WORKER:
-      rv = swm->GetActive(mWindow, getter_AddRefs(serviceWorker));
+      rv = swm->GetActive(GetOwner(), getter_AddRefs(serviceWorker));
       break;
     default:
       MOZ_CRASH("Invalid enum value");
   }
 
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return nullptr;
   }
@@ -175,79 +168,32 @@ ServiceWorkerRegistration::InvalidateWor
   }
 }
 
 // XXXnsm, maybe this can be optimized to only add when a event handler is
 // registered.
 void
 ServiceWorkerRegistration::StartListeningForEvents()
 {
-  MOZ_ASSERT(!mIsListeningForEvents);
-
   nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID);
-  MOZ_ASSERT(mWindow);
-
   if (swm) {
     swm->AddRegistrationEventListener(GetDocumentURI(), this);
   }
-
-  mIsListeningForEvents = true;
 }
 
 void
 ServiceWorkerRegistration::StopListeningForEvents()
 {
-  if (!mIsListeningForEvents) {
-    return;
-  }
-
   nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID);
-
-  // StopListeningForEvents is called in the dtor, and it can happen that
-  // SnowWhite had already set to null mWindow.
-  if (swm && mWindow) {
+  if (swm) {
     swm->RemoveRegistrationEventListener(GetDocumentURI(), this);
   }
-
-  mIsListeningForEvents = false;
 }
 
 nsIURI*
 ServiceWorkerRegistration::GetDocumentURI() const
 {
-  MOZ_ASSERT(mWindow);
-  return mWindow->GetDocumentURI();
+  MOZ_ASSERT(GetOwner());
+  return GetOwner()->GetDocumentURI();
 }
 
-NS_IMETHODIMP
-ServiceWorkerRegistration::Observe(nsISupports* aSubject, const char* aTopic,
-                                   const char16_t* aData)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (strcmp(aTopic, "inner-window-destroyed")) {
-    return NS_OK;
-  }
-
-  if (!mIsListeningForEvents) {
-    return NS_OK;
-  }
-
-  nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
-  NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);
-
-  uint64_t innerID;
-  nsresult rv = wrapper->GetData(&innerID);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (innerID == mInnerID) {
-    nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
-    if (obs) {
-      obs->RemoveObserver(this, "inner-window-destroyed");
-    }
-
-    StopListeningForEvents();
-  }
-
-  return NS_OK;
-}
 } // dom namespace
 } // mozilla namespace
--- a/dom/workers/ServiceWorkerRegistration.h
+++ b/dom/workers/ServiceWorkerRegistration.h
@@ -17,35 +17,27 @@ namespace dom {
 
 class Promise;
 
 namespace workers {
 class ServiceWorker;
 }
 
 class ServiceWorkerRegistration MOZ_FINAL : public DOMEventTargetHelper
-                                          , public nsIObserver
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSIOBSERVER
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServiceWorkerRegistration,
                                            DOMEventTargetHelper)
 
   IMPL_EVENT_HANDLER(updatefound)
 
   ServiceWorkerRegistration(nsPIDOMWindow* aWindow,
                             const nsAString& aScope);
 
-  nsPIDOMWindow*
-  GetParentObject() const
-  {
-    return mWindow;
-  }
-
   JSObject*
   WrapObject(JSContext* aCx);
 
   already_AddRefed<workers::ServiceWorker>
   GetInstalling();
 
   already_AddRefed<workers::ServiceWorker>
   GetWaiting();
@@ -65,40 +57,38 @@ public:
   // Useful methods for ServiceWorkerManager:
 
   nsIURI*
   GetDocumentURI() const;
 
   void
   InvalidateWorkerReference(WhichServiceWorker aWhichOnes);
 
+  // DOMEventTargethelper
+  virtual void DisconnectFromOwner() MOZ_OVERRIDE;
+
 private:
   ~ServiceWorkerRegistration();
 
   already_AddRefed<workers::ServiceWorker>
   GetWorkerReference(WhichServiceWorker aWhichOne);
 
   void
   StartListeningForEvents();
 
   void
   StopListeningForEvents();
 
-  nsCOMPtr<nsPIDOMWindow> mWindow;
-
   // The following properties are cached here to ensure JS equality is satisfied
   // instead of acquiring a new worker instance from the ServiceWorkerManager
   // for every access. A null value is considered a cache miss.
   // These three may change to a new worker at any time.
   nsRefPtr<workers::ServiceWorker> mInstallingWorker;
   nsRefPtr<workers::ServiceWorker> mWaitingWorker;
   nsRefPtr<workers::ServiceWorker> mActiveWorker;
 
   const nsString mScope;
-
-  uint64_t mInnerID;
-  bool mIsListeningForEvents;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_ServiceWorkerRegistration_h */
--- a/dom/workers/test/serviceworkers/mochitest.ini
+++ b/dom/workers/test/serviceworkers/mochitest.ini
@@ -2,16 +2,17 @@
 run-if = os == "win" # Bug 1040924 - Failure prone on !Windows
 support-files =
   worker.js
   worker2.js
   worker3.js
   parse_error_worker.js
   install_event_worker.js
   simpleregister/index.html
+  simpleregister/ready.html
   controller/index.html
   unregister/index.html
 
 [test_installation_simple.html]
 [test_install_event.html]
 [test_navigator.html]
 [test_scopes.html]
 [test_controller.html]
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/simpleregister/ready.html
@@ -0,0 +1,15 @@
+<html>
+  <head></head>
+  <body>
+    <script type="text/javascript">
+
+       window.addEventListener('message', function(evt) {
+         navigator.serviceWorker.ready.then(function() {
+           evt.ports[0].postMessage("WOW!");
+         });
+       }, false);
+
+    </script>
+  </body>
+</html>
+
--- a/dom/workers/test/serviceworkers/test_installation_simple.html
+++ b/dom/workers/test/serviceworkers/test_installation_simple.html
@@ -136,37 +136,65 @@
         resolve();
       } else if (e.data.type == "check") {
         ok(e.data.status, e.data.msg);
       }
     }
     return p;
   }
 
+  var readyPromiseResolved = false;
+
+  function readyPromise() {
+    var frame = document.createElement("iframe");
+    frame.setAttribute("id", "simpleregister-frame-ready");
+    frame.setAttribute("src", new URL("simpleregister/ready.html", document.baseURI).href);
+    document.body.appendChild(frame);
+
+    var channel = new MessageChannel();
+    frame.addEventListener('load', function() {
+      frame.contentWindow.postMessage('your port!', '*', [channel.port2]);
+    }, false);
+
+    channel.port1.onmessage = function() {
+      readyPromiseResolved = true;
+    }
+
+    return Promise.resolve();
+  }
+
+  function checkReadyPromise() {
+    ok(readyPromiseResolved, "The ready promise has been resolved!");
+    return Promise.resolve();
+  }
+
   function runTest() {
     simpleRegister()
+      .then(readyPromise)
       .then(sameOriginWorker)
       .then(sameOriginScope)
       .then(httpsOnly)
       .then(realWorker)
       .then(abortPrevious)
       .then(networkError404)
       .then(parseError)
       .then(updatefound)
+      .then(checkReadyPromise)
       // put more tests here.
       .then(function() {
         SimpleTest.finish();
       }).catch(function(e) {
         ok(false, "Some test failed with error " + e);
         SimpleTest.finish();
       });
   }
 
   SimpleTest.waitForExplicitFinish();
   SpecialPowers.pushPrefEnv({"set": [
+    ["dom.messageChannel.enabled", true],
     ["dom.serviceWorkers.enabled", true],
     ["dom.serviceWorkers.testing.enabled", true]
   ]}, runTest);
 </script>
 </pre>
 </body>
 </html>
 
--- a/dom/xbl/XBLChildrenElement.cpp
+++ b/dom/xbl/XBLChildrenElement.cpp
@@ -76,17 +76,17 @@ XBLChildrenElement::ParseAttribute(int32
 using namespace mozilla::dom;
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsAnonymousContentList, mParent)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsAnonymousContentList)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsAnonymousContentList)
 
 NS_INTERFACE_TABLE_HEAD(nsAnonymousContentList)
-  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
   NS_INTERFACE_TABLE_INHERITED(nsAnonymousContentList, nsINodeList,
                                nsIDOMNodeList)
   NS_INTERFACE_TABLE_TO_MAP_SEGUE
   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsAnonymousContentList)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 NS_IMETHODIMP
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/crashtests/1057677.html
@@ -0,0 +1,9 @@
+<html><body></body><script>
+document.designMode = "on";
+var hrElem = document.createElement("HR");
+var select = window.getSelection();
+document.body.appendChild(hrElem);
+select.collapse(hrElem,0);
+document.execCommand("InsertHTML", false, "<div>foo</div><div>bar</div>");
+</script>
+</html>
--- a/editor/libeditor/crashtests/crashtests.list
+++ b/editor/libeditor/crashtests/crashtests.list
@@ -53,8 +53,9 @@ load 766795.html
 load 767169.html
 load 769967.xhtml
 load 768748.html
 load 768765.html
 needs-focus load 771749.html
 load 772282.html
 load 776323.html
 needs-focus load 793866.html
+load 1057677.html
--- a/editor/libeditor/nsEditorEventListener.cpp
+++ b/editor/libeditor/nsEditorEventListener.cpp
@@ -44,16 +44,17 @@
 #include "nsIPresShell.h"               // for nsIPresShell
 #include "nsISelection.h"               // for nsISelection
 #include "nsISelectionController.h"     // for nsISelectionController, etc
 #include "nsISelectionPrivate.h"        // for nsISelectionPrivate
 #include "nsITransferable.h"            // for kFileMime, kHTMLMime, etc
 #include "nsIWidget.h"                  // for nsIWidget
 #include "nsLiteralString.h"            // for NS_LITERAL_STRING
 #include "nsPIWindowRoot.h"             // for nsPIWindowRoot
+#include "nsPrintfCString.h"            // for nsPrintfCString
 #include "nsServiceManagerUtils.h"      // for do_GetService
 #include "nsString.h"                   // for nsAutoString
 #ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
 #include "nsContentUtils.h"             // for nsContentUtils, etc
 #include "nsIBidiKeyboard.h"            // for nsIBidiKeyboard
 #endif
 
 class nsPresContext;
@@ -85,19 +86,20 @@ DoCommandCallback(Command aCommand, void
   bool commandEnabled;
   nsresult rv = controller->IsCommandEnabled(commandStr, &commandEnabled);
   NS_ENSURE_SUCCESS_VOID(rv);
   if (commandEnabled) {
     controller->DoCommand(commandStr);
   }
 }
 
-nsEditorEventListener::nsEditorEventListener() :
-  mEditor(nullptr), mCommitText(false),
-  mInTransaction(false)
+nsEditorEventListener::nsEditorEventListener()
+  : mEditor(nullptr)
+  , mCommitText(false)
+  , mInTransaction(false)
 #ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
   , mHaveBidiKeyboards(false)
   , mShouldSwitchTextDirection(false)
   , mSwitchToRTL(false)
 #endif
 {
 }
 
@@ -305,60 +307,119 @@ NS_IMPL_ISUPPORTS(nsEditorEventListener,
 
 /**
  *  nsIDOMEventListener implementation
  */
 
 NS_IMETHODIMP
 nsEditorEventListener::HandleEvent(nsIDOMEvent* aEvent)
 {
-  NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
+  NS_ENSURE_TRUE(mEditor, NS_ERROR_FAILURE);
+
   nsCOMPtr<nsIEditor> kungFuDeathGrip = mEditor;
 
+  WidgetEvent* internalEvent = aEvent->GetInternalNSEvent();
+
+  // Let's handle each event with the message of the internal event of the
+  // coming event.  If the DOM event was created with improper interface,
+  // e.g., keydown event is created with |new MouseEvent("keydown", {});|,
+  // its message is always 0.  Therefore, we can ban such strange event easy.
+  // However, we need to handle strange "focus" and "blur" event.  See the
+  // following code of this switch statement.
+  // NOTE: Each event handler may require specific event interface.  Before
+  //       calling it, this queries the specific interface.  If it would fail,
+  //       each event handler would just ignore the event.  So, in this method,
+  //       you don't need to check if the QI succeeded before each call.
+  switch (internalEvent->message) {
+    // dragenter
+    case NS_DRAGDROP_ENTER: {
+      nsCOMPtr<nsIDOMDragEvent> dragEvent = do_QueryInterface(aEvent);
+      return DragEnter(dragEvent);
+    }
+    // dragover
+    case NS_DRAGDROP_OVER_SYNTH: {
+      nsCOMPtr<nsIDOMDragEvent> dragEvent = do_QueryInterface(aEvent);
+      return DragOver(dragEvent);
+    }
+    // dragexit
+    case NS_DRAGDROP_EXIT_SYNTH: {
+      nsCOMPtr<nsIDOMDragEvent> dragEvent = do_QueryInterface(aEvent);
+      return DragExit(dragEvent);
+    }
+    // drop
+    case NS_DRAGDROP_DROP: {
+      nsCOMPtr<nsIDOMDragEvent> dragEvent = do_QueryInterface(aEvent);
+      return Drop(dragEvent);
+    }
+#ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
+    // keydown
+    case NS_KEY_DOWN: {
+      nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aEvent);
+      return KeyDown(keyEvent);
+    }
+    // keyup
+    case NS_KEY_UP: {
+      nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aEvent);
+      return KeyUp(keyEvent);
+    }
+#endif // #ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
+    // keypress
+    case NS_KEY_PRESS: {
+      nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aEvent);
+      return KeyPress(keyEvent);
+    }
+    // mousedown
+    case NS_MOUSE_BUTTON_DOWN: {
+      nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
+      return MouseDown(mouseEvent);
+    }
+    // mouseup
+    case NS_MOUSE_BUTTON_UP: {
+      nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
+      return MouseUp(mouseEvent);
+    }
+    // click
+    case NS_MOUSE_CLICK: {
+      nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
+      return MouseClick(mouseEvent);
+    }
+    // focus
+    case NS_FOCUS_CONTENT:
+      return Focus(aEvent);
+    // blur
+    case NS_BLUR_CONTENT:
+      return Blur(aEvent);
+    // text
+    case NS_TEXT_TEXT:
+      return HandleText(aEvent);
+    // compositionstart
+    case NS_COMPOSITION_START:
+      return HandleStartComposition(aEvent);
+    // compositionend
+    case NS_COMPOSITION_END:
+      HandleEndComposition(aEvent);
+      return NS_OK;
+  }
+
   nsAutoString eventType;
   aEvent->GetType(eventType);
-
-  nsCOMPtr<nsIDOMDragEvent> dragEvent = do_QueryInterface(aEvent);
-  if (dragEvent) {
-    if (eventType.EqualsLiteral("dragenter"))
-      return DragEnter(dragEvent);
-    if (eventType.EqualsLiteral("dragover"))
-      return DragOver(dragEvent);
-    if (eventType.EqualsLiteral("dragexit"))
-      return DragExit(dragEvent);
-    if (eventType.EqualsLiteral("drop"))
-      return Drop(dragEvent);
+  // We should accept "focus" and "blur" event even if it's synthesized with
+  // wrong interface for compatibility with older Gecko.
+  if (eventType.EqualsLiteral("focus")) {
+    return Focus(aEvent);
   }
-
-#ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
-  if (eventType.EqualsLiteral("keydown"))
-    return KeyDown(aEvent);
-  if (eventType.EqualsLiteral("keyup"))
-    return KeyUp(aEvent);
+  if (eventType.EqualsLiteral("blur")) {
+    return Blur(aEvent);
+  }
+#ifdef DEBUG
+  nsPrintfCString assertMessage("Editor doesn't handle \"%s\" event "
+    "because its internal event doesn't have proper message",
+    NS_ConvertUTF16toUTF8(eventType).get());
+  NS_ASSERTION(false, assertMessage.get());
 #endif
-  if (eventType.EqualsLiteral("keypress"))
-    return KeyPress(aEvent);
-  if (eventType.EqualsLiteral("mousedown"))
-    return MouseDown(aEvent);
-  if (eventType.EqualsLiteral("mouseup"))
-    return MouseUp(aEvent);
-  if (eventType.EqualsLiteral("click"))
-    return MouseClick(aEvent);
-  if (eventType.EqualsLiteral("focus"))
-    return Focus(aEvent);
-  if (eventType.EqualsLiteral("blur"))
-    return Blur(aEvent);
-  if (eventType.EqualsLiteral("text"))
-    return HandleText(aEvent);
-  if (eventType.EqualsLiteral("compositionstart"))
-    return HandleStartComposition(aEvent);
-  if (eventType.EqualsLiteral("compositionend")) {
-    HandleEndComposition(aEvent);
-    return NS_OK;
-  }
 
   return NS_OK;
 }
 
 #ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
 #include <windows.h>
 // Undo the windows.h damage
 #undef GetMessage
@@ -382,18 +443,19 @@ bool IsCtrlShiftPressed(bool& isRTL)
   // (or a left-shift key), we use the steps below:
   // 1. Check if a user is pressing a control key and a right-shift key (or
   //    a left-shift key).
   // 2. If the condition 1 is true, we should check if there are any other
   //    keys pressed at the same time.
   //    To ignore the keys checked in 1, we set their status to 0 before
   //    checking the key status.
   const int kKeyDownMask = 0x80;
-  if ((keystate[VK_CONTROL] & kKeyDownMask) == 0)
+  if ((keystate[VK_CONTROL] & kKeyDownMask) == 0) {
     return false;
+  }
 
   if (keystate[VK_RSHIFT] & kKeyDownMask) {
     keystate[VK_RSHIFT] = 0;
     isRTL = true;
   } else if (keystate[VK_LSHIFT] & kKeyDownMask) {
     keystate[VK_LSHIFT] = 0;
     isRTL = false;
   } else {
@@ -406,85 +468,79 @@ bool IsCtrlShiftPressed(bool& isRTL)
   // right-shift key (or a left-shift key), i.e. we should ignore the status of
   // the keys: VK_SHIFT, VK_CONTROL, VK_RCONTROL, and VK_LCONTROL.
   // So, we reset their status to 0 and ignore them.
   keystate[VK_SHIFT] = 0;
   keystate[VK_CONTROL] = 0;
   keystate[VK_RCONTROL] = 0;
   keystate[VK_LCONTROL] = 0;
   for (int i = 0; i <= VK_PACKET; ++i) {
-    if (keystate[i] & kKeyDownMask)
+    if (keystate[i] & kKeyDownMask) {
       return false;
+    }
   }
   return true;
 }
 
 }
 
 // This logic is mostly borrowed from Chromium's
 // RenderWidgetHostViewWin::OnKeyEvent.
 
-NS_IMETHODIMP
-nsEditorEventListener::KeyUp(nsIDOMEvent* aKeyEvent)
+nsresult
+nsEditorEventListener::KeyUp(nsIDOMKeyEvent* aKeyEvent)
 {
-  if (mHaveBidiKeyboards) {
-    nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aKeyEvent);
-    if (!keyEvent) {
-      // non-key event passed to keyup.  bad things.
-      return NS_OK;
-    }
+  NS_ENSURE_TRUE(aKeyEvent, NS_OK);
 
-    uint32_t keyCode = 0;
-    keyEvent->GetKeyCode(&keyCode);
-    if (keyCode == nsIDOMKeyEvent::DOM_VK_SHIFT ||
-        keyCode == nsIDOMKeyEvent::DOM_VK_CONTROL) {
-      if (mShouldSwitchTextDirection && mEditor->IsPlaintextEditor()) {
-        mEditor->SwitchTextDirectionTo(mSwitchToRTL ?
-          nsIPlaintextEditor::eEditorRightToLeft :
-          nsIPlaintextEditor::eEditorLeftToRight);
-        mShouldSwitchTextDirection = false;
-      }
-    }
+  if (!mHaveBidiKeyboards) {
+    return NS_OK;
   }
 
+  uint32_t keyCode = 0;
+  aKeyEvent->GetKeyCode(&keyCode);
+  if ((keyCode == nsIDOMKeyEvent::DOM_VK_SHIFT ||
+       keyCode == nsIDOMKeyEvent::DOM_VK_CONTROL) &&
+      mShouldSwitchTextDirection && mEditor->IsPlaintextEditor()) {
+    mEditor->SwitchTextDirectionTo(mSwitchToRTL ?
+      nsIPlaintextEditor::eEditorRightToLeft :
+      nsIPlaintextEditor::eEditorLeftToRight);
+    mShouldSwitchTextDirection = false;
+  }
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsEditorEventListener::KeyDown(nsIDOMEvent* aKeyEvent)
+nsresult
+nsEditorEventListener::KeyDown(nsIDOMKeyEvent* aKeyEvent)
 {
-  if (mHaveBidiKeyboards) {
-    nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aKeyEvent);
-    if (!keyEvent) {
-      // non-key event passed to keydown.  bad things.
-      return NS_OK;
-    }
+  NS_ENSURE_TRUE(aKeyEvent, NS_OK);
 
-    uint32_t keyCode = 0;
-    keyEvent->GetKeyCode(&keyCode);
-    if (keyCode == nsIDOMKeyEvent::DOM_VK_SHIFT) {
-      bool switchToRTL;
-      if (IsCtrlShiftPressed(switchToRTL)) {
-        mShouldSwitchTextDirection = true;
-        mSwitchToRTL = switchToRTL;
-      }
-    } else if (keyCode != nsIDOMKeyEvent::DOM_VK_CONTROL) {
-      // In case the user presses any other key besides Ctrl and Shift
-      mShouldSwitchTextDirection = false;
-    }
+  if (!mHaveBidiKeyboards) {
+    return NS_OK;
   }
 
+  uint32_t keyCode = 0;
+  aKeyEvent->GetKeyCode(&keyCode);
+  if (keyCode == nsIDOMKeyEvent::DOM_VK_SHIFT) {
+    bool switchToRTL;
+    if (IsCtrlShiftPressed(switchToRTL)) {
+      mShouldSwitchTextDirection = true;
+      mSwitchToRTL = switchToRTL;
+    }
+  } else if (keyCode != nsIDOMKeyEvent::DOM_VK_CONTROL) {
+    // In case the user presses any other key besides Ctrl and Shift
+    mShouldSwitchTextDirection = false;
+  }
   return NS_OK;
 }
 #endif
 
-NS_IMETHODIMP
-nsEditorEventListener::KeyPress(nsIDOMEvent* aKeyEvent)
+nsresult
+nsEditorEventListener::KeyPress(nsIDOMKeyEvent* aKeyEvent)
 {
-  NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
+  NS_ENSURE_TRUE(aKeyEvent, NS_OK);
 
   if (!mEditor->IsAcceptableInputEvent(aKeyEvent)) {
     return NS_OK;
   }
 
   // DOM event handling happens in two passes, the client pass and the system
   // pass.  We do all of our processing in the system pass, to allow client
   // handlers the opportunity to cancel events and prevent typing in the editor.
@@ -492,64 +548,56 @@ nsEditorEventListener::KeyPress(nsIDOMEv
   // below.
 
   bool defaultPrevented;
   aKeyEvent->GetDefaultPrevented(&defaultPrevented);
   if (defaultPrevented) {
     return NS_OK;
   }
 
-  nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aKeyEvent);
-  if (!keyEvent) {
-    //non-key event passed to keypress.  bad things.
-    return NS_OK;
-  }
-
-  nsresult rv = mEditor->HandleKeyPressEvent(keyEvent);
+  nsresult rv = mEditor->HandleKeyPressEvent(aKeyEvent);
   NS_ENSURE_SUCCESS(rv, rv);
 
   aKeyEvent->GetDefaultPrevented(&defaultPrevented);
   if (defaultPrevented) {
     return NS_OK;
   }
 
-  if (ShouldHandleNativeKeyBindings(aKeyEvent)) {
-    // Now, ask the native key bindings to handle the event.
-    WidgetKeyboardEvent* keyEvent =
-      aKeyEvent->GetInternalNSEvent()->AsKeyboardEvent();
-    MOZ_ASSERT(keyEvent,
-               "DOM key event's internal event must be WidgetKeyboardEvent");
-    nsIWidget* widget = keyEvent->widget;
-    // If the event is created by chrome script, the widget is always nullptr.
-    if (!widget) {
-      nsCOMPtr<nsIPresShell> ps = GetPresShell();
-      nsPresContext* pc = ps ? ps->GetPresContext() : nullptr;
-      widget = pc ? pc->GetNearestWidget() : nullptr;
-      NS_ENSURE_TRUE(widget, NS_OK);
-    }
-
-    nsCOMPtr<nsIDocument> doc = mEditor->GetDocument();
-    bool handled = widget->ExecuteNativeKeyBinding(
-                             nsIWidget::NativeKeyBindingsForRichTextEditor,
-                             *keyEvent, DoCommandCallback, doc);
-    if (handled) {
-      aKeyEvent->PreventDefault();
-    }
+  if (!ShouldHandleNativeKeyBindings(aKeyEvent)) {
+    return NS_OK;
   }
 
+  // Now, ask the native key bindings to handle the event.
+  WidgetKeyboardEvent* keyEvent =
+    aKeyEvent->GetInternalNSEvent()->AsKeyboardEvent();
+  MOZ_ASSERT(keyEvent,
+             "DOM key event's internal event must be WidgetKeyboardEvent");
+  nsIWidget* widget = keyEvent->widget;
+  // If the event is created by chrome script, the widget is always nullptr.
+  if (!widget) {
+    nsCOMPtr<nsIPresShell> ps = GetPresShell();
+    nsPresContext* pc = ps ? ps->GetPresContext() : nullptr;
+    widget = pc ? pc->GetNearestWidget() : nullptr;
+    NS_ENSURE_TRUE(widget, NS_OK);
+  }
+
+  nsCOMPtr<nsIDocument> doc = mEditor->GetDocument();
+  bool handled = widget->ExecuteNativeKeyBinding(
+                           nsIWidget::NativeKeyBindingsForRichTextEditor,
+                           *keyEvent, DoCommandCallback, doc);
+  if (handled) {
+    aKeyEvent->PreventDefault();
+  }
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsEditorEventListener::MouseClick(nsIDOMEvent* aMouseEvent)
+nsresult
+nsEditorEventListener::MouseClick(nsIDOMMouseEvent* aMouseEvent)
 {
-  NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
-
-  nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aMouseEvent);
-  NS_ENSURE_TRUE(mouseEvent, NS_OK);
+  NS_ENSURE_TRUE(aMouseEvent, NS_OK);
 
   // nothing to do if editor isn't editable or clicked on out of the editor.
   if (mEditor->IsReadonly() || mEditor->IsDisabled() ||
       !mEditor->IsAcceptableInputEvent(aMouseEvent)) {
     return NS_OK;
   }
 
   // Notifies clicking on editor to IMEStateManager even when the event was
@@ -558,100 +606,111 @@ nsEditorEventListener::MouseClick(nsIDOM
   if (focusedContent) {
     nsIDocument* currentDoc = focusedContent->GetCurrentDoc();
     nsCOMPtr<nsIPresShell> presShell = GetPresShell();
     nsPresContext* presContext =
       presShell ? presShell->GetPresContext() : nullptr;
     if (presContext && currentDoc) {
       IMEStateManager::OnClickInEditor(presContext,
         currentDoc->HasFlag(NODE_IS_EDITABLE) ? nullptr : focusedContent,
-        mouseEvent);
+        aMouseEvent);
     }
   }
 
   bool preventDefault;
   nsresult rv = aMouseEvent->GetDefaultPrevented(&preventDefault);
   if (NS_FAILED(rv) || preventDefault) {
     // We're done if 'preventdefault' is true (see for example bug 70698).
     return rv;
   }
 
   // If we got a mouse down inside the editing area, we should force the 
   // IME to commit before we change the cursor position
   mEditor->ForceCompositionEnd();
 
   int16_t button = -1;
-  mouseEvent->GetButton(&button);
-  // middle-mouse click (paste);
-  if (button == 1)
-  {
-    if (Preferences::GetBool("middlemouse.paste", false))
-    {
-      // Set the selection to the point under the mouse cursor:
-      nsCOMPtr<nsIDOMNode> parent;
-      if (NS_FAILED(mouseEvent->GetRangeParent(getter_AddRefs(parent))))
-        return NS_ERROR_NULL_POINTER;
-      int32_t offset = 0;
-      if (NS_FAILED(mouseEvent->GetRangeOffset(&offset)))
-        return NS_ERROR_NULL_POINTER;
-
-      nsCOMPtr<nsISelection> selection;
-      if (NS_SUCCEEDED(mEditor->GetSelection(getter_AddRefs(selection))))
-        (void)selection->Collapse(parent, offset);
-
-      // If the ctrl key is pressed, we'll do paste as quotation.
-      // Would've used the alt key, but the kde wmgr treats alt-middle specially. 
-      bool ctrlKey = false;
-      mouseEvent->GetCtrlKey(&ctrlKey);
-
-      nsCOMPtr<nsIEditorMailSupport> mailEditor;
-      if (ctrlKey)
-        mailEditor = do_QueryObject(mEditor);
-
-      int32_t clipboard = nsIClipboard::kGlobalClipboard;
-      nsCOMPtr<nsIClipboard> clipboardService =
-        do_GetService("@mozilla.org/widget/clipboard;1", &rv);
-      if (NS_SUCCEEDED(rv)) {
-        bool selectionSupported;
-        rv = clipboardService->SupportsSelectionClipboard(&selectionSupported);
-        if (NS_SUCCEEDED(rv) && selectionSupported) {
-          clipboard = nsIClipboard::kSelectionClipboard;
-        }
-      }
-
-      if (mailEditor)
-        mailEditor->PasteAsQuotation(clipboard);
-      else
-        mEditor->Paste(clipboard);
-
-      // Prevent the event from propagating up to be possibly handled
-      // again by the containing window:
-      mouseEvent->StopPropagation();
-      mouseEvent->PreventDefault();
-
-      // We processed the event, whether drop/paste succeeded or not
-      return NS_OK;
-    }
+  aMouseEvent->GetButton(&button);
+  if (button == 1) {
+    return HandleMiddleClickPaste(aMouseEvent);
   }
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsEditorEventListener::MouseDown(nsIDOMEvent* aMouseEvent)
+nsresult
+nsEditorEventListener::HandleMiddleClickPaste(nsIDOMMouseEvent* aMouseEvent)
 {
-  NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
+  if (!Preferences::GetBool("middlemouse.paste", false)) {
+    // Middle click paste isn't enabled.
+    return NS_OK;
+  }
+
+  // Set the selection to the point under the mouse cursor:
+  nsCOMPtr<nsIDOMNode> parent;
+  if (NS_FAILED(aMouseEvent->GetRangeParent(getter_AddRefs(parent)))) {
+    return NS_ERROR_NULL_POINTER;
+  }
+  int32_t offset = 0;
+  if (NS_FAILED(aMouseEvent->GetRangeOffset(&offset))) {
+    return NS_ERROR_NULL_POINTER;
+  }
+
+  nsCOMPtr<nsISelection> selection;
+  if (NS_SUCCEEDED(mEditor->GetSelection(getter_AddRefs(selection)))) {
+    selection->Collapse(parent, offset);
+  }
+
+  // If the ctrl key is pressed, we'll do paste as quotation.
+  // Would've used the alt key, but the kde wmgr treats alt-middle specially. 
+  bool ctrlKey = false;
+  aMouseEvent->GetCtrlKey(&ctrlKey);
+
+  nsCOMPtr<nsIEditorMailSupport> mailEditor;
+  if (ctrlKey) {
+    mailEditor = do_QueryObject(mEditor);
+  }
+
+  nsresult rv;
+  int32_t clipboard = nsIClipboard::kGlobalClipboard;
+  nsCOMPtr<nsIClipboard> clipboardService =
+    do_GetService("@mozilla.org/widget/clipboard;1", &rv);
+  if (NS_SUCCEEDED(rv)) {
+    bool selectionSupported;
+    rv = clipboardService->SupportsSelectionClipboard(&selectionSupported);
+    if (NS_SUCCEEDED(rv) && selectionSupported) {
+      clipboard = nsIClipboard::kSelectionClipboard;
+    }
+  }
+
+  if (mailEditor) {
+    mailEditor->PasteAsQuotation(clipboard);
+  } else {
+    mEditor->Paste(clipboard);
+  }
+
+  // Prevent the event from propagating up to be possibly handled
+  // again by the containing window:
+  aMouseEvent->StopPropagation();
+  aMouseEvent->PreventDefault();
+
+  // We processed the event, whether drop/paste succeeded or not
+  return NS_OK;
+}
+
+nsresult
+nsEditorEventListener::MouseDown(nsIDOMMouseEvent* aMouseEvent)
+{
+  NS_ENSURE_TRUE(aMouseEvent, NS_OK);
+
   mEditor->ForceCompositionEnd();
   return NS_OK;
 }
 
-NS_IMETHODIMP
+nsresult
 nsEditorEventListener::HandleText(nsIDOMEvent* aTextEvent)
 {
-  NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
-
   if (!mEditor->IsAcceptableInputEvent(aTextEvent)) {
     return NS_OK;
   }
 
   // if we are readonly or disabled, then do nothing.
   if (mEditor->IsReadonly() || mEditor->IsDisabled()) {
     return NS_OK;
   }
@@ -661,16 +720,18 @@ nsEditorEventListener::HandleText(nsIDOM
 
 /**
  * Drag event implementation
  */
 
 nsresult
 nsEditorEventListener::DragEnter(nsIDOMDragEvent* aDragEvent)
 {
+  NS_ENSURE_TRUE(aDragEvent, NS_OK);
+
   nsCOMPtr<nsIPresShell> presShell = GetPresShell();
   NS_ENSURE_TRUE(presShell, NS_OK);
 
   if (!mCaret) {
     mCaret = new nsCaret();
     mCaret->Init(presShell);
     mCaret->SetCaretReadOnly(true);
   }
@@ -678,118 +739,124 @@ nsEditorEventListener::DragEnter(nsIDOMD
   presShell->SetCaret(mCaret);
 
   return DragOver(aDragEvent);
 }
 
 nsresult
 nsEditorEventListener::DragOver(nsIDOMDragEvent* aDragEvent)
 {
+  NS_ENSURE_TRUE(aDragEvent, NS_OK);
+
   nsCOMPtr<nsIDOMNode> parent;
   bool defaultPrevented;
   aDragEvent->GetDefaultPrevented(&defaultPrevented);
   if (defaultPrevented) {
     return NS_OK;
   }
 
   aDragEvent->GetRangeParent(getter_AddRefs(parent));
   nsCOMPtr<nsIContent> dropParent = do_QueryInterface(parent);
   NS_ENSURE_TRUE(dropParent, NS_ERROR_FAILURE);
 
   if (dropParent->IsEditable() && CanDrop(aDragEvent)) {
     aDragEvent->PreventDefault(); // consumed
 
-    if (mCaret) {
-      int32_t offset = 0;
-      nsresult rv = aDragEvent->GetRangeOffset(&offset);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      mCaret->SetVisible(true);
-      mCaret->SetCaretPosition(parent, offset);
-    }
-  }
-  else
-  {
-    if (!IsFileControlTextBox()) {
-      // This is needed when dropping on an input, to prevent the editor for
-      // the editable parent from receiving the event.
-      aDragEvent->StopPropagation();
+    if (!mCaret) {
+      return NS_OK;
     }
 
-    if (mCaret)
-    {
-      mCaret->SetVisible(false);
-    }
+    int32_t offset = 0;
+    nsresult rv = aDragEvent->GetRangeOffset(&offset);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    mCaret->SetVisible(true);
+    mCaret->SetCaretPosition(parent, offset);
+
+    return NS_OK;
   }
 
+  if (!IsFileControlTextBox()) {
+    // This is needed when dropping on an input, to prevent the editor for
+    // the editable parent from receiving the event.
+    aDragEvent->StopPropagation();
+  }
+
+  if (mCaret) {
+    mCaret->SetVisible(false);
+  }
   return NS_OK;
 }
 
 void
 nsEditorEventListener::CleanupDragDropCaret()
 {
-  if (mCaret)
-  {
-    mCaret->SetVisible(false);    // hide it, so that it turns off its timer
+  if (!mCaret) {
+    return;
+  }
+
+  mCaret->SetVisible(false);    // hide it, so that it turns off its timer
 
-    nsCOMPtr<nsIPresShell> presShell = GetPresShell();
-    if (presShell)
-    {
-      nsCOMPtr<nsISelectionController> selCon(do_QueryInterface(presShell));
-      if (selCon) {
-        selCon->SetCaretEnabled(false);
-      }
-      presShell->RestoreCaret();
+  nsCOMPtr<nsIPresShell> presShell = GetPresShell();
+  if (presShell) {
+    nsCOMPtr<nsISelectionController> selCon(do_QueryInterface(presShell));
+    if (selCon) {
+      selCon->SetCaretEnabled(false);
     }
+    presShell->RestoreCaret();
+  }
 
-    mCaret->Terminate();
-    mCaret = nullptr;
-  }
+  mCaret->Terminate();
+  mCaret = nullptr;
 }
 
 nsresult
 nsEditorEventListener::DragExit(nsIDOMDragEvent* aDragEvent)
 {
+  NS_ENSURE_TRUE(aDragEvent, NS_OK);
+
   CleanupDragDropCaret();
 
   return NS_OK;
 }
 
 nsresult
-nsEditorEventListener::Drop(nsIDOMDragEvent* aMouseEvent)
+nsEditorEventListener::Drop(nsIDOMDragEvent* aDragEvent)
 {
+  NS_ENSURE_TRUE(aDragEvent, NS_OK);
+
   CleanupDragDropCaret();
 
   bool defaultPrevented;
-  aMouseEvent->GetDefaultPrevented(&defaultPrevented);
+  aDragEvent->GetDefaultPrevented(&defaultPrevented);
   if (defaultPrevented) {
     return NS_OK;
   }
 
   nsCOMPtr<nsIDOMNode> parent;
-  aMouseEvent->GetRangeParent(getter_AddRefs(parent));
+  aDragEvent->GetRangeParent(getter_AddRefs(parent));
   nsCOMPtr<nsIContent> dropParent = do_QueryInterface(parent);
   NS_ENSURE_TRUE(dropParent, NS_ERROR_FAILURE);
 
-  if (!dropParent->IsEditable() || !CanDrop(aMouseEvent)) {
+  if (!dropParent->IsEditable() || !CanDrop(aDragEvent)) {
     // was it because we're read-only?
     if ((mEditor->IsReadonly() || mEditor->IsDisabled()) &&
         !IsFileControlTextBox()) {
       // it was decided to "eat" the event as this is the "least surprise"
       // since someone else handling it might be unintentional and the 
       // user could probably re-drag to be not over the disabled/readonly 
       // editfields if that is what is desired.
-      return aMouseEvent->StopPropagation();
+      return aDragEvent->StopPropagation();
     }
     return NS_OK;
   }
 
-  aMouseEvent->StopPropagation();
-  aMouseEvent->PreventDefault();
-  return mEditor->InsertFromDrop(aMouseEvent);
+  aDragEvent->StopPropagation();
+  aDragEvent->PreventDefault();
+  return mEditor->InsertFromDrop(aDragEvent);
 }
 
 bool
 nsEditorEventListener::CanDrop(nsIDOMDragEvent* aEvent)
 {
   // if the target doc is read-only, we can't drop
   if (mEditor->IsReadonly() || mEditor->IsDisabled()) {
     return false;
@@ -812,95 +879,103 @@ nsEditorEventListener::CanDrop(nsIDOMDra
     return false;
   }
 
   // If there is no source node, this is probably an external drag and the
   // drop is allowed. The later checks rely on checking if the drag target
   // is the same as the drag source.
   nsCOMPtr<nsIDOMNode> sourceNode;
   dataTransfer->GetMozSourceNode(getter_AddRefs(sourceNode));
-  if (!sourceNode)
+  if (!sourceNode) {
     return true;
+  }
 
   // There is a source node, so compare the source documents and this document.
   // Disallow drops on the same document.
 
   nsCOMPtr<nsIDOMDocument> domdoc = mEditor->GetDOMDocument();
   NS_ENSURE_TRUE(domdoc, false);
 
   nsCOMPtr<nsIDOMDocument> sourceDoc;
   nsresult rv = sourceNode->GetOwnerDocument(getter_AddRefs(sourceDoc));
   NS_ENSURE_SUCCESS(rv, false);
-  if (domdoc == sourceDoc)      // source and dest are the same document; disallow drops within the selection
-  {
-    nsCOMPtr<nsISelection> selection;
-    rv = mEditor->GetSelection(getter_AddRefs(selection));
-    if (NS_FAILED(rv) || !selection)
-      return false;
-    
-    // Don't bother if collapsed - can always drop
-    if (!selection->Collapsed()) {
-      nsCOMPtr<nsIDOMNode> parent;
-      rv = aEvent->GetRangeParent(getter_AddRefs(parent));
-      if (NS_FAILED(rv) || !parent) return false;
+
+  // If the source and the dest are not same document, allow to drop it always.
+  if (domdoc != sourceDoc) {
+    return true;
+  }
 
-      int32_t offset = 0;
-      rv = aEvent->GetRangeOffset(&offset);
-      NS_ENSURE_SUCCESS(rv, false);
+  nsCOMPtr<nsISelection> selection;
+  rv = mEditor->GetSelection(getter_AddRefs(selection));
+  if (NS_FAILED(rv) || !selection) {
+    return false;
+  }
+
+  // If selection is collapsed, allow to drop it always.
+  if (selection->Collapsed()) {
+    return true;
+  }
 
-      int32_t rangeCount;
-      rv = selection->GetRangeCount(&rangeCount);
-      NS_ENSURE_SUCCESS(rv, false);
+  nsCOMPtr<nsIDOMNode> parent;
+  rv = aEvent->GetRangeParent(getter_AddRefs(parent));
+  if (NS_FAILED(rv) || !parent) {
+    return false;
+  }
+
+  int32_t offset = 0;
+  rv = aEvent->GetRangeOffset(&offset);
+  NS_ENSURE_SUCCESS(rv, false);
+
+  int32_t rangeCount;
+  rv = selection->GetRangeCount(&rangeCount);
+  NS_ENSURE_SUCCESS(rv, false);
 
-      for (int32_t i = 0; i < rangeCount; i++)
-      {
-        nsCOMPtr<nsIDOMRange> range;
-        rv = selection->GetRangeAt(i, getter_AddRefs(range));
-        if (NS_FAILED(rv) || !range) 
-          continue; //don't bail yet, iterate through them all
+  for (int32_t i = 0; i < rangeCount; i++) {
+    nsCOMPtr<nsIDOMRange> range;
+    rv = selection->GetRangeAt(i, getter_AddRefs(range));
+    if (NS_FAILED(rv) || !range) {
+      // Don't bail yet, iterate through them all
+      continue;
+    }
 
-        bool inRange = true;
-        (void)range->IsPointInRange(parent, offset, &inRange);
-        if (inRange)
-          return false;  //okay, now you can bail, we are over the orginal selection
-      }
+    bool inRange = true;
+    range->IsPointInRange(parent, offset, &inRange);
+    if (inRange) {
+      // Okay, now you can bail, we are over the orginal selection
+      return false;
     }
   }
-  
   return true;
 }
 
-NS_IMETHODIMP
+nsresult
 nsEditorEventListener::HandleStartComposition(nsIDOMEvent* aCompositionEvent)
 {
-  NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
   if (!mEditor->IsAcceptableInputEvent(aCompositionEvent)) {
     return NS_OK;
   }
   WidgetCompositionEvent* compositionStart =
     aCompositionEvent->GetInternalNSEvent()->AsCompositionEvent();
   return mEditor->BeginIMEComposition(compositionStart);
 }
 
 void
 nsEditorEventListener::HandleEndComposition(nsIDOMEvent* aCompositionEvent)
 {
-  MOZ_ASSERT(mEditor);
   if (!mEditor->IsAcceptableInputEvent(aCompositionEvent)) {
     return;
   }
 
   mEditor->EndIMEComposition();
 }
 
-NS_IMETHODIMP
+nsresult
 nsEditorEventListener::Focus(nsIDOMEvent* aEvent)
 {
-  NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
-  NS_ENSURE_ARG(aEvent);
+  NS_ENSURE_TRUE(aEvent, NS_OK);
 
   // Don't turn on selection and caret when the editor is disabled.
   if (mEditor->IsDisabled()) {
     return NS_OK;
   }
 
   // Spell check a textarea the first time that it is focused.
   SpellCheckIfNeeded();
@@ -929,81 +1004,80 @@ nsEditorEventListener::Focus(nsIDOMEvent
     // make sure that the element is really focused in case an earlier
     // listener in the chain changed the focus.
     if (editableRoot) {
       nsIFocusManager* fm = nsFocusManager::GetFocusManager();
       NS_ENSURE_TRUE(fm, NS_OK);
 
       nsCOMPtr<nsIDOMElement> element;
       fm->GetFocusedElement(getter_AddRefs(element));
-      if (!SameCOMIdentity(element, target))
+      if (!SameCOMIdentity(element, target)) {
         return NS_OK;
+      }
     }
   }
 
   mEditor->OnFocus(target);
 
   nsCOMPtr<nsIPresShell> ps = GetPresShell();
   NS_ENSURE_TRUE(ps, NS_OK);
   nsCOMPtr<nsIContent> focusedContent = mEditor->GetFocusedContentForIME();
   IMEStateManager::OnFocusInEditor(ps->GetPresContext(), focusedContent);
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
+nsresult
 nsEditorEventListener::Blur(nsIDOMEvent* aEvent)
 {
-  NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
-  NS_ENSURE_ARG(aEvent);
+  NS_ENSURE_TRUE(aEvent, NS_OK);
 
   // check if something else is focused. If another element is focused, then
   // we should not change the selection.
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   NS_ENSURE_TRUE(fm, NS_OK);
 
   nsCOMPtr<nsIDOMElement> element;
   fm->GetFocusedElement(getter_AddRefs(element));
-  if (element)
-    return NS_OK;
-
-  mEditor->FinalizeSelection();
+  if (!element) {
+    mEditor->FinalizeSelection();
+  }
   return NS_OK;
 }
 
 void
-nsEditorEventListener::SpellCheckIfNeeded() {
+nsEditorEventListener::SpellCheckIfNeeded()
+{
   // If the spell check skip flag is still enabled from creation time,
   // disable it because focused editors are allowed to spell check.
   uint32_t currentFlags = 0;
   mEditor->GetFlags(&currentFlags);
-  if(currentFlags & nsIPlaintextEditor::eEditorSkipSpellCheck)
-  {
+  if(currentFlags & nsIPlaintextEditor::eEditorSkipSpellCheck) {
     currentFlags ^= nsIPlaintextEditor::eEditorSkipSpellCheck;
     mEditor->SetFlags(currentFlags);
   }
 }
 
 bool
 nsEditorEventListener::IsFileControlTextBox()
 {
   dom::Element* root = mEditor->GetRoot();
-  if (root && root->ChromeOnlyAccess()) {
-    nsIContent* parent = root->FindFirstNonChromeOnlyAccessContent();
-    if (parent && parent->IsHTML(nsGkAtoms::input)) {
-      nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(parent);
-      MOZ_ASSERT(formControl);
-      return formControl->GetType() == NS_FORM_INPUT_FILE;
-    }
+  if (!root || !root->ChromeOnlyAccess()) {
+    return false;
   }
-  return false;
+  nsIContent* parent = root->FindFirstNonChromeOnlyAccessContent();
+  if (!parent || !parent->IsHTML(nsGkAtoms::input)) {
+    return false;
+  }
+  nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(parent);
+  return formControl->GetType() == NS_FORM_INPUT_FILE;
 }
 
 bool
-nsEditorEventListener::ShouldHandleNativeKeyBindings(nsIDOMEvent* aKeyEvent)
+nsEditorEventListener::ShouldHandleNativeKeyBindings(nsIDOMKeyEvent* aKeyEvent)
 {
   // Only return true if the target of the event is a desendant of the active
   // editing host in order to match the similar decision made in
   // nsXBLWindowKeyHandler.
   // Note that IsAcceptableInputEvent doesn't check for the active editing
   // host for keyboard events, otherwise this check would have been
   // unnecessary.  IsAcceptableInputEvent currently makes a similar check for
   // mouse events.
@@ -1029,9 +1103,8 @@ nsEditorEventListener::ShouldHandleNativ
 
   nsIContent* editingHost = htmlEditor->GetActiveEditingHost();
   if (!editingHost) {
     return false;
   }
 
   return nsContentUtils::ContentIsDescendantOf(targetContent, editingHost);
 }
-
--- a/editor/libeditor/nsEditorEventListener.h
+++ b/editor/libeditor/nsEditorEventListener.h
@@ -9,78 +9,79 @@
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsError.h"
 #include "nsIDOMEventListener.h"
 #include "nsISupportsImpl.h"
 #include "nscore.h"
 
 class nsCaret;
+class nsIDOMDragEvent;
 class nsIDOMEvent;
+class nsIDOMKeyEvent;
+class nsIDOMMouseEvent;
 class nsIPresShell;
+class nsEditor;
 
 // X.h defines KeyPress
 #ifdef KeyPress
 #undef KeyPress
 #endif
 
 #ifdef XP_WIN
 // On Windows, we support switching the text direction by pressing Ctrl+Shift
 #define HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
 #endif
 
-class nsEditor;
-class nsIDOMDragEvent;
-
 class nsEditorEventListener : public nsIDOMEventListener
 {
 public:
   nsEditorEventListener();
 
   virtual nsresult Connect(nsEditor* aEditor);
 
   void Disconnect();
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMEVENTLISTENER
 
-#ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
-  NS_IMETHOD KeyDown(nsIDOMEvent* aKeyEvent);
-  NS_IMETHOD KeyUp(nsIDOMEvent* aKeyEvent);
-#endif
-  NS_IMETHOD KeyPress(nsIDOMEvent* aKeyEvent);
-  NS_IMETHOD HandleText(nsIDOMEvent* aTextEvent);
-  NS_IMETHOD HandleStartComposition(nsIDOMEvent* aCompositionEvent);
-  void       HandleEndComposition(nsIDOMEvent* aCompositionEvent);
-  NS_IMETHOD MouseDown(nsIDOMEvent* aMouseEvent);
-  NS_IMETHOD MouseUp(nsIDOMEvent* aMouseEvent) { return NS_OK; }
-  NS_IMETHOD MouseClick(nsIDOMEvent* aMouseEvent);
-  NS_IMETHOD Focus(nsIDOMEvent* aEvent);
-  NS_IMETHOD Blur(nsIDOMEvent* aEvent);
-
   void SpellCheckIfNeeded();
 
 protected:
   virtual ~nsEditorEventListener();
 
   nsresult InstallToEditor();
   void UninstallFromEditor();
 
-  bool CanDrop(nsIDOMDragEvent* aEvent);
+#ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
+  nsresult KeyDown(nsIDOMKeyEvent* aKeyEvent);
+  nsresult KeyUp(nsIDOMKeyEvent* aKeyEvent);
+#endif
+  nsresult KeyPress(nsIDOMKeyEvent* aKeyEvent);
+  nsresult HandleText(nsIDOMEvent* aTextEvent);
+  nsresult HandleStartComposition(nsIDOMEvent* aCompositionEvent);
+  void HandleEndComposition(nsIDOMEvent* aCompositionEvent);
+  virtual nsresult MouseDown(nsIDOMMouseEvent* aMouseEvent);
+  virtual nsresult MouseUp(nsIDOMMouseEvent* aMouseEvent) { return NS_OK; }
+  virtual nsresult MouseClick(nsIDOMMouseEvent* aMouseEvent);
+  nsresult Focus(nsIDOMEvent* aEvent);
+  nsresult Blur(nsIDOMEvent* aEvent);
   nsresult DragEnter(nsIDOMDragEvent* aDragEvent);
   nsresult DragOver(nsIDOMDragEvent* aDragEvent);
   nsresult DragExit(nsIDOMDragEvent* aDragEvent);
   nsresult Drop(nsIDOMDragEvent* aDragEvent);
   nsresult DragGesture(nsIDOMDragEvent* aDragEvent);
+
+  bool CanDrop(nsIDOMDragEvent* aEvent);
   void CleanupDragDropCaret();
   already_AddRefed<nsIPresShell> GetPresShell();
   bool IsFileControlTextBox();
-  bool ShouldHandleNativeKeyBindings(nsIDOMEvent* aKeyEvent);
+  bool ShouldHandleNativeKeyBindings(nsIDOMKeyEvent* aKeyEvent);
+  nsresult HandleMiddleClickPaste(nsIDOMMouseEvent* aMouseEvent);
 
-protected:
   nsEditor* mEditor; // weak
   nsRefPtr<nsCaret> mCaret;
   bool mCommitText;
   bool mInTransaction;
 #ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH
   bool mHaveBidiKeyboards;
   bool mShouldSwitchTextDirection;
   bool mSwitchToRTL;
--- a/editor/libeditor/nsHTMLDataTransfer.cpp
+++ b/editor/libeditor/nsHTMLDataTransfer.cpp
@@ -406,19 +406,19 @@ nsHTMLEditor::DoInsertHTMLWithContext(co
 
     // Adjust position based on the first node we are going to insert.
     NormalizeEOLInsertPosition(nodeList[0], address_of(parentNode), &offsetOfNewNode);
 
     // if there are any invisible br's after our insertion point, remove them.
     // this is because if there is a br at end of what we paste, it will make
     // the invisible br visible.
     nsWSRunObject wsObj(this, parentNode, offsetOfNewNode);
-    if (nsTextEditUtils::IsBreak(wsObj.mEndReasonNode) && 
-        !IsVisBreak(wsObj.mEndReasonNode) )
-    {
+    if (wsObj.mEndReasonNode &&
+        nsTextEditUtils::IsBreak(wsObj.mEndReasonNode) &&
+        !IsVisBreak(wsObj.mEndReasonNode)) {
       rv = DeleteNode(wsObj.mEndReasonNode);
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     // Remember if we are in a link.
     bool bStartedInLink = IsInLink(parentNode);
 
     // Are we in a text node? If so, split it.
--- a/editor/libeditor/nsHTMLEditorEventListener.cpp
+++ b/editor/libeditor/nsHTMLEditorEventListener.cpp
@@ -29,215 +29,190 @@
  *
  */
 
 #ifdef DEBUG
 nsresult
 nsHTMLEditorEventListener::Connect(nsEditor* aEditor)
 {
   nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryObject(aEditor);
-  nsCOMPtr<nsIHTMLInlineTableEditor> htmlInlineTableEditor = do_QueryObject(aEditor);
+  nsCOMPtr<nsIHTMLInlineTableEditor> htmlInlineTableEditor =
+    do_QueryObject(aEditor);
   NS_PRECONDITION(htmlEditor && htmlInlineTableEditor,
                   "Set nsHTMLEditor or its sub class");
   return nsEditorEventListener::Connect(aEditor);
 }
 #endif
 
 nsHTMLEditor*
 nsHTMLEditorEventListener::GetHTMLEditor()
 {
   // mEditor must be nsHTMLEditor or its subclass.
   return static_cast<nsHTMLEditor*>(mEditor);
 }
 
-NS_IMETHODIMP
-nsHTMLEditorEventListener::MouseUp(nsIDOMEvent* aMouseEvent)
+nsresult
+nsHTMLEditorEventListener::MouseUp(nsIDOMMouseEvent* aMouseEvent)
 {
-  NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
-
-  nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aMouseEvent) );
-  if (!mouseEvent) {
-    //non-ui event passed in.  bad things.
-    return NS_OK;
-  }
+  NS_ENSURE_TRUE(aMouseEvent, NS_OK);
 
   nsHTMLEditor* htmlEditor = GetHTMLEditor();
 
   nsCOMPtr<nsIDOMEventTarget> target;
-  nsresult res = aMouseEvent->GetTarget(getter_AddRefs(target));
-  NS_ENSURE_SUCCESS(res, res);
+  nsresult rv = aMouseEvent->GetTarget(getter_AddRefs(target));
+  NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(target, NS_ERROR_NULL_POINTER);
   nsCOMPtr<nsIDOMElement> element = do_QueryInterface(target);
 
   int32_t clientX, clientY;
-  mouseEvent->GetClientX(&clientX);
-  mouseEvent->GetClientY(&clientY);
+  aMouseEvent->GetClientX(&clientX);
+  aMouseEvent->GetClientY(&clientY);
   htmlEditor->MouseUp(clientX, clientY, element);
 
   return nsEditorEventListener::MouseUp(aMouseEvent);
 }
 
-NS_IMETHODIMP
-nsHTMLEditorEventListener::MouseDown(nsIDOMEvent* aMouseEvent)
+nsresult
+nsHTMLEditorEventListener::MouseDown(nsIDOMMouseEvent* aMouseEvent)
 {
-  NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
-
-  nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aMouseEvent) );
-  if (!mouseEvent) {
-    //non-ui event passed in.  bad things.
-    return NS_OK;
-  }
+  NS_ENSURE_TRUE(aMouseEvent, NS_OK);
 
   nsHTMLEditor* htmlEditor = GetHTMLEditor();
 
   // Detect only "context menu" click
-  //XXX This should be easier to do!
-  // But eDOMEvents_contextmenu and NS_CONTEXTMENU is not exposed in any event interface :-(
+  // XXX This should be easier to do!
+  // But eDOMEvents_contextmenu and NS_CONTEXTMENU is not exposed in any event
+  // interface :-(
   int16_t buttonNumber;
-  nsresult res = mouseEvent->GetButton(&buttonNumber);
-  NS_ENSURE_SUCCESS(res, res);
+  nsresult rv = aMouseEvent->GetButton(&buttonNumber);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   bool isContextClick = buttonNumber == 2;
 
   int32_t clickCount;
-  res = mouseEvent->GetDetail(&clickCount);
-  NS_ENSURE_SUCCESS(res, res);
+  rv = aMouseEvent->GetDetail(&clickCount);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIDOMEventTarget> target;
-  res = aMouseEvent->GetExplicitOriginalTarget(getter_AddRefs(target));
-  NS_ENSURE_SUCCESS(res, res);
+  rv = aMouseEvent->GetExplicitOriginalTarget(getter_AddRefs(target));
+  NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(target, NS_ERROR_NULL_POINTER);
   nsCOMPtr<nsIDOMElement> element = do_QueryInterface(target);
 
   // Contenteditable should disregard mousedowns outside it
   if (element && !htmlEditor->IsDescendantOfEditorRoot(element)) {
     return NS_OK;
   }
 
-  if (isContextClick || (buttonNumber == 0 && clickCount == 2))
-  {
+  if (isContextClick || (buttonNumber == 0 && clickCount == 2)) {
     nsCOMPtr<nsISelection> selection;
     mEditor->GetSelection(getter_AddRefs(selection));
     NS_ENSURE_TRUE(selection, NS_OK);
 
     // Get location of mouse within target node
     nsCOMPtr<nsIDOMNode> parent;
-    res = mouseEvent->GetRangeParent(getter_AddRefs(parent));
-    NS_ENSURE_SUCCESS(res, res);
+    rv = aMouseEvent->GetRangeParent(getter_AddRefs(parent));
+    NS_ENSURE_SUCCESS(rv, rv);
     NS_ENSURE_TRUE(parent, NS_ERROR_FAILURE);
 
     int32_t offset = 0;
-    res = mouseEvent->GetRangeOffset(&offset);
-    NS_ENSURE_SUCCESS(res, res);
+    rv = aMouseEvent->GetRangeOffset(&offset);
+    NS_ENSURE_SUCCESS(rv, rv);
 
     // Detect if mouse point is within current selection for context click
     bool nodeIsInSelection = false;
     if (isContextClick && !selection->Collapsed()) {
       int32_t rangeCount;
-      res = selection->GetRangeCount(&rangeCount);
-      NS_ENSURE_SUCCESS(res, res);
+      rv = selection->GetRangeCount(&rangeCount);
+      NS_ENSURE_SUCCESS(rv, rv);
 
       for (int32_t i = 0; i < rangeCount; i++) {
         nsCOMPtr<nsIDOMRange> range;
 
-        res = selection->GetRangeAt(i, getter_AddRefs(range));
-        if (NS_FAILED(res) || !range)
-          continue;//don't bail yet, iterate through them all
+        rv = selection->GetRangeAt(i, getter_AddRefs(range));
+        if (NS_FAILED(rv) || !range) {
+          // Don't bail yet, iterate through them all
+          continue;
+        }
 
-        res = range->IsPointInRange(parent, offset, &nodeIsInSelection);
+        range->IsPointInRange(parent, offset, &nodeIsInSelection);
 
         // Done when we find a range that we are in
-        if (nodeIsInSelection)
+        if (nodeIsInSelection) {
           break;
+        }
       }
     }
     nsCOMPtr<nsIDOMNode> node = do_QueryInterface(target);
-    if (node && !nodeIsInSelection)
-    {
-      if (!element)
-      {
-        if (isContextClick)
-        {
+    if (node && !nodeIsInSelection) {
+      if (!element) {
+        if (isContextClick) {
           // Set the selection to the point under the mouse cursor:
           selection->Collapse(parent, offset);
-        }
-        else
-        {
+        } else {
           // Get enclosing link if in text so we can select the link
           nsCOMPtr<nsIDOMElement> linkElement;
-          res = htmlEditor->GetElementOrParentByTagName(NS_LITERAL_STRING("href"), node, getter_AddRefs(linkElement));
-          NS_ENSURE_SUCCESS(res, res);
-          if (linkElement)
+          rv = htmlEditor->GetElementOrParentByTagName(
+                             NS_LITERAL_STRING("href"), node,
+                             getter_AddRefs(linkElement));
+          NS_ENSURE_SUCCESS(rv, rv);
+          if (linkElement) {
             element = linkElement;
+          }
         }
       }
       // Select entire element clicked on if NOT within an existing selection
       //   and not the entire body, or table-related elements
-      if (element)
-      {
+      if (element) {
         nsCOMPtr<nsIDOMNode> selectAllNode =
           htmlEditor->FindUserSelectAllNode(element);
 
-        if (selectAllNode)
-        {
+        if (selectAllNode) {
           nsCOMPtr<nsIDOMElement> newElement = do_QueryInterface(selectAllNode);
-          if (newElement)
-          {
+          if (newElement) {
             node = selectAllNode;
             element = newElement;
           }
         }
 
-        if (isContextClick && !nsHTMLEditUtils::IsImage(node))
-        {
+        if (isContextClick && !nsHTMLEditUtils::IsImage(node)) {
           selection->Collapse(parent, offset);
-        }
-        else
-        {
+        } else {
           htmlEditor->SelectElement(element);
         }
       }
     }
     // HACK !!! Context click places the caret but the context menu consumes
     // the event; so we need to check resizing state ourselves
     htmlEditor->CheckSelectionStateForAnonymousButtons(selection);
 
     // Prevent bubbling if we changed selection or 
     //   for all context clicks
-    if (element || isContextClick)
-    {
-      mouseEvent->PreventDefault();
+    if (element || isContextClick) {
+      aMouseEvent->PreventDefault();
       return NS_OK;
     }
-  }
-  else if (!isContextClick && buttonNumber == 0 && clickCount == 1)
-  {
+  } else if (!isContextClick && buttonNumber == 0 && clickCount == 1) {
     // if the target element is an image, we have to display resizers
     int32_t clientX, clientY;
-    mouseEvent->GetClientX(&clientX);
-    mouseEvent->GetClientY(&clientY);
+    aMouseEvent->GetClientX(&clientX);
+    aMouseEvent->GetClientY(&clientY);
     htmlEditor->MouseDown(clientX, clientY, element, aMouseEvent);
   }
 
   return nsEditorEventListener::MouseDown(aMouseEvent);
 }
 
-NS_IMETHODIMP
-nsHTMLEditorEventListener::MouseClick(nsIDOMEvent* aMouseEvent)
+nsresult
+nsHTMLEditorEventListener::MouseClick(nsIDOMMouseEvent* aMouseEvent)
 {
-  NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
-
-  nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aMouseEvent) );
-  if (!mouseEvent) {
-    //non-ui event passed in.  bad things.
-    return NS_OK;
-  }
+  NS_ENSURE_TRUE(aMouseEvent, NS_OK);
 
   nsCOMPtr<nsIDOMEventTarget> target;
-  nsresult res = aMouseEvent->GetTarget(getter_AddRefs(target));
-  NS_ENSURE_SUCCESS(res, res);
+  nsresult rv = aMouseEvent->GetTarget(getter_AddRefs(target));
+  NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(target, NS_ERROR_NULL_POINTER);
   nsCOMPtr<nsIDOMElement> element = do_QueryInterface(target);
 
   GetHTMLEditor()->DoInlineTableEditingAction(element);
 
   return nsEditorEventListener::MouseClick(aMouseEvent);
 }
--- a/editor/libeditor/nsHTMLEditorEventListener.h
+++ b/editor/libeditor/nsHTMLEditorEventListener.h
@@ -25,18 +25,18 @@ public:
   {
   }
 
 #ifdef DEBUG
   // WARNING: You must be use nsHTMLEditor or its sub class for this class.
   virtual nsresult Connect(nsEditor* aEditor);
 #endif
 
-  NS_IMETHOD MouseDown(nsIDOMEvent* aMouseEvent);
-  NS_IMETHOD MouseUp(nsIDOMEvent* aMouseEvent);
-  NS_IMETHOD MouseClick(nsIDOMEvent* aMouseEvent);
+protected:
+  virtual nsresult MouseDown(nsIDOMMouseEvent* aMouseEvent) MOZ_OVERRIDE;
+  virtual nsresult MouseUp(nsIDOMMouseEvent* aMouseEvent) MOZ_OVERRIDE;
+  virtual nsresult MouseClick(nsIDOMMouseEvent* aMouseEvent) MOZ_OVERRIDE;
 
-protected:
   inline nsHTMLEditor* GetHTMLEditor();
 };
 
 #endif // nsHTMLEditorEventListener_h__
 
--- a/editor/libeditor/tests/test_composition_event_created_in_chrome.html
+++ b/editor/libeditor/tests/test_composition_event_created_in_chrome.html
@@ -10,16 +10,19 @@
 </head>
 
 <body>
 
 <input id="input">
 
 <script type="application/javascript">
 
+// In nsEditorEventListener, when listening event is not created with proper
+// event interface, it asserts the fact.
+SimpleTest.expectAssertions(2);
 SimpleTest.waitForExplicitFinish();
 
 var gInputElement = document.getElementById("input");
 
 function getEditorIMESupport(aInputElement)
 {
   var editableElement = aInputElement.QueryInterface(Components.interfaces.nsIDOMNSEditableElement);
   ok(editableElement, "The input element doesn't have nsIDOMNSEditableElement interface");
--- a/embedding/components/commandhandler/nsCommandParams.cpp
+++ b/embedding/components/commandhandler/nsCommandParams.cpp
@@ -1,40 +1,38 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=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 "xpcom-config.h"
 #include <new>    // for placement new
 #include "nscore.h"
 #include "nsCRT.h"
 
 #include "nsCommandParams.h"
 #include "mozilla/HashFunctions.h"
 
 using namespace mozilla;
 
 const PLDHashTableOps nsCommandParams::sHashOps =
 {
-    PL_DHashAllocTable,
-    PL_DHashFreeTable,
-    HashKey,
-    HashMatchEntry,
-    HashMoveEntry,
-    HashClearEntry,
-    PL_DHashFinalizeStub
+  PL_DHashAllocTable,
+  PL_DHashFreeTable,
+  HashKey,
+  HashMatchEntry,
+  HashMoveEntry,
+  HashClearEntry,
+  PL_DHashFinalizeStub
 };
 
-
 NS_IMPL_ISUPPORTS(nsCommandParams, nsICommandParams)
 
 nsCommandParams::nsCommandParams()
-: mCurEntry(0)
-, mNumEntries(eNumEntriesUnknown)
 {
   // ini