Merge mozilla-central to mozilla-inbound
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 27 Jul 2016 16:38:35 +0200
changeset 346923 950a962b75eae61cb9f0c5638b6b362427f7ebe6
parent 346922 4d7badaa705c87a15855a701663f07f9911f6186 (current diff)
parent 346871 fef429fba4c64c5b9c0c823a6ab713edbbcd4220 (diff)
child 346924 fc5b4f286716bf47199435415f945695c1c20d0b
push id6389
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:38:22 +0000
treeherdermozilla-beta@01d67bfe6c81 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone50.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to mozilla-inbound
build/autoconf/winsdk.m4
mobile/android/geckoview_library/.classpath
mobile/android/geckoview_library/.project
mobile/android/geckoview_library/AndroidManifest.xml.in
mobile/android/geckoview_library/Makefile.in
mobile/android/geckoview_library/build.xml
mobile/android/geckoview_library/geckolibs/AndroidManifest.xml
mobile/android/geckoview_library/geckolibs/classes.jar
mobile/android/geckoview_library/geckoview/AndroidManifest.xml
mobile/android/geckoview_library/local.properties.in
mobile/android/geckoview_library/moz.build
mobile/android/geckoview_library/project.properties.in
python/mozbuild/mozbuild/action/package_geckolibs_aar.py
--- a/.eslintignore
+++ b/.eslintignore
@@ -82,17 +82,20 @@ devtools/client/canvasdebugger/**
 devtools/client/commandline/**
 devtools/client/debugger/**
 devtools/client/eyedropper/**
 devtools/client/framework/**
 devtools/client/jsonview/lib/**
 devtools/client/memory/**
 devtools/client/netmonitor/test/**
 devtools/client/netmonitor/har/test/**
-devtools/client/performance/**
+devtools/client/performance/components/**
+devtools/client/performance/legacy/**
+devtools/client/performance/modules/**
+devtools/client/performance/test/**
 devtools/client/projecteditor/**
 devtools/client/promisedebugger/**
 devtools/client/responsivedesign/**
 devtools/client/scratchpad/**
 devtools/client/shadereditor/**
 devtools/client/shared/*.jsm
 devtools/client/shared/webgl-utils.js
 devtools/client/shared/developer-toolbar.js
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -19,17 +19,16 @@ builtin(include, build/autoconf/mozheade
 builtin(include, build/autoconf/lto.m4)dnl
 builtin(include, build/autoconf/frameptr.m4)dnl
 builtin(include, build/autoconf/compiler-opts.m4)dnl
 builtin(include, build/autoconf/expandlibs.m4)dnl
 builtin(include, build/autoconf/arch.m4)dnl
 builtin(include, build/autoconf/android.m4)dnl
 builtin(include, build/autoconf/zlib.m4)dnl
 builtin(include, build/autoconf/linux.m4)dnl
-builtin(include, build/autoconf/winsdk.m4)dnl
 builtin(include, build/autoconf/icu.m4)dnl
 builtin(include, build/autoconf/ffi.m4)dnl
 builtin(include, build/autoconf/clang-plugin.m4)dnl
 builtin(include, build/autoconf/alloc.m4)dnl
 builtin(include, build/autoconf/ios.m4)dnl
 builtin(include, build/autoconf/jemalloc.m4)dnl
 builtin(include, build/autoconf/sanitize.m4)dnl
 
--- a/b2g/config/aries/sources.xml
+++ b/b2g/config/aries/sources.xml
@@ -15,17 +15,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <remote fetch="git://github.com/mozilla/" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--
     B2G repositories for all targets
     -->
   <project name="gaia" path="gaia" remote="b2g" revision="99c01f5646b2d8aa5ebf1968114ab2f5db5ac6a8"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="1ec02eda4b375778b3611ebb7fb186faf5f75bb0"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="99003a6e7ecee880330a3fb8b5e49fefdb762374"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="34adfb400e031f3dd3353d92413572db5e3a7376"/>
   <project name="platform_system_libpdu" path="system/libpdu" remote="b2g" revision="f1a61fa8f97cc0a1ac4eca160acc222981b21d90"/>
   <project name="platform_system_sensorsd" path="system/sensorsd" remote="b2g" revision="3618678c472320de386f5ddc27897992d0e148a8"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="964d9fa4eabe9eb473ef9101ca2a690880f28547">
     <copyfile dest="Makefile" src="core/root.mk"/>
--- a/b2g/config/nexus-5-l/sources.xml
+++ b/b2g/config/nexus-5-l/sources.xml
@@ -15,17 +15,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <remote fetch="git://github.com/mozilla/" name="mozilla"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!--
     B2G repositories for all targets
     -->
   <project name="gaia" path="gaia" remote="b2g" revision="99c01f5646b2d8aa5ebf1968114ab2f5db5ac6a8"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="1ec02eda4b375778b3611ebb7fb186faf5f75bb0"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="99003a6e7ecee880330a3fb8b5e49fefdb762374"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="34adfb400e031f3dd3353d92413572db5e3a7376"/>
   <project name="platform_system_libpdu" path="system/libpdu" remote="b2g" revision="f1a61fa8f97cc0a1ac4eca160acc222981b21d90"/>
   <project name="platform_system_sensorsd" path="system/sensorsd" remote="b2g" revision="3618678c472320de386f5ddc27897992d0e148a8"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="aee7ff3dba262a037559d360b62af429b62cb876">
     <copyfile dest="Makefile" src="core/root.mk"/>
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1455,17 +1455,17 @@ pref("toolkit.pageThumbs.minHeight", 190
 
 // Enable speech synthesis
 pref("media.webspeech.synth.enabled", true);
 
 pref("browser.esedbreader.loglevel", "Error");
 
 pref("browser.laterrun.enabled", false);
 
-pref("browser.migration.automigrate", false);
+pref("browser.migrate.automigrate.enabled", false);
 
 // Enable browser frames for use on desktop.  Only exposed to chrome callers.
 pref("dom.mozBrowserFramesEnabled", true);
 
 pref("extensions.pocket.enabled", true);
 
 pref("signon.schemeUpgrades", true);
 
--- a/browser/base/content/aboutDialog-appUpdater.js
+++ b/browser/base/content/aboutDialog-appUpdater.js
@@ -21,38 +21,38 @@ function onUnload(aEvent) {
   // Safe to call even when there isn't a download in progress.
   gAppUpdater.removeDownloadListener();
   gAppUpdater = null;
 }
 
 
 function appUpdater()
 {
+  XPCOMUtils.defineLazyServiceGetter(this, "aus",
+                                     "@mozilla.org/updates/update-service;1",
+                                     "nsIApplicationUpdateService");
+  XPCOMUtils.defineLazyServiceGetter(this, "checker",
+                                     "@mozilla.org/updates/update-checker;1",
+                                     "nsIUpdateChecker");
+  XPCOMUtils.defineLazyServiceGetter(this, "um",
+                                     "@mozilla.org/updates/update-manager;1",
+                                     "nsIUpdateManager");
+
   this.updateDeck = document.getElementById("updateDeck");
 
   // Hide the update deck when the update window is already open and it's not
   // already applied, to avoid syncing issues between them. Applied updates
   // don't have any information to sync between the windows as they both just
   // show the "Restart to continue"-type button.
   if (Services.wm.getMostRecentWindow("Update:Wizard") &&
       !this.isApplied) {
     this.updateDeck.hidden = true;
     return;
   }
 
-  XPCOMUtils.defineLazyServiceGetter(this, "aus",
-                                     "@mozilla.org/updates/update-service;1",
-                                     "nsIApplicationUpdateService");
-  XPCOMUtils.defineLazyServiceGetter(this, "checker",
-                                     "@mozilla.org/updates/update-checker;1",
-                                     "nsIUpdateChecker");
-  XPCOMUtils.defineLazyServiceGetter(this, "um",
-                                     "@mozilla.org/updates/update-manager;1",
-                                     "nsIUpdateManager");
-
   this.bundle = Services.strings.
                 createBundle("chrome://browser/locale/browser.properties");
 
   let manualURL = Services.urlFormatter.formatURLPref("app.update.url.manual");
   let manualLink = document.getElementById("manualLink");
   manualLink.value = manualURL;
   manualLink.href = manualURL;
   document.getElementById("failedLink").href = manualURL;
--- a/browser/components/downloads/content/downloads.css
+++ b/browser/components/downloads/content/downloads.css
@@ -177,17 +177,16 @@ richlistitem.download button {
   display: none;
 }
 
 /* Make the panel wide enough to show the download list items without improperly
    truncating them. */
 #downloadsPanel-multiView > .panel-viewcontainer,
 #downloadsPanel-multiView > .panel-viewcontainer > .panel-viewstack,
 #downloadsPanel-multiView > .panel-viewcontainer > .panel-viewstack > .panel-mainview {
-  overflow: visible;
   max-width: unset;
 }
 
 /* Show the "show blocked info" button. */
 #downloadsPanel-mainView .download-state[state="8"] .downloadShowBlockedInfo {
   display: inline;
 }
 
--- a/browser/components/migration/AutoMigrate.jsm
+++ b/browser/components/migration/AutoMigrate.jsm
@@ -3,83 +3,129 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 this.EXPORTED_SYMBOLS = ["AutoMigrate"];
 
 const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
 
-const kAutoMigrateStartedPref = "browser.migrate.automigrate-started";
-const kAutoMigrateFinishedPref = "browser.migrate.automigrate-finished";
+const kAutoMigrateEnabledPref = "browser.migrate.automigrate.enabled";
+
+const kAutoMigrateStartedPref = "browser.migrate.automigrate.started";
+const kAutoMigrateFinishedPref = "browser.migrate.automigrate.finished";
+const kAutoMigrateBrowserPref = "browser.migrate.automigrate.browser";
+
+const kPasswordManagerTopic = "passwordmgr-storage-changed";
+const kPasswordManagerTopicTypes = new Set([
+  "addLogin",
+  "modifyLogin",
+]);
 
 Cu.import("resource:///modules/MigrationUtils.jsm");
+Cu.import("resource://gre/modules/Preferences.jsm");
 Cu.import("resource://gre/modules/PlacesUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 const AutoMigrate = {
   get resourceTypesToUse() {
     let {BOOKMARKS, HISTORY, PASSWORDS} = Ci.nsIBrowserProfileMigrator;
     return BOOKMARKS | HISTORY | PASSWORDS;
   },
 
+  init() {
+    this.enabled = Preferences.get(kAutoMigrateEnabledPref, false);
+    if (this.enabled) {
+      this.maybeInitUndoObserver();
+    }
+  },
+
+  maybeInitUndoObserver() {
+    // Check synchronously (NB: canUndo is async) if we really need
+    // to do this:
+    if (!this.getUndoRange()) {
+      return;
+    }
+    // Now register places and password observers:
+    this.onItemAdded = this.onItemMoved = this.onItemChanged =
+      this.removeUndoOption;
+    PlacesUtils.addLazyBookmarkObserver(this, true);
+    Services.obs.addObserver(this, kPasswordManagerTopic, true);
+  },
+
+  observe(subject, topic, data) {
+    // As soon as any login gets added or modified, disable undo:
+    // (Note that this ignores logins being removed as that doesn't
+    //  impair the 'undo' functionality of the import.)
+    if (kPasswordManagerTopicTypes.has(data)) {
+      this.removeUndoOption();
+    }
+  },
+
   /**
    * Automatically pick a migrator and resources to migrate,
    * then migrate those and start up.
    *
    * @throws if automatically deciding on migrators/data
    *         failed for some reason.
    */
   migrate(profileStartup, migratorKey, profileToMigrate) {
-    let histogram = Services.telemetry.getHistogramById("FX_STARTUP_MIGRATION_AUTOMATED_IMPORT_PROCESS_SUCCESS");
+    let histogram = Services.telemetry.getHistogramById(
+      "FX_STARTUP_MIGRATION_AUTOMATED_IMPORT_PROCESS_SUCCESS");
     histogram.add(0);
-    let migrator = this.pickMigrator(migratorKey);
+    let {migrator, pickedKey} = this.pickMigrator(migratorKey);
     histogram.add(5);
 
     profileToMigrate = this.pickProfile(migrator, profileToMigrate);
     histogram.add(10);
 
     let resourceTypes = migrator.getMigrateData(profileToMigrate, profileStartup);
     if (!(resourceTypes & this.resourceTypesToUse)) {
       throw new Error("No usable resources were found for the selected browser!");
     }
     histogram.add(15);
 
     let sawErrors = false;
-    let migrationObserver = function(subject, topic, data) {
+    let migrationObserver = (subject, topic, data) => {
       if (topic == "Migration:ItemError") {
         sawErrors = true;
       } else if (topic == "Migration:Ended") {
         histogram.add(25);
         if (sawErrors) {
           histogram.add(26);
         }
         Services.obs.removeObserver(migrationObserver, "Migration:Ended");
         Services.obs.removeObserver(migrationObserver, "Migration:ItemError");
         Services.prefs.setCharPref(kAutoMigrateStartedPref, startTime.toString());
         Services.prefs.setCharPref(kAutoMigrateFinishedPref, Date.now().toString());
+        Services.prefs.setCharPref(kAutoMigrateBrowserPref, pickedKey);
+        // Need to manually start listening to new bookmarks/logins being created,
+        // because, when we were initialized, there wasn't the possibility to
+        // 'undo' anything.
+        this.maybeInitUndoObserver();
       }
     };
 
     Services.obs.addObserver(migrationObserver, "Migration:Ended", false);
     Services.obs.addObserver(migrationObserver, "Migration:ItemError", false);
     // We'll save this when the migration has finished, at which point the pref
     // service will be available.
     let startTime = Date.now();
     migrator.migrate(this.resourceTypesToUse, profileStartup, profileToMigrate);
     histogram.add(20);
   },
 
   /**
    * Pick and return a migrator to use for automatically migrating.
    *
    * @param {String} migratorKey   optional, a migrator key to prefer/pick.
-   * @returns                      the migrator to use for migrating.
+   * @returns {Object}             an object with the migrator to use for migrating, as
+   *                               well as the key we eventually ended up using to obtain it.
    */
   pickMigrator(migratorKey) {
     if (!migratorKey) {
       let defaultKey = MigrationUtils.getMigratorKeyForDefaultBrowser();
       if (!defaultKey) {
         throw new Error("Could not determine default browser key to migrate from");
       }
       migratorKey = defaultKey;
@@ -87,17 +133,17 @@ const AutoMigrate = {
     if (migratorKey == "firefox") {
       throw new Error("Can't automatically migrate from Firefox.");
     }
 
     let migrator = MigrationUtils.getMigrator(migratorKey);
     if (!migrator) {
       throw new Error("Migrator specified or a default was found, but the migrator object is not available.");
     }
-    return migrator;
+    return {migrator, pickedKey: migratorKey};
   },
 
   /**
    * Pick a source profile (from the original browser) to use.
    *
    * @param {Migrator} migrator     the migrator object to use
    * @param {String}   suggestedId  the id of the profile to migrate, if pre-specified, or null
    * @returns                       the profile to migrate, or null if migrating
@@ -122,18 +168,18 @@ const AutoMigrate = {
       throw new Error("Don't know how to pick a profile when more than 1 profile is present.");
     }
     return profiles ? profiles[0] : null;
   },
 
   getUndoRange() {
     let start, finish;
     try {
-      start = parseInt(Services.prefs.getCharPref(kAutoMigrateStartedPref), 10);
-      finish = parseInt(Services.prefs.getCharPref(kAutoMigrateFinishedPref), 10);
+      start = parseInt(Preferences.get(kAutoMigrateStartedPref, "0"), 10);
+      finish = parseInt(Preferences.get(kAutoMigrateFinishedPref, "0"), 10);
     } catch (ex) {
       Cu.reportError(ex);
     }
     if (!finish || !start) {
       return null;
     }
     return [new Date(start), new Date(finish)];
   },
@@ -182,14 +228,32 @@ const AutoMigrate = {
     histogram.add(20);
 
     try {
       Services.logins.removeAllLogins();
     } catch (ex) {
       // ignore failure.
     }
     histogram.add(25);
-    Services.prefs.clearUserPref("browser.migrate.automigrate-started");
-    Services.prefs.clearUserPref("browser.migrate.automigrate-finished");
+    this.removeUndoOption();
     histogram.add(30);
   }),
+
+  removeUndoOption() {
+    // Remove observers, and ensure that exceptions doing so don't break
+    // removing the pref.
+    try {
+      Services.obs.removeObserver(this, kPasswordManagerTopic);
+    } catch (ex) {}
+    try {
+      PlacesUtils.removeLazyBookmarkObserver(this);
+    } catch (ex) {}
+    Services.prefs.clearUserPref(kAutoMigrateStartedPref);
+    Services.prefs.clearUserPref(kAutoMigrateFinishedPref);
+    Services.prefs.clearUserPref(kAutoMigrateBrowserPref);
+  },
+
+  QueryInterface: XPCOMUtils.generateQI(
+    [Ci.nsIObserver, Ci.nsINavBookmarkObserver, Ci.nsISupportsWeakReference]
+  ),
 };
 
+AutoMigrate.init();
--- a/browser/components/migration/MigrationUtils.jsm
+++ b/browser/components/migration/MigrationUtils.jsm
@@ -447,16 +447,46 @@ this.MigrationUtils = Object.freeze({
     aKey = OVERRIDES[aKey] || aKey;
 
     if (aReplacements === undefined)
       return getMigrationBundle().GetStringFromName(aKey);
     return getMigrationBundle().formatStringFromName(
       aKey, aReplacements, aReplacements.length);
   },
 
+  _getLocalePropertyForBrowser(browserId) {
+    switch (browserId) {
+      case "edge":
+        return "sourceNameEdge";
+      case "ie":
+        return "sourceNameIE";
+      case "safari":
+        return "sourceNameSafari";
+      case "canary":
+        return "sourceNameCanary";
+      case "chrome":
+        return "sourceNameChrome";
+      case "chromium":
+        return "sourceNameChromium";
+      case "firefox":
+        return "sourceNameFirefox";
+      case "360se":
+        return "sourceName360se";
+    }
+    return null;
+  },
+
+  getBrowserName(browserId) {
+    let prop = this._getLocalePropertyForBrowser(browserId);
+    if (prop) {
+      return this.getLocalizedString(prop);
+    }
+    return null;
+  },
+
   /**
    * Helper for creating a folder for imported bookmarks from a particular
    * migration source.  The folder is created at the end of the given folder.
    *
    * @param sourceNameStr
    *        the source name (first letter capitalized).  This is used
    *        for reading the localized source name from the migration
    *        bundle (e.g. if aSourceNameStr is Mosaic, this will try to read
@@ -711,18 +741,17 @@ this.MigrationUtils = Object.freeze({
         this.finishMigration();
         return;
       }
     }
 
     let isRefresh = migrator && skipSourcePage &&
                     migratorKey == AppConstants.MOZ_APP_NAME;
 
-    if (!isRefresh &&
-        Services.prefs.getBoolPref("browser.migration.automigrate")) {
+    if (!isRefresh && AutoMigrate.enabled) {
       try {
         AutoMigrate.migrate(aProfileStartup, aMigratorKey, aProfileToMigrate);
         return;
       } catch (ex) {
         // If automigration failed, continue and show the dialog.
         Cu.reportError(ex);
       }
     }
--- a/browser/components/migration/content/migration.js
+++ b/browser/components/migration/content/migration.js
@@ -309,48 +309,24 @@ var MigrationWizard = {
     document.getElementById("homePageImportDesc").setAttribute("value", pageDesc);
 
     this._wiz._adjustWizardHeader();
 
     var singleStart = document.getElementById("homePageSingleStart");
     singleStart.setAttribute("label", mainStr);
     singleStart.setAttribute("value", "DEFAULT");
 
-    var source = null;
-    switch (this._source) {
-      case "ie":
-        source = "sourceNameIE";
-        break;
-      case "safari":
-        source = "sourceNameSafari";
-        break;
-      case "canary":
-        source = "sourceNameCanary";
-        break;
-      case "chrome":
-        source = "sourceNameChrome";
-        break;
-      case "chromium":
-        source = "sourceNameChromium";
-        break;
-      case "firefox":
-        source = "sourceNameFirefox";
-        break;
-      case "360se":
-        source = "sourceName360se";
-        break;
-    }
+    var appName = MigrationUtils.getBrowserName(this._source);
 
     // semi-wallpaper for crash when multiple profiles exist, since we haven't initialized mSourceProfile in places
     this._migrator.getMigrateData(this._selectedProfile, this._autoMigrate);
 
     var oldHomePageURL = this._migrator.sourceHomePageURL;
 
-    if (oldHomePageURL && source) {
-      var appName = MigrationUtils.getLocalizedString(source);
+    if (oldHomePageURL && appName) {
       var oldHomePageLabel =
         brandBundle.getFormattedString("homePageImport", [appName]);
       var oldHomePage = document.getElementById("oldHomePage");
       oldHomePage.setAttribute("label", oldHomePageLabel);
       oldHomePage.setAttribute("value", oldHomePageURL);
       oldHomePage.removeAttribute("hidden");
     }
     else {
--- a/browser/components/migration/tests/unit/test_automigration.js
+++ b/browser/components/migration/tests/unit/test_automigration.js
@@ -1,10 +1,11 @@
 Cu.import("resource:///modules/MigrationUtils.jsm");
 Cu.import("resource://gre/modules/PlacesUtils.jsm");
+Cu.import("resource://gre/modules/Preferences.jsm");
 Cu.import("resource://testing-common/TestUtils.jsm");
 Cu.import("resource://testing-common/PlacesTestUtils.jsm");
 let AutoMigrateBackstage = Cu.import("resource:///modules/AutoMigrate.jsm");
 
 let gShimmedMigratorKeyPicker = null;
 let gShimmedMigrator = null;
 
 const kUsecPerMin = 60 * 1000000;
@@ -155,19 +156,19 @@ add_task(function* checkUndoPrecondition
                      "getMigrateData called with 'null' as a profile");
 
   let {BOOKMARKS, HISTORY, PASSWORDS} = Ci.nsIBrowserProfileMigrator;
   let expectedTypes = BOOKMARKS | HISTORY | PASSWORDS;
   Assert.deepEqual(gShimmedMigrator._migrateArgs, [expectedTypes, "startup", null],
                    "migrate called with 'null' as a profile");
 
   yield migrationFinishedPromise;
-  Assert.ok(Services.prefs.getPrefType("browser.migrate.automigrate-started"),
+  Assert.ok(Preferences.has("browser.migrate.automigrate.started"),
             "Should have set start time pref");
-  Assert.ok(Services.prefs.getPrefType("browser.migrate.automigrate-finished"),
+  Assert.ok(Preferences.has("browser.migrate.automigrate.finished"),
             "Should have set finish time pref");
   Assert.ok((yield AutoMigrate.canUndo()), "Should be able to undo migration");
 
   let [beginRange, endRange] = AutoMigrate.getUndoRange();
   let stringRange = `beginRange: ${beginRange}; endRange: ${endRange}`;
   Assert.ok(beginRange <= endRange,
             "Migration should have started before or when it ended " + stringRange);
 
@@ -175,17 +176,16 @@ add_task(function* checkUndoPrecondition
   Assert.ok(true, "Should be able to finish an undo cycle.");
 });
 
 /**
  * Fake a migration and then try to undo it to verify all data gets removed.
  */
 add_task(function* checkUndoRemoval() {
   let startTime = "" + Date.now();
-  Services.prefs.setCharPref("browser.migrate.automigrate-started", startTime);
 
   // Insert a login and check that that worked.
   let login = Cc["@mozilla.org/login-manager/loginInfo;1"].createInstance(Ci.nsILoginInfo);
   login.init("www.mozilla.org", "http://www.mozilla.org", null, "user", "pass", "userEl", "passEl");
   Services.logins.addLogin(login);
   let storedLogins = Services.logins.findLogins({}, "www.mozilla.org",
                                                 "http://www.mozilla.org", null);
   Assert.equal(storedLogins.length, 1, "Should have 1 login");
@@ -217,17 +217,18 @@ add_task(function* checkUndoRemoval() {
   let visits = PlacesUtils.history.executeQuery(query, opts);
   visits.root.containerOpen = true;
   Assert.equal(visits.root.childCount, 2, "Should have 2 visits");
   // Clean up:
   visits.root.containerOpen = false;
 
   // Now set finished pref:
   let endTime = "" + Date.now();
-  Services.prefs.setCharPref("browser.migrate.automigrate-finished", endTime);
+  Preferences.set("browser.migrate.automigrate.started", startTime);
+  Preferences.set("browser.migrate.automigrate.finished", endTime);
 
   // Verify that we can undo, then undo:
   Assert.ok(yield AutoMigrate.canUndo(), "Should be possible to undo migration");
   yield AutoMigrate.undo();
 
   // Check that the undo removed the history visits:
   visits = PlacesUtils.history.executeQuery(query, opts);
   visits.root.containerOpen = true;
@@ -239,13 +240,49 @@ add_task(function* checkUndoRemoval() {
   Assert.ok(!bookmark, "Should have no bookmarks after undo");
 
   // Check that the undo removed the passwords:
   storedLogins = Services.logins.findLogins({}, "www.mozilla.org",
                                             "http://www.mozilla.org", null);
   Assert.equal(storedLogins.length, 0, "Should have no logins");
 
   // Finally check prefs got cleared:
-  Assert.ok(!Services.prefs.getPrefType("browser.migrate.automigrate-started"),
+  Assert.ok(!Preferences.has("browser.migrate.automigrate.started"),
             "Should no longer have pref for migration start time.");
-  Assert.ok(!Services.prefs.getPrefType("browser.migrate.automigrate-finished"),
+  Assert.ok(!Preferences.has("browser.migrate.automigrate.finished"),
             "Should no longer have pref for migration finish time.");
 });
+
+add_task(function* checkUndoDisablingByBookmarksAndPasswords() {
+  let startTime = "" + Date.now();
+  Services.prefs.setCharPref("browser.migrate.automigrate.started", startTime);
+  // Now set finished pref:
+  let endTime = "" + (Date.now() + 1000);
+  Services.prefs.setCharPref("browser.migrate.automigrate.finished", endTime);
+  AutoMigrate.maybeInitUndoObserver();
+
+  ok((yield AutoMigrate.canUndo()), "Should be able to undo.");
+
+  // Insert a login and check that that disabled undo.
+  let login = Cc["@mozilla.org/login-manager/loginInfo;1"].createInstance(Ci.nsILoginInfo);
+  login.init("www.mozilla.org", "http://www.mozilla.org", null, "user", "pass", "userEl", "passEl");
+  Services.logins.addLogin(login);
+
+  ok(!(yield AutoMigrate.canUndo()), "Should no longer be able to undo.");
+  Services.prefs.setCharPref("browser.migrate.automigrate.started", startTime);
+  Services.prefs.setCharPref("browser.migrate.automigrate.finished", endTime);
+  ok((yield AutoMigrate.canUndo()), "Should be able to undo.");
+  AutoMigrate.maybeInitUndoObserver();
+
+  // Insert a bookmark and check that that disabled undo.
+  yield PlacesUtils.bookmarks.insert({
+    parentGuid: PlacesUtils.bookmarks.toolbarGuid,
+    url: "http://www.example.org/",
+    title: "Some example bookmark",
+  });
+  ok(!(yield AutoMigrate.canUndo()), "Should no longer be able to undo.");
+
+  try {
+    Services.logins.removeAllLogins();
+  } catch (ex) {}
+  yield PlacesUtils.bookmarks.eraseEverything();
+});
+
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -793,16 +793,19 @@ BrowserGlue.prototype = {
     Feeds.init();
     ContentPrefServiceParent.init();
 
     LoginManagerParent.init();
     ReaderParent.init();
 
     SelfSupportBackend.init();
 
+    // Ensure we keep track of places/pw-mananager undo by init'ing this early.
+    Cu.import("resource:///modules/AutoMigrate.jsm");
+
     if (!AppConstants.RELEASE_BUILD) {
       let themeName = gBrowserBundle.GetStringFromName("deveditionTheme.name");
       let vendorShortName = gBrandBundle.GetStringFromName("vendorShortName");
 
       LightweightThemeManager.addBuiltInTheme({
         id: "firefox-devedition@mozilla.org",
         name: themeName,
         headerURL: "resource:///chrome/browser/content/browser/defaultthemes/devedition.header.png",
deleted file mode 100644
--- a/build/autoconf/winsdk.m4
+++ /dev/null
@@ -1,22 +0,0 @@
-dnl This Source Code Form is subject to the terms of the Mozilla Public
-dnl License, v. 2.0. If a copy of the MPL was not distributed with this
-dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-dnl Identify which version of the SDK we're building with
-dnl Windows Server 2008 and newer SDKs have WinSDKVer.h, get the version
-dnl from there
-AC_DEFUN([MOZ_FIND_WINSDK_VERSION], [
-  AC_CACHE_CHECK(for highest Windows version supported by this SDK,
-                 ac_cv_winsdk_maxver,
-                 [cat > conftest.h <<EOF
-#include <winsdkver.h>
-
-WINVER_MAXVER
-EOF
-                      ac_cv_winsdk_maxver=`$CPP conftest.h 2>/dev/null | tail -n1`
-                      rm -f conftest.h
-                     ])
-      dnl WinSDKVer.h returns the version number in 4-digit format while many
-      dnl consumers expect 8. Therefore, pad the result with an extra 4 zeroes.
-      MOZ_WINSDK_MAXVER=${ac_cv_winsdk_maxver}0000
-])
--- a/build/moz.configure/old.configure
+++ b/build/moz.configure/old.configure
@@ -316,17 +316,16 @@ def old_configure_options(*options):
     '--with-system-nspr',
     '--with-system-nss',
     '--with-system-png',
     '--with-system-zlib',
     '--with-thumb',
     '--with-thumb-interwork',
     '--with-unify-dist',
     '--with-user-appdir',
-    '--with-windows-version',
     '--x-includes',
     '--x-libraries',
 
     # Below are the configure flags used by comm-central.
     '--enable-ldap',
     '--enable-mapi',
     '--enable-calendar',
     '--enable-incomplete-external-linkage',
--- a/build/moz.configure/toolchain.configure
+++ b/build/moz.configure/toolchain.configure
@@ -375,16 +375,81 @@ def check_compiler(compiler, language, t
         version=info.version,
         target_cpu=info.cpu,
         target_kernel=info.kernel,
         target_endianness=info.endianness,
         flags=flags,
     )
 
 
+@imports(_from='collections', _import='defaultdict')
+@imports(_from='__builtin__', _import='sorted')
+def get_vc_paths(base):
+    vc = defaultdict(lambda: defaultdict(dict))
+    subkey = r'Microsoft\VisualStudio\VC\*\*\*\Compiler'
+    for v, h, t, p in get_registry_values(base + '\\' + subkey):
+        vc[v][h][t] = p
+    if not vc:
+        return
+    version, data = sorted(vc.iteritems(), key=lambda x: Version(x[0]))[-1]
+    return data
+
+
+@depends(host)
+@imports('platform')
+def vc_compiler_path(host):
+    if host.kernel != 'WINNT':
+        return
+    vc_host = {
+        'x86': 'x86',
+        'AMD64': 'x64',
+    }.get(platform.machine())
+    if vc_host is None:
+        return
+    vc_target = {
+        'x86': 'x86',
+        'x86_64': 'x64',
+        'arm': 'arm',
+    }.get(host.cpu)
+    if vc_target is None:
+        return
+
+    base_key = r'HKEY_LOCAL_MACHINE\SOFTWARE'
+    data = get_vc_paths(base_key)
+    if not data:
+        data = get_vc_paths(base_key + r'\Wow6432Node')
+    if not data:
+        return
+
+    path = data.get(vc_host, {}).get(vc_target)
+    if not path and vc_host == 'x64':
+        vc_host = 'x86'
+        path = data.get(vc_host, {}).get(vc_target)
+    if not path:
+        return
+    path = os.path.dirname(path)
+    if vc_host != vc_target:
+        other_path = data.get(vc_host, {}).get(vc_host)
+        if other_path:
+            return (path, os.path.dirname(other_path))
+    return (path,)
+
+
+@depends(vc_compiler_path)
+@imports('os')
+def toolchain_search_path(vc_compiler_path):
+    if vc_compiler_path:
+        result = [os.environ.get('PATH')]
+        result.extend(vc_compiler_path)
+        # We're going to alter PATH for good in windows.configure, but we also
+        # need to do it for the valid_compiler() check below.
+        os.environ['PATH'] = os.pathsep.join(result)
+        return result
+
+
 @template
 def default_c_compilers(host_or_target):
     '''Template defining the set of default C compilers for the host and
     target platforms.
     `host_or_target` is either `host` or `target` (the @depends functions
     from init.configure.
     '''
     assert host_or_target in (host, target)
@@ -516,17 +581,18 @@ def compiler(language, host_or_target, c
                     for k, v in other_compiler.__dict__.iteritems()
                 })
 
     # Normally, we'd use `var` instead of `_var`, but the interaction with
     # old-configure complicates things, and for now, we a) can't take the plain
     # result from check_prog as CC/CXX/HOST_CC/HOST_CXX and b) have to let
     # old-configure AC_SUBST it (because it's autoconf doing it, not us)
     compiler = check_prog('_%s' % var, what=what, progs=default_compilers,
-                          input=delayed_getattr(provided_compiler, 'compiler'))
+                          input=delayed_getattr(provided_compiler, 'compiler'),
+                          paths=toolchain_search_path)
 
     @depends(compiler, provided_compiler, compiler_wrapper, host_or_target)
     @checking('whether %s can be used' % what, lambda x: bool(x))
     @imports(_from='mozbuild.shellutil', _import='quote')
     def valid_compiler(compiler, provided_compiler, compiler_wrapper,
                        host_or_target):
         wrapper = list(compiler_wrapper or ())
         if provided_compiler:
@@ -756,9 +822,10 @@ add_old_configure_assignment('MOZ_DEBUG_
 @depends(c_compiler, target)
 def libcxx_inline_visibility(c_compiler, target):
     if c_compiler.type == 'clang' and target.os == 'Android':
         return ''
 
 set_define('_LIBCPP_INLINE_VISIBILITY', libcxx_inline_visibility)
 set_define('_LIBCPP_INLINE_VISIBILITY_EXCEPT_GCC49', libcxx_inline_visibility)
 
+include('windows.configure')
 include('rust.configure')
--- a/build/moz.configure/util.configure
+++ b/build/moz.configure/util.configure
@@ -120,16 +120,115 @@ def try_invoke_compiler(compiler, langua
 
 def unique_list(l):
     result = []
     for i in l:
         if l not in result:
             result.append(i)
     return result
 
+
+# Get values out of the Windows registry. This function can only be called on
+# Windows.
+# The `pattern` argument is a string starting with HKEY_ and giving the full
+# "path" of the registry key to get the value for, with backslash separators.
+# The string can contains wildcards ('*').
+# The result of this functions is an enumerator yielding tuples for each
+# match. Each of these tuples contains the key name matching wildcards
+# followed by the value.
+#
+# Examples:
+#   get_registry_values(r'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\'
+#                       r'Windows Kits\Installed Roots\KitsRoot*')
+#   yields e.g.:
+#     ('KitsRoot81', r'C:\Program Files (x86)\Windows Kits\8.1\')
+#     ('KitsRoot10', r'C:\Program Files (x86)\Windows Kits\10\')
+#
+#   get_registry_values(r'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\'
+#                       r'Windows Kits\Installed Roots\KitsRoot8.1')
+#   yields e.g.:
+#     (r'C:\Program Files (x86)\Windows Kits\8.1\',)
+#
+#   get_registry_values(r'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\'
+#                       r'Windows Kits\*\KitsRoot*')
+#   yields e.g.:
+#     ('Installed Roots', 'KitsRoot81',
+#      r'C:\Program Files (x86)\Windows Kits\8.1\')
+#     ('Installed Roots', 'KitsRoot10',
+#      r'C:\Program Files (x86)\Windows Kits\10\')
+#
+#   get_registry_values(r'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\'
+#                       r'VisualStudio\VC\*\x86\*\Compiler')
+#   yields e.g.:
+#     ('19.0', 'arm', r'C:\...\amd64_arm\cl.exe')
+#     ('19.0', 'x64', r'C:\...\amd64\cl.exe')
+#     ('19.0', 'x86', r'C:\...\amd64_x86\cl.exe')
+@imports(_import='_winreg', _as='winreg')
+@imports(_from='__builtin__', _import='WindowsError')
+@imports(_from='fnmatch', _import='fnmatch')
+def get_registry_values(pattern):
+    def enum_helper(func, key):
+        i = 0
+        while True:
+            try:
+                yield func(key, i)
+            except WindowsError:
+                break
+            i += 1
+
+    def get_keys(key, pattern):
+        try:
+            s = winreg.OpenKey(key, '\\'.join(pattern[:-1]))
+        except WindowsError:
+            return
+        for k in enum_helper(winreg.EnumKey, s):
+            if fnmatch(k, pattern[-1]):
+                try:
+                    yield k, winreg.OpenKey(s, k)
+                except WindowsError:
+                    pass
+
+    def get_values(key, pattern):
+        try:
+            s = winreg.OpenKey(key, '\\'.join(pattern[:-1]))
+        except WindowsError:
+            return
+        for k, v, t in enum_helper(winreg.EnumValue, s):
+            if fnmatch(k, pattern[-1]):
+                yield k, v
+
+    def split_pattern(pattern):
+        subpattern = []
+        for p in pattern:
+            subpattern.append(p)
+            if '*' in p:
+                yield subpattern
+                subpattern = []
+        if subpattern:
+            yield subpattern
+
+    pattern = pattern.split('\\')
+    assert pattern[0].startswith('HKEY_')
+    keys = [(getattr(winreg, pattern[0]),)]
+    pattern = list(split_pattern(pattern[1:]))
+    for i, p in enumerate(pattern):
+        next_keys = []
+        for base_key in keys:
+            matches = base_key[:-1]
+            base_key = base_key[-1]
+            if i == len(pattern) - 1:
+                want_name = '*' in p[-1]
+                for name, value in get_values(base_key, p):
+                    yield matches + ((name, value) if want_name else (value,))
+            else:
+                for name, k in get_keys(base_key, p):
+                    next_keys.append(matches + (name, k))
+        keys = next_keys
+
+
 @imports(_from='mozbuild.configure.util', _import='Version', _as='_Version')
 def Version(v):
     'A version number that can be compared usefully.'
     return _Version(v)
 
 # Denotes a deprecated option. Combines option() and @depends:
 # @deprecated_option('--option')
 # def option(value):
new file mode 100644
--- /dev/null
+++ b/build/moz.configure/windows.configure
@@ -0,0 +1,195 @@
+# -*- 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/.
+
+option('--with-windows-version', nargs=1, default='603',
+       help='Windows SDK version to target. Win 8.1 (603) is currently'
+            'the minimum supported version.')
+
+@depends(target)
+def is_windows(target):
+    return target.kernel == 'WINNT'
+
+
+@template
+def depends_win(*args):
+    return depends_when(*args, when=is_windows)
+
+
+@depends_win('--with-windows-version')
+@imports(_from='__builtin__', _import='ValueError')
+def valid_windows_version(value):
+    if not value:
+        die('Cannot build with --without-windows-version')
+    try:
+        version = int(value[0], 16)
+        if version in (0x603,):
+            return version
+    except ValueError:
+        pass
+
+    die('Invalid value for --with-windows-version (%s)', value[0])
+
+
+option(env='WINDOWSSDKDIR', nargs=1,
+       help='Directory containing the Windows SDK')
+
+@depends_win('WINDOWSSDKDIR', host)
+def windows_sdk_dir(value, host):
+    if value:
+        return value
+    if host.kernel != 'WINNT':
+        return ()
+
+    return tuple(x[1] for x in get_registry_values(
+        r'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Kits\Installed Roots'
+        r'\KitsRoot*'))
+
+@imports(_from='mozbuild.shellutil', _import='quote')
+def valid_windows_sdk_dir_result(value):
+    if value:
+        return '0x%04x in %s' % (value.version, quote(value.path))
+
+@depends_win(c_compiler, windows_sdk_dir, valid_windows_version,
+             'WINDOWSSDKDIR')
+@checking('for Windows SDK', valid_windows_sdk_dir_result)
+@imports(_from='__builtin__', _import='sorted')
+@imports(_from='textwrap', _import='dedent')
+def valid_windows_sdk_dir(compiler, windows_sdk_dir, target_version,
+                          windows_sdk_dir_env):
+    if windows_sdk_dir_env:
+        windows_sdk_dir_env = windows_sdk_dir_env[0]
+    sdks = {}
+    for d in windows_sdk_dir:
+        um_dir = os.path.join(d, 'include', 'um')
+        shared_dir = os.path.join(d, 'include', 'shared')
+        if os.path.isdir(um_dir) and os.path.isdir(shared_dir):
+            check = dedent('''\
+            #include <winsdkver.h>
+            WINVER_MAXVER
+            ''')
+            result = try_preprocess(compiler.wrapper + [compiler.compiler] +
+                                    compiler.flags +
+                                    ['-I', um_dir, '-I', shared_dir], 'C',
+                                    check)
+            if result:
+                maxver = result.splitlines()[-1]
+                try:
+                    maxver = int(maxver, 0)
+                except:
+                    pass
+                else:
+                    sdks[d] = maxver
+                    continue
+        if d == windows_sdk_dir_env:
+            raise FatalCheckError(
+                'Error while checking the version of the SDK in '
+                'WINDOWSSDKDIR (%s). Please verify it contains a valid and '
+                'complete SDK installation.' % windows_sdk_dir_env)
+
+    valid_sdks = sorted(sdks, key=lambda x: sdks[x], reverse=True)
+    if valid_sdks:
+        biggest_version = sdks[valid_sdks[0]]
+    if not valid_sdks or biggest_version < target_version:
+        if windows_sdk_dir_env:
+            raise FatalCheckError(
+                'You are targeting Windows version 0x%04x, but your SDK only '
+                'supports up to version 0x%04x. Install and use an updated SDK, '
+                'or target a lower version using --with-windows-version. '
+                'Alternatively, try running the Windows SDK Configuration Tool '
+                'and selecting a newer SDK. See '
+                'https://developer.mozilla.org/En/Windows_SDK_versions for '
+                'details on fixing this.' % (target_version, biggest_version))
+
+        raise FatalCheckError(
+            'Cannot find a Windows SDK for version >= 0x%04x.' % target_version)
+
+    return namespace(
+        path=valid_sdks[0],
+        version=biggest_version,
+    )
+
+
+add_old_configure_assignment(
+    'WINDOWSSDKDIR',
+    delayed_getattr(valid_windows_sdk_dir, 'path'))
+add_old_configure_assignment(
+    'MOZ_WINSDK_MAXVER',
+    depends(valid_windows_sdk_dir)(
+        lambda x: '0x%04X0000' % x.version if x else None))
+
+
+option(env='MT', nargs=1, help='Path to the Microsoft Manifest Tool')
+
+@depends_win(valid_windows_sdk_dir)
+@imports(_from='os', _import='environ')
+@imports('platform')
+def sdk_bin_path(valid_windows_sdk_dir):
+    if not valid_windows_sdk_dir:
+        return
+
+    vc_host = {
+        'x86': 'x86',
+        'AMD64': 'x64',
+    }.get(platform.machine())
+
+    result = [
+        environ['PATH'],
+        os.path.join(valid_windows_sdk_dir.path, 'bin', vc_host)
+    ]
+    if vc_host == 'x64':
+        result.append(
+            os.path.join(valid_windows_sdk_dir.path, 'bin', 'x86'))
+    return result
+
+
+# Normally, we'd use `MT` instead of `_MT`, but for now, we want MT to only contain
+# mt.exe.
+mt = check_prog('_MT', depends_win()(lambda: ('mt.exe',)), what='mt',
+                input='MT', paths=sdk_bin_path)
+
+
+# Check that MT is not something unexpected like "magnetic tape manipulation
+# utility".
+@depends_win(mt)
+@checking('whether MT is really Microsoft Manifest Tool', lambda x: bool(x))
+@imports('re')
+@imports('subprocess')
+def valid_mt(path):
+    try:
+        out = subprocess.check_output([path]).splitlines()
+        out = '\n'.join(l for l in out
+                        if 'Microsoft (R) Manifest Tool' in l)
+        if out:
+              m = re.search(r'(?<=[^!-~])[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+',
+                            out)
+              if not m:
+                  raise FatalCheckError(
+                      'Unknown version of the Microsoft Manifest Tool')
+              return namespace(
+                  path=path,
+                  version=Version(m.group(0)),
+              )
+    except subprocess.CalledProcessError:
+        pass
+    raise FatalCheckError('%s is not Microsoft Manifest Tool')
+
+
+set_config('MT', depends_if(valid_mt)(lambda x: os.path.basename(x.path)))
+set_config('MSMANIFEST_TOOL', depends(valid_mt)(lambda x: bool(x)))
+
+
+# Normally, we'd just have CC, etc. set to absolute paths, but the build system
+# doesn't currently handle properly the case where the paths contain spaces.
+# Additionally, there's the issue described in toolchain.configure, in
+# valid_compiler().
+@depends_win(sdk_bin_path)
+@imports('os')
+def alter_path(sdk_bin_path):
+    path = os.pathsep.join(sdk_bin_path)
+    os.environ['PATH'] = path
+    return path
+
+set_config('PATH', alter_path)
--- a/build/win32/mozconfig.vs2015-win64
+++ b/build/win32/mozconfig.vs2015-win64
@@ -1,14 +1,15 @@
 if [ -z "${VSPATH}" ]; then
     TOOLTOOL_DIR=${TOOLTOOL_DIR:-$topsrcdir}
     VSPATH="$(cd ${TOOLTOOL_DIR} && pwd)/vs2015u2"
+    VSWINPATH="$(cd ${TOOLTOOL_DIR} && pwd -W)/vs2015u2"
 fi
 
-export WINDOWSSDKDIR="${VSPATH}/SDK"
+export WINDOWSSDKDIR="${VSWINPATH}/SDK"
 export WIN32_REDIST_DIR="${VSPATH}/VC/redist/x86/Microsoft.VC140.CRT"
 export WIN_UCRT_REDIST_DIR="${VSPATH}/SDK/Redist/ucrt/DLLs/x86"
 
 export PATH="${VSPATH}/VC/bin/amd64_x86:${VSPATH}/VC/bin/amd64:${VSPATH}/VC/bin:${VSPATH}/SDK/bin/x86:${VSPATH}/SDK/bin/x64:${VSPATH}/DIASDK/bin:${PATH}"
 export PATH="${VSPATH}/VC/redist/x86/Microsoft.VC140.CRT:${VSPATH}/VC/redist/x64/Microsoft.VC140.CRT:${VSPATH}/SDK/Redist/ucrt/DLLs/x86:${VSPATH}/SDK/Redist/ucrt/DLLs/x64:${PATH}"
 
 export INCLUDE="${VSPATH}/VC/include:${VSPATH}/VC/atlmfc/include:${VSPATH}/SDK/Include/ucrt:${VSPATH}/SDK/Include/shared:${VSPATH}/SDK/Include/um:${VSPATH}/SDK/Include/winrt:${VSPATH}/DIASDK/include"
 export LIB="${VSPATH}/VC/lib:${VSPATH}/VC/atlmfc/lib:${VSPATH}/SDK/lib/ucrt/x86:${VSPATH}/SDK/lib/um/x86:${VSPATH}/DIASDK/lib"
--- a/build/win64/mozconfig.vs2015
+++ b/build/win64/mozconfig.vs2015
@@ -1,14 +1,15 @@
 if [ -z "${VSPATH}" ]; then
     TOOLTOOL_DIR=${TOOLTOOL_DIR:-$topsrcdir}
     VSPATH="$(cd ${TOOLTOOL_DIR} && pwd)/vs2015u2"
+    VSWINPATH="$(cd ${TOOLTOOL_DIR} && pwd -W)/vs2015u2"
 fi
 
-export WINDOWSSDKDIR="${VSPATH}/SDK"
+export WINDOWSSDKDIR="${VSWINPATH}/SDK"
 export WIN32_REDIST_DIR=${VSPATH}/VC/redist/x64/Microsoft.VC140.CRT
 export WIN_UCRT_REDIST_DIR="${VSPATH}/SDK/Redist/ucrt/DLLs/x64"
 
 export PATH="${VSPATH}/VC/bin/amd64:${VSPATH}/VC/bin:${VSPATH}/SDK/bin/x64:${VSPATH}/VC/redist/x64/Microsoft.VC140.CRT:${VSPATH}/SDK/Redist/ucrt/DLLs/x64:${VSPATH}/DIASDK/bin/amd64:${PATH}"
 
 export INCLUDE="${VSPATH}/VC/include:${VSPATH}/VC/atlmfc/include:${VSPATH}/SDK/Include/ucrt:${VSPATH}/SDK/Include/shared:${VSPATH}/SDK/Include/um:${VSPATH}/SDK/Include/winrt:${VSPATH}/DIASDK/include"
 export LIB="${VSPATH}/VC/lib/amd64:${VSPATH}/VC/atlmfc/lib/amd64:${VSPATH}/SDK/lib/ucrt/x64:${VSPATH}/SDK/lib/um/x64:${VSPATH}/DIASDK/lib/amd64"
 
--- a/caps/nsNullPrincipalURI.cpp
+++ b/caps/nsNullPrincipalURI.cpp
@@ -266,16 +266,24 @@ NS_IMETHODIMP
 nsNullPrincipalURI::CloneIgnoringRef(nsIURI **_newURI)
 {
   // GetRef/SetRef not supported by nsNullPrincipalURI, so
   // CloneIgnoringRef() is the same as Clone().
   return Clone(_newURI);
 }
 
 NS_IMETHODIMP
+nsNullPrincipalURI::CloneWithNewRef(const nsACString& newRef, nsIURI **_newURI)
+{
+  // GetRef/SetRef not supported by nsNullPrincipalURI, so
+  // CloneWithNewRef() is the same as Clone().
+  return Clone(_newURI);
+}
+
+NS_IMETHODIMP
 nsNullPrincipalURI::Equals(nsIURI *aOther, bool *_equals)
 {
   *_equals = false;
   RefPtr<nsNullPrincipalURI> otherURI;
   nsresult rv = aOther->QueryInterface(kNullPrincipalURIImplementationCID,
                                        getter_AddRefs(otherURI));
   if (NS_SUCCEEDED(rv)) {
     *_equals = mPath == otherURI->mPath;
--- a/devtools/client/performance/panel.js
+++ b/devtools/client/performance/panel.js
@@ -1,16 +1,15 @@
 /* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
-const { Cc, Ci, Cu, Cr } = require("chrome");
 const { Task } = require("devtools/shared/task");
 
 loader.lazyRequireGetter(this, "promise");
 loader.lazyRequireGetter(this, "EventEmitter",
   "devtools/shared/event-emitter");
 
 function PerformancePanel(iframeWindow, toolbox) {
   this.panelWin = iframeWindow;
--- a/devtools/client/performance/performance-controller.js
+++ b/devtools/client/performance/performance-controller.js
@@ -1,43 +1,51 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
+/* globals document, PerformanceView, ToolbarView, RecordingsView, DetailsView */
+
+/* exported Cc, Ci, Cu, Cr, loader */
 var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
 var BrowserLoaderModule = {};
 Cu.import("resource://devtools/client/shared/browser-loader.js", BrowserLoaderModule);
 var { loader, require } = BrowserLoaderModule.BrowserLoader({
   baseURI: "resource://devtools/client/performance/",
   window: this
 });
 var { Task } = require("devtools/shared/task");
+/* exported Heritage, ViewHelpers, WidgetMethods, setNamedTimeout, clearNamedTimeout */
 var { Heritage, ViewHelpers, WidgetMethods, setNamedTimeout, clearNamedTimeout } = require("devtools/client/shared/widgets/view-helpers");
 var { gDevTools } = require("devtools/client/framework/devtools");
 
 // Events emitted by various objects in the panel.
 var EVENTS = require("devtools/client/performance/events");
 Object.defineProperty(this, "EVENTS", {
   value: EVENTS,
   enumerable: true,
   writable: false
 });
 
+/* exported React, ReactDOM, JITOptimizationsView, Services, promise, EventEmitter,
+   DevToolsUtils, system */
 var React = require("devtools/client/shared/vendor/react");
 var ReactDOM = require("devtools/client/shared/vendor/react-dom");
 var JITOptimizationsView = React.createFactory(require("devtools/client/performance/components/jit-optimizations"));
 var Services = require("Services");
 var promise = require("promise");
 var EventEmitter = require("devtools/shared/event-emitter");
 var DevToolsUtils = require("devtools/shared/DevToolsUtils");
 var system = require("devtools/shared/system");
 
 // Logic modules
-
+/* exported L10N, PerformanceTelemetry, TIMELINE_BLUEPRINT, RecordingUtils,
+   OptimizationsGraph, GraphsController, WaterfallHeader, MarkerView, MarkerDetails,
+   MarkerBlueprintUtils, WaterfallUtils, FrameUtils, CallView, ThreadNode, FrameNode */
 var { L10N } = require("devtools/client/performance/modules/global");
 var { PerformanceTelemetry } = require("devtools/client/performance/modules/logic/telemetry");
 var { TIMELINE_BLUEPRINT } = require("devtools/client/performance/modules/markers");
 var RecordingUtils = require("devtools/shared/performance/recording-utils");
 var { OptimizationsGraph, GraphsController } = require("devtools/client/performance/modules/widgets/graphs");
 var { WaterfallHeader } = require("devtools/client/performance/modules/widgets/waterfall-ticks");
 var { MarkerView } = require("devtools/client/performance/modules/widgets/marker-view");
 var { MarkerDetails } = require("devtools/client/performance/modules/widgets/marker-details");
@@ -45,29 +53,33 @@ var { MarkerBlueprintUtils } = require("
 var WaterfallUtils = require("devtools/client/performance/modules/logic/waterfall-utils");
 var FrameUtils = require("devtools/client/performance/modules/logic/frame-utils");
 var { CallView } = require("devtools/client/performance/modules/widgets/tree-view");
 var { ThreadNode } = require("devtools/client/performance/modules/logic/tree-model");
 var { FrameNode } = require("devtools/client/performance/modules/logic/tree-model");
 
 // Widgets modules
 
+/* exported OptionsView, FlameGraph, FlameGraphUtils, TreeWidget, SideMenuWidget */
 var { OptionsView } = require("devtools/client/shared/options-view");
 var { FlameGraph, FlameGraphUtils } = require("devtools/client/shared/widgets/FlameGraph");
 var { TreeWidget } = require("devtools/client/shared/widgets/TreeWidget");
-
 var { SideMenuWidget } = require("resource://devtools/client/shared/widgets/SideMenuWidget.jsm");
 
+/* exported BRANCH_NAME */
 var BRANCH_NAME = "devtools.performance.ui.";
 
 /**
  * The current target, toolbox and PerformanceFront, set by this tool's host.
  */
+/* exported gToolbox, gTarget, gFront */
 var gToolbox, gTarget, gFront;
 
+/* exported startupPerformance, shutdownPerformance, PerformanceController */
+
 /**
  * Initializes the profiler controller and views.
  */
 var startupPerformance = Task.async(function* () {
   yield PerformanceController.initialize();
   yield PerformanceView.initialize();
   PerformanceController.enableFrontEventListeners();
 });
@@ -278,18 +290,19 @@ var PerformanceController = {
    *        The file to stream the data into.
    */
   exportRecording: Task.async(function* (_, recording, file) {
     yield recording.exportRecording(file);
     this.emit(EVENTS.RECORDING_EXPORTED, recording, file);
   }),
 
    /**
-   * Clears all completed recordings from the list as well as the current non-console recording.
-   * Emits `EVENTS.RECORDING_DELETED` when complete so other components can clean up.
+   * Clears all completed recordings from the list as well as the current non-console
+   * recording. Emits `EVENTS.RECORDING_DELETED` when complete so other components can
+   * clean up.
    */
   clearRecordings: Task.async(function* () {
     for (let i = this._recordings.length - 1; i >= 0; i--) {
       let model = this._recordings[i];
       if (!model.isConsole() && model.isRecording()) {
         yield this.stopRecording();
       }
       // If last recording is not recording, but finalizing itself,
@@ -303,18 +316,17 @@ var PerformanceController = {
         this.emit(EVENTS.RECORDING_DELETED, model);
         this._recordings.splice(i, 1);
       }
     }
     if (this._recordings.length > 0) {
       if (!this._recordings.includes(this.getCurrentRecording())) {
         this.setCurrentRecording(this._recordings[0]);
       }
-    }
-    else {
+    } else {
       this.setCurrentRecording(null);
     }
   }),
 
   /**
    * Loads a recording from a file, adding it to the recordings list. Emits
    * `EVENTS.RECORDING_IMPORTED` when the file was loaded.
    *
@@ -453,18 +465,18 @@ var PerformanceController = {
   },
 
   /**
    * Utility method taking a string or an array of strings of feature names (like
    * "withAllocations" or "withMarkers"), and returns whether or not the current
    * recording supports that feature, based off of UI preferences and server support.
    *
    * @option {Array<string>|string} features
-   *         A string or array of strings indicating what configuration is needed on the recording
-   *         model, like `withTicks`, or `withMemory`.
+   *         A string or array of strings indicating what configuration is needed on the
+   *         recording model, like `withTicks`, or `withMemory`.
    *
    * @return boolean
    */
   isFeatureSupported: function (features) {
     if (!features) {
       return true;
     }
 
@@ -537,19 +549,18 @@ var PerformanceController = {
    * Called on init, sets an `e10s` attribute on the main view container with
    * "disabled" if e10s is possible on the platform and just not on, or "unsupported"
    * if e10s is not possible on the platform. If e10s is on, no attribute is set.
    */
   _setMultiprocessAttributes: function () {
     let { enabled, supported } = this.getMultiprocessStatus();
     if (!enabled && supported) {
       $("#performance-view").setAttribute("e10s", "disabled");
-    }
-    // Could be a chance where the directive goes away yet e10s is still on
-    else if (!enabled && !supported) {
+    } else if (!enabled && !supported) {
+      // Could be a chance where the directive goes away yet e10s is still on
       $("#performance-view").setAttribute("e10s", "unsupported");
     }
   },
 
   /**
    * Pipes an event from some source to the PerformanceController.
    */
   _pipe: function (eventName, ...data) {
@@ -562,14 +573,15 @@ var PerformanceController = {
 /**
  * Convenient way of emitting events from the controller.
  */
 EventEmitter.decorate(PerformanceController);
 
 /**
  * DOM query helpers.
  */
+/* exported $, $$ */
 function $(selector, target = document) {
   return target.querySelector(selector);
 }
 function $$(selector, target = document) {
   return target.querySelectorAll(selector);
 }
--- a/devtools/client/performance/performance-view.js
+++ b/devtools/client/performance/performance-view.js
@@ -1,55 +1,119 @@
 /* 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/. */
 /* import-globals-from performance-controller.js */
+/* globals OverviewView, window */
 "use strict";
-
 /**
  * Master view handler for the performance tool.
  */
 var PerformanceView = {
 
   _state: null,
 
   // Set to true if the front emits a "buffer-status" event, indicating
   // that the server has support for determining buffer status.
   _bufferStatusSupported: false,
 
   // Mapping of state to selectors for different properties and their values,
   // from the main profiler view. Used in `PerformanceView.setState()`
   states: {
     "unavailable": [
-      { sel: "#performance-view", opt: "selectedPanel", val: () => $("#unavailable-notice") },
-      { sel: "#performance-view-content", opt: "hidden", val: () => true },
+      {
+        sel: "#performance-view",
+        opt: "selectedPanel",
+        val: () => $("#unavailable-notice")
+      },
+      {
+        sel: "#performance-view-content",
+        opt: "hidden",
+        val: () => true
+      },
     ],
     "empty": [
-      { sel: "#performance-view", opt: "selectedPanel", val: () => $("#empty-notice") },
-      { sel: "#performance-view-content", opt: "hidden", val: () => true },
+      {
+        sel: "#performance-view",
+        opt: "selectedPanel",
+        val: () => $("#empty-notice")
+      },
+      {
+        sel: "#performance-view-content",
+        opt: "hidden",
+        val: () => true
+      },
     ],
     "recording": [
-      { sel: "#performance-view", opt: "selectedPanel", val: () => $("#performance-view-content") },
-      { sel: "#performance-view-content", opt: "hidden", val: () => false },
-      { sel: "#details-pane-container", opt: "selectedPanel", val: () => $("#recording-notice") },
+      {
+        sel: "#performance-view",
+        opt: "selectedPanel",
+        val: () => $("#performance-view-content")
+      },
+      {
+        sel: "#performance-view-content",
+        opt: "hidden",
+        val: () => false
+      },
+      {
+        sel: "#details-pane-container",
+        opt: "selectedPanel",
+        val: () => $("#recording-notice")
+      },
     ],
     "console-recording": [
-      { sel: "#performance-view", opt: "selectedPanel", val: () => $("#performance-view-content") },
-      { sel: "#performance-view-content", opt: "hidden", val: () => false },
-      { sel: "#details-pane-container", opt: "selectedPanel", val: () => $("#console-recording-notice") },
+      {
+        sel: "#performance-view",
+        opt: "selectedPanel",
+        val: () => $("#performance-view-content")
+      },
+      {
+        sel: "#performance-view-content",
+        opt: "hidden",
+        val: () => false
+      },
+      {
+        sel: "#details-pane-container",
+        opt: "selectedPanel",
+        val: () => $("#console-recording-notice")
+      },
     ],
     "recorded": [
-      { sel: "#performance-view", opt: "selectedPanel", val: () => $("#performance-view-content") },
-      { sel: "#performance-view-content", opt: "hidden", val: () => false },
-      { sel: "#details-pane-container", opt: "selectedPanel", val: () => $("#details-pane") },
+      {
+        sel: "#performance-view",
+        opt: "selectedPanel",
+        val: () => $("#performance-view-content")
+      },
+      {
+        sel: "#performance-view-content",
+        opt: "hidden",
+        val: () => false
+      },
+      {
+        sel: "#details-pane-container",
+        opt: "selectedPanel",
+        val: () => $("#details-pane")
+      },
     ],
     "loading": [
-      { sel: "#performance-view", opt: "selectedPanel", val: () => $("#performance-view-content") },
-      { sel: "#performance-view-content", opt: "hidden", val: () => false },
-      { sel: "#details-pane-container", opt: "selectedPanel", val: () => $("#loading-notice") },
+      {
+        sel: "#performance-view",
+        opt: "selectedPanel",
+        val: () => $("#performance-view-content")
+      },
+      {
+        sel: "#performance-view-content",
+        opt: "hidden",
+        val: () => false
+      },
+      {
+        sel: "#details-pane-container",
+        opt: "selectedPanel",
+        val: () => $("#loading-notice")
+      },
     ]
   },
 
   /**
    * Sets up the view with event binding and main subviews.
    */
   initialize: Task.async(function* () {
     this._recordButton = $("#main-record-button");
@@ -67,20 +131,22 @@ var PerformanceView = {
     for (let button of $$(".record-button")) {
       button.addEventListener("click", this._onRecordButtonClick);
     }
     this._importButton.addEventListener("click", this._onImportButtonClick);
     this._clearButton.addEventListener("click", this._onClearButtonClick);
 
     // Bind to controller events to unlock the record button
     PerformanceController.on(EVENTS.RECORDING_SELECTED, this._onRecordingSelected);
-    PerformanceController.on(EVENTS.RECORDING_PROFILER_STATUS_UPDATE, this._onProfilerStatusUpdated);
+    PerformanceController.on(EVENTS.RECORDING_PROFILER_STATUS_UPDATE,
+                             this._onProfilerStatusUpdated);
     PerformanceController.on(EVENTS.RECORDING_STATE_CHANGE, this._onRecordingStateChange);
     PerformanceController.on(EVENTS.RECORDING_ADDED, this._onRecordingStateChange);
-    PerformanceController.on(EVENTS.BACKEND_FAILED_AFTER_RECORDING_START, this._onNewRecordingFailed);
+    PerformanceController.on(EVENTS.BACKEND_FAILED_AFTER_RECORDING_START,
+                             this._onNewRecordingFailed);
 
     if (yield PerformanceController.canCurrentlyRecord()) {
       this.setState("empty");
     } else {
       this.setState("unavailable");
     }
 
     // Initialize the ToolbarView first, because other views may need access
@@ -97,35 +163,38 @@ var PerformanceView = {
   destroy: Task.async(function* () {
     for (let button of $$(".record-button")) {
       button.removeEventListener("click", this._onRecordButtonClick);
     }
     this._importButton.removeEventListener("click", this._onImportButtonClick);
     this._clearButton.removeEventListener("click", this._onClearButtonClick);
 
     PerformanceController.off(EVENTS.RECORDING_SELECTED, this._onRecordingSelected);
-    PerformanceController.off(EVENTS.RECORDING_PROFILER_STATUS_UPDATE, this._onProfilerStatusUpdated);
-    PerformanceController.off(EVENTS.RECORDING_STATE_CHANGE, this._onRecordingStateChange);
+    PerformanceController.off(EVENTS.RECORDING_PROFILER_STATUS_UPDATE,
+                              this._onProfilerStatusUpdated);
+    PerformanceController.off(EVENTS.RECORDING_STATE_CHANGE,
+                              this._onRecordingStateChange);
     PerformanceController.off(EVENTS.RECORDING_ADDED, this._onRecordingStateChange);
-    PerformanceController.off(EVENTS.BACKEND_FAILED_AFTER_RECORDING_START, this._onNewRecordingFailed);
+    PerformanceController.off(EVENTS.BACKEND_FAILED_AFTER_RECORDING_START,
+                              this._onNewRecordingFailed);
 
     yield ToolbarView.destroy();
     yield RecordingsView.destroy();
     yield OverviewView.destroy();
     yield DetailsView.destroy();
   }),
 
   /**
    * Sets the state of the profiler view. Possible options are "unavailable",
    * "empty", "recording", "console-recording", "recorded".
    */
   setState: function (state) {
     // Make sure that the focus isn't captured on a hidden iframe. This fixes a
     // XUL bug where shortcuts stop working.
-    const iframes = window.document.querySelectorAll('iframe');
+    const iframes = window.document.querySelectorAll("iframe");
     for (let iframe of iframes) {
       iframe.blur();
     }
     window.focus();
 
     let viewConfig = this.states[state];
     if (!viewConfig) {
       throw new Error(`Invalid state for PerformanceView: ${state}`);
@@ -279,17 +348,18 @@ var PerformanceView = {
     }
   },
 
   /**
    * Handler for clicking the import button.
    */
   _onImportButtonClick: function (e) {
     let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
-    fp.init(window, L10N.getStr("recordingsList.importDialogTitle"), Ci.nsIFilePicker.modeOpen);
+    fp.init(window, L10N.getStr("recordingsList.importDialogTitle"),
+            Ci.nsIFilePicker.modeOpen);
     fp.appendFilter(L10N.getStr("recordingsList.saveDialogJSONFilter"), "*.json");
     fp.appendFilter(L10N.getStr("recordingsList.saveDialogAllFilter"), "*.*");
 
     if (fp.show() == Ci.nsIFilePicker.returnOK) {
       this.emit(EVENTS.UI_IMPORT_RECORDING, fp.file);
     }
   },
 
--- a/devtools/client/performance/views/details-abstract-subview.js
+++ b/devtools/client/performance/views/details-abstract-subview.js
@@ -1,53 +1,60 @@
 /* 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/. */
 /* import-globals-from ../performance-controller.js */
 /* import-globals-from ../performance-view.js */
+/* exported DetailsSubview */
 "use strict";
 
 /**
  * A base class from which all detail views inherit.
  */
 var DetailsSubview = {
   /**
    * Sets up the view with event binding.
    */
   initialize: function () {
     this._onRecordingStoppedOrSelected = this._onRecordingStoppedOrSelected.bind(this);
     this._onOverviewRangeChange = this._onOverviewRangeChange.bind(this);
     this._onDetailsViewSelected = this._onDetailsViewSelected.bind(this);
     this._onPrefChanged = this._onPrefChanged.bind(this);
 
-    PerformanceController.on(EVENTS.RECORDING_STATE_CHANGE, this._onRecordingStoppedOrSelected);
-    PerformanceController.on(EVENTS.RECORDING_SELECTED, this._onRecordingStoppedOrSelected);
+    PerformanceController.on(EVENTS.RECORDING_STATE_CHANGE,
+                             this._onRecordingStoppedOrSelected);
+    PerformanceController.on(EVENTS.RECORDING_SELECTED,
+                             this._onRecordingStoppedOrSelected);
     PerformanceController.on(EVENTS.PREF_CHANGED, this._onPrefChanged);
     OverviewView.on(EVENTS.UI_OVERVIEW_RANGE_SELECTED, this._onOverviewRangeChange);
     DetailsView.on(EVENTS.UI_DETAILS_VIEW_SELECTED, this._onDetailsViewSelected);
 
     let self = this;
     let originalRenderFn = this.render;
-    let afterRenderFn = () => this._wasRendered = true;
+    let afterRenderFn = () => {
+      this._wasRendered = true;
+    };
 
     this.render = Task.async(function* (...args) {
       let maybeRetval = yield originalRenderFn.apply(self, args);
       afterRenderFn();
       return maybeRetval;
     });
   },
 
   /**
    * Unbinds events.
    */
   destroy: function () {
     clearNamedTimeout("range-change-debounce");
 
-    PerformanceController.off(EVENTS.RECORDING_STATE_CHANGE, this._onRecordingStoppedOrSelected);
-    PerformanceController.off(EVENTS.RECORDING_SELECTED, this._onRecordingStoppedOrSelected);
+    PerformanceController.off(EVENTS.RECORDING_STATE_CHANGE,
+                              this._onRecordingStoppedOrSelected);
+    PerformanceController.off(EVENTS.RECORDING_SELECTED,
+                              this._onRecordingStoppedOrSelected);
     PerformanceController.off(EVENTS.PREF_CHANGED, this._onPrefChanged);
     OverviewView.off(EVENTS.UI_OVERVIEW_RANGE_SELECTED, this._onOverviewRangeChange);
     DetailsView.off(EVENTS.UI_DETAILS_VIEW_SELECTED, this._onDetailsViewSelected);
   },
 
   /**
    * Returns true if this view was rendered at least once.
    */
@@ -128,17 +135,18 @@ var DetailsSubview = {
   _onOverviewRangeChange: function (_, interval) {
     if (!this.requiresUpdateOnRangeChange) {
       return;
     }
     if (DetailsView.isViewSelected(this)) {
       let debounced = () => {
         if (!this.shouldUpdateWhileMouseIsActive && OverviewView.isMouseActive) {
           // Don't render yet, while the selection is still being dragged.
-          setNamedTimeout("range-change-debounce", this.rangeChangeDebounceTime, debounced);
+          setNamedTimeout("range-change-debounce", this.rangeChangeDebounceTime,
+                          debounced);
         } else {
           this.render(interval);
         }
       };
       setNamedTimeout("range-change-debounce", this.rangeChangeDebounceTime, debounced);
     } else {
       this.shouldUpdateWhenShown = true;
     }
--- a/devtools/client/performance/views/details-js-call-tree.js
+++ b/devtools/client/performance/views/details-js-call-tree.js
@@ -1,28 +1,30 @@
 /* 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/. */
 /* import-globals-from ../performance-controller.js */
 /* import-globals-from ../performance-view.js */
+/* globals DetailsSubview */
 "use strict";
 
 /**
  * CallTree view containing profiler call tree, controlled by DetailsView.
  */
 var JsCallTreeView = Heritage.extend(DetailsSubview, {
 
   rerenderPrefs: [
     "invert-call-tree",
     "show-platform-data",
     "flatten-tree-recursion",
     "show-jit-optimizations",
   ],
 
-  rangeChangeDebounceTime: 75, // ms
+  // Units are in milliseconds.
+  rangeChangeDebounceTime: 75,
 
   /**
    * Sets up the view with event binding.
    */
   initialize: function () {
     DetailsSubview.initialize.call(this);
 
     this._onLink = this._onLink.bind(this);
@@ -76,17 +78,16 @@ var JsCallTreeView = Heritage.extend(Det
   },
 
   hideOptimizations: function () {
     this.optimizationsElement.classList.add("hidden");
   },
 
   _onFocus: function (_, treeItem) {
     let showOptimizations = PerformanceController.getOption("show-jit-optimizations");
-    let recording = PerformanceController.getCurrentRecording();
     let frameNode = treeItem.frame;
     let optimizationSites = frameNode && frameNode.hasOptimizations()
                             ? frameNode.getOptimizations().optimizationSites
                             : [];
 
     if (!showOptimizations || !frameNode || optimizationSites.length === 0) {
       this.hideOptimizations();
       this.emit("focus", treeItem);
@@ -131,17 +132,18 @@ var JsCallTreeView = Heritage.extend(Det
 
   /**
    * Called when the recording is stopped and prepares data to
    * populate the call tree.
    */
   _prepareCallTree: function (profile, { startTime, endTime }, options) {
     let thread = profile.threads[0];
     let { contentOnly, invertTree, flattenRecursion } = options;
-    let threadNode = new ThreadNode(thread, { startTime, endTime, contentOnly, invertTree, flattenRecursion });
+    let threadNode = new ThreadNode(thread, { startTime, endTime, contentOnly, invertTree,
+                                              flattenRecursion });
 
     // Real profiles from nsProfiler (i.e. not synthesized from allocation
     // logs) always have a (root) node. Go down one level in the uninverted
     // view to avoid displaying both the synthesized root node and the (root)
     // node from the profiler.
     if (!invertTree) {
       threadNode.calls = threadNode.calls[0].calls;
     }
--- a/devtools/client/performance/views/details-js-flamegraph.js
+++ b/devtools/client/performance/views/details-js-flamegraph.js
@@ -1,13 +1,14 @@
 /* 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/. */
 /* import-globals-from ../performance-controller.js */
 /* import-globals-from ../performance-view.js */
+/* globals DetailsSubview */
 "use strict";
 
 /**
  * FlameGraph view containing a pyramid-like visualization of a profile,
  * controlled by DetailsView.
  */
 var JsFlameGraphView = Heritage.extend(DetailsSubview, {
 
@@ -61,17 +62,18 @@ var JsFlameGraphView = Heritage.extend(D
     let duration = recording.getDuration();
     let profile = recording.getProfile();
     let thread = profile.threads[0];
 
     let data = FlameGraphUtils.createFlameGraphDataFromThread(thread, {
       invertTree: PerformanceController.getOption("invert-flame-graph"),
       flattenRecursion: PerformanceController.getOption("flatten-tree-recursion"),
       contentOnly: !PerformanceController.getOption("show-platform-data"),
-      showIdleBlocks: PerformanceController.getOption("show-idle-blocks") && L10N.getStr("table.idle")
+      showIdleBlocks: PerformanceController.getOption("show-idle-blocks")
+                      && L10N.getStr("table.idle")
     });
 
     this.graph.setData({ data,
       bounds: {
         startTime: 0,
         endTime: duration
       },
       visible: {
--- a/devtools/client/performance/views/details-memory-call-tree.js
+++ b/devtools/client/performance/views/details-memory-call-tree.js
@@ -1,25 +1,27 @@
 /* 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/. */
 /* import-globals-from ../performance-controller.js */
 /* import-globals-from ../performance-view.js */
+/* globals DetailsSubview */
 "use strict";
 
 /**
  * CallTree view containing memory allocation sites, controlled by DetailsView.
  */
 var MemoryCallTreeView = Heritage.extend(DetailsSubview, {
 
   rerenderPrefs: [
     "invert-call-tree"
   ],
 
-  rangeChangeDebounceTime: 100, // ms
+  // Units are in milliseconds.
+  rangeChangeDebounceTime: 100,
 
   /**
    * Sets up the view with event binding.
    */
   initialize: function () {
     DetailsSubview.initialize.call(this);
 
     this._onLink = this._onLink.bind(this);
--- a/devtools/client/performance/views/details-memory-flamegraph.js
+++ b/devtools/client/performance/views/details-memory-flamegraph.js
@@ -1,13 +1,14 @@
 /* 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/. */
 /* import-globals-from ../performance-controller.js */
 /* import-globals-from ../performance-view.js */
+/* globals DetailsSubview */
 "use strict";
 
 /**
  * FlameGraph view containing a pyramid-like visualization of memory allocation
  * sites, controlled by DetailsView.
  */
 var MemoryFlameGraphView = Heritage.extend(DetailsSubview, {
 
@@ -59,17 +60,18 @@ var MemoryFlameGraphView = Heritage.exte
     let recording = PerformanceController.getCurrentRecording();
     let duration = recording.getDuration();
     let allocations = recording.getAllocations();
 
     let thread = RecordingUtils.getProfileThreadFromAllocations(allocations);
     let data = FlameGraphUtils.createFlameGraphDataFromThread(thread, {
       invertStack: PerformanceController.getOption("invert-flame-graph"),
       flattenRecursion: PerformanceController.getOption("flatten-tree-recursion"),
-      showIdleBlocks: PerformanceController.getOption("show-idle-blocks") && L10N.getStr("table.idle")
+      showIdleBlocks: PerformanceController.getOption("show-idle-blocks")
+                      && L10N.getStr("table.idle")
     });
 
     this.graph.setData({ data,
       bounds: {
         startTime: 0,
         endTime: duration
       },
       visible: {
--- a/devtools/client/performance/views/details-waterfall.js
+++ b/devtools/client/performance/views/details-waterfall.js
@@ -1,18 +1,19 @@
 /* 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/. */
 /* import-globals-from ../performance-controller.js */
 /* import-globals-from ../performance-view.js */
-/* globals window */
+/* globals window, DetailsSubview */
 "use strict";
 
-const WATERFALL_RESIZE_EVENTS_DRAIN = 100; // ms
 const MARKER_DETAILS_WIDTH = 200;
+// Units are in milliseconds.
+const WATERFALL_RESIZE_EVENTS_DRAIN = 100;
 
 /**
  * Waterfall view containing the timeline markers, controlled by DetailsView.
  */
 var WaterfallView = Heritage.extend(DetailsSubview, {
 
   // Smallest unit of time between two markers. Larger by 10x^3 than Number.EPSILON.
   MARKER_EPSILON: 0.000000000001,
@@ -20,17 +21,18 @@ var WaterfallView = Heritage.extend(Deta
   observedPrefs: [
     "hidden-markers"
   ],
 
   rerenderPrefs: [
     "hidden-markers"
   ],
 
-  rangeChangeDebounceTime: 75, // ms
+  // Units are in milliseconds.
+  rangeChangeDebounceTime: 75,
 
   /**
    * Sets up the view with event binding.
    */
   initialize: function () {
     DetailsSubview.initialize.call(this);
 
     this._cache = new WeakMap();
@@ -41,17 +43,18 @@ var WaterfallView = Heritage.extend(Deta
     this._onShowAllocations = this._onShowAllocations.bind(this);
     this._hiddenMarkers = PerformanceController.getPref("hidden-markers");
 
     this.headerContainer = $("#waterfall-header");
     this.breakdownContainer = $("#waterfall-breakdown");
     this.detailsContainer = $("#waterfall-details");
     this.detailsSplitter = $("#waterfall-view > splitter");
 
-    this.details = new MarkerDetails($("#waterfall-details"), $("#waterfall-view > splitter"));
+    this.details = new MarkerDetails($("#waterfall-details"),
+                                     $("#waterfall-view > splitter"));
     this.details.hidden = true;
 
     this.details.on("resize", this._onResize);
     this.details.on("view-source", this._onViewSource);
     this.details.on("show-allocations", this._onShowAllocations);
     window.addEventListener("resize", this._onResize);
 
     // TODO bug 1167093 save the previously set width, and ensure minimum width
--- a/devtools/client/performance/views/details.js
+++ b/devtools/client/performance/views/details.js
@@ -1,13 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 /* import-globals-from ../performance-controller.js */
 /* import-globals-from ../performance-view.js */
+/* globals WaterfallView, JsCallTreeView, JsFlameGraphView, MemoryCallTreeView,
+           MemoryFlameGraphView, Iterator */
 "use strict";
 
 /**
  * Details view containing call trees, flamegraphs and markers waterfall.
  * Manages subviews and toggles visibility between them.
  */
 var DetailsView = {
   /**
@@ -53,42 +55,47 @@ var DetailsView = {
     this.setAvailableViews = this.setAvailableViews.bind(this);
 
     for (let button of $$("toolbarbutton[data-view]", this.toolbar)) {
       button.addEventListener("command", this._onViewToggle);
     }
 
     yield this.setAvailableViews();
 
-    PerformanceController.on(EVENTS.RECORDING_STATE_CHANGE, this._onRecordingStoppedOrSelected);
-    PerformanceController.on(EVENTS.RECORDING_SELECTED, this._onRecordingStoppedOrSelected);
+    PerformanceController.on(EVENTS.RECORDING_STATE_CHANGE,
+                             this._onRecordingStoppedOrSelected);
+    PerformanceController.on(EVENTS.RECORDING_SELECTED,
+                             this._onRecordingStoppedOrSelected);
     PerformanceController.on(EVENTS.PREF_CHANGED, this.setAvailableViews);
   }),
 
   /**
    * Unbinds events, destroys subviews.
    */
   destroy: Task.async(function* () {
     for (let button of $$("toolbarbutton[data-view]", this.toolbar)) {
       button.removeEventListener("command", this._onViewToggle);
     }
 
-    for (let [_, component] of Iterator(this.components)) {
+    for (let [, component] of Iterator(this.components)) {
       component.initialized && (yield component.view.destroy());
     }
 
-    PerformanceController.off(EVENTS.RECORDING_STATE_CHANGE, this._onRecordingStoppedOrSelected);
-    PerformanceController.off(EVENTS.RECORDING_SELECTED, this._onRecordingStoppedOrSelected);
+    PerformanceController.off(EVENTS.RECORDING_STATE_CHANGE,
+                              this._onRecordingStoppedOrSelected);
+    PerformanceController.off(EVENTS.RECORDING_SELECTED,
+                              this._onRecordingStoppedOrSelected);
     PerformanceController.off(EVENTS.PREF_CHANGED, this.setAvailableViews);
   }),
 
   /**
    * Sets the possible views based off of recording features and server actor support
    * by hiding/showing the buttons that select them and going to default view
-   * if currently selected. Called when a preference changes in `devtools.performance.ui.`.
+   * if currently selected. Called when a preference changes in
+   * `devtools.performance.ui.`.
    */
   setAvailableViews: Task.async(function* () {
     let recording = PerformanceController.getCurrentRecording();
     let isCompleted = recording && recording.isCompleted();
     let invalidCurrentView = false;
 
     for (let [name, { view }] of Iterator(this.components)) {
       let isSupported = this._isViewSupported(name);
@@ -170,21 +177,20 @@ var DetailsView = {
    * and preferences enabled.
    */
   selectDefaultView: function () {
     // We want the waterfall to be default view in almost all cases, except when
     // timeline actor isn't supported, or we have markers disabled (which should only
     // occur temporarily via bug 1156499
     if (this._isViewSupported("waterfall")) {
       return this.selectView("waterfall");
-    } else {
-      // The JS CallTree should always be supported since the profiler
-      // actor is as old as the world.
-      return this.selectView("js-calltree");
     }
+    // The JS CallTree should always be supported since the profiler
+    // actor is as old as the world.
+    return this.selectView("js-calltree");
   },
 
   /**
    * Checks if the provided view is currently selected.
    *
    * @param object viewObject
    * @return boolean
    */
--- a/devtools/client/performance/views/overview.js
+++ b/devtools/client/performance/views/overview.js
@@ -1,21 +1,24 @@
 /* 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/. */
 /* import-globals-from ../performance-controller.js */
 /* import-globals-from ../performance-view.js */
+/* globals Iterator */
 "use strict";
 
 // No sense updating the overview more often than receiving data from the
 // backend. Make sure this isn't lower than DEFAULT_TIMELINE_DATA_PULL_TIMEOUT
 // in devtools/server/actors/timeline.js
-const OVERVIEW_UPDATE_INTERVAL = 200; // ms
-const FRAMERATE_GRAPH_LOW_RES_INTERVAL = 100; // ms
-const FRAMERATE_GRAPH_HIGH_RES_INTERVAL = 16; // ms
+
+// The following units are in milliseconds.
+const OVERVIEW_UPDATE_INTERVAL = 200;
+const FRAMERATE_GRAPH_LOW_RES_INTERVAL = 100;
+const FRAMERATE_GRAPH_HIGH_RES_INTERVAL = 16;
 const GRAPH_REQUIREMENTS = {
   timeline: {
     features: ["withMarkers"]
   },
   framerate: {
     features: ["withTicks"]
   },
   memory: {
@@ -73,17 +76,18 @@ var OverviewView = {
   },
 
   /**
    * Unbinds events.
    */
   destroy: Task.async(function* () {
     PerformanceController.off(EVENTS.PREF_CHANGED, this._onPrefChanged);
     PerformanceController.off(EVENTS.THEME_CHANGED, this._onThemeChanged);
-    PerformanceController.off(EVENTS.RECORDING_STATE_CHANGE, this._onRecordingStateChange);
+    PerformanceController.off(EVENTS.RECORDING_STATE_CHANGE,
+                              this._onRecordingStateChange);
     PerformanceController.off(EVENTS.RECORDING_SELECTED, this._onRecordingSelected);
     this.graphs.off("selecting", this._onGraphSelecting);
     this.graphs.off("rendered", this._onGraphRendered);
     yield this.graphs.destroy();
   }),
 
   /**
    * Returns true if any of the overview graphs have mouse dragging active,
@@ -201,31 +205,32 @@ var OverviewView = {
     if (this.isRendering()) {
       this._timeoutId = setTimeout(this._onRecordingTick, this.OVERVIEW_UPDATE_INTERVAL);
     }
   },
 
   /**
    * Called when recording state changes.
    */
-  _onRecordingStateChange: OverviewViewOnStateChange(Task.async(function* (_, state, recording) {
-    if (state !== "recording-stopped") {
-      return;
-    }
-    // Check to see if the recording that just stopped is the current recording.
-    // If it is, render the high-res graphs. For manual recordings, it will also
-    // be the current recording, but profiles generated by `console.profile` can stop
-    // while having another profile selected -- in this case, OverviewView should keep
-    // rendering the current recording.
-    if (recording !== PerformanceController.getCurrentRecording()) {
-      return;
-    }
-    this.render(FRAMERATE_GRAPH_HIGH_RES_INTERVAL);
-    yield this._checkSelection(recording);
-  })),
+  _onRecordingStateChange: OverviewViewOnStateChange(Task.async(
+    function* (_, state, recording) {
+      if (state !== "recording-stopped") {
+        return;
+      }
+      // Check to see if the recording that just stopped is the current recording.
+      // If it is, render the high-res graphs. For manual recordings, it will also
+      // be the current recording, but profiles generated by `console.profile` can stop
+      // while having another profile selected -- in this case, OverviewView should keep
+      // rendering the current recording.
+      if (recording !== PerformanceController.getCurrentRecording()) {
+        return;
+      }
+      this.render(FRAMERATE_GRAPH_HIGH_RES_INTERVAL);
+      yield this._checkSelection(recording);
+    })),
 
   /**
    * Called when a new recording is selected.
    */
   _onRecordingSelected: OverviewViewOnStateChange(Task.async(function* (_, recording) {
     this._setGraphVisibilityFromRecordingFeatures(recording);
 
     // If this recording is complete, render the high res graph
@@ -297,30 +302,31 @@ var OverviewView = {
    * Called whenever a preference in `devtools.performance.ui.` changes.
    * Does not care about the enabling of memory/framerate graphs,
    * because those will set values on a recording model, and
    * the graphs will render based on the existence.
    */
   _onPrefChanged: Task.async(function* (_, prefName, prefValue) {
     switch (prefName) {
       case "hidden-markers": {
-        let graph;
-        if (graph = yield this.graphs.isAvailable("timeline")) {
+        let graph = yield this.graphs.isAvailable("timeline");
+        if (graph) {
           let filter = PerformanceController.getPref("hidden-markers");
           graph.setFilter(filter);
           graph.refresh({ force: true });
         }
         break;
       }
     }
   }),
 
   _setGraphVisibilityFromRecordingFeatures: function (recording) {
     for (let [graphName, requirements] of Iterator(GRAPH_REQUIREMENTS)) {
-      this.graphs.enable(graphName, PerformanceController.isFeatureSupported(requirements.features));
+      this.graphs.enable(graphName,
+                         PerformanceController.isFeatureSupported(requirements.features));
     }
   },
 
   /**
    * Fetch the multiprocess status and if e10s is not currently on, disable
    * realtime rendering.
    *
    * @return {boolean}
@@ -393,19 +399,18 @@ function OverviewViewOnStateChange(fn) {
 
     // If realtime rendering is not enabed (e10s not on), then
     // show the disabled message, or the full graphs if the recording is completed
     if (!this.isRealtimeRenderingEnabled()) {
       if (recording.isRecording()) {
         this._hideGraphsPanel();
         // Abort, as we do not want to change polling status.
         return;
-      } else {
-        this._showGraphsPanel(recording);
       }
+      this._showGraphsPanel(recording);
     }
 
     if (this.isRendering() && !currentRecording.isRecording()) {
       this._stopPolling();
     } else if (currentRecording.isRecording() && !this.isRendering()) {
       this._startPolling();
     }
 
--- a/devtools/client/performance/views/recordings.js
+++ b/devtools/client/performance/views/recordings.js
@@ -31,17 +31,18 @@ var RecordingsView = Heritage.extend(Wid
     PerformanceController.on(EVENTS.RECORDING_EXPORTED, this._onRecordingExported);
     this.widget.addEventListener("select", this._onSelect, false);
   },
 
   /**
    * Destruction function, called when the tool is closed.
    */
   destroy: function () {
-    PerformanceController.off(EVENTS.RECORDING_STATE_CHANGE, this._onRecordingStateChange);
+    PerformanceController.off(EVENTS.RECORDING_STATE_CHANGE,
+                              this._onRecordingStateChange);
     PerformanceController.off(EVENTS.RECORDING_ADDED, this._onNewRecording);
     PerformanceController.off(EVENTS.RECORDING_DELETED, this._onRecordingDeleted);
     PerformanceController.off(EVENTS.RECORDING_EXPORTED, this._onRecordingExported);
     this.widget.removeEventListener("select", this._onSelect, false);
   },
 
   /**
    * Adds an empty recording to this container.
@@ -186,17 +187,18 @@ var RecordingsView = Heritage.extend(Wid
     this.emit(EVENTS.UI_RECORDING_SELECTED, model);
   }),
 
   /**
    * The click listener for the "save" button of each item in this container.
    */
   _onSaveButtonClick: function (e) {
     let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
-    fp.init(window, L10N.getStr("recordingsList.saveDialogTitle"), Ci.nsIFilePicker.modeSave);
+    fp.init(window, L10N.getStr("recordingsList.saveDialogTitle"),
+            Ci.nsIFilePicker.modeSave);
     fp.appendFilter(L10N.getStr("recordingsList.saveDialogJSONFilter"), "*.json");
     fp.appendFilter(L10N.getStr("recordingsList.saveDialogAllFilter"), "*.*");
     fp.defaultString = "profile.json";
 
     fp.open({ done: result => {
       if (result == Ci.nsIFilePicker.returnCancel) {
         return;
       }
--- a/devtools/client/performance/views/toolbar.js
+++ b/devtools/client/performance/views/toolbar.js
@@ -1,14 +1,14 @@
 /* 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/. */
 /* import-globals-from ../performance-controller.js */
 /* import-globals-from ../performance-view.js */
-/* globals document */
+/* globals document, Iterator */
 "use strict";
 
 /**
  * View handler for toolbar events (mostly option toggling and triggering)
  */
 var ToolbarView = {
   /**
    * Sets up the view with event binding.
@@ -30,43 +30,48 @@ var ToolbarView = {
     let experimentalEnabled = PerformanceController.getOption("experimental");
     this._toggleExperimentalUI(experimentalEnabled);
 
     yield this.optionsView.initialize();
     this.optionsView.on("pref-changed", this._onPrefChanged);
 
     this._buildMarkersFilterPopup();
     this._updateHiddenMarkersPopup();
-    $("#performance-filter-menupopup").addEventListener("popupshowing", this._onFilterPopupShowing);
-    $("#performance-filter-menupopup").addEventListener("popuphiding", this._onFilterPopupHiding);
+    $("#performance-filter-menupopup").addEventListener("popupshowing",
+                                                        this._onFilterPopupShowing);
+    $("#performance-filter-menupopup").addEventListener("popuphiding",
+                                                        this._onFilterPopupHiding);
   }),
 
   /**
    * Unbinds events and cleans up view.
    */
   destroy: function () {
-    $("#performance-filter-menupopup").removeEventListener("popupshowing", this._onFilterPopupShowing);
-    $("#performance-filter-menupopup").removeEventListener("popuphiding", this._onFilterPopupHiding);
+    $("#performance-filter-menupopup").removeEventListener("popupshowing",
+                                                           this._onFilterPopupShowing);
+    $("#performance-filter-menupopup").removeEventListener("popuphiding",
+                                                           this._onFilterPopupHiding);
     this._popup = null;
 
     this.optionsView.off("pref-changed", this._onPrefChanged);
     this.optionsView.destroy();
   },
 
   /**
    * Creates the timeline markers filter popup.
    */
   _buildMarkersFilterPopup: function () {
     for (let [markerName, markerDetails] of Iterator(TIMELINE_BLUEPRINT)) {
       let menuitem = document.createElement("menuitem");
       menuitem.setAttribute("closemenu", "none");
       menuitem.setAttribute("type", "checkbox");
       menuitem.setAttribute("align", "center");
       menuitem.setAttribute("flex", "1");
-      menuitem.setAttribute("label", MarkerBlueprintUtils.getMarkerGenericName(markerName));
+      menuitem.setAttribute("label",
+                            MarkerBlueprintUtils.getMarkerGenericName(markerName));
       menuitem.setAttribute("marker-type", markerName);
       menuitem.className = `marker-color-${markerDetails.colorName}`;
 
       menuitem.addEventListener("command", this._onHiddenMarkersChanged);
 
       $("#performance-filter-menupopup").appendChild(menuitem);
     }
   },
@@ -91,17 +96,18 @@ var ToolbarView = {
    * Fired when `devtools.performance.ui.experimental` is changed, or
    * during init. Toggles the visibility of experimental performance tool options
    * in the UI options.
    *
    * Sets or removes "experimental-enabled" on the menu and main elements,
    * hiding or showing all elements with class "experimental-option".
    *
    * TODO re-enable "#option-enable-memory" permanently once stable in bug 1163350
-   * TODO re-enable "#option-show-jit-optimizations" permanently once stable in bug 1163351
+   * TODO re-enable "#option-show-jit-optimizations" permanently once stable in
+   *      bug 1163351
    *
    * @param {boolean} isEnabled
    */
   _toggleExperimentalUI: function (isEnabled) {
     if (isEnabled) {
       $(".theme-body").classList.add("experimental-enabled");
       this._popup.classList.add("experimental-enabled");
     } else {
@@ -123,17 +129,18 @@ var ToolbarView = {
   _onFilterPopupHiding: function () {
     $("#filter-button").removeAttribute("open");
   },
 
   /**
    * Fired when a menu item in the markers filter popup is checked or unchecked.
    */
   _onHiddenMarkersChanged: function () {
-    let checkedMenuItems = $$("#performance-filter-menupopup menuitem[marker-type]:not([checked])");
+    let checkedMenuItems =
+      $$("#performance-filter-menupopup menuitem[marker-type]:not([checked])");
     let hiddenMarkers = Array.map(checkedMenuItems, e => e.getAttribute("marker-type"));
     PerformanceController.setPref("hidden-markers", hiddenMarkers);
   },
 
   /**
    * Fired when a preference changes in the underlying OptionsView.
    * Propogated by the PerformanceController.
    */
--- a/devtools/client/shared/components/reps/array.js
+++ b/devtools/client/shared/components/reps/array.js
@@ -27,17 +27,17 @@ define(function (require, exports, modul
     getTitle: function (object, context) {
       return "[" + object.length + "]";
     },
 
     arrayIterator: function (array, max) {
       let items = [];
       let delim;
 
-      for (let i = 0; i < array.length && i <= max; i++) {
+      for (let i = 0; i < array.length && i < max; i++) {
         try {
           let value = array[i];
 
           delim = (i == array.length - 1 ? "" : ", ");
 
           if (value === array) {
             items.push(Reference({
               key: i,
@@ -56,24 +56,22 @@ define(function (require, exports, modul
             object: exc,
             delim: delim,
             key: i
           }));
         }
       }
 
       if (array.length > max) {
-        items.pop();
-
         let objectLink = this.props.objectLink || DOM.span;
         items.push(Caption({
           key: "more",
           object: objectLink({
             object: this.props.object
-          }, "more…")
+          }, (array.length - max) + " more…")
         }));
       }
 
       return items;
     },
 
     /**
      * Returns true if the passed object is an array with additional (custom)
--- a/devtools/client/shared/components/reps/grip-array.js
+++ b/devtools/client/shared/components/reps/grip-array.js
@@ -54,17 +54,17 @@ define(function (require, exports, modul
       let array = grip.preview.items;
       if (!array) {
         return items;
       }
 
       let delim;
       let provider = this.props.provider;
 
-      for (let i = 0; i < array.length && i <= max; i++) {
+      for (let i = 0; i < array.length && i < max; i++) {
         try {
           let itemGrip = array[i];
           let value = provider ? provider.getValue(itemGrip) : itemGrip;
 
           delim = (i == array.length - 1 ? "" : ", ");
 
           if (value === array) {
             items.push(Reference({
@@ -84,23 +84,22 @@ define(function (require, exports, modul
             object: exc,
             delim: delim,
             key: i}
           )));
         }
       }
 
       if (array.length > max) {
-        items.pop();
         let objectLink = this.props.objectLink || span;
         items.push(Caption({
           key: "more",
           object: objectLink({
             object: this.props.object
-          }, "more…")
+          }, (grip.preview.length - max) + " more…")
         }));
       }
 
       return items;
     },
 
     render: function () {
       let mode = this.props.mode || "short";
--- a/devtools/client/shared/components/reps/grip.js
+++ b/devtools/client/shared/components/reps/grip.js
@@ -74,17 +74,17 @@ define(function (require, exports, modul
       if (props.length < object.ownPropertyLength) {
         // There are some undisplayed props. Then display "more...".
         let objectLink = this.props.objectLink || span;
 
         props.push(Caption({
           key: "more",
           object: objectLink({
             object: object
-          }, "more…")
+          }, ((object ? object.ownPropertyLength : 0) - max) + " more…")
         }));
       } else if (props.length > 0) {
         // Remove the last comma.
         // NOTE: do not change comp._store.props directly to update a property,
         // it should be re-rendered or cloned with changed props
         let last = props.length - 1;
         props[last] = React.cloneElement(props[last], {
           delim: ""
--- a/devtools/client/shared/components/reps/object.js
+++ b/devtools/client/shared/components/reps/object.js
@@ -73,17 +73,17 @@ define(function (require, exports, modul
       if (props.length > max) {
         props.pop();
         let objectLink = this.props.objectLink || span;
 
         props.push(Caption({
           key: "more",
           object: objectLink({
             object: object
-          }, "more…")
+          }, (Object.keys(object).length - max) + " more…")
         }));
       } else if (props.length > 0) {
         // Remove the last comma.
         props[props.length - 1] = React.cloneElement(
           props[props.length - 1], { delim: "" });
       }
 
       return props;
--- a/devtools/client/shared/components/test/mochitest/test_reps_array.html
+++ b/devtools/client/shared/components/test/mochitest/test_reps_array.html
@@ -102,17 +102,17 @@ window.onload = Task.async(function* () 
       }
     ];
 
     testRepRenderModes(modeTests, "testMaxProps", componentUnderTest, stub);
   }
 
   function testMoreThanShortMaxProps() {
     const stub = Array(maxLength.short + 1).fill("foo");
-    const defaultShortOutput = `[${Array(maxLength.short).fill("\"foo\"").join(", ")}, more…]`;
+    const defaultShortOutput = `[${Array(maxLength.short).fill("\"foo\"").join(", ")}, 1 more…]`;
 
     const modeTests = [
       {
         mode: undefined,
         expectedOutput: defaultShortOutput,
       },
       {
         mode: "tiny",
@@ -128,18 +128,18 @@ window.onload = Task.async(function* () 
       }
     ];
 
     testRepRenderModes(modeTests, "testMoreThanMaxProps", componentUnderTest, stub);
   }
 
   function testMoreThanLongMaxProps() {
     const stub = Array(maxLength.long + 1).fill("foo");
-    const defaultShortOutput = `[${Array(maxLength.short).fill("\"foo\"").join(", ")}, more…]`;
-    const defaultLongOutput = `[${Array(maxLength.long).fill("\"foo\"").join(", ")}, more…]`;
+    const defaultShortOutput = `[${Array(maxLength.short).fill("\"foo\"").join(", ")}, ${maxLength.long + 1 - maxLength.short} more…]`;
+    const defaultLongOutput = `[${Array(maxLength.long).fill("\"foo\"").join(", ")}, 1 more…]`;
 
     const modeTests = [
       {
         mode: undefined,
         expectedOutput: defaultShortOutput,
       },
       {
         mode: "tiny",
@@ -189,17 +189,17 @@ window.onload = Task.async(function* () 
     let stub = [
       {
         p1: "s1",
         p2: ["a1", "a2", "a3"],
         p3: "s3",
         p4: "s4"
       }
     ];
-    const defaultOutput = `[Object{p1: "s1", p3: "s3", p4: "s4", more…}]`;
+    const defaultOutput = `[Object{p1: "s1", p3: "s3", p4: "s4", 1 more…}]`;
 
     const modeTests = [
       {
         mode: undefined,
         expectedOutput: defaultOutput,
       },
       {
         mode: "tiny",
@@ -222,17 +222,17 @@ window.onload = Task.async(function* () 
     let stub = [
       "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
       "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"
     ];
 
     const defaultOutput = `["a", "b", "c", "d", "e", "f", "g", "h", "i", "j",` +
                           ` "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",` +
                           ` "u", "v", "w", "x", "y", "z"]`;
-    const shortOutput = `["a", "b", "c", more…]`;
+    const shortOutput = `["a", "b", "c", 23 more…]`;
 
     const modeTests = [
       {
         mode: undefined,
         expectedOutput: shortOutput,
       },
       {
         mode: "tiny",
--- a/devtools/client/shared/components/test/mochitest/test_reps_grip-array.html
+++ b/devtools/client/shared/components/test/mochitest/test_reps_grip-array.html
@@ -101,17 +101,17 @@ window.onload = Task.async(function* () 
 
     testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
   }
 
   function testMoreThanShortMaxProps() {
     // Test array = `["test string"…] //4 items`
     const testName = "testMoreThanShortMaxProps";
 
-    const defaultOutput = `Array[${Array(maxLength.short).fill("\"test string\"").join(", ")}, more…]`;
+    const defaultOutput = `Array[${Array(maxLength.short).fill("\"test string\"").join(", ")}, 1 more…]`;
 
     const modeTests = [
       {
         mode: undefined,
         expectedOutput: defaultOutput,
       },
       {
         mode: "tiny",
@@ -129,18 +129,18 @@ window.onload = Task.async(function* () 
 
     testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
   }
 
   function testMoreThanLongMaxProps() {
     // Test array = `["test string"…] //301 items`
     const testName = "testMoreThanLongMaxProps";
 
-    const defaultShortOutput = `Array[${Array(maxLength.short).fill("\"test string\"").join(", ")}, more…]`;
-    const defaultLongOutput = `Array[${Array(maxLength.long).fill("\"test string\"").join(", ")}, more…]`;
+    const defaultShortOutput = `Array[${Array(maxLength.short).fill("\"test string\"").join(", ")}, ${maxLength.long + 1 - maxLength.short} more…]`;
+    const defaultLongOutput = `Array[${Array(maxLength.long).fill("\"test string\"").join(", ")}, 1 more…]`;
 
     const modeTests = [
       {
         mode: undefined,
         expectedOutput: defaultShortOutput,
       },
       {
         mode: "tiny",
--- a/devtools/client/shared/components/test/mochitest/test_reps_grip.html
+++ b/devtools/client/shared/components/test/mochitest/test_reps_grip.html
@@ -95,29 +95,29 @@ window.onload = Task.async(function* () 
         expectedOutput: defaultOutput,
       }
     ];
 
     testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
   }
 
   function testMoreThanMaxProps() {
-    // Test object = `{p0: "0", p1: "1", p2: "2", …, p101: "101"}`
+    // Test object = `{p0: "0", p1: "1", p2: "2", …, p100: "100"}`
     const testName = "testMoreThanMaxProps";
 
-    const defaultOutput = `Object {p0: "0", p1: "1", p2: "2", more…}`;
+    const defaultOutput = `Object {p0: "0", p1: "1", p2: "2", 98 more…}`;
 
     // Generate string with 100 properties, which is the max limit
     // for 'long' mode.
     let props = "";
     for (let i = 0; i < 100; i++) {
       props += "p" + i + ": \"" + i + "\", ";
     }
 
-    const longOutput = `Object {${props}more…}`;
+    const longOutput = `Object {${props}1 more…}`;
 
     const modeTests = [
       {
         mode: undefined,
         expectedOutput: defaultOutput,
       },
       {
         mode: "tiny",
@@ -135,17 +135,17 @@ window.onload = Task.async(function* () 
 
     testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
   }
 
   function testUninterestingProps() {
     // Test object: `{a: undefined, b: undefined, c: "c", d: 1}`
     // @TODO This is not how we actually want the preview to be output.
     // See https://bugzilla.mozilla.org/show_bug.cgi?id=1276376
-    const expectedOutput = `Object {a: undefined, b: undefined, c: "c", more…}`;
+    const expectedOutput = `Object {a: undefined, b: undefined, c: "c", 1 more…}`;
   }
 
   function testNestedObject() {
     // Test object: `{objProp: {id: 1}, strProp: "test string"}`
     const testName = "testNestedObject";
 
     const defaultOutput = `Object {objProp: Object, strProp: "test string"}`;
 
--- a/devtools/client/shared/components/test/mochitest/test_reps_object.html
+++ b/devtools/client/shared/components/test/mochitest/test_reps_object.html
@@ -96,17 +96,17 @@ window.onload = Task.async(function* () 
     testRepRenderModes(modeTests, "testMaxProps", componentUnderTest, stub);
   }
 
   function testMoreThanMaxProps() {
     let stub = {};
     for (let i = 0; i<100; i++) {
       stub[`p${i}`] = i
     }
-    const defaultOutput = `Object{p0: 0, p1: 1, p2: 2, more…}`;
+    const defaultOutput = `Object{p0: 0, p1: 1, p2: 2, 97 more…}`;
 
     const modeTests = [
       {
         mode: undefined,
         expectedOutput: defaultOutput,
       },
       {
         mode: "tiny",
@@ -122,17 +122,17 @@ window.onload = Task.async(function* () 
       }
     ];
 
     testRepRenderModes(modeTests, "testMoreThanMaxProps", componentUnderTest, stub);
   }
 
   function testUninterestingProps() {
     const stub = {a:undefined, b:undefined, c:"c", d:0};
-    const defaultOutput = `Object{c: "c", d: 0, a: undefined, more…}`;
+    const defaultOutput = `Object{c: "c", d: 0, a: undefined, 1 more…}`;
 
     const modeTests = [
       {
         mode: undefined,
         expectedOutput: defaultOutput,
       },
       {
         mode: "tiny",
--- a/devtools/client/themes/images/add.svg
+++ b/devtools/client/themes/images/add.svg
@@ -1,6 +1,6 @@
 <!-- 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/. -->
 <svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="#0b0b0b">
-  <path d="M8.5 8.5V14a.5.5 0 1 1-1 0V8.5H2a.5.5 0 0 1 0-1h5.5V2a.5.5 0 0 1 1 0v5.5H14a.5.5 0 1 1 0 1H8.5z"/>
+  <path d="M8 8v5.5c0 .276-.224.5-.5.5s-.5-.224-.5-.5V8H1.5c-.276 0-.5-.224-.5-.5s.224-.5.5-.5H7V1.5c0-.276.224-.5.5-.5s.5.224.5.5V7h5.5c.276 0 .5.224.5.5s-.224.5-.5.5H8z"/>
 </svg>
--- a/devtools/server/actors/addon.js
+++ b/devtools/server/actors/addon.js
@@ -105,16 +105,25 @@ BrowserAddonActor.prototype = {
   },
 
   setOptions: function BAA_setOptions(aOptions) {
     if ("global" in aOptions) {
       this._global = aOptions.global;
     }
   },
 
+  onInstalled: function BAA_updateAddonWrapper(aAddon) {
+    if (aAddon.id != this._addon.id) {
+      return;
+    }
+
+    // Update the AddonManager's addon object on reload/update.
+    this._addon = aAddon;
+  },
+
   onDisabled: function BAA_onDisabled(aAddon) {
     if (aAddon != this._addon) {
       return;
     }
 
     this._global = null;
   },
 
--- a/devtools/server/actors/webbrowser.js
+++ b/devtools/server/actors/webbrowser.js
@@ -2288,21 +2288,16 @@ Object.defineProperty(BrowserAddonList.p
         "onListChanged property may only be set to 'null' or a function");
     }
     this._onListChanged = v;
     this._adjustListener();
   }
 });
 
 BrowserAddonList.prototype.onInstalled = function (addon) {
-  if (this._actorByAddonId.get(addon.id)) {
-    // When an add-on gets upgraded or reloaded, it will not be uninstalled
-    // so this step is necessary to clear the cache.
-    this._actorByAddonId.delete(addon.id);
-  }
   this._notifyListChanged();
   this._adjustListener();
 };
 
 BrowserAddonList.prototype.onUninstalled = function (addon) {
   this._actorByAddonId.delete(addon.id);
   this._notifyListChanged();
   this._adjustListener();
new file mode 100644
--- /dev/null
+++ b/devtools/server/tests/unit/addons/web-extension-upgrade/manifest.json
@@ -0,0 +1,10 @@
+{
+  "manifest_version": 2,
+  "name": "Test Addons Actor Upgrade",
+  "version": "1.0",
+  "applications": {
+    "gecko": {
+      "id": "test-addons-actor@mozilla.org"
+    }
+  }
+}
--- a/devtools/server/tests/unit/test_addon_reload.js
+++ b/devtools/server/tests/unit/test_addon_reload.js
@@ -62,10 +62,37 @@ add_task(function* testReloadExitedAddon
   installedAddon2.uninstall();
   const [uninstalledAddon] = yield onUninstalled;
 
   // Try to re-list all add-ons after a reload.
   // This was throwing an exception because of the exited actor.
   const newAddonActor = yield findAddonInRootList(client, installedAddon.id);
   equal(newAddonActor.id, addonActor.id);
 
+  // The actor id should be the same after the reload
+  equal(newAddonActor.actor, addonActor.actor);
+
+  const onAddonListChanged = new Promise((resolve) => {
+    client.addListener("addonListChanged", function listener() {
+      client.removeListener("addonListChanged", listener);
+      resolve();
+    });
+  });
+
+  // Install an upgrade version of the first add-on.
+  const addonUpgradeFile = getSupportFile("addons/web-extension-upgrade");
+  const upgradedAddon = yield AddonManager.installTemporaryAddon(
+    addonUpgradeFile);
+
+  // Waiting for addonListChanged unsolicited event
+  yield onAddonListChanged;
+
+  // re-list all add-ons after an upgrade.
+  const upgradedAddonActor = yield findAddonInRootList(client, upgradedAddon.id);
+  equal(upgradedAddonActor.id, addonActor.id);
+  // The actor id should be the same after the upgrade.
+  equal(upgradedAddonActor.actor, addonActor.actor);
+
+  // The addon metadata has been updated.
+  equal(upgradedAddonActor.name, "Test Addons Actor Upgrade");
+
   yield close(client);
 });
--- a/devtools/server/tests/unit/xpcshell.ini
+++ b/devtools/server/tests/unit/xpcshell.ini
@@ -26,16 +26,17 @@ support-files =
   setBreakpoint-on-column-with-no-offsets-in-gcd-script.js
   setBreakpoint-on-line.js
   setBreakpoint-on-line-in-gcd-script.js
   setBreakpoint-on-line-with-multiple-offsets.js
   setBreakpoint-on-line-with-multiple-statements.js
   setBreakpoint-on-line-with-no-offsets.js
   setBreakpoint-on-line-with-no-offsets-in-gcd-script.js
   addons/web-extension/manifest.json
+  addons/web-extension-upgrade/manifest.json
   addons/web-extension2/manifest.json
 
 [test_addon_reload.js]
 [test_addons_actor.js]
 [test_animation_name.js]
 [test_animation_type.js]
 [test_actor-registry-actor.js]
 [test_nesting-01.js]
--- a/dom/animation/ComputedTimingFunction.cpp
+++ b/dom/animation/ComputedTimingFunction.cpp
@@ -14,17 +14,16 @@ void
 ComputedTimingFunction::Init(const nsTimingFunction &aFunction)
 {
   mType = aFunction.mType;
   if (nsTimingFunction::IsSplineType(mType)) {
     mTimingFunction.Init(aFunction.mFunc.mX1, aFunction.mFunc.mY1,
                          aFunction.mFunc.mX2, aFunction.mFunc.mY2);
   } else {
     mSteps = aFunction.mSteps;
-    mStepSyntax = aFunction.mStepSyntax;
   }
 }
 
 static inline double
 StepTiming(uint32_t aSteps,
            double aPortion,
            ComputedTimingFunction::BeforeFlag aBeforeFlag,
            nsTimingFunction::Type aType)
@@ -136,19 +135,16 @@ ComputedTimingFunction::Compare(const Co
     if (order != 0) {
       return order;
     }
   } else if (mType == nsTimingFunction::Type::StepStart ||
              mType == nsTimingFunction::Type::StepEnd) {
     if (mSteps != aRhs.mSteps) {
       return int32_t(mSteps) - int32_t(aRhs.mSteps);
     }
-    if (mStepSyntax != aRhs.mStepSyntax) {
-      return int32_t(mStepSyntax) - int32_t(aRhs.mStepSyntax);
-    }
   }
 
   return 0;
 }
 
 void
 ComputedTimingFunction::AppendToString(nsAString& aResult) const
 {
@@ -157,18 +153,17 @@ ComputedTimingFunction::AppendToString(n
       nsStyleUtil::AppendCubicBezierTimingFunction(mTimingFunction.X1(),
                                                    mTimingFunction.Y1(),
                                                    mTimingFunction.X2(),
                                                    mTimingFunction.Y2(),
                                                    aResult);
       break;
     case nsTimingFunction::Type::StepStart:
     case nsTimingFunction::Type::StepEnd:
-      nsStyleUtil::AppendStepsTimingFunction(mType, mSteps, mStepSyntax,
-                                             aResult);
+      nsStyleUtil::AppendStepsTimingFunction(mType, mSteps, aResult);
       break;
     default:
       nsStyleUtil::AppendCubicBezierKeywordTimingFunction(mType, aResult);
       break;
   }
 }
 
 /* static */ int32_t
--- a/dom/animation/ComputedTimingFunction.h
+++ b/dom/animation/ComputedTimingFunction.h
@@ -26,24 +26,22 @@ public:
   const nsSMILKeySpline* GetFunction() const
   {
     NS_ASSERTION(HasSpline(), "Type mismatch");
     return &mTimingFunction;
   }
   nsTimingFunction::Type GetType() const { return mType; }
   bool HasSpline() const { return nsTimingFunction::IsSplineType(mType); }
   uint32_t GetSteps() const { return mSteps; }
-  nsTimingFunction::StepSyntax GetStepSyntax() const { return mStepSyntax; }
   bool operator==(const ComputedTimingFunction& aOther) const
   {
     return mType == aOther.mType &&
            (HasSpline() ?
             mTimingFunction == aOther.mTimingFunction :
-            (mSteps == aOther.mSteps &&
-             mStepSyntax == aOther.mStepSyntax));
+            mSteps == aOther.mSteps);
   }
   bool operator!=(const ComputedTimingFunction& aOther) const
   {
     return !(*this == aOther);
   }
   int32_t Compare(const ComputedTimingFunction& aRhs) const;
   void AppendToString(nsAString& aResult) const;
 
@@ -55,14 +53,13 @@ public:
   }
   static int32_t Compare(const Maybe<ComputedTimingFunction>& aLhs,
                          const Maybe<ComputedTimingFunction>& aRhs);
 
 private:
   nsTimingFunction::Type mType;
   nsSMILKeySpline mTimingFunction;
   uint32_t mSteps;
-  nsTimingFunction::StepSyntax mStepSyntax;
 };
 
 } // namespace mozilla
 
 #endif // mozilla_ComputedTimingFunction_h
--- a/dom/animation/test/css-animations/file_keyframeeffect-getkeyframes.html
+++ b/dom/animation/test/css-animations/file_keyframeeffect-getkeyframes.html
@@ -166,26 +166,22 @@ function assert_frames_equal(a, b, name)
 // getKeyframes() will group frames with the same easing function
 // together (by nsTimingFunction::Compare).
 const kTimingFunctionValues = [
   "ease",
   "linear",
   "ease-in",
   "ease-out",
   "ease-in-out",
-  "step-start",
   "steps(1, start)",
   "steps(2, start)",
-  "step-end",
   "steps(1)",
-  "steps(1, end)",
   "steps(2)",
-  "steps(2, end)",
   "cubic-bezier(0, 0, 1, 1)",
-  "cubic-bezier(0, 0.25, 0.75, 1)",
+  "cubic-bezier(0, 0.25, 0.75, 1)"
 ];
 
 test(function(t) {
   var div = addDiv(t);
 
   div.style.animation = 'anim-empty 100s';
   assert_equals(getKeyframes(div).length, 0,
                 "number of frames with empty @keyframes");
@@ -251,33 +247,33 @@ test(function(t) {
   div.style.animation = 'anim-simple-timing 100s';
   var frames = getKeyframes(div);
 
   assert_equals(frames.length, 3, "number of frames");
   assert_equals(frames[0].easing, "linear",
                 "value of 'easing' on ComputedKeyframe #0");
   assert_equals(frames[1].easing, "ease-in-out",
                 "value of 'easing' on ComputedKeyframe #1");
-  assert_equals(frames[2].easing, "step-end",
+  assert_equals(frames[2].easing, "steps(1)",
                 "value of 'easing' on ComputedKeyframe #2");
 }, 'KeyframeEffectReadOnly.getKeyframes() returns frames with expected easing'
    + ' values, when the easing is specified on each keyframe');
 
 test(function(t) {
   var div = addDiv(t);
 
   div.style.animation = 'anim-simple-timing-some 100s step-start';
   var frames = getKeyframes(div);
 
   assert_equals(frames.length, 3, "number of frames");
   assert_equals(frames[0].easing, "linear",
                 "value of 'easing' on ComputedKeyframe #0");
-  assert_equals(frames[1].easing, "step-start",
+  assert_equals(frames[1].easing, "steps(1, start)",
                 "value of 'easing' on ComputedKeyframe #1");
-  assert_equals(frames[2].easing, "step-start",
+  assert_equals(frames[2].easing, "steps(1, start)",
                 "value of 'easing' on ComputedKeyframe #2");
 }, 'KeyframeEffectReadOnly.getKeyframes() returns frames with expected easing'
    + ' values, when the easing is specified on some keyframes');
 
 test(function(t) {
   var div = addDiv(t);
 
   div.style.animation = 'anim-simple-shorthand 100s';
@@ -423,17 +419,17 @@ test(function(t) {
   div.style.animation = 'anim-different-props-and-easing 100s';
   var frames = getKeyframes(div);
 
   assert_equals(frames.length, 4, "number of frames");
 
   var expected = [
     { offset: 0, computedOffset: 0, easing: "linear",
       color: "rgb(0, 0, 0)", marginTop: "8px" },
-    { offset: 0.25, computedOffset: 0.25, easing: "step-end",
+    { offset: 0.25, computedOffset: 0.25, easing: "steps(1)",
       color: "rgb(0, 0, 255)" },
     { offset: 0.75, computedOffset: 0.75, easing: "ease-in",
       marginTop: "12px" },
     { offset: 1, computedOffset: 1, easing: "ease",
       color: "rgb(255, 255, 255)", marginTop: "16px" },
   ];
 
   for (var i = 0; i < frames.length; i++) {
@@ -469,17 +465,17 @@ test(function(t) {
   var div = addDiv(t);
 
   div.style.animation = 'anim-merge-offset-and-easing 100s';
   var frames = getKeyframes(div);
 
   assert_equals(frames.length, 3, "number of frames");
 
   var expected = [
-    { offset: 0, computedOffset: 0, easing: "step-end",
+    { offset: 0, computedOffset: 0, easing: "steps(1)",
       color: "rgb(0, 0, 0)", fontSize: "16px" },
     { offset: 0, computedOffset: 0, easing: "linear",
       marginTop: "8px", paddingLeft: "2px" },
     { offset: 1, computedOffset: 1, easing: "ease",
       color: "rgb(255, 255, 255)", fontSize: "32px", marginTop: "16px",
       paddingLeft: "4px" },
   ];
 
@@ -491,26 +487,22 @@ test(function(t) {
    'different easing functions');
 
 test(function(t) {
   var div = addDiv(t);
 
   div.style.animation = 'anim-no-merge-equiv-easing 100s';
   var frames = getKeyframes(div);
 
-  assert_equals(frames.length, 5, "number of frames");
+  assert_equals(frames.length, 3, "number of frames");
 
   var expected = [
-    { offset: 0, computedOffset: 0, easing: "steps(1, end)",
-      marginTop: "0px" },
-    { offset: 0, computedOffset: 0, easing: "step-end",
-      marginRight: "0px" },
     { offset: 0, computedOffset: 0, easing: "steps(1)",
-      marginBottom: "0px" },
-    { offset: 0.5, computedOffset: 0.5, easing: "step-end",
+      marginTop: "0px", marginRight: "0px", marginBottom: "0px" },
+    { offset: 0.5, computedOffset: 0.5, easing: "steps(1)",
       marginTop: "10px", marginRight: "10px", marginBottom: "10px" },
     { offset: 1, computedOffset: 1, easing: "ease",
       marginTop: "20px", marginRight: "20px", marginBottom: "20px" },
   ];
 
   for (var i = 0; i < frames.length; i++) {
     assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
   }
@@ -670,12 +662,11 @@ test(function(t) {
       marginRight: "100px",
       marginTop: "100px" },
   ];
   for (var i = 0; i < frames.length; i++) {
     assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
   }
 }, 'KeyframeEffectReadOnly.getKeyframes() returns expected values for ' +
    'animations with CSS variables as keyframe values in a shorthand property');
-
 done();
 </script>
 </body>
--- a/dom/animation/test/css-transitions/file_keyframeeffect-getkeyframes.html
+++ b/dom/animation/test/css-transitions/file_keyframeeffect-getkeyframes.html
@@ -54,17 +54,17 @@ test(function(t) {
   div.style.transition = 'left 100s steps(2,end)';
   div.style.left = '100px';
 
   var frames = getKeyframes(div);
 
   assert_equals(frames.length, 2, "number of frames");
 
   var expected = [
-    { offset: 0, computedOffset: 0, easing: "steps(2, end)", left: "0px" },
+    { offset: 0, computedOffset: 0, easing: "steps(2)", left: "0px" },
     { offset: 1, computedOffset: 1, easing: "linear", left: "100px" },
   ];
 
   for (var i = 0; i < frames.length; i++) {
     assert_frames_equal(frames[i], expected[i], "ComputedKeyframe #" + i);
   }
 }, 'KeyframeEffectReadOnly.getKeyframes() returns expected frames for a simple'
    + ' transition with a non-default easing function');
--- a/dom/base/nsHostObjectURI.cpp
+++ b/dom/base/nsHostObjectURI.cpp
@@ -156,21 +156,22 @@ nsHostObjectURI::SetScheme(const nsACStr
   // with a different protocol handler that doesn't expect us to be carrying
   // around a principal with nsIURIWithPrincipal.
   return NS_ERROR_FAILURE;
 }
 
 // nsIURI methods:
 nsresult
 nsHostObjectURI::CloneInternal(mozilla::net::nsSimpleURI::RefHandlingEnum aRefHandlingMode,
+                               const nsACString& newRef,
                                nsIURI** aClone)
 {
   nsCOMPtr<nsIURI> simpleClone;
   nsresult rv =
-    mozilla::net::nsSimpleURI::CloneInternal(aRefHandlingMode, getter_AddRefs(simpleClone));
+    mozilla::net::nsSimpleURI::CloneInternal(aRefHandlingMode, newRef, getter_AddRefs(simpleClone));
   NS_ENSURE_SUCCESS(rv, rv);
 
 #ifdef DEBUG
   RefPtr<nsHostObjectURI> uriCheck;
   rv = simpleClone->QueryInterface(kHOSTOBJECTURICID, getter_AddRefs(uriCheck));
   MOZ_ASSERT(NS_SUCCEEDED(rv) && uriCheck);
 #endif
 
--- a/dom/base/nsHostObjectURI.h
+++ b/dom/base/nsHostObjectURI.h
@@ -44,24 +44,30 @@ public:
   NS_DECL_NSISERIALIZABLE
   NS_DECL_NSICLASSINFO
   NS_DECL_NSIIPCSERIALIZABLEURI
 
   NS_IMETHOD SetScheme(const nsACString &aProtocol) override;
 
   // Override CloneInternal() and EqualsInternal()
   virtual nsresult CloneInternal(RefHandlingEnum aRefHandlingMode,
+                                 const nsACString& newRef,
                                  nsIURI** aClone) override;
   virtual nsresult EqualsInternal(nsIURI* aOther,
                                   RefHandlingEnum aRefHandlingMode,
                                   bool* aResult) override;
 
   // Override StartClone to hand back a nsHostObjectURI
-  virtual mozilla::net::nsSimpleURI* StartClone(RefHandlingEnum /* unused */) override
-  { return new nsHostObjectURI(); }
+  virtual mozilla::net::nsSimpleURI* StartClone(RefHandlingEnum refHandlingMode,
+                                                const nsACString& newRef) override
+  {
+    nsHostObjectURI* url = new nsHostObjectURI();
+    SetRefOnClone(url, refHandlingMode, newRef);
+    return url;
+  }
 
   nsCOMPtr<nsIPrincipal> mPrincipal;
   RefPtr<mozilla::dom::BlobImpl> mBlobImpl;
 
 protected:
   virtual ~nsHostObjectURI() {}
 };
 
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -25,16 +25,17 @@
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/HTMLVideoElement.h"
 #include "mozilla/dom/ImageData.h"
 #include "mozilla/dom/WebGLContextEvent.h"
 #include "mozilla/EnumeratedArrayCycleCollection.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ProcessPriorityManager.h"
+#include "mozilla/ScopeExit.h"
 #include "mozilla/Services.h"
 #include "mozilla/Telemetry.h"
 #include "nsContentUtils.h"
 #include "nsDisplayList.h"
 #include "nsError.h"
 #include "nsIClassInfoImpl.h"
 #include "nsIConsoleService.h"
 #include "nsIDOMEvent.h"
@@ -848,16 +849,20 @@ WebGLContext::ThrowEvent_WebGLContextCre
 
     GenerateWarning("Failed to create WebGL context: %s", text.BeginReading());
 }
 
 NS_IMETHODIMP
 WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight)
 {
     if (signedWidth < 0 || signedHeight < 0) {
+        if (!gl) {
+            Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID,
+                                  NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_SIZE"));
+        }
         GenerateWarning("Canvas size is too large (seems like a negative value wrapped)");
         return NS_ERROR_OUT_OF_MEMORY;
     }
 
     uint32_t width = signedWidth;
     uint32_t height = signedHeight;
 
     // Early success return cases
@@ -903,16 +908,22 @@ WebGLContext::SetDimensions(int32_t sign
 
         // everything's good, we're done here
         mResetLayer = true;
         mBackbufferNeedsClear = true;
 
         return NS_OK;
     }
 
+    nsCString failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_UNKOWN");
+    auto autoTelemetry = mozilla::MakeScopeExit([&] {
+        Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID,
+                              failureId);
+    });
+
     // End of early return cases.
     // At this point we know that we're not just resizing an existing context,
     // we are initializing a new context.
 
     // if we exceeded either the global or the per-principal limit for WebGL contexts,
     // lose the oldest-used context now to free resources. Note that we can't do that
     // in the WebGLContext constructor as we don't have a canvas element yet there.
     // Here is the right place to do so, as we are about to create the OpenGL context
@@ -924,50 +935,47 @@ WebGLContext::SetDimensions(int32_t sign
     // context we're creating), we may have to dispatch a context lost
     // event.
 
     // If incrementing the generation would cause overflow,
     // don't allow it.  Allowing this would allow us to use
     // resource handles created from older context generations.
     if (!(mGeneration + 1).isValid()) {
         // exit without changing the value of mGeneration
-        Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID,
-                              NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_TOO_MANY"));
+        failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_TOO_MANY");
         const nsLiteralCString text("Too many WebGL contexts created this run.");
         ThrowEvent_WebGLContextCreationError(text);
         return NS_ERROR_FAILURE;
     }
 
     // increment the generation number - Do this early because later
     // in CreateOffscreenGL(), "default" objects are created that will
     // pick up the old generation.
     ++mGeneration;
 
     bool disabled = gfxPrefs::WebGLDisabled();
 
     // TODO: When we have software webgl support we should use that instead.
     disabled |= gfxPlatform::InSafeMode();
 
     if (disabled) {
-        Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID,
-                              NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_DISABLED"));
+        failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_DISABLED");
         const nsLiteralCString text("WebGL is currently disabled.");
         ThrowEvent_WebGLContextCreationError(text);
         return NS_ERROR_FAILURE;
     }
 
     if (gfxPrefs::WebGLDisableFailIfMajorPerformanceCaveat()) {
         mOptions.failIfMajorPerformanceCaveat = false;
     }
 
     if (mOptions.failIfMajorPerformanceCaveat) {
         nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
         if (!HasAcceleratedLayers(gfxInfo)) {
-            Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID,
-                                  NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_PERF_CAVEAT"));
+            failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_PERF_CAVEAT");
             const nsLiteralCString text("failIfMajorPerformanceCaveat: Compositor is not"
                                         " hardware-accelerated.");
             ThrowEvent_WebGLContextCreationError(text);
             return NS_ERROR_FAILURE;
         }
     }
 
     // Alright, now let's start trying.
@@ -979,52 +987,52 @@ WebGLContext::SetDimensions(int32_t sign
     if (!CreateAndInitGL(forceEnabled, &failReasons)) {
         nsCString text("WebGL creation failed: ");
         for (const auto& cur : failReasons) {
             Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID, cur.key);
 
             text.AppendASCII("\n* ");
             text.Append(cur.info);
         }
+        failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_REASON");
         ThrowEvent_WebGLContextCreationError(text);
         return NS_ERROR_FAILURE;
     }
     MOZ_ASSERT(gl);
     MOZ_ASSERT_IF(mOptions.alpha, gl->Caps().alpha);
 
     if (mOptions.failIfMajorPerformanceCaveat) {
         if (gl->IsWARP()) {
             DestroyResourcesAndContext();
             MOZ_ASSERT(!gl);
 
-            Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID,
-                                  NS_LITERAL_CSTRING("FEATURE_FAILURE_PERF_WARP"));
+            failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_PERF_WARP");
             const nsLiteralCString text("failIfMajorPerformanceCaveat: Driver is not"
                                         " hardware-accelerated.");
             ThrowEvent_WebGLContextCreationError(text);
             return NS_ERROR_FAILURE;
         }
 
 #ifdef XP_WIN
         if (gl->GetContextType() == gl::GLContextType::WGL &&
             !gl::sWGLLib.HasDXInterop2())
         {
             DestroyResourcesAndContext();
             MOZ_ASSERT(!gl);
 
+            failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_DXGL_INTEROP2");
             const nsLiteralCString text("Caveat: WGL without DXGLInterop2.");
             ThrowEvent_WebGLContextCreationError(text);
             return NS_ERROR_FAILURE;
         }
 #endif
     }
 
     if (!ResizeBackbuffer(width, height)) {
-        Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID,
-                              NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_RESIZE"));
+        failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_BACKBUFFER");
         const nsLiteralCString text("Initializing WebGL backbuffer failed.");
         ThrowEvent_WebGLContextCreationError(text);
         return NS_ERROR_FAILURE;
     }
 
     if (GLContext::ShouldSpew()) {
         printf_stderr("--- WebGL context created: %p\n", gl.get());
     }
@@ -1099,18 +1107,17 @@ WebGLContext::SetDimensions(int32_t sign
     ClearBackbufferIfNeeded();
 
     mShouldPresent = true;
 
     //////
 
     reporter.SetSuccessful();
 
-    Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID,
-                          NS_LITERAL_CSTRING("SUCCESS"));
+    failureId = NS_LITERAL_CSTRING("SUCCESS");
     return NS_OK;
 }
 
 void
 WebGLContext::ClearBackbufferIfNeeded()
 {
     if (!mBackbufferNeedsClear)
         return;
--- a/dom/jsurl/nsJSProtocolHandler.cpp
+++ b/dom/jsurl/nsJSProtocolHandler.cpp
@@ -1357,28 +1357,31 @@ nsJSURI::Deserialize(const mozilla::ipc:
     } else {
         mBaseURI = nullptr;
     }
     return true;
 }
 
 // nsSimpleURI methods:
 /* virtual */ mozilla::net::nsSimpleURI*
-nsJSURI::StartClone(mozilla::net::nsSimpleURI::RefHandlingEnum /* ignored */)
+nsJSURI::StartClone(mozilla::net::nsSimpleURI::RefHandlingEnum refHandlingMode,
+                    const nsACString& newRef)
 {
     nsCOMPtr<nsIURI> baseClone;
     if (mBaseURI) {
       // Note: We preserve ref on *base* URI, regardless of ref handling mode.
       nsresult rv = mBaseURI->Clone(getter_AddRefs(baseClone));
       if (NS_FAILED(rv)) {
         return nullptr;
       }
     }
 
-    return new nsJSURI(baseClone);
+    nsJSURI* url = new nsJSURI(baseClone);
+    SetRefOnClone(url, refHandlingMode, newRef);
+    return url;
 }
 
 /* virtual */ nsresult
 nsJSURI::EqualsInternal(nsIURI* aOther,
                         mozilla::net::nsSimpleURI::RefHandlingEnum aRefHandlingMode,
                         bool* aResult)
 {
     NS_ENSURE_ARG_POINTER(aOther);
--- a/dom/jsurl/nsJSProtocolHandler.h
+++ b/dom/jsurl/nsJSProtocolHandler.h
@@ -74,17 +74,18 @@ public:
     nsIURI* GetBaseURI() const
     {
         return mBaseURI;
     }
 
     NS_DECL_ISUPPORTS_INHERITED
 
     // nsIURI overrides
-    virtual mozilla::net::nsSimpleURI* StartClone(RefHandlingEnum refHandlingMode) override;
+    virtual mozilla::net::nsSimpleURI* StartClone(RefHandlingEnum refHandlingMode,
+                                                  const nsACString& newRef) override;
 
     // nsISerializable overrides
     NS_IMETHOD Read(nsIObjectInputStream* aStream) override;
     NS_IMETHOD Write(nsIObjectOutputStream* aStream) override;
 
     // nsIIPCSerializableURI overrides
     NS_DECL_NSIIPCSERIALIZABLEURI
 
--- a/dom/media/eme/CDMCaps.cpp
+++ b/dom/media/eme/CDMCaps.cpp
@@ -48,16 +48,17 @@ CDMCaps::AutoLock::IsKeyUsable(const Cen
 {
   mData.mMonitor.AssertCurrentThreadOwns();
   const auto& keys = mData.mKeyStatuses;
   for (size_t i = 0; i < keys.Length(); i++) {
     if (keys[i].mId != aKeyId) {
       continue;
     }
     if (keys[i].mStatus == kGMPUsable ||
+        keys[i].mStatus == kGMPOutputRestricted ||
         keys[i].mStatus == kGMPOutputDownscaled) {
       return true;
     }
   }
   return false;
 }
 
 bool
--- a/dom/media/platforms/PDMFactory.cpp
+++ b/dom/media/platforms/PDMFactory.cpp
@@ -24,16 +24,17 @@
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidDecoderModule.h"
 #endif
 #include "GMPDecoderModule.h"
 
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/SharedThreadPool.h"
 #include "mozilla/StaticPtr.h"
+#include "mozilla/SyncRunnable.h"
 #include "mozilla/TaskQueue.h"
 
 #include "MediaInfo.h"
 #include "MediaPrefs.h"
 #include "FuzzingWrapper.h"
 #include "H264Converter.h"
 
 #include "AgnosticDecoderModule.h"
@@ -82,27 +83,41 @@ PDMFactory::PDMFactory()
 
 PDMFactory::~PDMFactory()
 {
 }
 
 void
 PDMFactory::EnsureInit() const
 {
-  StaticMutexAutoLock mon(sMonitor);
-  if (!sInstance) {
-    sInstance = new PDMFactoryImpl();
+  {
+    StaticMutexAutoLock mon(sMonitor);
+    if (sInstance) {
+      // Quick exit if we already have an instance.
+      return;
+    }
     if (NS_IsMainThread()) {
+      // On the main thread and holding the lock -> Create instance.
+      sInstance = new PDMFactoryImpl();
       ClearOnShutdown(&sInstance);
-    } else {
-      nsCOMPtr<nsIRunnable> runnable =
-        NS_NewRunnableFunction([]() { ClearOnShutdown(&sInstance); });
-      NS_DispatchToMainThread(runnable);
+      return;
     }
   }
+
+  // Not on the main thread -> Sync-dispatch creation to main thread.
+  nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
+  nsCOMPtr<nsIRunnable> runnable =
+    NS_NewRunnableFunction([]() {
+      StaticMutexAutoLock mon(sMonitor);
+      if (!sInstance) {
+        sInstance = new PDMFactoryImpl();
+        ClearOnShutdown(&sInstance);
+      }
+    });
+  SyncRunnable::DispatchToThread(mainThread, runnable);
 }
 
 already_AddRefed<MediaDataDecoder>
 PDMFactory::CreateDecoder(const CreateDecoderParams& aParams)
 {
   const TrackInfo& config = aParams.mConfig;
   bool isEncrypted = mEMEPDM && config.mCrypto.mValid;
 
--- a/dom/media/platforms/agnostic/gmp/GMPDecoderModule.cpp
+++ b/dom/media/platforms/agnostic/gmp/GMPDecoderModule.cpp
@@ -8,17 +8,16 @@
 #include "DecoderDoctorDiagnostics.h"
 #include "GMPAudioDecoder.h"
 #include "GMPVideoDecoder.h"
 #include "MediaDataDecoderProxy.h"
 #include "MediaPrefs.h"
 #include "mozIGeckoMediaPluginService.h"
 #include "nsServiceManagerUtils.h"
 #include "mozilla/StaticMutex.h"
-#include "mozilla/SyncRunnable.h"
 #include "gmp-audio-decode.h"
 #include "gmp-video-decode.h"
 #ifdef XP_WIN
 #include "WMFDecoderModule.h"
 #endif
 
 namespace mozilla {
 
@@ -164,23 +163,17 @@ GMPDecoderModule::UpdateUsableCodecs()
                              nsDependentCString(gmp.mKeySystem));
   }
 }
 
 /* static */
 void
 GMPDecoderModule::Init()
 {
-  if (!NS_IsMainThread()) {
-    nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
-    nsCOMPtr<nsIRunnable> runnable =
-      NS_NewRunnableFunction([]() { Init(); });
-    SyncRunnable::DispatchToThread(mainThread, runnable);
-    return;
-  }
+  MOZ_ASSERT(NS_IsMainThread());
   // GMPService::HasPluginForAPI is main thread only, so to implement
   // SupportsMimeType() we build a table of the codecs which each whitelisted
   // GMP has and update it when any GMPs are removed or added at runtime.
   UpdateUsableCodecs();
 }
 
 /* static */
 const Maybe<nsCString>
--- a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp
+++ b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <algorithm>
+#include <winsdkver.h>
 #include "WMFVideoMFTManager.h"
 #include "MediaDecoderReader.h"
 #include "MediaPrefs.h"
 #include "WMFUtils.h"
 #include "ImageContainer.h"
 #include "VideoUtils.h"
 #include "DXVA2Manager.h"
 #include "nsThreadUtils.h"
@@ -32,17 +33,17 @@
 
 #define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
 
 using mozilla::layers::Image;
 using mozilla::layers::IMFYCbCrImage;
 using mozilla::layers::LayerManager;
 using mozilla::layers::LayersBackend;
 
-#if MOZ_WINSDK_MAXVER < 0x0A000000
+#if WINVER_MAXVER < 0x0A00
 // Windows 10+ SDK has VP80 and VP90 defines
 const GUID MFVideoFormat_VP80 =
 {
   0x30385056,
   0x0000,
   0x0010,
   {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
 };
--- a/embedding/browser/nsDocShellTreeOwner.cpp
+++ b/embedding/browser/nsDocShellTreeOwner.cpp
@@ -1118,16 +1118,18 @@ NS_IMPL_ISUPPORTS(ChromeTooltipListener,
 
 ChromeTooltipListener::ChromeTooltipListener(nsWebBrowser* aInBrowser,
                                              nsIWebBrowserChrome* aInChrome)
   : mWebBrowser(aInBrowser)
   , mWebBrowserChrome(aInChrome)
   , mTooltipListenerInstalled(false)
   , mMouseClientX(0)
   , mMouseClientY(0)
+  , mMouseScreenX(0)
+  , mMouseScreenY(0)
   , mShowingTooltip(false)
   , mTooltipShownOnce(false)
 {
   mTooltipTextProvider = do_GetService(NS_TOOLTIPTEXTPROVIDER_CONTRACTID);
   if (!mTooltipTextProvider) {
     mTooltipTextProvider = do_GetService(NS_DEFAULTTOOLTIPTEXTPROVIDER_CONTRACTID);
   }
 }
--- a/gfx/layers/ipc/LayerAnimationUtils.cpp
+++ b/gfx/layers/ipc/LayerAnimationUtils.cpp
@@ -25,18 +25,17 @@ AnimationUtils::TimingFunctionToComputed
       return Some(result);
     }
     case TimingFunction::TStepFunction: {
       StepFunction sf = aTimingFunction.get_StepFunction();
       nsTimingFunction::Type type = sf.type() == 1 ?
         nsTimingFunction::Type::StepStart :
         nsTimingFunction::Type::StepEnd;
       ComputedTimingFunction result;
-      result.Init(nsTimingFunction(type, sf.steps(),
-                  nsTimingFunction::Keyword::Explicit));
+      result.Init(nsTimingFunction(type, sf.steps()));
       return Some(result);
     }
     default:
       MOZ_ASSERT_UNREACHABLE(
         "Function must be null, bezier or step");
       break;
   }
   return Nothing();
--- a/image/decoders/icon/nsIconURI.cpp
+++ b/image/decoders/icon/nsIconURI.cpp
@@ -450,16 +450,25 @@ NS_IMETHODIMP
 nsMozIconURI::CloneIgnoringRef(nsIURI** result)
 {
   // GetRef/SetRef not supported by nsMozIconURI, so
   // CloneIgnoringRef() is the same as Clone().
   return Clone(result);
 }
 
 NS_IMETHODIMP
+nsMozIconURI::CloneWithNewRef(const nsACString& newRef, nsIURI** result)
+{
+  // GetRef/SetRef not supported by nsMozIconURI, so
+  // CloneWithNewRef() is the same as Clone().
+  return Clone(result);
+}
+
+
+NS_IMETHODIMP
 nsMozIconURI::Resolve(const nsACString& relativePath, nsACString& result)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsMozIconURI::GetAsciiSpec(nsACString& aSpecA)
 {
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -725,16 +725,24 @@ GeckoChildProcessHost::PerformAsyncLaunc
   // we split the logic here.
 
 #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_BSD)
   base::environment_map newEnvVars;
   ChildPrivileges privs = mPrivileges;
   if (privs == base::PRIVILEGES_DEFAULT) {
     privs = DefaultChildPrivileges();
   }
+
+#if defined(MOZ_WIDGET_GTK)
+  if (mProcessType == GeckoProcessType_Content) {
+    // disable IM module to avoid sandbox violation
+    newEnvVars["GTK_IM_MODULE"] = "gtk-im-context-simple";
+  }
+#endif
+
   // XPCOM may not be initialized in some subprocesses.  We don't want
   // to initialize XPCOM just for the directory service, especially
   // since LD_LIBRARY_PATH is already set correctly in subprocesses
   // (meaning that we don't need to set that up in the environment).
   if (ShouldHaveDirectoryService()) {
     MOZ_ASSERT(gGREBinPath);
     nsCString path;
     NS_CopyUnicodeToNative(nsDependentString(gGREBinPath), path);
--- a/js/src/aclocal.m4
+++ b/js/src/aclocal.m4
@@ -18,17 +18,16 @@ builtin(include, ../../build/autoconf/mo
 builtin(include, ../../build/autoconf/lto.m4)dnl
 builtin(include, ../../build/autoconf/frameptr.m4)dnl
 builtin(include, ../../build/autoconf/compiler-opts.m4)dnl
 builtin(include, ../../build/autoconf/expandlibs.m4)dnl
 builtin(include, ../../build/autoconf/arch.m4)dnl
 builtin(include, ../../build/autoconf/android.m4)dnl
 builtin(include, ../../build/autoconf/zlib.m4)dnl
 builtin(include, ../../build/autoconf/linux.m4)dnl
-builtin(include, ../../build/autoconf/winsdk.m4)dnl
 builtin(include, ../../build/autoconf/icu.m4)dnl
 builtin(include, ../../build/autoconf/ffi.m4)dnl
 builtin(include, ../../build/autoconf/clang-plugin.m4)dnl
 builtin(include, ../../build/autoconf/alloc.m4)dnl
 builtin(include, ../../build/autoconf/jemalloc.m4)dnl
 builtin(include, ../../build/autoconf/sanitize.m4)dnl
 builtin(include, ../../build/autoconf/ios.m4)dnl
 
--- a/js/src/old-configure.in
+++ b/js/src/old-configure.in
@@ -48,18 +48,16 @@ dnl ====================================
 NSPR_VERSION=4
 NSPR_MINVER=4.9.2
 
 dnl Set the minimum version of toolkit libs used by mozilla
 dnl ========================================================
 WINDRES_VERSION=2.14.90
 W32API_VERSION=3.14
 
-MSMANIFEST_TOOL=
-
 dnl Set various checks
 dnl ========================================================
 MISSING_X=
 
 dnl Initialize the Pthread test variables early so they can be
 dnl  overridden by each platform.
 dnl ========================================================
 USE_PTHREADS=
@@ -144,36 +142,18 @@ MOZ_TOOL_VARIABLES
 
 AC_PROG_CPP
 AC_PROG_CXXCPP
 
 dnl Special win32 checks
 dnl ========================================================
 
 # Target the Windows 8.1 SDK by default
-WINSDK_TARGETVER=603
 WINVER=502
 
-MOZ_ARG_WITH_STRING(windows-version,
-[  --with-windows-version=WINSDK_TARGETVER
-                          Windows SDK version to target. Win8.1 (603) is
-                          currently the minimum supported version.],
-  WINSDK_TARGETVER=$withval)
-
-# Currently only version 603 is allowed
-case "$WINSDK_TARGETVER" in
-603)
-    MOZ_WINSDK_TARGETVER=0${WINSDK_TARGETVER}0000
-    ;;
-
-*)
-    AC_MSG_ERROR([Invalid value for --with-windows-version ($WINSDK_TARGETVER)]);
-    ;;
-esac
-
 case "$target" in
 *-mingw*)
     if test "$GCC" != "yes"; then
         # Check to see if we are really running in a msvc environemnt
         _WIN32_MSVC=1
 
         # Make sure compilers are valid
         CFLAGS="$CFLAGS -TC -nologo"
@@ -234,36 +214,16 @@ case "$target" in
             # See https://connect.microsoft.com/VisualStudio/feedback/details/1789709/visual-c-2015-runtime-broken-on-windows-server-2003-c-11-magic-statics
             CXXFLAGS="$CXXFLAGS -Zc:threadSafeInit-"
             ;;
         esac
         AC_SUBST(MSVS_VERSION)
         AC_SUBST(MSVC_C_RUNTIME_DLL)
         AC_SUBST(MSVC_CXX_RUNTIME_DLL)
 
-        dnl Ensure that mt.exe is 'Microsoft (R) Manifest Tool',
-        dnl not something else like "magnetic tape manipulation utility".
-        MT=${MT-mt.exe}
-        MSMT_TOOL=`${MT} 2>&1|grep 'Microsoft (R) Manifest Tool'`
-        if test -z "$MSMT_TOOL"; then
-          AC_MSG_ERROR([Microsoft (R) Manifest Tool must be in your \$PATH.])
-        fi
-
-        changequote(,)
-        _MSMT_VER_FILTER='s|.*[^!-~]\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*|\1|p'
-        changequote([,])
-        MSMANIFEST_TOOL_VERSION=`echo ${MSMT_TOOL}|sed -ne "$_MSMT_VER_FILTER"`
-        if test -z "$MSMANIFEST_TOOL_VERSION"; then
-          AC_MSG_WARN([Unknown version of the Microsoft (R) Manifest Tool.])
-        fi
-
-        MSMANIFEST_TOOL=1
-        unset MSMT_TOOL
-        AC_SUBST(MT)
-
         # Check linker version
         _LD_FULL_VERSION=`"${LD}" -v 2>&1 | sed -nre "$_MSVC_VER_FILTER"`
         _LD_MAJOR_VERSION=`echo ${_LD_FULL_VERSION} | $AWK -F\. '{ print $1 }'`
         if test "$_LD_MAJOR_VERSION" != "$_CC_SUITE"; then
             AC_MSG_ERROR([The linker major version, $_LD_FULL_VERSION,  does not match the compiler suite version, $_CC_SUITE.])
         fi
 
         INCREMENTAL_LINKER=1
@@ -304,33 +264,21 @@ case "$target" in
                 "$_WINDRES_MAJOR_VERSION" -eq "$WINDRES_MAJOR_VERSION" -a \
                 "$_WINDRES_MINOR_VERSION" -eq "$WINDRES_MINOR_VERSION" -a \
                 "$_WINDRES_RELEASE_VERSION" -lt "$WINDRES_RELEASE_VERSION"
         then
             AC_MSG_ERROR([windres version $WINDRES_VERSION or higher is required to build.])
         fi
     fi # !GNU_CC
 
-    MOZ_FIND_WINSDK_VERSION
     AC_DEFINE_UNQUOTED(WINVER,0x$WINVER)
     AC_DEFINE_UNQUOTED(_WIN32_WINNT,0x$WINVER)
     # Require OS features provided by IE 6.0 SP2 (XP SP2)
     AC_DEFINE_UNQUOTED(_WIN32_IE,0x0603)
 
-    # If the maximum version supported by this SDK is lower than the target
-    # version, error out
-    AC_MSG_CHECKING([for Windows SDK being recent enough])
-    if $PERL -e "exit(0x$MOZ_WINSDK_TARGETVER > $MOZ_WINSDK_MAXVER)"; then
-        AC_MSG_RESULT("yes")
-    else
-        AC_MSG_RESULT("no")
-        AC_MSG_ERROR([You are targeting Windows version 0x$MOZ_WINSDK_TARGETVER, but your SDK only supports up to version $MOZ_WINSDK_MAXVER. Install and use an updated SDK, or target a lower version using --with-windows-version. Alternatively, try running the Windows SDK Configuration Tool and selecting a newer SDK. See https://developer.mozilla.org/En/Windows_SDK_versions for more details on fixing this.])
-    fi
-
-    AC_DEFINE_UNQUOTED(MOZ_WINSDK_TARGETVER,0x$MOZ_WINSDK_TARGETVER)
     ;;
 esac
 
 if test -n "$_WIN32_MSVC"; then
     SKIP_PATH_CHECKS=1
     SKIP_COMPILER_CHECKS=1
     SKIP_LIBRARY_CHECKS=1
 
@@ -2453,17 +2401,16 @@ AC_SUBST(DLL_PREFIX)
 AC_SUBST(DLL_SUFFIX)
 AC_DEFINE_UNQUOTED(MOZ_DLL_SUFFIX, "$DLL_SUFFIX")
 AC_SUBST(LIB_SUFFIX)
 AC_SUBST(OBJ_SUFFIX)
 AC_SUBST(BIN_SUFFIX)
 AC_SUBST(IMPORT_LIB_SUFFIX)
 AC_SUBST(USE_N32)
 AC_SUBST(CC_VERSION)
-AC_SUBST(MSMANIFEST_TOOL)
 AC_SUBST(MOZ_LINKER)
 AC_SUBST(WIN32_CONSOLE_EXE_LDFLAGS)
 AC_SUBST(WIN32_GUI_EXE_LDFLAGS)
 
 AC_CHECK_FUNCS(posix_fadvise posix_fallocate)
 
 dnl Set various defines and substitutions
 dnl ========================================================
--- a/layout/generic/ReflowInput.cpp
+++ b/layout/generic/ReflowInput.cpp
@@ -1076,17 +1076,17 @@ struct nsHypotheticalPosition {
 static bool
 GetIntrinsicSizeFor(nsIFrame* aFrame, nsSize& aIntrinsicSize, nsIAtom* aFrameType)
 {
   // See if it is an image frame
   bool success = false;
 
   // Currently the only type of replaced frame that we can get the intrinsic
   // size for is an image frame
-  // XXX We should add back the GetReflowMetrics() function and one of the
+  // XXX We should add back the GetReflowOutput() function and one of the
   // things should be the intrinsic size...
   if (aFrameType == nsGkAtoms::imageFrame) {
     nsImageFrame* imageFrame = (nsImageFrame*)aFrame;
 
     if (NS_SUCCEEDED(imageFrame->GetIntrinsicImageSize(aIntrinsicSize))) {
       success = (aIntrinsicSize != nsSize(0, 0));
     }
   }
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -1230,40 +1230,40 @@ nsBlockFrame::Reflow(nsPresContext*     
   // contains a block (example: <LI>\n<P>... ). This is where
   // the second case can happen.
   if (HasOutsideBullet() && !mLines.empty() &&
       (mLines.front()->IsBlock() ||
        (0 == mLines.front()->BSize() &&
         mLines.front() != mLines.back() &&
         mLines.begin().next()->IsBlock()))) {
     // Reflow the bullet
-    ReflowOutput metrics(aReflowInput);
+    ReflowOutput reflowOutput(aReflowInput);
     // XXX Use the entire line when we fix bug 25888.
     nsLayoutUtils::LinePosition position;
     WritingMode wm = aReflowInput.GetWritingMode();
     bool havePosition = nsLayoutUtils::GetFirstLinePosition(wm, this,
                                                             &position);
     nscoord lineBStart = havePosition ?
       position.mBStart :
       reflowInput->ComputedLogicalBorderPadding().BStart(wm);
     nsIFrame* bullet = GetOutsideBullet();
-    ReflowBullet(bullet, state, metrics, lineBStart);
-    NS_ASSERTION(!BulletIsEmpty() || metrics.BSize(wm) == 0,
+    ReflowBullet(bullet, state, reflowOutput, lineBStart);
+    NS_ASSERTION(!BulletIsEmpty() || reflowOutput.BSize(wm) == 0,
                  "empty bullet took up space");
 
     if (havePosition && !BulletIsEmpty()) {
       // We have some lines to align the bullet with.  
 
       // Doing the alignment using the baseline will also cater for
       // bullets that are placed next to a child block (bug 92896)
     
       // Tall bullets won't look particularly nice here...
-      LogicalRect bbox = bullet->GetLogicalRect(wm, metrics.PhysicalSize());
-      bbox.BStart(wm) = position.mBaseline - metrics.BlockStartAscent();
-      bullet->SetRect(wm, bbox, metrics.PhysicalSize());
+      LogicalRect bbox = bullet->GetLogicalRect(wm, reflowOutput.PhysicalSize());
+      bbox.BStart(wm) = position.mBaseline - reflowOutput.BlockStartAscent();
+      bullet->SetRect(wm, bbox, reflowOutput.PhysicalSize());
     }
     // Otherwise just leave the bullet where it is, up against our
     // block-start padding.
   }
 
   CheckFloats(state);
 
   // Compute our final size
--- a/layout/generic/nsBulletFrame.cpp
+++ b/layout/generic/nsBulletFrame.cpp
@@ -670,22 +670,22 @@ nsBulletFrame::Reflow(nsPresContext* aPr
   aStatus = NS_FRAME_COMPLETE;
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aMetrics);
 }
 
 /* virtual */ nscoord
 nsBulletFrame::GetMinISize(nsRenderingContext *aRenderingContext)
 {
   WritingMode wm = GetWritingMode();
-  ReflowOutput metrics(wm);
-  DISPLAY_MIN_WIDTH(this, metrics.ISize(wm));
+  ReflowOutput reflowOutput(wm);
+  DISPLAY_MIN_WIDTH(this, reflowOutput.ISize(wm));
   LogicalMargin padding(wm);
-  GetDesiredSize(PresContext(), aRenderingContext, metrics, 1.0f, &padding);
-  metrics.ISize(wm) += padding.IStartEnd(wm);
-  return metrics.ISize(wm);
+  GetDesiredSize(PresContext(), aRenderingContext, reflowOutput, 1.0f, &padding);
+  reflowOutput.ISize(wm) += padding.IStartEnd(wm);
+  return reflowOutput.ISize(wm);
 }
 
 /* virtual */ nscoord
 nsBulletFrame::GetPrefISize(nsRenderingContext *aRenderingContext)
 {
   WritingMode wm = GetWritingMode();
   ReflowOutput metrics(wm);
   DISPLAY_PREF_WIDTH(this, metrics.ISize(wm));
--- a/layout/generic/nsFrameSetFrame.cpp
+++ b/layout/generic/nsFrameSetFrame.cpp
@@ -687,29 +687,29 @@ nsHTMLFramesetFrame::ReflowPlaceChild(ns
                                       nsSize&                  aSize,
                                       nsIntPoint*              aCellIndex)
 {
   // reflow the child
   ReflowInput reflowInput(aPresContext, aReflowInput, aChild,
                                 LogicalSize(aChild->GetWritingMode(), aSize));
   reflowInput.SetComputedWidth(std::max(0, aSize.width - reflowInput.ComputedPhysicalBorderPadding().LeftRight()));
   reflowInput.SetComputedHeight(std::max(0, aSize.height - reflowInput.ComputedPhysicalBorderPadding().TopBottom()));
-  ReflowOutput metrics(aReflowInput);
-  metrics.Width() = aSize.width;
-  metrics.Height() = aSize.height;
+  ReflowOutput reflowOutput(aReflowInput);
+  reflowOutput.Width() = aSize.width;
+  reflowOutput.Height() = aSize.height;
   nsReflowStatus status;
 
-  ReflowChild(aChild, aPresContext, metrics, reflowInput, aOffset.x,
+  ReflowChild(aChild, aPresContext, reflowOutput, reflowInput, aOffset.x,
               aOffset.y, 0, status);
   NS_ASSERTION(NS_FRAME_IS_COMPLETE(status), "bad status");
 
   // Place and size the child
-  metrics.Width() = aSize.width;
-  metrics.Height() = aSize.height;
-  FinishReflowChild(aChild, aPresContext, metrics, nullptr, aOffset.x, aOffset.y, 0);
+  reflowOutput.Width() = aSize.width;
+  reflowOutput.Height() = aSize.height;
+  FinishReflowChild(aChild, aPresContext, reflowOutput, nullptr, aOffset.x, aOffset.y, 0);
 }
 
 static
 nsFrameborder GetFrameBorderHelper(nsGenericHTMLElement* aContent)
 {
   if (nullptr != aContent) {
     const nsAttrValue* attr = aContent->GetParsedAttr(nsGkAtoms::frameborder);
     if (attr && attr->Type() == nsAttrValue::eEnum) {
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -2015,17 +2015,17 @@ public:
    * Otherwise, if the frame has the NS_FRAME_HAS_DIRTY_CHILDREN bit
    * set, then it is responsible for reflowing at least those
    * children that have NS_FRAME_HAS_DIRTY_CHILDREN or NS_FRAME_IS_DIRTY
    * set.
    *
    * If a difference in available size from the previous reflow causes
    * the frame's size to change, it should reflow descendants as needed.
    *
-   * @param aReflowMetrics <i>out</i> parameter where you should return the
+   * @param aReflowOutput <i>out</i> parameter where you should return the
    *          desired size and ascent/descent info. You should include any
    *          space you want for border/padding in the desired size you return.
    *
    *          It's okay to return a desired size that exceeds the avail
    *          size if that's the smallest you can be, i.e. it's your
    *          minimum size.
    *
    *          For an incremental reflow you are responsible for invalidating
@@ -2043,17 +2043,17 @@ public:
    *          still must return an accurate desired size. If you're a container
    *          you must <b>always</b> reflow at least one frame regardless of the
    *          available space
    *
    * @param aStatus a return value indicating whether the frame is complete
    *          and whether the next-in-flow is dirty and needs to be reflowed
    */
   virtual void Reflow(nsPresContext*           aPresContext,
-                      ReflowOutput&     aReflowMetrics,
+                      ReflowOutput&     aReflowOutput,
                       const ReflowInput& aReflowInput,
                       nsReflowStatus&          aStatus) = 0;
 
   /**
    * Post-reflow hook. After a frame is reflowed this method will be called
    * informing the frame that this reflow process is complete, and telling the
    * frame the status returned by the Reflow member function.
    *
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -919,38 +919,38 @@ nsLineLayout::ReflowFrame(nsIFrame* aFra
   if (mGotLineBox && IsPercentageAware(aFrame)) {
     mLineBox->DisableResizeReflowOptimization();
   }
 
   // Note that we don't bother positioning the frame yet, because we're probably
   // going to end up moving it when we do the block-direction alignment.
 
   // Adjust spacemanager coordinate system for the frame.
-  ReflowOutput metrics(lineWM);
+  ReflowOutput reflowOutput(lineWM);
 #ifdef DEBUG
-  metrics.ISize(lineWM) = nscoord(0xdeadbeef);
-  metrics.BSize(lineWM) = nscoord(0xdeadbeef);
+  reflowOutput.ISize(lineWM) = nscoord(0xdeadbeef);
+  reflowOutput.BSize(lineWM) = nscoord(0xdeadbeef);
 #endif
   nscoord tI = pfd->mBounds.LineLeft(lineWM, ContainerSize());
   nscoord tB = pfd->mBounds.BStart(lineWM);
   mFloatManager->Translate(tI, tB);
 
   int32_t savedOptionalBreakOffset;
   gfxBreakPriority savedOptionalBreakPriority;
   nsIFrame* savedOptionalBreakFrame =
     GetLastOptionalBreakPosition(&savedOptionalBreakOffset,
                                  &savedOptionalBreakPriority);
 
   if (!isText) {
-    aFrame->Reflow(mPresContext, metrics, *reflowInputHolder, aReflowStatus);
+    aFrame->Reflow(mPresContext, reflowOutput, *reflowInputHolder, aReflowStatus);
   } else {
     static_cast<nsTextFrame*>(aFrame)->
       ReflowText(*this, availableSpaceOnLine,
                  psd->mReflowInput->mRenderingContext->GetDrawTarget(),
-                 metrics, aReflowStatus);
+                 reflowOutput, aReflowStatus);
   }
 
   pfd->mJustificationInfo = mJustificationInfo;
   mJustificationInfo = JustificationInfo();
 
   // See if the frame is a placeholderFrame and if it is process
   // the float. At the same time, check if the frame has any non-collapsed-away
   // content.
@@ -1015,65 +1015,65 @@ nsLineLayout::ReflowFrame(nsIFrame* aFra
         isEmpty = pfd->mFrame->IsEmpty();
       }
     }
   }
   pfd->mIsEmpty = isEmpty;
 
   mFloatManager->Translate(-tI, -tB);
 
-  NS_ASSERTION(metrics.ISize(lineWM) >= 0, "bad inline size");
-  NS_ASSERTION(metrics.BSize(lineWM) >= 0,"bad block size");
-  if (metrics.ISize(lineWM) < 0) {
-    metrics.ISize(lineWM) = 0;
+  NS_ASSERTION(reflowOutput.ISize(lineWM) >= 0, "bad inline size");
+  NS_ASSERTION(reflowOutput.BSize(lineWM) >= 0,"bad block size");
+  if (reflowOutput.ISize(lineWM) < 0) {
+    reflowOutput.ISize(lineWM) = 0;
   }
-  if (metrics.BSize(lineWM) < 0) {
-    metrics.BSize(lineWM) = 0;
+  if (reflowOutput.BSize(lineWM) < 0) {
+    reflowOutput.BSize(lineWM) = 0;
   }
 
 #ifdef DEBUG
   // Note: break-before means ignore the reflow metrics since the
   // frame will be reflowed another time.
   if (!NS_INLINE_IS_BREAK_BEFORE(aReflowStatus)) {
-    if ((CRAZY_SIZE(metrics.ISize(lineWM)) ||
-         CRAZY_SIZE(metrics.BSize(lineWM))) &&
+    if ((CRAZY_SIZE(reflowOutput.ISize(lineWM)) ||
+         CRAZY_SIZE(reflowOutput.BSize(lineWM))) &&
         !LineContainerFrame()->GetParent()->IsCrazySizeAssertSuppressed()) {
       printf("nsLineLayout: ");
       nsFrame::ListTag(stdout, aFrame);
-      printf(" metrics=%d,%d!\n", metrics.Width(), metrics.Height());
+      printf(" metrics=%d,%d!\n", reflowOutput.Width(), reflowOutput.Height());
     }
-    if ((metrics.Width() == nscoord(0xdeadbeef)) ||
-        (metrics.Height() == nscoord(0xdeadbeef))) {
+    if ((reflowOutput.Width() == nscoord(0xdeadbeef)) ||
+        (reflowOutput.Height() == nscoord(0xdeadbeef))) {
       printf("nsLineLayout: ");
       nsFrame::ListTag(stdout, aFrame);
-      printf(" didn't set w/h %d,%d!\n", metrics.Width(), metrics.Height());
+      printf(" didn't set w/h %d,%d!\n", reflowOutput.Width(), reflowOutput.Height());
     }
   }
 #endif
 
   // Unlike with non-inline reflow, the overflow area here does *not*
   // include the accumulation of the frame's bounds and its inline
   // descendants' bounds. Nor does it include the outline area; it's
   // just the union of the bounds of any absolute children. That is
   // added in later by nsLineLayout::ReflowInlineFrames.
-  pfd->mOverflowAreas = metrics.mOverflowAreas;
+  pfd->mOverflowAreas = reflowOutput.mOverflowAreas;
 
-  pfd->mBounds.ISize(lineWM) = metrics.ISize(lineWM);
-  pfd->mBounds.BSize(lineWM) = metrics.BSize(lineWM);
+  pfd->mBounds.ISize(lineWM) = reflowOutput.ISize(lineWM);
+  pfd->mBounds.BSize(lineWM) = reflowOutput.BSize(lineWM);
 
   // Size the frame, but |RelativePositionFrames| will size the view.
   aFrame->SetRect(lineWM, pfd->mBounds, ContainerSizeForSpan(psd));
 
   // Tell the frame that we're done reflowing it
   aFrame->DidReflow(mPresContext,
                     isText ? nullptr : reflowInputHolder.ptr(),
                     nsDidReflowStatus::FINISHED);
 
   if (aMetrics) {
-    *aMetrics = metrics;
+    *aMetrics = reflowOutput;
   }
 
   if (!NS_INLINE_IS_BREAK_BEFORE(aReflowStatus)) {
     // If frame is complete and has a next-in-flow, we need to delete
     // them now. Do not do this when a break-before is signaled because
     // the frame is going to get reflowed again (and may end up wanting
     // a next-in-flow where it ends up).
     if (NS_FRAME_IS_COMPLETE(aReflowStatus)) {
@@ -1099,17 +1099,17 @@ nsLineLayout::ReflowFrame(nsIFrame* aFra
     // See if we can place the frame. If we can't fit it, then we
     // return now.
     bool optionalBreakAfterFits;
     NS_ASSERTION(isText ||
                  !reflowInputHolder->IsFloating(),
                  "How'd we get a floated inline frame? "
                  "The frame ctor should've dealt with this.");
     if (CanPlaceFrame(pfd, notSafeToBreak, continuingTextRun,
-                      savedOptionalBreakFrame != nullptr, metrics,
+                      savedOptionalBreakFrame != nullptr, reflowOutput,
                       aReflowStatus, &optionalBreakAfterFits)) {
       if (!isEmpty) {
         psd->mHasNonemptyContent = true;
         mLineIsEmpty = false;
         if (!pfd->mSpan) {
           // nonempty leaf content has been placed
           mLineAtStart = false;
         }
@@ -1117,17 +1117,17 @@ nsLineLayout::ReflowFrame(nsIFrame* aFra
           mHasRuby = true;
           SyncAnnotationBounds(pfd);
         }
       }
 
       // Place the frame, updating aBounds with the final size and
       // location.  Then apply the bottom+right margins (as
       // appropriate) to the frame.
-      PlaceFrame(pfd, metrics);
+      PlaceFrame(pfd, reflowOutput);
       PerSpanData* span = pfd->mSpan;
       if (span) {
         // The frame we just finished reflowing is an inline
         // container.  It needs its child frames aligned in the block direction,
         // so do most of it now.
         VerticalAlignFrames(span);
       }
       
--- a/layout/mathml/nsMathMLContainerFrame.cpp
+++ b/layout/mathml/nsMathMLContainerFrame.cpp
@@ -119,48 +119,48 @@ static bool
 IsForeignChild(const nsIFrame* aFrame)
 {
   // This counts nsMathMLmathBlockFrame as a foreign child, because it
   // uses block reflow
   return !(aFrame->IsFrameOfType(nsIFrame::eMathML)) ||
     aFrame->GetType() == nsGkAtoms::blockFrame;
 }
 
-NS_DECLARE_FRAME_PROPERTY_DELETABLE(HTMLReflowMetricsProperty,
+NS_DECLARE_FRAME_PROPERTY_DELETABLE(HTMLReflowOutputProperty,
                                     ReflowOutput)
 
 /* static */ void
 nsMathMLContainerFrame::SaveReflowAndBoundingMetricsFor(nsIFrame*                  aFrame,
-                                                        const ReflowOutput& aReflowMetrics,
+                                                        const ReflowOutput& aReflowOutput,
                                                         const nsBoundingMetrics&   aBoundingMetrics)
 {
-  ReflowOutput *metrics = new ReflowOutput(aReflowMetrics);
-  metrics->mBoundingMetrics = aBoundingMetrics;
-  aFrame->Properties().Set(HTMLReflowMetricsProperty(), metrics);
+  ReflowOutput* reflowOutput = new ReflowOutput(aReflowOutput);
+  reflowOutput->mBoundingMetrics = aBoundingMetrics;
+  aFrame->Properties().Set(HTMLReflowOutputProperty(), reflowOutput);
 }
 
 // helper method to facilitate getting the reflow and bounding metrics
 /* static */ void
 nsMathMLContainerFrame::GetReflowAndBoundingMetricsFor(nsIFrame*            aFrame,
-                                                       ReflowOutput& aReflowMetrics,
+                                                       ReflowOutput& aReflowOutput,
                                                        nsBoundingMetrics&   aBoundingMetrics,
                                                        eMathMLFrameType*    aMathMLFrameType)
 {
   NS_PRECONDITION(aFrame, "null arg");
 
-  ReflowOutput* metrics =
-    aFrame->Properties().Get(HTMLReflowMetricsProperty());
+  ReflowOutput* reflowOutput =
+    aFrame->Properties().Get(HTMLReflowOutputProperty());
 
   // IMPORTANT: This function is only meant to be called in Place() methods
   // where it is assumed that SaveReflowAndBoundingMetricsFor has recorded the
   // information.
-  NS_ASSERTION(metrics, "Didn't SaveReflowAndBoundingMetricsFor frame!");
-  if (metrics) {
-    aReflowMetrics = *metrics;
-    aBoundingMetrics = metrics->mBoundingMetrics;
+  NS_ASSERTION(reflowOutput, "Didn't SaveReflowAndBoundingMetricsFor frame!");
+  if (reflowOutput) {
+    aReflowOutput = *reflowOutput;
+    aBoundingMetrics = reflowOutput->mBoundingMetrics;
   }
 
   if (aMathMLFrameType) {
     if (!IsForeignChild(aFrame)) {
       nsIMathMLFrame* mathMLFrame = do_QueryFrame(aFrame);
       if (mathMLFrame) {
         *aMathMLFrameType = mathMLFrame->GetMathMLFrameType();
         return;
@@ -172,17 +172,17 @@ nsMathMLContainerFrame::GetReflowAndBoun
 }
 
 void
 nsMathMLContainerFrame::ClearSavedChildMetrics()
 {
   nsIFrame* childFrame = mFrames.FirstChild();
   FramePropertyTable* props = PresContext()->PropertyTable();
   while (childFrame) {
-    props->Delete(childFrame, HTMLReflowMetricsProperty());
+    props->Delete(childFrame, HTMLReflowOutputProperty());
     childFrame = childFrame->GetNextSibling();
   }
 }
 
 // helper to get the preferred size that a container frame should use to fire
 // the stretch on its stretchy child frames.
 void
 nsMathMLContainerFrame::GetPreferredStretchSize(DrawTarget*          aDrawTarget,
@@ -191,19 +191,19 @@ nsMathMLContainerFrame::GetPreferredStre
                                                 nsBoundingMetrics&   aPreferredStretchSize)
 {
   if (aOptions & STRETCH_CONSIDER_ACTUAL_SIZE) {
     // when our actual size is ok, just use it
     aPreferredStretchSize = mBoundingMetrics;
   }
   else if (aOptions & STRETCH_CONSIDER_EMBELLISHMENTS) {
     // compute our up-to-date size using Place()
-    ReflowOutput metrics(GetWritingMode()); // ???
-    Place(aDrawTarget, false, metrics);
-    aPreferredStretchSize = metrics.mBoundingMetrics;
+    ReflowOutput reflowOutput(GetWritingMode());
+    Place(aDrawTarget, false, reflowOutput);
+    aPreferredStretchSize = reflowOutput.mBoundingMetrics;
   }
   else {
     // compute a size that includes embellishments iff the container stretches
     // in the same direction as the embellished operator.
     bool stretchAll = aStretchDirection == NS_STRETCH_DIRECTION_VERTICAL ?
                       NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) :
                       NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags);
     NS_ASSERTION(aStretchDirection == NS_STRETCH_DIRECTION_HORIZONTAL ||
@@ -1165,17 +1165,17 @@ static nscoord GetThinSpace(const nsStyl
 {
   return NSToCoordRound(float(aStyleFont->mFont.size)*float(3) / float(18));
 }
 
 class nsMathMLContainerFrame::RowChildFrameIterator {
 public:
   explicit RowChildFrameIterator(nsMathMLContainerFrame* aParentFrame) :
     mParentFrame(aParentFrame),
-    mSize(aParentFrame->GetWritingMode()), // ???
+    mReflowOutput(aParentFrame->GetWritingMode()),
     mX(0),
     mCarrySpace(0),
     mFromFrameType(eMathMLFrameType_UNKNOWN),
     mRTL(aParentFrame->StyleVisibility()->mDirection)
   {
     if (!mRTL) {
       mChildFrame = aParentFrame->mFrames.FirstChild();
     } else {
@@ -1186,17 +1186,17 @@ public:
       return;
 
     InitMetricsForChild();
   }
 
   RowChildFrameIterator& operator++()
   {
     // add child size + italic correction
-    mX += mSize.mBoundingMetrics.width + mItalicCorrection;
+    mX += mReflowOutput.mBoundingMetrics.width + mItalicCorrection;
 
     if (!mRTL) {
       mChildFrame = mChildFrame->GetNextSibling();
     } else {
       mChildFrame = mChildFrame->GetPrevSibling();
     }
 
     if (!mChildFrame)
@@ -1212,42 +1212,42 @@ public:
                            prevFrameType, mChildFrameType,
                            &mFromFrameType, &mCarrySpace);
     mX += space * GetThinSpace(font);
     return *this;
   }
 
   nsIFrame* Frame() const { return mChildFrame; }
   nscoord X() const { return mX; }
-  const ReflowOutput& ReflowMetrics() const { return mSize; }
-  nscoord Ascent() const { return mSize.BlockStartAscent(); }
-  nscoord Descent() const { return mSize.Height() - mSize.BlockStartAscent(); }
+  const ReflowOutput& GetReflowOutput() const { return mReflowOutput; }
+  nscoord Ascent() const { return mReflowOutput.BlockStartAscent(); }
+  nscoord Descent() const { return mReflowOutput.Height() - mReflowOutput.BlockStartAscent(); }
   const nsBoundingMetrics& BoundingMetrics() const {
-    return mSize.mBoundingMetrics;
+    return mReflowOutput.mBoundingMetrics;
   }
 
 private:
   const nsMathMLContainerFrame* mParentFrame;
   nsIFrame* mChildFrame;
-  ReflowOutput mSize;
+  ReflowOutput mReflowOutput;
   nscoord mX;
 
   nscoord mItalicCorrection;
   eMathMLFrameType mChildFrameType;
   int32_t mCarrySpace;
   eMathMLFrameType mFromFrameType;
 
   bool mRTL;
 
   void InitMetricsForChild()
   {
-    GetReflowAndBoundingMetricsFor(mChildFrame, mSize, mSize.mBoundingMetrics,
+    GetReflowAndBoundingMetricsFor(mChildFrame, mReflowOutput, mReflowOutput.mBoundingMetrics,
                                    &mChildFrameType);
     nscoord leftCorrection, rightCorrection;
-    GetItalicCorrection(mSize.mBoundingMetrics,
+    GetItalicCorrection(mReflowOutput.mBoundingMetrics,
                         leftCorrection, rightCorrection);
     if (!mChildFrame->GetPrevSibling() &&
         mParentFrame->GetContent()->IsMathMLElement(nsGkAtoms::msqrt_)) {
       // Remove leading correction in <msqrt> because the sqrt glyph itself is
       // there first.
       if (!mRTL) {
         leftCorrection = 0;
       } else {
@@ -1308,17 +1308,17 @@ nsMathMLContainerFrame::Place(DrawTarget
 void
 nsMathMLContainerFrame::PositionRowChildFrames(nscoord aOffsetX,
                                                nscoord aBaseline)
 {
   RowChildFrameIterator child(this);
   while (child.Frame()) {
     nscoord dx = aOffsetX + child.X();
     nscoord dy = aBaseline - child.Ascent();
-    FinishReflowChild(child.Frame(), PresContext(), child.ReflowMetrics(),
+    FinishReflowChild(child.Frame(), PresContext(), child.GetReflowOutput(),
                       nullptr, dx, dy, 0);
     ++child;
   }
 }
 
 class ForceReflow : public nsIReflowCallback {
 public:
   virtual bool ReflowFinished() override {
--- a/layout/mathml/nsMathMLContainerFrame.h
+++ b/layout/mathml/nsMathMLContainerFrame.h
@@ -295,29 +295,29 @@ protected:
   // helper method to complete the post-reflow hook and ensure that embellished
   // operators don't terminate their Reflow without receiving a Stretch command.
   virtual nsresult
   FinalizeReflow(DrawTarget* aDrawTarget, ReflowOutput& aDesiredSize);
 
   // Record metrics of a child frame for recovery through the following method
   static void
   SaveReflowAndBoundingMetricsFor(nsIFrame*                  aFrame,
-                                  const ReflowOutput& aReflowMetrics,
+                                  const ReflowOutput& aReflowOutput,
                                   const nsBoundingMetrics&   aBoundingMetrics);
 
   // helper method to facilitate getting the reflow and bounding metrics of a
   // child frame.  The argument aMathMLFrameType, when non null, will return
   // the 'type' of the frame, which is used to determine the inter-frame
   // spacing.
   // IMPORTANT: This function is only meant to be called in Place() methods as
   // the information is available only when set up with the above method
   // during Reflow/Stretch() and GetPrefISize().
   static void
   GetReflowAndBoundingMetricsFor(nsIFrame*            aFrame,
-                                 ReflowOutput& aReflowMetrics,
+                                 ReflowOutput& aReflowOutput,
                                  nsBoundingMetrics&   aBoundingMetrics,
                                  eMathMLFrameType*    aMathMLFrameType = nullptr);
 
   // helper method to clear metrics saved with
   // SaveReflowAndBoundingMetricsFor() from all child frames.
   void ClearSavedChildMetrics();
 
   // helper to let the update of presentation data pass through
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -518,17 +518,17 @@ nsComputedDOMStyle::GetStyleContextForEl
     // We want to build a list of user/ua rules that is in order from least to
     // most important, so we have to reverse the list.
     // Integer division to get "stop" is purposeful here: if length is odd, we
     // don't have to do anything with the middle element of the array.
     for (uint32_t i = 0, length = rules.Length(), stop = length / 2;
          i < stop; ++i) {
       rules[i].swap(rules[length - i - 1]);
     }
-    
+
     sc = styleSet->AsGecko()->ResolveStyleForRules(parentContext, rules);
   }
 
   return sc.forget();
 }
 
 nsMargin
 nsComputedDOMStyle::GetAdjustedValuesForBoxSizing()
@@ -2234,17 +2234,17 @@ nsComputedDOMStyle::DoGetImageLayerRepea
     }
 
     RefPtr<nsROCSSPrimitiveValue> valY;
     if (hasContraction) {
       valX->SetIdent(nsCSSProps::ValueToKeywordEnum(contraction,
                                          nsCSSProps::kImageLayerRepeatKTable));
     } else {
       valY = new nsROCSSPrimitiveValue;
-      
+
       valX->SetIdent(nsCSSProps::ValueToKeywordEnum(xRepeat,
                                           nsCSSProps::kImageLayerRepeatKTable));
       valY->SetIdent(nsCSSProps::ValueToKeywordEnum(yRepeat,
                                           nsCSSProps::kImageLayerRepeatKTable));
     }
     itemList->AppendCSSValue(valX.forget());
     if (valY) {
       itemList->AppendCSSValue(valY.forget());
@@ -4725,17 +4725,17 @@ nsComputedDOMStyle::DoGetHeight()
   if (mInnerFrame) {
     calcHeight = true;
 
     const nsStyleDisplay* displayData = StyleDisplay();
     if (displayData->mDisplay == NS_STYLE_DISPLAY_INLINE &&
         !(mInnerFrame->IsFrameOfType(nsIFrame::eReplaced)) &&
         // An outer SVG frame should behave the same as eReplaced in this case
         mInnerFrame->GetType() != nsGkAtoms::svgOuterSVGFrame) {
-      
+
       calcHeight = false;
     }
   }
 
   if (calcHeight) {
     AssertFlushedPendingReflows();
     nsMargin adjustedValues = GetAdjustedValuesForBoxSizing();
     val->SetAppUnits(mInnerFrame->GetContentRect().height +
@@ -4769,17 +4769,17 @@ nsComputedDOMStyle::DoGetWidth()
   if (mInnerFrame) {
     calcWidth = true;
 
     const nsStyleDisplay *displayData = StyleDisplay();
     if (displayData->mDisplay == NS_STYLE_DISPLAY_INLINE &&
         !(mInnerFrame->IsFrameOfType(nsIFrame::eReplaced)) &&
         // An outer SVG frame should behave the same as eReplaced in this case
         mInnerFrame->GetType() != nsGkAtoms::svgOuterSVGFrame) {
-      
+
       calcWidth = false;
     }
   }
 
   if (calcWidth) {
     AssertFlushedPendingReflows();
     nsMargin adjustedValues = GetAdjustedValuesForBoxSizing();
     val->SetAppUnits(mInnerFrame->GetContentRect().width +
@@ -6322,17 +6322,16 @@ nsComputedDOMStyle::AppendTimingFunction
                                                    aTimingFunction.mFunc.mX2,
                                                    aTimingFunction.mFunc.mY2,
                                                    tmp);
       break;
     case nsTimingFunction::Type::StepStart:
     case nsTimingFunction::Type::StepEnd:
       nsStyleUtil::AppendStepsTimingFunction(aTimingFunction.mType,
                                              aTimingFunction.mSteps,
-                                             aTimingFunction.mStepSyntax,
                                              tmp);
       break;
     default:
       nsStyleUtil::AppendCubicBezierKeywordTimingFunction(aTimingFunction.mType,
                                                           tmp);
       break;
   }
   timingFunction->SetString(tmp);
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -5291,20 +5291,17 @@ nsRuleNode::ComputeTimingFunction(const 
                        NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END ||
                       array->Item(1).GetIntValue() == -1),
                      "unexpected second value");
         nsTimingFunction::Type type =
           (array->Item(1).GetIntValue() ==
             NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START) ?
               nsTimingFunction::Type::StepStart :
               nsTimingFunction::Type::StepEnd;
-        aResult = nsTimingFunction(type, array->Item(0).GetIntValue(),
-                                   array->Item(1).GetIntValue() == -1 ?
-                                     nsTimingFunction::Keyword::Implicit :
-                                     nsTimingFunction::Keyword::Explicit);
+        aResult = nsTimingFunction(type, array->Item(0).GetIntValue());
       }
       break;
     default:
       NS_NOTREACHED("Invalid transition property unit");
   }
 }
 
 static uint8_t
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -151,17 +151,17 @@ nsStyleFont::nsStyleFont(const nsStyleFo
 }
 
 nsStyleFont::nsStyleFont(StyleStructContext aContext)
   : nsStyleFont(*aContext.GetDefaultFont(kPresContext_DefaultVariableFont_ID),
                 aContext)
 {
 }
 
-void 
+void
 nsStyleFont::Destroy(nsPresContext* aContext) {
   this->~nsStyleFont();
   aContext->PresShell()->
     FreeByObjectID(eArenaObjectID_nsStyleFont, this);
 }
 
 void
 nsStyleFont::EnableZoom(nsPresContext* aContext, bool aEnable)
@@ -267,17 +267,17 @@ nsStyleMargin::nsStyleMargin(StyleStruct
 }
 
 nsStyleMargin::nsStyleMargin(const nsStyleMargin& aSrc)
   : mMargin(aSrc.mMargin)
 {
   MOZ_COUNT_CTOR(nsStyleMargin);
 }
 
-void 
+void
 nsStyleMargin::Destroy(nsPresContext* aContext) {
   this->~nsStyleMargin();
   aContext->PresShell()->
     FreeByObjectID(eArenaObjectID_nsStyleMargin, this);
 }
 
 nsChangeHint
 nsStyleMargin::CalcDifference(const nsStyleMargin& aNewData) const
@@ -302,17 +302,17 @@ nsStylePadding::nsStylePadding(StyleStru
 }
 
 nsStylePadding::nsStylePadding(const nsStylePadding& aSrc)
   : mPadding(aSrc.mPadding)
 {
   MOZ_COUNT_CTOR(nsStylePadding);
 }
 
-void 
+void
 nsStylePadding::Destroy(nsPresContext* aContext) {
   this->~nsStylePadding();
   aContext->PresShell()->
     FreeByObjectID(eArenaObjectID_nsStylePadding, this);
 }
 
 nsChangeHint
 nsStylePadding::CalcDifference(const nsStylePadding& aNewData) const
@@ -555,17 +555,17 @@ nsStyleOutline::nsStyleOutline(const nsS
   , mActualOutlineWidth(aSrc.mActualOutlineWidth)
   , mOutlineColor(aSrc.mOutlineColor)
   , mOutlineStyle(aSrc.mOutlineStyle)
   , mTwipsPerPixel(aSrc.mTwipsPerPixel)
 {
   MOZ_COUNT_CTOR(nsStyleOutline);
 }
 
-void 
+void
 nsStyleOutline::RecalcData()
 {
   if (NS_STYLE_BORDER_STYLE_NONE == GetOutlineStyle()) {
     mActualOutlineWidth = 0;
   } else {
     MOZ_ASSERT(mOutlineWidth.ConvertsToLength() ||
                mOutlineWidth.GetUnit() == eStyleUnit_Enumerated);
     // Clamp negative calc() to 0.
@@ -603,25 +603,25 @@ nsStyleOutline::CalcDifference(const nsS
   }
 
   return nsChangeHint(0);
 }
 
 // --------------------
 // nsStyleList
 //
-nsStyleList::nsStyleList(StyleStructContext aContext) 
+nsStyleList::nsStyleList(StyleStructContext aContext)
   : mListStylePosition(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE)
   , mCounterStyle(aContext.BuildCounterStyle(NS_LITERAL_STRING("disc")))
 {
   MOZ_COUNT_CTOR(nsStyleList);
   SetQuotesInitial();
 }
 
-nsStyleList::~nsStyleList() 
+nsStyleList::~nsStyleList()
 {
   MOZ_COUNT_DTOR(nsStyleList);
 }
 
 nsStyleList::nsStyleList(const nsStyleList& aSource)
   : mListStylePosition(aSource.mListStylePosition)
   , mCounterStyle(aSource.mCounterStyle)
   , mQuotes(aSource.mQuotes)
@@ -2774,24 +2774,22 @@ nsStyleBackground::IsTransparent() const
 }
 
 void
 nsTimingFunction::AssignFromKeyword(int32_t aTimingFunctionType)
 {
   switch (aTimingFunctionType) {
     case NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START:
       mType = Type::StepStart;
-      mStepSyntax = StepSyntax::Keyword;
       mSteps = 1;
       return;
     default:
       MOZ_FALLTHROUGH_ASSERT("aTimingFunctionType must be a keyword value");
     case NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END:
       mType = Type::StepEnd;
-      mStepSyntax = StepSyntax::Keyword;
       mSteps = 1;
       return;
     case NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE:
     case NS_STYLE_TRANSITION_TIMING_FUNCTION_LINEAR:
     case NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN:
     case NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_OUT:
     case NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN_OUT:
       mType = static_cast<Type>(aTimingFunctionType);
@@ -3178,20 +3176,20 @@ nsStyleDisplay::CalcDifference(const nsS
       if (HasTransformStyle()) {
         hint |= transformHint;
       } else {
         hint |= nsChangeHint_NeutralChange;
       }
     }
   }
 
-  // Note that the HasTransformStyle() != aNewData.HasTransformStyle() 
+  // Note that the HasTransformStyle() != aNewData.HasTransformStyle()
   // test above handles relevant changes in the
-  // NS_STYLE_WILL_CHANGE_TRANSFORM bit, which in turn handles frame 
-  // reconstruction for changes in the containing block of 
+  // NS_STYLE_WILL_CHANGE_TRANSFORM bit, which in turn handles frame
+  // reconstruction for changes in the containing block of
   // fixed-positioned elements.
   uint8_t willChangeBitsChanged =
     mWillChangeBitField ^ aNewData.mWillChangeBitField;
   if (willChangeBitsChanged & (NS_STYLE_WILL_CHANGE_STACKING_CONTEXT |
                                NS_STYLE_WILL_CHANGE_SCROLL |
                                NS_STYLE_WILL_CHANGE_OPACITY)) {
     hint |= nsChangeHint_RepaintFrame;
   }
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -2262,23 +2262,16 @@ struct nsTimingFunction
     EaseIn,       // ease-in
     EaseOut,      // ease-out
     EaseInOut,    // ease-in-out
     StepStart,    // step-start and steps(..., start)
     StepEnd,      // step-end, steps(..., end) and steps(...)
     CubicBezier,  // cubic-bezier()
   };
 
-  enum class StepSyntax {
-    Keyword,                     // step-start and step-end
-    FunctionalWithoutKeyword,    // steps(...)
-    FunctionalWithStartKeyword,  // steps(..., start)
-    FunctionalWithEndKeyword,    // steps(..., end)
-  };
-
   // Whether the timing function type is represented by a spline,
   // and thus will have mFunc filled in.
   static bool IsSplineType(Type aType)
   {
     return aType != Type::StepStart && aType != Type::StepEnd;
   }
 
   explicit nsTimingFunction(int32_t aTimingFunctionType
@@ -2293,48 +2286,38 @@ struct nsTimingFunction
     mFunc.mX1 = x1;
     mFunc.mY1 = y1;
     mFunc.mX2 = x2;
     mFunc.mY2 = y2;
   }
 
   enum class Keyword { Implicit, Explicit };
 
-  nsTimingFunction(Type aType, uint32_t aSteps, Keyword aKeyword)
+  nsTimingFunction(Type aType, uint32_t aSteps)
     : mType(aType)
   {
     MOZ_ASSERT(mType == Type::StepStart || mType == Type::StepEnd,
                "wrong type");
     mSteps = aSteps;
-    if (mType == Type::StepStart) {
-      MOZ_ASSERT(aKeyword == Keyword::Explicit,
-                 "only StepEnd can have an implicit keyword");
-      mStepSyntax = StepSyntax::FunctionalWithStartKeyword;
-    } else {
-      mStepSyntax = aKeyword == Keyword::Explicit ?
-                      StepSyntax::FunctionalWithEndKeyword :
-                      StepSyntax::FunctionalWithoutKeyword;
-    }
   }
 
   nsTimingFunction(const nsTimingFunction& aOther)
   {
     *this = aOther;
   }
 
   Type mType;
   union {
     struct {
       float mX1;
       float mY1;
       float mX2;
       float mY2;
     } mFunc;
     struct {
-      StepSyntax mStepSyntax;
       uint32_t mSteps;
     };
   };
 
   nsTimingFunction&
   operator=(const nsTimingFunction& aOther)
   {
     if (&aOther == this) {
@@ -2345,33 +2328,31 @@ struct nsTimingFunction
 
     if (HasSpline()) {
       mFunc.mX1 = aOther.mFunc.mX1;
       mFunc.mY1 = aOther.mFunc.mY1;
       mFunc.mX2 = aOther.mFunc.mX2;
       mFunc.mY2 = aOther.mFunc.mY2;
     } else {
       mSteps = aOther.mSteps;
-      mStepSyntax = aOther.mStepSyntax;
     }
 
     return *this;
   }
 
   bool operator==(const nsTimingFunction& aOther) const
   {
     if (mType != aOther.mType) {
       return false;
     }
     if (HasSpline()) {
       return mFunc.mX1 == aOther.mFunc.mX1 && mFunc.mY1 == aOther.mFunc.mY1 &&
              mFunc.mX2 == aOther.mFunc.mX2 && mFunc.mY2 == aOther.mFunc.mY2;
     }
-    return mSteps == aOther.mSteps &&
-           mStepSyntax == aOther.mStepSyntax;
+    return mSteps == aOther.mSteps;
   }
 
   bool operator!=(const nsTimingFunction& aOther) const
   {
     return !(*this == aOther);
   }
 
   bool HasSpline() const { return IsSplineType(mType); }
--- a/layout/style/nsStyleUtil.cpp
+++ b/layout/style/nsStyleUtil.cpp
@@ -588,46 +588,27 @@ nsStyleUtil::AppendSerializedFontSrc(con
     aResult.AppendLiteral(", ");
   }
   aResult.Truncate(aResult.Length() - 2); // remove the last comma-space
 }
 
 /* static */ void
 nsStyleUtil::AppendStepsTimingFunction(nsTimingFunction::Type aType,
                                        uint32_t aSteps,
-                                       nsTimingFunction::StepSyntax aSyntax,
                                        nsAString& aResult)
 {
   MOZ_ASSERT(aType == nsTimingFunction::Type::StepStart ||
              aType == nsTimingFunction::Type::StepEnd);
 
-  if (aSyntax == nsTimingFunction::StepSyntax::Keyword) {
-    if (aType == nsTimingFunction::Type::StepStart) {
-      aResult.AppendLiteral("step-start");
-    } else {
-      aResult.AppendLiteral("step-end");
-    }
-    return;
-  }
-
   aResult.AppendLiteral("steps(");
   aResult.AppendInt(aSteps);
-  switch (aSyntax) {
-    case nsTimingFunction::StepSyntax::Keyword:
-      // handled above
-      break;
-    case nsTimingFunction::StepSyntax::FunctionalWithStartKeyword:
-      aResult.AppendLiteral(", start)");
-      break;
-    case nsTimingFunction::StepSyntax::FunctionalWithEndKeyword:
-      aResult.AppendLiteral(", end)");
-      break;
-    case nsTimingFunction::StepSyntax::FunctionalWithoutKeyword:
-      aResult.Append(')');
-      break;
+  if (aType == nsTimingFunction::Type::StepStart) {
+    aResult.AppendLiteral(", start)");
+  } else {
+    aResult.AppendLiteral(")");
   }
 }
 
 /* static */ void
 nsStyleUtil::AppendCubicBezierTimingFunction(float aX1, float aY1,
                                              float aX2, float aY2,
                                              nsAString& aResult)
 {
--- a/layout/style/nsStyleUtil.h
+++ b/layout/style/nsStyleUtil.h
@@ -73,17 +73,16 @@ public:
 
   static void AppendCSSNumber(float aNumber, nsAString& aResult)
   {
     aResult.AppendFloat(aNumber);
   }
 
   static void AppendStepsTimingFunction(nsTimingFunction::Type aType,
                                         uint32_t aSteps,
-                                        nsTimingFunction::StepSyntax aSyntax,
                                         nsAString& aResult);
   static void AppendCubicBezierTimingFunction(float aX1, float aY1,
                                               float aX2, float aY2,
                                               nsAString& aResult);
   static void AppendCubicBezierKeywordTimingFunction(
       nsTimingFunction::Type aType,
       nsAString& aResult);
 
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -2985,17 +2985,16 @@ nsTableFrame::PlaceRepeatedFooter(TableR
              // on the right-hand side so we're not simply converting a
              // point, we're also swapping the child's origin side.
              kidPosition.GetPhysicalPoint(wm, containerSize -
                                               desiredSize.PhysicalSize()),
              desiredSize, origTfootRect, origTfootVisualOverflow);
 }
 
 // Reflow the children based on the avail size and reason in aReflowInput
-// update aReflowMetrics a aStatus
 void
 nsTableFrame::ReflowChildren(TableReflowInput& aReflowInput,
                              nsReflowStatus&     aStatus,
                              nsIFrame*&          aLastChildReflowed,
                              nsOverflowAreas&    aOverflowAreas)
 {
   aStatus = NS_FRAME_COMPLETE;
   aLastChildReflowed = nullptr;
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -387,43 +387,16 @@ res/raw/browsersearch.json: .locales.dep
 res/raw/suggestedsites.json: .locales.deps ;
 
 all_resources = \
   $(DEPTH)/mobile/android/base/AndroidManifest.xml \
   $(android_res_files) \
   $(ANDROID_GENERATED_RESFILES) \
   $(NULL)
 
-# For GeckoView, we want a zip of an Android res/ directory that
-# merges the contents of all the ANDROID_RES_DIRS.  The inner res/
-# directory must have the Android resource two-layer hierarchy.
-
-# The following helper zips files in a directory into a zip file while
-# maintaining the directory structure rooted below the directory.
-# (adding or creating said file as appropriate).  For example, if the
-# dir contains dir/subdir/file, calling with directory dir would
-# create a zip containing subdir/file.  Note: the trailing newline is
-# necessary.
-
-# $(1): zip file to add to (or create).
-# $(2): directory to zip contents of.
-define zip_directory_with_relative_paths
-cd $(2) && zip -q $(1) -r * -x $(subst *,\*,$(not_android_res_files))
-
-endef
-
-ifndef MOZ_DISABLE_GECKOVIEW
-# We delete the archive before updating so that resources removed from
-# the filesystem are removed from the archive.
-geckoview_resources.zip: $(all_resources) $(GLOBAL_DEPS)
-	$(REPORT_BUILD)
-	$(RM) -rf $@
-	$(foreach dir,$(ANDROID_RES_DIRS),$(call zip_directory_with_relative_paths,$(CURDIR)/$@,$(dir)))
-endif
-
 # All of generated/org/mozilla/gecko/R.java, gecko.ap_, and R.txt are
 # produced by aapt; this saves aapt invocations.  The trailing
 # semi-colon defines an empty recipe; defining no recipe at all causes
 # Make to treat the target differently, in a way that defeats our
 # dependencies.
 
 generated/org/mozilla/gecko/R.java: .aapt.deps ;
 
@@ -544,21 +517,16 @@ ifndef MOZILLA_OFFICIAL
 gradle-omnijar: $(abspath $(DIST)/fennec/$(OMNIJAR_NAME))
 else
 # In automation, omni.ja is built only during packaging.
 gradle-omnijar:
 endif
 
 .PHONY: gradle-targets gradle-omnijar
 
-ifndef MOZ_DISABLE_GECKOVIEW
-libs:: geckoview_resources.zip
-	$(INSTALL) geckoview_resources.zip $(FINAL_TARGET)
-endif
-
 # GeneratedJNIWrappers.cpp target also generates
 # GeneratedJNIWrappers.h and GeneratedJNINatives.h
 ifndef MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE
 libs:: jni-stubs.inc GeneratedJNIWrappers.cpp
 	@(diff jni-stubs.inc $(topsrcdir)/mozglue/android/jni-stubs.inc >/dev/null && \
 	  diff GeneratedJNIWrappers.cpp $(topsrcdir)/widget/android/GeneratedJNIWrappers.cpp >/dev/null && \
 	  diff GeneratedJNIWrappers.h $(topsrcdir)/widget/android/GeneratedJNIWrappers.h >/dev/null && \
 	  diff GeneratedJNINatives.h $(topsrcdir)/widget/android/GeneratedJNINatives.h >/dev/null) || \
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -743,17 +743,17 @@ public class BrowserApp extends GeckoApp
         });
 
         // Set the maximum bits-per-pixel the favicon system cares about.
         IconDirectoryEntry.setMaxBPP(GeckoAppShell.getScreenDepth());
 
         // The update service is enabled for RELEASE_BUILD, which includes the release and beta channels.
         // However, no updates are served.  Therefore, we don't trust the update service directly, and
         // try to avoid prompting unnecessarily. See Bug 1232798.
-        if (!AppConstants.RELEASE_BUILD && UpdateServiceHelper.isUpdaterEnabled()) {
+        if (!AppConstants.RELEASE_BUILD && UpdateServiceHelper.isUpdaterEnabled(this)) {
             Permissions.from(this)
                        .withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
                        .doNotPrompt()
                        .andFallback(new Runnable() {
                            @Override
                            public void run() {
                                showUpdaterPermissionSnackbar();
                            }
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java
@@ -126,19 +126,18 @@ public class GeckoApplication extends Ap
     }
 
     public void onActivityResume(GeckoActivityStatus activity) {
         if (mPausedGecko) {
             GeckoThread.onResume();
             mPausedGecko = false;
         }
 
-        final Context applicationContext = getApplicationContext();
-        GeckoBatteryManager.getInstance().start(applicationContext);
-        GeckoNetworkManager.getInstance().start();
+        GeckoBatteryManager.getInstance().start(this);
+        GeckoNetworkManager.getInstance().start(this);
 
         mInBackground = false;
     }
 
     @Override
     protected void attachBaseContext(Context base) {
         super.attachBaseContext(base);
         AppConstants.maybeInstallMultiDex(base);
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoNetworkManager.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoNetworkManager.java
@@ -44,16 +44,20 @@ import android.util.Log;
  */
 public class GeckoNetworkManager extends BroadcastReceiver implements NativeEventListener {
     private static final String LOGTAG = "GeckoNetworkManager";
 
     private static final String LINK_DATA_CHANGED = "changed";
 
     private static GeckoNetworkManager instance;
 
+    // We hackishly (yet harmlessly, in this case) keep a Context reference passed in via the start method.
+    // See context handling notes in handleManagerEvent, and Bug 1277333.
+    private Context context;
+
     public static void destroy() {
         if (instance != null) {
             instance.onDestroy();
             instance = null;
         }
     }
 
     public enum ManagerState {
@@ -115,17 +119,18 @@ public class GeckoNetworkManager extends
         };
     }
 
     @Override
     public void onReceive(Context aContext, Intent aIntent) {
         handleManagerEvent(ManagerEvent.receivedUpdate);
     }
 
-    public void start() {
+    public void start(final Context context) {
+        this.context = context;
         handleManagerEvent(ManagerEvent.start);
     }
 
     public void stop() {
         handleManagerEvent(ManagerEvent.stop);
     }
 
     public void enableNotifications() {
@@ -147,17 +152,36 @@ public class GeckoNetworkManager extends
         final ManagerState nextState = getNextState(currentState, event);
 
         Log.d(LOGTAG, "Incoming event " + event + " for state " + currentState + " -> " + nextState);
         if (nextState == null) {
             Log.w(LOGTAG, "Invalid event " + event + " for state " + currentState);
             return false;
         }
 
-        performActionsForStateEvent(currentState, event);
+        // We're being deliberately careful about handling context here; it's possible that in some
+        // rare cases and possibly related to timing of when this is called (seems to be early in the startup phase),
+        // GeckoAppShell.getApplicationContext() will be null, and .start() wasn't called yet,
+        // so we don't have a local Context reference either. If both of these are true, we have to drop the event.
+        // NB: this is hacky (and these checks attempt to isolate the hackiness), and root cause
+        // seems to be how this class fits into the larger ecosystem and general flow of events.
+        // See Bug 1277333.
+        final Context contextForAction;
+        if (context != null) {
+            contextForAction = context;
+        } else {
+            contextForAction = GeckoAppShell.getApplicationContext();
+        }
+
+        if (contextForAction == null) {
+            Log.w(LOGTAG, "Context is not available while processing event " + event + " for state " + currentState);
+            return false;
+        }
+
+        performActionsForStateEvent(contextForAction, currentState, event);
         currentState = nextState;
 
         return true;
     }
 
     /**
      * Defines a transition matrix for our state machine. For a given state/event pair, returns nextState.
      *
@@ -216,71 +240,70 @@ public class GeckoNetworkManager extends
     /**
      * For a given state/event combination, run any actions which are by-products of leaving the state
      * because of a given event. Since this is a deterministic state machine, we can easily do that
      * without any additional information.
      *
      * @param currentState State which we are leaving
      * @param event Event which is causing us to leave the state
      */
-    private void performActionsForStateEvent(ManagerState currentState, ManagerEvent event) {
+    private void performActionsForStateEvent(final Context context, final ManagerState currentState, final ManagerEvent event) {
         // NB: network state might be queried via getCurrentInformation at any time; pre-rewrite behaviour was
         // that network state was updated whenever enableNotifications was called. To avoid deviating
         // from previous behaviour and causing weird side-effects, we call updateNetworkStateAndConnectionType
         // whenever notifications are enabled.
         switch (currentState) {
             case OffNoListeners:
                 if (event == ManagerEvent.start) {
-                    updateNetworkStateAndConnectionType();
-                    registerBroadcastReceiver();
+                    updateNetworkStateAndConnectionType(context);
+                    registerBroadcastReceiver(context, this);
                 }
                 if (event == ManagerEvent.enableNotifications) {
-                    updateNetworkStateAndConnectionType();
+                    updateNetworkStateAndConnectionType(context);
                 }
                 break;
             case OnNoListeners:
                 if (event == ManagerEvent.receivedUpdate) {
-                    updateNetworkStateAndConnectionType();
-                    sendNetworkStateToListeners();
+                    updateNetworkStateAndConnectionType(context);
+                    sendNetworkStateToListeners(context);
                 }
                 if (event == ManagerEvent.enableNotifications) {
-                    updateNetworkStateAndConnectionType();
-                    registerBroadcastReceiver();
+                    updateNetworkStateAndConnectionType(context);
+                    registerBroadcastReceiver(context, this);
                 }
                 if (event == ManagerEvent.stop) {
-                    unregisterBroadcastReceiver();
+                    unregisterBroadcastReceiver(context, this);
                 }
                 break;
             case OnWithListeners:
                 if (event == ManagerEvent.receivedUpdate) {
-                    updateNetworkStateAndConnectionType();
-                    sendNetworkStateToListeners();
+                    updateNetworkStateAndConnectionType(context);
+                    sendNetworkStateToListeners(context);
                 }
                 if (event == ManagerEvent.stop) {
-                    unregisterBroadcastReceiver();
+                    unregisterBroadcastReceiver(context, this);
                 }
                 /* no-op event: ManagerEvent.disableNotifications */
                 break;
             case OffWithListeners:
                 if (event == ManagerEvent.start) {
-                    registerBroadcastReceiver();
+                    registerBroadcastReceiver(context, this);
                 }
                 /* no-op event: ManagerEvent.disableNotifications */
                 break;
             default:
                 throw new IllegalStateException("Unknown current state: " + currentState.name());
         }
     }
 
     /**
      * Update current network state and connection types.
      */
-    private void updateNetworkStateAndConnectionType() {
-        final Context applicationContext = GeckoAppShell.getApplicationContext();
-        final ConnectivityManager connectivityManager = (ConnectivityManager) applicationContext.getSystemService(
+    private void updateNetworkStateAndConnectionType(final Context context) {
+        final ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(
                 Context.CONNECTIVITY_SERVICE);
         // Type/status getters below all have a defined behaviour for when connectivityManager == null
         if (connectivityManager == null) {
             Log.e(LOGTAG, "ConnectivityManager does not exist.");
         }
         currentConnectionType = NetworkUtils.getConnectionType(connectivityManager);
         currentNetworkStatus = NetworkUtils.getNetworkStatus(connectivityManager);
         currentConnectionSubtype = NetworkUtils.getConnectionSubType(connectivityManager);
@@ -292,25 +315,25 @@ public class GeckoNetworkManager extends
                                                    boolean isWifi, int DHCPGateway);
 
     @WrapForJNI
     private static native void onStatusChanged(String status);
 
     /**
      * Send current network state and connection type as a GeckoEvent, to whomever is listening.
      */
-    private void sendNetworkStateToListeners() {
+    private void sendNetworkStateToListeners(final Context context) {
         if (currentConnectionType != previousConnectionType ||
                 currentConnectionSubtype != previousConnectionSubtype) {
             previousConnectionType = currentConnectionType;
             previousConnectionSubtype = currentConnectionSubtype;
 
             final boolean isWifi = currentConnectionType == ConnectionType.WIFI;
             final int gateway = !isWifi ? 0 :
-                    wifiDhcpGatewayAddress(GeckoAppShell.getApplicationContext());
+                    wifiDhcpGatewayAddress(context);
 
             if (GeckoThread.isRunning()) {
                 onConnectionChanged(currentConnectionType.value,
                                     currentConnectionSubtype.value, isWifi, gateway);
             } else {
                 GeckoThread.queueNativeCall(GeckoNetworkManager.class, "onConnectionChanged",
                                             currentConnectionType.value,
                                             String.class, currentConnectionSubtype.value,
@@ -333,29 +356,29 @@ public class GeckoNetworkManager extends
             GeckoThread.queueNativeCall(GeckoNetworkManager.class, "onStatusChanged",
                                         String.class, status);
         }
     }
 
     /**
      * Stop listening for network state updates.
      */
-    private void unregisterBroadcastReceiver() {
-        GeckoAppShell.getApplicationContext().unregisterReceiver(this);
+    private static void unregisterBroadcastReceiver(final Context context, final BroadcastReceiver receiver) {
+        context.unregisterReceiver(receiver);
     }
 
     /**
      * Start listening for network state updates.
      */
-    private void registerBroadcastReceiver() {
+    private static void registerBroadcastReceiver(final Context context, final BroadcastReceiver receiver) {
         final IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
-        GeckoAppShell.getApplicationContext().registerReceiver(this, filter);
+        context.registerReceiver(receiver, filter);
     }
 
-    private static int wifiDhcpGatewayAddress(Context context) {
+    private static int wifiDhcpGatewayAddress(final Context context) {
         if (context == null) {
             return 0;
         }
 
         try {
             WifiManager mgr = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
             DhcpInfo d = mgr.getDhcpInfo();
             if (d == null) {
@@ -393,17 +416,17 @@ public class GeckoNetworkManager extends
                 }
                 break;
             case "Wifi:GetIPAddress":
                 getWifiIPAddress(callback);
                 break;
         }
     }
 
-    // This function only works for IPv4
+    // This function only works for IPv4; not part of the state machine flow.
     private void getWifiIPAddress(final EventCallback callback) {
         final WifiManager mgr = (WifiManager) GeckoAppShell.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
 
         if (mgr == null) {
             callback.sendError("Cannot get WifiManager");
             return;
         }
 
@@ -448,16 +471,18 @@ public class GeckoNetworkManager extends
         return -1;
     }
 
     /**
      * These are called from JavaScript ctypes. Avoid letting ProGuard delete them.
      *
      * Note that these methods must only be called after GeckoAppShell has been
      * initialized: they depend on access to the context.
+     *
+     * Not part of the state machine flow.
      */
     @JNITarget
     public static int getMCC() {
         return getNetworkOperator(InfoType.MCC, GeckoAppShell.getApplicationContext());
     }
 
     @JNITarget
     public static int getMNC() {
--- a/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java
+++ b/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java
@@ -34,16 +34,17 @@ import org.mozilla.gecko.feeds.FeedServi
 import org.mozilla.gecko.feeds.action.CheckForUpdatesAction;
 import org.mozilla.gecko.permissions.Permissions;
 import org.mozilla.gecko.restrictions.Restrictable;
 import org.mozilla.gecko.restrictions.Restrictions;
 import org.mozilla.gecko.tabqueue.TabQueueHelper;
 import org.mozilla.gecko.tabqueue.TabQueuePrompt;
 import org.mozilla.gecko.updater.UpdateService;
 import org.mozilla.gecko.updater.UpdateServiceHelper;
+import org.mozilla.gecko.util.ContextUtils;
 import org.mozilla.gecko.util.EventCallback;
 import org.mozilla.gecko.util.GeckoEventListener;
 import org.mozilla.gecko.util.HardwareUtils;
 import org.mozilla.gecko.util.InputOptionsUtils;
 import org.mozilla.gecko.util.NativeEventListener;
 import org.mozilla.gecko.util.NativeJSObject;
 import org.mozilla.gecko.util.ThreadUtils;
 
@@ -703,17 +704,17 @@ OnSharedPreferenceChangeListener
                         preferences.removePreference(pref);
                         i--;
                         continue;
                     }
                 }
 
                 pref.setOnPreferenceChangeListener(this);
                 if (PREFS_UPDATER_AUTODOWNLOAD.equals(key)) {
-                    if (!AppConstants.MOZ_UPDATER) {
+                    if (!AppConstants.MOZ_UPDATER || ContextUtils.isInstalledFromGooglePlay(this)) {
                         preferences.removePreference(pref);
                         i--;
                         continue;
                     }
                 } else if (PREFS_TRACKING_PROTECTION.equals(key)) {
                     // Remove UI for global TP pref in non-Nightly builds.
                     if (!AppConstants.NIGHTLY_BUILD) {
                         preferences.removePreference(pref);
--- a/mobile/android/base/java/org/mozilla/gecko/updater/UpdateServiceHelper.java
+++ b/mobile/android/base/java/org/mozilla/gecko/updater/UpdateServiceHelper.java
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.updater;
 
 import org.mozilla.gecko.annotation.RobocopTarget;
 import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.PrefsHelper;
+import org.mozilla.gecko.util.ContextUtils;
 import org.mozilla.gecko.util.GeckoJarReader;
 
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ApplicationInfo;
 import android.os.Build;
 import android.util.Log;
@@ -126,18 +127,18 @@ public class UpdateServiceHelper {
         try {
             return new URI(url);
         } catch (java.net.URISyntaxException e) {
             Log.e(LOGTAG, "Failed to create update url: ", e);
             return null;
         }
     }
 
-    public static boolean isUpdaterEnabled() {
-        return AppConstants.MOZ_UPDATER && isEnabled;
+    public static boolean isUpdaterEnabled(final Context context) {
+        return AppConstants.MOZ_UPDATER && isEnabled && !ContextUtils.isInstalledFromGooglePlay(context);
     }
 
     public static void setUpdateUrl(Context context, String url) {
         registerForUpdates(context, null, url);
     }
 
     public static void setAutoDownloadPolicy(Context context, UpdateService.AutoDownloadPolicy policy) {
         registerForUpdates(context, policy, null);
@@ -163,17 +164,17 @@ public class UpdateServiceHelper {
         if (context == null) {
             return;
         }
 
         context.startService(createIntent(context, ACTION_APPLY_UPDATE));
     }
 
     public static void registerForUpdates(final Context context) {
-        if (!isUpdaterEnabled()) {
+        if (!isUpdaterEnabled(context)) {
              return;
         }
 
         final HashMap<String, Object> prefs = new HashMap<String, Object>();
 
         PrefsHelper.getPrefs(Pref.names, new PrefsHelper.PrefHandlerBase() {
             @Override public void prefValue(String pref, String value) {
                 prefs.put(pref, value);
@@ -184,17 +185,17 @@ public class UpdateServiceHelper {
                     UpdateService.AutoDownloadPolicy.get(
                         (String) prefs.get(Pref.AUTO_DOWNLOAD_POLICY.toString())),
                       (String) prefs.get(Pref.UPDATE_URL.toString()));
             }
         });
     }
 
     public static void registerForUpdates(Context context, UpdateService.AutoDownloadPolicy policy, String url) {
-        if (!isUpdaterEnabled()) {
+        if (!isUpdaterEnabled(context)) {
              return;
         }
 
         Intent intent = createIntent(context, ACTION_REGISTER_FOR_UPDATES);
 
         if (policy != null) {
             intent.putExtra(EXTRA_AUTODOWNLOAD_NAME, policy.value);
         }
--- a/mobile/android/base/java/org/mozilla/gecko/util/ContextUtils.java
+++ b/mobile/android/base/java/org/mozilla/gecko/util/ContextUtils.java
@@ -4,25 +4,38 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
 package org.mozilla.gecko.util;
 
 import android.content.Context;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.text.TextUtils;
 
 public class ContextUtils {
+    private static final String INSTALLER_GOOGLE_PLAY = "com.android.vending";
+
     private ContextUtils() {}
 
     /**
      * @return {@link android.content.pm.PackageInfo#firstInstallTime} for the context's package.
      * @throws PackageManager.NameNotFoundException Unexpected - we get the package name from the context so
      *         it's expected to be found.
      */
     public static PackageInfo getCurrentPackageInfo(final Context context) {
         try {
             return context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
         } catch (PackageManager.NameNotFoundException e) {
             throw new AssertionError("Should not happen: Can't get package info of own package");
         }
     }
+
+    public static boolean isInstalledFromGooglePlay(final Context context) {
+        final String installerPackageName = context.getPackageManager().getInstallerPackageName(context.getPackageName());
+
+        if (TextUtils.isEmpty(installerPackageName)) {
+            return false;
+        }
+
+        return INSTALLER_GOOGLE_PLAY.equals(installerPackageName);
+    }
 }
--- a/mobile/android/config/mozconfigs/android-api-15-frontend/nightly
+++ b/mobile/android/config/mozconfigs/android-api-15-frontend/nightly
@@ -35,11 +35,9 @@ ac_add_options --with-branding=mobile/an
 
 # This will overwrite the default of stripping everything and keep the symbol table.
 # This is useful for profiling with eideticker. See bug 788680
 STRIP_FLAGS="--strip-debug"
 
 export MOZILLA_OFFICIAL=1
 export MOZ_TELEMETRY_REPORTING=1
 
-MOZ_ANDROID_GECKOLIBS_AAR=1
-
 . "$topsrcdir/mobile/android/config/mozconfigs/common.override"
--- a/mobile/android/config/mozconfigs/android-api-15-gradle-dependencies/nightly
+++ b/mobile/android/config/mozconfigs/android-api-15-gradle-dependencies/nightly
@@ -37,11 +37,9 @@ ac_add_options --with-branding=mobile/an
 
 # This will overwrite the default of stripping everything and keep the symbol table.
 # This is useful for profiling with eideticker. See bug 788680
 STRIP_FLAGS="--strip-debug"
 
 export MOZILLA_OFFICIAL=1
 export MOZ_TELEMETRY_REPORTING=1
 
-MOZ_ANDROID_GECKOLIBS_AAR=1
-
 . "$topsrcdir/mobile/android/config/mozconfigs/common.override"
--- a/mobile/android/config/mozconfigs/android-api-15/l10n-nightly
+++ b/mobile/android/config/mozconfigs/android-api-15/l10n-nightly
@@ -10,17 +10,16 @@ ac_add_options --disable-tests
 ac_add_options --with-android-min-sdk=15
 ac_add_options --target=arm-linux-androideabi
 
 ac_add_options --with-system-zlib
 ac_add_options --enable-updater
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 
 export MOZILLA_OFFICIAL=1
-export MOZ_DISABLE_GECKOVIEW=1
 
 ac_add_options --with-branding=mobile/android/branding/nightly
 
 ac_add_options --disable-stdcxx-compat
 
 # Don't autoclobber l10n, as this can lead to missing binaries and broken builds
 # Bug 1283438
 mk_add_options AUTOCLOBBER=
--- a/mobile/android/config/mozconfigs/android-api-15/l10n-release
+++ b/mobile/android/config/mozconfigs/android-api-15/l10n-release
@@ -10,17 +10,16 @@ ac_add_options --disable-tests
 ac_add_options --with-android-min-sdk=15
 ac_add_options --target=arm-linux-androideabi
 
 ac_add_options --with-system-zlib
 ac_add_options --enable-updater
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 
 export MOZILLA_OFFICIAL=1
-export MOZ_DISABLE_GECKOVIEW=1
 
 ac_add_options --enable-official-branding
 ac_add_options --with-branding=mobile/android/branding/beta
 
 ac_add_options --disable-stdcxx-compat
 
 # Don't autoclobber l10n, as this can lead to missing binaries and broken builds
 # Bug 1283438
--- a/mobile/android/config/mozconfigs/android-api-15/nightly
+++ b/mobile/android/config/mozconfigs/android-api-15/nightly
@@ -10,11 +10,9 @@ ac_add_options --with-branding=mobile/an
 
 # This will overwrite the default of stripping everything and keep the symbol table.
 # This is useful for profiling with eideticker. See bug 788680
 STRIP_FLAGS="--strip-debug"
 
 export MOZILLA_OFFICIAL=1
 export MOZ_TELEMETRY_REPORTING=1
 
-MOZ_ANDROID_GECKOLIBS_AAR=1
-
 . "$topsrcdir/mobile/android/config/mozconfigs/common.override"
--- a/mobile/android/config/mozconfigs/android-x86/l10n-nightly
+++ b/mobile/android/config/mozconfigs/android-x86/l10n-nightly
@@ -9,17 +9,16 @@ ac_add_options --disable-tests
 # Android
 ac_add_options --target=i386-linux-android
 ac_add_options --with-android-min-sdk=15
 
 ac_add_options --enable-updater
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 
 export MOZILLA_OFFICIAL=1
-export MOZ_DISABLE_GECKOVIEW=1
 
 ac_add_options --with-branding=mobile/android/branding/nightly
 
 ac_add_options --disable-stdcxx-compat
 
 # Don't autoclobber l10n, as this can lead to missing binaries and broken builds
 # Bug 1283438
 mk_add_options AUTOCLOBBER=
--- a/mobile/android/config/mozconfigs/android-x86/l10n-release
+++ b/mobile/android/config/mozconfigs/android-x86/l10n-release
@@ -9,17 +9,16 @@ ac_add_options --disable-tests
 # Android
 ac_add_options --target=i386-linux-android
 ac_add_options --with-android-min-sdk=15
 
 ac_add_options --enable-updater
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 
 export MOZILLA_OFFICIAL=1
-export MOZ_DISABLE_GECKOVIEW=1
 
 ac_add_options --enable-official-branding
 ac_add_options --with-branding=mobile/android/branding/beta
 
 ac_add_options --disable-stdcxx-compat
 
 # Don't autoclobber l10n, as this can lead to missing binaries and broken builds
 # Bug 1283438
--- a/mobile/android/config/mozconfigs/public-partner/distribution_sample/mozconfig1
+++ b/mobile/android/config/mozconfigs/public-partner/distribution_sample/mozconfig1
@@ -13,11 +13,9 @@ ac_add_options --with-android-distributi
 
 # This will overwrite the default of stripping everything and keep the symbol table.
 # This is useful for profiling with eideticker. See bug 788680
 STRIP_FLAGS="--strip-debug"
 
 export MOZILLA_OFFICIAL=1
 export MOZ_TELEMETRY_REPORTING=1
 
-MOZ_ANDROID_GECKOLIBS_AAR=1
-
 . "$topsrcdir/mobile/android/config/mozconfigs/common.override"
deleted file mode 100644
--- a/mobile/android/geckoview_library/.classpath
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
-	<classpathentry kind="src" path="src"/>
-	<classpathentry kind="src" path="gen"/>
-	<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
-	<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES">
-		<attributes>
-			<attribute name="org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY" value="geckoview_library/libs/armeabi-v7a"/>
-		</attributes>
-	</classpathentry>
-	<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
-	<classpathentry kind="output" path="bin/classes"/>
-</classpath>
deleted file mode 100644
--- a/mobile/android/geckoview_library/.project
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-	<name>GeckoView</name>
-	<comment></comment>
-	<projects>
-	</projects>
-	<buildSpec>
-		<buildCommand>
-			<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
-			<arguments>
-			</arguments>
-		</buildCommand>
-		<buildCommand>
-			<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
-			<arguments>
-			</arguments>
-		</buildCommand>
-		<buildCommand>
-			<name>org.eclipse.jdt.core.javabuilder</name>
-			<arguments>
-			</arguments>
-		</buildCommand>
-		<buildCommand>
-			<name>com.android.ide.eclipse.adt.ApkBuilder</name>
-			<arguments>
-			</arguments>
-		</buildCommand>
-	</buildSpec>
-	<natures>
-		<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
-		<nature>org.eclipse.jdt.core.javanature</nature>
-	</natures>
-</projectDescription>
deleted file mode 100644
--- a/mobile/android/geckoview_library/AndroidManifest.xml.in
+++ /dev/null
@@ -1,13 +0,0 @@
-#filter substitution
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="org.mozilla.gecko"
-    android:versionCode="1"
-    android:versionName="1.0" >
-
-    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
-    <uses-permission android:name="android.permission.INTERNET"/>
-    <uses-sdk
-        android:minSdkVersion="8"
-        android:targetSdkVersion="@ANDROID_TARGET_SDK@" />
-
-</manifest>
deleted file mode 100644
--- a/mobile/android/geckoview_library/Makefile.in
+++ /dev/null
@@ -1,44 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-GARBAGE_DIRS = \
-  bin \
-  libs \
-  src \
-  .deps \
-  gen  \
-  res \
-  $(NULL)
-
-include $(topsrcdir)/config/rules.mk
-
-dist_files = $(addprefix $(ABS_DIST)/bin/, libmozglue.so $(MOZ_CHILD_PROCESS_NAME) $(MOZ_CHILD_PROCESS_NAME_PIE))
-
-package: local.properties project.properties AndroidManifest.xml FORCE
-	# Make directory for the zips
-	$(MKDIR) -p $(ABS_DIST)/geckoview_library
-
-	# Zip the assets into $(DIST)/geckoview_library/geckoview_assets.zip
-	$(call py_action,zip,-C $(ABS_DIST)/$(MOZ_APP_NAME) $(ABS_DIST)/geckoview_library/geckoview_assets.zip assets)
-
-	# Make empty directories to fit an Android project structure
-	$(MKDIR) -p bin gen libs/$(ANDROID_CPU_ARCH) src
-
-	# Copy the JARs, except for the jar containing org.mozilla.gecko.R.
-	# org.mozilla.gecko.R will be provided by the embedding application.
-	cp $(DEPTH)/mobile/android/base/*.jar libs/
-	$(RM) libs/gecko-R.jar
-
-	# Copy the SOs.
-	cp $(dist_files) libs/$(ANDROID_CPU_ARCH)/
-
-	# Copy the resources
-	$(RM) -rf res
-	$(MKDIR) -p res
-	cd res && \
-	$(UNZIP) -q -u -o $(ABS_DIST)/bin/geckoview_resources.zip
-
-	# Zip the directory
-	cd $(DEPTH)/mobile/android && \
-	$(ZIP) -q -r $(ABS_DIST)/geckoview_library/geckoview_library.zip geckoview_library -x geckoview_library/backend.mk geckoview_library/Makefile
deleted file mode 100644
--- a/mobile/android/geckoview_library/build.xml
+++ /dev/null
@@ -1,92 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project name="GeckoView" default="help">
-
-    <!-- The local.properties file is created and updated by the 'android' tool.
-         It contains the path to the SDK. It should *NOT* be checked into
-         Version Control Systems. -->
-    <property file="local.properties" />
-
-    <!-- The ant.properties file can be created by you. It is only edited by the
-         'android' tool to add properties to it.
-         This is the place to change some Ant specific build properties.
-         Here are some properties you may want to change/update:
-
-         source.dir
-             The name of the source directory. Default is 'src'.
-         out.dir
-             The name of the output directory. Default is 'bin'.
-
-         For other overridable properties, look at the beginning of the rules
-         files in the SDK, at tools/ant/build.xml
-
-         Properties related to the SDK location or the project target should
-         be updated using the 'android' tool with the 'update' action.
-
-         This file is an integral part of the build system for your
-         application and should be checked into Version Control Systems.
-
-         -->
-    <!--<property file="ant.properties" />-->
-
-    <!-- if sdk.dir was not set from one of the property file, then
-         get it from the ANDROID_HOME env var.
-         This must be done before we load project.properties since
-         the proguard config can use sdk.dir -->
-    <property environment="env" />
-    <condition property="sdk.dir" value="${env.ANDROID_HOME}">
-        <isset property="env.ANDROID_HOME" />
-    </condition>
-
-    <!-- The project.properties file is created and updated by the 'android'
-         tool, as well as ADT.
-
-         This contains project specific properties such as project target, and library
-         dependencies. Lower level build properties are stored in ant.properties
-         (or in .classpath for Eclipse projects).
-
-         This file is an integral part of the build system for your
-         application and should be checked into Version Control Systems. -->
-    <loadproperties srcFile="project.properties" />
-
-    <!-- quick check on sdk.dir -->
-    <fail
-            message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
-            unless="sdk.dir"
-    />
-
-    <!--
-        Import per project custom build rules if present at the root of the project.
-        This is the place to put custom intermediary targets such as:
-            -pre-build
-            -pre-compile
-            -post-compile (This is typically used for code obfuscation.
-                           Compiled code location: ${out.classes.absolute.dir}
-                           If this is not done in place, override ${out.dex.input.absolute.dir})
-            -post-package
-            -post-build
-            -pre-clean
-    -->
-    <import file="custom_rules.xml" optional="true" />
-
-    <!-- Import the actual build file.
-
-         To customize existing targets, there are two options:
-         - Customize only one target:
-             - copy/paste the target into this file, *before* the
-               <import> task.
-             - customize it to your needs.
-         - Customize the whole content of build.xml
-             - copy/paste the content of the rules files (minus the top node)
-               into this file, replacing the <import> task.
-             - customize to your needs.
-
-         ***********************
-         ****** IMPORTANT ******
-         ***********************
-         In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
-         in order to avoid having your file be overridden by tools such as "android update project"
-    -->
-    <!-- version-tag: 1 -->
-    <import file="${sdk.dir}/tools/ant/build.xml" />
-
-</project>
deleted file mode 100644
--- a/mobile/android/geckoview_library/geckolibs/AndroidManifest.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="org.mozilla.gecko.libs">
-
-</manifest>
deleted file mode 100644
index 09af11bda0c895e33494d4aac83c1171c3267ab8..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
--- a/mobile/android/geckoview_library/geckoview/AndroidManifest.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="org.mozilla.gecko">
-
-    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
-    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
-    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
-    <uses-permission android:name="android.permission.INTERNET"/>
-
-</manifest>
deleted file mode 100644
--- a/mobile/android/geckoview_library/local.properties.in
+++ /dev/null
@@ -1,11 +0,0 @@
-#filter substitution
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must *NOT* be checked into Version Control Systems,
-# as it contains information specific to your local configuration.
-
-# location of the SDK. This is only used by Ant
-# For customization when using a Version Control System, please read the
-# header note.
-sdk.dir=@ANDROID_SDK_ROOT@
deleted file mode 100644
--- a/mobile/android/geckoview_library/moz.build
+++ /dev/null
@@ -1,20 +0,0 @@
-# -*- Mode: python; 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/.
-
-DEFINES['ANDROID_SDK'] = CONFIG['ANDROID_SDK']
-DEFINES['ANDROID_SDK_ROOT'] = CONFIG['ANDROID_SDK_ROOT']
-
-OBJDIR_FILES.mobile.android.geckoview_library += [
-    '.classpath',
-    '.project',
-    'build.xml',
-]
-
-OBJDIR_PP_FILES.mobile.android.geckoview_library += [
-    'AndroidManifest.xml.in',
-    'local.properties.in',
-    'project.properties.in',
-]
deleted file mode 100644
--- a/mobile/android/geckoview_library/project.properties.in
+++ /dev/null
@@ -1,16 +0,0 @@
-#filter substitution
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must be checked in Version Control Systems.
-#
-# To customize properties used by the Ant build system edit
-# "ant.properties", and override values to adapt the script to your
-# project structure.
-#
-# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
-#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
-
-# Project target.
-target=android-@ANDROID_TARGET_SDK@
-android.library=true
--- a/mobile/android/moz.build
+++ b/mobile/android/moz.build
@@ -19,17 +19,16 @@ DIRS += [
     'base',
     'chrome',
     'components',
     'extensions',
     'modules',
     'themes/core',
     'app',
     'fonts',
-    'geckoview_library',
 ]
 
 if CONFIG['MOZ_ANDROID_PACKAGE_INSTALL_BOUNCER']:
     DIRS += ['bouncer'] # No ordering implied with respect to base.
 
 TEST_DIRS += [
     'tests',
 ]
--- a/modules/libjar/nsJARURI.cpp
+++ b/modules/libjar/nsJARURI.cpp
@@ -523,16 +523,30 @@ nsJARURI::CloneIgnoringRef(nsIURI **resu
     rv = CloneWithJARFileInternal(mJARFile, eIgnoreRef, getter_AddRefs(uri));
     if (NS_FAILED(rv)) return rv;
 
     uri.forget(result);
     return NS_OK;
 }
 
 NS_IMETHODIMP
+nsJARURI::CloneWithNewRef(const nsACString& newRef, nsIURI **result)
+{
+    nsresult rv;
+
+    nsCOMPtr<nsIJARURI> uri;
+    rv = CloneWithJARFileInternal(mJARFile, eReplaceRef, newRef,
+                                  getter_AddRefs(uri));
+    if (NS_FAILED(rv)) return rv;
+
+    uri.forget(result);
+    return NS_OK;
+}
+
+NS_IMETHODIMP
 nsJARURI::Resolve(const nsACString &relativePath, nsACString &result)
 {
     nsresult rv;
 
     nsCOMPtr<nsIIOService> ioServ(do_GetIOService(&rv));
     if (NS_FAILED(rv))
       return rv;
 
@@ -779,33 +793,45 @@ nsJARURI::CloneWithJARFile(nsIURI *jarFi
     return CloneWithJARFileInternal(jarFile, eHonorRef, result);
 }
 
 nsresult
 nsJARURI::CloneWithJARFileInternal(nsIURI *jarFile,
                                    nsJARURI::RefHandlingEnum refHandlingMode,
                                    nsIJARURI **result)
 {
+  return CloneWithJARFileInternal(jarFile, refHandlingMode, EmptyCString(), result);
+}
+
+nsresult
+nsJARURI::CloneWithJARFileInternal(nsIURI *jarFile,
+                                   nsJARURI::RefHandlingEnum refHandlingMode,
+                                   const nsACString& newRef,
+                                   nsIJARURI **result)
+{
     if (!jarFile) {
         return NS_ERROR_INVALID_ARG;
     }
 
     nsresult rv;
 
     nsCOMPtr<nsIURI> newJARFile;
     rv = jarFile->Clone(getter_AddRefs(newJARFile));
     if (NS_FAILED(rv)) return rv;
 
     NS_TryToSetImmutable(newJARFile);
 
     nsCOMPtr<nsIURI> newJAREntryURI;
-    rv = refHandlingMode == eHonorRef ?
-        mJAREntry->Clone(getter_AddRefs(newJAREntryURI)) :
-        mJAREntry->CloneIgnoringRef(getter_AddRefs(newJAREntryURI));
-
+    if (refHandlingMode == eHonorRef) {
+      rv = mJAREntry->Clone(getter_AddRefs(newJAREntryURI));
+    } else if (refHandlingMode == eReplaceRef) {
+      rv = mJAREntry->CloneWithNewRef(newRef, getter_AddRefs(newJAREntryURI));
+    } else {
+      rv = mJAREntry->CloneIgnoringRef(getter_AddRefs(newJAREntryURI));
+    }
     if (NS_FAILED(rv)) return rv;
 
     nsCOMPtr<nsIURL> newJAREntry(do_QueryInterface(newJAREntryURI));
     NS_ASSERTION(newJAREntry, "This had better QI to nsIURL!");
     
     nsJARURI* uri = new nsJARURI();
     NS_ADDREF(uri);
     uri->mJARFile = newJARFile;
--- a/modules/libjar/nsJARURI.h
+++ b/modules/libjar/nsJARURI.h
@@ -62,28 +62,33 @@ public:
     nsresult SetSpecWithBase(const nsACString& aSpec, nsIURI* aBaseURL);
 
 protected:
     virtual ~nsJARURI();
 
     // enum used in a few places to specify how .ref attribute should be handled
     enum RefHandlingEnum {
         eIgnoreRef,
-        eHonorRef
+        eHonorRef,
+        eReplaceRef
     };
 
     // Helper to share code between Equals methods.
     virtual nsresult EqualsInternal(nsIURI* other,
                                     RefHandlingEnum refHandlingMode,
                                     bool* result);
 
-    // Helper to share code between Clone methods.
+    // Helpers to share code between Clone methods.
     nsresult CloneWithJARFileInternal(nsIURI *jarFile,
                                       RefHandlingEnum refHandlingMode,
                                       nsIJARURI **result);
+    nsresult CloneWithJARFileInternal(nsIURI *jarFile,
+                                      RefHandlingEnum refHandlingMode,
+                                      const nsACString& newRef,
+                                      nsIJARURI **result);
     nsCOMPtr<nsIURI> mJARFile;
     // mJarEntry stored as a URL so that we can easily access things
     // like extensions, refs, etc.
     nsCOMPtr<nsIURL> mJAREntry;
     nsCString        mCharsetHint;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsJARURI, NS_THIS_JARURI_IMPL_CID)
--- a/netwerk/base/Predictor.cpp
+++ b/netwerk/base/Predictor.cpp
@@ -2427,16 +2427,26 @@ Predictor::UpdateCacheability(nsIURI *so
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (lci && lci->IsPrivate()) {
     PREDICTOR_LOG(("Predictor::UpdateCacheability in PB mode - ignoring"));
     return;
   }
 
+  if (!sourceURI || !targetURI) {
+    PREDICTOR_LOG(("Predictor::UpdateCacheability missing source or target uri"));
+    return;
+  }
+
+  if (!IsNullOrHttp(sourceURI) || !IsNullOrHttp(targetURI)) {
+    PREDICTOR_LOG(("Predictor::UpdateCacheability non-http(s) uri"));
+    return;
+  }
+
   RefPtr<Predictor> self = sSelf;
   if (self) {
     nsAutoCString method;
     requestHead.Method(method);
     self->UpdateCacheabilityInternal(sourceURI, targetURI, httpStatus,
                                      method);
   }
 }
--- a/netwerk/base/nsIOService.cpp
+++ b/netwerk/base/nsIOService.cpp
@@ -619,16 +619,22 @@ nsIOService::NewURI(const nsACString &aS
 
     nsAutoCString scheme;
     nsresult rv = ExtractScheme(aSpec, scheme);
     if (NS_FAILED(rv)) {
         // then aSpec is relative
         if (!aBaseURI)
             return NS_ERROR_MALFORMED_URI;
 
+        if (!aSpec.IsEmpty() && aSpec[0] == '#') {
+            // Looks like a reference instead of a fully-specified URI.
+            // --> initialize |uri| as a clone of |aBaseURI|, with ref appended.
+            return aBaseURI->CloneWithNewRef(aSpec, result);
+        }
+
         rv = aBaseURI->GetScheme(scheme);
         if (NS_FAILED(rv)) return rv;
     }
 
     // now get the handler for this scheme
     nsCOMPtr<nsIProtocolHandler> handler;
     rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
     if (NS_FAILED(rv)) return rv;
--- a/netwerk/base/nsIURI.idl
+++ b/netwerk/base/nsIURI.idl
@@ -241,16 +241,22 @@ interface nsIURI : nsISupports
     boolean equalsExceptRef(in nsIURI other);
 
     /**
      * Clones the current URI, clearing the 'ref' attribute in the clone.
      */
     nsIURI cloneIgnoringRef();
 
     /**
+     * Clones the current URI, replacing the 'ref' attribute in the clone with
+     * the ref supplied.
+     */
+    nsIURI cloneWithNewRef(in AUTF8String newRef);
+
+    /**
      * returns a string for the current URI with the ref element cleared.
      */
    readonly attribute AUTF8String specIgnoringRef;
 
     /**
      * Returns if there is a reference portion (the part after the "#") of the URI.
      */
    readonly attribute boolean hasRef;
--- a/netwerk/base/nsSimpleNestedURI.cpp
+++ b/netwerk/base/nsSimpleNestedURI.cpp
@@ -144,30 +144,37 @@ nsSimpleNestedURI::EqualsInternal(nsIURI
             }
         }
     }
 
     return NS_OK;
 }
 
 /* virtual */ nsSimpleURI*
-nsSimpleNestedURI::StartClone(nsSimpleURI::RefHandlingEnum refHandlingMode)
+nsSimpleNestedURI::StartClone(nsSimpleURI::RefHandlingEnum refHandlingMode,
+                              const nsACString& newRef)
 {
     NS_ENSURE_TRUE(mInnerURI, nullptr);
     
     nsCOMPtr<nsIURI> innerClone;
-    nsresult rv = refHandlingMode == eHonorRef ?
-        mInnerURI->Clone(getter_AddRefs(innerClone)) :
-        mInnerURI->CloneIgnoringRef(getter_AddRefs(innerClone));
+    nsresult rv;
+    if (refHandlingMode == eHonorRef) {
+        rv = mInnerURI->Clone(getter_AddRefs(innerClone));
+    } else if (refHandlingMode == eReplaceRef) {
+        rv = mInnerURI->CloneWithNewRef(newRef, getter_AddRefs(innerClone));
+    } else {
+        rv = mInnerURI->CloneIgnoringRef(getter_AddRefs(innerClone));
+    }
 
     if (NS_FAILED(rv)) {
         return nullptr;
     }
 
     nsSimpleNestedURI* url = new nsSimpleNestedURI(innerClone);
+    SetRefOnClone(url, refHandlingMode, newRef);
     url->SetMutable(false);
 
     return url;
 }
 
 // nsIClassInfo overrides
 
 NS_IMETHODIMP 
--- a/netwerk/base/nsSimpleNestedURI.h
+++ b/netwerk/base/nsSimpleNestedURI.h
@@ -46,17 +46,18 @@ public:
     NS_DECL_NSINESTEDURI
 
     // Overrides for various methods nsSimpleURI implements follow.
   
     // nsSimpleURI overrides
     virtual nsresult EqualsInternal(nsIURI* other,
                                     RefHandlingEnum refHandlingMode,
                                     bool* result) override;
-    virtual nsSimpleURI* StartClone(RefHandlingEnum refHandlingMode) override;
+    virtual nsSimpleURI* StartClone(RefHandlingEnum refHandlingMode,
+                                    const nsACString& newRef) override;
 
     // nsISerializable overrides
     NS_IMETHOD Read(nsIObjectInputStream* aStream) override;
     NS_IMETHOD Write(nsIObjectOutputStream* aStream) override;
 
     // nsIIPCSerializableURI overrides
     NS_DECL_NSIIPCSERIALIZABLEURI
 
--- a/netwerk/base/nsSimpleURI.cpp
+++ b/netwerk/base/nsSimpleURI.cpp
@@ -466,49 +466,68 @@ nsSimpleURI::SchemeIs(const char *i_Sche
     } else {
         *o_Equals = false;
     }
 
     return NS_OK;
 }
 
 /* virtual */ nsSimpleURI*
-nsSimpleURI::StartClone(nsSimpleURI::RefHandlingEnum /* ignored */)
+nsSimpleURI::StartClone(nsSimpleURI::RefHandlingEnum refHandlingMode,
+                        const nsACString& newRef)
 {
-    return new nsSimpleURI();
+    nsSimpleURI* url = new nsSimpleURI();
+    SetRefOnClone(url, refHandlingMode, newRef);
+    return url;
+}
+
+/* virtual */ void
+nsSimpleURI::SetRefOnClone(nsSimpleURI* url,
+                           nsSimpleURI::RefHandlingEnum refHandlingMode,
+                           const nsACString& newRef)
+{
+    if (refHandlingMode == eHonorRef) {
+        url->mRef = mRef;
+        url->mIsRefValid = mIsRefValid;
+    } else if (refHandlingMode == eReplaceRef) {
+        url->SetRef(newRef);
+    }
 }
 
 NS_IMETHODIMP
 nsSimpleURI::Clone(nsIURI** result)
 {
-    return CloneInternal(eHonorRef, result);
+    return CloneInternal(eHonorRef, EmptyCString(), result);
 }
 
 NS_IMETHODIMP
 nsSimpleURI::CloneIgnoringRef(nsIURI** result)
 {
-    return CloneInternal(eIgnoreRef, result);
+    return CloneInternal(eIgnoreRef, EmptyCString(), result);
+}
+
+NS_IMETHODIMP
+nsSimpleURI::CloneWithNewRef(const nsACString &newRef, nsIURI** result)
+{
+    return CloneInternal(eReplaceRef, newRef, result);
 }
 
 nsresult
 nsSimpleURI::CloneInternal(nsSimpleURI::RefHandlingEnum refHandlingMode,
+                           const nsACString &newRef,
                            nsIURI** result)
 {
-    RefPtr<nsSimpleURI> url = StartClone(refHandlingMode);
+    RefPtr<nsSimpleURI> url = StartClone(refHandlingMode, newRef);
     if (!url)
         return NS_ERROR_OUT_OF_MEMORY;
 
     // Note: |url| may well have mMutable false at this point, so
     // don't call any setter methods.
     url->mScheme = mScheme;
     url->mPath = mPath;
-    if (refHandlingMode == eHonorRef) {
-        url->mRef = mRef;
-        url->mIsRefValid = mIsRefValid;
-    }
 
     url.forget(result);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSimpleURI::Resolve(const nsACString &relativePath, nsACString &result) 
 {
--- a/netwerk/base/nsSimpleURI.h
+++ b/netwerk/base/nsSimpleURI.h
@@ -57,36 +57,44 @@ public:
     // - nsBlobURI: mPrincipal
     virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
     virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override;
 
 protected:
     // enum used in a few places to specify how .ref attribute should be handled
     enum RefHandlingEnum {
         eIgnoreRef,
-        eHonorRef
+        eHonorRef,
+        eReplaceRef
     };
 
     // Helper to share code between Equals methods.
     virtual nsresult EqualsInternal(nsIURI* other,
                                     RefHandlingEnum refHandlingMode,
                                     bool* result);
 
     // Helper to be used by inherited classes who want to test
     // equality given an assumed nsSimpleURI.  This must NOT check
     // the passed-in other for QI to our CID.
     bool EqualsInternal(nsSimpleURI* otherUri, RefHandlingEnum refHandlingMode);
 
+    // Used by StartClone (and versions of StartClone in subclasses) to
+    // handle the ref in the right way for clones.
+    void SetRefOnClone(nsSimpleURI* url, RefHandlingEnum refHandlingMode,
+                       const nsACString& newRef);
+
     // NOTE: This takes the refHandlingMode as an argument because
     // nsSimpleNestedURI's specialized version needs to know how to clone
     // its inner URI.
-    virtual nsSimpleURI* StartClone(RefHandlingEnum refHandlingMode);
+    virtual nsSimpleURI* StartClone(RefHandlingEnum refHandlingMode,
+                                    const nsACString& newRef);
 
     // Helper to share code between Clone methods.
     virtual nsresult CloneInternal(RefHandlingEnum refHandlingMode,
+                                   const nsACString &newRef,
                                    nsIURI** clone);
     
     nsCString mScheme;
     nsCString mPath; // NOTE: mPath does not include ref, as an optimization
     nsCString mRef;  // so that URIs with different refs can share string data.
     bool mMutable;
     bool mIsRefValid; // To distinguish between empty-ref and no-ref.
 };
--- a/netwerk/base/nsStandardURL.cpp
+++ b/netwerk/base/nsStandardURL.cpp
@@ -1305,17 +1305,17 @@ nsStandardURL::SetSpec(const nsACString 
     net_FilterURIString(flat, filteredURI);
 
     if (filteredURI.Length() == 0) {
         return NS_ERROR_MALFORMED_URI;
     }
 
     // Make a backup of the curent URL
     nsStandardURL prevURL(false,false);
-    prevURL.CopyMembers(this, eHonorRef);
+    prevURL.CopyMembers(this, eHonorRef, EmptyCString());
     Clear();
 
     if (IsSpecialProtocol(filteredURI)) {
         // Bug 652186: Replace all backslashes with slashes when parsing paths
         // Stop when we reach the query or the hash.
         nsAutoCString::iterator start;
         nsAutoCString::iterator end;
         filteredURI.BeginWriting(start);
@@ -1346,17 +1346,17 @@ nsStandardURL::SetSpec(const nsACString 
     if (mURLType == URLTYPE_AUTHORITY && mHost.mLen == -1) {
         rv = NS_ERROR_MALFORMED_URI;
     }
 
     if (NS_FAILED(rv)) {
         Clear();
         // If parsing the spec has failed, restore the old URL
         // so we don't end up with an empty URL.
-        CopyMembers(&prevURL, eHonorRef);
+        CopyMembers(&prevURL, eHonorRef, EmptyCString());
         return rv;
     }
 
     if (LOG_ENABLED()) {
         LOG((" spec      = %s\n", mSpec.get()));
         LOG((" port      = %d\n", mPort));
         LOG((" scheme    = (%u,%d)\n", mScheme.mPos,    mScheme.mLen));
         LOG((" authority = (%u,%d)\n", mAuthority.mPos, mAuthority.mLen));
@@ -2036,45 +2036,53 @@ nsStandardURL::StartClone()
 {
     nsStandardURL *clone = new nsStandardURL();
     return clone;
 }
 
 NS_IMETHODIMP
 nsStandardURL::Clone(nsIURI **result)
 {
-    return CloneInternal(eHonorRef, result);
+    return CloneInternal(eHonorRef, EmptyCString(), result);
 }
 
 
 NS_IMETHODIMP
 nsStandardURL::CloneIgnoringRef(nsIURI **result)
 {
-    return CloneInternal(eIgnoreRef, result);
+    return CloneInternal(eIgnoreRef, EmptyCString(), result);
+}
+
+NS_IMETHODIMP
+nsStandardURL::CloneWithNewRef(const nsACString& newRef, nsIURI **result)
+{
+    return CloneInternal(eReplaceRef, newRef, result);
 }
 
 nsresult
 nsStandardURL::CloneInternal(nsStandardURL::RefHandlingEnum refHandlingMode,
+                             const nsACString& newRef,
                              nsIURI **result)
 
 {
     RefPtr<nsStandardURL> clone = StartClone();
     if (!clone)
         return NS_ERROR_OUT_OF_MEMORY;
 
     // Copy local members into clone.
     // Also copies the cached members mFile, mHostA
-    clone->CopyMembers(this, refHandlingMode, true);
+    clone->CopyMembers(this, refHandlingMode, newRef, true);
 
     clone.forget(result);
     return NS_OK;
 }
 
 nsresult nsStandardURL::CopyMembers(nsStandardURL * source,
-    nsStandardURL::RefHandlingEnum refHandlingMode, bool copyCached)
+    nsStandardURL::RefHandlingEnum refHandlingMode, const nsACString& newRef,
+    bool copyCached)
 {
     mSpec = source->mSpec;
     mDefaultPort = source->mDefaultPort;
     mPort = source->mPort;
     mScheme = source->mScheme;
     mAuthority = source->mAuthority;
     mUsername = source->mUsername;
     mPassword = source->mPassword;
@@ -2101,16 +2109,18 @@ nsresult nsStandardURL::CopyMembers(nsSt
         // The same state as after calling InvalidateCache()
         mFile = nullptr;
         mHostA = nullptr;
         mSpecEncoding = eEncoding_Unknown;
     }
 
     if (refHandlingMode == eIgnoreRef) {
         SetRef(EmptyCString());
+    } else if (refHandlingMode == eReplaceRef) {
+        SetRef(newRef);
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStandardURL::Resolve(const nsACString &in, nsACString &out)
 {
--- a/netwerk/base/nsStandardURL.h
+++ b/netwerk/base/nsStandardURL.h
@@ -144,33 +144,36 @@ public: /* internal -- HPUX compiler can
         nsCOMPtr<nsIUnicodeEncoder> mEncoder;
     };
     friend class nsSegmentEncoder;
 
 protected:
     // enum used in a few places to specify how .ref attribute should be handled
     enum RefHandlingEnum {
         eIgnoreRef,
-        eHonorRef
+        eHonorRef,
+        eReplaceRef
     };
 
     // Helper to share code between Equals and EqualsExceptRef
     // NOTE: *not* virtual, because no one needs to override this so far...
     nsresult EqualsInternal(nsIURI* unknownOther,
                             RefHandlingEnum refHandlingMode,
                             bool* result);
 
     virtual nsStandardURL* StartClone();
 
     // Helper to share code between Clone methods.
     nsresult CloneInternal(RefHandlingEnum aRefHandlingMode,
+                           const nsACString& newRef,
                            nsIURI** aClone);
     // Helper method that copies member variables from the source StandardURL
     // if copyCached = true, it will also copy mFile and mHostA
     nsresult CopyMembers(nsStandardURL * source, RefHandlingEnum mode,
+                         const nsACString& newRef,
                          bool copyCached = false);
 
     // Helper for subclass implementation of GetFile().  Subclasses that map
     // URIs to files in a special way should implement this method.  It should
     // ensure that our mFile is initialized, if it's possible.
     // returns NS_ERROR_NO_INTERFACE if the url does not map to a file
     virtual nsresult EnsureFile();
 
--- a/netwerk/protocol/about/nsAboutProtocolHandler.cpp
+++ b/netwerk/protocol/about/nsAboutProtocolHandler.cpp
@@ -387,33 +387,40 @@ nsNestedAboutURI::Write(nsIObjectOutputS
         if (NS_FAILED(rv)) return rv;
     }
 
     return NS_OK;
 }
 
 // nsSimpleURI
 /* virtual */ nsSimpleURI*
-nsNestedAboutURI::StartClone(nsSimpleURI::RefHandlingEnum aRefHandlingMode)
+nsNestedAboutURI::StartClone(nsSimpleURI::RefHandlingEnum aRefHandlingMode,
+                             const nsACString& aNewRef)
 {
     // Sadly, we can't make use of nsSimpleNestedURI::StartClone here.
     // However, this function is expected to exactly match that function,
     // aside from the "new ns***URI()" call.
     NS_ENSURE_TRUE(mInnerURI, nullptr);
 
     nsCOMPtr<nsIURI> innerClone;
-    nsresult rv = aRefHandlingMode == eHonorRef ?
-        mInnerURI->Clone(getter_AddRefs(innerClone)) :
-        mInnerURI->CloneIgnoringRef(getter_AddRefs(innerClone));
+    nsresult rv;
+    if (aRefHandlingMode == eHonorRef) {
+        rv = mInnerURI->Clone(getter_AddRefs(innerClone));
+    } else if (aRefHandlingMode == eReplaceRef) {
+        rv = mInnerURI->CloneWithNewRef(aNewRef, getter_AddRefs(innerClone));
+    } else {
+        rv = mInnerURI->CloneIgnoringRef(getter_AddRefs(innerClone));
+    }
 
     if (NS_FAILED(rv)) {
         return nullptr;
     }
 
     nsNestedAboutURI* url = new nsNestedAboutURI(innerClone, mBaseURI);
+    SetRefOnClone(url, aRefHandlingMode, aNewRef);
     url->SetMutable(false);
 
     return url;
 }
 
 // nsIClassInfo
 NS_IMETHODIMP
 nsNestedAboutURI::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
--- a/netwerk/protocol/about/nsAboutProtocolHandler.h
+++ b/netwerk/protocol/about/nsAboutProtocolHandler.h
@@ -65,17 +65,18 @@ public:
     virtual ~nsNestedAboutURI() {}
 
     // Override QI so we can QI to our CID as needed
     NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
 
     // Override StartClone(), the nsISerializable methods, and
     // GetClassIDNoAlloc; this last is needed to make our nsISerializable impl
     // work right.
-    virtual nsSimpleURI* StartClone(RefHandlingEnum aRefHandlingMode);
+    virtual nsSimpleURI* StartClone(RefHandlingEnum aRefHandlingMode,
+                                    const nsACString& newRef);
     NS_IMETHOD Read(nsIObjectInputStream* aStream);
     NS_IMETHOD Write(nsIObjectOutputStream* aStream);
     NS_IMETHOD GetClassIDNoAlloc(nsCID *aClassIDNoAlloc);
 
     nsIURI* GetBaseURI() const {
         return mBaseURI;
     }
 
--- a/netwerk/test/unit/test_URIs.js
+++ b/netwerk/test/unit/test_URIs.js
@@ -421,16 +421,29 @@ function do_test_uri_with_hash_suffix(aT
 
   if (!origURI.ref) {
     // These tests fail if origURI has a ref
     do_info("testing cloneIgnoringRef on " + testURI.spec +
             " is equal to no-ref version but not equal to ref version");
     var cloneNoRef = testURI.cloneIgnoringRef();
     do_check_uri_eq(cloneNoRef, origURI);
     do_check_false(cloneNoRef.equals(testURI));
+
+    do_info("testing cloneWithNewRef on " + testURI.spec +
+            " with an empty ref is equal to no-ref version but not equal to ref version");
+    var cloneNewRef = testURI.cloneWithNewRef("");
+    do_check_uri_eq(cloneNewRef, origURI);
+    do_check_uri_eq(cloneNewRef, cloneNoRef);
+    do_check_false(cloneNewRef.equals(testURI));
+
+    do_info("testing cloneWithNewRef on " + origURI.spec +
+            " with the same new ref is equal to ref version and not equal to no-ref version");
+    cloneNewRef = origURI.cloneWithNewRef(aSuffix);
+    do_check_uri_eq(cloneNewRef, testURI);
+    do_check_true(cloneNewRef.equals(testURI));
   }
 
   do_check_property(aTest, testURI, "scheme");
   do_check_property(aTest, testURI, "prePath");
   if (!origURI.ref) {
     // These don't work if it's a ref already because '+' doesn't give the right result
     do_check_property(aTest, testURI, "path",
                       function(aStr) { return aStr + aSuffix; });
--- a/old-configure.in
+++ b/old-configure.in
@@ -68,18 +68,16 @@ 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.13.0
 FONTCONFIG_VERSION=2.7.0
 
-MSMANIFEST_TOOL=
-
 dnl Set various checks
 dnl ========================================================
 MISSING_X=
 
 dnl Initialize the Pthread test variables early so they can be
 dnl  overridden by each platform.
 dnl ========================================================
 MOZ_USE_PTHREADS=
@@ -250,37 +248,18 @@ MOZ_TOOL_VARIABLES
 
 AC_PROG_CPP
 AC_PROG_CXXCPP
 
 dnl ========================================================
 dnl Special win32 checks
 dnl ========================================================
 
-# Target the Windows 8.1 SDK by default
-WINSDK_TARGETVER=603
 WINVER=502
 
-MOZ_ARG_WITH_STRING(windows-version,
-[  --with-windows-version=WINSDK_TARGETVER
-                          Windows SDK version to target. Win8.1 (603) is
-                          currently the minimum supported version.],
-  WINSDK_TARGETVER=$withval)
-
-# Currently only version 603 is allowed
-case "$WINSDK_TARGETVER" in
-603)
-    MOZ_WINSDK_TARGETVER=0${WINSDK_TARGETVER}0000
-    ;;
-
-*)
-    AC_MSG_ERROR([Invalid value for --with-windows-version ($WINSDK_TARGETVER)]);
-    ;;
-esac
-
 case "$target" in
 *-mingw*)
     if test "$GCC" != "yes"; then
         # Check to see if we are really running in a msvc environemnt
         _WIN32_MSVC=1
         AC_CHECK_PROGS(MIDL, midl)
 
         # Make sure compilers are valid
@@ -361,36 +340,16 @@ case "$target" in
 
         if test -n "$WIN32_REDIST_DIR"; then
           if test ! -d "$WIN32_REDIST_DIR"; then
             AC_MSG_ERROR([Invalid Win32 Redist directory: ${WIN32_REDIST_DIR}])
           fi
           WIN32_REDIST_DIR=`cd "$WIN32_REDIST_DIR" && pwd -W`
         fi
 
-        dnl Ensure that mt.exe is 'Microsoft (R) Manifest Tool',
-        dnl not something else like "magnetic tape manipulation utility".
-        MT=${MT-mt.exe}
-        MSMT_TOOL=`${MT} 2>&1|grep 'Microsoft (R) Manifest Tool'`
-        if test -z "$MSMT_TOOL"; then
-          AC_MSG_ERROR([Microsoft (R) Manifest Tool must be in your \$PATH.])
-        fi
-
-        changequote(,)
-        _MSMT_VER_FILTER='s|.*[^!-~]\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*|\1|p'
-        changequote([,])
-        MSMANIFEST_TOOL_VERSION=`echo ${MSMT_TOOL}|sed -ne "$_MSMT_VER_FILTER"`
-        if test -z "$MSMANIFEST_TOOL_VERSION"; then
-          AC_MSG_WARN([Unknown version of the Microsoft (R) Manifest Tool.])
-        fi
-
-        MSMANIFEST_TOOL=1
-        unset MSMT_TOOL
-        AC_SUBST(MT)
-
         # Check linker version
         _LD_FULL_VERSION=`"${LD}" -v 2>&1 | sed -nre "$_MSVC_VER_FILTER"`
         _LD_MAJOR_VERSION=`echo ${_LD_FULL_VERSION} | $AWK -F\. '{ print $1 }'`
         if test "$_LD_MAJOR_VERSION" != "$_CC_SUITE"; then
             AC_MSG_ERROR([The linker major version, $_LD_FULL_VERSION,  does not match the compiler suite version, $_CC_SUITE.])
         fi
 
         INCREMENTAL_LINKER=1
@@ -486,35 +445,21 @@ case "$target" in
             esac
         fi
 
         # strsafe.h on mingw uses macros for function deprecation that pollutes namespace
         # causing problems with local implementations with the same name.
         AC_DEFINE(STRSAFE_NO_DEPRECATE)
     fi # !GNU_CC
 
-    MOZ_FIND_WINSDK_VERSION
     AC_DEFINE_UNQUOTED(WINVER,0x$WINVER)
     AC_DEFINE_UNQUOTED(_WIN32_WINNT,0x$WINVER)
     # Require OS features provided by IE 6.0 SP2 (XP SP2)
     AC_DEFINE_UNQUOTED(_WIN32_IE,0x0603)
 
-    # If the maximum version supported by this SDK is lower than the target
-    # version, error out
-    AC_MSG_CHECKING([for Windows SDK being recent enough])
-    if $PERL -e "exit(0x$MOZ_WINSDK_TARGETVER > $MOZ_WINSDK_MAXVER)"; then
-        AC_MSG_RESULT("yes")
-    else
-        AC_MSG_RESULT("no")
-        AC_MSG_ERROR([You are targeting Windows version 0x$MOZ_WINSDK_TARGETVER, but your SDK only supports up to version $MOZ_WINSDK_MAXVER. Install and use an updated SDK, or target a lower version using --with-windows-version. Alternatively, try running the Windows SDK Configuration Tool and selecting a newer SDK. See https://developer.mozilla.org/En/Windows_SDK_versions for more details on fixing this.])
-    fi
-
-    AC_DEFINE_UNQUOTED(MOZ_WINSDK_TARGETVER,0x$MOZ_WINSDK_TARGETVER)
-    AC_DEFINE_UNQUOTED(MOZ_WINSDK_MAXVER,$MOZ_WINSDK_MAXVER)
-    AC_SUBST(MOZ_WINSDK_MAXVER)
     ;;
 esac
 
 if test -n "$_WIN32_MSVC"; then
     SKIP_PATH_CHECKS=1
     SKIP_COMPILER_CHECKS=1
     SKIP_LIBRARY_CHECKS=1
 
@@ -6157,18 +6102,16 @@ AC_SUBST(MOZ_D3D_CPU_SUFFIX)
 AC_SUBST(MOZ_HAS_WINSDK_WITH_D3D)
 AC_SUBST(MOZ_D3DCOMPILER_VISTA_DLL)
 AC_SUBST(MOZ_D3DCOMPILER_VISTA_DLL_PATH)
 AC_SUBST(MOZ_DIRECTX_SDK_PATH)
 AC_SUBST(MOZ_D3DCOMPILER_XP_DLL)
 AC_SUBST(MOZ_D3DCOMPILER_XP_CAB)
 
 AC_SUBST(MOZ_WEBSMS_BACKEND)
-AC_SUBST(MOZ_DISABLE_GECKOVIEW)
-AC_SUBST(MOZ_ANDROID_GECKOLIBS_AAR)
 AC_SUBST(MOZ_ANDROID_APPLICATION_CLASS)
 AC_SUBST(MOZ_ANDROID_BROWSER_INTENT_CLASS)
 AC_SUBST(MOZ_ANDROID_SEARCH_INTENT_CLASS)
 AC_SUBST(MOZ_EXCLUDE_HYPHENATION_DICTIONARIES)
 AC_SUBST(MOZ_INSTALL_TRACKING)
 AC_SUBST(ENABLE_STRIP)
 AC_SUBST(PKG_SKIP_STRIP)
 AC_SUBST(STRIP_FLAGS)
@@ -6509,17 +6452,16 @@ AC_SUBST(DLL_PREFIX)
 AC_SUBST(DLL_SUFFIX)
 AC_DEFINE_UNQUOTED(MOZ_DLL_SUFFIX, "$DLL_SUFFIX")
 AC_SUBST(LIB_SUFFIX)
 AC_SUBST(OBJ_SUFFIX)
 AC_SUBST(BIN_SUFFIX)
 AC_SUBST(IMPORT_LIB_SUFFIX)
 AC_SUBST(USE_N32)
 AC_SUBST(CC_VERSION)
-AC_SUBST(MSMANIFEST_TOOL)
 AC_SUBST(NS_ENABLE_TSF)
 AC_SUBST(WIN32_CONSOLE_EXE_LDFLAGS)
 AC_SUBST(WIN32_GUI_EXE_LDFLAGS)
 
 AC_SUBST(MOZ_VORBIS)
 AC_SUBST(MOZ_TREMOR)
 AC_SUBST(MOZ_FFVPX)
 AC_SUBST_LIST(FFVPX_ASFLAGS)
--- a/parser/xml/test/unit/results.js
+++ b/parser/xml/test/unit/results.js
@@ -134,17 +134,17 @@ var vectors = [
     "sanitized": "<html><head></head><body><a></a><a>XXX</a><a>XXX</a></body></html>"
   },
   {
     "data": "1<vmlframe xmlns=urn:schemas-microsoft-com:vml style=behavior:url(#default#vml);position:absolute;width:100%;height:100% src=test.vml#xss></vmlframe>",
     "sanitized": "<html><head></head><body>1</body></html>"
   },
   {
     "data": "1<a href=#><line xmlns=urn:schemas-microsoft-com:vml style=behavior:url(#default#vml);position:absolute href=javascript:alert(1) strokecolor=white strokeweight=1000px from=0 to=1000 /></a>",
-    "sanitized": "<html><head></head><body>1<a></a></body></html>"
+    "sanitized": "<html><head></head><body>1<a href=\"#\"></a></body></html>"
   },
   {
     "data": "<a style=\"behavior:url(#default#AnchorClick);\" folder=\"javascript:alert(1)\">XXX</a>",
     "sanitized": "<html><head></head><body><a>XXX</a></body></html>"
   },
   {
     "data": "<!--<img src=\"--><img src=x onerror=alert(1)//\">",
     "sanitized": "<html><head></head><body><img></body></html>"
@@ -474,17 +474,17 @@ var vectors = [
     "sanitized": "<html><head></head><body><div draggable=\"true\">\n\t<h1>Drop me</h1>\n</div>\n\n</body></html>"
   },
   {
     "data": "<iframe src=\"view-source:http://www.example.org/\" frameborder=\"0\" style=\"width:400px;height:180px\"></iframe>\n\n<textarea type=\"text\" cols=\"50\" rows=\"10\"></textarea>",
     "sanitized": "<html><head></head><body>\n\n<textarea type=\"text\" cols=\"50\" rows=\"10\"></textarea></body></html>"
   },
   {
     "data": "<script>\nfunction makePopups(){\n\tfor (i=1;i<6;i++) {\n\t\twindow.open('popup.html','spam'+i,'width=50,height=50');\n\t}\n}\n</script>\n\n<body>\n<a href=\"#\" onclick=\"makePopups()\">Spam</a>",
-    "sanitized": "<html><head>\n\n</head><body>\n<a>Spam</a></body></html>"
+    "sanitized": "<html><head>\n\n</head><body>\n<a href=\"#\">Spam</a></body></html>"
   },
   {
     "data": "<html xmlns=\"http://www.w3.org/1999/xhtml\"\nxmlns:svg=\"http://www.w3.org/2000/svg\">\n<body style=\"background:gray\">\n<iframe src=\"http://example.com/\" style=\"width:800px; height:350px; border:none; mask: url(#maskForClickjacking);\"/>\n<svg:svg>\n<svg:mask id=\"maskForClickjacking\" maskUnits=\"objectBoundingBox\" maskContentUnits=\"objectBoundingBox\">\n\t<svg:rect x=\"0.0\" y=\"0.0\" width=\"0.373\" height=\"0.3\" fill=\"white\"/>\n\t<svg:circle cx=\"0.45\" cy=\"0.7\" r=\"0.075\" fill=\"white\"/>\n</svg:mask>\n</svg:svg>\n</body>\n</html>",
     "sanitized": "<html><head></head><body>\n\n&lt;svg:svg&gt;\n&lt;svg:mask id=\"maskForClickjacking\" maskUnits=\"objectBoundingBox\" maskContentUnits=\"objectBoundingBox\"&gt;\n\t&lt;svg:rect x=\"0.0\" y=\"0.0\" width=\"0.373\" height=\"0.3\" fill=\"white\"/&gt;\n\t&lt;svg:circle cx=\"0.45\" cy=\"0.7\" r=\"0.075\" fill=\"white\"/&gt;\n&lt;/svg:mask&gt;\n&lt;/svg:svg&gt;\n&lt;/body&gt;\n&lt;/html&gt;</body></html>"
   },
   {
     "data": "<iframe sandbox=\"allow-same-origin allow-forms allow-scripts\" src=\"http://example.org/\"></iframe>",
     "sanitized": "<html><head></head><body></body></html>"
deleted file mode 100644
--- a/python/mozbuild/mozbuild/action/package_geckolibs_aar.py
+++ /dev/null
@@ -1,267 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-'''
-Script to produce an Android ARchive (.aar) containing the compiled
-Gecko library binaries.  The AAR file is intended for use by local
-developers using Gradle.
-'''
-
-from __future__ import absolute_import, print_function
-
-import argparse
-import hashlib
-import os
-import shutil
-import sys
-import zipfile
-
-from mozbuild import util
-from mozpack.copier import Jarrer
-from mozpack.files import (
-    File,
-    FileFinder,
-    JarFinder,
-)
-from mozpack.mozjar import JarReader
-
-MAVEN_POM_TEMPLATE = r'''
-<?xml version="1.0" encoding="UTF-8"?>
-<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
-  <modelVersion>4.0.0</modelVersion>
-  <groupId>{groupId}</groupId>
-  <artifactId>{artifactId}</artifactId>
-  <version>{version}</version>
-  <packaging>{packaging}</packaging>
-  <dependencies>
-    {dependencies}
-  </dependencies>
-</project>
-'''.lstrip()
-
-MAVEN_POM_DEPENDENCY_TEMPLATE = r'''
-  <dependency>
-     <groupId>{groupId}</groupId>
-     <artifactId>{artifactId}</artifactId>
-     <version>{version}</version>
-     <type>{packaging}</type>
-  </dependency>
-'''.lstrip()
-
-IVY_XML_TEMPLATE = r'''
-<?xml version="1.0" encoding="UTF-8"?>
-<ivy-module version="2.0">
-  <info organisation="{organisation}" module="{module}" revision="{revision}" status="integration" publication="{publication}"/>
-  <configurations/>
-  <publications>
-    <artifact name="{name}" type="{type}" ext="{ext}"/>
-  </publications>
-  <dependencies>
-    {dependencies}
-  </dependencies>
-</ivy-module>
-'''.lstrip()
-
-IVY_XML_DEPENDENCY_TEMPLATE = r'''
-<dependency org="{organisation}" name="{name}" rev="{revision}" />
-'''.lstrip()
-
-def _zipdir(path, output_file):
-    zip = zipfile.ZipFile(output_file, "w")
-    for root, dirs, files in os.walk(path, topdown=True):
-        archive_root = root.replace(path, '')
-        for file in files:
-            zip.write(os.path.join(root, file), os.path.join(archive_root, file))
-
-def _generate_geckoview_classes_jar(distdir, base_path):
-    base_folder = FileFinder(base_path, ignore=['gecko-R.jar'])
-
-    # Unzip all jar files into $(DISTDIR)/geckoview_aar_classes.
-    geckoview_aar_classes_path = os.path.join(distdir, 'geckoview_aar_classes')
-    shutil.rmtree(geckoview_aar_classes_path, ignore_errors=True)
-    util.ensureParentDir(geckoview_aar_classes_path)
-
-    for p, f in base_folder.find('*.jar'):
-        with zipfile.ZipFile(f.path) as zf:
-            zf.extractall(geckoview_aar_classes_path)
-
-    # Rezip them into a single classes.jar file.
-    classes_jar_path =  os.path.join(distdir, 'classes.jar')
-    _zipdir(geckoview_aar_classes_path, classes_jar_path)
-    return File(classes_jar_path)
-
-def package_geckolibs_aar(topsrcdir, distdir, appname, output_file):
-    jarrer = Jarrer(optimize=False)
-
-    srcdir = os.path.join(topsrcdir, 'mobile', 'android', 'geckoview_library', 'geckolibs')
-    jarrer.add('AndroidManifest.xml', File(os.path.join(srcdir, 'AndroidManifest.xml')))
-    jarrer.add('classes.jar', File(os.path.join(srcdir, 'classes.jar')))
-
-    jni = FileFinder(os.path.join(distdir, appname, 'lib'))
-    for p, f in jni.find('**/*.so'):
-        jarrer.add(os.path.join('jni', p), f)
-
-    # Include the buildinfo JSON as an asset, to give future consumers at least
-    # a hope of determining where this AAR came from.
-    json = FileFinder(distdir, ignore=['*.mozinfo.json'])
-    for p, f in json.find('*.json'):
-        jarrer.add(os.path.join('assets', p), f)
-
-    # This neatly ignores omni.ja.
-    assets = FileFinder(os.path.join(distdir, appname, 'assets'))
-    for p, f in assets.find('**/*.so'):
-        jarrer.add(os.path.join('assets', p), f)
-
-    jarrer.copy(output_file)
-    return 0
-
-def package_geckoview_aar(topsrcdir, distdir, appname, output_file):
-    jarrer = Jarrer(optimize=False)
-    app_path = os.path.join(distdir, appname)
-    assets = FileFinder(os.path.join(app_path, 'assets'), ignore=['*.so'])
-    for p, f in assets.find('omni.ja'):
-        jarrer.add(os.path.join('assets', p), f)
-
-    # The folder that contains Fennec's JAR files and resources.
-    base_path = os.path.join(distdir, '..', 'mobile', 'android', 'base')
-
-    # The resource set is packaged during Fennec's build.
-    resjar = JarReader(os.path.join(base_path, 'geckoview_resources.zip'))
-    for p, f in JarFinder(base_path, resjar).find('*'):
-        jarrer.add(os.path.join('res', p), f)
-
-    # Package the contents of all Fennec JAR files into classes.jar.
-    classes_jar_file = _generate_geckoview_classes_jar(distdir, base_path)
-    jarrer.add('classes.jar', classes_jar_file)
-
-    # Add R.txt.
-    jarrer.add('R.txt', File(os.path.join(base_path, 'R.txt')))
-
-    # Finally add AndroidManifest.xml.
-    srcdir = os.path.join(topsrcdir, 'mobile', 'android', 'geckoview_library', 'geckoview')
-    jarrer.add('AndroidManifest.xml', File(os.path.join(srcdir, 'AndroidManifest.xml')))
-
-    jarrer.copy(output_file)
-    return 0
-
-def main(args):
-    parser = argparse.ArgumentParser()
-    parser.add_argument(dest='dir',
-                        metavar='DIR',
-                        help='Path to write Android ARchives and metadata to.')
-    parser.add_argument('--verbose', '-v', default=False, action='store_true',
-                        help='be verbose')
-    parser.add_argument('--revision',
-                        help='Revision identifier to write.')
-    parser.add_argument('--topsrcdir',
-                        help='Top source directory.')
-    parser.add_argument('--distdir',
-                        help='Distribution directory (usually $OBJDIR/dist).')
-    parser.add_argument('--appname',
-                        help='Application name (usually $MOZ_APP_NAME, like "fennec").')
-    parser.add_argument('--purge-old', default=False, action='store_true',
-                        help='Delete any existing output files in the output directory.')
-    args = parser.parse_args(args)
-
-    # An Ivy 'publication' date must be given in the form yyyyMMddHHmmss, and Mozilla buildids are in this format.
-    if len(args.revision) != 14:
-        raise ValueError('Revision must be in yyyyMMddHHmmss format: %s' % args.revision)
-
-    paths_to_hash = []
-
-    groupId='org.mozilla'
-    packaging_type='aar'
-    gecklibs_aar = os.path.join(args.dir, 'geckolibs-{revision}.aar').format(revision=args.revision)
-    paths_to_hash.append(gecklibs_aar)
-    geckoview_aar = os.path.join(args.dir, 'geckoview-{revision}.aar').format(revision=args.revision)
-    paths_to_hash.append(geckoview_aar)
-
-    if args.purge_old:
-        old_output_finder = FileFinder(args.dir, find_executables=False)
-        for p, f in old_output_finder.find('geckoview-*.*'):
-            os.remove(f.path)
-        for p, f in old_output_finder.find('geckolibs-*.*'):
-            os.remove(f.path)
-        for p, f in old_output_finder.find('ivy-*.*'):
-            os.remove(f.path)
-
-    package_geckolibs_aar(args.topsrcdir, args.distdir, args.appname, gecklibs_aar)
-    package_geckoview_aar(args.topsrcdir, args.distdir, args.appname, geckoview_aar)
-
-    geckolibs_pom_path = os.path.join(args.dir, 'geckolibs-{revision}.pom').format(revision=args.revision)
-    paths_to_hash.append(geckolibs_pom_path)
-    geckolibs_pom = MAVEN_POM_TEMPLATE.format(
-            groupId=groupId,
-            artifactId='geckolibs',
-            version=args.revision,
-            packaging=packaging_type,
-            dependencies=''
-        )
-
-    with open(geckolibs_pom_path, 'wt') as f:
-        f.write(geckolibs_pom)
-
-    geckoview_pom_path = os.path.join(args.dir, 'geckoview-{revision}.pom').format(revision=args.revision)
-    paths_to_hash.append(geckoview_pom_path)
-    geckoview_pom = MAVEN_POM_TEMPLATE.format(
-        groupId=groupId,
-        artifactId='geckoview',
-        version=args.revision,
-        packaging=packaging_type,
-        dependencies=MAVEN_POM_DEPENDENCY_TEMPLATE.format(
-            groupId=groupId,
-            artifactId='geckolibs',
-            version=args.revision,
-            packaging=packaging_type
-        )
-    )
-
-    with open(geckoview_pom_path, 'wt') as f:
-        f.write(geckoview_pom)
-
-    geckolibs_ivy_path = os.path.join(args.dir, 'ivy-geckolibs-{revision}.xml').format(revision=args.revision)
-    paths_to_hash.append(geckolibs_ivy_path)
-    with open(geckolibs_ivy_path, 'wt') as f:
-        f.write(IVY_XML_TEMPLATE.format(
-            organisation=groupId,
-            module='geckolibs',
-            revision=args.revision,
-            publication=args.revision, # A white lie.
-            name='geckolibs',
-            type=packaging_type,
-            ext=packaging_type,
-            dependencies=''
-        ))
-
-    geckoview_ivy_path = os.path.join(args.dir, 'ivy-geckoview-{revision}.xml').format(revision=args.revision)
-    paths_to_hash.append(geckoview_ivy_path)
-    with open(geckoview_ivy_path, 'wt') as f:
-        f.write(IVY_XML_TEMPLATE.format(
-            organisation=groupId,
-            module='geckoview',
-            revision=args.revision,
-            publication=args.revision, # A white lie.
-            name='geckoview',
-            type=packaging_type,
-            ext=packaging_type,
-            dependencies=IVY_XML_DEPENDENCY_TEMPLATE.format(
-                organisation=groupId,
-                name='geckolibs',
-                revision=args.revision)
-        ))
-
-    for p in paths_to_hash:
-        sha = "%s.sha1" % p
-        with open(sha, 'wt') as f:
-            f.write(util.hash_file(p, hasher=hashlib.sha1()))
-        if args.verbose:
-            print(p)
-            print(sha)
-
-    return 0
-
-
-if __name__ == '__main__':
-    sys.exit(main(sys.argv[1:]))
--- a/security/certverifier/tests/gtest/CTTestUtils.cpp
+++ b/security/certverifier/tests/gtest/CTTestUtils.cpp
@@ -120,16 +120,17 @@ CharToByte(char c)
   if (c >= '0' && c <= '9') {
     return c - '0';
   } else if (c >= 'a' && c <= 'f') {
     return c - 'a' + 10;
   } else if (c >= 'A' && c <= 'F') {
     return c - 'A' + 10;
   }
   MOZ_RELEASE_ASSERT(false);
+  return 0;
 }
 
 static Buffer
 HexToBytes(const char* hexData)
 {
   size_t hexLen = strlen(hexData);
   MOZ_RELEASE_ASSERT(hexLen > 0 && (hexLen % 2 == 0));
   size_t resultLen = hexLen / 2;
--- a/taskcluster/taskgraph/transforms/tests/desktop_test.py
+++ b/taskcluster/taskgraph/transforms/tests/desktop_test.py
@@ -39,16 +39,28 @@ def set_treeherder_machine_platform(conf
     }
     for test in tests:
         build_platform = test['build-platform']
         test['treeherder-machine-platform'] = translation.get(build_platform, build_platform)
         yield test
 
 
 @transforms.add
+def set_asan_docker_image(config, tests):
+    """Set the appropriate task.extra.treeherder.docker-image"""
+    # Linux64-asan has many leaks with running mochitest-media jobs
+    # on Ubuntu 16.04, please remove this when bug 1289209 is resolved
+    for test in tests:
+        if test['suite'] == 'mochitest/mochitest-media' and \
+           test['build-platform'] == 'linux64-asan/opt':
+            test['docker-image'] = {"in-tree": "desktop-test"}
+        yield test
+
+
+@transforms.add
 def split_e10s(config, tests):
     for test in tests:
         e10s = get_keyed_by(item=test, field='e10s',
                             item_name=test['test-name'])
         test.setdefault('attributes', {})
         test['e10s'] = False
         test['attributes']['e10s'] = False
 
--- a/testing/marionette/client/marionette_driver/decorators.py
+++ b/testing/marionette/client/marionette_driver/decorators.py
@@ -1,55 +1,61 @@
 # 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/.
 
-from errors import MarionetteException
+from errors import MarionetteException, TimeoutException
 from functools import wraps
 import socket
 import sys
 import traceback
 
 
 def _find_marionette_in_args(*args, **kwargs):
     try:
         m = [a for a in args + tuple(kwargs.values()) if hasattr(a, 'session')][0]
     except IndexError:
         print("Can only apply decorator to function using a marionette object")
         raise
     return m
 
 
-def do_crash_check(func, always=False):
-    """Decorator which checks for crashes after the function has run.
+def do_process_check(func, always=False):
+    """Decorator which checks the process after the function has run.
+
+    There is a check for crashes which always gets executed. And in the case of
+    connection issues the process will be force closed.
 
     :param always: If False, only checks for crashes if an exception
                    was raised. If True, always checks for crashes.
     """
     @wraps(func)
     def _(*args, **kwargs):
-        def check():
-            m = _find_marionette_in_args(*args, **kwargs)
+        m = _find_marionette_in_args(*args, **kwargs)
+
+        def check_for_crash():
             try:
                 m.check_for_crash()
             except:
                 # don't want to lose the original exception
                 traceback.print_exc()
 
         try:
             return func(*args, **kwargs)
         except (MarionetteException, socket.error, IOError) as e:
             exc, val, tb = sys.exc_info()
             if not isinstance(e, MarionetteException) or type(e) is MarionetteException:
                 if not always:
-                    check()
+                    check_for_crash()
+            if not isinstance(e, MarionetteException) or type(e) is TimeoutException:
+                m.force_shutdown()
             raise exc, val, tb
         finally:
             if always:
-                check()
+                check_for_crash(m)
     return _
 
 
 def uses_marionette(func):
     """Decorator which creates a marionette session and deletes it
     afterwards if one doesn't already exist.
     """
     @wraps(func)
--- a/testing/marionette/client/marionette_driver/errors.py
+++ b/testing/marionette/client/marionette_driver/errors.py
@@ -25,36 +25,36 @@ class MarionetteException(Exception):
             information about the root exception cause.  Expected
             tuple values are (type, value, traceback).
 
         :param stacktrace: Optional string containing a stacktrace
             (typically from a failed JavaScript execution) that will
             be displayed in the exception's string representation.
 
         """
-
-        self.msg = message
         self.cause = cause
         self.stacktrace = stacktrace
 
+        super(MarionetteException, self).__init__(message)
+
     def __str__(self):
-        msg = str(self.msg)
+        msg = str(self.message)
         tb = None
 
         if self.cause:
             if type(self.cause) is tuple:
                 msg += ", caused by %r" % self.cause[0]
                 tb = self.cause[2]
             else:
                 msg += ", caused by %s" % self.cause
         if self.stacktrace:
             st = "".join(["\t%s\n" % x for x in self.stacktrace.splitlines()])
             msg += "\nstacktrace:\n%s" % st
 
-        return "".join(traceback.format_exception(self.__class__, msg, tb))
+        return "".join(traceback.format_exception(self.__class__, msg, tb)).strip()
 
 
 class ElementNotSelectableException(MarionetteException):
     status = "element not selectable"
 
 
 class InvalidArgumentException(MarionetteException):
     status = "invalid argument"
--- a/testing/marionette/client/marionette_driver/marionette.py
+++ b/testing/marionette/client/marionette_driver/marionette.py
@@ -2,22 +2,23 @@
 # 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/.
 
 import base64
 import ConfigParser
 import json
 import os
 import socket
+import sys
 import traceback
 import warnings
 
 from contextlib import contextmanager
 
-from decorators import do_crash_check
+from decorators import do_process_check
 from keys import Keys
 
 import geckoinstance
 import errors
 import transport
 
 WEBELEMENT_KEY = "ELEMENT"
 W3C_WEBELEMENT_KEY = "element-6066-11e4-a52e-4f735466cecf"
@@ -639,22 +640,22 @@ class Marionette(object):
             return False
         finally:
             s.close()
 
     def wait_for_port(self, timeout=None):
         timeout = timeout or self.DEFAULT_STARTUP_TIMEOUT
         return transport.wait_for_port(self.host, self.port, timeout=timeout)
 
-    @do_crash_check
+    @do_process_check
     def raise_for_port(self, port_obtained):
         if not port_obtained:
             raise IOError("Timed out waiting for port!")
 
-    @do_crash_check
+    @do_process_check
     def _send_message(self, name, params=None, key=None):
         """Send a blocking message to the server.
 
         Marionette provides an asynchronous, non-blocking interface and
         this attempts to paper over this by providing a synchronous API
         to the user.
 
         :param name: Requested command key.
@@ -674,24 +675,16 @@ class Marionette(object):
                 if params:
                     data["parameters"] = params
                 self.client.send(data)
                 msg = self.client.receive()
 
             else:
                 msg = self.client.request(name, params)
 
-        except IOError:
-            if self.instance:
-                # If we've launched the binary we've connected to, wait
-                # for it to shut down.
-                returncode = self.instance.runner.wait(timeout=self.DEFAULT_STARTUP_TIMEOUT)
-                raise IOError("process died with returncode %s" % returncode)
-            raise
-
         except socket.timeout:
             self.session = None
             self.window = None
             self.client.close()
             raise errors.TimeoutException("Connection timed out")
 
         res, err = msg.result, msg.error
         if err:
@@ -746,16 +739,38 @@ class Marionette(object):
             if self.instance.runner.check_for_crashes(
                     test_name=self.test_name):
                 crashed = True
         if returncode is not None:
             print ('PROCESS-CRASH | %s | abnormal termination with exit code %d' %
                    (name, returncode))
         return crashed
 
+    def force_shutdown(self):
+        """Force a shutdown of the running instance.
+
+        If we've launched the binary we are connected to, wait for it to shut down.
+        In the case when it doesn't happen, force its shut down.
+
+        """
+        if self.instance:
+            exc, val, tb = sys.exc_info()
+
+            returncode = self.instance.runner.returncode
+            if returncode is None:
+                self.instance.runner.stop()
+                message = 'Process killed because the connection was lost'
+            else:
+                message = 'Process died with returncode "{returncode}"'
+
+            if exc:
+                message += ' (Reason: {reason})'
+
+            raise exc, message.format(returncode=returncode, reason=val), tb
+
     @staticmethod
     def convert_keys(*string):
         typing = []
         for val in string:
             if isinstance(val, Keys):
                 typing.append(val)
             elif isinstance(val, int):
                 val = str(val)
--- a/testing/marionette/harness/marionette/tests/unit/single_finger_functions.py
+++ b/testing/marionette/harness/marionette/tests/unit/single_finger_functions.py
@@ -2,17 +2,18 @@ from marionette_driver.marionette import
 from marionette_driver.errors import TimeoutException
 from marionette_driver.by import By
 
 
 def wait_for_condition_else_raise(marionette, wait_for_condition, expected, script):
     try:
         wait_for_condition(lambda m: expected in m.execute_script(script))
     except TimeoutException as e:
-        raise TimeoutException(e.msg + " got %s instead of %s" % (marionette.execute_script(script), expected))
+        raise TimeoutException("{0} got {1} instead of {2}".format(
+            e.message, marionette.execute_script(script), expected))
 
 def press_release(marionette, times, wait_for_condition, expected):
     testAction = marionette.absolute_url("testAction.html")
     marionette.navigate(testAction)
     action = Actions(marionette)
     button = marionette.find_element(By.ID, "button1")
     action.press(button).release()
     # Insert wait between each press and release chain.
--- a/testing/marionette/harness/marionette/tests/unit/test_errors.py
+++ b/testing/marionette/harness/marionette/tests/unit/test_errors.py
@@ -15,34 +15,34 @@ def fake_cause():
 
 message = "foo"
 cause = fake_cause()
 stacktrace = "first\nsecond"
 
 class TestErrors(marionette_test.MarionetteTestCase):
     def test_defaults(self):
         exc = errors.MarionetteException()
-        self.assertIsNone(exc.msg)
+        self.assertIsNone(exc.message)
         self.assertIsNone(exc.cause)
         self.assertIsNone(exc.stacktrace)
 
     def test_construction(self):
         exc = errors.MarionetteException(
             message=message, cause=cause, stacktrace=stacktrace)
-        self.assertEquals(exc.msg, message)
+        self.assertEquals(exc.message, message)
         self.assertEquals(exc.cause, cause)
         self.assertEquals(exc.stacktrace, stacktrace)
 
     def test_str(self):
         exc = errors.MarionetteException(
             message=message, cause=cause, stacktrace=stacktrace)
         r = str(exc)
         self.assertIn(message, r)
         self.assertIn(", caused by %r" % cause[0], r)
-        self.assertIn("\nstacktrace:\n\tfirst\n\tsecond\n", r)
+        self.assertIn("\nstacktrace:\n\tfirst\n\tsecond", r)
         self.assertIn("MarionetteException:", r)
 
     def test_cause_string(self):
         exc = errors.MarionetteException(cause="foo")
         self.assertEqual(exc.cause, "foo")
         r = str(exc)
         self.assertIn(", caused by foo", r)
 
--- a/testing/marionette/harness/marionette/tests/unit/test_execute_script.py
+++ b/testing/marionette/harness/marionette/tests/unit/test_execute_script.py
@@ -31,17 +31,17 @@ class TestExecuteSimpleTestContent(Mario
     def test_stack_trace(self):
         try:
             self.marionette.execute_js_script("""
                 let a = 1;
                 throwHere();
                 """, filename="file.js")
             self.assertFalse(True)
         except errors.JavascriptException as e:
-            self.assertIn("throwHere is not defined", e.msg)
+            self.assertIn("throwHere is not defined", e.message)
             self.assertIn("@file.js:2", e.stacktrace)
 
 
 class TestExecuteContent(MarionetteTestCase):
     def test_return_number(self):
         self.assertEqual(1, self.marionette.execute_script("return 1"))
         self.assertEqual(1.5, self.marionette.execute_script("return 1.5"))
 
@@ -133,17 +133,17 @@ class TestExecuteContent(MarionetteTestC
     def test_stacktrace(self):
         try:
             self.marionette.execute_script("return b")
             self.assertFalse(True)
         except errors.JavascriptException as e:
             # by default execute_script pass the name of the python file
             self.assertIn(
                 os.path.basename(__file__.replace(".pyc", ".py")), e.stacktrace)
-            self.assertIn("b is not defined", e.msg)
+            self.assertIn("b is not defined", e.message)
             self.assertIn("return b", e.stacktrace)
 
     def test_permission(self):
         with self.assertRaises(errors.JavascriptException):
             self.marionette.execute_script("""
                 let prefs = Components.classes["@mozilla.org/preferences-service;1"]
                     .getService(Components.interfaces.nsIPrefBranch)""")
 
--- a/testing/marionette/harness/marionette/tests/unit/test_proxy.py
+++ b/testing/marionette/harness/marionette/tests/unit/test_proxy.py
@@ -220,17 +220,17 @@ class TestProxy(MarionetteTestCase):
                                     {
                                     "proxy":"I really should be a dictionary"
                                     }
                             }
         try:
             self.marionette.start_session(capabilities)
             self.fail("We should have started a session because proxy should be a dict")
         except InvalidArgumentException as e:
-            assert e.msg == "Value of 'proxy' should be an object"
+            assert e.message == "Value of 'proxy' should be an object"
 
     def test_proxy_is_passed_in_with_no_proxy_doesnt_set_it(self):
         capabilities = {"requiredCapabilities":
             {
                 "proxy": {"proxyType": "NOPROXY"},
             }
         }
         self.marionette.start_session(capabilities)
--- a/testing/marionette/harness/marionette/tests/unit/test_switch_frame.py
+++ b/testing/marionette/harness/marionette/tests/unit/test_switch_frame.py
@@ -66,17 +66,17 @@ class TestSwitchFrame(MarionetteTestCase
         self.marionette.switch_to_frame()
         self.assertEqual(verify_title, self.marionette.title)
         self.marionette.switch_to_frame(inner_frame_element)
         self.assertTrue(start_url in self.marionette.get_url())
 
         try:
             self.marionette.execute_async_script("foo();")
         except JavascriptException as e:
-            self.assertTrue("foo" in e.msg)
+            self.assertTrue("foo" in e.message)
 
     def test_should_be_able_to_carry_on_working_if_the_frame_is_deleted_from_under_us(self):
         test_html = self.marionette.absolute_url("deletingFrame.html")
         self.marionette.navigate(test_html)
 
         self.marionette.switch_to_frame(self.marionette.find_element(By.ID,
                                                                      'iframe1'))
         killIframe = self.marionette.find_element(By.ID, "killIframe")
--- a/testing/marionette/harness/marionette/tests/unit/test_switch_frame_chrome.py
+++ b/testing/marionette/harness/marionette/tests/unit/test_switch_frame_chrome.py
@@ -42,9 +42,9 @@ class TestSwitchFrameChrome(MarionetteTe
 
     def test_stack_trace(self):
         self.assertIn("test.xul", self.marionette.get_url(), "Initial navigation has failed")
         self.marionette.switch_to_frame(0)
         self.assertRaises(JavascriptException, self.marionette.execute_async_script, "foo();")
         try:
             self.marionette.execute_async_script("foo();")
         except JavascriptException as e:
-            self.assertIn("foo", e.msg)
+            self.assertIn("foo", e.message)
--- a/testing/web-platform/tests/web-animations/interfaces/AnimationEffectTiming/easing.html
+++ b/testing/web-platform/tests/web-animations/interfaces/AnimationEffectTiming/easing.html
@@ -23,17 +23,18 @@ function assert_progress(animation, curr
 
 gEffectEasingTests.forEach(function(options) {
   test(function(t) {
     var target = createDiv(t);
     var anim = target.animate([ { opacity: 0 }, { opacity: 1 } ],
                               { duration: 1000 * MS_PER_SEC,
                                 fill: 'forwards' });
     anim.effect.timing.easing = options.easing;
-    assert_equals(anim.effect.timing.easing, options.easing);
+    assert_equals(anim.effect.timing.easing,
+                  options.serialization || options.easing);
 
     var easing = options.easingFunction;
     assert_progress(anim, 0, easing);
     assert_progress(anim, 250 * MS_PER_SEC, easing);
     assert_progress(anim, 500 * MS_PER_SEC, easing);
     assert_progress(anim, 750 * MS_PER_SEC, easing);
     assert_progress(anim, 1000 * MS_PER_SEC, easing);
   }, options.desc);
--- a/testing/web-platform/tests/web-animations/resources/effect-easing-tests.js
+++ b/testing/web-platform/tests/web-animations/resources/effect-easing-tests.js
@@ -1,18 +1,47 @@
 var gEffectEasingTests = [
   {
-    desc: 'steps(start) function',
+    desc: 'step-start function',
+    easing: 'step-start',
+    easingFunction: stepStart(1),
+    serialization: 'steps(1, start)'
+  },
+  {
+    desc: 'steps(1, start) function',
+    easing: 'steps(1, start)',
+    easingFunction: stepStart(1)
+  },
+  {
+    desc: 'steps(2, start) function',
     easing: 'steps(2, start)',
     easingFunction: stepStart(2)
   },
   {
-    desc: 'steps(end) function',
+    desc: 'step-end function',
+    easing: 'step-end',
+    easingFunction: stepEnd(1),
+    serialization: 'steps(1)'
+  },
+  {
+    desc: 'steps(1) function',
+    easing: 'steps(1)',
+    easingFunction: stepEnd(1)
+  },
+  {
+    desc: 'steps(1, end) function',
+    easing: 'steps(1, end)',
+    easingFunction: stepEnd(1),
+    serialization: 'steps(1)'
+  },
+  {
+    desc: 'steps(2, end) function',
     easing: 'steps(2, end)',
-    easingFunction: stepEnd(2)
+    easingFunction: stepEnd(2),
+    serialization: 'steps(2)'
   },
   {
     desc: 'linear function',
     easing: 'linear', // cubic-bezier(0, 0, 1.0, 1.0)
     easingFunction: cubicBezier(0, 0, 1.0, 1.0)
   },
   {
     desc: 'ease function',
--- a/testing/web-platform/tests/web-animations/resources/keyframe-utils.js
+++ b/testing/web-platform/tests/web-animations/resources/keyframe-utils.js
@@ -316,19 +316,19 @@ var gKeyframeSequenceTests = [
     output: [{ offset: 0.0, computedOffset: 0.0, easing: "ease",
                left: "10px" },
              { offset: 0.0, computedOffset: 0.0, easing: "ease",
                top: "20px" },
              { offset: 0.5, computedOffset: 0.5, easing: "linear",
                left: "30px" },
              { offset: 0.5, computedOffset: 0.5, easing: "linear",
                top: "40px" },
-             { offset: 1.0, computedOffset: 1.0, easing: "step-end",
+             { offset: 1.0, computedOffset: 1.0, easing: "steps(1)",
                left: "50px" },
-             { offset: 1.0, computedOffset: 1.0, easing: "step-end",
+             { offset: 1.0, computedOffset: 1.0, easing: "steps(1)",
                top: "60px" }] },
   { desc:   "a keyframe sequence with different composite values, but the"
             + " same composite value for a given offset",
     input:  [{ offset: 0.0, composite: "replace", left: "10px" },
              { offset: 0.0, composite: "replace", top: "20px" },
              { offset: 0.5, composite: "add",     left: "30px" },
              { offset: 0.5, composite: "add",     top: "40px" },
              { offset: 1.0, composite: "replace", left: "50px" },
@@ -427,17 +427,17 @@ var gKeyframeSequenceTests = [
     output: [{ offset: 0.0, computedOffset: 0.0, easing: "ease",
                left: "100px" },
              { offset: 0.0, computedOffset: 0.0, easing: "ease",
                left: "200px" },
              { offset: 0.5, computedOffset: 0.5, easing: "linear",
                left: "300px" },
              { offset: 1.0, computedOffset: 1.0, easing: "ease-out",
                left: "400px" },
-             { offset: 1.0, computedOffset: 1.0, easing: "step-end",
+             { offset: 1.0, computedOffset: 1.0, easing: "steps(1)",
                left: "500px" }] },
 ];
 
 var gInvalidKeyframesTests = [
   { desc:     "keyframes with an out-of-bounded positive offset",
     input:    [ { opacity: 0 },
                 { opacity: 0.5, offset: 2 },
                 { opacity: 1 } ],
--- a/toolkit/components/extensions/ext-backgroundPage.js
+++ b/toolkit/components/extensions/ext-backgroundPage.js
@@ -105,31 +105,31 @@ BackgroundPage.prototype = {
     // TODO(robwu): This implementation of onStartup is wrong, see
     // https://bugzil.la/1247435#c1
     if (this.extension.onStartup) {
       this.extension.onStartup();
     }
   }),
 
   shutdown() {
+    if (this.extension.addonData.instanceID) {
+      AddonManager.getAddonByInstanceID(this.extension.addonData.instanceID)
+                  .then(addon => addon.setDebugGlobal(null));
+    }
+
     // Navigate away from the background page to invalidate any
     // setTimeouts or other callbacks.
     if (this.webNav) {
       this.webNav.loadURI("about:blank", 0, null, null, null);
       this.webNav = null;
     }
 
     this.windowlessBrowser.loadURI("about:blank", 0, null, null, null);
     this.windowlessBrowser.close();
     this.windowlessBrowser = null;
-
-    if (this.extension.addonData.instanceID) {
-      AddonManager.getAddonByInstanceID(this.extension.addonData.instanceID)
-                  .then(addon => addon.setDebugGlobal(null));
-    }
   },
 };
 
 /* eslint-disable mozilla/balanced-listeners */
 extensions.on("manifest_background", (type, directive, extension, manifest) => {
   let bgPage = new BackgroundPage(manifest.background, extension);
   backgroundPagesMap.set(extension, bgPage);
   return bgPage.build();
--- a/toolkit/components/extensions/test/mochitest/test_chrome_ext_background_debug_global.html
+++ b/toolkit/components/extensions/test/mochitest/test_chrome_ext_background_debug_global.html
@@ -10,16 +10,21 @@
   <link rel="stylesheet" href="chrome://mochikit/contents/tests/SimpleTest/test.css"/>
 </head>
 <body>
 
 <script type="text/javascript">
 "use strict";
 
 Cu.import("resource://devtools/client/framework/ToolboxProcess.jsm");
+Cu.import("resource://gre/modules/AddonManager.jsm");
+
+const {
+  XPIProvider,
+} = Components.utils.import("resource://gre/modules/addons/XPIProvider.jsm");
 
 /**
  * This test is asserting that ext-backgroundPage.js successfully sets its
  * debug global in the AddonWrapper provided by XPIProvider.jsm
  *
  * It does _not_ test any functionality in devtools and does not guarantee
  * debugging is actually working correctly end-to-end.
  */
@@ -34,17 +39,16 @@ let extensionData = {
   background: "(" + backgroundScript.toString() + ")()",
   manifest: {},
   files: {},
 };
 
 add_task(function* () {
   let extension = ExtensionTestUtils.loadExtension(extensionData);
   yield extension.startup();
-  info("extension loaded");
 
   yield extension.awaitFinish("background script ran");
 
   yield new Promise(function(resolve) {
     window.BrowserToolboxProcess.emit("connectionchange", "opened", {
       setAddonOptions(id, options) {
         if (id === extension.id) {
           let context = Cu.waiveXrays(options.global);
@@ -52,15 +56,109 @@ add_task(function* () {
           ok(context.browser, "global context has a browser object");
           is("test!", context.testThing, "global context is the background script context");
           resolve();
         }
       },
     });
   });
 
+  let addon = yield new Promise((resolve, reject) => {
+    AddonManager.getAddonByID(extension.id, addon => addon ? resolve(addon) : reject());
+  });
+
+  ok(addon, `Got the addon wrapper for ${addon.id}`);
+
+  function waitForDebugGlobalChanges(times, initialAddonInstanceID) {
+    return new Promise((resolve) => {
+      AddonManager.addAddonListener({
+        count: 0,
+        notNullGlobalsCount: 0,
+        undefinedPrivateWrappersCount: 0,
+        lastAddonInstanceID: initialAddonInstanceID,
+        onPropertyChanged(newAddon, changedPropNames) {
+          if (newAddon.id != addon.id ||
+              !changedPropNames.includes("debugGlobal")) {
+            return;
+          }
+
+          ok(!(newAddon.setDebugGlobal) && !(newAddon.getDebugGlobal),
+             "The addon wrapper should not be a PrivateWrapper");
+
+          let activeAddon = XPIProvider.activeAddons.get(addon.id);
+
+          let addonInstanceID;
+
+          if (!activeAddon) {
+            // The addon has been disable, the preferred global should be null
+            addonInstanceID = this.lastAddonInstanceID;
+            delete this.lastAddonInstanceID;
+          } else {
+            addonInstanceID = activeAddon.instanceID;
+            this.lastAddonInstanceID = addonInstanceID;
+          }
+
+          ok(addonInstanceID, `Got the addon instanceID for ${addon.id}`);
+
+          AddonManager.getAddonByInstanceID(addonInstanceID).then((privateWrapper) => {
+            this.count += 1;
+
+            if (!privateWrapper) {
+              // The addon has been uninstalled
+              this.undefinedPrivateWrappersCount += 1;
+            } else {
+              ok((privateWrapper.getDebugGlobal), "Got the addon PrivateWrapper");
+
+              if (privateWrapper.getDebugGlobal()) {
+                this.notNullGlobalsCount += 1;
+              }
+            }
+
+            if (this.count == times) {
+              AddonManager.removeAddonListener(this);
+              resolve({
+                counters: {
+                  count: this.count,
+                  notNullGlobalsCount: this.notNullGlobalsCount,
+                  undefinedPrivateWrappersCount: this.undefinedPrivateWrappersCount,
+                },
+                lastAddonInstanceID: this.lastAddonInstanceID,
+              });
+            }
+          });
+        },
+      });
+    });
+  }
+
+  // two calls expected, one for the shutdown and one for the startup
+  // of the background page.
+  let waitForDebugGlobalChangesOnReload = waitForDebugGlobalChanges(2);
+
+  info("Addon reload...");
+  yield addon.reload();
+
+  info("Addon completed startup after reload");
+
+  let {
+    counters: reloadCounters,
+    lastAddonInstanceID,
+  } = yield waitForDebugGlobalChangesOnReload;
+
+  isDeeply(reloadCounters, {count: 2, notNullGlobalsCount: 1, undefinedPrivateWrappersCount: 0},
+           "Got the expected number of onPropertyChanged calls on reload");
+
+  // one more call expected for the shutdown.
+  let waitForDebugGlobalChangesOnShutdown = waitForDebugGlobalChanges(1, lastAddonInstanceID);
+
+  info("extension unloading...");
   yield extension.unload();
   info("extension unloaded");
+
+  let {counters: unloadCounters} = yield waitForDebugGlobalChangesOnShutdown;
+
+  isDeeply(unloadCounters, {count: 1, notNullGlobalsCount: 0, undefinedPrivateWrappersCount: 1},
+           "Got the expected number of onPropertyChanged calls on shutdown");
 });
 </script>
 
 </body>
 </html>
--- a/toolkit/content/widgets/findbar.xml
+++ b/toolkit/content/widgets/findbar.xml
@@ -757,16 +757,19 @@
         <body><![CDATA[
           if (this.hidden)
             return;
 
           if (aNoAnim)
             this.setAttribute("noanim", true);
           this.hidden = true;
 
+          // 'focusContent()' iterates over all listeners in the chrome
+          // process, so we need to call it from here.
+          this.browser.finder.focusContent();
           this.browser.finder.onFindbarClose();
 
           this._cancelTimers();
 
           this._findFailedString = null;
         ]]></body>
       </method>
 
--- a/toolkit/modules/Finder.jsm
+++ b/toolkit/modules/Finder.jsm
@@ -292,17 +292,16 @@ Finder.prototype = {
         fastFind.collapseSelection();
       } else {
         this._getWindow().focus()
       }
     } catch (e) {}
   },
 
   onFindbarClose: function() {
-    this.focusContent();
     this.enableSelection();
     this.highlighter.highlight(false);
   },
 
   onModalHighlightChange(useModalHighlight) {
     if (this._highlighter)
       this._highlighter.onModalHighlightChange(useModalHighlight);
   },
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -7542,32 +7542,64 @@ AddonWrapper.prototype = {
  * called with the add-on instanceID, disallowing other add-ons to access it.
  */
 function PrivateWrapper(aAddon) {
   AddonWrapper.call(this, aAddon);
 }
 
 PrivateWrapper.prototype = Object.create(AddonWrapper.prototype);
 Object.assign(PrivateWrapper.prototype, {
-
   addonId() {
     return this.id;
   },
 
   /**
+   * Retrieves the preferred global context to be used from the
+   * add-on debugging window.
+   *
+   * @returns  global
+   *         The object set as global context. Must be a window object.
+   */
+  getDebugGlobal(global) {
+    let activeAddon = XPIProvider.activeAddons.get(this.id);
+    if (activeAddon) {
+      return activeAddon.debugGlobal;
+    }
+
+    return null;
+  },
+
+  /**
    * Defines a global context to be used in the console
    * of the add-on debugging window.
    *
    * @param  global
    *         The object to set as global context. Must be a window object.
    */
   setDebugGlobal(global) {
-    let activeAddon = XPIProvider.activeAddons.get(this.id);
-    if (activeAddon) {
-      activeAddon.debugGlobal = global;
+    if (!global) {
+      // If the new global is null, notify the listeners regardless
+      // from the current state of the addon.
+      // NOTE: this happen after the addon has been disabled and
+      // the global will never be set to null otherwise.
+      AddonManagerPrivate.callAddonListeners("onPropertyChanged",
+                                             addonFor(this),
+                                             ["debugGlobal"]);
+    } else {
+      let activeAddon = XPIProvider.activeAddons.get(this.id);
+      if (activeAddon) {
+        let globalChanged = activeAddon.debugGlobal != global;
+        activeAddon.debugGlobal = global;
+
+        if (globalChanged) {
+          AddonManagerPrivate.callAddonListeners("onPropertyChanged",
+                                                 addonFor(this),
+                                                 ["debugGlobal"]);
+        }
+      }
     }
   }
 });
 
 function chooseValue(aAddon, aObj, aProp) {
   let repositoryAddon = aAddon._repositoryAddon;
   let objValue = aObj[aProp];
 
--- a/toolkit/mozapps/installer/upload-files-APK.mk
+++ b/toolkit/mozapps/installer/upload-files-APK.mk
@@ -20,18 +20,16 @@ ROOT_FILES := \
   $(NULL)
 
 GECKO_APP_AP_PATH = $(topobjdir)/mobile/android/base
 
 ifdef ENABLE_TESTS
 INNER_ROBOCOP_PACKAGE=true
 ifeq ($(MOZ_BUILD_APP),mobile/android)
 UPLOAD_EXTRA_FILES += robocop.apk
-UPLOAD_EXTRA_FILES += geckoview_library/geckoview_library.zip
-UPLOAD_EXTRA_FILES += geckoview_library/geckoview_assets.zip
 
 # Robocop/Robotium tests, Android Background tests, and Fennec need to
 # be signed with the same key, which means release signing them all.
 
 ifndef MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE
 robocop_apk := $(topobjdir)/mobile/android/tests/browser/robocop/robocop-debug-unsigned-unaligned.apk
 else
 robocop_apk := $(topobjdir)/gradle/build/mobile/android/app/outputs/apk/app-automation-debug-androidTest-unaligned.apk
@@ -65,65 +63,16 @@ INNER_INSTALL_BOUNCER_PACKAGE=\
    (echo "*** Error: The permissions of the bouncer package differ from the permissions of the main package.  Ensure the bouncer and main package Android manifests agree, rebuild mobile/android, and re-package." && exit 1))
 else
 INNER_INSTALL_BOUNCER_PACKAGE=echo 'Testing is disabled, so the install bouncer is disabled - No trampolines for you'
 endif # ENABLE_TESTS
 else
 INNER_INSTALL_BOUNCER_PACKAGE=echo 'Install bouncer is disabled - No trampolines for you'
 endif # MOZ_ANDROID_PACKAGE_INSTALL_BOUNCER
 
-# Create geckoview_library/geckoview_{assets,library}.zip for third-party GeckoView consumers.
-ifdef NIGHTLY_BUILD
-ifndef MOZ_DISABLE_GECKOVIEW
-INNER_MAKE_GECKOVIEW_LIBRARY= \
-  $(MAKE) -C ../mobile/android/geckoview_library package
-else
-INNER_MAKE_GECKOVIEW_LIBRARY=echo 'GeckoView library packaging is disabled'
-endif
-else
-INNER_MAKE_GECKOVIEW_LIBRARY=echo 'GeckoView library packaging is only enabled on Nightly'
-endif
-
-# Create Android ARchives and metadata for download by local
-# developers using Gradle.
-ifdef MOZ_ANDROID_GECKOLIBS_AAR
-ifndef MOZ_DISABLE_GECKOVIEW
-geckoaar-revision := $(BUILDID)
-
-UPLOAD_EXTRA_FILES += \
-  geckolibs-$(geckoaar-revision).aar \
-  geckolibs-$(geckoaar-revision).aar.sha1 \
-  geckolibs-$(geckoaar-revision).pom \
-  geckolibs-$(geckoaar-revision).pom.sha1 \
-  ivy-geckolibs-$(geckoaar-revision).xml \
-  ivy-geckolibs-$(geckoaar-revision).xml.sha1 \
-  geckoview-$(geckoaar-revision).aar \
-  geckoview-$(geckoaar-revision).aar.sha1 \
-  geckoview-$(geckoaar-revision).pom \
-  geckoview-$(geckoaar-revision).pom.sha1 \
-  ivy-geckoview-$(geckoaar-revision).xml \
-  ivy-geckoview-$(geckoaar-revision).xml.sha1 \
-  $(NULL)
-
-INNER_MAKE_GECKOLIBS_AAR= \
-  $(PYTHON) -m mozbuild.action.package_geckolibs_aar \
-    --verbose \
-    --revision $(geckoaar-revision) \
-    --topsrcdir '$(topsrcdir)' \
-    --distdir '$(ABS_DIST)' \
-    --appname '$(MOZ_APP_NAME)' \
-    --purge-old \
-    '$(ABS_DIST)'
-else
-INNER_MAKE_GECKOLIBS_AAR=echo 'Android geckolibs.aar packaging requires packaging geckoview'
-endif # MOZ_DISABLE_GECKOVIEW
-else
-INNER_MAKE_GECKOLIBS_AAR=echo 'Android geckolibs.aar packaging is disabled'
-endif # MOZ_ANDROID_GECKOLIBS_AAR
-
 # Fennec's OMNIJAR_NAME can include a directory; for example, it might
 # be "assets/omni.ja". This path specifies where the omni.ja file
 # lives in the APK, but should not root the resources it contains
 # under assets/ (i.e., resources should not live at chrome://assets/).
 # packager.py writes /omni.ja in order to be consistent with the
 # layout expected by language repacks. Therefore, we move it to the
 # correct path here, in INNER_MAKE_PACKAGE. See comment about
 # OMNIJAR_NAME in configure.in.
@@ -155,19 +104,17 @@ INNER_FENNEC_PACKAGE = \
     --root-files $(foreach f,$(ROOT_FILES),$(STAGEPATH)$(MOZ_PKG_DIR)/$(f)) \
     --output $(PACKAGE:.apk=-unsigned-unaligned.apk) && \
   $(call RELEASE_SIGN_ANDROID_APK,$(PACKAGE:.apk=-unsigned-unaligned.apk),$(PACKAGE))
 
 # Packaging produces many optional artifacts.
 package_fennec = \
   $(INNER_FENNEC_PACKAGE) && \
   $(INNER_ROBOCOP_PACKAGE) && \
-  $(INNER_INSTALL_BOUNCER_PACKAGE) && \
-  $(INNER_MAKE_GECKOLIBS_AAR) && \
-  $(INNER_MAKE_GECKOVIEW_LIBRARY)
+  $(INNER_INSTALL_BOUNCER_PACKAGE)
 
 # Re-packaging only replaces Android resources and the omnijar before
 # (re-)signing.
 repackage_fennec = \
   $(MAKE) -C $(GECKO_APP_AP_PATH) gecko-nodeps.ap_ && \
   $(PYTHON) -m mozbuild.action.package_fennec_apk \
     --verbose \
     --inputs \
--- a/widget/windows/WindowsUIUtils.cpp
+++ b/widget/windows/WindowsUIUtils.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <windows.h>
+#include <winsdkver.h>
 #include "mozwrlbase.h"
 #include "nsServiceManagerUtils.h"
 
 #include "WindowsUIUtils.h"
 
 #include "nsIObserverService.h"
 #include "nsIBaseWindow.h"
 #include "nsIDocShell.h"
@@ -31,17 +32,17 @@ using namespace mozilla;
 using namespace ABI::Windows::UI;
 using namespace ABI::Windows::UI::ViewManagement;
 using namespace Microsoft::WRL;
 using namespace Microsoft::WRL::Wrappers;
 using namespace ABI::Windows::Foundation;
 
 /* All of this is win10 stuff and we're compiling against win81 headers
  * for now, so we may need to do some legwork: */
-#if MOZ_WINSDK_MAXVER < 0x0A000000
+#if WINVER_MAXVER < 0x0A00
 namespace ABI {
   namespace Windows {
     namespace UI {
       namespace ViewManagement {
         enum UserInteractionMode {
           UserInteractionMode_Mouse = 0,
           UserInteractionMode_Touch = 1
         };
@@ -51,17 +52,17 @@ namespace ABI {
 }
 
 #endif
 
 #ifndef RuntimeClass_Windows_UI_ViewManagement_UIViewSettings
 #define RuntimeClass_Windows_UI_ViewManagement_UIViewSettings L"Windows.UI.ViewManagement.UIViewSettings"
 #endif
 
-#if MOZ_WINSDK_MAXVER < 0x0A000000
+#if WINVER_MAXVER < 0x0A00
 namespace ABI {
   namespace Windows {
     namespace UI {
       namespace ViewManagement {
         interface IUIViewSettings;
         MIDL_INTERFACE("C63657F6-8850-470D-88F8-455E16EA2C26")
           IUIViewSettings : public IInspectable
           {