merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Tue, 16 Feb 2016 11:51:26 +0100
changeset 320670 6ea654cad929c9bedd8a4161a182b6189fbeae6a
parent 320606 fb7ceaf4b009243423cdaf1077adbb6c609b22e5 (current diff)
parent 320669 53029769feefdb9e01b239c9c9e7bb3b089b1019 (diff)
child 320678 d73b4d5f5d259b9015d7af8f7bfaae81d33529ec
child 320807 cf16002d74e4a8ae9a8c5e7ef2de7e9876c61f3f
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone47.0a1
first release with
nightly linux32
6ea654cad929 / 47.0a1 / 20160216030245 / files
nightly linux64
6ea654cad929 / 47.0a1 / 20160216030245 / files
nightly mac
6ea654cad929 / 47.0a1 / 20160216030245 / files
nightly win32
6ea654cad929 / 47.0a1 / 20160216030245 / files
nightly win64
6ea654cad929 / 47.0a1 / 20160216030245 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
browser/base/content/browser.js
--- a/accessible/jsat/Gestures.jsm
+++ b/accessible/jsat/Gestures.jsm
@@ -74,16 +74,20 @@ const TAP_MAX_RADIUS = 0.2;
 // consequent pointer move lines.
 const DIRECTNESS_COEFF = 1.44;
 // The virtual touch ID generated by a mouse event.
 const MOUSE_ID = 'mouse';
 // Amount in inches from the edges of the screen for it to be an edge swipe
 const EDGE = 0.1;
 // Multiply timeouts by this constant, x2 works great too for slower users.
 const TIMEOUT_MULTIPLIER = 1;
+// A single pointer down/up sequence periodically precedes the tripple swipe
+// gesture on Android. This delay acounts for that.
+const IS_ANDROID = Utils.MozBuildApp === 'mobile/android' &&
+  Utils.AndroidSdkVersion >= 14;
 
 /**
  * A point object containing distance travelled data.
  * @param {Object} aPoint A point object that looks like: {
  *   x: x coordinate in pixels,
  *   y: y coordinate in pixels
  * }
  */
@@ -197,23 +201,23 @@ this.GestureTracker = { // jshint ignore
 
   /**
    * Create a new gesture object and attach resolution handler to it as well as
    * handle the incoming pointer event.
    * @param  {Object} aDetail A new pointer event detail.
    * @param  {Number} aTimeStamp A new pointer event timeStamp.
    * @param  {Function} aGesture A gesture constructor (default: Tap).
    */
-  _init: function GestureTracker__init(aDetail, aTimeStamp, aGesture = Tap) {
+  _init: function GestureTracker__init(aDetail, aTimeStamp, aGesture) {
     // Only create a new gesture on |pointerdown| event.
     if (aDetail.type !== 'pointerdown') {
       return;
     }
     let points = aDetail.points;
-    let GestureConstructor = aGesture;
+    let GestureConstructor = aGesture || (IS_ANDROID ? DoubleTap : Tap);
     this._create(GestureConstructor);
     this._update(aDetail, aTimeStamp);
   },
 
   /**
    * Handle the incoming pointer event with the existing gesture object(if
    * present) or with the newly created one.
    * @param  {Object} aDetail A new pointer event detail.
--- a/addon-sdk/source/lib/sdk/io/fs.js
+++ b/addon-sdk/source/lib/sdk/io/fs.js
@@ -116,18 +116,18 @@ function remove(path, recursive) {
   else {
     throw FSError("remove", "ENOENT", 34, path);
   }
 }
 
 /**
  * Utility function to convert either an octal number or string
  * into an octal number
- * 0777 => 0777
- * "0644" => 0644
+ * 0777 => 0o777
+ * "0644" => 0o644
  */
 function Mode(mode, fallback) {
   return isString(mode) ? parseInt(mode, 8) : mode || fallback;
 }
 function Flags(flag) {
   return !isString(flag) ? flag :
          FLAGS[flag] || Error("Unknown file open flag: " + flag);
 }
--- a/b2g/components/HelperAppDialog.js
+++ b/b2g/components/HelperAppDialog.js
@@ -84,28 +84,28 @@ HelperAppLauncherDialog.prototype = {
           else
             aLocalFile.leafName = aLocalFile.leafName.replace(/(\.[^\.]*)?$/, "(2)$&");
         }
         else {
           // replace the last (n) in the filename with (n+1)
           aLocalFile.leafName = aLocalFile.leafName.replace(/^(.*\()\d+\)/, "$1" + (collisionCount+1) + ")");
         }
       }
-      aLocalFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
+      aLocalFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600);
     }
     catch (e) {
       dump("*** exception in makeFileUnique: " + e + "\n");
 
       if (e.result == Cr.NS_ERROR_FILE_ACCESS_DENIED)
         throw e;
 
       if (aLocalFile.leafName == "" || aLocalFile.isDirectory()) {
         aLocalFile.append("unnamed");
         if (aLocalFile.exists())
-          aLocalFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
+          aLocalFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600);
       }
     }
   },
 
   isUsableDirectory: function(aDirectory) {
     return aDirectory.exists() &&
            aDirectory.isDirectory() &&
            aDirectory.isWritable();
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -319,19 +319,17 @@
 @RESPATH@/components/storage.xpt
 @RESPATH@/components/telemetry.xpt
 @RESPATH@/components/toolkit_asyncshutdown.xpt
 @RESPATH@/components/toolkit_filewatcher.xpt
 @RESPATH@/components/toolkit_finalizationwitness.xpt
 @RESPATH@/components/toolkit_formautofill.xpt
 @RESPATH@/components/toolkit_osfile.xpt
 @RESPATH@/components/toolkit_securityreporter.xpt
-#ifdef NIGHTLY_BUILD
 @RESPATH@/components/toolkit_perfmonitoring.xpt
-#endif
 @RESPATH@/components/toolkit_xulstore.xpt
 @RESPATH@/components/toolkitprofile.xpt
 #ifdef MOZ_ENABLE_XREMOTE
 @RESPATH@/components/toolkitremote.xpt
 #endif
 @RESPATH@/components/txtsvc.xpt
 @RESPATH@/components/txmgr.xpt
 #ifdef MOZ_USE_NATIVE_UCONV
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -56,16 +56,18 @@ XPCOMUtils.defineLazyServiceGetter(this,
 XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
                                   "resource://gre/modules/LightweightThemeManager.jsm");
 XPCOMUtils.defineLazyServiceGetter(this, "gAboutNewTabService",
                                    "@mozilla.org/browser/aboutnewtab-service;1",
                                    "nsIAboutNewTabService");
 XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function() {
   return Services.strings.createBundle('chrome://browser/locale/browser.properties');
 });
+XPCOMUtils.defineLazyModuleGetter(this, "AddonWatcher",
+                                  "resource://gre/modules/AddonWatcher.jsm");
 
 const nsIWebNavigation = Ci.nsIWebNavigation;
 
 var gLastBrowserCharset = null;
 var gLastValidURLStr = "";
 var gInPrintPreviewMode = false;
 var gContextMenu = null; // nsContextMenu instance
 var gMultiProcessBrowser =
@@ -1343,16 +1345,19 @@ var gBrowserInit = {
         return;
       }
 
       // Enable the Restore Last Session command if needed
       RestoreLastSessionObserver.init();
 
       SocialUI.init();
 
+      // Start monitoring slow add-ons
+      AddonWatcher.init();
+
       // Telemetry for master-password - we do this after 5 seconds as it
       // can cause IO if NSS/PSM has not already initialized.
       setTimeout(() => {
         if (window.closed) {
           return;
         }
         let secmodDB = Cc["@mozilla.org/security/pkcs11moduledb;1"]
                        .getService(Ci.nsIPKCS11ModuleDB);
@@ -3975,17 +3980,17 @@ function updateEditUIVisibility()
  * living on the tab's docShell.
  *
  * @param event
  *        A click event on a userContext File Menu option
  */
 function openNewUserContextTab(event)
 {
   openUILinkIn(BROWSER_NEW_TAB_URL, "tab", {
-    userContextId: event.target.getAttribute('usercontextid'),
+    userContextId: parseInt(event.target.getAttribute('usercontextid')),
   });
 }
 
 /**
  * Updates File Menu User Context UI visibility depending on
  * privacy.userContext.enabled pref state.
  */
 function updateUserContextUIVisibility()
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -978,17 +978,17 @@ nsContextMenu.prototype = {
         sm.checkSameOriginURI(referrerURI, targetURI, false);
         persistAllowMixedContentInChildTab = true;
       }
       catch (e) { }
     }
 
     let params = this._openLinkInParameters({
       allowMixedContent: persistAllowMixedContentInChildTab,
-      userContextId: event.target.getAttribute('usercontextid'),
+      userContextId: parseInt(event.target.getAttribute('usercontextid')),
     });
     openLinkIn(this.linkURL, "tab", params);
   },
 
   // open URL in current tab
   openLinkInCurrent: function() {
     urlSecurityCheck(this.linkURL, this.principal);
     openLinkIn(this.linkURL, "current", this._openLinkInParameters());
--- a/browser/base/content/sync/utils.js
+++ b/browser/base/content/sync/utils.js
@@ -1,13 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-// Equivalent to 0600 permissions; used for saved Sync Recovery Key.
+// Equivalent to 0o600 permissions; used for saved Sync Recovery Key.
 // This constant can be replaced when the equivalent values are available to
 // chrome JS; see Bug 433295 and Bug 757351.
 const PERMISSIONS_RWUSR = 0x180;
 
 // Weave should always exist before before this file gets included.
 var gSyncUtils = {
   get bundle() {
     delete this.bundle;
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1721,18 +1721,19 @@
             let b = document.createElementNS(NS_XUL, "browser");
             b.permanentKey = {};
             b.setAttribute("type", "content-targetable");
             b.setAttribute("message", "true");
             b.setAttribute("messagemanagergroup", "browsers");
             b.setAttribute("contextmenu", this.getAttribute("contentcontextmenu"));
             b.setAttribute("tooltip", this.getAttribute("contenttooltip"));
 
-            if (userContextId)
+            if (userContextId) {
               b.setAttribute("usercontextid", userContextId);
+            }
 
             if (remote)
               b.setAttribute("remote", "true");
 
             if (window.gShowPageResizers && window.windowState == window.STATE_NORMAL) {
               b.setAttribute("showresizer", "true");
             }
 
@@ -6267,18 +6268,23 @@
         ]]>
         </body>
       </method>
 
       <method name="setUserContextId">
         <parameter name="aUserContextId"/>
         <body>
         <![CDATA[
-          this.linkedBrowser.setAttribute("usercontextid", aUserContextId);
-          this.setAttribute("usercontextid", aUserContextId);
+          if (aUserContextId) {
+            this.linkedBrowser.setAttribute("usercontextid", aUserContextId);
+            this.setAttribute("usercontextid", aUserContextId);
+          } else {
+            this.linkedBrowser.removeAttribute("usercontextid");
+            this.removeAttribute("usercontextid");
+          }
         ]]>
         </body>
       </method>
     </implementation>
 
     <handlers>
       <handler event="mouseover"><![CDATA[
         let anonid = event.originalTarget.getAttribute("anonid");
--- a/browser/base/content/test/general/browser_save_link-perwindowpb.js
+++ b/browser/base/content/test/general/browser_save_link-perwindowpb.js
@@ -195,13 +195,13 @@ Cc["@mozilla.org/moz/jssubscript-loader;
 
 function createTemporarySaveDirectory() {
   var saveDir = Cc["@mozilla.org/file/directory_service;1"]
                   .getService(Ci.nsIProperties)
                   .get("TmpD", Ci.nsIFile);
   saveDir.append("testsavedir");
   if (!saveDir.exists()) {
     info("create testsavedir!");
-    saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
+    saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
   }
   info("return from createTempSaveDir: " + saveDir.path);
   return saveDir;
 }
--- a/browser/base/content/test/general/browser_save_link_when_window_navigates.js
+++ b/browser/base/content/test/general/browser_save_link_when_window_navigates.js
@@ -15,17 +15,17 @@ Cc["@mozilla.org/moz/jssubscript-loader;
 
 function createTemporarySaveDirectory() {
   var saveDir = Cc["@mozilla.org/file/directory_service;1"]
                   .getService(Ci.nsIProperties)
                   .get("TmpD", Ci.nsIFile);
   saveDir.append("testsavedir");
   if (!saveDir.exists()) {
     info("create testsavedir!");
-    saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
+    saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
   }
   info("return from createTempSaveDir: " + saveDir.path);
   return saveDir;
 }
 
 function triggerSave(aWindow, aCallback) {
   info("started triggerSave, persite downloads: " + (Services.prefs.getBoolPref(SAVE_PER_SITE_PREF) ? "on" : "off"));
   var fileName;
--- a/browser/base/content/test/general/browser_save_private_link_perwindowpb.js
+++ b/browser/base/content/test/general/browser_save_private_link_perwindowpb.js
@@ -48,17 +48,17 @@ function test() {
   }
 
   function createTemporarySaveDirectory() {
     var saveDir = Cc["@mozilla.org/file/directory_service;1"]
                     .getService(Ci.nsIProperties)
                     .get("TmpD", Ci.nsIFile);
     saveDir.append("testsavedir");
     if (!saveDir.exists())
-      saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
+      saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
     return saveDir;
   }
 
   function doTest(aIsPrivateMode, aWindow, aCallback) {
     function contextMenuOpened(event) {
       cache.clear();
 
       aWindow.document.removeEventListener("popupshown", contextMenuOpened);
--- a/browser/base/content/test/general/browser_save_video.js
+++ b/browser/base/content/test/general/browser_save_video.js
@@ -77,11 +77,11 @@ Cc["@mozilla.org/moz/jssubscript-loader;
                  this);
 
 function createTemporarySaveDirectory() {
   var saveDir = Cc["@mozilla.org/file/directory_service;1"]
                   .getService(Ci.nsIProperties)
                   .get("TmpD", Ci.nsIFile);
   saveDir.append("testsavedir");
   if (!saveDir.exists())
-    saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
+    saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
   return saveDir;
 }
--- a/browser/base/content/test/general/browser_save_video_frame.js
+++ b/browser/base/content/test/general/browser_save_video_frame.js
@@ -19,17 +19,17 @@ Cc["@mozilla.org/moz/jssubscript-loader;
  * @return nsIFile
  */
 function createTemporarySaveDirectory() {
   let saveDir = Cc["@mozilla.org/file/directory_service;1"]
                   .getService(Ci.nsIProperties)
                   .get("TmpD", Ci.nsIFile);
   saveDir.append("testsavedir");
   if (!saveDir.exists())
-    saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
+    saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
   return saveDir;
 }
 /**
  * MockTransfer exposes a "mockTransferCallback" global which
  * allows us to define a callback to be called once the mock file
  * selector has selected where to save the file.
  */
 function waitForTransferComplete() {
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -538,17 +538,16 @@ BrowserGlue.prototype = {
     }
     os.addObserver(this, "browser-search-engine-modified", false);
     os.addObserver(this, "restart-in-safe-mode", false);
     os.addObserver(this, "flash-plugin-hang", false);
     os.addObserver(this, "xpi-signature-changed", false);
     os.addObserver(this, "autocomplete-did-enter-text", false);
 
     if (AppConstants.NIGHTLY_BUILD) {
-      AddonWatcher.init();
       os.addObserver(this, AddonWatcher.TOPIC_SLOW_ADDON_DETECTED, false);
     }
 
     ExtensionManagement.registerScript("chrome://browser/content/ext-utils.js");
     ExtensionManagement.registerScript("chrome://browser/content/ext-browserAction.js");
     ExtensionManagement.registerScript("chrome://browser/content/ext-pageAction.js");
     ExtensionManagement.registerScript("chrome://browser/content/ext-contextMenus.js");
     ExtensionManagement.registerScript("chrome://browser/content/ext-desktop-runtime.js");
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_opendir.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_opendir.js
@@ -25,17 +25,17 @@ function test() {
   // initialization
   waitForExplicitFinish();
   let ds = Cc["@mozilla.org/file/directory_service;1"].
            getService(Ci.nsIProperties);
   let dir1 = ds.get("ProfD", Ci.nsIFile);
   let dir2 = ds.get("TmpD", Ci.nsIFile);
   let file = dir2.clone();
   file.append("pbtest.file");
-  file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
+  file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600);
 
   const kPrefName = "browser.open.lastDir";
 
   function setupCleanSlate(win) {
     win.gLastOpenDirectory.reset();
     gPrefService.clearUserPref(kPrefName);
   }
 
--- a/browser/components/sessionstore/test/browser_backup_recovery.js
+++ b/browser/components/sessionstore/test/browser_backup_recovery.js
@@ -136,17 +136,17 @@ add_task(function* test_recovery_inacces
   yield File.makeDir(Paths.backups);
   yield File.writeAtomic(Paths.recoveryBackup, SOURCE);
 
   // Write a valid recovery file but make it inaccessible.
   yield File.writeAtomic(Paths.recovery, SOURCE_RECOVERY);
   yield File.setPermissions(Paths.recovery, { unixMode: 0 });
 
   is((yield SessionFile.read()).source, SOURCE, "Recovered the correct source from the recovery file");
-  yield File.setPermissions(Paths.recovery, { unixMode: 0644 });
+  yield File.setPermissions(Paths.recovery, { unixMode: 0o644 });
 });
 
 add_task(function* test_clean() {
   yield SessionFile.wipe();
   let SOURCE = yield promiseSource("Paths.clean");
   yield File.writeAtomic(Paths.clean, SOURCE);
   yield SessionFile.read();
   yield SessionSaver.run();
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -313,19 +313,17 @@
 @RESPATH@/components/spellchecker.xpt
 @RESPATH@/components/storage.xpt
 @RESPATH@/components/toolkit_asyncshutdown.xpt
 @RESPATH@/components/toolkit_filewatcher.xpt
 @RESPATH@/components/toolkit_finalizationwitness.xpt
 @RESPATH@/components/toolkit_formautofill.xpt
 @RESPATH@/components/toolkit_osfile.xpt
 @RESPATH@/components/toolkit_securityreporter.xpt
-#ifdef NIGHTLY_BUILD
 @RESPATH@/components/toolkit_perfmonitoring.xpt
-#endif
 @RESPATH@/components/toolkit_xulstore.xpt
 @RESPATH@/components/toolkitprofile.xpt
 #ifdef MOZ_ENABLE_XREMOTE
 @RESPATH@/components/toolkitremote.xpt
 #endif
 @RESPATH@/components/txtsvc.xpt
 @RESPATH@/components/txmgr.xpt
 @RESPATH@/components/uconv.xpt
--- a/config/config.mk
+++ b/config/config.mk
@@ -25,20 +25,16 @@ endif
 
 ifndef INCLUDED_AUTOCONF_MK
 include $(DEPTH)/config/autoconf.mk
 endif
 
 -include $(DEPTH)/.mozconfig.mk
 
 ifndef EXTERNALLY_MANAGED_MAKE_FILE
-# Using $(firstword) may not be perfect. But it should be good enough for most
-# scenarios.
-_current_makefile = $(CURDIR)/$(firstword $(MAKEFILE_LIST))
-
 # Import the automatically generated backend file. If this file doesn't exist,
 # the backend hasn't been properly configured. We want this to be a fatal
 # error, hence not using "-include".
 ifndef STANDALONE_MAKEFILE
 GLOBAL_DEPS += backend.mk
 include backend.mk
 endif
 
--- a/config/external/nspr/pr/moz.build
+++ b/config/external/nspr/pr/moz.build
@@ -24,16 +24,23 @@ if CONFIG['OS_ARCH'] == 'Linux':
     SOURCES += ['/nsprpub/pr/src/md/unix/linux.c']
     if CONFIG['CPU_ARCH'] == 'x86_64':
         SOURCES += ['/nsprpub/pr/src/md/unix/os_Linux_x86_64.s']
     elif CONFIG['CPU_ARCH'] == 'x86':
         DEFINES['i386'] = True
         SOURCES += ['/nsprpub/pr/src/md/unix/os_Linux_x86.s']
     elif CONFIG['CPU_ARCH'] == 'ppc':
         SOURCES += ['/nsprpub/pr/src/md/unix/os_Linux_ppc.s']
+elif CONFIG['OS_TARGET'] in ('FreeBSD', 'OpenBSD', 'NetBSD'):
+    DEFINES.update(
+        HAVE_BSD_FLOCK=True,
+        HAVE_SOCKLEN_T=True,
+    )
+    DEFINES[CONFIG['OS_TARGET'].upper()] = True
+    SOURCES += ['/nsprpub/pr/src/md/unix/%s.c' % CONFIG['OS_TARGET'].lower()]
 elif CONFIG['OS_TARGET'] == 'Darwin':
     DEFINES.update(
         DARWIN=True,
         HAVE_BSD_FLOCK=True,
         HAVE_SOCKLEN_T=True,
     )
     SOURCES += [
         '/nsprpub/pr/src/md/unix/darwin.c',
@@ -205,17 +212,20 @@ EXPORTS.nspr += [
     '/nsprpub/pr/include/prtrace.h',
     '/nsprpub/pr/include/prtypes.h',
     '/nsprpub/pr/include/prvrsion.h',
     '/nsprpub/pr/include/prwin16.h',
 ]
 
 EXPORTS.nspr.md += [
     '/nsprpub/pr/include/md/_darwin.cfg',
+    '/nsprpub/pr/include/md/_freebsd.cfg',
     '/nsprpub/pr/include/md/_linux.cfg',
+    '/nsprpub/pr/include/md/_netbsd.cfg',
+    '/nsprpub/pr/include/md/_openbsd.cfg',
     '/nsprpub/pr/include/md/_win95.cfg',
 ]
 
 EXPORTS.nspr.private += [
     '/nsprpub/pr/include/private/pprio.h',
     '/nsprpub/pr/include/private/pprthred.h',
     '/nsprpub/pr/include/private/prpriv.h',
 ]
--- a/config/external/nspr/prcpucfg.h
+++ b/config/external/nspr/prcpucfg.h
@@ -9,15 +9,21 @@
 /*
  * Need to support conditionals that are defined in both the top-level build
  * system as well as NSS' build system for now.
  */
 #if defined(XP_DARWIN) || defined(DARWIN)
 #include "md/_darwin.cfg"
 #elif defined(XP_WIN) || defined(_WINDOWS)
 #include "md/_win95.cfg"
+#elif defined(__FreeBSD__)
+#include "md/_freebsd.cfg"
+#elif defined(__NetBSD__)
+#include "md/_netbsd.cfg"
+#elif defined(__OpenBSD__)
+#include "md/_openbsd.cfg"
 #elif defined(__linux__)
 #include "md/_linux.cfg"
 #else
 #error "Unsupported platform!"
 #endif
 
 #endif /* NSPR_PRCPUCFG_H_ */
--- a/configure.in
+++ b/configure.in
@@ -71,16 +71,17 @@ GTK3_VERSION=3.4.0
 GDK_VERSION_MIN_REQUIRED=GDK_VERSION_3_4
 WINDRES_VERSION=2.14.90
 W32API_VERSION=3.14
 GNOMEUI_VERSION=2.2.0
 GCONF_VERSION=1.2.1
 STARTUP_NOTIFICATION_VERSION=0.8
 DBUS_VERSION=0.60
 SQLITE_VERSION=3.10.2
+FONTCONFIG_VERSION=2.7.0
 
 MSMANIFEST_TOOL=
 
 dnl Set various checks
 dnl ========================================================
 MISSING_X=
 AC_PROG_AWK
 
@@ -8073,17 +8074,17 @@ if test "$USE_FC_FREETYPE"; then
         CPPFLAGS="$CPPFLAGS $FT2_CFLAGS $XCFLAGS"
         MOZ_CHECK_HEADERS([fontconfig/fcfreetype.h], ,
             [AC_MSG_ERROR(Can't find header fontconfig/fcfreetype.h.)], [#include <fontconfig/fontconfig.h>])
         CPPFLAGS="$_SAVE_CPPFLAGS"
     else
         AC_DEFINE(HAVE_FONTCONFIG_FCFREETYPE_H)
     fi
 
-    PKG_CHECK_MODULES(_FONTCONFIG, fontconfig,
+    PKG_CHECK_MODULES(_FONTCONFIG, fontconfig >= $FONTCONFIG_VERSION,
     [
         if test "$MOZ_PANGO"; then
             MOZ_PANGO_CFLAGS="$MOZ_PANGO_CFLAGS $_FONTCONFIG_CFLAGS"
             MOZ_PANGO_LIBS="$MOZ_PANGO_LIBS $_FONTCONFIG_LIBS"
         else
             FT2_CFLAGS="$FT2_CFLAGS $_FONTCONFIG_CFLAGS"
             FT2_LIBS="$FT2_LIBS $_FONTCONFIG_LIBS"
         fi
--- a/devtools/client/projecteditor/test/head.js
+++ b/devtools/client/projecteditor/test/head.js
@@ -229,17 +229,17 @@ function writeToFile(file, data) {
 // You should typically use the async version of this, writeToFile.
 // https://developer.mozilla.org/en-US/Add-ons/Code_snippets/File_I_O#More
 function writeToFileSync(file, data) {
   // file is nsIFile, data is a string
   var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"].
                  createInstance(Components.interfaces.nsIFileOutputStream);
 
   // use 0x02 | 0x10 to open file for appending.
-  foStream.init(file, 0x02 | 0x08 | 0x20, 0666, 0);
+  foStream.init(file, 0x02 | 0x08 | 0x20, 0o666, 0);
   // write, create, truncate
   // In a c file operation, we have no need to set file mode with or operation,
   // directly using "r" or "w" usually.
 
   // if you are sure there will never ever be any non-ascii text in data you can
   // also call foStream.write(data, data.length) directly
   var converter = Components.classes["@mozilla.org/intl/converter-output-stream;1"].
                   createInstance(Components.interfaces.nsIConverterOutputStream);
--- a/devtools/client/scratchpad/test/browser_scratchpad_confirm_close.js
+++ b/devtools/client/scratchpad/test/browser_scratchpad_confirm_close.js
@@ -187,27 +187,27 @@ function cleanup()
   Services.prompt = oldPrompt;
   gFile.remove(false);
   gFile = null;
 }
 
 function createTempFile(name)
 {
   let file = FileUtils.getFile("TmpD", [name]);
-  file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
   file.QueryInterface(Ci.nsILocalFile)
   return file;
 }
 
 function writeFile(file, content, callback)
 {
   let fout = Cc["@mozilla.org/network/file-output-stream;1"].
              createInstance(Ci.nsIFileOutputStream);
   fout.init(file.QueryInterface(Ci.nsILocalFile), 0x02 | 0x08 | 0x20,
-            0644, fout.DEFER_OPEN);
+            0o644, fout.DEFER_OPEN);
 
   let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
                   createInstance(Ci.nsIScriptableUnicodeConverter);
   converter.charset = "UTF-8";
   let fileContentStream = converter.convertToInputStream(content);
 
   NetUtil.asyncCopy(fileContentStream, fout, callback);
 }
--- a/devtools/server/actors/root.js
+++ b/devtools/server/actors/root.js
@@ -205,16 +205,19 @@ RootActor.prototype = {
       this._parameters.tabList.onListChanged = null;
     }
     if (this._parameters.addonList) {
       this._parameters.addonList.onListChanged = null;
     }
     if (this._parameters.workerList) {
       this._parameters.workerList.onListChanged = null;
     }
+    if (this._parameters.serviceWorkerRegistrationList) {
+      this._parameters.serviceWorkerRegistrationList.onListChanged = null;
+    }
     if (typeof this._parameters.onShutdown === 'function') {
       this._parameters.onShutdown();
     }
     this._extraActors = null;
     this.conn = null;
     this._tabActorPool = null;
     this._globalActorPool = null;
     this._parameters = null;
--- a/devtools/shared/apps/tests/debugger-protocol-helper.js
+++ b/devtools/shared/apps/tests/debugger-protocol-helper.js
@@ -91,17 +91,17 @@ function downloadURL(url, file) {
   let istream = channel.open2();
   let bstream = Cc["@mozilla.org/binaryinputstream;1"]
                   .createInstance(Ci.nsIBinaryInputStream);
   bstream.setInputStream(istream);
   let data = bstream.readBytes(bstream.available());
 
   let ostream = Cc["@mozilla.org/network/safe-file-output-stream;1"]
                   .createInstance(Ci.nsIFileOutputStream);
-  ostream.init(file, 0x04 | 0x08 | 0x20, 0600, 0);
+  ostream.init(file, 0x04 | 0x08 | 0x20, 0o600, 0);
   ostream.write(data, data.length);
   ostream.QueryInterface(Ci.nsISafeOutputStream).finish();
 }
 
 // Install a test packaged webapp from data folder
 addMessageListener("install", function (aMessage) {
   let url = aMessage.url;
   let appId = aMessage.appId;
--- a/docshell/base/nsAboutRedirector.cpp
+++ b/docshell/base/nsAboutRedirector.cpp
@@ -90,22 +90,20 @@ static RedirEntry kRedirMap[] = {
     "networking", "chrome://global/content/aboutNetworking.xhtml",
     nsIAboutModule::ALLOW_SCRIPT
   },
   {
     "newaddon", "chrome://mozapps/content/extensions/newaddon.xul",
     nsIAboutModule::ALLOW_SCRIPT |
       nsIAboutModule::HIDE_FROM_ABOUTABOUT
   },
-#ifdef NIGHTLY_BUILD
   {
     "performance", "chrome://global/content/aboutPerformance.xhtml",
     nsIAboutModule::ALLOW_SCRIPT
   },
-#endif
   {
     "plugins", "chrome://global/content/plugins.html",
     nsIAboutModule::URI_MUST_LOAD_IN_CHILD
   },
   {
     "serviceworkers", "chrome://global/content/aboutServiceWorkers.xhtml",
     nsIAboutModule::URI_CAN_LOAD_IN_CHILD |
     nsIAboutModule::URI_MUST_LOAD_IN_CHILD |
--- a/dom/animation/CSSPseudoElement.cpp
+++ b/dom/animation/CSSPseudoElement.cpp
@@ -31,16 +31,22 @@ CSSPseudoElement::~CSSPseudoElement()
 {
   // Element might have been unlinked already, so we have to do null check.
   if (mParentElement) {
     mParentElement->DeleteProperty(
       GetCSSPseudoElementPropertyAtom(mPseudoType));
   }
 }
 
+ParentObject
+CSSPseudoElement::GetParentObject() const
+{
+  return mParentElement->GetParentObject();
+}
+
 JSObject*
 CSSPseudoElement::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return CSSPseudoElementBinding::Wrap(aCx, this, aGivenProto);
 }
 
 void
 CSSPseudoElement::GetAnimations(nsTArray<RefPtr<Animation>>& aRetVal)
--- a/dom/animation/CSSPseudoElement.h
+++ b/dom/animation/CSSPseudoElement.h
@@ -27,20 +27,17 @@ class CSSPseudoElement final : public ns
 public:
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(CSSPseudoElement)
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(CSSPseudoElement)
 
 protected:
   virtual ~CSSPseudoElement();
 
 public:
-  ParentObject GetParentObject() const
-  {
-    return mParentElement->GetParentObject();
-  }
+  ParentObject GetParentObject() const;
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) override;
 
   nsCSSPseudoElements::Type GetType() const { return mPseudoType; }
   void GetType(nsString& aRetVal) const
   {
     MOZ_ASSERT(nsCSSPseudoElements::GetPseudoAtom(mPseudoType),
--- a/dom/base/PostMessageEvent.cpp
+++ b/dom/base/PostMessageEvent.cpp
@@ -154,17 +154,17 @@ PostMessageEvent::Run()
   // window if it can get a reference to it.
 
   nsIPresShell *shell = targetWindow->GetExtantDoc()->GetShell();
   RefPtr<nsPresContext> presContext;
   if (shell)
     presContext = shell->GetPresContext();
 
   event->SetTrusted(mTrustedCaller);
-  WidgetEvent* internalEvent = event->GetInternalNSEvent();
+  WidgetEvent* internalEvent = event->WidgetEventPtr();
 
   nsEventStatus status = nsEventStatus_eIgnore;
   EventDispatcher::Dispatch(window,
                             presContext,
                             internalEvent,
                             static_cast<dom::Event*>(event.get()),
                             &status);
   return NS_OK;
--- a/dom/base/TextInputProcessor.cpp
+++ b/dom/base/TextInputProcessor.cpp
@@ -339,17 +339,17 @@ TextInputProcessor::PrepareKeyboardEvent
                       uint32_t& aKeyFlags,
                       uint8_t aOptionalArgc,
                       WidgetKeyboardEvent*& aKeyboardEvent)
 {
   aKeyboardEvent = nullptr;
 
   aKeyboardEvent =
     aOptionalArgc && aDOMKeyEvent ?
-      aDOMKeyEvent->AsEvent()->GetInternalNSEvent()->AsKeyboardEvent() : nullptr;
+      aDOMKeyEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent() : nullptr;
   if (!aKeyboardEvent || aOptionalArgc < 2) {
     aKeyFlags = 0;
   }
 
   if (!aKeyboardEvent) {
     return NS_OK;
   }
 
@@ -764,17 +764,17 @@ TextInputProcessor::Keydown(nsIDOMKeyEve
   MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
   if (!aOptionalArgc) {
     aKeyFlags = 0;
   }
   if (NS_WARN_IF(!aDOMKeyEvent)) {
     return NS_ERROR_INVALID_ARG;
   }
   WidgetKeyboardEvent* originalKeyEvent =
-    aDOMKeyEvent->AsEvent()->GetInternalNSEvent()->AsKeyboardEvent();
+    aDOMKeyEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent();
   if (NS_WARN_IF(!originalKeyEvent)) {
     return NS_ERROR_INVALID_ARG;
   }
   return KeydownInternal(*originalKeyEvent, aKeyFlags, true, *aConsumedFlags);
 }
 
 TextEventDispatcher::DispatchTo
 TextInputProcessor::GetDispatchTo() const
@@ -870,17 +870,17 @@ TextInputProcessor::Keyup(nsIDOMKeyEvent
   MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
   if (!aOptionalArgc) {
     aKeyFlags = 0;
   }
   if (NS_WARN_IF(!aDOMKeyEvent)) {
     return NS_ERROR_INVALID_ARG;
   }
   WidgetKeyboardEvent* originalKeyEvent =
-    aDOMKeyEvent->AsEvent()->GetInternalNSEvent()->AsKeyboardEvent();
+    aDOMKeyEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent();
   if (NS_WARN_IF(!originalKeyEvent)) {
     return NS_ERROR_INVALID_ARG;
   }
   return KeyupInternal(*originalKeyEvent, aKeyFlags, *aDoDefault);
 }
 
 nsresult
 TextInputProcessor::KeyupInternal(const WidgetKeyboardEvent& aKeyboardEvent,
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -3778,17 +3778,17 @@ nsContentUtils::DispatchEvent(nsIDocumen
                               bool aOnlyChromeDispatch)
 {
   nsCOMPtr<nsIDOMEvent> event;
   nsCOMPtr<EventTarget> target;
   nsresult rv = GetEventAndTarget(aDoc, aTarget, aEventName, aCanBubble,
                                   aCancelable, aTrusted, getter_AddRefs(event),
                                   getter_AddRefs(target));
   NS_ENSURE_SUCCESS(rv, rv);
-  event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = aOnlyChromeDispatch;
+  event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = aOnlyChromeDispatch;
 
   bool dummy;
   return target->DispatchEvent(event, aDefaultAction ? aDefaultAction : &dummy);
 }
 
 nsresult
 nsContentUtils::DispatchChromeEvent(nsIDocument *aDoc,
                                     nsISupports *aTarget,
@@ -4942,17 +4942,17 @@ nsContentUtils::GetAccelKeyCandidates(ns
 
   nsAutoString eventType;
   aDOMKeyEvent->AsEvent()->GetType(eventType);
   // Don't process if aDOMKeyEvent is not a keypress event.
   if (!eventType.EqualsLiteral("keypress"))
     return;
 
   WidgetKeyboardEvent* nativeKeyEvent =
-    aDOMKeyEvent->AsEvent()->GetInternalNSEvent()->AsKeyboardEvent();
+    aDOMKeyEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent();
   if (nativeKeyEvent) {
     NS_ASSERTION(nativeKeyEvent->mClass == eKeyboardEventClass,
                  "wrong type of native event");
     // nsShortcutCandidate::mCharCode is a candidate charCode.
     // nsShoftcutCandidate::mIgnoreShift means the mCharCode should be tried to
     // execute a command with/without shift key state. If this is TRUE, the
     // shifted key state should be ignored. Otherwise, don't ignore the state.
     // the priority of the charCodes are (shift key is not pressed):
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -1768,17 +1768,17 @@ nsDOMWindowUtils::GetFullZoom(float* aFu
 NS_IMETHODIMP
 nsDOMWindowUtils::DispatchDOMEventViaPresShell(nsIDOMNode* aTarget,
                                                nsIDOMEvent* aEvent,
                                                bool aTrusted,
                                                bool* aRetVal)
 {
   NS_ENSURE_STATE(aEvent);
   aEvent->SetTrusted(aTrusted);
-  WidgetEvent* internalEvent = aEvent->GetInternalNSEvent();
+  WidgetEvent* internalEvent = aEvent->WidgetEventPtr();
   NS_ENSURE_STATE(internalEvent);
   nsCOMPtr<nsIContent> content = do_QueryInterface(aTarget);
   NS_ENSURE_STATE(content);
   nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow);
   if (content->OwnerDoc()->GetWindow() != window) {
     return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
   }
   nsCOMPtr<nsIDocument> targetDoc = content->GetCurrentDoc();
@@ -3451,17 +3451,17 @@ nsDOMWindowUtils::GetPaintFlashing(bool*
 
 NS_IMETHODIMP
 nsDOMWindowUtils::DispatchEventToChromeOnly(nsIDOMEventTarget* aTarget,
                                             nsIDOMEvent* aEvent,
                                             bool* aRetVal)
 {
   *aRetVal = false;
   NS_ENSURE_STATE(aTarget && aEvent);
-  aEvent->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
+  aEvent->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
   aTarget->DispatchEvent(aEvent, aRetVal);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::RequestCompositorProperty(const nsAString& property,
                                             float* aResult)
 {
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -5090,17 +5090,17 @@ nsDocument::DispatchContentLoadedEvents(
         event->SetTrusted(true);
 
         // To dispatch this event we must manually call
         // EventDispatcher::Dispatch() on the ancestor document since the
         // target is not in the same document, so the event would never reach
         // the ancestor document if we used the normal event
         // dispatching code.
 
-        WidgetEvent* innerEvent = event->GetInternalNSEvent();
+        WidgetEvent* innerEvent = event->WidgetEventPtr();
         if (innerEvent) {
           nsEventStatus status = nsEventStatus_eIgnore;
 
           nsIPresShell *shell = parent->GetShell();
           if (shell) {
             RefPtr<nsPresContext> context = shell->GetPresContext();
 
             if (context) {
@@ -8108,17 +8108,17 @@ nsIDocument::CreateEvent(const nsAString
   // Create event even without presContext.
   RefPtr<Event> ev =
     EventDispatcher::CreateEvent(const_cast<nsIDocument*>(this), presContext,
                                  nullptr, aEventType);
   if (!ev) {
     rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     return nullptr;
   }
-  WidgetEvent* e = ev->GetInternalNSEvent();
+  WidgetEvent* e = ev->WidgetEventPtr();
   e->mFlags.mBubbles = false;
   e->mFlags.mCancelable = false;
   return ev.forget();
 }
 
 void
 nsDocument::FlushPendingNotifications(mozFlushType aType)
 {
@@ -9195,17 +9195,17 @@ NotifyPageHide(nsIDocument* aDocument, v
 static void
 DispatchCustomEventWithFlush(nsINode* aTarget, const nsAString& aEventType,
                              bool aBubbles, bool aOnlyChromeDispatch)
 {
   RefPtr<Event> event = NS_NewDOMEvent(aTarget, nullptr, nullptr);
   event->InitEvent(aEventType, aBubbles, false);
   event->SetTrusted(true);
   if (aOnlyChromeDispatch) {
-    event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
+    event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
   }
   if (nsIPresShell* shell = aTarget->OwnerDoc()->GetShell()) {
     shell->GetPresContext()->
       RefreshDriver()->ScheduleEventDispatch(aTarget, event);
   }
 }
 
 static void
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -5060,19 +5060,17 @@ nsGlobalWindow::GetScreenXY(ErrorResult&
   // placed to the right of a lo-dpi screen on Windows. (Instead, there
   // may be "gaps" in the resulting CSS px coordinates in some cases.)
   nsDeviceContext *dc = presContext->DeviceContext();
   nsRect screenRect;
   dc->GetRect(screenRect);
   LayoutDeviceRect screenRectDev =
     LayoutDevicePixel::FromAppUnits(screenRect, dc->AppUnitsPerDevPixel());
 
-  nsCOMPtr<nsIWidget> widget = GetMainWidget();
-  DesktopToLayoutDeviceScale scale = widget ? widget->GetDesktopToDeviceScale()
-                                            : DesktopToLayoutDeviceScale(1.0);
+  DesktopToLayoutDeviceScale scale = dc->GetDesktopToDeviceScale();
   DesktopRect screenRectDesk = screenRectDev / scale;
 
   CSSPoint cssPt =
     LayoutDevicePoint(x - screenRectDev.x, y - screenRectDev.y) /
     presContext->CSSToDevPixelScale();
   cssPt.x += screenRectDesk.x;
   cssPt.y += screenRectDesk.y;
 
@@ -5698,17 +5696,17 @@ nsGlobalWindow::DispatchResizeEvent(cons
                                /* cancelable = */ true,
                                detailValue,
                                res);
   if (res.Failed()) {
     return false;
   }
 
   domEvent->SetTrusted(true);
-  domEvent->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
+  domEvent->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
 
   nsCOMPtr<EventTarget> target = do_QueryInterface(GetOuterWindow());
   domEvent->SetTarget(target);
 
   bool defaultActionEnabled = true;
   target->DispatchEvent(domEvent, &defaultActionEnabled);
 
   return defaultActionEnabled;
@@ -8493,17 +8491,17 @@ nsGlobalWindow::LeaveModalState()
   nsGlobalWindow *inner = topWin->GetCurrentInnerWindowInternal();
   if (inner)
     inner->mLastDialogQuitTime = TimeStamp::Now();
 
   if (topWin->mModalStateDepth == 0) {
     RefPtr<Event> event = NS_NewDOMEvent(inner, nullptr, nullptr);
     event->InitEvent(NS_LITERAL_STRING("endmodalstate"), true, false);
     event->SetTrusted(true);
-    event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
+    event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
     bool dummy;
     topWin->DispatchEvent(event, &dummy);
   }
 }
 
 bool
 nsGlobalWindow::IsInModalState()
 {
@@ -11107,17 +11105,17 @@ nsGlobalWindow::Observe(nsISupports* aSu
                                                         event, error);
     if (error.Failed()) {
       return error.StealNSResult();
     }
 
     newEvent->SetTrusted(true);
 
     if (fireMozStorageChanged) {
-      WidgetEvent* internalEvent = newEvent->GetInternalNSEvent();
+      WidgetEvent* internalEvent = newEvent->WidgetEventPtr();
       internalEvent->mFlags.mOnlyChromeDispatch = true;
     }
 
     if (IsFrozen()) {
       // This window is frozen, rather than firing the events here,
       // store the domain in which the change happened and fire the
       // events if we're ever thawed.
 
@@ -13240,17 +13238,17 @@ nsGlobalWindow::BeginWindowMove(Event& a
   }
 #endif
 
   if (!widget) {
     return;
   }
 
   WidgetMouseEvent* mouseEvent =
-    aMouseDownEvent.GetInternalNSEvent()->AsMouseEvent();
+    aMouseDownEvent.WidgetEventPtr()->AsMouseEvent();
   if (!mouseEvent || mouseEvent->mClass != eMouseEventClass) {
     aError.Throw(NS_ERROR_FAILURE);
     return;
   }
 
   aError = widget->BeginMoveDrag(mouseEvent);
 }
 
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -348,17 +348,17 @@ nsPluginCrashedEvent::Run()
   init.mSubmittedCrashReport = mSubmittedCrashReport;
   init.mBubbles = true;
   init.mCancelable = true;
 
   RefPtr<PluginCrashedEvent> event =
     PluginCrashedEvent::Constructor(doc, NS_LITERAL_STRING("PluginCrashed"), init);
 
   event->SetTrusted(true);
-  event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
+  event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
 
   EventDispatcher::DispatchDOMEvent(mContent, nullptr, event, nullptr, nullptr);
   return NS_OK;
 }
 
 class nsStopPluginRunnable : public nsRunnable, public nsITimerCallback
 {
 public:
--- a/dom/base/test/bug578096LoadChromeScript.js
+++ b/dom/base/test/bug578096LoadChromeScript.js
@@ -1,16 +1,16 @@
 var file;
 Components.utils.importGlobalProperties(["File"]);
 
 addMessageListener("file.create", function (message) {
   file = Components.classes["@mozilla.org/file/directory_service;1"]
              .getService(Components.interfaces.nsIProperties)
              .get("TmpD", Components.interfaces.nsIFile);
   file.append("foo.txt");
-  file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0600);
+  file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0o600);
   sendAsyncMessage("file.created", new File(file));
 });
 
 addMessageListener("file.remove", function (message) {
   file.remove(false);
   sendAsyncMessage("file.removed", {});
 });
--- a/dom/base/test/file_bug1198095.js
+++ b/dom/base/test/file_bug1198095.js
@@ -3,17 +3,17 @@ Cu.importGlobalProperties(["File"]);
 
 function createFileWithData(message) {
   var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
   var testFile = dirSvc.get("ProfD", Ci.nsIFile);
   testFile.append("fileAPItestfileBug1198095");
 
   var outStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
   outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
-                 0666, 0);
+                 0o666, 0);
 
   outStream.write(message, message.length);
   outStream.close();
 
   var domFile = new File(testFile);
   return domFile;
 }
 
--- a/dom/base/test/fileapi_chromeScript.js
+++ b/dom/base/test/fileapi_chromeScript.js
@@ -6,17 +6,17 @@ var fileNum = 1;
 function createFileWithData(fileData) {
   var willDelete = fileData === null;
   var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
   var testFile = dirSvc.get("ProfD", Ci.nsIFile);
   testFile.append("fileAPItestfile" + fileNum);
   fileNum++;
   var outStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
   outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
-                 0666, 0);
+                 0o666, 0);
   if (willDelete) {
     fileData = "some irrelevant test data\n";
   }
   outStream.write(fileData, fileData.length);
   outStream.close();
   var domFile = new File(testFile);
   if (willDelete) {
     testFile.remove(/* recursive: */ false);
--- a/dom/base/test/unit/head_xml.js
+++ b/dom/base/test/unit/head_xml.js
@@ -41,17 +41,17 @@ function ParseFile(file) {
     file = fileObj;
   }
 
   do_check_eq(file instanceof nsILocalFile, true);
 
   var fileStr = C["@mozilla.org/network/file-input-stream;1"]
                  .createInstance(nsIFileInputStream);
   // Init for readonly reading
-  fileStr.init(file,  0x01, 0400, nsIFileInputStream.CLOSE_ON_EOF);
+  fileStr.init(file,  0x01, 0o400, nsIFileInputStream.CLOSE_ON_EOF);
   return ParseXML(fileStr);
 }
 
 function ParseXML(data) {
   if (typeof(data) == "string") {
     return DOMParser().parseFromString(data, "application/xml");
   }
 
--- a/dom/events/AsyncEventDispatcher.cpp
+++ b/dom/events/AsyncEventDispatcher.cpp
@@ -40,17 +40,17 @@ AsyncEventDispatcher::Run()
   RefPtr<Event> event = mEvent ? mEvent->InternalDOMEvent() : nullptr;
   if (!event) {
     event = NS_NewDOMEvent(mTarget, nullptr, nullptr);
     event->InitEvent(mEventType, mBubbles, false);
     event->SetTrusted(true);
   }
   if (mOnlyChromeDispatch) {
     MOZ_ASSERT(event->IsTrusted());
-    event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
+    event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
   }
   bool dummy;
   mTarget->DispatchEvent(event, &dummy);
   return NS_OK;
 }
 
 nsresult
 AsyncEventDispatcher::PostDOMEvent()
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -624,17 +624,17 @@ Event::SetTarget(nsIDOMEventTarget* aTar
 
 NS_IMETHODIMP_(bool)
 Event::IsDispatchStopped()
 {
   return mEvent->mFlags.mPropagationStopped;
 }
 
 NS_IMETHODIMP_(WidgetEvent*)
-Event::GetInternalNSEvent()
+Event::WidgetEventPtr()
 {
   return mEvent;
 }
 
 NS_IMETHODIMP_(Event*)
 Event::InternalDOMEvent()
 {
   return this;
--- a/dom/events/Event.h
+++ b/dom/events/Event.h
@@ -354,17 +354,17 @@ private:
   NS_IMETHOD GetDefaultPrevented(bool* aDefaultPrevented) override { return _to GetDefaultPrevented(aDefaultPrevented); } \
   NS_IMETHOD StopImmediatePropagation(void) override { return _to StopImmediatePropagation(); } \
   NS_IMETHOD GetOriginalTarget(nsIDOMEventTarget** aOriginalTarget) override { return _to GetOriginalTarget(aOriginalTarget); } \
   NS_IMETHOD GetExplicitOriginalTarget(nsIDOMEventTarget** aExplicitOriginalTarget) override { return _to GetExplicitOriginalTarget(aExplicitOriginalTarget); } \
   NS_IMETHOD GetPreventDefault(bool* aRetval) override { return _to GetPreventDefault(aRetval); } \
   NS_IMETHOD GetIsTrusted(bool* aIsTrusted) override { return _to GetIsTrusted(aIsTrusted); } \
   NS_IMETHOD SetTarget(nsIDOMEventTarget* aTarget) override { return _to SetTarget(aTarget); } \
   NS_IMETHOD_(bool) IsDispatchStopped(void) override { return _to IsDispatchStopped(); } \
-  NS_IMETHOD_(WidgetEvent*) GetInternalNSEvent(void) override { return _to GetInternalNSEvent(); } \
+  NS_IMETHOD_(WidgetEvent*) WidgetEventPtr(void) override { return _to WidgetEventPtr(); } \
   NS_IMETHOD_(void) SetTrusted(bool aTrusted) override { _to SetTrusted(aTrusted); } \
   NS_IMETHOD_(void) SetOwner(EventTarget* aOwner) override { _to SetOwner(aOwner); } \
   NS_IMETHOD_(Event*) InternalDOMEvent() override { return _to InternalDOMEvent(); }
 
 #define NS_FORWARD_TO_EVENT_NO_SERIALIZATION_NO_DUPLICATION \
   NS_FORWARD_NSIDOMEVENT_NO_SERIALIZATION_NO_DUPLICATION(Event::) \
   virtual void PreventDefault(JSContext* aCx) override { Event::PreventDefault(aCx); }
 
--- a/dom/events/EventDispatcher.cpp
+++ b/dom/events/EventDispatcher.cpp
@@ -504,17 +504,17 @@ EventDispatcher::Dispatch(nsISupports* a
         NS_WARNING("Fix the caller!");
       } else {
         NS_ERROR("This is unsafe! Fix the caller!");
       }
     }
   }
 
   if (aDOMEvent) {
-    WidgetEvent* innerEvent = aDOMEvent->GetInternalNSEvent();
+    WidgetEvent* innerEvent = aDOMEvent->WidgetEventPtr();
     NS_ASSERTION(innerEvent == aEvent,
                   "The inner event of aDOMEvent is not the same as aEvent!");
   }
 #endif
 
   nsresult rv = NS_OK;
   bool externalDOMEvent = !!(aDOMEvent);
 
@@ -693,17 +693,17 @@ EventDispatcher::Dispatch(nsISupports* a
 /* static */ nsresult
 EventDispatcher::DispatchDOMEvent(nsISupports* aTarget,
                                   WidgetEvent* aEvent,
                                   nsIDOMEvent* aDOMEvent,
                                   nsPresContext* aPresContext,
                                   nsEventStatus* aEventStatus)
 {
   if (aDOMEvent) {
-    WidgetEvent* innerEvent = aDOMEvent->GetInternalNSEvent();
+    WidgetEvent* innerEvent = aDOMEvent->WidgetEventPtr();
     NS_ENSURE_TRUE(innerEvent, NS_ERROR_ILLEGAL_VALUE);
 
     bool dontResetTrusted = false;
     if (innerEvent->mFlags.mDispatchedAtLeastOnce) {
       innerEvent->target = nullptr;
       innerEvent->originalTarget = nullptr;
     } else {
       aDOMEvent->GetIsTrusted(&dontResetTrusted);
--- a/dom/events/IMEStateManager.cpp
+++ b/dom/events/IMEStateManager.cpp
@@ -579,17 +579,17 @@ IMEStateManager::OnMouseButtonEventInEdi
   if (!sActiveIMEContentObserver->IsManaging(aPresContext, aContent)) {
     MOZ_LOG(sISMLog, LogLevel::Debug,
       ("ISM:   IMEStateManager::OnMouseButtonEventInEditor(), "
        "the active IMEContentObserver isn't managing the editor"));
     return false;
   }
 
   WidgetMouseEvent* internalEvent =
-    aMouseEvent->AsEvent()->GetInternalNSEvent()->AsMouseEvent();
+    aMouseEvent->AsEvent()->WidgetEventPtr()->AsMouseEvent();
   if (NS_WARN_IF(!internalEvent)) {
     MOZ_LOG(sISMLog, LogLevel::Debug,
       ("ISM:   IMEStateManager::OnMouseButtonEventInEditor(), "
        "the internal event of aMouseEvent isn't WidgetMouseEvent"));
     return false;
   }
 
   bool consumed =
--- a/dom/html/nsTextEditorState.cpp
+++ b/dom/html/nsTextEditorState.cpp
@@ -867,17 +867,17 @@ nsTextInputListener::HandleEvent(nsIDOME
   bool isTrusted = false;
   rv = aEvent->GetIsTrusted(&isTrusted);
   NS_ENSURE_SUCCESS(rv, rv);
   if (!isTrusted) {
     return NS_OK;
   }
 
   WidgetKeyboardEvent* keyEvent =
-    aEvent->GetInternalNSEvent()->AsKeyboardEvent();
+    aEvent->WidgetEventPtr()->AsKeyboardEvent();
   if (!keyEvent) {
     return NS_ERROR_UNEXPECTED;
   }
 
   if (keyEvent->mMessage != eKeyPress) {
     return NS_OK;
   }
 
--- a/dom/indexedDB/ActorsChild.cpp
+++ b/dom/indexedDB/ActorsChild.cpp
@@ -738,17 +738,17 @@ DispatchErrorEvent(IDBRequest* aRequest,
   nsresult rv = request->DispatchEvent(aEvent, &doDefault);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
   MOZ_ASSERT(!transaction || transaction->IsOpen() || transaction->IsAborted());
 
   if (transaction && transaction->IsOpen()) {
-    WidgetEvent* internalEvent = aEvent->GetInternalNSEvent();
+    WidgetEvent* internalEvent = aEvent->WidgetEventPtr();
     MOZ_ASSERT(internalEvent);
 
     if (internalEvent->mFlags.mExceptionHasBeenRisen) {
       transaction->Abort(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR);
     } else if (doDefault) {
       transaction->Abort(request);
     }
   }
@@ -811,17 +811,17 @@ DispatchSuccessEvent(ResultHelper* aResu
   nsresult rv = request->DispatchEvent(aEvent, &dummy);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
   MOZ_ASSERT_IF(transaction,
                 transaction->IsOpen() || transaction->IsAborted());
 
-  WidgetEvent* internalEvent = aEvent->GetInternalNSEvent();
+  WidgetEvent* internalEvent = aEvent->WidgetEventPtr();
   MOZ_ASSERT(internalEvent);
 
   if (transaction &&
       transaction->IsOpen() &&
       internalEvent->mFlags.mExceptionHasBeenRisen) {
     transaction->Abort(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR);
   }
 }
--- a/dom/indexedDB/test/unit/test_blob_file_backed.js
+++ b/dom/indexedDB/test/unit/test_blob_file_backed.js
@@ -7,17 +7,17 @@ var disableWorkerTest = "This test uses 
 
 var testGenerator = testSteps();
 
 function testSteps()
 {
   const fileIOFlags = 0x02 | // PR_WRONLY
                       0x08 | // PR_CREATEFILE
                       0x20;  // PR_TRUNCATE
-  const filePerms = 0664;
+  const filePerms = 0o664;
   const fileData = "abcdefghijklmnopqrstuvwxyz";
   const fileType = "text/plain";
 
   const databaseName =
     ("window" in this) ? window.location.pathname : "Test";
   const objectStoreName = "foo";
   const objectStoreKey = "10";
 
--- a/dom/interfaces/events/nsIDOMEvent.idl
+++ b/dom/interfaces/events/nsIDOMEvent.idl
@@ -2,17 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "domstubs.idl"
 
 interface nsIDOMEventTarget;
 
-[ptr] native WidgetEventPtr(mozilla::WidgetEvent);
+[ptr] native WidgetEvent(mozilla::WidgetEvent);
 [ptr] native DOMEventPtr(mozilla::dom::Event);
 [ptr] native IPCMessagePtr(IPC::Message);
 [ptr] native ConstIPCMessagePtr(const IPC::Message);
 [ptr] native EventTargetPtr(mozilla::dom::EventTarget);
 %{C++
 #ifdef ERROR
 #undef ERROR
 #endif
@@ -202,17 +202,17 @@ interface nsIDOMEvent : nsISupports
    */
   boolean                   getPreventDefault();
 
   readonly attribute boolean isTrusted;
 
   [noscript] void duplicatePrivateData();
   [noscript] void setTarget(in nsIDOMEventTarget aTarget);
   [notxpcom] boolean IsDispatchStopped();
-  [notxpcom] WidgetEventPtr GetInternalNSEvent();
+  [notxpcom] WidgetEvent WidgetEventPtr();
   [noscript,notxpcom] void SetTrusted(in boolean aTrusted);
   [notxpcom] void Serialize(in IPCMessagePtr aMsg,
                             in boolean aSerializeInterfaceType);
   [notxpcom] boolean Deserialize(in ConstIPCMessagePtr aMsg, out voidPtr aIter);
   [noscript,notxpcom] void SetOwner(in EventTargetPtr aOwner);
   [notxpcom] DOMEventPtr InternalDOMEvent();
   [noscript] void stopCrossProcessForwarding();
 };
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -3096,17 +3096,17 @@ TabParent::LayerTreeUpdate(bool aActive)
 
   RefPtr<Event> event = NS_NewDOMEvent(mFrameElement, nullptr, nullptr);
   if (aActive) {
     event->InitEvent(NS_LITERAL_STRING("MozLayerTreeReady"), true, false);
   } else {
     event->InitEvent(NS_LITERAL_STRING("MozLayerTreeCleared"), true, false);
   }
   event->SetTrusted(true);
-  event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
+  event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
   bool dummy;
   mFrameElement->DispatchEvent(event, &dummy);
   return true;
 }
 
 void
 TabParent::SwapLayerTreeObservers(TabParent* aOther)
 {
@@ -3131,17 +3131,17 @@ TabParent::RecvRemotePaintIsReady()
   if (!target) {
     NS_WARNING("Could not locate target for MozAfterRemotePaint message.");
     return true;
   }
 
   RefPtr<Event> event = NS_NewDOMEvent(mFrameElement, nullptr, nullptr);
   event->InitEvent(NS_LITERAL_STRING("MozAfterRemotePaint"), false, false);
   event->SetTrusted(true);
-  event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
+  event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
   bool dummy;
   mFrameElement->DispatchEvent(event, &dummy);
   return true;
 }
 
 mozilla::plugins::PPluginWidgetParent*
 TabParent::AllocPPluginWidgetParent()
 {
--- a/dom/json/test/unit/test_encode.js
+++ b/dom/json/test/unit/test_encode.js
@@ -7,17 +7,17 @@ var dirSvc = Cc["@mozilla.org/file/direc
 var workingDir = dirSvc.get("TmpD", Ci.nsIFile);
 
 var outputName = "json-test-output";
 var outputDir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
 outputDir.initWithFile(workingDir);
 outputDir.append(outputName);
 
 if (!outputDir.exists()) {
-  outputDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0777);
+  outputDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o777);
 } else if (!outputDir.isDirectory()) {
   do_throw(outputName + " is not a directory?")
 }
 
 function testStringEncode()
 {
   var obj1 = {a:1};
   var obj2 = {foo:"bar"};
@@ -78,20 +78,20 @@ function testThrowingToJSON() {
   }
 }
 
 function testOutputStreams() {
   function writeToFile(obj, charset, writeBOM) {
     var jsonFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
     jsonFile.initWithFile(outputDir);
     jsonFile.append("test.json");
-    jsonFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
+    jsonFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600);
     var stream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
     try {
-      stream.init(jsonFile, 0x04 | 0x08 | 0x20, 0600, 0); // write, create, truncate
+      stream.init(jsonFile, 0x04 | 0x08 | 0x20, 0o600, 0); // write, create, truncate
       nativeJSON.encodeToStream(stream, charset, writeBOM, obj);
     } finally {
       stream.close();
     }
     return jsonFile;
   }
 
   var pairs = [
--- a/dom/media/gmp/GMPService.cpp
+++ b/dom/media/gmp/GMPService.cpp
@@ -200,17 +200,17 @@ GeckoMediaPluginService::GMPCrashCallbac
   nsCOMPtr<nsIDocument> document;
   if (!GetParentWindowAndDocumentIfValid(parentWindow, document)) {
     return;
   }
 
   RefPtr<dom::PluginCrashedEvent> event =
     dom::PluginCrashedEvent::Constructor(document, NS_LITERAL_STRING("PluginCrashed"), init);
   event->SetTrusted(true);
-  event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
+  event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
 
   EventDispatcher::DispatchDOMEvent(parentWindow, nullptr, event, nullptr, nullptr);
 }
 
 bool
 GeckoMediaPluginService::GMPCrashCallback::IsStillValid()
 {
   nsCOMPtr<nsPIDOMWindowInner> parentWindow;
--- a/dom/media/mediasink/DecodedStream.cpp
+++ b/dom/media/mediasink/DecodedStream.cpp
@@ -14,16 +14,25 @@
 #include "MediaStreamGraph.h"
 #include "OutputStreamManager.h"
 #include "SharedBuffer.h"
 #include "VideoSegment.h"
 #include "VideoUtils.h"
 
 namespace mozilla {
 
+/*
+ * A container class to make it easier to pass the playback info all the
+ * way to DecodedStreamGraphListener from DecodedStream.
+ */
+struct PlaybackInfoInit {
+  int64_t mStartTime;
+  MediaInfo mInfo;
+};
+
 class DecodedStreamGraphListener : public MediaStreamListener {
   typedef MediaStreamListener::MediaStreamGraphEvent MediaStreamGraphEvent;
 public:
   DecodedStreamGraphListener(MediaStream* aStream,
                              MozPromiseHolder<GenericPromise>&& aPromise)
     : mMutex("DecodedStreamGraphListener::mMutex")
     , mStream(aStream)
     , mLastOutputTime(aStream->StreamTimeToMicroseconds(aStream->GetCurrentTime()))
@@ -102,17 +111,18 @@ UpdateStreamSuspended(MediaStream* aStre
  * We have at most one DecodedStreamDaata per MediaDecoder. Its stream
  * is used as the input for each ProcessedMediaStream created by calls to
  * captureStream(UntilEnded). Seeking creates a new source stream, as does
  * replaying after the input as ended. In the latter case, the new source is
  * not connected to streams created by captureStreamUntilEnded.
  */
 class DecodedStreamData {
 public:
-  DecodedStreamData(SourceMediaStream* aStream,
+  DecodedStreamData(OutputStreamManager* aOutputStreamManager,
+                    PlaybackInfoInit&& aInit,
                     MozPromiseHolder<GenericPromise>&& aPromise);
   ~DecodedStreamData();
   int64_t GetPosition() const;
   void SetPlaying(bool aPlaying);
 
   /* The following group of fields are protected by the decoder's monitor
    * and can be read or written on any thread.
    */
@@ -122,55 +132,66 @@ public:
   // Therefore video packets starting at or after this time need to be copied
   // to the output stream.
   int64_t mNextVideoTime; // microseconds
   int64_t mNextAudioTime; // microseconds
   // The last video image sent to the stream. Useful if we need to replicate
   // the image.
   RefPtr<layers::Image> mLastVideoImage;
   gfx::IntSize mLastVideoImageDisplaySize;
-  // This is set to true when the stream is initialized (audio and
-  // video tracks added).
-  bool mStreamInitialized;
   bool mHaveSentFinish;
   bool mHaveSentFinishAudio;
   bool mHaveSentFinishVideo;
 
   // The decoder is responsible for calling Destroy() on this stream.
   const RefPtr<SourceMediaStream> mStream;
-  RefPtr<DecodedStreamGraphListener> mListener;
+  const RefPtr<DecodedStreamGraphListener> mListener;
   bool mPlaying;
   // True if we need to send a compensation video frame to ensure the
   // StreamTime going forward.
   bool mEOSVideoCompensation;
+
+  const RefPtr<OutputStreamManager> mOutputStreamManager;
 };
 
-DecodedStreamData::DecodedStreamData(SourceMediaStream* aStream,
+DecodedStreamData::DecodedStreamData(OutputStreamManager* aOutputStreamManager,
+                                     PlaybackInfoInit&& aInit,
                                      MozPromiseHolder<GenericPromise>&& aPromise)
   : mAudioFramesWritten(0)
-  , mNextVideoTime(-1)
-  , mNextAudioTime(-1)
-  , mStreamInitialized(false)
+  , mNextVideoTime(aInit.mStartTime)
+  , mNextAudioTime(aInit.mStartTime)
   , mHaveSentFinish(false)
   , mHaveSentFinishAudio(false)
   , mHaveSentFinishVideo(false)
-  , mStream(aStream)
+  , mStream(aOutputStreamManager->Graph()->CreateSourceStream(nullptr))
+  // DecodedStreamGraphListener will resolve this promise.
+  , mListener(new DecodedStreamGraphListener(mStream, Move(aPromise)))
+  // mPlaying is initially true because MDSM won't start playback until playing
+  // becomes true. This is consistent with the settings of AudioSink.
   , mPlaying(true)
   , mEOSVideoCompensation(false)
+  , mOutputStreamManager(aOutputStreamManager)
 {
-  // DecodedStreamGraphListener will resolve this promise.
-  mListener = new DecodedStreamGraphListener(mStream, Move(aPromise));
   mStream->AddListener(mListener);
+  mOutputStreamManager->Connect(mStream);
 
-  // mPlaying is initially true because MDSM won't start playback until playing
-  // becomes true. This is consistent with the settings of AudioSink.
+  // Initialize tracks.
+  if (aInit.mInfo.HasAudio()) {
+    mStream->AddAudioTrack(aInit.mInfo.mAudio.mTrackId,
+                           aInit.mInfo.mAudio.mRate,
+                           0, new AudioSegment());
+  }
+  if (aInit.mInfo.HasVideo()) {
+    mStream->AddTrack(aInit.mInfo.mVideo.mTrackId, 0, new VideoSegment());
+  }
 }
 
 DecodedStreamData::~DecodedStreamData()
 {
+  mOutputStreamManager->Disconnect();
   mListener->Forget();
   mStream->Destroy();
 }
 
 int64_t
 DecodedStreamData::GetPosition() const
 {
   return mListener->GetLastOutputTime();
@@ -243,37 +264,41 @@ DecodedStream::Start(int64_t aStartTime,
 
   mStartTime.emplace(aStartTime);
   mInfo = aInfo;
   mPlaying = true;
   ConnectListener();
 
   class R : public nsRunnable {
     typedef MozPromiseHolder<GenericPromise> Promise;
-    typedef void(DecodedStream::*Method)(Promise&&);
+    typedef decltype(&DecodedStream::CreateData) Method;
   public:
-    R(DecodedStream* aThis, Method aMethod, Promise&& aPromise)
-      : mThis(aThis), mMethod(aMethod)
+    R(DecodedStream* aThis, Method aMethod, PlaybackInfoInit&& aInit, Promise&& aPromise)
+      : mThis(aThis), mMethod(aMethod), mInit(Move(aInit))
     {
       mPromise = Move(aPromise);
     }
     NS_IMETHOD Run() override
     {
-      (mThis->*mMethod)(Move(mPromise));
+      (mThis->*mMethod)(Move(mInit), Move(mPromise));
       return NS_OK;
     }
   private:
     RefPtr<DecodedStream> mThis;
     Method mMethod;
+    PlaybackInfoInit mInit;
     Promise mPromise;
   };
 
   MozPromiseHolder<GenericPromise> promise;
   mFinishPromise = promise.Ensure(__func__);
-  nsCOMPtr<nsIRunnable> r = new R(this, &DecodedStream::CreateData, Move(promise));
+  PlaybackInfoInit init {
+    aStartTime, aInfo
+  };
+  nsCOMPtr<nsIRunnable> r = new R(this, &DecodedStream::CreateData, Move(init), Move(promise));
   AbstractThread::MainThread()->Dispatch(r.forget());
 }
 
 void
 DecodedStream::Stop()
 {
   AssertOwnerThread();
   MOZ_ASSERT(mStartTime.isSome(), "playback not started.");
@@ -306,40 +331,36 @@ DecodedStream::DestroyData(UniquePtr<Dec
 {
   AssertOwnerThread();
 
   if (!aData) {
     return;
   }
 
   DecodedStreamData* data = aData.release();
-  RefPtr<DecodedStream> self = this;
   nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
-    self->mOutputStreamManager->Disconnect();
     delete data;
   });
   AbstractThread::MainThread()->Dispatch(r.forget());
 }
 
 void
-DecodedStream::CreateData(MozPromiseHolder<GenericPromise>&& aPromise)
+DecodedStream::CreateData(PlaybackInfoInit&& aInit, MozPromiseHolder<GenericPromise>&& aPromise)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // No need to create a source stream when there are no output streams. This
   // happens when RemoveOutput() is called immediately after StartPlayback().
   if (!mOutputStreamManager->Graph()) {
     // Resolve the promise to indicate the end of playback.
     aPromise.Resolve(true, __func__);
     return;
   }
 
-  auto source = mOutputStreamManager->Graph()->CreateSourceStream(nullptr);
-  auto data = new DecodedStreamData(source, Move(aPromise));
-  mOutputStreamManager->Connect(data->mStream);
+  auto data = new DecodedStreamData(mOutputStreamManager, Move(aInit), Move(aPromise));
 
   class R : public nsRunnable {
     typedef void(DecodedStream::*Method)(UniquePtr<DecodedStreamData>);
   public:
     R(DecodedStream* aThis, Method aMethod, DecodedStreamData* aData)
       : mThis(aThis), mMethod(aMethod), mData(aData) {}
     NS_IMETHOD Run() override
     {
@@ -349,19 +370,17 @@ DecodedStream::CreateData(MozPromiseHold
   private:
     virtual ~R()
     {
       // mData is not transferred when dispatch fails and Run() is not called.
       // We need to dispatch a task to ensure DecodedStreamData is destroyed
       // properly on the main thread.
       if (mData) {
         DecodedStreamData* data = mData.release();
-        RefPtr<DecodedStream> self = mThis.forget();
         nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
-          self->mOutputStreamManager->Disconnect();
           delete data;
         });
         // We are in tail dispatching phase. Don't call
         // AbstractThread::MainThread()->Dispatch() to avoid reentrant
         // AutoTaskDispatcher.
         NS_DispatchToMainThread(r.forget());
       }
     }
@@ -426,47 +445,16 @@ DecodedStream::SetPlaybackRate(double aP
 
 void
 DecodedStream::SetPreservesPitch(bool aPreservesPitch)
 {
   AssertOwnerThread();
   mParams.mPreservesPitch = aPreservesPitch;
 }
 
-void
-DecodedStream::InitTracks()
-{
-  AssertOwnerThread();
-
-  if (mData->mStreamInitialized) {
-    return;
-  }
-
-  SourceMediaStream* sourceStream = mData->mStream;
-
-  if (mInfo.HasAudio()) {
-    TrackID audioTrackId = mInfo.mAudio.mTrackId;
-    AudioSegment* audio = new AudioSegment();
-    sourceStream->AddAudioTrack(audioTrackId, mInfo.mAudio.mRate, 0, audio,
-                                SourceMediaStream::ADDTRACK_QUEUED);
-    mData->mNextAudioTime = mStartTime.ref();
-  }
-
-  if (mInfo.HasVideo()) {
-    TrackID videoTrackId = mInfo.mVideo.mTrackId;
-    VideoSegment* video = new VideoSegment();
-    sourceStream->AddTrack(videoTrackId, 0, video,
-                           SourceMediaStream::ADDTRACK_QUEUED);
-    mData->mNextVideoTime = mStartTime.ref();
-  }
-
-  sourceStream->FinishAddTracks();
-  mData->mStreamInitialized = true;
-}
-
 static void
 SendStreamAudio(DecodedStreamData* aStream, int64_t aStartTime,
                 MediaData* aData, AudioSegment* aOutput,
                 uint32_t aRate, double aVolume)
 {
   // The amount of audio frames that is used to fuzz rounding errors.
   static const int64_t AUDIO_FUZZ_FRAMES = 1;
 
@@ -689,17 +677,16 @@ DecodedStream::SendData()
     return;
   }
 
   // Nothing to do when the stream is finished.
   if (mData->mHaveSentFinish) {
     return;
   }
 
-  InitTracks();
   SendAudio(mParams.mVolume, mSameOrigin);
   SendVideo(mSameOrigin);
   AdvanceTracks();
 
   bool finished = (!mInfo.HasAudio() || mAudioQueue.IsFinished()) &&
                   (!mInfo.HasVideo() || mVideoQueue.IsFinished());
 
   if (finished && !mData->mHaveSentFinish) {
--- a/dom/media/mediasink/DecodedStream.h
+++ b/dom/media/mediasink/DecodedStream.h
@@ -18,16 +18,17 @@
 #include "mozilla/UniquePtr.h"
 
 namespace mozilla {
 
 class DecodedStreamData;
 class MediaData;
 class MediaStream;
 class OutputStreamManager;
+struct PlaybackInfoInit;
 class ProcessedMediaStream;
 class TimeStamp;
 
 template <class T> class MediaQueue;
 
 class DecodedStream : public media::MediaSink {
   using media::MediaSink::PlaybackParams;
 
@@ -60,20 +61,19 @@ public:
   void Stop() override;
   bool IsStarted() const override;
   bool IsPlaying() const override;
 
 protected:
   virtual ~DecodedStream();
 
 private:
-  void CreateData(MozPromiseHolder<GenericPromise>&& aPromise);
+  void CreateData(PlaybackInfoInit&& aInit, MozPromiseHolder<GenericPromise>&& aPromise);
   void DestroyData(UniquePtr<DecodedStreamData> aData);
   void OnDataCreated(UniquePtr<DecodedStreamData> aData);
-  void InitTracks();
   void AdvanceTracks();
   void SendAudio(double aVolume, bool aIsSameOrigin);
   void SendVideo(bool aIsSameOrigin);
   void SendData();
 
   void AssertOwnerThread() const {
     MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
   }
--- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp
@@ -42,19 +42,21 @@ ChoosePixelFormat(AVCodecContext* aCodec
 {
   FFMPEG_LOG("Choosing FFmpeg pixel format for video decoding.");
   for (; *aFormats > -1; aFormats++) {
     switch (*aFormats) {
       case AV_PIX_FMT_YUV444P:
         FFMPEG_LOG("Requesting pixel format YUV444P.");
         return AV_PIX_FMT_YUV444P;
       case AV_PIX_FMT_YUV420P:
-      case AV_PIX_FMT_YUVJ420P:
         FFMPEG_LOG("Requesting pixel format YUV420P.");
         return AV_PIX_FMT_YUV420P;
+      case AV_PIX_FMT_YUVJ420P:
+        FFMPEG_LOG("Requesting pixel format YUVJ420P.");
+        return AV_PIX_FMT_YUVJ420P;
       default:
         break;
     }
   }
 
   NS_WARNING("FFmpeg does not share any supported pixel formats.");
   return AV_PIX_FMT_NONE;
 }
--- a/dom/media/test/external/README.md
+++ b/dom/media/test/external/README.md
@@ -1,17 +1,33 @@
 external-media-tests
 ===================
 
 [Marionette Python tests][marionette-python-tests] for media playback in Mozilla Firefox. MediaTestCase uses [Firefox Puppeteer][ff-puppeteer-docs] library.
 
 Setup
 -----
 
-Normally, you get this source by cloning a firefox repo such as mozilla-central. The path to these tests would be in <mozilla-central>/dom/media/test/external, and these instuctions refer to this path as '$PROJECT_HOME'.
+Normally, you get this source by cloning a firefox repo such as mozilla-central. The path to these tests would be in <mozilla-central>/dom/media/test/external, and these instructions refer to this path as '$PROJECT_HOME'.
+
+Running from a build
+--------------------
+
+If you have built Firefox using ./mach build from a source tree such as mozilla-central, you can run the following command:
+
+    '''sh
+    $ ./mach external-media-tests
+    '''
+
+You can pass any of the test options on this command line. They are listed below.
+
+Running with an installer and a tests payload
+---------------------------------------------
+
+If you are testing a version of Firefox that you have not built, you must setup a virtualenv to run tests from. You will need a path to the installer or binary of Firefox.
 
 * Create a virtualenv called `foo`.
 
    ```sh
    $ virtualenv foo
    $ source foo/bin/activate #or `foo\Scripts\activate` on Windows
    ```
 
@@ -22,56 +38,81 @@ Normally, you get this source by cloning
    ```
 
 Now `external-media-tests` should be a recognized command. Try `external-media-tests --help` to see if it works.
 
 
 Running the Tests
 -----------------
 
-In the examples below, `$FF_PATH` is a path to a recent Firefox binary.
+In the examples below, `$FF_PATH` is a path to a recent Firefox binary. If you are running from a source build, the commands below should be invoked with:
+
+    '''sh
+    ./mach external-media-tests
+    '''
+
+If you are running with a virtualenv, you will need to run like this:
+
+    '''sh
+    external-media-tests --binary $FF_PATH
+    '''
+
+or
+
+    '''sh
+    external-media-tests --installer $FF_INSTALLER_PATH
+    '''
+
+or
+
+    '''sh
+    external-media-tests --installer-url <url to installer package>
+    '''
+
+The following examples assume that you will use of these command lines instead of $EXTERNAL-MEDIA-TESTS.
+
 
 This runs all the tests listed in `$PROJECT_HOME/external_media_tests/manifest.ini`:
 
    ```sh
-   $ external-media-tests --binary $FF_PATH
+   $ $EXTERNAL-MEDIA-TESTS
    ```
 
 You can also run all the tests at a particular path:
 
    ```sh
-   $ external-media-tests --binary $FF_PATH some/path/foo
+   $ $EXTERNAL-MEDIA-TESTS some/path/foo
    ```
 
 Or you can run the tests that are listed in a manifest file of your choice.
 
    ```sh
-   $ external-media-tests --binary $FF_PATH some/other/path/manifest.ini
+   $ $EXTERNAL-MEDIA-TESTS some/other/path/manifest.ini
    ```
 
 By default, the urls listed in `external_media_tests/urls/default.ini` are used for the tests, but you can also supply your own ini file of urls:
 
    ```sh
-   $ external-media-tests --binary $FF_PATH --urls some/other/path/my_urls.ini
+   $ $EXTERNAL-MEDIA-TESTS --urls some/other/path/my_urls.ini
    ```
 
 ### Running EME tests
 
 In order to run EME tests, you must use a Firefox profile that has a signed plugin-container.exe and voucher.bin. With Netflix, this will be created when you log in and save the credentials. You must also use a custom .ini file for urls to the provider's content and indicate which test to run, like above. Ex:
 
    ```sh
-   $ external-media-tests --binary $FF_PATH some/path/tests.ini --profile custom_profile --urls some/path/provider-urls.ini
+   $ $EXTERNAL-MEDIA-TESTS some/path/tests.ini --profile custom_profile --urls some/path/provider-urls.ini
    ```
 
 
 ### Running tests in a way that provides information about a crash
 
 What if Firefox crashes during a test run? You want to know why! To report useful crash data, the test runner needs access to a "minidump_stackwalk" binary and a "symbols.zip" file.
 
-1. Download a `minidump_stackwalk` binary for your platform (save it whereever). Get it from http://hg.mozilla.org/build/tools/file/tip/breakpad/.
+1. Download a `minidump_stackwalk` binary for your platform (save it wherever). Get it from http://hg.mozilla.org/build/tools/file/tip/breakpad/.
 2. Make `minidump_stackwalk` executable
 
    ```sh
    $ chmod +x path/to/minidump_stackwalk
    ```
 
 3. Create an environment variable called `MINIDUMP_STACKWALK` that points to that local path
 
@@ -79,17 +120,17 @@ 3. Create an environment variable called
    $ export MINIDUMP_STACKWALK=path/to/minidump_stackwalk
    ```
 
 4. Download the `crashreporter-symbols.zip` file for the Firefox build you are testing and extract it. Example: ftp://ftp.mozilla.org/pub/firefox/tinderbox-builds/mozilla-aurora-win32/1427442016/firefox-38.0a2.en-US.win32.crashreporter-symbols.zip
 
 5. Run the tests with a `--symbols-path` flag
 
   ```sh
-   $ external-media-tests --binary $FF_PATH --symbols-path path/to/example/firefox-38.0a2.en-US.win32.crashreporter-symbols
+   $ $EXTERNAL-MEDIA-TESTS --symbols-path path/to/example/firefox-38.0a2.en-US.win32.crashreporter-symbols
   ```
 
 To check whether the above setup is working for you, trigger a (silly) Firefox crash while the tests are running. One way to do this is with the [crashme add-on](https://github.com/luser/crashme) -- you can add it to Firefox even while the tests are running. Another way on Linux and Mac OS systems:
 
 1. Find the process id (PID) of the Firefox process being used by the tests.
 
   ```sh
    $ ps x | grep 'Firefox'
@@ -119,27 +160,25 @@ Crash reason:  EXC_SOFTWARE / SIGABRT
 Crash address: 0x104616900
 ...
 ```
 
 ### Setting up for network shaping tests (browsermobproxy)
 
 1. Download the browsermob proxy zip file from http://bmp.lightbody.net/. The most current version as of this writing is browsermob-proxy-2.1.0-beta-2-bin.zip.
 2. Unpack the .zip file.
-3. Verify that you can launch browsermobproxy on your machine by running \<browsermob\>/bin/browsermob-proxy on your machine. I had to do a lot of work to install and use a java that browsermobproxy would like.
+3. Verify that you can launch browsermobproxy on your machine by running \<browsermob\>/bin/browsermob-proxy (or browsermob-proxy.bat on Windows) on your machine. I had to do a lot of work to install and use a java that browsermobproxy would like.
 4. Import the certificate into your Firefox profile. Select Preferences->Advanced->Certificates->View Certificates->Import... Navigate to <browsermob>/ssl-support and select cybervilliansCA.cer. Select all of the checkboxes.
-5. Tell marionette where browsermobproxy is and what port to start it on. Add the following command-line parameters to your firefox-media-tests command line:
+5. Tell marionette where browsermobproxy is and what port to start it on. Add the following command-line parameters to your external-media-tests command line:
 
 <pre><code>
 --browsermob-script <browsermob>/bin/browsermob-proxy --browsermob-port 999 --profile <your saved profile>
 </code></pre>
 
-On Windows, use browsermob-proxy.bat.
-
-You can then call browsermob to shape the network. You can find an example in firefox_media_tests/playback/test_playback_limiting_bandwidth.py. Another example can be found at https://dxr.mozilla.org/mozilla-central/source/testing/marionette/client/marionette/tests/unit/test_browsermobproxy.py.
+You can then call browsermob to shape the network. You can find an example in external_media_tests/playback/test_playback_limiting_bandwidth.py. Another example can be found at https://dxr.mozilla.org/mozilla-central/source/testing/marionette/client/marionette/tests/unit/test_browsermobproxy.py.
 
 ### A warning about video URLs
 The ini files in `external_media_tests/urls` may contain URLs pulled from Firefox crash or bug data. Automated tests don't care about video content, but you might: visit these at your own risk and be aware that they may be NSFW. We do not intend to ever moderate or filter these URLs.
 
 Writing a test
 --------------
 Write your test in a new or existing `test_*.py` file under `$PROJECT_HOME/external_media_tests`. Add it to the appropriate `manifest.ini` file(s) as well. Look in `media_utils` for useful video-playback functions.
 
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -1660,17 +1660,17 @@ nsresult nsPluginInstanceOwner::Dispatch
 
 #ifndef XP_MACOSX
   if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow)) {
     // continue only for cases without child window
     return aFocusEvent->PreventDefault(); // consume event
   }
 #endif
 
-  WidgetEvent* theEvent = aFocusEvent->GetInternalNSEvent();
+  WidgetEvent* theEvent = aFocusEvent->WidgetEventPtr();
   if (theEvent) {
     WidgetGUIEvent focusEvent(theEvent->mFlags.mIsTrusted, theEvent->mMessage,
                               nullptr);
     nsEventStatus rv = ProcessEvent(focusEvent);
     if (nsEventStatus_eConsumeNoDefault == rv) {
       aFocusEvent->PreventDefault();
       aFocusEvent->StopPropagation();
     }
@@ -1702,17 +1702,17 @@ nsresult nsPluginInstanceOwner::Dispatch
 #if !defined(XP_MACOSX)
   if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow))
     return aKeyEvent->PreventDefault(); // consume event
   // continue only for cases without child window
 #endif
 
   if (mInstance) {
     WidgetKeyboardEvent* keyEvent =
-      aKeyEvent->GetInternalNSEvent()->AsKeyboardEvent();
+      aKeyEvent->WidgetEventPtr()->AsKeyboardEvent();
     if (keyEvent && keyEvent->mClass == eKeyboardEventClass) {
       nsEventStatus rv = ProcessEvent(*keyEvent);
       if (nsEventStatus_eConsumeNoDefault == rv) {
         aKeyEvent->PreventDefault();
         aKeyEvent->StopPropagation();
       }
     }
   }
@@ -1737,17 +1737,17 @@ nsPluginInstanceOwner::ProcessMouseDown(
     nsIFocusManager* fm = nsFocusManager::GetFocusManager();
     if (fm) {
       nsCOMPtr<nsIDOMElement> elem = do_QueryReferent(mContent);
       fm->SetFocus(elem, 0);
     }
   }
 
   WidgetMouseEvent* mouseEvent =
-    aMouseEvent->GetInternalNSEvent()->AsMouseEvent();
+    aMouseEvent->WidgetEventPtr()->AsMouseEvent();
   if (mouseEvent && mouseEvent->mClass == eMouseEventClass) {
     mLastMouseDownButtonType = mouseEvent->button;
     nsEventStatus rv = ProcessEvent(*mouseEvent);
     if (nsEventStatus_eConsumeNoDefault == rv) {
       return aMouseEvent->PreventDefault(); // consume event
     }
   }
 
@@ -1762,17 +1762,17 @@ nsresult nsPluginInstanceOwner::Dispatch
     return aMouseEvent->PreventDefault(); // consume event
   // continue only for cases without child window
 #endif
   // don't send mouse events if we are hidden
   if (!mWidgetVisible)
     return NS_OK;
 
   WidgetMouseEvent* mouseEvent =
-    aMouseEvent->GetInternalNSEvent()->AsMouseEvent();
+    aMouseEvent->WidgetEventPtr()->AsMouseEvent();
   if (mouseEvent && mouseEvent->mClass == eMouseEventClass) {
     nsEventStatus rv = ProcessEvent(*mouseEvent);
     if (nsEventStatus_eConsumeNoDefault == rv) {
       aMouseEvent->PreventDefault();
       if (!aAllowPropagate) {
         aMouseEvent->StopPropagation();
       }
     }
@@ -1877,17 +1877,17 @@ nsPluginInstanceOwner::DispatchCompositi
 {
 #ifdef XP_WIN
   if (!mPluginWindow) {
     // CompositionEvent isn't cancellable.  So it is unnecessary to call
     // PreventDefaults() to consume event
     return NS_OK;
   }
   WidgetCompositionEvent* compositionEvent =
-    aEvent->GetInternalNSEvent()->AsCompositionEvent();
+    aEvent->WidgetEventPtr()->AsCompositionEvent();
   if (NS_WARN_IF(!compositionEvent)) {
       return NS_ERROR_INVALID_ARG;
   }
 
   if (compositionEvent->mMessage == eCompositionChange) {
     RefPtr<TextComposition> composition = GetTextComposition();
     if (NS_WARN_IF(!composition)) {
       return NS_ERROR_FAILURE;
@@ -2020,17 +2020,17 @@ nsPluginInstanceOwner::HandleEvent(nsIDO
   if (eventType.EqualsLiteral("compositionstart") ||
       eventType.EqualsLiteral("compositionend") ||
       eventType.EqualsLiteral("text")) {
     return DispatchCompositionToPlugin(aEvent);
   }
 
   nsCOMPtr<nsIDOMDragEvent> dragEvent(do_QueryInterface(aEvent));
   if (dragEvent && mInstance) {
-    WidgetEvent* ievent = aEvent->GetInternalNSEvent();
+    WidgetEvent* ievent = aEvent->WidgetEventPtr();
     if (ievent && ievent->mFlags.mIsTrusted &&
         ievent->mMessage != eDragEnter && ievent->mMessage != eDragOver) {
       aEvent->PreventDefault();
     }
 
     // Let the plugin handle drag events.
     aEvent->StopPropagation();
   }
--- a/dom/plugins/test/unit/test_bug455213.js
+++ b/dom/plugins/test/unit/test_bug455213.js
@@ -17,17 +17,17 @@ function write_registry(version, info) {
   header += "Version" + DELIM + version + DELIM + "$\n\n";
   header += "[PLUGINS]\n";
 
   var registry = gProfD.clone();
   registry.append("pluginreg.dat");
   var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
                            .createInstance(Components.interfaces.nsIFileOutputStream);
   // write, create, truncate
-  foStream.init(registry, 0x02 | 0x08 | 0x20, 0666, 0);
+  foStream.init(registry, 0x02 | 0x08 | 0x20, 0o666, 0);
 
   var charset = "UTF-8"; // Can be any character encoding name that Mozilla supports
   var os = Cc["@mozilla.org/intl/converter-output-stream;1"].
            createInstance(Ci.nsIConverterOutputStream);
   os.init(foStream, charset, 0, 0x0000);
 
   os.writeString(header);
   os.writeString(info);
--- a/dom/plugins/test/unit/test_bug813245.js
+++ b/dom/plugins/test/unit/test_bug813245.js
@@ -21,17 +21,17 @@ function write_registry(version, info) {
   header += "\n";
   header += "[PLUGINS]\n";
 
   var registry = gProfD.clone();
   registry.append("pluginreg.dat");
   var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
                            .createInstance(Components.interfaces.nsIFileOutputStream);
   // write, create, truncate
-  foStream.init(registry, 0x02 | 0x08 | 0x20, 0666, 0);
+  foStream.init(registry, 0x02 | 0x08 | 0x20, 0o666, 0);
 
   var charset = "UTF-8"; // Can be any character encoding name that Mozilla supports
   var os = Cc["@mozilla.org/intl/converter-output-stream;1"].
            createInstance(Ci.nsIConverterOutputStream);
   os.init(foStream, charset, 0, 0x0000);
 
   os.writeString(header);
   os.writeString(info);
--- a/dom/plugins/test/unit/test_persist_in_prefs.js
+++ b/dom/plugins/test/unit/test_persist_in_prefs.js
@@ -21,17 +21,17 @@ function write_registry(version, info) {
   header += "\n";
   header += "[PLUGINS]\n";
 
   let registry = gProfD.clone();
   registry.append("pluginreg.dat");
   let foStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
                            .createInstance(Components.interfaces.nsIFileOutputStream);
   // write, create, truncate
-  foStream.init(registry, 0x02 | 0x08 | 0x20, 0666, 0);
+  foStream.init(registry, 0x02 | 0x08 | 0x20, 0o666, 0);
 
   let charset = "UTF-8"; // Can be any character encoding name that Mozilla supports
   let os = Cc["@mozilla.org/intl/converter-output-stream;1"].
            createInstance(Ci.nsIConverterOutputStream);
   os.init(foStream, charset, 0, 0x0000);
 
   os.writeString(header);
   os.writeString(info);
--- a/dom/workers/ServiceWorkerPrivate.cpp
+++ b/dom/workers/ServiceWorkerPrivate.cpp
@@ -259,17 +259,17 @@ public:
   DispatchExtendableEventOnWorkerScope(JSContext* aCx,
                                        WorkerGlobalScope* aWorkerScope,
                                        ExtendableEvent* aEvent,
                                        Promise** aWaitUntilPromise)
   {
     MOZ_ASSERT(aWorkerScope);
     MOZ_ASSERT(aEvent);
     nsCOMPtr<nsIGlobalObject> sgo = aWorkerScope;
-    WidgetEvent* internalEvent = aEvent->GetInternalNSEvent();
+    WidgetEvent* internalEvent = aEvent->WidgetEventPtr();
 
     ErrorResult result;
     result = aWorkerScope->DispatchDOMEvent(nullptr, aEvent, nullptr, nullptr);
     if (NS_WARN_IF(result.Failed()) || internalEvent->mFlags.mExceptionHasBeenRisen) {
       result.SuppressException();
       return;
     }
 
@@ -1218,17 +1218,17 @@ private:
     event->SetTrusted(true);
 
     RefPtr<EventTarget> target = do_QueryObject(aWorkerPrivate->GlobalScope());
     nsresult rv2 = target->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
     if (NS_WARN_IF(NS_FAILED(rv2)) || !event->WaitToRespond()) {
       nsCOMPtr<nsIRunnable> runnable;
       if (event->DefaultPrevented(aCx)) {
         event->ReportCanceled();
-      } else if (event->GetInternalNSEvent()->mFlags.mExceptionHasBeenRisen) {
+      } else if (event->WidgetEventPtr()->mFlags.mExceptionHasBeenRisen) {
         // Exception logged via the WorkerPrivate ErrorReporter
       } else {
         runnable = new ResumeRequest(mInterceptedChannel);
       }
 
       if (!runnable) {
         nsCOMPtr<nsIRunnable> updateRunnable =
           new RegistrationUpdateRunnable(mRegistration, false /* time check */);
--- a/dom/workers/ServiceWorkerRegistrar.cpp
+++ b/dom/workers/ServiceWorkerRegistrar.cpp
@@ -136,51 +136,59 @@ ServiceWorkerRegistrar::GetRegistrations
   if (firstTime) {
     firstTime = false;
     Telemetry::AccumulateTimeDelta(
       Telemetry::SERVICE_WORKER_REGISTRATION_LOADING,
       startTime);
   }
 }
 
+namespace {
+
+bool Equivalent(const ServiceWorkerRegistrationData& aLeft,
+                const ServiceWorkerRegistrationData& aRight)
+{
+  MOZ_ASSERT(aLeft.principal().type() ==
+             mozilla::ipc::PrincipalInfo::TContentPrincipalInfo);
+  MOZ_ASSERT(aRight.principal().type() ==
+             mozilla::ipc::PrincipalInfo::TContentPrincipalInfo);
+
+  const auto& leftPrincipal = aLeft.principal().get_ContentPrincipalInfo();
+  const auto& rightPrincipal = aRight.principal().get_ContentPrincipalInfo();
+
+  // Only compare the attributes, not the spec part of the principal.
+  // The scope comparison above already covers the origin and codebase
+  // principals include the full path in their spec which is not what
+  // we want here.
+  return aLeft.scope() == aRight.scope() &&
+         leftPrincipal.attrs() == rightPrincipal.attrs();
+}
+
+} // anonymous namespace
+
 void
 ServiceWorkerRegistrar::RegisterServiceWorker(
                                      const ServiceWorkerRegistrationData& aData)
 {
   AssertIsOnBackgroundThread();
 
   if (mShuttingDown) {
     NS_WARNING("Failed to register a serviceWorker during shutting down.");
     return;
   }
 
   {
     MonitorAutoLock lock(mMonitor);
     MOZ_ASSERT(mDataLoaded);
 
-    const mozilla::ipc::PrincipalInfo& newPrincipalInfo = aData.principal();
-    MOZ_ASSERT(newPrincipalInfo.type() ==
-               mozilla::ipc::PrincipalInfo::TContentPrincipalInfo);
-
-    const mozilla::ipc::ContentPrincipalInfo& newContentPrincipalInfo =
-      newPrincipalInfo.get_ContentPrincipalInfo();
-
     bool found = false;
     for (uint32_t i = 0, len = mData.Length(); i < len; ++i) {
-      if (mData[i].scope() == aData.scope()) {
-        const mozilla::ipc::PrincipalInfo& existingPrincipalInfo =
-          mData[i].principal();
-        const mozilla::ipc::ContentPrincipalInfo& existingContentPrincipalInfo =
-          existingPrincipalInfo.get_ContentPrincipalInfo();
-
-        if (newContentPrincipalInfo == existingContentPrincipalInfo) {
-          mData[i] = aData;
-          found = true;
-          break;
-        }
+      if (Equivalent(aData, mData[i])) {
+        found = true;
+        break;
       }
     }
 
     if (!found) {
       mData.AppendElement(aData);
     }
   }
 
@@ -200,19 +208,22 @@ ServiceWorkerRegistrar::UnregisterServic
   }
 
   bool deleted = false;
 
   {
     MonitorAutoLock lock(mMonitor);
     MOZ_ASSERT(mDataLoaded);
 
+    ServiceWorkerRegistrationData tmp;
+    tmp.principal() = aPrincipalInfo;
+    tmp.scope() = aScope;
+
     for (uint32_t i = 0; i < mData.Length(); ++i) {
-      if (mData[i].principal() == aPrincipalInfo &&
-          mData[i].scope() == aScope) {
+      if (Equivalent(tmp, mData[i])) {
         mData.RemoveElementAt(i);
         deleted = true;
         break;
       }
     }
   }
 
   if (deleted) {
@@ -310,19 +321,21 @@ ServiceWorkerRegistrar::ReadData()
   }
 
   if (!IsSupportedVersion(version)) {
     nsContentUtils::LogMessageToConsole(nsPrintfCString(
       "Unsupported service worker registrar version: %s", version.get()).get());
     return NS_ERROR_FAILURE;
   }
 
+  nsTArray<ServiceWorkerRegistrationData> tmpData;
+
   bool overwrite = false;
   while (hasMoreLines) {
-    ServiceWorkerRegistrationData* entry = mData.AppendElement();
+    ServiceWorkerRegistrationData* entry = tmpData.AppendElement();
 
 #define GET_LINE(x)                                   \
     rv = lineInputStream->ReadLine(x, &hasMoreLines); \
     if (NS_WARN_IF(NS_FAILED(rv))) {                  \
       return rv;                                      \
     }                                                 \
     if (NS_WARN_IF(!hasMoreLines)) {                  \
       return NS_ERROR_FAILURE;                        \
@@ -390,16 +403,38 @@ ServiceWorkerRegistrar::ReadData()
 
     if (!line.EqualsLiteral(SERVICEWORKERREGISTRAR_TERMINATOR)) {
       return NS_ERROR_FAILURE;
     }
   }
 
   stream->Close();
 
+  // Dedupe data in file.  Old profiles had many duplicates.  In theory
+  // we can remove this in the future. (Bug 1248449)
+  for (uint32_t i = 0; i < tmpData.Length(); ++i) {
+    bool match = false;
+    for (uint32_t j = 0; j < mData.Length(); ++j) {
+      // Use same comparison as RegisterServiceWorker. Scope contains
+      // basic origin information.  Combine with any principal attributes.
+      if (Equivalent(tmpData[i], mData[j])) {
+        // Last match wins, just like legacy loading used to do in
+        // the ServiceWorkerManager.
+        mData[j] = tmpData[i];
+        // Dupe found, so overwrite file with reduced list.
+        overwrite = true;
+        match = true;
+        break;
+      }
+    }
+    if (!match) {
+      mData.AppendElement(tmpData[i]);
+    }
+  }
+
   // Overwrite previous version.
   // Cannot call SaveData directly because gtest uses main-thread.
   if (overwrite && NS_FAILED(WriteData())) {
     NS_WARNING("Failed to write data for the ServiceWorker Registations.");
     DeleteData();
   }
 
   return NS_OK;
--- a/dom/workers/test/fileapi_chromeScript.js
+++ b/dom/workers/test/fileapi_chromeScript.js
@@ -6,17 +6,17 @@ var fileNum = 1;
 function createFileWithData(fileData) {
   var willDelete = fileData === null;
   var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
   var testFile = dirSvc.get("ProfD", Ci.nsIFile);
   testFile.append("fileAPItestfile" + fileNum);
   fileNum++;
   var outStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
   outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
-                 0666, 0);
+                 0o666, 0);
   if (willDelete) {
     fileData = "some irrelevant test data\n";
   }
   outStream.write(fileData, fileData.length);
   outStream.close();
   var domFile = new File(testFile);
   if (willDelete) {
     testFile.remove(/* recursive: */ false);
--- a/dom/workers/test/gtest/TestReadWrite.cpp
+++ b/dom/workers/test/gtest/TestReadWrite.cpp
@@ -152,17 +152,17 @@ TEST(ServiceWorkerRegistrar, TestReadDat
   ASSERT_TRUE(CreateFile(buffer)) << "CreateFile should not fail";
 
   RefPtr<ServiceWorkerRegistrarTest> swr = new ServiceWorkerRegistrarTest;
 
   nsresult rv = swr->TestReadData();
   ASSERT_EQ(NS_OK, rv) << "ReadData() should not fail";
 
   const nsTArray<ServiceWorkerRegistrationData>& data = swr->TestGetData();
-  ASSERT_EQ((uint32_t)2, data.Length()) << "4 entries should be found";
+  ASSERT_EQ((uint32_t)2, data.Length()) << "2 entries should be found";
 
   const mozilla::ipc::PrincipalInfo& info0 = data[0].principal();
   ASSERT_EQ(info0.type(), mozilla::ipc::PrincipalInfo::TContentPrincipalInfo) << "First principal must be content";
   const mozilla::ipc::ContentPrincipalInfo& cInfo0 = data[0].principal();
 
   nsAutoCString suffix0;
   cInfo0.attrs().CreateSuffix(suffix0);
 
@@ -307,14 +307,77 @@ TEST(ServiceWorkerRegistrar, TestVersion
 
   ASSERT_STREQ("", suffix1.get());
   ASSERT_STREQ("spec 1", cInfo1.spec().get());
   ASSERT_STREQ("scope 1", data[1].scope().get());
   ASSERT_STREQ("currentWorkerURL 1", data[1].currentWorkerURL().get());
   ASSERT_STREQ("activeCache 1", NS_ConvertUTF16toUTF8(data[1].cacheName()).get());
 }
 
+TEST(ServiceWorkerRegistrar, TestDedupe)
+{
+  nsAutoCString buffer(SERVICEWORKERREGISTRAR_VERSION "\n");
+
+  // unique entries
+  buffer.Append("^appId=123&inBrowser=1\n");
+  buffer.Append("spec 0\nscope 0\ncurrentWorkerURL 0\ncacheName 0\n");
+  buffer.Append(SERVICEWORKERREGISTRAR_TERMINATOR "\n");
+
+  buffer.Append("\n");
+  buffer.Append("spec 1\nscope 1\ncurrentWorkerURL 1\ncacheName 1\n");
+  buffer.Append(SERVICEWORKERREGISTRAR_TERMINATOR "\n");
+
+  // dupe entries
+  buffer.Append("^appId=123&inBrowser=1\n");
+  buffer.Append("spec 1\nscope 0\ncurrentWorkerURL 0\ncacheName 0\n");
+  buffer.Append(SERVICEWORKERREGISTRAR_TERMINATOR "\n");
+
+  buffer.Append("^appId=123&inBrowser=1\n");
+  buffer.Append("spec 2\nscope 0\ncurrentWorkerURL 0\ncacheName 0\n");
+  buffer.Append(SERVICEWORKERREGISTRAR_TERMINATOR "\n");
+
+  buffer.Append("\n");
+  buffer.Append("spec 3\nscope 1\ncurrentWorkerURL 1\ncacheName 1\n");
+  buffer.Append(SERVICEWORKERREGISTRAR_TERMINATOR "\n");
+
+  ASSERT_TRUE(CreateFile(buffer)) << "CreateFile should not fail";
+
+  RefPtr<ServiceWorkerRegistrarTest> swr = new ServiceWorkerRegistrarTest;
+
+  nsresult rv = swr->TestReadData();
+  ASSERT_EQ(NS_OK, rv) << "ReadData() should not fail";
+
+  const nsTArray<ServiceWorkerRegistrationData>& data = swr->TestGetData();
+  ASSERT_EQ((uint32_t)2, data.Length()) << "2 entries should be found";
+
+  const mozilla::ipc::PrincipalInfo& info0 = data[0].principal();
+  ASSERT_EQ(info0.type(), mozilla::ipc::PrincipalInfo::TContentPrincipalInfo) << "First principal must be content";
+  const mozilla::ipc::ContentPrincipalInfo& cInfo0 = data[0].principal();
+
+  nsAutoCString suffix0;
+  cInfo0.attrs().CreateSuffix(suffix0);
+
+  ASSERT_STREQ("^appId=123&inBrowser=1", suffix0.get());
+  ASSERT_STREQ("spec 2", cInfo0.spec().get());
+  ASSERT_STREQ("scope 0", data[0].scope().get());
+  ASSERT_STREQ("currentWorkerURL 0", data[0].currentWorkerURL().get());
+  ASSERT_STREQ("cacheName 0", NS_ConvertUTF16toUTF8(data[0].cacheName()).get());
+
+  const mozilla::ipc::PrincipalInfo& info1 = data[1].principal();
+  ASSERT_EQ(info1.type(), mozilla::ipc::PrincipalInfo::TContentPrincipalInfo) << "First principal must be content";
+  const mozilla::ipc::ContentPrincipalInfo& cInfo1 = data[1].principal();
+
+  nsAutoCString suffix1;
+  cInfo1.attrs().CreateSuffix(suffix1);
+
+  ASSERT_STREQ("", suffix1.get());
+  ASSERT_STREQ("spec 3", cInfo1.spec().get());
+  ASSERT_STREQ("scope 1", data[1].scope().get());
+  ASSERT_STREQ("currentWorkerURL 1", data[1].currentWorkerURL().get());
+  ASSERT_STREQ("cacheName 1", NS_ConvertUTF16toUTF8(data[1].cacheName()).get());
+}
+
 int main(int argc, char** argv) {
   ::testing::InitGoogleTest(&argc, argv);
 
   int rv = RUN_ALL_TESTS();
   return rv;
 }
--- a/dom/xbl/nsXBLEventHandler.cpp
+++ b/dom/xbl/nsXBLEventHandler.cpp
@@ -85,17 +85,17 @@ nsXBLKeyEventHandler::~nsXBLKeyEventHand
 NS_IMPL_ISUPPORTS(nsXBLKeyEventHandler, nsIDOMEventListener)
 
 bool
 nsXBLKeyEventHandler::ExecuteMatchedHandlers(
                         nsIDOMKeyEvent* aKeyEvent,
                         uint32_t aCharCode,
                         const IgnoreModifierState& aIgnoreModifierState)
 {
-  WidgetEvent* event = aKeyEvent->AsEvent()->GetInternalNSEvent();
+  WidgetEvent* event = aKeyEvent->AsEvent()->WidgetEventPtr();
   nsCOMPtr<EventTarget> target = aKeyEvent->AsEvent()->InternalDOMEvent()->GetCurrentTarget();
 
   bool executed = false;
   for (uint32_t i = 0; i < mProtoHandlers.Length(); ++i) {
     nsXBLPrototypeHandler* handler = mProtoHandlers[i];
     bool hasAllowUntrustedAttr = handler->HasAllowUntrustedAttr();
     if ((event->mFlags.mIsTrusted ||
         (hasAllowUntrustedAttr && handler->AllowUntrustedEvents()) ||
--- a/dom/xbl/nsXBLPrototypeHandler.cpp
+++ b/dom/xbl/nsXBLPrototypeHandler.cpp
@@ -900,17 +900,17 @@ nsXBLPrototypeHandler::ReportKeyConflict
                                   nullptr, EmptyString(), mLineNumber);
 }
 
 bool
 nsXBLPrototypeHandler::ModifiersMatchMask(
                          nsIDOMUIEvent* aEvent,
                          const IgnoreModifierState& aIgnoreModifierState)
 {
-  WidgetInputEvent* inputEvent = aEvent->AsEvent()->GetInternalNSEvent()->AsInputEvent();
+  WidgetInputEvent* inputEvent = aEvent->AsEvent()->WidgetEventPtr()->AsInputEvent();
   NS_ENSURE_TRUE(inputEvent, false);
 
   if (mKeyMask & cMetaMask) {
     if (inputEvent->IsMeta() != ((mKeyMask & cMeta) != 0)) {
       return false;
     }
   }
 
--- a/dom/xbl/nsXBLWindowKeyHandler.cpp
+++ b/dom/xbl/nsXBLWindowKeyHandler.cpp
@@ -317,24 +317,24 @@ nsXBLWindowKeyHandler::HandleEvent(nsIDO
 
   return WalkHandlers(keyEvent, eventTypeAtom);
 }
 
 void
 nsXBLWindowKeyHandler::HandleEventOnCapture(nsIDOMKeyEvent* aEvent)
 {
   WidgetKeyboardEvent* widgetEvent =
-    aEvent->AsEvent()->GetInternalNSEvent()->AsKeyboardEvent();
+    aEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent();
 
   if (widgetEvent->mFlags.mNoCrossProcessBoundaryForwarding) {
     return;
   }
 
   nsCOMPtr<mozilla::dom::Element> originalTarget =
-    do_QueryInterface(aEvent->AsEvent()->GetInternalNSEvent()->originalTarget);
+    do_QueryInterface(aEvent->AsEvent()->WidgetEventPtr()->originalTarget);
   if (!EventStateManager::IsRemoteTarget(originalTarget)) {
     return;
   }
 
   bool aReservedForChrome = false;
   if (!HasHandlerForEvent(aEvent, &aReservedForChrome)) {
     return;
   }
@@ -560,17 +560,17 @@ nsXBLWindowKeyHandler::WalkHandlersAndEx
 
 #ifdef XP_WIN
   // Windows native applications ignore Windows-Logo key state when checking
   // shortcut keys even if the key is pressed.  Therefore, if there is no
   // shortcut key which exactly matches current modifier state, we should
   // retry to look for a shortcut key without the Windows-Logo key press.
   if (!aIgnoreModifierState.mOS) {
     WidgetKeyboardEvent* keyEvent =
-      aKeyEvent->AsEvent()->GetInternalNSEvent()->AsKeyboardEvent();
+      aKeyEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent();
     if (keyEvent && keyEvent->IsOS()) {
       IgnoreModifierState ignoreModifierState(aIgnoreModifierState);
       ignoreModifierState.mOS = true;
       return WalkHandlersAndExecute(aKeyEvent, aEventType, aHandler, aCharCode,
                                     ignoreModifierState, aExecute);
     }
   }
 #endif
--- a/editor/libeditor/nsEditor.cpp
+++ b/editor/libeditor/nsEditor.cpp
@@ -4611,17 +4611,17 @@ nsEditor::HandleKeyPressEvent(nsIDOMKeyE
   // NOTE: When you change this method, you should also change:
   //   * editor/libeditor/tests/test_texteditor_keyevent_handling.html
   //   * editor/libeditor/tests/test_htmleditor_keyevent_handling.html
   //
   // And also when you add new key handling, you need to change the subclass's
   // HandleKeyPressEvent()'s switch statement.
 
   WidgetKeyboardEvent* nativeKeyEvent =
-    aKeyEvent->AsEvent()->GetInternalNSEvent()->AsKeyboardEvent();
+    aKeyEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent();
   NS_ENSURE_TRUE(nativeKeyEvent, NS_ERROR_UNEXPECTED);
   NS_ASSERTION(nativeKeyEvent->mMessage == eKeyPress,
                "HandleKeyPressEvent gets non-keypress event");
 
   // if we are readonly or disabled, then do nothing.
   if (IsReadonly() || IsDisabled()) {
     // consume backspace for disabled and readonly textfields, to prevent
     // back in history, which could be confusing to users
@@ -5048,17 +5048,17 @@ nsEditor::IsActiveInDOMWindow()
 }
 
 bool
 nsEditor::IsAcceptableInputEvent(nsIDOMEvent* aEvent)
 {
   // If the event is trusted, the event should always cause input.
   NS_ENSURE_TRUE(aEvent, false);
 
-  WidgetEvent* widgetEvent = aEvent->GetInternalNSEvent();
+  WidgetEvent* widgetEvent = aEvent->WidgetEventPtr();
   if (NS_WARN_IF(!widgetEvent)) {
     return false;
   }
 
   // If this is dispatched by using cordinates but this editor doesn't have
   // focus, we shouldn't handle it.
   if (widgetEvent->IsUsingCoordinates()) {
     nsCOMPtr<nsIContent> focusedContent = GetFocusedContent();
@@ -5081,17 +5081,17 @@ nsEditor::IsAcceptableInputEvent(nsIDOME
       return false;
     case eCompositionStart:
     case eCompositionEnd:
     case eCompositionUpdate:
     case eCompositionChange:
     case eCompositionCommitAsIs:
       // Don't allow composition events whose internal event are not
       // WidgetCompositionEvent.
-      widgetGUIEvent = aEvent->GetInternalNSEvent()->AsCompositionEvent();
+      widgetGUIEvent = aEvent->WidgetEventPtr()->AsCompositionEvent();
       needsWidget = true;
       break;
     default:
       break;
   }
   if (needsWidget &&
       (!widgetGUIEvent || !widgetGUIEvent->widget)) {
     return false;
--- a/editor/libeditor/nsEditorEventListener.cpp
+++ b/editor/libeditor/nsEditorEventListener.cpp
@@ -352,17 +352,17 @@ NS_IMPL_ISUPPORTS(nsEditorEventListener,
 
 NS_IMETHODIMP
 nsEditorEventListener::HandleEvent(nsIDOMEvent* aEvent)
 {
   NS_ENSURE_TRUE(mEditor, NS_ERROR_FAILURE);
 
   nsCOMPtr<nsIEditor> kungFuDeathGrip = mEditor;
 
-  WidgetEvent* internalEvent = aEvent->GetInternalNSEvent();
+  WidgetEvent* internalEvent = aEvent->WidgetEventPtr();
 
   // 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
@@ -636,17 +636,17 @@ nsEditorEventListener::KeyPress(nsIDOMKe
   }
 
   if (!ShouldHandleNativeKeyBindings(aKeyEvent)) {
     return NS_OK;
   }
 
   // Now, ask the native key bindings to handle the event.
   WidgetKeyboardEvent* keyEvent =
-    aKeyEvent->AsEvent()->GetInternalNSEvent()->AsKeyboardEvent();
+    aKeyEvent->AsEvent()->WidgetEventPtr()->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;
@@ -1042,17 +1042,17 @@ nsEditorEventListener::CanDrop(nsIDOMDra
 
 nsresult
 nsEditorEventListener::HandleStartComposition(nsIDOMEvent* aCompositionEvent)
 {
   if (!mEditor->IsAcceptableInputEvent(aCompositionEvent)) {
     return NS_OK;
   }
   WidgetCompositionEvent* compositionStart =
-    aCompositionEvent->GetInternalNSEvent()->AsCompositionEvent();
+    aCompositionEvent->WidgetEventPtr()->AsCompositionEvent();
   return mEditor->BeginIMEComposition(compositionStart);
 }
 
 void
 nsEditorEventListener::HandleEndComposition(nsIDOMEvent* aCompositionEvent)
 {
   if (!mEditor->IsAcceptableInputEvent(aCompositionEvent)) {
     return;
--- a/editor/libeditor/nsHTMLEditor.cpp
+++ b/editor/libeditor/nsHTMLEditor.cpp
@@ -612,17 +612,17 @@ nsHTMLEditor::HandleKeyPressEvent(nsIDOM
 
   if (IsReadonly() || IsDisabled()) {
     // When we're not editable, the events are handled on nsEditor, so, we can
     // bypass nsPlaintextEditor.
     return nsEditor::HandleKeyPressEvent(aKeyEvent);
   }
 
   WidgetKeyboardEvent* nativeKeyEvent =
-    aKeyEvent->AsEvent()->GetInternalNSEvent()->AsKeyboardEvent();
+    aKeyEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent();
   NS_ENSURE_TRUE(nativeKeyEvent, NS_ERROR_UNEXPECTED);
   NS_ASSERTION(nativeKeyEvent->mMessage == eKeyPress,
                "HandleKeyPressEvent gets non-keypress event");
 
   switch (nativeKeyEvent->keyCode) {
     case nsIDOMKeyEvent::DOM_VK_META:
     case nsIDOMKeyEvent::DOM_VK_WIN:
     case nsIDOMKeyEvent::DOM_VK_SHIFT:
@@ -5177,17 +5177,17 @@ nsHTMLEditor::IsAcceptableInputEvent(nsI
 {
   if (!nsEditor::IsAcceptableInputEvent(aEvent)) {
     return false;
   }
 
   // While there is composition, all composition events in its top level window
   // are always fired on the composing editor.  Therefore, if this editor has
   // composition, the composition events should be handled in this editor.
-  if (mComposition && aEvent->GetInternalNSEvent()->AsCompositionEvent()) {
+  if (mComposition && aEvent->WidgetEventPtr()->AsCompositionEvent()) {
     return true;
   }
 
   NS_ENSURE_TRUE(mDocWeak, false);
 
   nsCOMPtr<nsIDOMEventTarget> target;
   aEvent->GetTarget(getter_AddRefs(target));
   NS_ENSURE_TRUE(target, false);
--- a/editor/libeditor/nsPlaintextDataTransfer.cpp
+++ b/editor/libeditor/nsPlaintextDataTransfer.cpp
@@ -179,17 +179,17 @@ nsresult nsPlaintextEditor::InsertFromDr
 
   nsCOMPtr<nsIDOMDocument> srcdomdoc;
   if (sourceNode) {
     sourceNode->GetOwnerDocument(getter_AddRefs(srcdomdoc));
     NS_ENSURE_TRUE(sourceNode, NS_ERROR_FAILURE);
   }
 
   if (nsContentUtils::CheckForSubFrameDrop(dragSession,
-        aDropEvent->GetInternalNSEvent()->AsDragEvent())) {
+        aDropEvent->WidgetEventPtr()->AsDragEvent())) {
     // Don't allow drags from subframe documents with different origins than
     // the drop destination.
     if (srcdomdoc && !IsSafeToInsertData(srcdomdoc))
       return NS_OK;
   }
 
   // Current doc is destination
   nsCOMPtr<nsIDOMDocument> destdomdoc = GetDOMDocument();
--- a/editor/libeditor/nsPlaintextEditor.cpp
+++ b/editor/libeditor/nsPlaintextEditor.cpp
@@ -357,17 +357,17 @@ nsPlaintextEditor::HandleKeyPressEvent(n
   // HandleKeyPressEvent()'s switch statement.
 
   if (IsReadonly() || IsDisabled()) {
     // When we're not editable, the events handled on nsEditor.
     return nsEditor::HandleKeyPressEvent(aKeyEvent);
   }
 
   WidgetKeyboardEvent* nativeKeyEvent =
-    aKeyEvent->AsEvent()->GetInternalNSEvent()->AsKeyboardEvent();
+    aKeyEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent();
   NS_ENSURE_TRUE(nativeKeyEvent, NS_ERROR_UNEXPECTED);
   NS_ASSERTION(nativeKeyEvent->mMessage == eKeyPress,
                "HandleKeyPressEvent gets non-keypress event");
 
   switch (nativeKeyEvent->keyCode) {
     case nsIDOMKeyEvent::DOM_VK_META:
     case nsIDOMKeyEvent::DOM_VK_WIN:
     case nsIDOMKeyEvent::DOM_VK_SHIFT:
@@ -843,17 +843,17 @@ nsPlaintextEditor::BeginIMEComposition(W
 }
 
 nsresult
 nsPlaintextEditor::UpdateIMEComposition(nsIDOMEvent* aDOMTextEvent)
 {
   MOZ_ASSERT(aDOMTextEvent, "aDOMTextEvent must not be nullptr");
 
   WidgetCompositionEvent* compositionChangeEvent =
-    aDOMTextEvent->GetInternalNSEvent()->AsCompositionEvent();
+    aDOMTextEvent->WidgetEventPtr()->AsCompositionEvent();
   NS_ENSURE_TRUE(compositionChangeEvent, NS_ERROR_INVALID_ARG);
   MOZ_ASSERT(compositionChangeEvent->mMessage == eCompositionChange,
              "The internal event should be eCompositionChange");
 
   EnsureComposition(compositionChangeEvent);
 
   nsCOMPtr<nsIPresShell> ps = GetPresShell();
   NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
--- a/embedding/components/windowwatcher/nsAutoWindowStateHelper.cpp
+++ b/embedding/components/windowwatcher/nsAutoWindowStateHelper.cpp
@@ -58,15 +58,15 @@ nsAutoWindowStateHelper::DispatchEventTo
 
   ErrorResult rv;
   RefPtr<Event> event = doc->CreateEvent(NS_LITERAL_STRING("Events"), rv);
   if (rv.Failed()) {
     return false;
   }
   event->InitEvent(NS_ConvertASCIItoUTF16(aEventName), true, true);
   event->SetTrusted(true);
-  event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
+  event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
 
   nsCOMPtr<EventTarget> target = do_QueryInterface(mWindow);
   bool defaultActionEnabled;
   target->DispatchEvent(event, &defaultActionEnabled);
   return defaultActionEnabled;
 }
--- a/extensions/cookie/test/unit/test_permmanager_defaults.js
+++ b/extensions/cookie/test/unit/test_permmanager_defaults.js
@@ -25,17 +25,17 @@ add_task(function* do_test() {
 
   // create a file in the temp directory with the defaults.
   let file = do_get_tempdir();
   file.append("test_default_permissions");
 
   // write our test data to it.
   let ostream = Cc["@mozilla.org/network/file-output-stream;1"].
                 createInstance(Ci.nsIFileOutputStream);
-  ostream.init(file, -1, 0666, 0);
+  ostream.init(file, -1, 0o666, 0);
   let conv = Cc["@mozilla.org/intl/converter-output-stream;1"].
              createInstance(Ci.nsIConverterOutputStream);
   conv.init(ostream, "UTF-8", 0, 0);
 
   conv.writeString("# this is a comment\n");
   conv.writeString("\n"); // a blank line!
   conv.writeString("host\t" + TEST_PERMISSION + "\t1\t" + TEST_ORIGIN.host + "\n");
   conv.writeString("host\t" + TEST_PERMISSION + "\t1\t" + TEST_ORIGIN_2.host + "\n");
--- a/extensions/cookie/test/unit/test_permmanager_removeall.js
+++ b/extensions/cookie/test/unit/test_permmanager_removeall.js
@@ -12,25 +12,25 @@ function run_test() {
   // get the db file
   var file = dir.clone();
   file.append("permissions.sqlite");
   do_check_true(file.exists());
 
   // corrupt the file
   var ostream = Cc["@mozilla.org/network/file-output-stream;1"].
                 createInstance(Ci.nsIFileOutputStream);
-  ostream.init(file, 0x02, 0666, 0);
+  ostream.init(file, 0x02, 0o666, 0);
   var conv = Cc["@mozilla.org/intl/converter-output-stream;1"].
              createInstance(Ci.nsIConverterOutputStream);
   conv.init(ostream, "UTF-8", 0, 0);
   for (var i = 0; i < file.fileSize; ++i)
     conv.writeString("a");
   conv.close();
 
   // prepare an empty hostperm.1 file so that it can be used for importing
   var hostperm = dir.clone();
   hostperm.append("hostperm.1");
-  ostream.init(hostperm, 0x02 | 0x08, 0666, 0);
+  ostream.init(hostperm, 0x02 | 0x08, 0o666, 0);
   ostream.close();
 
   // remove all should not throw
   pm.removeAll();
 }
--- a/extensions/spellcheck/hunspell/tests/unit/test_hunspell.js
+++ b/extensions/spellcheck/hunspell/tests/unit/test_hunspell.js
@@ -125,17 +125,17 @@ const tests = [
 ];
 
 function do_get_file_by_line(file, charset) {
   dump("getting file by line for file " + file.path + "\n");
   dump("using charset " + charset +"\n");
   let fis = Cc["@mozilla.org/network/file-input-stream;1"].
               createInstance(Ci.nsIFileInputStream);
   fis.init(file, 0x1 /* READONLY */,
-           0444, Ci.nsIFileInputStream.CLOSE_ON_EOF);
+           0o444, Ci.nsIFileInputStream.CLOSE_ON_EOF);
 
   let lis = Cc["@mozilla.org/intl/converter-input-stream;1"].
               createInstance(Ci.nsIConverterInputStream);
   lis.init(fis, charset, 1024, 0);
   lis.QueryInterface(Ci.nsIUnicharLineInputStream);
 
   var val = {};
   while (lis.readLine(val)) {
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -62,16 +62,17 @@ struct DeviceAttachmentsD3D11
 {
   DeviceAttachmentsD3D11(ID3D11Device* device)
    : mSyncHandle(0),
      mDevice(device),
      mInitOkay(true)
   {}
 
   bool CreateShaders();
+  bool InitBlendShaders();
   bool InitSyncObject();
 
   typedef EnumeratedArray<MaskType, MaskType::NumMaskTypes, RefPtr<ID3D11VertexShader>>
           VertexShaderArray;
   typedef EnumeratedArray<MaskType, MaskType::NumMaskTypes, RefPtr<ID3D11PixelShader>>
           PixelShaderArray;
 
   RefPtr<ID3D11InputLayout> mInputLayout;
@@ -966,17 +967,19 @@ CompositorD3D11::DrawQuad(const gfx::Rec
 
     // If the blend operation needs to read from the backdrop, copy the
     // current render target into a new texture and bind it now.
     if (BlendOpIsMixBlendMode(blendMode)) {
       gfx::Matrix4x4 backdropTransform;
       gfx::IntRect rect = ComputeBackdropCopyRect(aRect, aClipRect, aTransform, &backdropTransform);
 
       RefPtr<ID3D11ShaderResourceView> srv;
-      if (CopyBackdrop(rect, &mixBlendBackdrop, &srv)) {
+      if (CopyBackdrop(rect, &mixBlendBackdrop, &srv) &&
+          mAttachments->InitBlendShaders())
+      {
         vertexShader = mAttachments->mVSQuadBlendShader[maskType];
         pixelShader = mAttachments->mBlendShader[MaskType::MaskNone];
 
         ID3D11ShaderResourceView* srView = srv.get();
         mContext->PSSetShaderResources(TexSlot::Backdrop, 1, &srView);
 
         memcpy(&mVSConstants.backdropTransform, &backdropTransform._11, 64);
 
@@ -1487,35 +1490,45 @@ DeviceAttachmentsD3D11::InitSyncObject()
     }));
     return false;
   }
 
   return true;
 }
 
 bool
+DeviceAttachmentsD3D11::InitBlendShaders()
+{
+  if (!mVSQuadBlendShader[MaskType::MaskNone]) {
+    InitVertexShader(sLayerQuadBlendVS, mVSQuadBlendShader, MaskType::MaskNone);
+    InitVertexShader(sLayerQuadBlendMaskVS, mVSQuadBlendShader, MaskType::Mask2d);
+    InitVertexShader(sLayerQuadBlendMask3DVS, mVSQuadBlendShader, MaskType::Mask3d);
+  }
+  if (!mBlendShader[MaskType::MaskNone]) {
+    InitPixelShader(sBlendShader, mBlendShader, MaskType::MaskNone);
+  }
+  return mInitOkay;
+}
+
+bool
 DeviceAttachmentsD3D11::CreateShaders()
 {
   InitVertexShader(sLayerQuadVS, mVSQuadShader, MaskType::MaskNone);
   InitVertexShader(sLayerQuadMaskVS, mVSQuadShader, MaskType::Mask2d);
   InitVertexShader(sLayerQuadMask3DVS, mVSQuadShader, MaskType::Mask3d);
-  InitVertexShader(sLayerQuadBlendVS, mVSQuadBlendShader, MaskType::MaskNone);
-  InitVertexShader(sLayerQuadBlendMaskVS, mVSQuadBlendShader, MaskType::Mask2d);
-  InitVertexShader(sLayerQuadBlendMask3DVS, mVSQuadBlendShader, MaskType::Mask3d);
 
   InitPixelShader(sSolidColorShader, mSolidColorShader, MaskType::MaskNone);
   InitPixelShader(sSolidColorShaderMask, mSolidColorShader, MaskType::Mask2d);
   InitPixelShader(sRGBShader, mRGBShader, MaskType::MaskNone);
   InitPixelShader(sRGBShaderMask, mRGBShader, MaskType::Mask2d);
   InitPixelShader(sRGBAShader, mRGBAShader, MaskType::MaskNone);
   InitPixelShader(sRGBAShaderMask, mRGBAShader, MaskType::Mask2d);
   InitPixelShader(sRGBAShaderMask3D, mRGBAShader, MaskType::Mask3d);
   InitPixelShader(sYCbCrShader, mYCbCrShader, MaskType::MaskNone);
   InitPixelShader(sYCbCrShaderMask, mYCbCrShader, MaskType::Mask2d);
-  InitPixelShader(sBlendShader, mBlendShader, MaskType::MaskNone);
   if (gfxPrefs::ComponentAlphaEnabled()) {
     InitPixelShader(sComponentAlphaShader, mComponentAlphaShader, MaskType::MaskNone);
     InitPixelShader(sComponentAlphaShaderMask, mComponentAlphaShader, MaskType::Mask2d);
   }
 
   InitVertexShader(sOculus050VRDistortionVS, getter_AddRefs(mVRDistortionVS[VRHMDType::Oculus050]));
   InitPixelShader(sOculus050VRDistortionPS, getter_AddRefs(mVRDistortionPS[VRHMDType::Oculus050]));
 
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -2963,20 +2963,21 @@ void gfxFontGroup::ComputeRanges(nsTArra
         }
 
         if (lastRangeIndex == -1) {
             // first char ==> make a new range
             aRanges.AppendElement(gfxTextRange(0, 1, font, matchType, orient));
             lastRangeIndex++;
             prevFont = font;
         } else {
-            // if font has changed, make a new range
+            // if font or orientation has changed, make a new range...
+            // unless ch is a variation selector (bug 1248248)
             gfxTextRange& prevRange = aRanges[lastRangeIndex];
             if (prevRange.font != font || prevRange.matchType != matchType ||
-                prevRange.orientation != orient) {
+                (prevRange.orientation != orient && !IsClusterExtender(ch))) {
                 // close out the previous range
                 prevRange.end = origI;
                 aRanges.AppendElement(gfxTextRange(origI, i + 1,
                                                    font, matchType, orient));
                 lastRangeIndex++;
 
                 // update prevFont for the next match, *unless* we switched
                 // fonts on a ZWJ, in which case propagating the changed font
--- a/image/Downscaler.cpp
+++ b/image/Downscaler.cpp
@@ -197,19 +197,19 @@ GetFilterOffsetAndLength(UniquePtr<skia:
 {
   MOZ_ASSERT(aOutputImagePosition < aFilter->num_values());
   aFilter->FilterForValue(aOutputImagePosition,
                           aFilterOffsetOut,
                           aFilterLengthOut);
 }
 
 void
-Downscaler::ClearRow(uint32_t aStartingAtCol)
+Downscaler::ClearRestOfRow(uint32_t aStartingAtCol)
 {
-  MOZ_ASSERT(int64_t(mOriginalSize.width) > int64_t(aStartingAtCol));
+  MOZ_ASSERT(int64_t(aStartingAtCol) <= int64_t(mOriginalSize.width));
   uint32_t bytesToClear = (mOriginalSize.width - aStartingAtCol)
                         * sizeof(uint32_t);
   memset(mRowBuffer.get() + (aStartingAtCol * sizeof(uint32_t)),
          0, bytesToClear);
 }
 
 void
 Downscaler::CommitRow()
--- a/image/Downscaler.h
+++ b/image/Downscaler.h
@@ -87,18 +87,21 @@ public:
   bool IsFrameComplete() const { return mCurrentInLine >= mOriginalSize.height; }
 
   /// Retrieves the buffer into which the Decoder should write each row.
   uint8_t* RowBuffer()
   {
     return mRowBuffer.get() + mFrameRect.x * sizeof(uint32_t);
   }
 
-  /// Clears the current row buffer (optionally starting at @aStartingAtCol).
-  void ClearRow(uint32_t aStartingAtCol = 0);
+  /// Clears the current row buffer.
+  void ClearRow() { ClearRestOfRow(0); }
+
+  /// Clears the current row buffer starting at @aStartingAtCol.
+  void ClearRestOfRow(uint32_t aStartingAtCol);
 
   /// Signals that the decoder has finished writing a row into the row buffer.
   void CommitRow();
 
   /// Returns true if there is a non-empty invalid rect available.
   bool HasInvalidation() const;
 
   /// Takes the Downscaler's current invalid rect and resets it.
@@ -161,17 +164,18 @@ public:
 
   nsresult BeginFrame(const nsIntSize&, const Maybe<nsIntRect>&, uint8_t*, bool, bool = false)
   {
     return NS_ERROR_FAILURE;
   }
 
   bool IsFrameComplete() const { return false; }
   uint8_t* RowBuffer() { return nullptr; }
-  void ClearRow(uint32_t = 0) { }
+  void ClearRow() { }
+  void ClearRestOfRow(uint32_t) { }
   void CommitRow() { }
   bool HasInvalidation() const { return false; }
   DownscalerInvalidRect TakeInvalidRect() { return DownscalerInvalidRect(); }
   void ResetForNextProgressivePass() { }
   const nsIntSize FrameSize() const { return nsIntSize(0, 0); }
 };
 
 #endif // MOZ_ENABLE_SKIA
--- a/image/decoders/nsBMPDecoder.cpp
+++ b/image/decoders/nsBMPDecoder.cpp
@@ -989,17 +989,17 @@ nsBMPDecoder::ReadRLEDelta(const char* a
   // Delta encoding makes it possible to skip pixels making part of the image
   // transparent.
   MOZ_ASSERT(mMayHaveTransparency);
   mDoesHaveTransparency = true;
 
   if (mDownscaler) {
     // Clear the skipped pixels. (This clears to the end of the row,
     // which is perfect if there's a Y delta and harmless if not).
-    mDownscaler->ClearRow(/* aStartingAtCol = */ mCurrentPos);
+    mDownscaler->ClearRestOfRow(/* aStartingAtCol = */ mCurrentPos);
   }
 
   // Handle the XDelta.
   mCurrentPos += uint8_t(aData[0]);
   if (mCurrentPos > mH.mWidth) {
     mCurrentPos = mH.mWidth;
   }
 
new file mode 100644
--- /dev/null
+++ b/image/test/crashtests/1242093-1.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset='UTF-8'>
+<meta http-equiv='Cache-control' content='no-cache'>
+</head>
+<body>
+<img id='m1' src='data:image/bmp;base64,Qk1mDgAAAAAAAHYAAAAoAAAAQAEAAPAAAAABAAQAAgAAAPANAADoAwAA6AMAABAAAAAAAAAA/wD/AAAAAAAAAP8AAP8AAP8AAAD///8AzMzMAMzMzADMzMwAzMzMAMzMzADMzMwAzMzMAMzMzADMzMwAzMzMAAACAAEAAgABAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAAAAAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRCAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBpRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAIAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICAGgiAAJqAGpEAAAAAgIAaCIAAmoAakQAAAACAgBoIgACagBqRAAAAAICADgRMCIAAmoAakQAAAACAgA4ETAiAAJqAGpEAAAAAgIABhEBVQURA1UDEQFVCREEVQIRBFUCEQFVCBEBVQYRMCIAAmoAakQAAAACAgAGEQFVBBEBVQMRAVUCEQFVCREBVQURAVUFEQFVCBEBVQYRMCIAAmoAakQAAAACAgAGEQFVBBEBVQMRAVUCEQFVCREBVQURAVUFEQFVCBEBVQYRMCIAAmoAakQAAAACAgAGEQFVBBEBVQMRAVUCEQRVBhEBVQURA1UDEQNVBhEBVQYRMCIAAmoAakQAAAACAgAGEQFVBBEBVQMRAVUCEQFVAxEBVQURAVUFEQFVBREBVQgRAVUGETAiAAJqAGpEAAAAAgIABhEBVQQRAVUDEQFVAhEBVQMRAVUFEQFVBREBVQURAVUIEQFVBhEwIgACagBqRAAAAAICAAMRB1UCEQNVAxEEVQYRAVUFEQRVAhEEVQIRB1UDETAiAAJqAGpEAAAAAgIAOBEwIgACagBqRAAAAAICADgRMCIAAmoAakQAAAACAAEAAgABAAE='>
+<img id='m2' height='2' width='2'>
+<canvas id='c1'></canvas>
+<script>
+  var im1=document.getElementById('m1');
+  var im2=document.getElementById('m2');
+  im2.src=im1.src;
+  window.onload=function(){
+    var ctx=document.getElementById('c1').getContext('2d');
+    ctx.drawImage(im1, 0, 0); // sync docoder call
+    ctx.drawImage(im2, 0, 0); // sync downscaler call
+  }
+</script>
+</body>
+</html>
\ No newline at end of file
--- a/image/test/crashtests/crashtests.list
+++ b/image/test/crashtests/crashtests.list
@@ -12,16 +12,17 @@ load 732319-1.html
 load 844403-1.html
 load 856616.gif
 skip-if(B2G) load 944353.jpg
 load 1205923-1.html
 load 1212954-1.svg
 load 1235605.gif
 load 1241728-1.html
 load 1241729-1.html
+load 1242093-1.html
 load 1242778-1.png
 load colormap-range.gif
 HTTP load delayedframe.sjs # A 3-frame animated GIF with an inordinate delay between the second and third frame
 
 # Animated gifs with a very large canvas, but tiny actual content.
 skip-if(B2G) load delaytest.html?523528-1.gif
 skip-if(B2G) load delaytest.html?523528-2.gif
 
--- a/image/test/unit/test_imgtools.js
+++ b/image/test/unit/test_imgtools.js
@@ -14,17 +14,17 @@ var Cc = Components.classes;
  */
 function dumpToFile(aData) {
     var outputFile = do_get_tempdir();
     outputFile.append("testdump.png");
 
     var outputStream = Cc["@mozilla.org/network/file-output-stream;1"].
                        createInstance(Ci.nsIFileOutputStream);
     // WR_ONLY|CREAT|TRUNC
-    outputStream.init(outputFile, 0x02 | 0x08 | 0x20, 0644, null);
+    outputStream.init(outputFile, 0x02 | 0x08 | 0x20, 0o644, null);
 
     var bos = Cc["@mozilla.org/binaryoutputstream;1"].
               createInstance(Ci.nsIBinaryOutputStream);
     bos.setOutputStream(outputStream);
 
     bos.writeByteArray(aData, aData.length);
 
     outputStream.close();
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -788,16 +788,17 @@ class GCRuntime
 
     uint64_t majorGCCount() const { return majorGCNumber; }
     void incMajorGcNumber() { ++majorGCNumber; ++number; }
 
     int64_t defaultSliceBudget() const { return defaultTimeBudget_; }
 
     bool isIncrementalGc() const { return isIncremental; }
     bool isFullGc() const { return isFull; }
+    bool isCompactingGc() const { return isCompacting; }
 
     bool shouldCleanUpEverything() { return cleanUpEverything; }
 
     bool areGrayBitsValid() const { return grayBitsValid; }
     void setGrayBitsInvalid() { grayBitsValid = false; }
 
     bool minorGCRequested() const { return minorGCTriggerReason != JS::gcreason::NO_REASON; }
     bool majorGCRequested() const { return majorGCTriggerReason != JS::gcreason::NO_REASON; }
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -928,16 +928,17 @@ Statistics::endGC()
 
     runtime->addTelemetry(JS_TELEMETRY_GC_IS_COMPARTMENTAL, !zoneStats.isCollectingAllZones());
     runtime->addTelemetry(JS_TELEMETRY_GC_MS, t(total));
     runtime->addTelemetry(JS_TELEMETRY_GC_MAX_PAUSE_MS, t(longest));
     int64_t markTotal = SumPhase(PHASE_MARK, phaseTimes);
     int64_t markRootsTotal = SumPhase(PHASE_MARK_ROOTS, phaseTimes);
     runtime->addTelemetry(JS_TELEMETRY_GC_MARK_MS, t(markTotal));
     runtime->addTelemetry(JS_TELEMETRY_GC_SWEEP_MS, t(phaseTimes[PHASE_DAG_NONE][PHASE_SWEEP]));
+    runtime->addTelemetry(JS_TELEMETRY_GC_COMPACT_MS, t(phaseTimes[PHASE_DAG_NONE][PHASE_COMPACT]));
     runtime->addTelemetry(JS_TELEMETRY_GC_MARK_ROOTS_MS, t(markRootsTotal));
     runtime->addTelemetry(JS_TELEMETRY_GC_MARK_GRAY_MS, t(phaseTimes[PHASE_DAG_NONE][PHASE_SWEEP_MARK_GRAY]));
     runtime->addTelemetry(JS_TELEMETRY_GC_NON_INCREMENTAL, !!nonincrementalReason_);
     runtime->addTelemetry(JS_TELEMETRY_GC_INCREMENTAL_DISABLED, !runtime->gc.isIncrementalGCAllowed());
     runtime->addTelemetry(JS_TELEMETRY_GC_SCC_SWEEP_TOTAL_MS, t(sccTotal));
     runtime->addTelemetry(JS_TELEMETRY_GC_SCC_SWEEP_MAX_PAUSE_MS, t(sccLongest));
 
     if (!aborted) {
--- a/js/src/jit-test/lib/bullet.js
+++ b/js/src/jit-test/lib/bullet.js
@@ -1264,17 +1264,17 @@ function copyTempDouble(ptr) {
         }}};
   var MEMFS={CONTENT_OWNING:1,CONTENT_FLEXIBLE:2,CONTENT_FIXED:3,ensureFlexible:function (node) {
         if (node.contentMode !== MEMFS.CONTENT_FLEXIBLE) {
           var contents = node.contents;
           node.contents = Array.prototype.slice.call(contents);
           node.contentMode = MEMFS.CONTENT_FLEXIBLE;
         }
       },mount:function (mount) {
-        return MEMFS.create_node(null, '/', 0040000 | 0777, 0);
+        return MEMFS.create_node(null, '/', 0o040000 | 0o777, 0);
       },create_node:function (parent, name, mode, dev) {
         if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
           // no supported
           throw new FS.ErrnoError(ERRNO_CODES.EPERM);
         }
         var node = FS.createNode(parent, name, mode, dev);
         if (FS.isDir(node.mode)) {
           node.node_ops = {
@@ -1402,17 +1402,17 @@ function copyTempDouble(ptr) {
           for (var key in node.contents) {
             if (!node.contents.hasOwnProperty(key)) {
               continue;
             }
             entries.push(key);
           }
           return entries;
         },symlink:function (parent, newname, oldpath) {
-          var node = MEMFS.create_node(parent, newname, 0777 | 0120000, 0);
+          var node = MEMFS.create_node(parent, newname, 0o777 | 0o120000, 0);
           node.link = oldpath;
           return node;
         },readlink:function (node) {
           if (!FS.isLink(node.mode)) {
             throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
           }
           return node.link;
         }},stream_ops:{read:function (stream, buffer, offset, length, position) {
@@ -1652,29 +1652,29 @@ function copyTempDouble(ptr) {
         return node;
       },destroyNode:function (node) {
         FS.hashRemoveNode(node);
       },isRoot:function (node) {
         return node === node.parent;
       },isMountpoint:function (node) {
         return node.mounted;
       },isFile:function (mode) {
-        return (mode & 0170000) === 0100000;
+        return (mode & 0o170000) === 0o100000;
       },isDir:function (mode) {
-        return (mode & 0170000) === 0040000;
+        return (mode & 0o170000) === 0o040000;
       },isLink:function (mode) {
-        return (mode & 0170000) === 0120000;
+        return (mode & 0o170000) === 0o120000;
       },isChrdev:function (mode) {
-        return (mode & 0170000) === 0020000;
+        return (mode & 0o170000) === 0o020000;
       },isBlkdev:function (mode) {
-        return (mode & 0170000) === 0060000;
+        return (mode & 0o170000) === 0o060000;
       },isFIFO:function (mode) {
-        return (mode & 0170000) === 0010000;
+        return (mode & 0o170000) === 0o010000;
       },isSocket:function (mode) {
-        return (mode & 0140000) === 0140000;
+        return (mode & 0o140000) === 0o140000;
       },flagModes:{"r":0,"rs":8192,"r+":2,"w":1537,"wx":3585,"xw":3585,"w+":1538,"wx+":3586,"xw+":3586,"a":521,"ax":2569,"xa":2569,"a+":522,"ax+":2570,"xa+":2570},modeStringToFlags:function (str) {
         var flags = FS.flagModes[str];
         if (typeof flags === 'undefined') {
           throw new Error('Unknown file open mode: ' + str);
         }
         return flags;
       },flagsToPermissionString:function (flag) {
         var accmode = flag & 3;
@@ -1831,31 +1831,31 @@ function copyTempDouble(ptr) {
         if (err) {
           throw new FS.ErrnoError(err);
         }
         if (!parent.node_ops.mknod) {
           throw new FS.ErrnoError(ERRNO_CODES.EPERM);
         }
         return parent.node_ops.mknod(parent, name, mode, dev);
       },create:function (path, mode) {
-        mode = mode !== undefined ? mode : 0666;
+        mode = mode !== undefined ? mode : 0o666;
         mode &= 4095;
-        mode |= 0100000;
+        mode |= 0o100000;
         return FS.mknod(path, mode, 0);
       },mkdir:function (path, mode) {
-        mode = mode !== undefined ? mode : 0777;
-        mode &= 511 | 0001000;
-        mode |= 0040000;
+        mode = mode !== undefined ? mode : 0o777;
+        mode &= 511 | 0o001000;
+        mode |= 0o040000;
         return FS.mknod(path, mode, 0);
       },mkdev:function (path, mode, dev) {
         if (typeof(dev) === 'undefined') {
           dev = mode;
-          mode = 0666;
-        }
-        mode |= 0020000;
+          mode = 0o666;
+        }
+        mode |= 0o020000;
         return FS.mknod(path, mode, dev);
       },symlink:function (oldpath, newpath) {
         var lookup = FS.lookupPath(newpath, { parent: true });
         var parent = lookup.node;
         var newname = PATH.basename(newpath);
         var err = FS.mayCreate(parent, newname);
         if (err) {
           throw new FS.ErrnoError(err);
@@ -2091,26 +2091,26 @@ function copyTempDouble(ptr) {
         var lookup = FS.lookupPath(path, { follow: true });
         var node = lookup.node;
         node.node_ops.setattr(node, {
           timestamp: Math.max(atime, mtime)
         });
       },open:function (path, flags, mode, fd_start, fd_end) {
         path = PATH.normalize(path);
         flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
-        mode = typeof mode === 'undefined' ? 0666 : mode;
+        mode = typeof mode === 'undefined' ? 0o666 : mode;
         if ((flags & 512)) {
-          mode = (mode & 4095) | 0100000;
+          mode = (mode & 4095) | 0o100000;
         } else {
           mode = 0;
         }
         var node;
         try {
           var lookup = FS.lookupPath(path, {
-            follow: !(flags & 0200000)
+            follow: !(flags & 0o200000)
           });
           node = lookup.node;
           path = lookup.path;
         } catch (e) {
           // ignore
         }
         // perhaps we need to create the node
         if ((flags & 512)) {
@@ -2340,17 +2340,17 @@ function copyTempDouble(ptr) {
         var stdout = FS.open('/dev/stdout', 'w');
         HEAP32[((_stdout)>>2)]=stdout.fd;
         assert(stdout.fd === 2, 'invalid handle for stdout (' + stdout.fd + ')');
         var stderr = FS.open('/dev/stderr', 'w');
         HEAP32[((_stderr)>>2)]=stderr.fd;
         assert(stderr.fd === 3, 'invalid handle for stderr (' + stderr.fd + ')');
       },staticInit:function () {
         FS.nameTable = new Array(4096);
-        FS.root = FS.createNode(null, '/', 0040000 | 0777, 0);
+        FS.root = FS.createNode(null, '/', 0o040000 | 0o777, 0);
         FS.mount(MEMFS, {}, '/');
         FS.createDefaultDirectories();
         FS.createDefaultDevices();
       },init:function (input, output, error) {
         assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)');
         FS.init.initialized = true;
         // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
         Module['stdin'] = input || Module['stdin'];
@@ -2762,17 +2762,17 @@ function copyTempDouble(ptr) {
             };
             getRequest.onerror = function() { fail++; if (ok + fail == total) finish() };
           });
           transaction.onerror = onerror;
         };
         openRequest.onerror = onerror;
       }};
   var SOCKFS={mount:function (mount) {
-        return FS.createNode(null, '/', 0040000 | 0777, 0);
+        return FS.createNode(null, '/', 0o040000 | 0o777, 0);
       },nextname:function () {
         if (!SOCKFS.nextname.current) {
           SOCKFS.nextname.current = 0;
         }
         return 'socket[' + (SOCKFS.nextname.current++) + ']';
       },createSocket:function (family, type, protocol) {
         var streaming = type == 1;
         if (protocol) {
@@ -2786,17 +2786,17 @@ function copyTempDouble(ptr) {
           server: null,
           peers: {},
           pending: [],
           recv_queue: [],
           sock_ops: SOCKFS.websocket_sock_ops
         };
         // create the filesystem node to store the socket structure
         var name = SOCKFS.nextname();
-        var node = FS.createNode(SOCKFS.root, name, 0140000, 0);
+        var node = FS.createNode(SOCKFS.root, name, 0o140000, 0);
         node.sock = sock;
         // and the wrapping stream that enables library functions such
         // as read and write to indirectly interact with the socket
         var stream = FS.createStream({
           path: name,
           node: node,
           flags: FS.modeStringToFlags('r+'),
           seekable: false,
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -911,63 +911,64 @@ JS_TransplantObject(JSContext* cx, Handl
     AssertHeapIsIdle(cx);
     MOZ_ASSERT(origobj != target);
     MOZ_ASSERT(!origobj->is<CrossCompartmentWrapperObject>());
     MOZ_ASSERT(!target->is<CrossCompartmentWrapperObject>());
 
     RootedValue origv(cx, ObjectValue(*origobj));
     RootedObject newIdentity(cx);
 
-    {
-        AutoDisableProxyCheck adpc(cx->runtime());
-
-        JSCompartment* destination = target->compartment();
-
-        if (origobj->compartment() == destination) {
-            // If the original object is in the same compartment as the
-            // destination, then we know that we won't find a wrapper in the
-            // destination's cross compartment map and that the same
-            // object will continue to work.
-            if (!JSObject::swap(cx, origobj, target))
-                MOZ_CRASH();
-            newIdentity = origobj;
-        } else if (WrapperMap::Ptr p = destination->lookupWrapper(origv)) {
-            // There might already be a wrapper for the original object in
-            // the new compartment. If there is, we use its identity and swap
-            // in the contents of |target|.
-            newIdentity = &p->value().get().toObject();
-
-            // When we remove origv from the wrapper map, its wrapper, newIdentity,
-            // must immediately cease to be a cross-compartment wrapper. Nuke it.
-            destination->removeWrapper(p);
-            NukeCrossCompartmentWrapper(cx, newIdentity);
-
-            if (!JSObject::swap(cx, newIdentity, target))
-                MOZ_CRASH();
-        } else {
-            // Otherwise, we use |target| for the new identity object.
-            newIdentity = target;
-        }
-
-        // Now, iterate through other scopes looking for references to the
-        // old object, and update the relevant cross-compartment wrappers.
-        if (!RemapAllWrappersForObject(cx, origobj, newIdentity))
+    // Don't allow a compacting GC to observe any intermediate state.
+    AutoDisableCompactingGC nocgc(cx->runtime());
+
+    AutoDisableProxyCheck adpc(cx->runtime());
+
+    JSCompartment* destination = target->compartment();
+
+    if (origobj->compartment() == destination) {
+        // If the original object is in the same compartment as the
+        // destination, then we know that we won't find a wrapper in the
+        // destination's cross compartment map and that the same
+        // object will continue to work.
+        if (!JSObject::swap(cx, origobj, target))
             MOZ_CRASH();
-
-        // Lastly, update the original object to point to the new one.
-        if (origobj->compartment() != destination) {
-            RootedObject newIdentityWrapper(cx, newIdentity);
-            AutoCompartment ac(cx, origobj);
-            if (!JS_WrapObject(cx, &newIdentityWrapper))
-                MOZ_CRASH();
-            MOZ_ASSERT(Wrapper::wrappedObject(newIdentityWrapper) == newIdentity);
-            if (!JSObject::swap(cx, origobj, newIdentityWrapper))
-                MOZ_CRASH();
-            origobj->compartment()->putWrapper(cx, CrossCompartmentKey(newIdentity), origv);
-        }
+        newIdentity = origobj;
+    } else if (WrapperMap::Ptr p = destination->lookupWrapper(origv)) {
+        // There might already be a wrapper for the original object in
+        // the new compartment. If there is, we use its identity and swap
+        // in the contents of |target|.
+        newIdentity = &p->value().get().toObject();
+
+        // When we remove origv from the wrapper map, its wrapper, newIdentity,
+        // must immediately cease to be a cross-compartment wrapper. Nuke it.
+        destination->removeWrapper(p);
+        NukeCrossCompartmentWrapper(cx, newIdentity);
+
+        if (!JSObject::swap(cx, newIdentity, target))
+            MOZ_CRASH();
+    } else {
+        // Otherwise, we use |target| for the new identity object.
+        newIdentity = target;
+    }
+
+    // Now, iterate through other scopes looking for references to the
+    // old object, and update the relevant cross-compartment wrappers.
+    if (!RemapAllWrappersForObject(cx, origobj, newIdentity))
+        MOZ_CRASH();
+
+    // Lastly, update the original object to point to the new one.
+    if (origobj->compartment() != destination) {
+        RootedObject newIdentityWrapper(cx, newIdentity);
+        AutoCompartment ac(cx, origobj);
+        if (!JS_WrapObject(cx, &newIdentityWrapper))
+            MOZ_CRASH();
+        MOZ_ASSERT(Wrapper::wrappedObject(newIdentityWrapper) == newIdentity);
+        if (!JSObject::swap(cx, origobj, newIdentityWrapper))
+            MOZ_CRASH();
+        origobj->compartment()->putWrapper(cx, CrossCompartmentKey(newIdentity), origv);
     }
 
     // The new identity object might be one of several things. Return it to avoid
     // ambiguity.
     return newIdentity;
 }
 
 /*
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -110,16 +110,17 @@ enum {
     JS_TELEMETRY_GC_REASON,
     JS_TELEMETRY_GC_IS_COMPARTMENTAL,
     JS_TELEMETRY_GC_MS,
     JS_TELEMETRY_GC_BUDGET_MS,
     JS_TELEMETRY_GC_ANIMATION_MS,
     JS_TELEMETRY_GC_MAX_PAUSE_MS,
     JS_TELEMETRY_GC_MARK_MS,
     JS_TELEMETRY_GC_SWEEP_MS,
+    JS_TELEMETRY_GC_COMPACT_MS,
     JS_TELEMETRY_GC_MARK_ROOTS_MS,
     JS_TELEMETRY_GC_MARK_GRAY_MS,
     JS_TELEMETRY_GC_SLICE_MS,
     JS_TELEMETRY_GC_SLOW_PHASE,
     JS_TELEMETRY_GC_MMU_50,
     JS_TELEMETRY_GC_RESET,
     JS_TELEMETRY_GC_INCREMENTAL_DISABLED,
     JS_TELEMETRY_GC_NON_INCREMENTAL,
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2000,16 +2000,18 @@ GCRuntime::isCompactingGCEnabled() const
     MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
     return compactingEnabled && compactingDisabledCount == 0;
 }
 
 AutoDisableCompactingGC::AutoDisableCompactingGC(JSRuntime* rt)
   : gc(rt->gc)
 {
     gc.disableCompactingGC();
+    if (gc.isIncrementalGCInProgress() && gc.isCompactingGc())
+        AutoFinishGC finishGC(rt);
 }
 
 AutoDisableCompactingGC::~AutoDisableCompactingGC()
 {
     gc.enableCompactingGC();
 }
 
 static bool
--- a/js/src/jswrapper.h
+++ b/js/src/jswrapper.h
@@ -295,17 +295,17 @@ JS_FRIEND_API(JSObject*)
 UnwrapOneChecked(JSObject* obj, bool stopAtWindowProxy = true);
 
 JS_FRIEND_API(bool)
 IsCrossCompartmentWrapper(JSObject* obj);
 
 void
 NukeCrossCompartmentWrapper(JSContext* cx, JSObject* wrapper);
 
-bool
+void
 RemapWrapper(JSContext* cx, JSObject* wobj, JSObject* newTarget);
 
 JS_FRIEND_API(bool)
 RemapAllWrappersForObject(JSContext* cx, JSObject* oldTarget,
                           JSObject* newTarget);
 
 // API to recompute all cross-compartment wrappers whose source and target
 // match the given filters.
--- a/js/src/proxy/CrossCompartmentWrapper.cpp
+++ b/js/src/proxy/CrossCompartmentWrapper.cpp
@@ -489,17 +489,19 @@ js::NukeCrossCompartmentWrappers(JSConte
     }
 
     return true;
 }
 
 // Given a cross-compartment wrapper |wobj|, update it to point to
 // |newTarget|. This recomputes the wrapper with JS_WrapValue, and thus can be
 // useful even if wrapper already points to newTarget.
-bool
+// This operation crashes on failure rather than leaving the heap in an
+// inconsistent state.
+void
 js::RemapWrapper(JSContext* cx, JSObject* wobjArg, JSObject* newTargetArg)
 {
     RootedObject wobj(cx, wobjArg);
     RootedObject newTarget(cx, newTargetArg);
     MOZ_ASSERT(wobj->is<CrossCompartmentWrapperObject>());
     MOZ_ASSERT(!newTarget->is<CrossCompartmentWrapperObject>());
     JSObject* origTarget = Wrapper::wrappedObject(wobj);
     MOZ_ASSERT(origTarget);
@@ -546,18 +548,18 @@ js::RemapWrapper(JSContext* cx, JSObject
 
     // Before swapping, this wrapper came out of wrap(), which enforces the
     // invariant that the wrapper in the map points directly to the key.
     MOZ_ASSERT(Wrapper::wrappedObject(wobj) == newTarget);
 
     // Update the entry in the compartment's wrapper map to point to the old
     // wrapper, which has now been updated (via reuse or swap).
     MOZ_ASSERT(wobj->is<WrapperObject>());
-    wcompartment->putWrapper(cx, CrossCompartmentKey(newTarget), ObjectValue(*wobj));
-    return true;
+    if (!wcompartment->putWrapper(cx, CrossCompartmentKey(newTarget), ObjectValue(*wobj)))
+        MOZ_CRASH();
 }
 
 // Remap all cross-compartment wrappers pointing to |oldTarget| to point to
 // |newTarget|. All wrappers are recomputed.
 JS_FRIEND_API(bool)
 js::RemapAllWrappersForObject(JSContext* cx, JSObject* oldTargetArg,
                               JSObject* newTargetArg)
 {
@@ -570,20 +572,18 @@ js::RemapAllWrappersForObject(JSContext*
 
     for (CompartmentsIter c(cx->runtime(), SkipAtoms); !c.done(); c.next()) {
         if (WrapperMap::Ptr wp = c->lookupWrapper(origv)) {
             // We found a wrapper. Remember and root it.
             toTransplant.infallibleAppend(wp);
         }
     }
 
-    for (const Value& v : toTransplant) {
-        if (!RemapWrapper(cx, &v.toObject(), newTarget))
-            MOZ_CRASH();
-    }
+    for (const Value& v : toTransplant)
+        RemapWrapper(cx, &v.toObject(), newTarget);
 
     return true;
 }
 
 JS_FRIEND_API(bool)
 js::RecomputeWrappers(JSContext* cx, const CompartmentFilter& sourceFilter,
                       const CompartmentFilter& targetFilter)
 {
@@ -610,14 +610,13 @@ js::RecomputeWrappers(JSContext* cx, con
                 return false;
         }
     }
 
     // Recompute all the wrappers in the list.
     for (const Value& v : toRecompute) {
         JSObject* wrapper = &v.toObject();
         JSObject* wrapped = Wrapper::wrappedObject(wrapper);
-        if (!RemapWrapper(cx, wrapper, wrapped))
-            MOZ_CRASH();
+        RemapWrapper(cx, wrapper, wrapped);
     }
 
     return true;
 }
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -384,19 +384,19 @@ ExecuteState::pushInterpreterFrame(JSCon
 #ifdef _MSC_VER
 # pragma optimize("g", off)
 #endif
 bool
 js::RunScript(JSContext* cx, RunState& state)
 {
     JS_CHECK_RECURSION(cx, return false);
 
-#if defined(NIGHTLY_BUILD) && defined(MOZ_HAVE_RDTSC)
+#if defined(MOZ_HAVE_RDTSC)
     js::AutoStopwatch stopwatch(cx);
-#endif // defined(NIGHTLY_BUILD) && defined(MOZ_HAVE_RDTSC)
+#endif // defined(MOZ_HAVE_RDTSC)
 
     SPSEntryMarker marker(cx->runtime(), state.script());
 
     state.script()->ensureNonLazyCanonicalFunction(cx);
 
     if (jit::IsIonEnabled(cx)) {
         jit::MethodStatus status = jit::CanEnter(cx, state);
         if (status == jit::Method_Error)
--- a/js/src/vm/SavedStacks.cpp
+++ b/js/src/vm/SavedStacks.cpp
@@ -153,16 +153,20 @@ struct SavedFrame::Lookup {
         principals(principals),
         framePtr(framePtr),
         pc(pc),
         activation(activation)
     {
         MOZ_ASSERT(source);
         MOZ_ASSERT_IF(framePtr.isSome(), pc);
         MOZ_ASSERT_IF(framePtr.isSome(), activation);
+
+#ifdef JS_MORE_DETERMINISTIC
+        column = 0;
+#endif
     }
 
     explicit Lookup(SavedFrame& savedFrame)
       : source(savedFrame.getSource()),
         line(savedFrame.getLine()),
         column(savedFrame.getColumn()),
         functionDisplayName(savedFrame.getFunctionDisplayName()),
         asyncCause(savedFrame.getAsyncCause()),
@@ -419,16 +423,19 @@ void
 SavedFrame::initLine(uint32_t line)
 {
     initReservedSlot(JSSLOT_LINE, PrivateUint32Value(line));
 }
 
 void
 SavedFrame::initColumn(uint32_t column)
 {
+#ifdef JS_MORE_DETERMINISTIC
+    column = 0;
+#endif
     initReservedSlot(JSSLOT_COLUMN, PrivateUint32Value(column));
 }
 
 void
 SavedFrame::initPrincipals(JSPrincipals* principals)
 {
     if (principals)
         JS_HoldPrincipals(principals);
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -3143,16 +3143,19 @@ AccumulateTelemetryCallback(int id, uint
         Telemetry::Accumulate(Telemetry::GC_MAX_PAUSE_MS, sample);
         break;
       case JS_TELEMETRY_GC_MARK_MS:
         Telemetry::Accumulate(Telemetry::GC_MARK_MS, sample);
         break;
       case JS_TELEMETRY_GC_SWEEP_MS:
         Telemetry::Accumulate(Telemetry::GC_SWEEP_MS, sample);
         break;
+      case JS_TELEMETRY_GC_COMPACT_MS:
+        Telemetry::Accumulate(Telemetry::GC_COMPACT_MS, sample);
+        break;
       case JS_TELEMETRY_GC_MARK_ROOTS_MS:
         Telemetry::Accumulate(Telemetry::GC_MARK_ROOTS_MS, sample);
         break;
       case JS_TELEMETRY_GC_MARK_GRAY_MS:
         Telemetry::Accumulate(Telemetry::GC_MARK_GRAY_MS, sample);
         break;
       case JS_TELEMETRY_GC_SLICE_MS:
         Telemetry::Accumulate(Telemetry::GC_SLICE_MS, sample);
--- a/layout/base/AccessibleCaretManager.cpp
+++ b/layout/base/AccessibleCaretManager.cpp
@@ -1204,17 +1204,17 @@ AccessibleCaretManager::DispatchCaretSta
   init.mCaretVisuallyVisible = mFirstCaret->IsVisuallyVisible() ||
                                 mSecondCaret->IsVisuallyVisible();
   sel->Stringify(init.mSelectedTextContent);
 
   RefPtr<CaretStateChangedEvent> event =
     CaretStateChangedEvent::Constructor(doc, NS_LITERAL_STRING("mozcaretstatechanged"), init);
 
   event->SetTrusted(true);
-  event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
+  event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
 
   AC_LOG("%s: reason %d, collapsed %d, caretVisible %d", __FUNCTION__,
          init.mReason, init.mCollapsed, init.mCaretVisible);
 
   (new AsyncEventDispatcher(doc, event))->RunDOMEventWhenSafe();
 }
 
 } // namespace mozilla
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -3514,17 +3514,17 @@ ContainerState::NewPaintedLayerData(nsDi
                                     bool aShouldFixToViewport)
 {
   PaintedLayerData data;
   data.mAnimatedGeometryRoot = aAnimatedGeometryRoot;
   data.mScrollClip = aScrollClip;
   data.mAnimatedGeometryRootOffset = aTopLeft;
   data.mReferenceFrame = aItem->ReferenceFrame();
   data.mSingleItemFixedToViewport = aShouldFixToViewport;
-  data.mBackfaceHidden = aItem->Frame()->BackfaceIsHidden();
+  data.mBackfaceHidden = aItem->Frame()->In3DContextAndBackfaceIsHidden();
   data.mIsCaret = aItem->GetType() == nsDisplayItem::TYPE_CARET;
 
   data.mNewChildLayersIndex = mNewChildLayers.Length();
   NewLayerEntry* newLayerEntry = mNewChildLayers.AppendElement();
   newLayerEntry->mAnimatedGeometryRoot = aAnimatedGeometryRoot;
   newLayerEntry->mScrollClip = aScrollClip;
   newLayerEntry->mIsCaret = data.mIsCaret;
   // newLayerEntry->mOpaqueRegion is filled in later from
@@ -4133,17 +4133,17 @@ ContainerState::ProcessDisplayItems(nsDi
        * part of a PaintedLayer.
        */
       mLayerBuilder->AddLayerDisplayItem(ownLayer, item, layerState, nullptr);
     } else {
       bool avoidCreatingLayer = (maxLayers != -1 && layerCount >= maxLayers);
       PaintedLayerData* paintedLayerData =
         mPaintedLayerDataTree.FindPaintedLayerFor(animatedGeometryRoot, agrScrollClip,
                                                   itemVisibleRect, false,
-                                                  item->Frame()->BackfaceIsHidden(),
+                                                  item->Frame()->In3DContextAndBackfaceIsHidden(),
                                                   avoidCreatingLayer,
                                                   [&]() {
           layerCount++;
           return NewPaintedLayerData(item, animatedGeometryRoot, agrScrollClip,
                                      topLeft, shouldFixToViewport);
         });
 
       if (itemType == nsDisplayItem::TYPE_LAYER_EVENT_REGIONS) {
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -1136,17 +1136,17 @@ nsDocumentViewer::PermitUnloadInternal(b
   nsCOMPtr<nsIDocShell> docShell(mContainer);
   nsAutoString text;
   beforeUnload->GetReturnValue(text);
 
   // NB: we nullcheck mDocument because it might now be dead as a result of
   // the event being dispatched.
   if (!sIsBeforeUnloadDisabled && *aShouldPrompt && dialogsAreEnabled && mDocument &&
       (!sBeforeUnloadRequiresInteraction || mDocument->UserHasInteracted()) &&
-      (event->GetInternalNSEvent()->mFlags.mDefaultPrevented ||
+      (event->WidgetEventPtr()->mFlags.mDefaultPrevented ||
        !text.IsEmpty())) {
     // Ask the user if it's ok to unload the current page
 
     nsCOMPtr<nsIPrompt> prompt = do_GetInterface(docShell);
 
     if (prompt) {
       nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt);
       if (promptBag) {
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -2049,17 +2049,17 @@ nsLayoutUtils::HasPseudoStyle(nsIContent
   return pseudoContext != nullptr;
 }
 
 nsPoint
 nsLayoutUtils::GetDOMEventCoordinatesRelativeTo(nsIDOMEvent* aDOMEvent, nsIFrame* aFrame)
 {
   if (!aDOMEvent)
     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
-  WidgetEvent* event = aDOMEvent->GetInternalNSEvent();
+  WidgetEvent* event = aDOMEvent->WidgetEventPtr();
   if (!event)
     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
   return GetEventCoordinatesRelativeTo(event, aFrame);
 }
 
 nsPoint
 nsLayoutUtils::GetEventCoordinatesRelativeTo(const WidgetEvent* aEvent,
                                              nsIFrame* aFrame)
--- a/layout/forms/nsListControlFrame.cpp
+++ b/layout/forms/nsListControlFrame.cpp
@@ -1638,17 +1638,17 @@ nsListControlFrame::MouseUp(nsIDOMEvent*
     // And then NOT get an "onclick" event when when you click down on the select
     // and then up outside of the select
     // the EventStateManager tracks the content of the mouse down and the mouse up
     // to make sure they are the same, and the onclick is sent in the PostHandleEvent
     // depeneding on whether the clickCount is non-zero.
     // So we cheat here by either setting or unsetting the clcikCount in the native event
     // so the right thing happens for the onclick event
     WidgetMouseEvent* mouseEvent =
-      aMouseEvent->GetInternalNSEvent()->AsMouseEvent();
+      aMouseEvent->WidgetEventPtr()->AsMouseEvent();
 
     int32_t selectedIndex;
     if (NS_SUCCEEDED(GetIndexFromDOMEvent(aMouseEvent, selectedIndex))) {
       // If it's disabled, disallow the click and leave.
       bool isDisabled = false;
       IsOptionDisabled(selectedIndex, isDisabled);
       if (isDisabled) {
         aMouseEvent->PreventDefault();
@@ -2092,17 +2092,17 @@ nsListControlFrame::KeyDown(nsIDOMEvent*
 
   // Don't check defaultPrevented value because other browsers don't prevent
   // the key navigation of list control even if preventDefault() is called.
   // XXXmats 2015-04-16: the above is not true anymore, Chrome prevents all
   // XXXmats keyboard events, even tabbing, when preventDefault() is called
   // XXXmats in onkeydown. That seems sub-optimal though.
 
   const WidgetKeyboardEvent* keyEvent =
-    aKeyEvent->GetInternalNSEvent()->AsKeyboardEvent();
+    aKeyEvent->WidgetEventPtr()->AsKeyboardEvent();
   MOZ_ASSERT(keyEvent,
     "DOM event must have WidgetKeyboardEvent for its internal event");
 
   if (keyEvent->IsAlt()) {
     if (keyEvent->keyCode == NS_VK_UP || keyEvent->keyCode == NS_VK_DOWN) {
       DropDownToggleKey(aKeyEvent);
     }
     return NS_OK;
@@ -2245,17 +2245,17 @@ nsListControlFrame::KeyPress(nsIDOMEvent
   EventStates eventStates = mContent->AsElement()->State();
   if (eventStates.HasState(NS_EVENT_STATE_DISABLED)) {
     return NS_OK;
   }
 
   AutoIncrementalSearchResetter incrementalSearchResetter;
 
   const WidgetKeyboardEvent* keyEvent =
-    aKeyEvent->GetInternalNSEvent()->AsKeyboardEvent();
+    aKeyEvent->WidgetEventPtr()->AsKeyboardEvent();
   MOZ_ASSERT(keyEvent,
     "DOM event must have WidgetKeyboardEvent for its internal event");
 
   // Select option with this as the first character
   // XXX Not I18N compliant
 
   // Don't do incremental search if the key event has already consumed.
   if (keyEvent->mFlags.mDefaultPrevented) {
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -1160,16 +1160,22 @@ nsIFrame::Combines3DTransformWithAncesto
 {
   if (!GetParent() || !GetParent()->Extend3DContext()) {
     return false;
   }
   return StyleDisplay()->HasTransform(this) || StyleDisplay()->BackfaceIsHidden();
 }
 
 bool
+nsIFrame::In3DContextAndBackfaceIsHidden() const
+{
+  return Combines3DTransformWithAncestors() && StyleDisplay()->BackfaceIsHidden();
+}
+
+bool
 nsIFrame::HasPerspective() const
 {
   if (!IsTransformed()) {
     return false;
   }
   nsIFrame* containingBlock = GetContainingBlock(SKIP_SCROLLED_FRAME);
   if (!containingBlock) {
     return false;
@@ -2101,18 +2107,16 @@ nsIFrame::BuildDisplayListForStackingCon
 
   mozilla::gfx::VRDeviceProxy* vrHMDInfo = nullptr;
   if ((GetStateBits() & NS_FRAME_HAS_VR_CONTENT)) {
     vrHMDInfo = static_cast<mozilla::gfx::VRDeviceProxy*>(mContent->GetProperty(nsGkAtoms::vr_state));
   }
 
   DisplayListClipState::AutoSaveRestore clipState(aBuilder);
 
-  nsDisplayListBuilder::AutoSaveRestorePerspectiveIndex perspectiveIndex(aBuilder, this);
-
   if (isTransformed || useBlendMode || usingSVGEffects || useFixedPosition || useStickyPosition) {
     // We don't need to pass ancestor clipping down to our children;
     // everything goes inside a display item's child list, and the display
     // item itself will be clipped.
     // For transforms we also need to clear ancestor clipping because it's
     // relative to the wrong display item reference frame anyway.
     // We clear both regular and scroll clips here. Our content needs to be
     // able to walk up the complete cross stacking context scroll clip chain,
@@ -2121,16 +2125,19 @@ nsIFrame::BuildDisplayListForStackingCon
     clipState.ClearForStackingContextContents();
   }
 
   nsDisplayListCollection set;
   {
     DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder);
     nsDisplayListBuilder::AutoInTransformSetter
       inTransformSetter(aBuilder, inTransform);
+    nsDisplayListBuilder::AutoSaveRestorePerspectiveIndex
+      perspectiveIndex(aBuilder, this);
+
     CheckForApzAwareEventHandlers(aBuilder, this);
 
     nsRect clipPropClip;
     if (ApplyClipPropClipping(aBuilder, this, disp, &clipPropClip,
                               nestedClipState)) {
       dirtyRect.IntersectRect(dirtyRect, clipPropClip);
     }
 
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -1271,16 +1271,23 @@ public:
 
   /**
    * Returns whether this frame has a parent that Extend3DContext() and has
    * its own transform (or hidden backface) to be combined with the parent's
    * transform.
    */
   bool Combines3DTransformWithAncestors() const;
 
+  /**
+   * Returns whether this frame has a hidden backface and has a parent that
+   * Extend3DContext(). This is useful because in some cases the hidden
+   * backface can safely be ignored if it could not be visible anyway.
+   */
+  bool In3DContextAndBackfaceIsHidden() const;
+
   bool IsPreserve3DLeaf() const {
     return Combines3DTransformWithAncestors() && !Extend3DContext();
   }
 
   bool HasPerspective() const;
 
   bool ChildrenHavePerspective() const;
 
--- a/layout/printing/nsPrintPreviewListener.cpp
+++ b/layout/printing/nsPrintPreviewListener.cpp
@@ -107,17 +107,17 @@ enum eEventAction {
   eEventAction_Propagate, eEventAction_Suppress,
   eEventAction_StopPropagation
 };
 
 static eEventAction
 GetActionForEvent(nsIDOMEvent* aEvent)
 {
   WidgetKeyboardEvent* keyEvent =
-    aEvent->GetInternalNSEvent()->AsKeyboardEvent();
+    aEvent->WidgetEventPtr()->AsKeyboardEvent();
   if (!keyEvent) {
     return eEventAction_Suppress;
   }
 
   if (keyEvent->mFlags.mInSystemGroup) {
     NS_ASSERTION(keyEvent->mMessage == eKeyDown,
       "Assuming we're listening only keydown event in system group");
     return eEventAction_StopPropagation;
--- a/layout/reftests/reftest.list
+++ b/layout/reftests/reftest.list
@@ -350,16 +350,19 @@ include transform/reftest.list
 # 3d transforms
 include transform-3d/reftest.list
 
 # unicode/ (verify that we don't do expend effort doing unicode-aware case checks)
 include unicode/reftest.list
 
 include view-source/reftest.list
 
+# web-animations
+include web-animations/reftest.list
+
 # webcomponents/
 include webcomponents/reftest.list
 
 # widget/
 include ../../widget/reftests/reftest.list
 
 # xml-stylesheet/
 include ../../dom/tests/reftest/xml-stylesheet/reftest.list
new file mode 100644
--- /dev/null
+++ b/layout/reftests/transform-3d/1245450-1.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style type="text/css">
+  .scene {
+    perspective: 1000px;
+    transform-style: preserve-3d;
+    transform: rotateY(0deg);
+  }
+
+  .card {
+    perspective: 1000px;
+    transform-style: preserve-3d;
+    backface-visibility: hidden;
+    width: 100px;
+    height: 100px;
+  }
+
+  .front {
+    transform: rotateY(0deg);
+    background-color: #00FF00;
+  }
+
+  .back {
+    transform: rotateY(180deg);
+    background-color: #FF0000;
+  }
+</style>
+</head>
+<body>
+  <div class="scene">
+    <div class="card front"></div>
+    <div class="card back"></div>
+  </div>
+</body>
+</html>
--- a/layout/reftests/transform-3d/reftest.list
+++ b/layout/reftests/transform-3d/reftest.list
@@ -66,8 +66,9 @@ fuzzy(3,99) fuzzy-if(/^Windows\x20NT\x20
 != animate-cube-radians-ref.html animate-cube-radians-zoom-ref.html
 fuzzy(3,99) == animate-cube-degrees.html animate-cube-degrees-ref.html # subpixel AA
 == animate-cube-degrees-zoom.html animate-cube-degrees-zoom-ref.html
 != animate-cube-degrees-ref.html animate-cube-degrees-zoom-ref.html
 fuzzy-if(B2G||Android||OSX==1010,143,100) fuzzy-if(winWidget||OSX<1010,141,100) fuzzy-if(gtkWidget,128,100) == preserves3d-nested.html preserves3d-nested-ref.html
 fuzzy-if(cocoaWidget,128,9) == animate-preserve3d-parent.html animate-preserve3d-ref.html # intermittently fuzzy on Mac
 fuzzy-if(cocoaWidget,128,9) == animate-preserve3d-child.html animate-preserve3d-ref.html # intermittently fuzzy on Mac
 == animate-backface-hidden.html about:blank
+== 1245450-1.html green-rect.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/web-animations/1246046-1.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<html class="reftest-wait">
+  <head>
+    <meta charset=utf-8>
+    <title>Bug 1246046</title>
+    <style>
+      div {
+        width: 0px;
+        height: 100px;
+        background: green;
+      }
+    </style>
+  </head>
+  <body>
+    <div></div>
+    <script>
+      var target = document.querySelector("div");
+      var anim = target.animate(
+        [ { width: "0px" }, { width: "200px" } ], 2000);
+      anim.pause();
+      anim.currentTime = 1000;
+      document.documentElement.removeAttribute("class");
+    </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/web-animations/green-box.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset=utf-8>
+    <title>Reference green box</title>
+    <style>
+      div {
+        width: 100px;
+        height: 100px;
+        background: green;
+      }
+    </style>
+  </head>
+  <body>
+    <div></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/web-animations/reftest.list
@@ -0,0 +1,1 @@
+== 1246046-1.html green-box.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/writing-mode/1248248-1-orientation-break-glyphrun-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<style>
+@font-face {
+  font-family: test;
+  src: url('../fonts/gw1270797.ttf') format("truetype");
+}
+html {
+  font-size: 72pt;
+  font-family: test, sans-serif;
+  writing-mode: vertical-rl;
+  text-orientation: mixed;
+}
+</style>
+</head>
+<body>
+&#xFA19;&#xFA19;&#xFA19;&#xFA19;
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/writing-mode/1248248-1-orientation-break-glyphrun.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<style>
+@font-face {
+  font-family: test;
+  src: url('../fonts/gw1270797.ttf') format("truetype");
+}
+html {
+  font-size: 72pt;
+  font-family: test, sans-serif;
+  writing-mode: vertical-rl;
+  text-orientation: mixed;
+}
+</style>
+</head>
+<body>
+&#xFA19;&#x795E;&#xE0100;&#x795E;&#xE0103;&#x795E;&#xFE00;
+</body>
+</html>
--- a/layout/reftests/writing-mode/reftest.list
+++ b/layout/reftests/writing-mode/reftest.list
@@ -164,14 +164,16 @@ fuzzy-if(gtkWidget||B2G,255,6) fuzzy-if(
 == 1196887-1-computed-display-inline-block.html 1196887-1-computed-display-inline-block-ref.html
 == 1205787-legacy-svg-values-1.html 1205787-legacy-svg-values-1-ref.html
 
 == 1216747-1.html 1216747-1-ref.html
 != 1216747-1.html 1216747-1-notref.html
 
 == 1243125-1-floats-overflowing.html 1243125-1-floats-overflowing-ref.html
 
+HTTP(..) == 1248248-1-orientation-break-glyphrun.html 1248248-1-orientation-break-glyphrun-ref.html
+
 # Suite of tests from Gérard Talbot in bug 1079151
 # Frequent Windows 7 load failed: timed out waiting for test to complete (waiting for onload scripts to complete), bug 1167155 and friends
 skip-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) include abspos/reftest.list
 
 # Tests for tables with vertical writing modes
 include tables/reftest.list
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -296,56 +296,56 @@ CSSAnimation::ElapsedTimeToTimeStamp(con
 
 ////////////////////////// nsAnimationManager ////////////////////////////
 
 NS_IMPL_CYCLE_COLLECTION(nsAnimationManager, mEventDispatcher)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsAnimationManager, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsAnimationManager, Release)
 
-nsIStyleRule*
-nsAnimationManager::CheckAnimationRule(nsStyleContext* aStyleContext,
-                                       mozilla::dom::Element* aElement)
+void
+nsAnimationManager::UpdateAnimations(nsStyleContext* aStyleContext,
+                                     mozilla::dom::Element* aElement)
 {
-  // Ignore animations for print or print preview, and for elements
-  // that are not attached to the document tree.
-  if (!mPresContext->IsDynamic() || !aElement->IsInComposedDoc()) {
-    return nullptr;
-  }
+  MOZ_ASSERT(mPresContext->IsDynamic(),
+             "Should not update animations for print or print preview");
+  MOZ_ASSERT(aElement->IsInComposedDoc(),
+             "Should not update animations that are not attached to the "
+             "document tree");
 
   // Everything that causes our animation data to change triggers a
   // style change, which in turn triggers a non-animation restyle.
   // Likewise, when we initially construct frames, we're not in a
   // style change, but also not in an animation restyle.
 
   const nsStyleDisplay* disp = aStyleContext->StyleDisplay();
   AnimationCollection* collection =
     GetAnimationCollection(aElement,
                            aStyleContext->GetPseudoType(),
                            false /* aCreateIfNeeded */);
   if (!collection &&
       disp->mAnimationNameCount == 1 &&
       disp->mAnimations[0].GetName().IsEmpty()) {
-    return nullptr;
+    return;
   }
 
   nsAutoAnimationMutationBatch mb(aElement->OwnerDoc());
 
   // build the animations list
   dom::DocumentTimeline* timeline = aElement->OwnerDoc()->Timeline();
   AnimationPtrArray newAnimations;
   if (!aStyleContext->IsInDisplayNoneSubtree()) {
     BuildAnimations(aStyleContext, aElement, timeline, newAnimations);
   }
 
   if (newAnimations.IsEmpty()) {
     if (collection) {
       collection->Destroy();
     }
-    return nullptr;
+    return;
   }
 
   if (collection) {
     EffectSet* effectSet =
       EffectSet::GetEffectSet(aElement, aStyleContext->GetPseudoType());
     if (effectSet) {
       effectSet->UpdateAnimationGeneration(mPresContext);
     }
@@ -466,35 +466,28 @@ nsAnimationManager::CheckAnimationRule(n
   for (size_t newAnimIdx = newAnimations.Length(); newAnimIdx-- != 0; ) {
     newAnimations[newAnimIdx]->CancelFromStyle();
   }
 
   EffectCompositor::UpdateCascadeResults(aElement,
                                          aStyleContext->GetPseudoType(),
                                          aStyleContext);
 
-  EffectCompositor::CascadeLevel cascadeLevel =
-    EffectCompositor::CascadeLevel::Animations;
-  mPresContext->EffectCompositor()
-              ->MaybeUpdateAnimationRule(aElement,
-                                         aStyleContext->GetPseudoType(),
-                                         cascadeLevel);
+  mPresContext->EffectCompositor()->
+    MaybeUpdateAnimationRule(aElement,
+                             aStyleContext->GetPseudoType(),
+                             EffectCompositor::CascadeLevel::Animations);
 
   // We don't actually dispatch the pending events now.  We'll either
   // dispatch them the next time we get a refresh driver notification
   // or the next time somebody calls
   // nsPresShell::FlushPendingNotifications.
   if (mEventDispatcher.HasQueuedEvents()) {
     mPresContext->Document()->SetNeedStyleFlush();
   }
-
-  return mPresContext->EffectCompositor()
-                     ->GetAnimationRule(aElement,
-                                        aStyleContext->GetPseudoType(),
-                                        cascadeLevel);
 }
 
 void
 nsAnimationManager::StopAnimationsForElement(
   mozilla::dom::Element* aElement,
   nsCSSPseudoElements::Type aPseudoType)
 {
   MOZ_ASSERT(aElement);
--- a/layout/style/nsAnimationManager.h
+++ b/layout/style/nsAnimationManager.h
@@ -279,28 +279,25 @@ public:
     : mozilla::CommonAnimationManager(aPresContext)
   {
   }
 
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsAnimationManager)
   NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsAnimationManager)
 
   /**
-   * Return the style rule that RulesMatching should add for
-   * aStyleContext.  This might be different from what RulesMatching
-   * actually added during aStyleContext's construction because the
-   * element's animation-name may have changed.  (However, this does
-   * return null during the non-animation restyling phase, as
-   * RulesMatching does.)
+   * Update the set of animations on |aElement| based on |aStyleContext|.
+   * If necessary, this will notify the corresponding EffectCompositor so
+   * that it can update its animation rule.
    *
    * aStyleContext may be a style context for aElement or for its
    * :before or :after pseudo-element.
    */
-  nsIStyleRule* CheckAnimationRule(nsStyleContext* aStyleContext,
-                                   mozilla::dom::Element* aElement);
+  void UpdateAnimations(nsStyleContext* aStyleContext,
+                        mozilla::dom::Element* aElement);
 
   /**
    * Add a pending event.
    */
   void QueueEvent(mozilla::AnimationEventInfo&& aEventInfo)
   {
     mEventDispatcher.QueueEvent(
       mozilla::Forward<mozilla::AnimationEventInfo>(aEventInfo));
--- a/layout/style/nsStyleSet.cpp
+++ b/layout/style/nsStyleSet.cpp
@@ -965,23 +965,34 @@ nsStyleSet::GetContext(nsStyleContext* a
     }
   }
   else {
     NS_ASSERTION(result->GetPseudoType() == aPseudoType, "Unexpected type");
     NS_ASSERTION(result->GetPseudo() == aPseudoTag, "Unexpected pseudo");
   }
 
   if (aFlags & eDoAnimation) {
-    // Normally the animation manager has already added the correct
-    // style rule.  However, if the animation-name just changed, it
-    // might have been wrong.  So ask it to double-check based on the
-    // resulting style context.
+
     nsIStyleRule *oldAnimRule = GetAnimationRule(aRuleNode);
-    nsIStyleRule *animRule = PresContext()->AnimationManager()->
-      CheckAnimationRule(result, aElementForAnimation);
+    nsIStyleRule *animRule = nullptr;
+
+    // Ignore animations for print or print preview, and for elements
+    // that are not attached to the document tree.
+    if (PresContext()->IsDynamic() &&
+        aElementForAnimation->IsInComposedDoc()) {
+      // Update CSS animations in case the animation-name has just changed.
+      PresContext()->AnimationManager()->UpdateAnimations(result,
+                                                          aElementForAnimation);
+
+      animRule = PresContext()->EffectCompositor()->
+                   GetAnimationRule(aElementForAnimation,
+                                    result->GetPseudoType(),
+                                    EffectCompositor::CascadeLevel::Animations);
+    }
+
     MOZ_ASSERT(result->RuleNode() == aRuleNode,
                "unexpected rule node");
     MOZ_ASSERT(!result->GetStyleIfVisited() == !aVisitedRuleNode,
                "unexpected visited rule node");
     MOZ_ASSERT(!aVisitedRuleNode ||
                result->GetStyleIfVisited()->RuleNode() == aVisitedRuleNode,
                "unexpected visited rule node");
     MOZ_ASSERT(!aVisitedRuleNode ||
--- a/layout/tools/layout-debug/ui/content/layoutdebug.js
+++ b/layout/tools/layout-debug/ui/content/layoutdebug.js
@@ -377,17 +377,17 @@ RTestURLList.prototype = {
   doneURL : function()
   {
     var basename =
       String(this.mCurrentURL.relurl).replace(/[:=&.\/?]/g, "_") + ".rgd";
 
     var data = this.mCurrentURL.dir.clone();
     data.append( this.mIsBaseline ? "baseline" : "verify");
     if (!data.exists())
-      data.create(nsIFile.DIRECTORY_TYPE, 0777)
+      data.create(nsIFile.DIRECTORY_TYPE, 0o777)
     data.append(basename);
 
     dump("Writing regression data to " +
          data.QueryInterface(nsILocalFile).persistentDescriptor + "\n");
     if (this.mIsPrinting) {
       this.mRegressionTester.dumpFrameModel(gBrowser.contentWindow, data,
         nsILayoutRegressionTester.DUMP_FLAGS_MASK_PRINT_MODE);
     }
--- a/layout/xul/nsMenuBarFrame.cpp
+++ b/layout/xul/nsMenuBarFrame.cpp
@@ -161,17 +161,17 @@ nsMenuBarFrame::ToggleMenuActiveState()
 nsMenuFrame*
 nsMenuBarFrame::FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent)
 {
   uint32_t charCode;
   aKeyEvent->GetCharCode(&charCode);
 
   AutoTArray<uint32_t, 10> accessKeys;
   WidgetKeyboardEvent* nativeKeyEvent =
-    aKeyEvent->AsEvent()->GetInternalNSEvent()->AsKeyboardEvent();
+    aKeyEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent();
   if (nativeKeyEvent)
     nsContentUtils::GetAccessKeyCandidates(nativeKeyEvent, accessKeys);
   if (accessKeys.IsEmpty() && charCode)
     accessKeys.AppendElement(charCode);
 
   if (accessKeys.IsEmpty())
     return nullptr; // no character was pressed so just return
 
--- a/layout/xul/nsMenuBarListener.cpp
+++ b/layout/xul/nsMenuBarListener.cpp
@@ -214,17 +214,17 @@ nsMenuBarListener::KeyPress(nsIDOMEvent*
       nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aKeyEvent);
       uint32_t keyCode, charCode;
       keyEvent->GetKeyCode(&keyCode);
       keyEvent->GetCharCode(&charCode);
 
       bool hasAccessKeyCandidates = charCode != 0;
       if (!hasAccessKeyCandidates) {
         WidgetKeyboardEvent* nativeKeyEvent =
-          aKeyEvent->GetInternalNSEvent()->AsKeyboardEvent();
+          aKeyEvent->WidgetEventPtr()->AsKeyboardEvent();
         if (nativeKeyEvent) {
           AutoTArray<uint32_t, 10> keys;
           nsContentUtils::GetAccessKeyCandidates(nativeKeyEvent, keys);
           hasAccessKeyCandidates = !keys.IsEmpty();
         }
       }
 
       // Cancel the access key flag unless we are pressing the access key.
@@ -289,17 +289,17 @@ nsMenuBarListener::IsAccessKeyPressed(ns
           (modifiers & mAccessKeyMask) &&
           (modifiers & ~(mAccessKeyMask | MODIFIER_SHIFT)) == 0);
 }
 
 Modifiers
 nsMenuBarListener::GetModifiersForAccessKey(nsIDOMKeyEvent* aKeyEvent)
 {
   WidgetInputEvent* inputEvent =
-    aKeyEvent->AsEvent()->GetInternalNSEvent()->AsInputEvent();
+    aKeyEvent->AsEvent()->WidgetEventPtr()->AsInputEvent();
   MOZ_ASSERT(inputEvent);
 
   static const Modifiers kPossibleModifiersForAccessKey =
     (MODIFIER_SHIFT | MODIFIER_CONTROL | MODIFIER_ALT | MODIFIER_META |
      MODIFIER_OS);
   return (inputEvent->modifiers & kPossibleModifiersForAccessKey);
 }
 
--- a/layout/xul/nsSliderFrame.cpp
+++ b/layout/xul/nsSliderFrame.cpp
@@ -961,17 +961,17 @@ nsSliderFrame::StartDrag(nsIDOMEvent* aE
 {
 #ifdef DEBUG_SLIDER
   printf("Begin dragging\n");
 #endif
   if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
                             nsGkAtoms::_true, eCaseMatters))
     return NS_OK;
 
-  WidgetGUIEvent* event = aEvent->GetInternalNSEvent()->AsGUIEvent();
+  WidgetGUIEvent* event = aEvent->WidgetEventPtr()->AsGUIEvent();
 
   if (!ShouldScrollForEvent(event)) {
     return NS_OK;
   }
 
   nsPoint pt;
   if (!GetEventPoint(event, pt)) {
     return NS_OK;
--- a/layout/xul/nsXULPopupManager.cpp
+++ b/layout/xul/nsXULPopupManager.cpp
@@ -592,17 +592,17 @@ nsXULPopupManager::InitTriggerEvent(nsID
   nsCOMPtr<nsIDOMUIEvent> uiEvent = do_QueryInterface(aEvent);
   if (uiEvent) {
     uiEvent->GetRangeParent(getter_AddRefs(mRangeParent));
     uiEvent->GetRangeOffset(&mRangeOffset);
 
     // get the event coordinates relative to the root frame of the document
     // containing the popup.
     NS_ASSERTION(aPopup, "Expected a popup node");
-    WidgetEvent* event = aEvent->GetInternalNSEvent();
+    WidgetEvent* event = aEvent->WidgetEventPtr();
     if (event) {
       WidgetInputEvent* inputEvent = event->AsInputEvent();
       if (inputEvent) {
         mCachedModifiers = inputEvent->modifiers;
       }
       nsIDocument* doc = aPopup->GetCurrentDoc();
       if (doc) {
         nsIPresShell* presShell = doc->GetShell();
@@ -2053,33 +2053,33 @@ nsXULPopupManager::CancelMenuTimer(nsMen
 }
 
 bool
 nsXULPopupManager::HandleShortcutNavigation(nsIDOMKeyEvent* aKeyEvent,
                                             nsMenuPopupFrame* aFrame)
 {
   // On Windows, don't check shortcuts when the accelerator key is down.
 #ifdef XP_WIN
-  WidgetInputEvent* evt = aKeyEvent->AsEvent()->GetInternalNSEvent()->AsInputEvent();
+  WidgetInputEvent* evt = aKeyEvent->AsEvent()->WidgetEventPtr()->AsInputEvent();
   if (evt && evt->IsAccel()) {
     return false;
   }
 #endif
 
   nsMenuChainItem* item = GetTopVisibleMenu();
   if (!aFrame && item)
     aFrame = item->Frame();
 
   if (aFrame) {
     bool action;
     nsMenuFrame* result = aFrame->FindMenuWithShortcut(aKeyEvent, action);
     if (result) {
       aFrame->ChangeMenuItem(result, false, true);
       if (action) {
-        WidgetGUIEvent* evt = aKeyEvent->AsEvent()->GetInternalNSEvent()->AsGUIEvent();
+        WidgetGUIEvent* evt = aKeyEvent->AsEvent()->WidgetEventPtr()->AsGUIEvent();
         nsMenuFrame* menuToOpen = result->Enter(evt);
         if (menuToOpen) {
           nsCOMPtr<nsIContent> content = menuToOpen->GetContent();
           ShowMenu(content, true, false);
         }
       }
       return true;
     }
@@ -2316,17 +2316,17 @@ nsXULPopupManager::HandleKeyboardEventWi
       MOZ_FALLTHROUGH;
 
     case nsIDOMKeyEvent::DOM_VK_RETURN: {
       // If there is a popup open, check if the current item needs to be opened.
       // Otherwise, tell the active menubar, if any, to activate the menu. The
       // Enter method will return a menu if one needs to be opened as a result.
       nsMenuFrame* menuToOpen = nullptr;
       WidgetGUIEvent* GUIEvent = aKeyEvent->AsEvent()->
-        GetInternalNSEvent()->AsGUIEvent();
+        WidgetEventPtr()->AsGUIEvent();
 
       if (aTopVisibleMenuItem) {
         menuToOpen = aTopVisibleMenuItem->Frame()->Enter(GUIEvent);
       } else if (mActiveMenuBar) {
         menuToOpen = mActiveMenuBar->Enter(GUIEvent);
       }
       if (menuToOpen) {
         nsCOMPtr<nsIContent> content = menuToOpen->GetContent();
--- a/media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp
+++ b/media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp
@@ -1844,16 +1844,23 @@ JsepSessionImpl::ValidateRemoteDescripti
   for (size_t i = 0;
        i < mCurrentRemoteDescription->GetMediaSectionCount();
        ++i) {
     if (mSdpHelper.MsectionIsDisabled(description.GetMediaSection(i)) ||
         mSdpHelper.MsectionIsDisabled(mCurrentRemoteDescription->GetMediaSection(i))) {
       continue;
     }
 
+    if (mCurrentRemoteDescription->GetMediaSection(i).GetMediaType() !=
+        description.GetMediaSection(i).GetMediaType()) {
+      JSEP_SET_ERROR("Remote description changes the media type of m-line "
+                     << i);
+      return NS_ERROR_INVALID_ARG;
+    }
+
     const SdpAttributeList& newAttrs(
         description.GetMediaSection(i).GetAttributeList());
     const SdpAttributeList& oldAttrs(
         mCurrentRemoteDescription->GetMediaSection(i).GetAttributeList());
 
     if ((newAttrs.GetIceUfrag() != oldAttrs.GetIceUfrag()) ||
         (newAttrs.GetIcePwd() != oldAttrs.GetIcePwd())) {
       JSEP_SET_ERROR("ICE restart is unsupported at this time "
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -2623,17 +2623,17 @@ PeerConnectionImpl::PluginCrash(uint32_t
   init.mGmpPlugin = true;
   init.mBubbles = true;
   init.mCancelable = true;
 
   RefPtr<PluginCrashedEvent> event =
     PluginCrashedEvent::Constructor(doc, NS_LITERAL_STRING("PluginCrashed"), init);
 
   event->SetTrusted(true);
-  event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
+  event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
 
   EventDispatcher::DispatchDOMEvent(mWindow, nullptr, event, nullptr, nullptr);
 #endif
 
   return true;
 }
 
 void
--- a/media/webrtc/trunk/webrtc/tools/rtcbot/test.js
+++ b/media/webrtc/trunk/webrtc/tools/rtcbot/test.js
@@ -135,17 +135,17 @@ StatisticsReport.prototype = {
     };
   },
 
   finish: function (doneCallback) {
     fs.exists("test/reports/", function (exists) {
       if(exists) {
         writeFile.bind(this)();
       } else {
-        fs.mkdir("test/reports/", 0777, writeFile.bind(this));
+        fs.mkdir("test/reports/", 0o777, writeFile.bind(this));
       }
     }.bind(this));
 
     function writeFile () {
       fs.writeFile("test/reports/" + this.outputFileName_ + "_" +
         (new Date()).getTime() +".json", JSON.stringify(this.output_),
         doneCallback);
     }
--- a/mobile/android/b2gdroid/installer/package-manifest.in
+++ b/mobile/android/b2gdroid/installer/package-manifest.in
@@ -247,19 +247,17 @@
 @BINPATH@/components/storage.xpt
 @BINPATH@/components/telemetry.xpt
 @BINPATH@/components/toolkit_asyncshutdown.xpt
 @BINPATH@/components/toolkit_filewatcher.xpt
 @BINPATH@/components/toolkit_finalizationwitness.xpt
 @BINPATH@/components/toolkit_formautofill.xpt
 @BINPATH@/components/toolkit_osfile.xpt
 @BINPATH@/components/toolkit_securityreporter.xpt
-#ifdef NIGHTLY_BUILD
 @BINPATH@/components/toolkit_perfmonitoring.xpt
-#endif
 @BINPATH@/components/toolkit_xulstore.xpt
 @BINPATH@/components/toolkitprofile.xpt
 #ifdef MOZ_ENABLE_XREMOTE
 @BINPATH@/components/toolkitremote.xpt
 #endif
 @BINPATH@/components/txtsvc.xpt
 @BINPATH@/components/txmgr.xpt
 @BINPATH@/components/uconv.xpt
--- a/mobile/android/base/AdjustConstants.java.in
+++ b/mobile/android/base/AdjustConstants.java.in
@@ -1,9 +1,10 @@
 //#filter substitution
+//#include @OBJDIR@/adjust_sdk_app_token
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * 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/. */
 
 package org.mozilla.gecko;
 
 import org.mozilla.gecko.adjust.AdjustHelperInterface;
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -328,35 +328,16 @@ PP_TARGETS += manifest
 # need to write AppConstants.java.in to
 # generated/preprocessed/org/mozilla/gecko.
 preprocessed := $(addsuffix .in,$(subst generated/preprocessed/org/mozilla/gecko/,,$(filter generated/preprocessed/org/mozilla/gecko/%,$(constants_PP_JAVAFILES))))
 
 preprocessed_PATH := generated/preprocessed/org/mozilla/gecko
 preprocessed_KEEP_PATH := 1
 preprocessed_FLAGS := --marker='//\\\#'
 
-ifdef MOZ_INSTALL_TRACKING
-ifdef MOZ_INSTALL_TRACKING_ADJUST_SDK_APP_TOKEN
-# The value of MOZ_INSTALL_TRACKING_ADJUST_SDK_APP_TOKEN is sensitive: we don't
-# want to expose it in build logs.  Following the model set by
-# toolkit/components/urlformatter/Makefile.in, we expose it to AppConstants.java
-# quietly here.  Be aware that the included line's marker needs to agree with
-# --marker above.
-
-adjust_sdk_app_token:
-	@echo '//#define MOZ_INSTALL_TRACKING_ADJUST_SDK_APP_TOKEN $(MOZ_INSTALL_TRACKING_ADJUST_SDK_APP_TOKEN)' > $@
-
-export:: adjust_sdk_app_token
-
-preprocessed_FLAGS += -I adjust_sdk_app_token
-endif # MOZ_INSTALL_TRACKING
-endif # MOZ_INSTALL_TRACKING_ADJUST_SDK_APP_TOKEN
-
-GARBAGE += adjust_sdk_app_token
-
 PP_TARGETS += preprocessed
 
 include $(topsrcdir)/config/rules.mk
 
 not_android_res_files := \
   *.mkdir.done* \
   *.DS_Store* \
   *\#* \
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/adjust_sdk_app_token.in
@@ -0,0 +1,3 @@
+//#ifdef MOZ_INSTALL_TRACKING
+//#define MOZ_INSTALL_TRACKING_ADJUST_SDK_APP_TOKEN @MOZ_INSTALL_TRACKING_ADJUST_SDK_APP_TOKEN@
+//#endif
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -1,16 +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/.
 
 DIRS += ['locales']
 
+CONFIGURE_SUBST_FILES += ['adjust_sdk_app_token']
+
 include('android-services.mozbuild')
 
 thirdparty_source_dir = TOPSRCDIR + '/mobile/android/thirdparty/'
 
 constants_jar = add_java_jar('constants')
 constants_jar.sources = ['java/org/mozilla/gecko/' + x for x in [
     'adjust/AdjustHelperInterface.java',
     'annotation/JNITarget.java',
@@ -980,9 +982,10 @@ if CONFIG['MOZ_ANDROID_SEARCH_ACTIVITY']
         'gecko-browser.jar',
         'gecko-mozglue.jar',
         'gecko-thirdparty.jar',
         'gecko-util.jar'
     ]
 
 FINAL_TARGET_PP_FILES += ['package-name.txt.in']
 
+DEFINES['OBJDIR'] = OBJDIR
 DEFINES['TOPOBJDIR'] = TOPOBJDIR
--- a/mobile/android/components/HelperAppDialog.js
+++ b/mobile/android/components/HelperAppDialog.js
@@ -284,28 +284,28 @@ HelperAppLauncherDialog.prototype = {
           else
             aLocalFile.leafName = aLocalFile.leafName.replace(/(\.[^\.]*)?$/, "(2)$&");
         }
         else {
           // replace the last (n) in the filename with (n+1)
           aLocalFile.leafName = aLocalFile.leafName.replace(/^(.*\()\d+\)/, "$1" + (collisionCount+1) + ")");
         }
       }
-      aLocalFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
+      aLocalFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600);
     }
     catch (e) {
       dump("*** exception in validateLeafName: " + e + "\n");
 
       if (e.result == Cr.NS_ERROR_FILE_ACCESS_DENIED)
         throw e;
 
       if (aLocalFile.leafName == "" || aLocalFile.isDirectory()) {
         aLocalFile.append("unnamed");
         if (aLocalFile.exists())
-          aLocalFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
+          aLocalFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600);
       }
     }
   },
 
   isUsableDirectory: function hald_isUsableDirectory(aDirectory) {
     return aDirectory.exists() && aDirectory.isDirectory() && aDirectory.isWritable();
   },
 };
--- a/mobile/android/components/SessionStore.js
+++ b/mobile/android/components/SessionStore.js
@@ -676,17 +676,17 @@ SessionStore.prototype = {
     // Use async file writer and just return it's promise
     if (aAsync) {
       return OS.File.writeAtomic(aFile.path, aBuffer, { tmpPath: aFile.path + ".tmp" });
     }
 
     // Convert buffer to an encoded string and sync write to disk
     let bytes = String.fromCharCode.apply(null, new Uint16Array(aBuffer));
     let stream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
-    stream.init(aFile, 0x02 | 0x08 | 0x20, 0666, 0);
+    stream.init(aFile, 0x02 | 0x08 | 0x20, 0o666, 0);
     stream.write(bytes, bytes.length);
     stream.close();
 
     // Return a resolved promise to make the caller happy
     return Promise.resolve();
   },
 
   _updateCrashReportURL: function ss_updateCrashReportURL(aWindow) {
--- a/mobile/android/installer/package-manifest.in
+++ b/mobile/android/installer/package-manifest.in
@@ -1,8 +1,9 @@
+
 ; 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/.
 
 ; Package file for the Fennec build.
 ;
 ; File format:
 ;
@@ -223,19 +224,17 @@
 @BINPATH@/components/storage.xpt
 @BINPATH@/components/telemetry.xpt
 @BINPATH@/components/toolkit_asyncshutdown.xpt
 @BINPATH@/components/toolkit_filewatcher.xpt
 @BINPATH@/components/toolkit_finalizationwitness.xpt
 @BINPATH@/components/toolkit_formautofill.xpt
 @BINPATH@/components/toolkit_osfile.xpt
 @BINPATH@/components/toolkit_securityreporter.xpt
-#ifdef NIGHTLY_BUILD
 @BINPATH@/components/toolkit_perfmonitoring.xpt
-#endif
 @BINPATH@/components/toolkit_xulstore.xpt
 @BINPATH@/components/toolkitprofile.xpt
 #ifdef MOZ_ENABLE_XREMOTE
 @BINPATH@/components/toolkitremote.xpt
 #endif
 @BINPATH@/components/txtsvc.xpt
 @BINPATH@/components/txmgr.xpt
 @BINPATH@/components/uconv.xpt
--- a/modules/libjar/test/unit/test_umlaute.js
+++ b/modules/libjar/test/unit/test_umlaute.js
@@ -22,17 +22,17 @@ function run_test() {
 
   var entryName = entries.getNext();
   do_check_eq(entryName, "test_\u00FC.txt");
 
   do_check_true(zipreader.hasEntry(entryName));
 
   var target = tmpDir.clone();
   target.append(entryName);
-  target.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, 6 * 64 + 4 * 8 + 0); // 0640
+  target.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, 0o640); // 0640
 
   zipreader.extract(entryName, target);
 
   var entry = zipreader.getEntry(entryName);
   do_check_true(entry != null);
 
   zipreader.test(entryName);
 
--- a/modules/libjar/zipwriter/test/unit/test_zippermissions.js
+++ b/modules/libjar/zipwriter/test/unit/test_zippermissions.js
@@ -27,17 +27,17 @@ function build_tests() {
 function run_test() {
   build_tests();
 
   var foStream = Cc["@mozilla.org/network/file-output-stream;1"].
                  createInstance(Ci.nsIFileOutputStream);
 
   var tmp = tmpDir.clone();
   tmp.append("temp-permissions");
-  tmp.createUnique(Ci.nsILocalFile.DIRECTORY_TYPE, 0755);
+  tmp.createUnique(Ci.nsILocalFile.DIRECTORY_TYPE, 0o755);
 
   var file = tmp.clone();
   file.append("tempfile");
 
   zipW.open(tmpFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE);
   for (let i = 0; i < TESTS.length; i++) {
     // Open the file with the permissions to match how the zipreader extracts
     // This obeys the umask
--- a/modules/libmar/tests/unit/head_libmar.js
+++ b/modules/libmar/tests/unit/head_libmar.js
@@ -97,23 +97,23 @@ function createMAR(outMAR, dataDir, file
   let signmarBin = do_get_file("signmar" + BIN_SUFFIX);
 
   // Make sure the signmar binary exists and is an executable.
   do_check_true(signmarBin.exists());
   do_check_true(signmarBin.isExecutable());
 
   // Ensure on non Windows platforms we encode the same permissions
   // as the refernence MARs contain.  On Windows this is also safe.
-  // The reference MAR files have permissions of 0664, so in case
+  // The reference MAR files have permissions of 0o664, so in case
   // someone is running these tests locally with another permission
-  // (perhaps 0777), make sure that we encode them as 0664.
+  // (perhaps 0o777), make sure that we encode them as 0o664.
   for (filePath of files) {
     let f = dataDir.clone();
     f.append(filePath);
-    f.permissions = 0664;
+    f.permissions = 0o664;
   }
 
   // Setup the command line arguments to create the MAR.
   let args = ["-C", dataDir.path, "-H", "\@MAR_CHANNEL_ID\@", 
               "-V", "13.0a1", "-c", outMAR.path];
   args = args.concat(files);
 
   do_print('Running: ' + signmarBin.path);
--- a/modules/libmar/tests/unit/test_extract.js
+++ b/modules/libmar/tests/unit/test_extract.js
@@ -12,17 +12,17 @@ function run_test() {
   function run_one_test(marFileName, files) { 
     // Get the MAR file that we will be extracting
     let mar = do_get_file("data/" + marFileName);
 
     // Get the path that we will extract to
     let outDir = tempDir.clone();
     outDir.append("out");
     do_check_false(outDir.exists());
-    outDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0777);
+    outDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o777);
 
     // Get the ref files and the files that will be extracted.
     let outFiles = [];
     let refFiles = [];
     for (let i = 0; i < files.length; i++) {
       let outFile = outDir.clone();
       outFile.append(files[i]);
       do_check_false(outFile.exists());
--- a/modules/libpref/test/unit/test_libPrefs.js
+++ b/modules/libpref/test/unit/test_libPrefs.js
@@ -306,17 +306,17 @@ function run_test() {
   ps.setCharPref("ReadPref.char", "hello");
 
   // save those prefs in a file
   let savePrefFile = do_get_cwd();
   savePrefFile.append("data");
   savePrefFile.append("savePref.js");
   if (savePrefFile.exists())
     savePrefFile.remove(false);
-  savePrefFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  savePrefFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
   ps.savePrefFile(savePrefFile);
   ps.resetPrefs();
 
   // load a preexisting pref file
   let prefFile = do_get_file("data/testPref.js");
   ps.readUserPrefs(prefFile);
 
   // former prefs should have been replaced/lost
--- a/netwerk/cache2/CacheObserver.cpp
+++ b/netwerk/cache2/CacheObserver.cpp
@@ -498,37 +498,33 @@ CacheObserver::Observe(nsISupports* aSub
   }
 
   if (!strcmp(aTopic, "browser-delayed-startup-finished")) {
     uint32_t activeVersion = UseNewCache() ? 1 : 0;
     CacheStorageService::CleaupCacheDirectories(sAutoDeleteCacheVersion, activeVersion);
     return NS_OK;
   }
 
-  if (!strcmp(aTopic, "profile-before-change")) {
+  if (!strcmp(aTopic, "profile-change-net-teardown") ||
+      !strcmp(aTopic, "profile-before-change") ||
+      !strcmp(aTopic, "xpcom-shutdown")) {
     RefPtr<CacheStorageService> service = CacheStorageService::Self();
-    if (service)
+    if (service) {
       service->Shutdown();
-
-    return NS_OK;
-  }
-
-  if (!strcmp(aTopic, "xpcom-shutdown")) {
-    RefPtr<CacheStorageService> service = CacheStorageService::Self();
-    if (service)
-      service->Shutdown();
+    }
 
     CacheFileIOManager::Shutdown();
     return NS_OK;
   }
 
   if (!strcmp(aTopic, "last-pb-context-exited")) {
     RefPtr<CacheStorageService> service = CacheStorageService::Self();
-    if (service)
+    if (service) {
       service->DropPrivateBrowsingEntries();
+    }
 
     return NS_OK;
   }
 
   if (!strcmp(aTopic, "clear-origin-data")) {
     NeckoOriginAttributes oa;
     if (!oa.Init(nsDependentString(aData))) {
       NS_ERROR("Could not parse NeckoOriginAttributes JSON in clear-origin-data notification");
--- a/netwerk/protocol/websocket/WebSocketChannel.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannel.cpp
@@ -2992,39 +2992,18 @@ WebSocketChannel::AsyncOnChannelRedirect
   bool newuriIsHttps = false;
   rv = newuri->SchemeIs("https", &newuriIsHttps);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!mAutoFollowRedirects) {
     // Even if redirects configured off, still allow them for HTTP Strict
     // Transport Security (from ws://FOO to https://FOO (mapped to wss://FOO)
 
-    nsCOMPtr<nsIURI> clonedNewURI;
-    rv = newuri->Clone(getter_AddRefs(clonedNewURI));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = clonedNewURI->SetScheme(NS_LITERAL_CSTRING("ws"));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    nsCOMPtr<nsIURI> currentURI;
-    rv = GetURI(getter_AddRefs(currentURI));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // currentURI is expected to be ws or wss
-    bool currentIsHttps = false;
-    rv = currentURI->SchemeIs("wss", &currentIsHttps);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    bool uriEqual = false;
-    rv = clonedNewURI->Equals(currentURI, &uriEqual);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // It's only a HSTS redirect if we started with non-secure, are going to
-    // secure, and the new URI is otherwise the same as the old one.
-    if (!(!currentIsHttps && newuriIsHttps && uriEqual)) {
+    if (!(flags & (nsIChannelEventSink::REDIRECT_INTERNAL |
+                   nsIChannelEventSink::REDIRECT_STS_UPGRADE))) {
       nsAutoCString newSpec;
       rv = newuri->GetSpec(newSpec);
       NS_ENSURE_SUCCESS(rv, rv);
 
       LOG(("WebSocketChannel: Redirect to %s denied by configuration\n",
            newSpec.get()));
       return NS_ERROR_FAILURE;
     }
--- a/netwerk/test/httpserver/test/head_utils.js
+++ b/netwerk/test/httpserver/test/head_utils.js
@@ -54,17 +54,17 @@ function makeBIS(stream)
  * @param file : nsILocalFile
  *   the file whose contents are to be read
  * @returns string
  *   the contents of the file
  */
 function fileContents(file)
 {
   const PR_RDONLY = 0x01;
-  var fis = new FileInputStream(file, PR_RDONLY, 0444,
+  var fis = new FileInputStream(file, PR_RDONLY, 0o444,
                                 Ci.nsIFileInputStream.CLOSE_ON_EOF);
   var sis = new ScriptableInputStream(fis);
   var contents = sis.read(file.fileSize);
   sis.close();
   return contents;
 }
 
 /**
--- a/netwerk/test/httpserver/test/test_default_index_handler.js
+++ b/netwerk/test/httpserver/test/test_default_index_handler.js
@@ -37,17 +37,17 @@ function run_test()
 }
 
 function createTestDirectory()
 {
   dir = Cc["@mozilla.org/file/directory_service;1"]
           .getService(Ci.nsIProperties)
           .get("TmpD", Ci.nsIFile);
   dir.append("index_handler_test_" + Math.random());
-  dir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0744);
+  dir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0o744);
 
   // populate with test directories, files, etc.
   // Files must be in expected order of display on the index page!
 
   var files = [];
 
   makeFile("aa_directory", true, dir, files);
   makeFile("Ba_directory", true, dir, files);
@@ -244,17 +244,17 @@ function dataCheck(bytes, uri, path, dir
 function makeFile(name, isDirectory, parentDir, lst)
 {
   var type = Ci.nsIFile[isDirectory ? "DIRECTORY_TYPE" : "NORMAL_FILE_TYPE"];
   var file = parentDir.clone();
 
   try
   {
     file.append(name);
-    file.create(type, 0755);
+    file.create(type, 0o755);
     lst.push({name: name, isDirectory: isDirectory});
   }
   catch (e) { /* OS probably doesn't like file name, skip */ }
 }
 
 /*********
  * TESTS *
  *********/
--- a/netwerk/test/unit/test_NetUtil.js
+++ b/netwerk/test/unit/test_NetUtil.js
@@ -63,17 +63,17 @@ function async_write_file(aContractId, a
 {
   do_test_pending();
 
   // First, we need an output file to write to.
   let file = Cc["@mozilla.org/file/directory_service;1"].
              getService(Ci.nsIProperties).
              get("ProfD", Ci.nsIFile);
   file.append("NetUtil-async-test-file.tmp");
-  file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
   // Then, we need an output stream to our output file.
   let ostream = Cc[aContractId].createInstance(Ci.nsIFileOutputStream);
   ostream.init(file, -1, -1, aDeferOpen ? Ci.nsIFileOutputStream.DEFER_OPEN : 0);
 
   // Finally, we need an input stream to take data from.
   const TEST_DATA = "this is a test string";
   let istream = Cc["@mozilla.org/io/string-input-stream;1"].
@@ -118,17 +118,17 @@ function test_async_copy()
       return istream;
     }
 
     // File input streams are not buffered, so let's create a file
     let file = Cc["@mozilla.org/file/directory_service;1"].
       getService(Ci.nsIProperties).
       get("ProfD", Ci.nsIFile);
     file.append("NetUtil-asyncFetch-test-file.tmp");
-    file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+    file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
     let ostream = Cc["@mozilla.org/network/file-output-stream;1"].
       createInstance(Ci.nsIFileOutputStream);
     ostream.init(file, -1, -1, 0);
     ostream.write(data, data.length);
     ostream.close();
 
     let istream = Cc["@mozilla.org/network/file-input-stream;1"].
@@ -139,17 +139,17 @@ function test_async_copy()
   }
 
   // Create an output buffer holding some data
   function make_output(isBuffered) {
     let file = Cc["@mozilla.org/file/directory_service;1"].
       getService(Ci.nsIProperties).
       get("ProfD", Ci.nsIFile);
     file.append("NetUtil-asyncFetch-test-file.tmp");
-    file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+    file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
     let ostream = Cc["@mozilla.org/network/file-output-stream;1"].
       createInstance(Ci.nsIFileOutputStream);
     ostream.init(file, -1, -1, 0);
 
     if (!isBuffered) {
       return {file: file, sink: ostream};
     }
@@ -404,17 +404,17 @@ function test_asyncFetch_with_nsIFile()
 {
   const TEST_DATA = "this is a test string";
 
   // First we need a file to read from.
   let file = Cc["@mozilla.org/file/directory_service;1"].
              getService(Ci.nsIProperties).
              get("ProfD", Ci.nsIFile);
   file.append("NetUtil-asyncFetch-test-file.tmp");
-  file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
   // Write the test data to the file.
   let ostream = Cc["@mozilla.org/network/file-output-stream;1"].
                 createInstance(Ci.nsIFileOutputStream);
   ostream.init(file, -1, -1, 0);
   ostream.write(TEST_DATA, TEST_DATA.length);
 
   // Sanity check to make sure the data was written.
--- a/netwerk/test/unit/test_bug414122.js
+++ b/netwerk/test/unit/test_bug414122.js
@@ -5,17 +5,17 @@ var etld = Cc["@mozilla.org/network/effe
 var idn = Cc["@mozilla.org/network/idn-service;1"]
              .getService(Ci.nsIIDNService);
 
 function run_test()
 {
   var fis = Cc["@mozilla.org/network/file-input-stream;1"]
               .createInstance(Ci.nsIFileInputStream);
   fis.init(do_get_file("effective_tld_names.dat"),
-           PR_RDONLY, 0444, Ci.nsIFileInputStream.CLOSE_ON_EOF);
+           PR_RDONLY, 0o444, Ci.nsIFileInputStream.CLOSE_ON_EOF);
 
   var lis = Cc["@mozilla.org/intl/converter-input-stream;1"]
               .createInstance(Ci.nsIConverterInputStream);
   lis.init(fis, "UTF-8", 1024, 0);
   lis.QueryInterface(Ci.nsIUnicharLineInputStream);
 
   var out = { value: "" };
   do
--- a/netwerk/test/unit/test_file_partial_inputstream.js
+++ b/netwerk/test/unit/test_file_partial_inputstream.js
@@ -113,17 +113,17 @@ function run_test()
   tempInputStream = new_partial_file_input_stream(tempFile, 5, 10,
                                                   Ci.nsIFileInputStream.CLOSE_ON_EOF |
                                                   Ci.nsIFileInputStream.REOPEN_ON_REWIND);
   tempInputStream.QueryInterface(Ci.nsILineInputStream);
   do_check_eq(read_line_stream(tempInputStream)[1], "5678901234");
   let ostream = Cc["@mozilla.org/network/file-output-stream;1"].
                 createInstance(Ci.nsIFileOutputStream);
   ostream.init(tempFile, 0x02 | 0x08 | 0x20, // write, create, truncate
-               0666, 0);
+               0o666, 0);
   let newData = "abcdefghijklmnopqrstuvwxyz";
   ostream.write(newData, newData.length);
   ostream.close();
   tempInputStream.QueryInterface(Ci.nsISeekableStream);
   tempInputStream.seek(SET, 1);
   do_check_eq(read_line_stream(tempInputStream)[1], newData.substr(6,9));
 
   // Test auto-delete and auto-close together
@@ -494,19 +494,19 @@ function new_partial_file_input_stream(f
   return stream.QueryInterface(Ci.nsIInputStream);
 }
 
 function create_temp_file(data) {
   let file = Cc["@mozilla.org/file/directory_service;1"].
              getService(Ci.nsIProperties).
              get("ProfD", Ci.nsIFile);
   file.append("fileinputstream-test-file.tmp");
-  file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
   let ostream = Cc["@mozilla.org/network/file-output-stream;1"].
                 createInstance(Ci.nsIFileOutputStream);
   ostream.init(file, 0x02 | 0x08 | 0x20, // write, create, truncate
-               0666, 0);
+               0o666, 0);
   do_check_eq(ostream.write(data, data.length), data.length);
   ostream.close();
 
   return file;
 }
--- a/netwerk/test/unit/test_file_protocol.js
+++ b/netwerk/test/unit/test_file_protocol.js
@@ -175,17 +175,17 @@ function test_read_dir_2() {
 }
 
 function test_upload_file() {
   dump("*** test_upload_file\n");
 
   var file = do_get_file("../unit/data/test_readline6.txt"); // file to upload
   var dest = do_get_tempdir();      // file upload destination
   dest.append("junk.dat");
-  dest.createUnique(dest.NORMAL_FILE_TYPE, 0600);
+  dest.createUnique(dest.NORMAL_FILE_TYPE, 0o600);
 
   var uploadstream = new_file_input_stream(file, true);
 
   var chan = new_file_channel(dest);
   chan.QueryInterface(Ci.nsIUploadChannel);
   chan.setUploadStream(uploadstream, "", file.fileSize);
 
   function on_upload_complete(data) {
--- a/netwerk/test/unit/test_filestreams.js
+++ b/netwerk/test/unit/test_filestreams.js
@@ -123,17 +123,17 @@ function sync_operations(aDeferOpen)
 {
   const TEST_DATA = "this is a test string";
   const LEAF_NAME = "filestreams-test-file.tmp";
 
   let file = Cc["@mozilla.org/file/directory_service;1"].
              getService(Ci.nsIProperties).
              get("ProfD", Ci.nsIFile);
   file.append(LEAF_NAME);
-  file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
   let ostream = Cc[OUTPUT_STREAM_CONTRACT_ID].
                 createInstance(Ci.nsIFileOutputStream);
   ostream.init(file, -1, -1, aDeferOpen ? Ci.nsIFileOutputStream.DEFER_OPEN : 0);
 
   ostream.write(TEST_DATA, TEST_DATA.length);
   ostream.close();
 
@@ -210,17 +210,17 @@ function do_test_zero_size_buffered(disa
 {
   const LEAF_NAME = "filestreams-test-file.tmp";
   const BUFFERSIZE = 4096;
 
   let file = Cc["@mozilla.org/file/directory_service;1"].
              getService(Ci.nsIProperties).
              get("ProfD", Ci.nsIFile);
   file.append(LEAF_NAME);
-  file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
   let fstream = Cc["@mozilla.org/network/file-input-stream;1"].
                 createInstance(Ci.nsIFileInputStream);
   fstream.init(file, -1, 0,
                Ci.nsIFileInputStream.CLOSE_ON_EOF |
                Ci.nsIFileInputStream.REOPEN_ON_REWIND);
 
   var buffered = Cc["@mozilla.org/network/buffered-input-stream;1"].
--- a/security/manager/pki/resources/content/pippki.js
+++ b/security/manager/pki/resources/content/pippki.js
@@ -129,17 +129,17 @@ function exportToFile(parent, cert)
   var written = 0;
   try {
     var file = Components.classes["@mozilla.org/file/local;1"].
                createInstance(Components.interfaces.nsILocalFile);
     file.initWithPath(fp.file.path);
     var fos = Components.classes["@mozilla.org/network/file-output-stream;1"].
               createInstance(Components.interfaces.nsIFileOutputStream);
     // flags: PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE
-    fos.init(file, 0x02 | 0x08 | 0x20, 00644, 0);
+    fos.init(file, 0x02 | 0x08 | 0x20, 0o0644, 0);
     written = fos.write(content, content.length);
     fos.close();
   }
   catch(e) {
     switch (e.result) {
       case Components.results.NS_ERROR_FILE_ACCESS_DENIED:
         msg = bundle.getString("writeFileAccessDenied");
         break;
--- a/security/manager/ssl/tests/unit/test_sss_readstate_empty.js
+++ b/security/manager/ssl/tests/unit/test_sss_readstate_empty.js
@@ -23,17 +23,17 @@ function checkStateRead(aSubject, aTopic
 
 function run_test() {
   let profileDir = do_get_profile();
   let stateFile = profileDir.clone();
   stateFile.append(SSS_STATE_FILE_NAME);
   // Assuming we're working with a clean slate, the file shouldn't exist
   // until we create it.
   ok(!stateFile.exists());
-  stateFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0x1a4); // 0x1a4 == 0644
+  stateFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0x1a4); // 0x1a4 == 0o644
   ok(stateFile.exists());
   // Initialize nsISiteSecurityService after do_get_profile() so it
   // can read the state file.
   Services.obs.addObserver(checkStateRead, "data-storage-ready", false);
   do_test_pending();
   gSSService = Cc["@mozilla.org/ssservice;1"]
                  .getService(Ci.nsISiteSecurityService);
   notEqual(gSSService, null);
--- a/security/manager/tools/makeCNNICHashes.js
+++ b/security/manager/tools/makeCNNICHashes.js
@@ -247,15 +247,15 @@ for (let cert of invalidCerts) {
 }
 
 // Sort the key hashes to allow for binary search.
 certs.sort(compareCertificatesByHash);
 
 // Write the output file.
 var outFile = relativePathToFile("CNNICHashWhitelist.inc");
 if (!outFile.exists()) {
-  outFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0644);
+  outFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o644);
 }
 var outStream = Cc["@mozilla.org/network/file-output-stream;1"]
                   .createInstance(Ci.nsIFileOutputStream);
 outStream.init(outFile, -1, 0, 0);
 writeHashes(certs, lastValidTime, outStream);
 outStream.close();
--- a/services/sync/tests/unit/test_bookmark_engine.js
+++ b/services/sync/tests/unit/test_bookmark_engine.js
@@ -199,17 +199,17 @@ add_task(function* test_restorePromptsRe
       .getService(Ci.nsIProperties);
 
     let backupFile = dirSvc.get("TmpD", Ci.nsILocalFile);
 
     _("Make a backup.");
     backupFile.append("t_b_e_" + Date.now() + ".json");
 
     _("Backing up to file " + backupFile.path);
-    backupFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, 0600);
+    backupFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, 0o600);
     yield BookmarkJSONUtils.exportToFile(backupFile);
 
     _("Create a different record and sync.");
     let bmk2_id = PlacesUtils.bookmarks.insertBookmark(
       folder1_id, tburi, PlacesUtils.bookmarks.DEFAULT_INDEX, "Get Thunderbird!");
     let bmk2_guid = store.GUIDForId(bmk2_id);
     _("Get Thunderbird!: " + bmk2_id + ", " + bmk2_guid);
 
--- a/testing/talos/talos/pageloader/chrome/MozillaFileLogger.js
+++ b/testing/talos/talos/pageloader/chrome/MozillaFileLogger.js
@@ -47,17 +47,17 @@ const PR_EXCL         = 0x80;
 var MozillaFileLogger = {};
 
 
 MozillaFileLogger.init = function(path) {
   MozillaFileLogger._file = Cc[LF_CID].createInstance(Ci.nsILocalFile);
   MozillaFileLogger._file.initWithPath(path);
   MozillaFileLogger._foStream = Cc[FOSTREAM_CID].createInstance(Ci.nsIFileOutputStream);
   MozillaFileLogger._foStream.init(this._file, PR_WRITE_ONLY | PR_CREATE_FILE | PR_APPEND,
-                                   0664, 0);
+                                   0o664, 0);
 }
 
 MozillaFileLogger.getLogCallback = function() {
   return function (msg) {
     var data = msg.num + " " + msg.level + " " + msg.info.join(' ') + "\n";
     if (MozillaFileLogger._foStream)
       MozillaFileLogger._foStream.write(data, data.length);
 
--- a/testing/talos/talos/scripts/MozillaFileLogger.js
+++ b/testing/talos/talos/scripts/MozillaFileLogger.js
@@ -74,17 +74,17 @@ var MozFileLogger = {};
 
 MozFileLogger.init = function(path) {
   netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 
   MozFileLogger._file = Cc[LF_CID].createInstance(Ci.nsILocalFile);
   MozFileLogger._file.initWithPath(path);
   MozFileLogger._foStream = Cc[FOSTREAM_CID].createInstance(Ci.nsIFileOutputStream);
   MozFileLogger._foStream.init(this._file, PR_WRITE_ONLY | PR_CREATE_FILE | PR_APPEND,
-                                   0664, 0);
+                                   0o664, 0);
 }
 
 MozFileLogger.getLogCallback = function() {
   return function (msg) {
     netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 
     var data = msg.num + " " + msg.level + " " + msg.info.join(' ') + "\n";
     if (MozFileLogger._foStream)
--- a/testing/tools/fileid/win_fileid.cpp
+++ b/testing/tools/fileid/win_fileid.cpp
@@ -1,15 +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 <stdio.h>
 #include <stdint.h>
-#include <Windows.h>
+#include <windows.h>
 #include <dbghelp.h>
 
 const DWORD CV_SIGNATURE_RSDS = 0x53445352; // 'SDSR'
 
 struct CV_INFO_PDB70 {
   DWORD      CvSignature;
   GUID       Signature;
   DWORD      Age;
--- a/toolkit/components/jsdownloads/test/unit/test_PrivateTemp.js
+++ b/toolkit/components/jsdownloads/test/unit/test_PrivateTemp.js
@@ -14,11 +14,11 @@ add_task(function* test_private_temp() {
   let download = yield promiseStartExternalHelperAppServiceDownload(
                                                          httpUrl("empty.txt"));
 
   yield promiseDownloadStopped(download);
 
   var targetFile = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
   targetFile.initWithPath(download.target.path);
 
-  // 488 is the decimal value of 0700.
+  // 488 is the decimal value of 0o700.
   equal(targetFile.parent.permissions, 448);
 });
--- a/toolkit/components/moz.build
+++ b/toolkit/components/moz.build
@@ -7,16 +7,17 @@
 # These component dirs are built for all apps (including suite)
 if CONFIG['MOZ_ENABLE_XREMOTE']:
     DIRS += ['remote']
 
 DIRS += [
     'aboutcache',
     'aboutcheckerboard',
     'aboutmemory',
+    'aboutperformance',
     'addoncompat',
     'alerts',
     'apppicker',
     'asyncshutdown',
     'commandlines',
     'console',
     'contentprefs',
     'cookie',
@@ -34,16 +35,17 @@ DIRS += [
     'jsdownloads',
     'lz4',
     'mediasniffer',
     'microformats',
     'osfile',
     'parentalcontrols',
     'passwordmgr',
     'perf',
+    'perfmonitoring',
     'places',
     'privatebrowsing',
     'processsingleton',
     'promiseworker',
     'prompts',
     'protobuf',
     'reader',
     'remotebrowserutils',
@@ -93,21 +95,15 @@ if CONFIG['MOZ_TOOLKIT_SEARCH']:
 if CONFIG['MOZ_URL_CLASSIFIER']:
     DIRS += ['url-classifier']
 
 DIRS += ['captivedetect']
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] != "gonk" and CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android':
     DIRS += ['terminator']
 
-if CONFIG['NIGHTLY_BUILD']: # Bug 1136927 - Performance Monitoring is not ready for prime-time yet
-    DIRS += [
-      'aboutperformance',
-      'perfmonitoring',
-    ]
-
 DIRS += ['build']
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android':
     EXTRA_COMPONENTS += [
         'nsDefaultCLH.js',
         'nsDefaultCLH.manifest',
     ]
--- a/toolkit/components/osfile/tests/xpcshell/test_osfile_async_setPermissions.js
+++ b/toolkit/components/osfile/tests/xpcshell/test_osfile_async_setPermissions.js
@@ -9,17 +9,17 @@
  * (see bug 1001849)
  * These functions are currently Unix-specific.  The manifest skips
  * the test on Windows.
  */
 
 /**
  * Helper function for test logging: prints a POSIX file permission mode as an
  * octal number, with a leading '0' per C (not JS) convention.  When the
- * numeric value is 0777 or lower, it is padded on the left with zeroes to
+ * numeric value is 0o777 or lower, it is padded on the left with zeroes to
  * four digits wide.
  * Sample outputs:  0022, 0644, 04755.
  */
 function format_mode(mode) {
   if (mode <= 0o777) {
     return ("0000" + mode.toString(8)).slice(-4);
   } else {
     return "0" + mode.toString(8);
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -359,16 +359,24 @@
   "GC_SWEEP_MS": {
     "alert_emails": ["dev-telemetry-gc-alerts@mozilla.org"],
     "expires_in_version": "never",
     "kind": "exponential",
     "high": "10000",
     "n_buckets": 50,
     "description": "Time spent running JS GC sweep phase (ms)"
   },
+  "GC_COMPACT_MS": {
+    "alert_emails": ["dev-telemetry-gc-alerts@mozilla.org"],
+    "expires_in_version": "never",
+    "kind": "exponential",
+    "high": "10000",
+    "n_buckets": 50,
+    "description": "Time spent running JS GC compact phase (ms)"
+  },
   "GC_MARK_ROOTS_MS": {
     "alert_emails": ["dev-telemetry-gc-alerts@mozilla.org"],
     "expires_in_version": "never",
     "kind": "linear",
     "high": "200",
     "n_buckets": 50,
     "description": "Time spent marking GC roots (ms)"
   },
--- a/uriloader/exthandler/tests/unit/test_handlerService.js
+++ b/uriloader/exthandler/tests/unit/test_handlerService.js
@@ -63,17 +63,17 @@ function run_test() {
   // only that it has a path and exists.  Since we don't know any executable
   // that exists on all platforms (except possibly the application being
   // tested, but there doesn't seem to be a way to get a reference to that
   // from the directory service), we use the temporary directory itself.
   var executable = HandlerServiceTest._dirSvc.get("TmpD", Ci.nsIFile);
   // XXX We could, of course, create an actual executable in the directory:
   //executable.append("localhandler");
   //if (!executable.exists())
-  //  executable.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0755);
+  //  executable.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o755);
 
   var localHandler = {
     name: "Local Handler",
     executable: executable,
     interfaces: [Ci.nsIHandlerApp, Ci.nsILocalHandlerApp, Ci.nsISupports],
     QueryInterface: function(iid) {
       if (!this.interfaces.some( function(v) { return iid.equals(v) } ))
         throw Cr.NS_ERROR_NO_INTERFACE;
--- a/xpcom/ds/nsINIProcessor.js
+++ b/xpcom/ds/nsINIProcessor.js
@@ -139,17 +139,17 @@ INIProcessor.prototype = {
         }
 
         if (!aFile)
             aFile = this._iniFile;
 
         let safeStream = Cc["@mozilla.org/network/safe-file-output-stream;1"].
                          createInstance(Ci.nsIFileOutputStream);
         safeStream.init(aFile, MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE,
-                        0600, null);
+                        0o600, null);
 
         var outputStream = Cc["@mozilla.org/network/buffered-output-stream;1"].
                            createInstance(Ci.nsIBufferedOutputStream);
         outputStream.init(safeStream, 8192);
         outputStream.QueryInterface(Ci.nsISafeOutputStream); // for .finish()
 
         if (Ci.nsIINIParserWriter.WRITE_UTF16 == aFlags
          && 'nsIWindowsRegKey' in Ci) {
--- a/xpcom/tests/unit/test_bug364285-1.js
+++ b/xpcom/tests/unit/test_bug364285-1.js
@@ -17,21 +17,21 @@ function getTempDir()
 	.getService(Ci.nsIProperties);
     return dirService.get("TmpD", Ci.nsILocalFile);
 }
 
 function create_file(fileName)
 {
     var outFile = getTempDir();
     outFile.append(fileName);
-    outFile.createUnique(outFile.NORMAL_FILE_TYPE, 0600);
+    outFile.createUnique(outFile.NORMAL_FILE_TYPE, 0o600);
 
     var stream = Cc["@mozilla.org/network/file-output-stream;1"]
 	.createInstance(Ci.nsIFileOutputStream);
-    stream.init(outFile, 0x02 | 0x08 | 0x20, 0600, 0);
+    stream.init(outFile, 0x02 | 0x08 | 0x20, 0o600, 0);
     stream.write("foo", 3);
     stream.close();
 
     do_check_eq(outFile.leafName.substr(0, fileName.length), fileName);
 
     return outFile;
 }
 
--- a/xpcom/tests/unit/test_bug476919.js
+++ b/xpcom/tests/unit/test_bug476919.js
@@ -4,17 +4,17 @@ var Ci = Components.interfaces;
 function run_test() {
   // skip this test on Windows
   if (mozinfo.os != "win") {
     var testDir = __LOCATION__.parent;
     // create a test file, then symlink it, then check that we think it's a symlink
     var targetFile = testDir.clone();
     targetFile.append("target.txt");
     if (!targetFile.exists())
-      targetFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0644);
+      targetFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o644);
 
     var link = testDir.clone();
     link.append("link");
     if (link.exists())
       link.remove(false);
 
     var ln = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
     ln.initWithPath("/bin/ln");
--- a/xpcom/tests/unit/test_file_createUnique.js
+++ b/xpcom/tests/unit/test_file_createUnique.js
@@ -14,16 +14,16 @@ function run_test()
 
   // Generate the path for a file located in a directory with a long name.
   var tempFile = Cc["@mozilla.org/file/directory_service;1"].
                  getService(Ci.nsIProperties).get("TmpD", Ci.nsIFile);
   tempFile.append(longLeafName);
   tempFile.append("test.txt");
 
   try {
-    tempFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
+    tempFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600);
     do_throw("Creating an item in a folder with a very long name should throw");
   }
   catch (e if (e instanceof Ci.nsIException &&
                e.result == Cr.NS_ERROR_FILE_UNRECOGNIZED_PATH)) {
     // We expect the function not to crash but to raise this exception.
   }
 }
--- a/xpcom/tests/unit/test_hidden_files.js
+++ b/xpcom/tests/unit/test_hidden_files.js
@@ -8,17 +8,17 @@ var hiddenUnixFile;
 function createUNIXHiddenFile() {
   var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
   var tmpDir = dirSvc.get(NS_OS_TEMP_DIR, Ci.nsIFile);
   hiddenUnixFile = tmpDir.clone();
   hiddenUnixFile.append(".foo");
   // we don't care if this already exists because we don't care
   // about the file's contents (just the name)
   if (!hiddenUnixFile.exists())
-    hiddenUnixFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+    hiddenUnixFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
   return hiddenUnixFile.exists();
 }
 
 function run_test() {
   // Skip this test on Windows
   if (mozinfo.os == "win")
     return;
 
--- a/xpcom/tests/unit/test_localfile.js
+++ b/xpcom/tests/unit/test_localfile.js
@@ -63,17 +63,17 @@ function test_file_modification_time()
   var file = do_get_profile();
   file.append("testfile");
 
   // Should never happen but get rid of it anyway
   if (file.exists())
     file.remove(true);
 
   var now = Date.now();
-  file.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0644);
+  file.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o644);
   do_check_true(file.exists());
 
   // Modification time may be out by up to 2 seconds on FAT filesystems. Test
   // with a bit of leeway, close enough probably means it is correct.
   var diff = Math.abs(file.lastModifiedTime - now);
   do_check_true(diff < MAX_TIME_DIFFERENCE);
 
   var yesterday = now - MILLIS_PER_DAY;
@@ -103,17 +103,17 @@ function test_directory_modification_tim
   var dir = do_get_profile();
   dir.append("testdir");
 
   // Should never happen but get rid of it anyway
   if (dir.exists())
     dir.remove(true);
 
   var now = Date.now();
-  dir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
+  dir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
   do_check_true(dir.exists());
 
   // Modification time may be out by up to 2 seconds on FAT filesystems. Test
   // with a bit of leeway, close enough probably means it is correct.
   var diff = Math.abs(dir.lastModifiedTime - now);
   do_check_true(diff < MAX_TIME_DIFFERENCE);
 
   var yesterday = now - MILLIS_PER_DAY;
@@ -137,15 +137,15 @@ function test_diskSpaceAvailable()
   file.QueryInterface(Ci.nsILocalFile);
 
   let bytes = file.diskSpaceAvailable;
   do_check_true(bytes > 0);
 
   file.append("testfile");
   if (file.exists())
     file.remove(true);
-  file.create(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt("644", 8));
+  file.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o644);
 
   bytes = file.diskSpaceAvailable;
   do_check_true(bytes > 0);
 
   file.remove(true);
 }
--- a/xpcom/tests/unit/test_symlinks.js
+++ b/xpcom/tests/unit/test_symlinks.js
@@ -64,23 +64,23 @@ function setupTestDir(testDir, relative)
   var targetDir = testDir.clone();
   targetDir.append(DIR_TARGET);
 
   if (testDir.exists()) {
     testDir.remove(true);
   }
   do_check_true(!testDir.exists());
 
-  testDir.create(nsIFile.DIRECTORY_TYPE, 0777);
+  testDir.create(nsIFile.DIRECTORY_TYPE, 0o777);
 
-  targetDir.create(nsIFile.DIRECTORY_TYPE, 0777);
+  targetDir.create(nsIFile.DIRECTORY_TYPE, 0o777);
 
   var targetFile = testDir.clone();
   targetFile.append(FILE_TARGET);
-  targetFile.create(nsIFile.NORMAL_FILE_TYPE, 0666);
+  targetFile.create(nsIFile.NORMAL_FILE_TYPE, 0o666);
 
   var imaginary = testDir.clone();
   imaginary.append(DOES_NOT_EXIST);
 
   var loop = testDir.clone();
   loop.append(LOOP_LINK);
 
   var dirLink  = makeSymLink(targetDir, DIR_LINK, relative);
--- a/xpcom/tests/unit/test_windows_shortcut.js
+++ b/xpcom/tests/unit/test_windows_shortcut.js
@@ -18,17 +18,17 @@ Cu.import("resource://gre/modules/Servic
 function run_test()
 {
   // This test makes sense only on Windows, so skip it on other platforms
   if ("nsILocalFileWin" in Ci
    && do_get_cwd() instanceof Ci.nsILocalFileWin) {
 
     let tempDir = Services.dirsvc.get("TmpD", Ci.nsILocalFile);
     tempDir.append("shortcutTesting");
-    tempDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0666);
+    tempDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0o666);
 
     test_create_noargs(tempDir);
     test_create_notarget(tempDir);
     test_create_targetonly(tempDir);
     test_create_normal(tempDir);
     test_create_unicode(tempDir);
 
     test_update_noargs(tempDir);
@@ -38,17 +38,17 @@ function run_test()
     test_update_unicode(tempDir);
   }
 }
 
 function test_create_noargs(tempDir)
 {
   let shortcutFile = tempDir.clone();
   shortcutFile.append("shouldNeverExist.lnk");
-  shortcutFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  shortcutFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
   let win = shortcutFile.QueryInterface(Ci.nsILocalFileWin);
 
   try
   {
     win.setShortcut();
     do_throw("Creating a shortcut with no args (no target) should throw");
   }
@@ -58,17 +58,17 @@ function test_create_noargs(tempDir)
 
   }
 }
 
 function test_create_notarget(tempDir)
 {
   let shortcutFile = tempDir.clone();
   shortcutFile.append("shouldNeverExist2.lnk");
-  shortcutFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  shortcutFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
   let win = shortcutFile.QueryInterface(Ci.nsILocalFileWin);
 
   try
   {
     win.setShortcut(null,
                     do_get_cwd(),
                     "arg1 arg2",
@@ -81,81 +81,81 @@ function test_create_notarget(tempDir)
 
   }
 }
 
 function test_create_targetonly(tempDir)
 {
   let shortcutFile = tempDir.clone();
   shortcutFile.append("createdShortcut.lnk");
-  shortcutFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  shortcutFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
   let targetFile = tempDir.clone();
   targetFile.append("shortcutTarget.exe");
-  targetFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  targetFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
   let win = shortcutFile.QueryInterface(Ci.nsILocalFileWin);
 
   win.setShortcut(targetFile);
 
   let shortcutTarget = LocalFile(shortcutFile.target);
   do_check_true(shortcutTarget.equals(targetFile));
 }
 
 function test_create_normal(tempDir)
 {
   let shortcutFile = tempDir.clone();
   shortcutFile.append("createdShortcut.lnk");
-  shortcutFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  shortcutFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
   let targetFile = tempDir.clone();
   targetFile.append("shortcutTarget.exe");
-  targetFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  targetFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
   let win = shortcutFile.QueryInterface(Ci.nsILocalFileWin);
 
   win.setShortcut(targetFile,
                   do_get_cwd(),
                   "arg1 arg2",
                   "Ordinary shortcut");
 
   let shortcutTarget = LocalFile(shortcutFile.target);
   do_check_true(shortcutTarget.equals(targetFile))
 }
 
 function test_create_unicode(tempDir)
 {
   let shortcutFile = tempDir.clone();
   shortcutFile.append("createdShortcut.lnk");
-  shortcutFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  shortcutFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
   let targetFile = tempDir.clone();
   targetFile.append("ṩhогТϾừ†Target.exe");
-  targetFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  targetFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
   let win = shortcutFile.QueryInterface(Ci.nsILocalFileWin);
 
   win.setShortcut(targetFile,
                   do_get_cwd(), // XXX: This should probably be a unicode dir
                   "ᾶṟǵ1 ᾶṟǵ2",
                   "ῧṋіḉѻₑ");
 
   let shortcutTarget = LocalFile(shortcutFile.target);
   do_check_true(shortcutTarget.equals(targetFile))
 }
 
 function test_update_noargs(tempDir)
 {
   let shortcutFile = tempDir.clone();
   shortcutFile.append("createdShortcut.lnk");
-  shortcutFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  shortcutFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
   let targetFile = tempDir.clone();
   targetFile.append("shortcutTarget.exe");
-  targetFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  targetFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
   let win = shortcutFile.QueryInterface(Ci.nsILocalFileWin);
 
   win.setShortcut(targetFile,
                   do_get_cwd(),
                   "arg1 arg2",
                   "A sample shortcut");
 
@@ -164,21 +164,21 @@ function test_update_noargs(tempDir)
   let shortcutTarget = LocalFile(shortcutFile.target);
   do_check_true(shortcutTarget.equals(targetFile))
 }
 
 function test_update_notarget(tempDir)
 {
   let shortcutFile = tempDir.clone();
   shortcutFile.append("createdShortcut.lnk");
-  shortcutFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  shortcutFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
   let targetFile = tempDir.clone();
   targetFile.append("shortcutTarget.exe");
-  targetFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  targetFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
   let win = shortcutFile.QueryInterface(Ci.nsILocalFileWin);
 
   win.setShortcut(targetFile,
                   do_get_cwd(),
                   "arg1 arg2",
                   "A sample shortcut");
 
@@ -190,89 +190,89 @@ function test_update_notarget(tempDir)
   let shortcutTarget = LocalFile(shortcutFile.target);
   do_check_true(shortcutTarget.equals(targetFile))
 }
 
 function test_update_targetonly(tempDir)
 {
   let shortcutFile = tempDir.clone();
   shortcutFile.append("createdShortcut.lnk");
-  shortcutFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  shortcutFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
   let targetFile = tempDir.clone();
   targetFile.append("shortcutTarget.exe");
-  targetFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  targetFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
   let win = shortcutFile.QueryInterface(Ci.nsILocalFileWin);
 
   win.setShortcut(targetFile,
                   do_get_cwd(),
                   "arg1 arg2",
                   "A sample shortcut");
 
   let newTargetFile = tempDir.clone();
   newTargetFile.append("shortcutTarget.exe");
-  shortcutFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  shortcutFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
   win.setShortcut(newTargetFile);
 
   let shortcutTarget = LocalFile(shortcutFile.target);
   do_check_true(shortcutTarget.equals(newTargetFile))
 }
 
 function test_update_normal(tempDir)
 {
   let shortcutFile = tempDir.clone();
   shortcutFile.append("createdShortcut.lnk");
-  shortcutFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  shortcutFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
   let targetFile = tempDir.clone();
   targetFile.append("shortcutTarget.exe");
-  targetFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  targetFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
   let win = shortcutFile.QueryInterface(Ci.nsILocalFileWin);
 
   win.setShortcut(targetFile,
                   do_get_cwd(),
                   "arg1 arg2",
                   "A sample shortcut");
 
   let newTargetFile = tempDir.clone();
   newTargetFile.append("shortcutTarget.exe");
-  newTargetFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  newTargetFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
   win.setShortcut(newTargetFile,
                   do_get_profile(),
                   "arg3 arg4",
                   "An UPDATED shortcut");
 
   let shortcutTarget = LocalFile(shortcutFile.target);
   do_check_true(shortcutTarget.equals(newTargetFile))
 }
 
 function test_update_unicode(tempDir)
 {
   let shortcutFile = tempDir.clone();
   shortcutFile.append("createdShortcut.lnk");
-  shortcutFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  shortcutFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
   let targetFile = tempDir.clone();
   targetFile.append("shortcutTarget.exe");
-  targetFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  targetFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
   let win = shortcutFile.QueryInterface(Ci.nsILocalFileWin);
 
   win.setShortcut(targetFile,
                   do_get_cwd(),
                   "arg1 arg2",
                   "A sample shortcut");
 
   let newTargetFile = tempDir.clone();
   newTargetFile.append("ṩhогТϾừ†Target.exe");
-  shortcutFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
+  shortcutFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
 
   win.setShortcut(newTargetFile,
                   do_get_profile(), // XXX: This should probably be unicode
                   "ᾶṟǵ3 ᾶṟǵ4",
                   "A ῧṋіḉѻₑ shortcut");
 
   let shortcutTarget = LocalFile(shortcutFile.target);
   do_check_true(shortcutTarget.equals(newTargetFile))