Merge m-c to b2g-inbound
authorWes Kocher <wkocher@mozilla.com>
Wed, 14 May 2014 16:34:15 -0700
changeset 183227 13197875cc2fb08966c6665f237a015bbecf45a9
parent 183226 10c87667e3e94015f7b65b97ec1e6dbd6775206f (current diff)
parent 183182 e4843f4f08a77c337ec6cf4e0a6bf44e0e3699d8 (diff)
child 183228 26c3489ff62d5f062edb9548dbced1289841bc54
push id26788
push userkwierso@gmail.com
push dateThu, 15 May 2014 22:46:24 +0000
treeherdermozilla-central@827f4dc53387 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone32.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to b2g-inbound
toolkit/mozapps/update/nsUpdateService.js
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1013,16 +1013,18 @@ pref("browser.sessionstore.restore_hidde
 // If restore_on_demand is set, pinned tabs are restored on startup by default.
 // When set to true, this pref overrides that behavior, and pinned tabs will only
 // be restored when they are focused.
 pref("browser.sessionstore.restore_pinned_tabs_on_demand", false);
 // The version at which we performed the latest upgrade backup
 pref("browser.sessionstore.upgradeBackup.latestBuildID", "");
 // End-users should not run sessionstore in debug mode
 pref("browser.sessionstore.debug", false);
+// Forget closed windows/tabs after two weeks
+pref("browser.sessionstore.cleanup.forget_closed_after", 1209600000);
 
 // allow META refresh by default
 pref("accessibility.blockautorefresh", false);
 
 // Whether history is enabled or not.
 pref("places.history.enabled", true);
 
 // the (maximum) number of the recent visits to sample
--- a/browser/components/sessionstore/content/aboutSessionRestore.js
+++ b/browser/components/sessionstore/content/aboutSessionRestore.js
@@ -106,24 +106,30 @@ function restoreSession() {
   // if there's only this page open, reuse the window for restoring the session
   if (top.gBrowser.tabs.length == 1) {
     ss.setWindowState(top, stateString, true);
     return;
   }
 
   // restore the session into a new window and close the current tab
   var newWindow = top.openDialog(top.location, "_blank", "chrome,dialog=no,all");
-  newWindow.addEventListener("load", function() {
-    newWindow.removeEventListener("load", arguments.callee, true);
+
+  var obs = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
+  obs.addObserver(function observe(win, topic) {
+    if (win != newWindow) {
+      return;
+    }
+
+    obs.removeObserver(observe, topic);
     ss.setWindowState(newWindow, stateString, true);
 
     var tabbrowser = top.gBrowser;
     var tabIndex = tabbrowser.getBrowserIndexForDocument(document);
     tabbrowser.removeTab(tabbrowser.tabs[tabIndex]);
-  }, true);
+  }, "browser-delayed-startup-finished", false);
 }
 
 function startNewSession() {
   var prefBranch = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
   if (prefBranch.getIntPref("browser.startup.page") == 0)
     getBrowserWindow().gBrowser.loadURI("about:blank");
   else
     getBrowserWindow().BrowserHome();
--- a/browser/components/sessionstore/src/SessionStore.jsm
+++ b/browser/components/sessionstore/src/SessionStore.jsm
@@ -31,16 +31,17 @@ const MAX_CONCURRENT_TAB_RESTORES = 3;
 // global notifications observed
 const OBSERVING = [
   "browser-window-before-show", "domwindowclosed",
   "quit-application-requested", "quit-application-granted",
   "browser-lastwindow-close-granted",
   "quit-application", "browser:purge-session-history",
   "browser:purge-domain-data",
   "gather-telemetry",
+  "idle-daily",
 ];
 
 // XUL Window properties to (re)store
 // Restored in restoreDimensions()
 const WINDOW_ATTRIBUTES = ["width", "height", "screenX", "screenY", "sizemode"];
 
 // Hideable window features to (re)store
 // Restored in restoreWindowFeatures()
@@ -379,25 +380,24 @@ let SessionStoreInternal = {
     this._initPrefs();
     this._initialized = true;
   },
 
   /**
    * Initialize the session using the state provided by SessionStartup
    */
   initSession: function () {
+    TelemetryStopwatch.start("FX_SESSION_RESTORE_STARTUP_INIT_SESSION_MS");
     let state;
     let ss = gSessionStartup;
 
-    try {
-      if (ss.doRestore() ||
-          ss.sessionType == Ci.nsISessionStartup.DEFER_SESSION)
-        state = ss.state;
+    if (ss.doRestore() ||
+        ss.sessionType == Ci.nsISessionStartup.DEFER_SESSION) {
+      state = ss.state;
     }
-    catch(ex) { dump(ex + "\n"); } // no state to restore, which is ok
 
     if (state) {
       try {
         // If we're doing a DEFERRED session, then we want to pull pinned tabs
         // out so they can be restored.
         if (ss.sessionType == Ci.nsISessionStartup.DEFER_SESSION) {
           let [iniState, remainingState] = this._prepDataForDeferredRestore(state);
           // If we have a iniState with windows, that means that we have windows
@@ -461,16 +461,17 @@ let SessionStoreInternal = {
     // at this point, we've as good as resumed the session, so we can
     // clear the resume_session_once flag, if it's set
     if (this._loadState != STATE_QUITTING &&
         this._prefBranch.getBoolPref("sessionstore.resume_session_once"))
       this._prefBranch.setBoolPref("sessionstore.resume_session_once", false);
 
     this._performUpgradeBackup();
 
+    TelemetryStopwatch.finish("FX_SESSION_RESTORE_STARTUP_INIT_SESSION_MS");
     return state;
   },
 
   /**
    * If this is the first time we launc this build of Firefox,
    * backup sessionstore.js.
    */
   _performUpgradeBackup: function ssi_performUpgradeBackup() {
@@ -565,16 +566,19 @@ let SessionStoreInternal = {
         this.onPurgeDomainData(aData);
         break;
       case "nsPref:changed": // catch pref changes
         this.onPrefChange(aData);
         break;
       case "gather-telemetry":
         this.onGatherTelemetry();
         break;
+      case "idle-daily":
+        this.onIdleDaily();
+        break;
     }
   },
 
   /**
    * This method handles incoming messages sent by the session store content
    * script and thus enables communication with OOP tabs.
    */
   receiveMessage: function ssi_receiveMessage(aMessage) {
@@ -961,17 +965,20 @@ let SessionStoreInternal = {
         return;
       }
 
       if (this._sessionInitialized) {
         this.onLoad(aWindow);
       } else {
         let initialState = this.initSession();
         this._sessionInitialized = true;
+
+        TelemetryStopwatch.start("FX_SESSION_RESTORE_STARTUP_ONLOAD_INITIAL_WINDOW_MS");
         this.onLoad(aWindow, initialState);
+        TelemetryStopwatch.finish("FX_SESSION_RESTORE_STARTUP_ONLOAD_INITIAL_WINDOW_MS");
 
         // Let everyone know we're done.
         this._deferredInitialized.resolve();
       }
     }, console.error);
   },
 
   /**
@@ -1420,16 +1427,49 @@ let SessionStoreInternal = {
   onGatherTelemetry: function() {
     // On the first gather-telemetry notification of the session,
     // gather telemetry data.
     Services.obs.removeObserver(this, "gather-telemetry");
     let stateString = SessionStore.getBrowserState();
     return SessionFile.gatherTelemetry(stateString);
   },
 
+  // Clean up data that has been closed a long time ago.
+  // Do not reschedule a save. This will wait for the next regular
+  // save.
+  onIdleDaily: function() {
+    // Remove old closed windows
+    this._cleanupOldData([this._closedWindows]);
+
+    // Remove closed tabs of closed windows
+    this._cleanupOldData([winData._closedTabs for (winData of this._closedWindows)]);
+
+    // Remove closed tabs of open windows
+    this._cleanupOldData([this._windows[key]._closedTabs for (key of Object.keys(this._windows))]);
+  },
+
+  // Remove "old" data from an array
+  _cleanupOldData: function(targets) {
+    const TIME_TO_LIVE = this._prefBranch.getIntPref("sessionstore.cleanup.forget_closed_after");
+    const now = Date.now();
+
+    for (let array of targets) {
+      for (let i = array.length - 1; i >= 0; --i)  {
+        let data = array[i];
+        // Make sure that we have a timestamp to tell us when the target
+        // has been closed. If we don't have a timestamp, default to a
+        // safe timestamp: just now.
+        data.closedAt = data.closedAt || now;
+        if (now - data.closedAt > TIME_TO_LIVE) {
+          array.splice(i, 1);
+        }
+      }
+    }
+  },
+
   /* ........ nsISessionStore API .............. */
 
   getBrowserState: function ssi_getBrowserState() {
     let state = this.getCurrentState();
 
     // Don't include the last session state in getBrowserState().
     delete state.lastSessionState;
 
@@ -1663,16 +1703,18 @@ let SessionStoreInternal = {
 
   undoCloseWindow: function ssi_undoCloseWindow(aIndex) {
     if (!(aIndex in this._closedWindows)) {
       throw Components.Exception("Invalid index: not in the closed windows", Cr.NS_ERROR_INVALID_ARG);
     }
 
     // reopen the window
     let state = { windows: this._closedWindows.splice(aIndex, 1) };
+    delete state.windows[0].closedAt; // Window is now open.
+
     let window = this._openWindowWithState(state);
     this.windowToFocus = window;
     return window;
   },
 
   forgetClosedWindow: function ssi_forgetClosedWindow(aIndex) {
     // default to the most-recently closed window
     aIndex = aIndex || 0;
@@ -2464,16 +2506,17 @@ let SessionStoreInternal = {
       }
       if (tabData.extData) {
         tab.__SS_extdata = {};
         for (let key in tabData.extData)
          tab.__SS_extdata[key] = tabData.extData[key];
       } else {
         delete tab.__SS_extdata;
       }
+      delete tabData.closedAt; // Tab is now open.
 
       // Flush all data from the content script synchronously. This is done so
       // that all async messages that are still on their way to chrome will
       // be ignored and don't override any tab data set when restoring.
       TabState.flush(tab.linkedBrowser);
 
       // Ensure the index is in bounds.
       let activeIndex = (tabData.index || tabData.entries.length) - 1;
--- a/browser/components/sessionstore/test/browser.ini
+++ b/browser/components/sessionstore/test/browser.ini
@@ -52,19 +52,21 @@ support-files =
 #  browser_464620_b.html 
 #  browser_464620_xd.html
 
 
 #disabled-for-intermittent-failures--bug-766044, browser_459906_empty.html
 #disabled-for-intermittent-failures--bug-766044, browser_459906_sample.html
 #disabled-for-intermittent-failures--bug-765389, browser_461743_sample.html
 
+[browser_aboutSessionRestore.js]
 [browser_attributes.js]
 [browser_broadcast.js]
 [browser_capabilities.js]
+[browser_cleaner.js]
 [browser_dying_cache.js]
 [browser_dynamic_frames.js]
 [browser_form_restore_events.js]
 [browser_formdata.js]
 [browser_formdata_format.js]
 [browser_formdata_xpath.js]
 [browser_frametree.js]
 [browser_frame_history.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/browser_aboutSessionRestore.js
@@ -0,0 +1,46 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const CRASH_SHENTRY = {url: "about:mozilla"};
+const CRASH_TAB = {entries: [CRASH_SHENTRY]};
+const CRASH_STATE = {windows: [{tabs: [CRASH_TAB]}]};
+
+const TAB_FORMDATA = {id: {sessionData: CRASH_STATE}};
+const TAB_SHENTRY = {url: "about:sessionrestore", formdata: TAB_FORMDATA};
+const TAB_STATE = {entries: [TAB_SHENTRY]};
+
+const FRAME_SCRIPT = "data:," +
+                     "content.document.getElementById('errorTryAgain').click()";
+
+add_task(function* () {
+  // Prepare a blank tab.
+  let tab = gBrowser.addTab("about:blank");
+  let browser = tab.linkedBrowser;
+  yield promiseBrowserLoaded(browser);
+
+  // Fake a post-crash tab.
+  ss.setTabState(tab, JSON.stringify(TAB_STATE));
+  yield promiseTabRestored(tab);
+
+  ok(gBrowser.tabs.length > 1, "we have more than one tab");
+  browser.messageManager.loadFrameScript(FRAME_SCRIPT, true);
+
+  // Wait until the new window was restored.
+  let win = yield waitForNewWindow();
+  yield promiseWindowClosed(win);
+
+  let [{tabs: [{entries: [{url}]}]}] = JSON.parse(ss.getClosedWindowData());
+  is(url, "about:mozilla", "session was restored correctly");
+  ss.forgetClosedWindow(0);
+});
+
+function waitForNewWindow() {
+  return new Promise(resolve => {
+    Services.obs.addObserver(function observe(win, topic) {
+      Services.obs.removeObserver(observe, topic);
+      resolve(win);
+    }, "browser-delayed-startup-finished", false);
+  });
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/browser_cleaner.js
@@ -0,0 +1,160 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+
+/*
+ * This test ensures that Session Restore eventually forgets about
+ * tabs and windows that have been closed a long time ago.
+ */
+
+"use strict";
+
+Cu.import("resource://gre/modules/Services.jsm", this);
+Cu.import("resource://gre/modules/osfile.jsm", this);
+Cu.import("resource://gre/modules/Task.jsm", this);
+
+const LONG_TIME_AGO = 1;
+
+const URL_TAB1 = "http://example.com/browser_cleaner.js?newtab1=" + Math.random();
+const URL_TAB2 = "http://example.com/browser_cleaner.js?newtab2=" + Math.random();
+const URL_NEWWIN = "http://example.com/browser_cleaner.js?newwin=" + Math.random();
+
+function isRecent(stamp) {
+  is(typeof stamp, "number", "This is a timestamp");
+  return Date.now() - stamp <= 60000;
+}
+
+function promiseCleanup () {
+  info("Cleaning up browser");
+
+  return promiseBrowserState(getClosedState());
+};
+
+function getClosedState() {
+  return Cu.cloneInto(CLOSED_STATE, {});
+}
+
+let CLOSED_STATE;
+
+add_task(function* init() {
+  while (ss.getClosedWindowCount() > 0) {
+    ss.forgetClosedWindow(0);
+  }
+  while (ss.getClosedTabCount(window) > 0) {
+    ss.forgetClosedTab(window, 0);
+  }
+});
+
+add_task(function* test_open_and_close() {
+  let newTab1 = gBrowser.addTab(URL_TAB1);
+  yield promiseBrowserLoaded(newTab1.linkedBrowser);
+
+  let newTab2 = gBrowser.addTab(URL_TAB2);
+  yield promiseBrowserLoaded(newTab2.linkedBrowser);
+
+  let newWin = yield promiseNewWindowLoaded();
+  let tab = newWin.gBrowser.addTab(URL_NEWWIN);
+
+  yield promiseBrowserLoaded(tab.linkedBrowser);
+
+
+
+  info("1. Making sure that before closing, we don't have closedAt");
+  // For the moment, no "closedAt"
+  let state = JSON.parse(ss.getBrowserState());
+  is(state.windows[0].closedAt || false, false, "1. Main window doesn't have closedAt");
+  is(state.windows[1].closedAt || false, false, "1. Second window doesn't have closedAt");
+  is(state.windows[0].tabs[0].closedAt || false, false, "1. First tab doesn't have closedAt");
+  is(state.windows[0].tabs[1].closedAt || false, false, "1. Second tab doesn't have closedAt");
+
+
+
+  info("2. Making sure that after closing, we have closedAt");
+
+  // Now close stuff, this should add closeAt
+  yield promiseWindowClosed(newWin);
+  gBrowser.removeTab(newTab1);
+  gBrowser.removeTab(newTab2);
+
+  state = CLOSED_STATE = JSON.parse(ss.getBrowserState());
+
+  is(state.windows[0].closedAt || false, false, "2. Main window doesn't have closedAt");
+  ok(isRecent(state._closedWindows[0].closedAt), "2. Second window was closed recently");
+  ok(isRecent(state.windows[0]._closedTabs[0].closedAt), "2. First tab was closed recently");
+  ok(isRecent(state.windows[0]._closedTabs[1].closedAt), "2. Second tab was closed recently");
+});
+
+
+add_task(function* test_restore() {
+  info("3. Making sure that after restoring, we don't have closedAt");
+  yield promiseBrowserState(CLOSED_STATE);
+
+  let newWin = ss.undoCloseWindow(0);
+  yield promiseDelayedStartupFinished(newWin);
+
+  let newTab2 = ss.undoCloseTab(window, 0);
+  yield promiseTabRestored(newTab2);
+
+  let newTab1 = ss.undoCloseTab(window, 0);
+  yield promiseTabRestored(newTab1);
+
+  let state = JSON.parse(ss.getBrowserState());
+
+  is(state.windows[0].closedAt || false, false, "3. Main window doesn't have closedAt");
+  is(state.windows[1].closedAt || false, false, "3. Second window doesn't have closedAt");
+  is(state.windows[0].tabs[0].closedAt || false, false, "3. First tab doesn't have closedAt");
+  is(state.windows[0].tabs[1].closedAt || false, false, "3. Second tab doesn't have closedAt");
+
+  yield promiseWindowClosed(newWin);
+  gBrowser.removeTab(newTab1);
+  gBrowser.removeTab(newTab2);
+});
+
+
+add_task(function* test_old_data() {
+  info("4. Removing closedAt from the sessionstore, making sure that it is added upon idle-daily");
+
+  let state = getClosedState();
+  delete state._closedWindows[0].closedAt;
+  delete state.windows[0]._closedTabs[0].closedAt;
+  delete state.windows[0]._closedTabs[1].closedAt;
+  yield promiseBrowserState(state);
+
+  info("Sending idle-daily");
+  Services.obs.notifyObservers(null, "idle-daily", "");
+  info("Sent idle-daily");
+
+  state = JSON.parse(ss.getBrowserState());
+  is(state.windows[0].closedAt || false, false, "4. Main window doesn't have closedAt");
+  ok(isRecent(state._closedWindows[0].closedAt), "4. Second window was closed recently");
+  ok(isRecent(state.windows[0]._closedTabs[0].closedAt), "4. First tab was closed recently");
+  ok(isRecent(state.windows[0]._closedTabs[1].closedAt), "4. Second tab was closed recently");
+  yield promiseCleanup();
+});
+
+
+add_task(function* test_cleanup() {
+
+  info("5. Altering closedAt to an old date, making sure that stuff gets collected, eventually");
+  yield promiseCleanup();
+
+  let state = getClosedState();
+  state._closedWindows[0].closedAt = LONG_TIME_AGO;
+  state.windows[0]._closedTabs[0].closedAt = LONG_TIME_AGO;
+  state.windows[0]._closedTabs[1].closedAt = Date.now();
+  let url = state.windows[0]._closedTabs[1].state.entries[0].url;
+
+  yield promiseBrowserState(state);
+
+  info("Sending idle-daily");
+  Services.obs.notifyObservers(null, "idle-daily", "");
+  info("Sent idle-daily");
+
+  state = JSON.parse(ss.getBrowserState());
+  is(state._closedWindows[0], undefined, "5. Second window was forgotten");
+
+  is(state.windows[0]._closedTabs.length, 1, "5. Only one closed tab left");
+  is(state.windows[0]._closedTabs[0].state.entries[0].url, url, "5. The second tab is still here");
+  yield promiseCleanup();
+});
+
--- a/browser/components/sessionstore/test/head.js
+++ b/browser/components/sessionstore/test/head.js
@@ -83,16 +83,22 @@ function provideWindow(aCallback, aURL, 
       aWin.gBrowser.selectedBrowser.removeEventListener("load", selectedBrowserLoadListener, true);
       callbackSoon(aWin);
     }, true);
   });
 }
 
 // This assumes that tests will at least have some state/entries
 function waitForBrowserState(aState, aSetStateCallback) {
+  if (typeof aState == "string") {
+    aState = JSON.parse(aState);
+  }
+  if (typeof aState != "object") {
+    throw new TypeError("Argument must be an object or a JSON representation of an object");
+  }
   let windows = [window];
   let tabsRestored = 0;
   let expectedTabsRestored = 0;
   let expectedWindows = aState.windows.length;
   let windowsOpen = 1;
   let listening = false;
   let windowObserving = false;
   let restoreHiddenTabs = Services.prefs.getBoolPref(
@@ -167,16 +173,20 @@ function waitForBrowserState(aState, aSe
 
   // Ensure setBrowserState() doesn't remove the initial tab.
   gBrowser.selectedTab = gBrowser.tabs[0];
 
   // Finally, call setBrowserState
   ss.setBrowserState(JSON.stringify(aState));
 }
 
+function promiseBrowserState(aState) {
+  return new Promise(resolve => waitForBrowserState(aState, resolve));
+}
+
 // Doesn't assume that the tab needs to be closed in a cleanup function.
 // If that's the case, the test author should handle that in the test.
 function waitForTabState(aTab, aState, aCallback) {
   let listening = true;
 
   function onSSTabRestored() {
     aTab.removeEventListener("SSTabRestored", onSSTabRestored, false);
     listening = false;
@@ -476,16 +486,19 @@ function promiseWindowClosed(win) {
 function whenDelayedStartupFinished(aWindow, aCallback) {
   Services.obs.addObserver(function observer(aSubject, aTopic) {
     if (aWindow == aSubject) {
       Services.obs.removeObserver(observer, aTopic);
       executeSoon(aCallback);
     }
   }, "browser-delayed-startup-finished", false);
 }
+function promiseDelayedStartupFinished(aWindow) {
+  return new Promise((resolve) => whenDelayedStartupFinished(aWindow, resolve));
+}
 
 /**
  * The test runner that controls the execution flow of our tests.
  */
 let TestRunner = {
   _iter: null,
 
   /**
--- a/browser/themes/linux/downloads/indicator.css
+++ b/browser/themes/linux/downloads/indicator.css
@@ -21,16 +21,21 @@
 
 #downloads-button[cui-areatype="toolbar"] > #downloads-indicator-anchor > #downloads-indicator-icon {
   background: -moz-image-rect(url("chrome://browser/skin/Toolbar.png"),
                               0, 198, 18, 180) center no-repeat;
   min-width: 18px;
   min-height: 18px;
 }
 
+#downloads-button[cui-areatype="toolbar"] > #downloads-indicator-anchor > #downloads-indicator-icon:-moz-lwtheme-brighttext {
+  background: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted.png"),
+                              0, 198, 18, 180) center no-repeat;
+}
+
 #downloads-button[cui-areatype="toolbar"][attention] > #downloads-indicator-anchor > #downloads-indicator-icon {
   background-image: url("chrome://browser/skin/downloads/download-glow.png");
 }
 
 #downloads-button[cui-areatype="menu-panel"][attention] {
   list-style-image: url("chrome://browser/skin/downloads/download-glow-menuPanel.png");
   -moz-image-region: auto;
 }
@@ -39,16 +44,21 @@
    equivalent to -moz-any([progress], [paused]). */
 
 #downloads-button:not([counter]) > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter {
   background: -moz-image-rect(url("chrome://browser/skin/Toolbar-small.png"),
                               0, 16, 16, 0) center no-repeat;
   background-size: 12px;
 }
 
+#downloads-button:not([counter]) > #downloads-indicator-anchor >
+#downloads-button-progress-area > #downloads-indicator-counter:-moz-lwtheme-brighttext {
+  background-image: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted.png"), 0, 198, 18, 180);
+}
+
 #downloads-button:not([counter])[attention] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter {
   background-image: url("chrome://browser/skin/downloads/download-glow.png");
 }
 
 /*** Download notifications ***/
 
 #downloads-indicator-notification {
   opacity: 0;
@@ -100,16 +110,22 @@
   margin: 0;
   color: hsl(0,0%,30%);
   text-shadow: 0 1px 0 hsla(0,0%,100%,.5);
   font-size: 10px;
   line-height: 10px;
   text-align: center;
 }
 
+#downloads-indicator-counter:-moz-lwtheme-brighttext {
+  color: white;
+  text-shadow: 0 0 1px rgba(0,0,0,.7),
+               0 1px 1.5px rgba(0,0,0,.5);
+}
+
 #downloads-indicator-progress {
   width: 18px;
   height: 6px;
   min-width: 0;
   min-height: 0;
   margin-top: 1px;
   margin-bottom: 2px;
   border-radius: 2px;
--- a/configure.in
+++ b/configure.in
@@ -2542,17 +2542,17 @@ AC_LANG_CPLUSPLUS
 
 MOZ_CXX11
 
 AC_LANG_C
 
 dnl Check for .hidden assembler directive and visibility attribute.
 dnl Borrowed from glibc configure.in
 dnl ===============================================================
-if test "$GNU_CC"; then
+if test "$GNU_CC" -a "$OS_TARGET" != WINNT; then
   AC_DEFINE(HAVE_VISIBILITY_HIDDEN_ATTRIBUTE)
   AC_DEFINE(HAVE_VISIBILITY_ATTRIBUTE)
   if test -n "$gonkdir"; then
     visibility_target=Gonk
   else
     visibility_target=$OS_TARGET
   fi
   case "$visibility_target" in
@@ -5801,16 +5801,21 @@ if test -n "$MOZ_ANGLE_RENDERER"; then
       AC_MSG_RESULT([Windows SDK not found.])
     fi
   fi
 
   if test -z "$MOZ_D3DCOMPILER_VISTA_DLL_PATH"; then
     MOZ_D3DCOMPILER_VISTA_DLL=
   fi
 
+  # On mingw, check if headers are provided by toolchain.
+  if test -n "$GNU_CC"; then
+    MOZ_CHECK_HEADER(d3d10.h, MOZ_HAS_WINSDK_WITH_D3D=1)
+  fi
+
   ######################################
   # Find _43 for use by XP.
 
   # Get the SDK path from the registry.
   # First try to get the June 2010 SDK
   MOZ_DIRECTX_SDK_REG_KEY=`reg query 'HKLM\Software\Microsoft\DirectX' //s | grep 'Microsoft DirectX SDK (June 2010)' | head -n 1`
   if test -z "$MOZ_DIRECTX_SDK_REG_KEY" ; then
     # Otherwise just take whatever comes first
--- a/content/base/src/EventSource.cpp
+++ b/content/base/src/EventSource.cpp
@@ -5,16 +5,17 @@
 
 #include "mozilla/dom/EventSource.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/EventSourceBinding.h"
 #include "mozilla/dom/MessageEvent.h"
+#include "mozilla/dom/ScriptSettings.h"
 
 #include "js/OldDebugAPI.h"
 #include "nsNetUtil.h"
 #include "nsMimeTypes.h"
 #include "nsIPromptFactory.h"
 #include "nsIWindowWatcher.h"
 #include "nsPresContext.h"
 #include "nsContentPolicyUtils.h"
@@ -24,17 +25,16 @@
 #include "nsIScriptObjectPrincipal.h"
 #include "nsJSUtils.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "nsIScriptError.h"
 #include "mozilla/dom/EncodingUtils.h"
 #include "nsIChannelPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsContentUtils.h"
-#include "nsCxPusher.h"
 #include "mozilla/Preferences.h"
 #include "xpcpublic.h"
 #include "nsCrossSiteListenerProxy.h"
 #include "nsWrapperCacheInlines.h"
 #include "mozilla/Attributes.h"
 #include "nsError.h"
 
 namespace mozilla {
@@ -1231,25 +1231,25 @@ EventSource::DispatchAllMessageEvents()
 
   mGoingToDispatchAllMessages = false;
 
   nsresult rv = CheckInnerWindowCorrectness();
   if (NS_FAILED(rv)) {
     return;
   }
 
-  // Let's play get the JSContext
-  nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(GetOwner());
-  NS_ENSURE_TRUE_VOID(sgo);
+  // We need a parent object so that we can enter its compartment.
+  nsCOMPtr<nsIGlobalObject> parentObject = do_QueryInterface(GetParentObject());
+  if (NS_WARN_IF(!parentObject)) {
+    return;
+  }
 
-  nsIScriptContext* scriptContext = sgo->GetContext();
-  NS_ENSURE_TRUE_VOID(scriptContext);
-
-  AutoPushJSContext cx(scriptContext->GetNativeContext());
-  NS_ENSURE_TRUE_VOID(cx);
+  AutoJSAPI jsapi;
+  JSContext* cx = jsapi.cx();
+  JSAutoCompartment ac(cx, parentObject->GetGlobalJSObject());
 
   while (mMessagesToDispatch.GetSize() > 0) {
     nsAutoPtr<Message>
       message(static_cast<Message*>(mMessagesToDispatch.PopFront()));
 
     // Now we can turn our string into a jsval
     JS::Rooted<JS::Value> jsData(cx);
     {
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -28,17 +28,16 @@
 #include "nsIWebNavigation.h"
 #include "nsIWebProgress.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIDocShellLoadInfo.h"
 #include "nsIDOMApplicationRegistry.h"
 #include "nsIBaseWindow.h"
 #include "nsContentUtils.h"
-#include "nsCxPusher.h"
 #include "nsIXPConnect.h"
 #include "nsUnicharUtils.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIScrollable.h"
 #include "nsFrameLoader.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIFrame.h"
@@ -2418,22 +2417,16 @@ nsFrameLoader::EnsureMessageManager()
 
   if (mMessageManager) {
     if (ShouldUseRemoteProcess() && mRemoteBrowserShown) {
       mMessageManager->InitWithCallback(this);
     }
     return NS_OK;
   }
 
-  nsIScriptContext* sctx = mOwnerContent->GetContextForEventHandlers(&rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-  NS_ENSURE_STATE(sctx);
-  AutoPushJSContext cx(sctx->GetNativeContext());
-  NS_ENSURE_STATE(cx);
-
   nsCOMPtr<nsIDOMChromeWindow> chromeWindow =
     do_QueryInterface(GetOwnerDoc()->GetWindow());
   nsCOMPtr<nsIMessageBroadcaster> parentManager;
   if (chromeWindow) {
     chromeWindow->GetMessageManager(getter_AddRefs(parentManager));
   }
 
   if (ShouldUseRemoteProcess()) {
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -4281,26 +4281,28 @@ bool
 CanvasRenderingContext2D::ShouldForceInactiveLayer(LayerManager *aManager)
 {
   return !aManager->CanUseCanvasLayerForSize(IntSize(mWidth, mHeight));
 }
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(CanvasPath, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(CanvasPath, Release)
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(CanvasPath)
-
-CanvasPath::CanvasPath(nsCOMPtr<nsISupports> aParent) : mParent(aParent)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CanvasPath, mParent)
+
+CanvasPath::CanvasPath(nsISupports* aParent)
+  : mParent(aParent)
 {
   SetIsDOMBinding();
 
   mPathBuilder = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget()->CreatePathBuilder();
 }
 
-CanvasPath::CanvasPath(nsCOMPtr<nsISupports> aParent, RefPtr<PathBuilder> aPathBuilder): mParent(aParent), mPathBuilder(aPathBuilder)
+CanvasPath::CanvasPath(nsISupports* aParent, RefPtr<PathBuilder> aPathBuilder)
+  : mParent(aParent), mPathBuilder(aPathBuilder)
 {
   SetIsDOMBinding();
 
   if (!mPathBuilder) {
     mPathBuilder = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget()->CreatePathBuilder();
   }
 }
 
--- a/content/canvas/src/CanvasRenderingContext2D.h
+++ b/content/canvas/src/CanvasRenderingContext2D.h
@@ -41,17 +41,17 @@ class ImageData;
 class StringOrCanvasGradientOrCanvasPattern;
 class OwningStringOrCanvasGradientOrCanvasPattern;
 class TextMetrics;
 
 extern const mozilla::gfx::Float SIGMA_MAX;
 
 template<typename T> class Optional;
 
-class CanvasPath :
+class CanvasPath MOZ_FINAL :
   public nsWrapperCache
 {
 public:
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(CanvasPath)
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(CanvasPath)
 
   nsCOMPtr<nsISupports> GetParentObject() { return mParent; }
 
@@ -83,18 +83,18 @@ public:
   void LineTo(const gfx::Point& aPoint);
   void BezierTo(const gfx::Point& aCP1,
                 const gfx::Point& aCP2,
                 const gfx::Point& aCP3);
 
   mozilla::RefPtr<mozilla::gfx::Path> GetPath(const CanvasWindingRule& winding,
                                               const mozilla::RefPtr<mozilla::gfx::DrawTarget>& mTarget) const;
 
-  CanvasPath(nsCOMPtr<nsISupports> aParent);
-  CanvasPath(nsCOMPtr<nsISupports> aParent, RefPtr<gfx::PathBuilder> mPathBuilder);
+  explicit CanvasPath(nsISupports* aParent);
+  CanvasPath(nsISupports* aParent, RefPtr<gfx::PathBuilder> mPathBuilder);
   virtual ~CanvasPath() {}
 
 private:
 
   nsCOMPtr<nsISupports> mParent;
   static gfx::Float ToFloat(double aValue) { return gfx::Float(aValue); }
 
   mutable RefPtr<gfx::Path> mPath;
--- a/content/canvas/test/test_canvas_path.html
+++ b/content/canvas/test/test_canvas_path.html
@@ -378,9 +378,13 @@ function runTests() {
   ok(false, "unexpected exception thrown in: test_pathconstructor_canvas");
  }
  SpecialPowers.setBoolPref("canvas.path.enabled", false);
  SimpleTest.finish();
 }
 
 addLoadEvent(runTests);
 
+// Don't leak the world via the Path2D reference to its window.
+document.all;
+window.p = new Path2D();
+
 </script>
--- a/content/html/content/src/HTMLFormElement.h
+++ b/content/html/content/src/HTMLFormElement.h
@@ -421,17 +421,17 @@ protected:
   public:
     FormPasswordEventDispatcher(HTMLFormElement* aEventNode,
                                 const nsAString& aEventType)
       : AsyncEventDispatcher(aEventNode, aEventType, true, true)
     {}
 
     NS_IMETHOD Run() MOZ_OVERRIDE
     {
-      static_cast<HTMLFormElement*>(mEventNode.get())->EventHandled();
+      static_cast<HTMLFormElement*>(mTarget.get())->EventHandled();
       return AsyncEventDispatcher::Run();
     }
   };
 
   nsRefPtr<FormPasswordEventDispatcher> mFormPasswordEventDispatcher;
 
   class RemoveElementRunnable;
   friend class RemoveElementRunnable;
--- a/content/media/webaudio/AudioBuffer.cpp
+++ b/content/media/webaudio/AudioBuffer.cpp
@@ -161,18 +161,17 @@ AudioBuffer::CopyToChannel(JSContext* aJ
     return;
   }
 
   PodMove(JS_GetFloat32ArrayData(mJSChannels[aChannelNumber]) + aStartInChannel,
           aSource.Data(), length);
 }
 
 void
-AudioBuffer::SetRawChannelContents(JSContext* aJSContext, uint32_t aChannel,
-                                   float* aContents)
+AudioBuffer::SetRawChannelContents(uint32_t aChannel, float* aContents)
 {
   PodCopy(JS_GetFloat32ArrayData(mJSChannels[aChannel]), aContents, mLength);
 }
 
 JSObject*
 AudioBuffer::GetChannelData(JSContext* aJSContext, uint32_t aChannel,
                             ErrorResult& aRv)
 {
--- a/content/media/webaudio/AudioBuffer.h
+++ b/content/media/webaudio/AudioBuffer.h
@@ -92,19 +92,17 @@ public:
    * Can return null if there is no data.
    */
   ThreadSharedFloatArrayBufferList* GetThreadSharedChannelsForRate(JSContext* aContext);
 
   // This replaces the contents of the JS array for the given channel.
   // This function needs to be called on an AudioBuffer which has not been
   // handed off to the content yet, and right after the object has been
   // initialized.
-  void SetRawChannelContents(JSContext* aJSContext,
-                             uint32_t aChannel,
-                             float* aContents);
+  void SetRawChannelContents(uint32_t aChannel, float* aContents);
 
 protected:
   bool RestoreJSChannelData(JSContext* aJSContext);
   void ClearJSChannels();
 
   nsRefPtr<AudioContext> mContext;
   // Float32Arrays
   AutoFallibleTArray<JS::Heap<JSObject*>, 2> mJSChannels;
--- a/content/media/webaudio/AudioContext.cpp
+++ b/content/media/webaudio/AudioContext.cpp
@@ -585,31 +585,26 @@ AudioContext::UpdateNodeCount(int32_t aD
   mNodeCount += aDelta;
   MOZ_ASSERT(mNodeCount >= 0);
   // mDestinationNode may be null when we're destroying nodes unlinked by CC
   if (!firstNode && mDestination) {
     mDestination->SetIsOnlyNodeForContext(mNodeCount == 1);
   }
 }
 
-JSContext*
-AudioContext::GetJSContext() const
+JSObject*
+AudioContext::GetGlobalJSObject() const
 {
-  MOZ_ASSERT(NS_IsMainThread());
-
-  nsCOMPtr<nsIScriptGlobalObject> scriptGlobal =
-    do_QueryInterface(GetParentObject());
-  if (!scriptGlobal) {
+  nsCOMPtr<nsIGlobalObject> parentObject = do_QueryInterface(GetParentObject());
+  if (!parentObject) {
     return nullptr;
   }
-  nsIScriptContext* scriptContext = scriptGlobal->GetContext();
-  if (!scriptContext) {
-    return nullptr;
-  }
-  return scriptContext->GetNativeContext();
+
+  // This can also return null.
+  return parentObject->GetGlobalJSObject();
 }
 
 void
 AudioContext::StartRendering(ErrorResult& aRv)
 {
   MOZ_ASSERT(mIsOffline, "This should only be called on OfflineAudioContext");
   if (mIsStarted) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
--- a/content/media/webaudio/AudioContext.h
+++ b/content/media/webaudio/AudioContext.h
@@ -214,17 +214,17 @@ public:
   void UnregisterPannerNode(PannerNode* aNode);
   void UpdatePannerSource();
 
   uint32_t MaxChannelCount() const;
 
   void Mute() const;
   void Unmute() const;
 
-  JSContext* GetJSContext() const;
+  JSObject* GetGlobalJSObject() const;
 
   AudioChannel MozAudioChannelType() const;
   void SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv);
 
   void UpdateNodeCount(int32_t aDelta);
 
   double DOMTimeToStreamTime(double aTime) const
   {
--- a/content/media/webaudio/AudioDestinationNode.cpp
+++ b/content/media/webaudio/AudioDestinationNode.cpp
@@ -1,16 +1,17 @@
 /* -*- 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 "AudioDestinationNode.h"
 #include "mozilla/dom/AudioDestinationNodeBinding.h"
+#include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "AudioChannelAgent.h"
 #include "AudioChannelService.h"
 #include "AudioNodeEngine.h"
 #include "AudioNodeStream.h"
 #include "MediaStreamGraph.h"
 #include "OfflineAudioCompletionEvent.h"
@@ -120,31 +121,35 @@ public:
   void FireOfflineCompletionEvent(AudioDestinationNode* aNode)
   {
     AudioContext* context = aNode->Context();
     context->Shutdown();
     // Shutdown drops self reference, but the context is still referenced by aNode,
     // which is strongly referenced by the runnable that called
     // AudioDestinationNode::FireOfflineCompletionEvent.
 
-    AutoPushJSContext cx(context->GetJSContext());
-    if (!cx) {
+    // We need the global for the context so that we can enter its compartment.
+    JSObject* global = context->GetGlobalJSObject();
+    if (NS_WARN_IF(!global)) {
       return;
     }
-    JSAutoRequest ar(cx);
+
+    AutoJSAPI jsapi;
+    JSContext* cx = jsapi.cx();
+    JSAutoCompartment ac(cx, global);
 
     // Create the input buffer
     nsRefPtr<AudioBuffer> renderedBuffer = new AudioBuffer(context,
                                                            mLength,
                                                            mSampleRate);
     if (!renderedBuffer->InitializeBuffers(mInputChannels.Length(), cx)) {
       return;
     }
     for (uint32_t i = 0; i < mInputChannels.Length(); ++i) {
-      renderedBuffer->SetRawChannelContents(cx, i, mInputChannels[i]);
+      renderedBuffer->SetRawChannelContents(i, mInputChannels[i]);
     }
 
     nsRefPtr<OfflineAudioCompletionEvent> event =
         new OfflineAudioCompletionEvent(context, nullptr, nullptr);
     event->InitEvent(renderedBuffer);
     context->DispatchTrustedEvent(event);
   }
 
--- a/content/media/webaudio/AudioProcessingEvent.cpp
+++ b/content/media/webaudio/AudioProcessingEvent.cpp
@@ -1,16 +1,17 @@
 /* -*- 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 "AudioProcessingEvent.h"
 #include "mozilla/dom/AudioProcessingEventBinding.h"
+#include "mozilla/dom/ScriptSettings.h"
 #include "AudioContext.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(AudioProcessingEvent, Event,
                                    mInputBuffer, mOutputBuffer, mNode)
 
@@ -35,17 +36,25 @@ AudioProcessingEvent::WrapObject(JSConte
 {
   return AudioProcessingEventBinding::Wrap(aCx, this);
 }
 
 void
 AudioProcessingEvent::LazilyCreateBuffer(nsRefPtr<AudioBuffer>& aBuffer,
                                          uint32_t aNumberOfChannels)
 {
-  AutoPushJSContext cx(mNode->Context()->GetJSContext());
+  // We need the global for the context so that we can enter its compartment.
+  JSObject* global = mNode->Context()->GetGlobalJSObject();
+  if (NS_WARN_IF(!global)) {
+    return;
+  }
+
+  AutoJSAPI jsapi;
+  JSContext* cx = jsapi.cx();
+  JSAutoCompartment ac(cx, global);
 
   aBuffer = new AudioBuffer(mNode->Context(), mNode->BufferSize(),
                             mNode->Context()->SampleRate());
   aBuffer->InitializeBuffers(aNumberOfChannels, cx);
 }
 
 }
 }
--- a/content/media/webaudio/MediaBufferDecoder.cpp
+++ b/content/media/webaudio/MediaBufferDecoder.cpp
@@ -2,28 +2,28 @@
 /* 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 "MediaBufferDecoder.h"
 #include "BufferDecoder.h"
 #include "mozilla/dom/AudioContextBinding.h"
+#include "mozilla/dom/ScriptSettings.h"
 #include <speex/speex_resampler.h>
 #include "nsXPCOMCIDInternal.h"
 #include "nsComponentManagerUtils.h"
 #include "MediaDecoderReader.h"
 #include "BufferMediaResource.h"
 #include "DecoderTraits.h"
 #include "AudioContext.h"
 #include "AudioBuffer.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIScriptError.h"
 #include "nsMimeTypes.h"
-#include "nsCxPusher.h"
 #include "WebAudioUtils.h"
 
 namespace mozilla {
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(WebAudioDecodeJob)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(WebAudioDecodeJob)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)
@@ -397,30 +397,34 @@ MediaDecodeTask::CallbackTheResult()
 }
 
 bool
 WebAudioDecodeJob::AllocateBuffer()
 {
   MOZ_ASSERT(!mOutput);
   MOZ_ASSERT(NS_IsMainThread());
 
-  // First, get a JSContext
-  AutoPushJSContext cx(mContext->GetJSContext());
-  if (!cx) {
+  // We need the global for the context so that we can enter its compartment.
+  JSObject* global = mContext->GetGlobalJSObject();
+  if (NS_WARN_IF(!global)) {
     return false;
   }
 
+  AutoJSAPI jsapi;
+  JSContext* cx = jsapi.cx();
+  JSAutoCompartment ac(cx, global);
+
   // Now create the AudioBuffer
   mOutput = new AudioBuffer(mContext, mWriteIndex, mContext->SampleRate());
   if (!mOutput->InitializeBuffers(mChannelBuffers.Length(), cx)) {
     return false;
   }
 
   for (uint32_t i = 0; i < mChannelBuffers.Length(); ++i) {
-    mOutput->SetRawChannelContents(cx, i, mChannelBuffers[i]);
+    mOutput->SetRawChannelContents(i, mChannelBuffers[i]);
   }
 
   return true;
 }
 
 void
 MediaBufferDecoder::AsyncDecodeMedia(const char* aContentType, uint8_t* aBuffer,
                                      uint32_t aLength,
--- a/content/media/webaudio/ScriptProcessorNode.cpp
+++ b/content/media/webaudio/ScriptProcessorNode.cpp
@@ -7,17 +7,17 @@
 #include "ScriptProcessorNode.h"
 #include "mozilla/dom/ScriptProcessorNodeBinding.h"
 #include "AudioBuffer.h"
 #include "AudioDestinationNode.h"
 #include "AudioNodeEngine.h"
 #include "AudioNodeStream.h"
 #include "AudioProcessingEvent.h"
 #include "WebAudioUtils.h"
-#include "nsCxPusher.h"
+#include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/PodOperations.h"
 #include <deque>
 
 namespace mozilla {
 namespace dom {
 
 // The maximum latency, in seconds, that we can live with before dropping
@@ -397,54 +397,61 @@ private:
           // this function.
           MutexAutoLock lock(mStream->Engine()->NodeMutex());
           node = static_cast<ScriptProcessorNode*>(mStream->Engine()->Node());
         }
         if (!node || !node->Context()) {
           return NS_OK;
         }
 
-        AutoPushJSContext cx(node->Context()->GetJSContext());
-        if (cx) {
+        // Get the global for the context so that we can enter its compartment.
+        JSObject* global = node->Context()->GetGlobalJSObject();
+        if (NS_WARN_IF(!global)) {
+          return NS_OK;
+        }
 
-          // Create the input buffer
-          nsRefPtr<AudioBuffer> inputBuffer;
-          if (!mNullInput) {
-            inputBuffer = new AudioBuffer(node->Context(),
-                                          node->BufferSize(),
-                                          node->Context()->SampleRate());
-            if (!inputBuffer->InitializeBuffers(mInputChannels.Length(), cx)) {
-              return NS_OK;
-            }
-            // Put the channel data inside it
-            for (uint32_t i = 0; i < mInputChannels.Length(); ++i) {
-              inputBuffer->SetRawChannelContents(cx, i, mInputChannels[i]);
-            }
-          }
+        AutoJSAPI jsapi;
+        JSContext* cx = jsapi.cx();
+        JSAutoCompartment ac(cx, global);
 
-          // Ask content to produce data in the output buffer
-          // Note that we always avoid creating the output buffer here, and we try to
-          // avoid creating the input buffer as well.  The AudioProcessingEvent class
-          // knows how to lazily create them if needed once the script tries to access
-          // them.  Otherwise, we may be able to get away without creating them!
-          nsRefPtr<AudioProcessingEvent> event = new AudioProcessingEvent(node, nullptr, nullptr);
-          event->InitEvent(inputBuffer,
-                           mInputChannels.Length(),
-                           mPlaybackTime);
-          node->DispatchTrustedEvent(event);
+        // Create the input buffer
+        nsRefPtr<AudioBuffer> inputBuffer;
+        if (!mNullInput) {
+          inputBuffer = new AudioBuffer(node->Context(),
+                                        node->BufferSize(),
+                                        node->Context()->SampleRate());
+          if (!inputBuffer->InitializeBuffers(mInputChannels.Length(), cx)) {
+            return NS_OK;
+          }
+          // Put the channel data inside it
+          for (uint32_t i = 0; i < mInputChannels.Length(); ++i) {
+            inputBuffer->SetRawChannelContents(i, mInputChannels[i]);
+          }
+        }
 
-          // Steal the output buffers
-          nsRefPtr<ThreadSharedFloatArrayBufferList> output;
-          if (event->HasOutputBuffer()) {
-            output = event->OutputBuffer()->GetThreadSharedChannelsForRate(cx);
-          }
+        // Ask content to produce data in the output buffer
+        // Note that we always avoid creating the output buffer here, and we try to
+        // avoid creating the input buffer as well.  The AudioProcessingEvent class
+        // knows how to lazily create them if needed once the script tries to access
+        // them.  Otherwise, we may be able to get away without creating them!
+        nsRefPtr<AudioProcessingEvent> event = new AudioProcessingEvent(node, nullptr, nullptr);
+        event->InitEvent(inputBuffer,
+                         mInputChannels.Length(),
+                         mPlaybackTime);
+        node->DispatchTrustedEvent(event);
 
-          // Append it to our output buffer queue
-          node->GetSharedBuffers()->FinishProducingOutputBuffer(output, node->BufferSize());
+        // Steal the output buffers
+        nsRefPtr<ThreadSharedFloatArrayBufferList> output;
+        if (event->HasOutputBuffer()) {
+          output = event->OutputBuffer()->GetThreadSharedChannelsForRate(cx);
         }
+
+        // Append it to our output buffer queue
+        node->GetSharedBuffers()->FinishProducingOutputBuffer(output, node->BufferSize());
+
         return NS_OK;
       }
     private:
       nsRefPtr<AudioNodeStream> mStream;
       InputChannels mInputChannels;
       double mPlaybackTime;
       bool mNullInput;
     };
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -572,28 +572,28 @@ nsDOMWindowUtils::GetResolution(float* a
     *aXResolution = presShell->GetXResolution();
     *aYResolution = presShell->GetYResolution();
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMWindowUtils::GetIsHistoryRestored(bool* aIsHistoryRestored) {
+nsDOMWindowUtils::GetIsResolutionSet(bool* aIsResolutionSet) {
   if (!nsContentUtils::IsCallerChrome()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   nsIPresShell* presShell = GetPresShell();
   if (!presShell) {
     return NS_ERROR_FAILURE;
   }
 
   const nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
-  *aIsHistoryRestored = sf && sf->DidHistoryRestore();
+  *aIsResolutionSet = sf && sf->IsResolutionSet();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::SetIsFirstPaint(bool aIsFirstPaint)
 {
   if (!nsContentUtils::IsCallerChrome()) {
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -13447,22 +13447,16 @@ nsGlobalChromeWindow::GetMessageManager(
 
 nsIMessageBroadcaster*
 nsGlobalWindow::GetMessageManager(ErrorResult& aError)
 {
   FORWARD_TO_INNER_OR_THROW(GetMessageManager, (aError), aError, nullptr);
   MOZ_ASSERT(IsChromeWindow());
   nsGlobalChromeWindow* myself = static_cast<nsGlobalChromeWindow*>(this);
   if (!myself->mMessageManager) {
-    nsIScriptContext* scx = GetContextInternal();
-    if (NS_WARN_IF(!scx || !(scx->GetNativeContext()))) {
-      aError.Throw(NS_ERROR_UNEXPECTED);
-      return nullptr;
-    }
-
     nsCOMPtr<nsIMessageBroadcaster> globalMM =
       do_GetService("@mozilla.org/globalmessagemanager;1");
     myself->mMessageManager =
       new nsFrameMessageManager(nullptr,
                                 static_cast<nsFrameMessageManager*>(globalMM.get()),
                                 MM_CHROME | MM_BROADCASTER);
   }
   return myself->mMessageManager;
--- a/dom/events/AsyncEventDispatcher.cpp
+++ b/dom/events/AsyncEventDispatcher.cpp
@@ -14,76 +14,84 @@
 namespace mozilla {
 
 using namespace dom;
 
 /******************************************************************************
  * mozilla::AsyncEventDispatcher
  ******************************************************************************/
 
-AsyncEventDispatcher::AsyncEventDispatcher(nsINode* aEventNode,
+AsyncEventDispatcher::AsyncEventDispatcher(EventTarget* aTarget,
                                            WidgetEvent& aEvent)
-  : mEventNode(aEventNode)
+  : mTarget(aTarget)
   , mDispatchChromeOnly(false)
 {
-  MOZ_ASSERT(mEventNode);
-  EventDispatcher::CreateEvent(aEventNode, nullptr, &aEvent, EmptyString(),
+  MOZ_ASSERT(mTarget);
+  EventDispatcher::CreateEvent(aTarget, nullptr, &aEvent, EmptyString(),
                                getter_AddRefs(mEvent));
   NS_ASSERTION(mEvent, "Should never fail to create an event");
   mEvent->DuplicatePrivateData();
   mEvent->SetTrusted(aEvent.mFlags.mIsTrusted);
 }
 
 NS_IMETHODIMP
 AsyncEventDispatcher::Run()
 {
   if (mEvent) {
     if (mDispatchChromeOnly) {
       MOZ_ASSERT(mEvent->InternalDOMEvent()->IsTrusted());
 
-      nsCOMPtr<nsIDocument> ownerDoc = mEventNode->OwnerDoc();
-      nsPIDOMWindow* window = ownerDoc->GetWindow();
+      nsCOMPtr<nsINode> node = do_QueryInterface(mTarget);
+      MOZ_ASSERT(node, "ChromeOnly dispatch supported with Node targets only!");
+      nsPIDOMWindow* window = node->OwnerDoc()->GetWindow();
       if (!window) {
         return NS_ERROR_INVALID_ARG;
       }
 
       nsCOMPtr<EventTarget> target = window->GetParentTarget();
       if (!target) {
         return NS_ERROR_INVALID_ARG;
       }
       EventDispatcher::DispatchDOMEvent(target, nullptr, mEvent,
                                         nullptr, nullptr);
     } else {
-      nsCOMPtr<EventTarget> target = mEventNode.get();
       bool defaultActionEnabled; // This is not used because the caller is async
-      target->DispatchEvent(mEvent, &defaultActionEnabled);
+      mTarget->DispatchEvent(mEvent, &defaultActionEnabled);
     }
   } else {
-    nsIDocument* doc = mEventNode->OwnerDoc();
     if (mDispatchChromeOnly) {
-      nsContentUtils::DispatchChromeEvent(doc, mEventNode, mEventType,
+      nsCOMPtr<nsINode> node = do_QueryInterface(mTarget);
+      MOZ_ASSERT(node, "ChromeOnly dispatch supported with Node targets only!");
+      nsContentUtils::DispatchChromeEvent(node->OwnerDoc(), node, mEventType,
                                           mBubbles, false);
     } else {
-      nsContentUtils::DispatchTrustedEvent(doc, mEventNode, mEventType,
-                                           mBubbles, false);
+      nsCOMPtr<nsIDOMEvent> event;
+      NS_NewDOMEvent(getter_AddRefs(event), mTarget, nullptr, nullptr);
+      nsresult rv = event->InitEvent(mEventType, mBubbles, false);
+      NS_ENSURE_SUCCESS(rv, rv);
+      event->SetTrusted(true);
+      bool dummy;
+      mTarget->DispatchEvent(event, &dummy);
     }
   }
 
   return NS_OK;
 }
 
 nsresult
 AsyncEventDispatcher::PostDOMEvent()
 {
+  nsRefPtr<AsyncEventDispatcher> ensureDeletionWhenFailing = this;
   return NS_DispatchToCurrentThread(this);
 }
 
 void
 AsyncEventDispatcher::RunDOMEventWhenSafe()
 {
+  nsRefPtr<AsyncEventDispatcher> ensureDeletionWhenFailing = this;
   nsContentUtils::AddScriptRunner(this);
 }
 
 /******************************************************************************
  * mozilla::LoadBlockingAsyncEventDispatcher
  ******************************************************************************/
 
 LoadBlockingAsyncEventDispatcher::~LoadBlockingAsyncEventDispatcher()
--- a/dom/events/AsyncEventDispatcher.h
+++ b/dom/events/AsyncEventDispatcher.h
@@ -21,39 +21,48 @@ namespace mozilla {
  * For example, you may need to fire an event from within layout, but
  * want to ensure that the event handler doesn't mutate the DOM at
  * the wrong time, in order to avoid resulting instability.
  */
  
 class AsyncEventDispatcher : public nsRunnable
 {
 public:
-  AsyncEventDispatcher(nsINode* aEventNode, const nsAString& aEventType,
+  AsyncEventDispatcher(nsINode* aTarget, const nsAString& aEventType,
                        bool aBubbles, bool aDispatchChromeOnly)
-    : mEventNode(aEventNode)
+    : mTarget(aTarget)
     , mEventType(aEventType)
     , mBubbles(aBubbles)
     , mDispatchChromeOnly(aDispatchChromeOnly)
   {
   }
 
-  AsyncEventDispatcher(nsINode* aEventNode, nsIDOMEvent* aEvent)
-    : mEventNode(aEventNode)
+  AsyncEventDispatcher(dom::EventTarget* aTarget, const nsAString& aEventType,
+                       bool aBubbles)
+    : mTarget(aTarget)
+    , mEventType(aEventType)
+    , mBubbles(aBubbles)
+    , mDispatchChromeOnly(false)
+  {
+  }
+
+  AsyncEventDispatcher(dom::EventTarget* aTarget, nsIDOMEvent* aEvent)
+    : mTarget(aTarget)
     , mEvent(aEvent)
     , mDispatchChromeOnly(false)
   {
   }
 
-  AsyncEventDispatcher(nsINode* aEventNode, WidgetEvent& aEvent);
+  AsyncEventDispatcher(dom::EventTarget* aTarget, WidgetEvent& aEvent);
 
   NS_IMETHOD Run() MOZ_OVERRIDE;
   nsresult PostDOMEvent();
   void RunDOMEventWhenSafe();
 
-  nsCOMPtr<nsINode>     mEventNode;
+  nsCOMPtr<dom::EventTarget> mTarget;
   nsCOMPtr<nsIDOMEvent> mEvent;
   nsString              mEventType;
   bool                  mBubbles;
   bool                  mDispatchChromeOnly;
 };
 
 class LoadBlockingAsyncEventDispatcher MOZ_FINAL : public AsyncEventDispatcher
 {
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -43,17 +43,17 @@ interface nsIDOMFile;
 interface nsIFile;
 interface nsIDOMClientRect;
 interface nsIURI;
 interface nsIDOMEventTarget;
 interface nsIRunnable;
 interface nsICompositionStringSynthesizer;
 interface nsITranslationNodeList;
 
-[scriptable, uuid(8489681a-7407-457e-b889-53d1ae999b30)]
+[scriptable, uuid(aae2d993-366f-43e6-aa51-f2eb83935e7d)]
 interface nsIDOMWindowUtils : nsISupports {
 
   /**
    * Image animation mode of the window. When this attribute's value
    * is changed, the implementation should set all images in the window
    * to the given value. That is, when set to kDontAnimMode, all images
    * will stop animating. The attribute's value must be one of the
    * animationMode values from imgIContainer.
@@ -226,23 +226,23 @@ interface nsIDOMWindowUtils : nsISupport
    *
    * The caller of this method must have chrome privileges.
    */
   void setResolution(in float aXResolution, in float aYResolution);
 
   void getResolution(out float aXResolution, out float aYResolution);
 
   /**
-   * Whether the current window has been restored from session history.
-   * This gives a way to check whether the provided resolution and scroll
-   * position are default values or restored from a previous session.
+   * Whether the resolution has been set by the user.
+   * This gives a way to check whether the provided resolution is the default
+   * value or restored from a previous session.
    *
    * Can only be accessed with chrome privileges.
    */
-  readonly attribute boolean isHistoryRestored;
+  readonly attribute boolean isResolutionSet;
 
   /**
    * Whether the next paint should be flagged as the first paint for a document.
    * This gives a way to track the next paint that occurs after the flag is
    * set. The flag gets cleared after the next paint.
    *
    * Can only be accessed with chrome privileges.
    */
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -496,16 +496,21 @@ ContentParentsMemoryReporter::CollectRep
     return NS_OK;
 }
 
 nsDataHashtable<nsStringHashKey, ContentParent*>* ContentParent::sAppContentParents;
 nsTArray<ContentParent*>* ContentParent::sNonAppContentParents;
 nsTArray<ContentParent*>* ContentParent::sPrivateContent;
 StaticAutoPtr<LinkedList<ContentParent> > ContentParent::sContentParents;
 
+#ifdef MOZ_NUWA_PROCESS
+// The pref updates sent to the Nuwa process.
+static nsTArray<PrefSetting>* sNuwaPrefUpdates;
+#endif
+
 // This is true when subprocess launching is enabled.  This is the
 // case between StartUp() and ShutDown() or JoinAllSubprocesses().
 static bool sCanLaunchSubprocesses;
 
 // The first content child has ID 1, so the chrome process can have ID 0.
 static uint64_t gContentChildID = 1;
 
 // We want the prelaunched process to know that it's for apps, but not
@@ -1320,16 +1325,24 @@ ContentParent::ActorDestroy(ActorDestroy
 #endif
     if (mgr && isMemoryChild) {
         mgr->DecrementNumChildProcesses();
     }
 
     // remove the global remote preferences observers
     Preferences::RemoveObserver(this, "");
 
+#ifdef MOZ_NUWA_PROCESS
+    // Remove the pref update requests.
+    if (IsNuwaProcess() && sNuwaPrefUpdates) {
+        delete sNuwaPrefUpdates;
+        sNuwaPrefUpdates = nullptr;
+    }
+#endif
+
     RecvRemoveGeolocationListener();
 
     mConsoleService = nullptr;
 
     MarkAsDead();
 
     if (obs) {
         nsRefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
@@ -2110,16 +2123,23 @@ ContentParent::RecvAddNewProcess(const u
         return false;
     }
     nsRefPtr<ContentParent> content;
     content = new ContentParent(this,
                                 MAGIC_PREALLOCATED_APP_MANIFEST_URL,
                                 aPid,
                                 aFds);
     content->Init();
+
+    size_t numNuwaPrefUpdates = sNuwaPrefUpdates ?
+                                sNuwaPrefUpdates->Length() : 0;
+    // Resend pref updates to the forked child.
+    for (int i = 0; i < numNuwaPrefUpdates; i++) {
+        content->SendPreferenceUpdate(sNuwaPrefUpdates->ElementAt(i));
+    }
     PreallocatedProcessManager::PublishSpareProcess(content);
     return true;
 #else
     NS_ERROR("ContentParent::RecvAddNewProcess() not implemented!");
     return false;
 #endif
 }
 
@@ -2157,19 +2177,32 @@ ContentParent::Observe(nsISupports* aSub
     }
     // listening for remotePrefs...
     else if (!strcmp(aTopic, "nsPref:changed")) {
         // We know prefs are ASCII here.
         NS_LossyConvertUTF16toASCII strData(aData);
 
         PrefSetting pref(strData, null_t(), null_t());
         Preferences::GetPreference(&pref);
+#ifdef MOZ_NUWA_PROCESS
+        if (IsNuwaProcess() && PreallocatedProcessManager::IsNuwaReady()) {
+            // Don't send the pref update to the Nuwa process. Save the update
+            // to send to the forked child.
+            if (!sNuwaPrefUpdates) {
+                sNuwaPrefUpdates = new nsTArray<PrefSetting>();
+            }
+            sNuwaPrefUpdates->AppendElement(pref);
+        } else if (!SendPreferenceUpdate(pref)) {
+            return NS_ERROR_NOT_AVAILABLE;
+        }
+#else
         if (!SendPreferenceUpdate(pref)) {
             return NS_ERROR_NOT_AVAILABLE;
         }
+#endif
     }
     else if (!strcmp(aTopic, NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC)) {
       NS_ConvertUTF16toUTF8 dataStr(aData);
       const char *offline = dataStr.get();
       if (!SendSetOffline(!strcmp(offline, "true") ? true : false))
           return NS_ERROR_NOT_AVAILABLE;
     }
     // listening for alert notifications
--- a/dom/ipc/PreallocatedProcessManager.cpp
+++ b/dom/ipc/PreallocatedProcessManager.cpp
@@ -49,16 +49,17 @@ public:
   already_AddRefed<ContentParent> Take();
 
 #ifdef MOZ_NUWA_PROCESS
 public:
   void ScheduleDelayedNuwaFork();
   void DelayedNuwaFork();
   void PublishSpareProcess(ContentParent* aContent);
   void MaybeForgetSpare(ContentParent* aContent);
+  bool IsNuwaReady();
   void OnNuwaReady();
   bool PreallocatedProcessReady();
   already_AddRefed<ContentParent> GetSpareProcess();
   void RunAfterPreallocatedProcessReady(nsIRunnable* aRunnable);
 
 private:
   void NuwaFork();
 
@@ -335,16 +336,22 @@ PreallocatedProcessManagerImpl::MaybeFor
 
   if (aContent == mPreallocatedAppProcess) {
     mPreallocatedAppProcess = nullptr;
     mIsNuwaReady = false;
     ScheduleDelayedNuwaFork();
   }
 }
 
+bool
+PreallocatedProcessManagerImpl::IsNuwaReady()
+{
+  return mIsNuwaReady;
+}
+
 void
 PreallocatedProcessManagerImpl::OnNuwaReady()
 {
   NS_ASSERTION(!mIsNuwaReady, "Multiple Nuwa processes created!");
   ProcessPriorityManager::SetProcessPriority(mPreallocatedAppProcess,
                                              hal::PROCESS_PRIORITY_MASTER);
   mIsNuwaReady = true;
   if (Preferences::GetBool("dom.ipc.processPriorityManager.testMode")) {
@@ -477,16 +484,22 @@ PreallocatedProcessManager::MaybeForgetS
 }
 
 /* static */ void
 PreallocatedProcessManager::OnNuwaReady()
 {
   GetPPMImpl()->OnNuwaReady();
 }
 
+/* static */ bool
+PreallocatedProcessManager::IsNuwaReady()
+{
+  return GetPPMImpl()->IsNuwaReady();
+}
+
 /*static */ bool
 PreallocatedProcessManager::PreallocatedProcessReady()
 {
   return GetPPMImpl()->PreallocatedProcessReady();
 }
 
 /* static */ void
 PreallocatedProcessManager::RunAfterPreallocatedProcessReady(nsIRunnable* aRequest)
--- a/dom/ipc/PreallocatedProcessManager.h
+++ b/dom/ipc/PreallocatedProcessManager.h
@@ -78,16 +78,17 @@ public:
    * Allocate* functions (or change the dom.ipc.processPrelaunch pref from
    * false to true) before we'll create a new process.
    */
   static already_AddRefed<ContentParent> Take();
 
 #ifdef MOZ_NUWA_PROCESS
   static void PublishSpareProcess(ContentParent* aContent);
   static void MaybeForgetSpare(ContentParent* aContent);
+  static bool IsNuwaReady();
   static void OnNuwaReady();
   static bool PreallocatedProcessReady();
   static void RunAfterPreallocatedProcessReady(nsIRunnable* aRunnable);
 #endif
 
 private:
   PreallocatedProcessManager();
   DISALLOW_EVIL_CONSTRUCTORS(PreallocatedProcessManager);
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -2088,17 +2088,17 @@ fi
 
 AC_LANG_CPLUSPLUS
 
 MOZ_CXX11
 
 dnl Check for .hidden assembler directive and visibility attribute.
 dnl Borrowed from glibc configure.in
 dnl ===============================================================
-if test "$GNU_CC"; then
+if test "$GNU_CC" -a "$OS_TARGET" != WINNT; then
   AC_DEFINE(HAVE_VISIBILITY_HIDDEN_ATTRIBUTE)
   AC_DEFINE(HAVE_VISIBILITY_ATTRIBUTE)
   if test -n "$gonkdir"; then
     visibility_target=Gonk
   else
     visibility_target=$OS_TARGET
   fi
   case "$visibility_target" in
--- a/js/src/ctypes/libffi-patches/00-base.patch
+++ b/js/src/ctypes/libffi-patches/00-base.patch
@@ -1,13 +1,13 @@
 Modifications to upstream libffi needed for the Mozilla build:
 * Clear INFO_DEPS so that builds don't fail when makeinfo isn't present.
   - This can be removed if https://github.com/atgreen/libffi/issues/111 is fixed.
 * Various workarounds for pymake bugs.
-  - Once pymake support is fully deprecated, hunks 2 & 3 be safely removed.
+  - Once pymake support is fully deprecated, hunks 2-4 be safely removed.
 
 diff --git a/js/src/ctypes/libffi/Makefile.in b/js/src/ctypes/libffi/Makefile.in
 --- a/js/src/ctypes/libffi/Makefile.in
 +++ b/js/src/ctypes/libffi/Makefile.in
 @@ -358,17 +358,17 @@ am__v_TEXI2PDF_1 =
  AM_V_texinfo = $(am__v_texinfo_@AM_V@)
  am__v_texinfo_ = $(am__v_texinfo_@AM_DEFAULT_V@)
  am__v_texinfo_0 = -q
@@ -21,17 +21,40 @@ diff --git a/js/src/ctypes/libffi/Makefi
  am__TEXINFO_TEX_DIR = $(srcdir)
  DVIS = doc/libffi.dvi
  PDFS = doc/libffi.pdf
  PSS = doc/libffi.ps
  HTMLS = doc/libffi.html
  TEXINFOS = doc/libffi.texi
  TEXI2DVI = texi2dvi
  TEXI2PDF = $(TEXI2DVI) --pdf --batch
-@@ -1292,57 +1292,57 @@ distclean-compile:
+@@ -758,18 +758,20 @@ Makefile: $(srcdir)/Makefile.in $(top_bu
+ 
+ $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ 	$(am__cd) $(srcdir) && $(AUTOCONF)
+ $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ 	$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+ $(am__aclocal_m4_deps):
+ 
+ fficonfig.h: stamp-h1
+-	@test -f $@ || rm -f stamp-h1
+-	@test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
++	@if test ! -f $@; then \
++	  rm -f stamp-h1; \
++	  $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \
++	else :; fi
+ 
+ stamp-h1: $(srcdir)/fficonfig.h.in $(top_builddir)/config.status
+ 	@rm -f stamp-h1
+ 	cd $(top_builddir) && $(SHELL) ./config.status fficonfig.h
+ $(srcdir)/fficonfig.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) 
+ 	($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+ 	rm -f stamp-h1
+ 	touch $@
+@@ -1292,57 +1294,57 @@ distclean-compile:
  @AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/freebsd.Plo@am__quote@
  @AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/sysv.Plo@am__quote@
  @AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/unix64.Plo@am__quote@
  @AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/win32.Plo@am__quote@
  @AMDEP_TRUE@@am__include@ @am__quote@src/x86/$(DEPDIR)/win64.Plo@am__quote@
  @AMDEP_TRUE@@am__include@ @am__quote@src/xtensa/$(DEPDIR)/ffi.Plo@am__quote@
  @AMDEP_TRUE@@am__include@ @am__quote@src/xtensa/$(DEPDIR)/sysv.Plo@am__quote@
  
@@ -85,17 +108,17 @@ diff --git a/js/src/ctypes/libffi/Makefi
  @am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
  @am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
  @am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Plo
  @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
  @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
  @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
  
  mostlyclean-libtool:
-@@ -1443,17 +1443,17 @@ doc/libffi.html: doc/libffi.texi $(srcdi
+@@ -1443,17 +1445,17 @@ doc/libffi.html: doc/libffi.texi $(srcdi
  	-@rm -f vti.tmp
  	@cp $(srcdir)/doc/version.texi $@
  
  mostlyclean-vti:
  	-rm -f vti.tmp
  
  maintainer-clean-vti:
  @MAINTAINER_MODE_TRUE@	-rm -f $(srcdir)/doc/stamp-vti $(srcdir)/doc/version.texi
--- a/js/src/ctypes/libffi/Makefile.in
+++ b/js/src/ctypes/libffi/Makefile.in
@@ -758,18 +758,20 @@ Makefile: $(srcdir)/Makefile.in $(top_bu
 
 $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
 	$(am__cd) $(srcdir) && $(AUTOCONF)
 $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
 	$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
 $(am__aclocal_m4_deps):
 
 fficonfig.h: stamp-h1
-	@test -f $@ || rm -f stamp-h1
-	@test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
+	@if test ! -f $@; then \
+	  rm -f stamp-h1; \
+	  $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \
+	else :; fi
 
 stamp-h1: $(srcdir)/fficonfig.h.in $(top_builddir)/config.status
 	@rm -f stamp-h1
 	cd $(top_builddir) && $(SHELL) ./config.status fficonfig.h
 $(srcdir)/fficonfig.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) 
 	($(am__cd) $(top_srcdir) && $(AUTOHEADER))
 	rm -f stamp-h1
 	touch $@
--- a/js/src/jit-test/tests/asm.js/testSource.js
+++ b/js/src/jit-test/tests/asm.js/testSource.js
@@ -232,17 +232,17 @@ if (isAsmJSCompilationAvailable() && isC
     var m = new Function('glob', 'ffi', 'heap', bodyOnly);
     assertEq(isAsmJSModuleLoadedFromCache(m), true);
     assertEq(m.toString(), "function anonymous(glob, ffi, heap) {\n" + bodyOnly + "\n}");
     assertEq(m.toSource(), "(function anonymous(glob, ffi, heap) {\n" + bodyOnly + "\n})");
 }
 
 })();
 
-/* Implicit "use strict" context */
+/* Implicit "use strict" context in modules */
 (function() {
 
 var funcHeader =  'function (glob, ffi, heap) {',
     funcBody = '\n"use asm";\n\
     function g() {}\n\
     return g;\n\n'
     funcFooter = '}',
     funcSource = funcHeader + funcBody + funcFooter
@@ -331,8 +331,38 @@ if (isAsmJSCompilationAvailable() && isC
 
     eval('var x = 42;' + moduleDecl);
     m = g3();
     assertEq(isAsmJSModuleLoadedFromCache(g3), true);
     checkFuncSrc(m);
 }
 
 })();
+
+/* Implicit "use strict" context in functions */
+(function () {
+
+var funcCode = 'function g(x) {\n\
+    x=x|0;\n\
+    return x + 1 | 0;}';
+var moduleCode = 'function () {\n\
+    "use asm";\n' + funcCode + '\n\
+    return g;\n\
+    }',
+    useStrict = '"use strict";';
+
+var f5 = eval(useStrict + ";\n(" + moduleCode + "())");
+
+var expectedToString = funcCode.replace('{', '{\n' + useStrict + '\n')
+var expectedToSource = expectedToString
+
+assertEq(f5.toString(), expectedToString);
+assertEq(f5.toSource(), expectedToSource);
+
+if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
+    var mf5 = eval("\"use strict\";\n(" + moduleCode + ")");
+    assertEq(isAsmJSModuleLoadedFromCache(mf5), true);
+    var f5 = mf5();
+    assertEq(f5.toString(), expectedToString);
+    assertEq(f5.toSource(), expectedToSource);
+}
+
+})();
--- a/js/src/jit/AsmJSLink.cpp
+++ b/js/src/jit/AsmJSLink.cpp
@@ -580,16 +580,17 @@ HandleDynamicLinkFailure(JSContext *cx, 
         formals.infallibleAppend(module.globalArgumentName());
     if (module.importArgumentName())
         formals.infallibleAppend(module.importArgumentName());
     if (module.bufferArgumentName())
         formals.infallibleAppend(module.bufferArgumentName());
 
     CompileOptions options(cx);
     options.setOriginPrincipals(module.scriptSource()->originPrincipals())
+           .setFile(module.scriptSource()->filename())
            .setCompileAndGo(false)
            .setNoScriptRval(false);
 
     SourceBufferHolder srcBuf(src->chars(), end - begin, SourceBufferHolder::NoOwnership);
     if (!frontend::CompileFunctionBody(cx, &fun, options, formals, srcBuf))
         return false;
 
     // Call the function we just recompiled.
@@ -855,16 +856,38 @@ js::IsAsmJSModule(JSContext *cx, unsigne
 }
 
 bool
 js::IsAsmJSModule(HandleFunction fun)
 {
     return fun->isNative() && fun->maybeNative() == LinkAsmJS;
 }
 
+static bool
+AppendUseStrictSource(JSContext *cx, HandleFunction fun, Handle<JSFlatString*> src, StringBuffer &out)
+{
+    // We need to add "use strict" in the body right after the opening
+    // brace.
+    size_t bodyStart = 0, bodyEnd;
+
+    // No need to test for functions created with the Function ctor as
+    // these don't implicitly inherit the "use strict" context. Strict mode is
+    // enabled for functions created with the Function ctor only if they begin with
+    // the "use strict" directive, but these functions won't validate as asm.js
+    // modules.
+
+    ConstTwoByteChars chars(src->chars(), src->length());
+    if (!FindBody(cx, fun, chars, src->length(), &bodyStart, &bodyEnd))
+        return false;
+
+    return out.append(chars, bodyStart) &&
+           out.append("\n\"use strict\";\n") &&
+           out.append(chars + bodyStart, src->length() - bodyStart);
+}
+
 JSString *
 js::AsmJSModuleToString(JSContext *cx, HandleFunction fun, bool addParenToLambda)
 {
     AsmJSModule &module = ModuleFunctionToModuleObject(fun).module();
 
     uint32_t begin = module.funcStart();
     uint32_t end = module.funcEndAfterCurly();
     ScriptSource *source = module.scriptSource();
@@ -904,36 +927,18 @@ js::AsmJSModuleToString(JSContext *cx, H
             return nullptr;
     }
 
     Rooted<JSFlatString*> src(cx, source->substring(cx, begin, end));
     if (!src)
         return nullptr;
 
     if (module.strict()) {
-        // We need to add "use strict" in the body right after the opening
-        // brace.
-        size_t bodyStart = 0, bodyEnd;
-
-        // No need to test for functions created with the Function ctor as
-        // these doesn't implicitly inherit the "use strict" context. Strict mode is
-        // enabled for functions created with the Function ctor only if they begin with
-        // the "use strict" directive, but these functions won't validate as asm.js
-        // modules.
-
-        ConstTwoByteChars chars(src->chars(), src->length());
-        if (!FindBody(cx, fun, chars, src->length(), &bodyStart, &bodyEnd))
+        if (!AppendUseStrictSource(cx, fun, src, out))
             return nullptr;
-
-        if (!out.append(chars, bodyStart) ||
-            !out.append("\n\"use strict\";\n") ||
-            !out.append(chars + bodyStart, src->length() - bodyStart))
-        {
-            return nullptr;
-        }
     } else {
         if (!out.append(src->chars(), src->length()))
             return nullptr;
     }
 
     if (funCtor && !out.append("\n}"))
         return nullptr;
 
@@ -990,17 +995,32 @@ js::AsmJSFunctionToString(JSContext *cx,
 
     // asm.js functions cannot have been created with a Function constructor
     // as they belong within a module.
     JS_ASSERT(!(begin == 0 && end == source->length() && source->argumentsNotIncluded()));
 
     if (!out.append("function "))
         return nullptr;
 
-    Rooted<JSFlatString*> src(cx, source->substring(cx, begin, end));
-    if (!src)
-        return nullptr;
+    if (module.strict()) {
+        // AppendUseStrictSource expects its input to start right after the
+        // function name, so split the source chars from the src into two parts:
+        // the function name and the rest (arguments + body).
+
+        // asm.js functions can't be anonymous
+        JS_ASSERT(fun->atom());
+        if (!out.append(fun->atom()))
+            return nullptr;
 
-    if (!out.append(src->chars(), src->length()))
-        return nullptr;
+        size_t nameEnd = begin + fun->atom()->length();
+        Rooted<JSFlatString*> src(cx, source->substring(cx, nameEnd, end));
+        if (!AppendUseStrictSource(cx, fun, src, out))
+            return nullptr;
+    } else {
+        Rooted<JSFlatString*> src(cx, source->substring(cx, begin, end));
+        if (!src)
+            return nullptr;
+        if (!out.append(src->chars(), src->length()))
+            return nullptr;
+    }
 
     return out.finishString();
 }
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -1562,81 +1562,81 @@ GenerateLIR(MIRGenerator *mir)
         IonSpewPass("Generate LIR");
 
         if (mir->shouldCancel("Generate LIR"))
             return nullptr;
     }
 
     AllocationIntegrityState integrity(*lir);
 
-    TraceLogStartEvent(logger, TraceLogger::RegisterAllocation);
-
-    switch (mir->optimizationInfo().registerAllocator()) {
-      case RegisterAllocator_LSRA: {
+    {
+        AutoTraceLog log(logger, TraceLogger::RegisterAllocation);
+
+        switch (mir->optimizationInfo().registerAllocator()) {
+          case RegisterAllocator_LSRA: {
 #ifdef DEBUG
-        if (!integrity.record())
-            return nullptr;
+            if (!integrity.record())
+                return nullptr;
 #endif
 
-        LinearScanAllocator regalloc(mir, &lirgen, *lir);
-        if (!regalloc.go())
-            return nullptr;
+            LinearScanAllocator regalloc(mir, &lirgen, *lir);
+            if (!regalloc.go())
+                return nullptr;
 
 #ifdef DEBUG
-        if (!integrity.check(false))
-            return nullptr;
+            if (!integrity.check(false))
+                return nullptr;
 #endif
 
-        IonSpewPass("Allocate Registers [LSRA]", &regalloc);
-        break;
-      }
-
-      case RegisterAllocator_Backtracking: {
+            IonSpewPass("Allocate Registers [LSRA]", &regalloc);
+            break;
+          }
+
+          case RegisterAllocator_Backtracking: {
 #ifdef DEBUG
-        if (!integrity.record())
-            return nullptr;
+            if (!integrity.record())
+                return nullptr;
 #endif
 
-        BacktrackingAllocator regalloc(mir, &lirgen, *lir);
-        if (!regalloc.go())
-            return nullptr;
+            BacktrackingAllocator regalloc(mir, &lirgen, *lir);
+            if (!regalloc.go())
+                return nullptr;
 
 #ifdef DEBUG
-        if (!integrity.check(false))
-            return nullptr;
+            if (!integrity.check(false))
+                return nullptr;
 #endif
 
-        IonSpewPass("Allocate Registers [Backtracking]");
-        break;
-      }
-
-      case RegisterAllocator_Stupid: {
-        // Use the integrity checker to populate safepoint information, so
-        // run it in all builds.
-        if (!integrity.record())
+            IonSpewPass("Allocate Registers [Backtracking]");
+            break;
+          }
+
+          case RegisterAllocator_Stupid: {
+            // Use the integrity checker to populate safepoint information, so
+            // run it in all builds.
+            if (!integrity.record())
+                return nullptr;
+
+            StupidAllocator regalloc(mir, &lirgen, *lir);
+            if (!regalloc.go())
+                return nullptr;
+            if (!integrity.check(true))
+                return nullptr;
+            IonSpewPass("Allocate Registers [Stupid]");
+            break;
+          }
+
+          default:
+            MOZ_ASSUME_UNREACHABLE("Bad regalloc");
+        }
+
+        if (mir->shouldCancel("Allocate Registers"))
             return nullptr;
-
-        StupidAllocator regalloc(mir, &lirgen, *lir);
-        if (!regalloc.go())
-            return nullptr;
-        if (!integrity.check(true))
-            return nullptr;
-        IonSpewPass("Allocate Registers [Stupid]");
-        break;
-      }
-
-      default:
-        MOZ_ASSUME_UNREACHABLE("Bad regalloc");
     }
 
-    if (mir->shouldCancel("Allocate Registers"))
-        return nullptr;
-
-    TraceLogStopEvent(logger, TraceLogger::RegisterAllocation);
-
     {
         AutoTraceLog log(logger, TraceLogger::UnsplitEdges);
         // Now that all optimization and register allocation is done, re-introduce
         // critical edges to avoid unnecessary jumps.
         if (!UnsplitEdges(lir))
             return nullptr;
         IonSpewPass("Unsplit Critical Edges");
         AssertBasicGraphCoherency(graph);
--- a/js/src/vm/String-inl.h
+++ b/js/src/vm/String-inl.h
@@ -82,17 +82,17 @@ JSString::validateLength(js::ThreadSafeC
     }
 
     return true;
 }
 
 MOZ_ALWAYS_INLINE void
 JSRope::init(js::ThreadSafeContext *cx, JSString *left, JSString *right, size_t length)
 {
-    d.lengthAndFlags = buildLengthAndFlags(length, ROPE_FLAGS);
+    d.u0.lengthAndFlags = buildLengthAndFlags(length, ROPE_FLAGS);
     d.u1.left = left;
     d.s.u2.right = right;
     js::StringWriteBarrierPost(cx, &d.u1.left);
     js::StringWriteBarrierPost(cx, &d.s.u2.right);
 }
 
 template <js::AllowGC allowGC>
 MOZ_ALWAYS_INLINE JSRope *
@@ -117,17 +117,17 @@ JSRope::markChildren(JSTracer *trc)
     js::gc::MarkStringUnbarriered(trc, &d.s.u2.right, "right child");
 }
 
 MOZ_ALWAYS_INLINE void
 JSDependentString::init(js::ThreadSafeContext *cx, JSLinearString *base, const jschar *chars,
                         size_t length)
 {
     JS_ASSERT(!js::IsPoisonedPtr(base));
-    d.lengthAndFlags = buildLengthAndFlags(length, DEPENDENT_FLAGS);
+    d.u0.lengthAndFlags = buildLengthAndFlags(length, DEPENDENT_FLAGS);
     d.u1.chars = chars;
     d.s.u2.base = base;
     js::StringWriteBarrierPost(cx, reinterpret_cast<JSString **>(&d.s.u2.base));
 }
 
 MOZ_ALWAYS_INLINE JSLinearString *
 JSDependentString::new_(js::ExclusiveContext *cx,
                         JSLinearString *baseArg, const jschar *chars, size_t length)
@@ -180,17 +180,17 @@ JSString::markBase(JSTracer *trc)
 {
     JS_ASSERT(hasBase());
     js::gc::MarkStringUnbarriered(trc, &d.s.u2.base, "base");
 }
 
 MOZ_ALWAYS_INLINE void
 JSFlatString::init(const jschar *chars, size_t length)
 {
-    d.lengthAndFlags = buildLengthAndFlags(length, FIXED_FLAGS);
+    d.u0.lengthAndFlags = buildLengthAndFlags(length, FIXED_FLAGS);
     d.u1.chars = chars;
 }
 
 template <js::AllowGC allowGC>
 MOZ_ALWAYS_INLINE JSFlatString *
 JSFlatString::new_(js::ThreadSafeContext *cx, const jschar *chars, size_t length)
 {
     JS_ASSERT(chars[length] == jschar(0));
@@ -224,42 +224,42 @@ MOZ_ALWAYS_INLINE JSInlineString *
 JSInlineString::new_(js::ThreadSafeContext *cx)
 {
     return (JSInlineString *)js_NewGCString<allowGC>(cx);
 }
 
 MOZ_ALWAYS_INLINE jschar *
 JSInlineString::init(size_t length)
 {
-    d.lengthAndFlags = buildLengthAndFlags(length, FIXED_FLAGS);
+    d.u0.lengthAndFlags = buildLengthAndFlags(length, FIXED_FLAGS);
     d.u1.chars = d.inlineStorage;
     JS_ASSERT(lengthFits(length) || (isFatInline() && JSFatInlineString::lengthFits(length)));
     return d.inlineStorage;
 }
 
 MOZ_ALWAYS_INLINE void
 JSInlineString::resetLength(size_t length)
 {
-    d.lengthAndFlags = buildLengthAndFlags(length, FIXED_FLAGS);
+    d.u0.lengthAndFlags = buildLengthAndFlags(length, FIXED_FLAGS);
     JS_ASSERT(lengthFits(length) || (isFatInline() && JSFatInlineString::lengthFits(length)));
 }
 
 template <js::AllowGC allowGC>
 MOZ_ALWAYS_INLINE JSFatInlineString *
 JSFatInlineString::new_(js::ThreadSafeContext *cx)
 {
     return js_NewGCFatInlineString<allowGC>(cx);
 }
 
 MOZ_ALWAYS_INLINE void
 JSExternalString::init(const jschar *chars, size_t length, const JSStringFinalizer *fin)
 {
     JS_ASSERT(fin);
     JS_ASSERT(fin->finalize);
-    d.lengthAndFlags = buildLengthAndFlags(length, FIXED_FLAGS);
+    d.u0.lengthAndFlags = buildLengthAndFlags(length, FIXED_FLAGS);
     d.u1.chars = chars;
     d.s.u2.externalFinalizer = fin;
 }
 
 MOZ_ALWAYS_INLINE JSExternalString *
 JSExternalString::new_(JSContext *cx, const jschar *chars, size_t length,
                        const JSStringFinalizer *fin)
 {
--- a/js/src/vm/String.cpp
+++ b/js/src/vm/String.cpp
@@ -226,18 +226,17 @@ JSRope::flattenInternal(ExclusiveContext
      * Perform a depth-first dag traversal, splatting each node's characters
      * into a contiguous buffer. Visit each rope node three times:
      *   1. record position in the buffer and recurse into left child;
      *   2. recurse into the right child;
      *   3. transform the node into a dependent string.
      * To avoid maintaining a stack, tree nodes are mutated to indicate how many
      * times they have been visited. Since ropes can be dags, a node may be
      * encountered multiple times during traversal. However, step 3 above leaves
-     * a valid dependent string, so everything works out. This algorithm is
-     * homomorphic to marking code.
+     * a valid dependent string, so everything works out.
      *
      * While ropes avoid all sorts of quadratic cases with string
      * concatenation, they can't help when ropes are immediately flattened.
      * One idiomatic case that we'd like to keep linear (and has traditionally
      * been linear in SM and other JS engines) is:
      *
      *   while (...) {
      *     s += ...
@@ -255,52 +254,60 @@ JSRope::flattenInternal(ExclusiveContext
      * N.B. This optimization can create chains of dependent strings.
      */
     const size_t wholeLength = length();
     size_t wholeCapacity;
     jschar *wholeChars;
     JSString *str = this;
     jschar *pos;
 
+    /*
+     * JSString::flattenData is a tagged pointer to the parent node.
+     * The tag indicates what to do when we return to the parent.
+     */
+    static const uintptr_t Tag_Mask = 0x3;
+    static const uintptr_t Tag_FinishNode = 0x0;
+    static const uintptr_t Tag_VisitRightChild = 0x1;
+
     /* Find the left most string, containing the first string. */
     JSRope *leftMostRope = this;
     while (leftMostRope->leftChild()->isRope())
         leftMostRope = &leftMostRope->leftChild()->asRope();
 
     if (leftMostRope->leftChild()->isExtensible()) {
         JSExtensibleString &left = leftMostRope->leftChild()->asExtensible();
         size_t capacity = left.capacity();
         if (capacity >= wholeLength) {
             /*
              * Simulate a left-most traversal from the root to leftMost->leftChild()
              * via first_visit_node
              */
+            JS_ASSERT(str->isRope());
             while (str != leftMostRope) {
-                JS_ASSERT(str->isRope());
                 if (b == WithIncrementalBarrier) {
                     JSString::writeBarrierPre(str->d.u1.left);
                     JSString::writeBarrierPre(str->d.s.u2.right);
                 }
                 JSString *child = str->d.u1.left;
+                JS_ASSERT(child->isRope());
                 str->d.u1.chars = left.chars();
-                child->d.s.u3.parent = str;
-                child->d.lengthAndFlags = 0x200;
+                child->d.u0.flattenData = uintptr_t(str) | Tag_VisitRightChild;
                 str = child;
             }
             if (b == WithIncrementalBarrier) {
                 JSString::writeBarrierPre(str->d.u1.left);
                 JSString::writeBarrierPre(str->d.s.u2.right);
             }
             str->d.u1.chars = left.chars();
             wholeCapacity = capacity;
             wholeChars = const_cast<jschar *>(left.chars());
-            size_t bits = left.d.lengthAndFlags;
+            size_t bits = left.d.u0.lengthAndFlags;
             pos = wholeChars + (bits >> LENGTH_SHIFT);
             JS_STATIC_ASSERT(!(EXTENSIBLE_FLAGS & DEPENDENT_FLAGS));
-            left.d.lengthAndFlags = bits ^ (EXTENSIBLE_FLAGS | DEPENDENT_FLAGS);
+            left.d.u0.lengthAndFlags = bits ^ (EXTENSIBLE_FLAGS | DEPENDENT_FLAGS);
             left.d.s.u2.base = (JSLinearString *)this;  /* will be true on exit */
             StringWriteBarrierPostRemove(maybecx, &left.d.u1.left);
             StringWriteBarrierPost(maybecx, (JSString **)&left.d.s.u2.base);
             goto visit_right_child;
         }
     }
 
     if (!AllocChars(maybecx, wholeLength, &wholeChars, &wholeCapacity))
@@ -312,56 +319,56 @@ JSRope::flattenInternal(ExclusiveContext
             JSString::writeBarrierPre(str->d.u1.left);
             JSString::writeBarrierPre(str->d.s.u2.right);
         }
 
         JSString &left = *str->d.u1.left;
         str->d.u1.chars = pos;
         StringWriteBarrierPostRemove(maybecx, &str->d.u1.left);
         if (left.isRope()) {
-            left.d.s.u3.parent = str;          /* Return to this when 'left' done, */
-            left.d.lengthAndFlags = 0x200;     /* but goto visit_right_child. */
+            /* Return to this node when 'left' done, then goto visit_right_child. */
+            left.d.u0.flattenData = uintptr_t(str) | Tag_VisitRightChild;
             str = &left;
             goto first_visit_node;
         }
         size_t len = left.length();
         PodCopy(pos, left.d.u1.chars, len);
         pos += len;
     }
     visit_right_child: {
         JSString &right = *str->d.s.u2.right;
         if (right.isRope()) {
-            right.d.s.u3.parent = str;         /* Return to this node when 'right' done, */
-            right.d.lengthAndFlags = 0x300;    /* but goto finish_node. */
+            /* Return to this node when 'right' done, then goto finish_node. */
+            right.d.u0.flattenData = uintptr_t(str) | Tag_FinishNode;
             str = &right;
             goto first_visit_node;
         }
         size_t len = right.length();
         PodCopy(pos, right.d.u1.chars, len);
         pos += len;
     }
     finish_node: {
         if (str == this) {
             JS_ASSERT(pos == wholeChars + wholeLength);
             *pos = '\0';
-            str->d.lengthAndFlags = buildLengthAndFlags(wholeLength, EXTENSIBLE_FLAGS);
+            str->d.u0.lengthAndFlags = buildLengthAndFlags(wholeLength, EXTENSIBLE_FLAGS);
             str->d.u1.chars = wholeChars;
             str->d.s.u2.capacity = wholeCapacity;
             StringWriteBarrierPostRemove(maybecx, &str->d.u1.left);
             StringWriteBarrierPostRemove(maybecx, &str->d.s.u2.right);
             return &this->asFlat();
         }
-        size_t progress = str->d.lengthAndFlags;
-        str->d.lengthAndFlags = buildLengthAndFlags(pos - str->d.u1.chars, DEPENDENT_FLAGS);
+        uintptr_t flattenData = str->d.u0.flattenData;
+        str->d.u0.lengthAndFlags = buildLengthAndFlags(pos - str->d.u1.chars, DEPENDENT_FLAGS);
         str->d.s.u2.base = (JSLinearString *)this;       /* will be true on exit */
         StringWriteBarrierPost(maybecx, (JSString **)&str->d.s.u2.base);
-        str = str->d.s.u3.parent;
-        if (progress == 0x200)
+        str = (JSString *)(flattenData & ~Tag_Mask);
+        if ((flattenData & Tag_Mask) == Tag_VisitRightChild)
             goto visit_right_child;
-        JS_ASSERT(progress == 0x300);
+        JS_ASSERT((flattenData & Tag_Mask) == Tag_FinishNode);
         goto finish_node;
     }
 }
 
 JSFlatString *
 JSRope::flatten(ExclusiveContext *maybecx)
 {
 #if JSGC_INCREMENTAL
@@ -460,17 +467,17 @@ JSDependentString::undepend(ExclusiveCon
     PodCopy(s, chars(), n);
     s[n] = 0;
     d.u1.chars = s;
 
     /*
      * Transform *this into an undepended string so 'base' will remain rooted
      * for the benefit of any other dependent string that depends on *this.
      */
-    d.lengthAndFlags = buildLengthAndFlags(n, UNDEPENDED_FLAGS);
+    d.u0.lengthAndFlags = buildLengthAndFlags(n, UNDEPENDED_FLAGS);
 
     return &this->asFlat();
 }
 
 bool
 JSFlatString::isIndexSlow(uint32_t *indexp) const
 {
     const jschar *s = charsZ();
--- a/js/src/vm/String.h
+++ b/js/src/vm/String.h
@@ -131,34 +131,33 @@ static const size_t UINT32_CHAR_BUFFER_L
 class JSString : public js::gc::BarrieredCell<JSString>
 {
   protected:
     static const size_t NUM_INLINE_CHARS = 2 * sizeof(void *) / sizeof(jschar);
 
     /* Fields only apply to string types commented on the right. */
     struct Data
     {
-        size_t                     lengthAndFlags;      /* JSString */
+        union {
+            size_t                 lengthAndFlags;      /* JSString */
+            uintptr_t              flattenData;         /* JSRope (temporary while flattening) */
+        } u0;
         union {
             const jschar           *chars;              /* JSLinearString */
             JSString               *left;               /* JSRope */
         } u1;
         union {
             jschar                 inlineStorage[NUM_INLINE_CHARS]; /* JS(Inline|FatInline)String */
             struct {
                 union {
                     JSLinearString *base;               /* JS(Dependent|Undepended)String */
                     JSString       *right;              /* JSRope */
                     size_t         capacity;            /* JSFlatString (extensible) */
                     const JSStringFinalizer *externalFinalizer;/* JSExternalString */
                 } u2;
-                union {
-                    JSString       *parent;             /* JSRope (temporary) */
-                    size_t         reserved;            /* may use for bug 615290 */
-                } u3;
             } s;
         };
     } d;
 
   public:
     /* Flags exposed only for jits */
 
     /*
@@ -247,22 +246,22 @@ class JSString : public js::gc::Barriere
     /* Avoid lame compile errors in JSRope::flatten */
     friend class JSRope;
 
   public:
     /* All strings have length. */
 
     MOZ_ALWAYS_INLINE
     size_t length() const {
-        return d.lengthAndFlags >> LENGTH_SHIFT;
+        return d.u0.lengthAndFlags >> LENGTH_SHIFT;
     }
 
     MOZ_ALWAYS_INLINE
     bool empty() const {
-        return d.lengthAndFlags <= FLAGS_MASK;
+        return d.u0.lengthAndFlags <= FLAGS_MASK;
     }
 
     /*
      * All strings have a fallible operation to get an array of chars.
      * getCharsZ additionally ensures the array is null terminated.
      */
 
     inline const jschar *getChars(js::ExclusiveContext *cx);
@@ -294,17 +293,17 @@ class JSString : public js::gc::Barriere
     static bool ensureLinear(js::ExclusiveContext *cx, JSString *str) {
         return str->ensureLinear(cx) != nullptr;
     }
 
     /* Type query and debug-checked casts */
 
     MOZ_ALWAYS_INLINE
     bool isRope() const {
-        return (d.lengthAndFlags & FLAGS_MASK) == ROPE_FLAGS;
+        return (d.u0.lengthAndFlags & FLAGS_MASK) == ROPE_FLAGS;
     }
 
     MOZ_ALWAYS_INLINE
     JSRope &asRope() const {
         JS_ASSERT(isRope());
         return *(JSRope *)this;
     }
 
@@ -316,17 +315,17 @@ class JSString : public js::gc::Barriere
     MOZ_ALWAYS_INLINE
     JSLinearString &asLinear() const {
         JS_ASSERT(JSString::isLinear());
         return *(JSLinearString *)this;
     }
 
     MOZ_ALWAYS_INLINE
     bool isDependent() const {
-        return (d.lengthAndFlags & FLAGS_MASK) == DEPENDENT_FLAGS;
+        return (d.u0.lengthAndFlags & FLAGS_MASK) == DEPENDENT_FLAGS;
     }
 
     MOZ_ALWAYS_INLINE
     JSDependentString &asDependent() const {
         JS_ASSERT(isDependent());
         return *(JSDependentString *)this;
     }
 
@@ -338,17 +337,17 @@ class JSString : public js::gc::Barriere
     MOZ_ALWAYS_INLINE
     JSFlatString &asFlat() const {
         JS_ASSERT(isFlat());
         return *(JSFlatString *)this;
     }
 
     MOZ_ALWAYS_INLINE
     bool isExtensible() const {
-        return (d.lengthAndFlags & FLAGS_MASK) == EXTENSIBLE_FLAGS;
+        return (d.u0.lengthAndFlags & FLAGS_MASK) == EXTENSIBLE_FLAGS;
     }
 
     MOZ_ALWAYS_INLINE
     JSExtensibleString &asExtensible() const {
         JS_ASSERT(isExtensible());
         return *(JSExtensibleString *)this;
     }
 
@@ -371,40 +370,40 @@ class JSString : public js::gc::Barriere
     MOZ_ALWAYS_INLINE
     JSExternalString &asExternal() const {
         JS_ASSERT(isExternal());
         return *(JSExternalString *)this;
     }
 
     MOZ_ALWAYS_INLINE
     bool isUndepended() const {
-        return (d.lengthAndFlags & FLAGS_MASK) == UNDEPENDED_FLAGS;
+        return (d.u0.lengthAndFlags & FLAGS_MASK) == UNDEPENDED_FLAGS;
     }
 
     MOZ_ALWAYS_INLINE
     bool isAtom() const {
-        return d.lengthAndFlags & ATOM_BIT;
+        return d.u0.lengthAndFlags & ATOM_BIT;
     }
 
     MOZ_ALWAYS_INLINE
     bool isPermanentAtom() const {
-        return (d.lengthAndFlags & FLAGS_MASK) == PERMANENT_ATOM_FLAGS;
+        return (d.u0.lengthAndFlags & FLAGS_MASK) == PERMANENT_ATOM_FLAGS;
     }
 
     MOZ_ALWAYS_INLINE
     JSAtom &asAtom() const {
         JS_ASSERT(isAtom());
         return *(JSAtom *)this;
     }
 
     /* Only called by the GC for dependent or undepended strings. */
 
     inline bool hasBase() const {
         JS_STATIC_ASSERT((DEPENDENT_FLAGS | JS_BIT(1)) == UNDEPENDED_FLAGS);
-        return d.lengthAndFlags & HAS_BASE_BIT;
+        return d.u0.lengthAndFlags & HAS_BASE_BIT;
     }
 
     inline JSLinearString *base() const;
 
     inline void markBase(JSTracer *trc);
 
     /* Only called by the GC for strings with the FINALIZE_STRING kind. */
 
@@ -412,17 +411,17 @@ class JSString : public js::gc::Barriere
 
     /* Gets the number of bytes that the chars take on the heap. */
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
 
     /* Offsets for direct field from jit code. */
 
     static size_t offsetOfLengthAndFlags() {
-        return offsetof(JSString, d.lengthAndFlags);
+        return offsetof(JSString, d.u0.lengthAndFlags);
     }
 
     static size_t offsetOfChars() {
         return offsetof(JSString, d.u1.chars);
     }
 
     js::gc::AllocKind getAllocKind() const { return tenuredGetAllocKind(); }
 
@@ -589,21 +588,21 @@ class JSFlatString : public JSLinearStri
      */
     inline js::PropertyName *toPropertyName(JSContext *cx);
 
     /*
      * Once a JSFlatString sub-class has been added to the atom state, this
      * operation changes the string to the JSAtom type, in place.
      */
     MOZ_ALWAYS_INLINE JSAtom *morphAtomizedStringIntoAtom() {
-        d.lengthAndFlags = buildLengthAndFlags(length(), ATOM_BIT);
+        d.u0.lengthAndFlags = buildLengthAndFlags(length(), ATOM_BIT);
         return &asAtom();
     }
     MOZ_ALWAYS_INLINE JSAtom *morphAtomizedStringIntoPermanentAtom() {
-        d.lengthAndFlags = buildLengthAndFlags(length(), PERMANENT_ATOM_FLAGS);
+        d.u0.lengthAndFlags = buildLengthAndFlags(length(), PERMANENT_ATOM_FLAGS);
         return &asAtom();
     }
 
     inline void finalize(js::FreeOp *fop);
 };
 
 JS_STATIC_ASSERT(sizeof(JSFlatString) == sizeof(JSString));
 
@@ -735,23 +734,23 @@ class JSAtom : public JSFlatString
   public:
     /* Returns the PropertyName for this.  isIndex() must be false. */
     inline js::PropertyName *asPropertyName();
 
     inline void finalize(js::FreeOp *fop);
 
     MOZ_ALWAYS_INLINE
     bool isPermanent() const {
-        return d.lengthAndFlags & PERMANENT_BIT;
+        return d.u0.lengthAndFlags & PERMANENT_BIT;
     }
 
     // Transform this atom into a permanent atom. This is only done during
     // initialization of the runtime.
     MOZ_ALWAYS_INLINE void morphIntoPermanentAtom() {
-        d.lengthAndFlags = buildLengthAndFlags(length(), PERMANENT_ATOM_FLAGS);
+        d.u0.lengthAndFlags = buildLengthAndFlags(length(), PERMANENT_ATOM_FLAGS);
     }
 
 #ifdef DEBUG
     void dump();
 #endif
 };
 
 JS_STATIC_ASSERT(sizeof(JSAtom) == sizeof(JSString));
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -1602,16 +1602,17 @@ ScrollFrameHelper::ScrollFrameHelper(nsC
   , mHorizontalOverflow(false)
   , mVerticalOverflow(false)
   , mPostedReflowCallback(false)
   , mMayHaveDirtyFixedChildren(false)
   , mUpdateScrollbarAttributes(false)
   , mCollapsedResizer(false)
   , mShouldBuildScrollableLayer(false)
   , mHasBeenScrolled(false)
+  , mIsResolutionSet(false)
 {
   mScrollingActive = IsAlwaysActive();
 
   if (LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars) != 0) {
     mScrollbarActivity = new ScrollbarActivity(do_QueryFrame(aOuter));
   }
 
   EnsureImageVisPrefsCached();
@@ -2790,16 +2791,17 @@ ScrollFrameHelper::GetResolution() const
 {
   return mResolution;
 }
 
 void
 ScrollFrameHelper::SetResolution(const gfxSize& aResolution)
 {
   mResolution = aResolution;
+  mIsResolutionSet = true;
 }
 
 static void
 AdjustForWholeDelta(int32_t aDelta, nscoord* aCoord)
 {
   if (aDelta < 0) {
     *aCoord = nscoord_MIN;
   } else if (aDelta > 0) {
@@ -4533,16 +4535,17 @@ ScrollFrameHelper::SaveState() const
 
 void
 ScrollFrameHelper::RestoreState(nsPresState* aState)
 {
   mRestorePos = aState->GetScrollState();
   mDidHistoryRestore = true;
   mLastPos = mScrolledFrame ? GetLogicalScrollPosition() : nsPoint(0,0);
   mResolution = aState->GetResolution();
+  mIsResolutionSet = true;
 
   if (mIsRoot) {
     mOuter->PresContext()->PresShell()->SetResolution(mResolution.width, mResolution.height);
   }
 }
 
 void
 ScrollFrameHelper::PostScrolledAreaEvent()
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -402,16 +402,20 @@ public:
 
   // If true, the layer should always be active because we always build a
   // scrollable layer. Used for asynchronous scrolling.
   bool mShouldBuildScrollableLayer:1;
 
   // True if this frame has been scrolled at least once
   bool mHasBeenScrolled:1;
 
+  // True if the frame's resolution has been set via SetResolution or restored
+  // via RestoreState.
+  bool mIsResolutionSet:1;
+
 protected:
   /**
    * @note This method might destroy the frame, pres shell and other objects.
    */
   void ScrollToWithOrigin(nsPoint aScrollPosition,
                           nsIScrollableFrame::ScrollMode aMode,
                           nsIAtom *aOrigin, // nullptr indicates "other" origin
                           const nsRect* aRange);
@@ -653,16 +657,19 @@ public:
     return mHelper.IsScrollingActive();
   }
   virtual bool IsProcessingAsyncScroll() MOZ_OVERRIDE {
     return mHelper.IsProcessingAsyncScroll();
   }
   virtual void ResetScrollPositionForLayerPixelAlignment() MOZ_OVERRIDE {
     mHelper.ResetScrollPositionForLayerPixelAlignment();
   }
+  virtual bool IsResolutionSet() const MOZ_OVERRIDE {
+    return mHelper.mIsResolutionSet;
+  }
   virtual bool DidHistoryRestore() const MOZ_OVERRIDE {
     return mHelper.mDidHistoryRestore;
   }
   virtual void ClearDidHistoryRestore() MOZ_OVERRIDE {
     mHelper.mDidHistoryRestore = false;
   }
   virtual bool IsRectNearlyVisible(const nsRect& aRect) MOZ_OVERRIDE {
     return mHelper.IsRectNearlyVisible(aRect);
@@ -967,16 +974,19 @@ public:
     return mHelper.IsScrollingActive();
   }
   virtual bool IsProcessingAsyncScroll() MOZ_OVERRIDE {
     return mHelper.IsProcessingAsyncScroll();
   }
   virtual void ResetScrollPositionForLayerPixelAlignment() MOZ_OVERRIDE {
     mHelper.ResetScrollPositionForLayerPixelAlignment();
   }
+  virtual bool IsResolutionSet() const MOZ_OVERRIDE {
+    return mHelper.mIsResolutionSet;
+  }
   virtual bool DidHistoryRestore() const MOZ_OVERRIDE {
     return mHelper.mDidHistoryRestore;
   }
   virtual void ClearDidHistoryRestore() MOZ_OVERRIDE {
     mHelper.mDidHistoryRestore = false;
   }
   virtual bool IsRectNearlyVisible(const nsRect& aRect) MOZ_OVERRIDE {
     return mHelper.IsRectNearlyVisible(aRect);
--- a/layout/generic/nsIScrollableFrame.h
+++ b/layout/generic/nsIScrollableFrame.h
@@ -267,16 +267,20 @@ public:
    * completely redrawn.
    */
   virtual void ResetScrollPositionForLayerPixelAlignment() = 0;
   /**
    * Was the current presentation state for this frame restored from history?
    */
   virtual bool DidHistoryRestore() const = 0;
   /**
+   * Was the current resolution set by the user or just default initialized?
+   */
+  virtual bool IsResolutionSet() const = 0;
+  /**
    * Clear the flag so that DidHistoryRestore() returns false until the next
    * RestoreState call.
    * @see nsIStatefulFrame::RestoreState
    */
   virtual void ClearDidHistoryRestore() = 0;
   /**
    * Determine if the passed in rect is nearly visible according to the image
    * visibility heuristics for how close it is to the visible scrollport.
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/button/disabled-1-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Bug 1007278: test button "disabled" text style</title>
+<style>
+  button {
+    color: GrayText;
+    border-width: 0;
+    background: transparent;
+  }
+</style>
+</head>
+<body>
+  <button>Some text</button>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/button/disabled-1.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Bug 1007278: test button "disabled" text style</title>
+<style>
+  button {
+    border-width: 0;
+    background: transparent;
+  }
+</style>
+</head>
+<body>
+  <button disabled>Some text</button>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/button/disabled-2-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Bug 1007278: test all types of buttons look similar when disabled</title>
+</head>
+<body>
+  <button>Some text</button>
+  <button>Some text</button>
+  <button>Reset</button>
+  <button>Submit Query</button>
+  <br>
+  <button disabled>Some text</button>
+  <button disabled>Some text</button>
+  <button disabled>Reset</button>
+  <button disabled>Submit Query</button>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/button/disabled-2.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Bug 1007278: test all types of buttons look similar when disabled</title>
+</head>
+<body>
+  <button>Some text</button>
+  <input type="button" value="Some text">
+  <input type="reset">
+  <input type="submit">
+  <br>
+  <button disabled>Some text</button>
+  <input disabled type="button" value="Some text">
+  <input disabled type="reset">
+  <input disabled type="submit">
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/button/disabled-3-notref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Bug 1007278: check disabled and non-disabled buttons look different</title>
+</head>
+<body>
+  <button disabled>Some text</button>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/button/disabled-3.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Bug 1007278: check disabled and non-disabled buttons look different</title>
+</head>
+<body>
+  <button>Some text</button>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/button/disabled-4-notref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Bug 1007278: check disabled and non-disabled buttons look different</title>
+</head>
+<body>
+  <input disabled type="button" value="Some text">
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/button/disabled-4.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Bug 1007278: check disabled and non-disabled buttons look different</title>
+</head>
+<body>
+  <input type="button" value="Some text">
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/button/disabled-5-notref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Bug 1007278: check disabled and non-disabled buttons look different</title>
+</head>
+<body>
+  <input disabled type="reset">
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/button/disabled-5.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Bug 1007278: check disabled and non-disabled buttons look different</title>
+</head>
+<body>
+  <input type="reset">
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/button/disabled-6-notref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Bug 1007278: check disabled and non-disabled buttons look different</title>
+</head>
+<body>
+  <input disabled type="submit">
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/button/disabled-6.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Bug 1007278: check disabled and non-disabled buttons look different</title>
+</head>
+<body>
+  <input type="submit">
+</body>
+</html>
--- a/layout/reftests/forms/button/reftest.list
+++ b/layout/reftests/forms/button/reftest.list
@@ -12,8 +12,20 @@ fuzzy-if(B2G||Android,125,20) == percent
 fuzzy-if(B2G||Android,125,80) == percent-width-child-2.html  percent-width-child-2-ref.html
 
 == vertical-centering.html vertical-centering-ref.html
 
 != line-height-button-0.5.html line-height-button-1.0.html
 != line-height-button-1.5.html line-height-button-1.0.html
 != line-height-input-0.5.html line-height-input-1.0.html
 != line-height-input-1.5.html line-height-input-1.0.html
+
+# Looks like Android and B2G change the text color, but to something slightly
+# different from ColorGray
+fails-if(Android||B2G) == disabled-1.html disabled-1-ref.html
+# While disabled buttons don't look like non-disabled buttons, <button disabled>
+# is different from other disabled buttons for B2G ICS Emulator (see bug 1009714)
+fails-if(B2G) == disabled-2.html disabled-2-ref.html
+
+!= disabled-3.html disabled-3-notref.html
+!= disabled-4.html disabled-4-notref.html
+!= disabled-5.html disabled-5-notref.html
+!= disabled-6.html disabled-6-notref.html
--- a/layout/style/forms.css
+++ b/layout/style/forms.css
@@ -659,16 +659,17 @@ input[type="submit"]:disabled:active,
 input[type="submit"]:disabled {
   /* The sum of border-top, border-bottom, padding-top, padding-bottom
      must be the same here and for text inputs */
   padding: 0px 6px 0px 6px;
   border: 2px outset ButtonFace;
   cursor: inherit; 
 }
 
+button:disabled:active, button:disabled,
 input[type="reset"]:disabled:active,
 input[type="reset"]:disabled,
 input[type="button"]:disabled:active,
 input[type="button"]:disabled,
 select:disabled > button,
 select:disabled > button,
 input[type="submit"]:disabled:active,
 input[type="submit"]:disabled {
--- a/mach
+++ b/mach
@@ -1,9 +1,9 @@
-#!/usr/bin/env python2.7
+#!/usr/bin/env 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/.
 
 from __future__ import print_function, unicode_literals
 
 import os
 import sys
--- a/mobile/android/base/locales/en-US/suggestedsites/fxmarketplace.json
+++ b/mobile/android/base/locales/en-US/suggestedsites/fxmarketplace.json
@@ -1,3 +1,3 @@
 { "title": "Firefox Marketplace",
-  "url": "http://marketplace.firefox.com",
+  "url": "https://marketplace.firefox.com/",
   "bgcolor": "#0095dd" }
--- a/mobile/android/base/locales/en-US/suggestedsites/mozilla.json
+++ b/mobile/android/base/locales/en-US/suggestedsites/mozilla.json
@@ -1,3 +1,3 @@
 { "title": "Mozilla",
-  "url": "http://mozilla.org",
+  "url": "http://www.mozilla.org/en-US/",
   "bgcolor": "#c13832" }
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..da1ff4ddcdb68da59ecfcfd17df4038b4591fec7
GIT binary patch
literal 803
zc$@(v1Kj+HP)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UAX9Cm^C0!3_Wa0<cL$
zK~z}7?U+Ak6hRcmzc=0;xyBS0Mhig{6hQ-`ppE#469fe<5*3Z077__0YzT>&Be}T8
z>19dWbaoaZh!%oYvV{>WL=XbDVv$ZHLPQ9;B=gzq!E&5Q?soUK$-uxdvorkWd*6Gr
zdqBuGGc%KMUAGevH3_rWah#4!Ci5P^5dg0M^z`@lSHkR>3Zo2wcRmaNbOTrba6b%?
zYIY&Xha``YM4<P&u6wcNA#+{#5P&%V={lhEBoA7awbV+59@T>Z01?@vl<IAnLays}
zlAPP%v7aROHlvbi!aIF6L%&3%3?P_YI{{pcJ!GX)sofZJBWPq}O!vURz=$!X5F7_^
zFLt1|wzexGk_`;K9UL5-^}XYY$b4Y#M7dnvA1e^au9`G|Qk}CbYsnb%G&rA1rMhA>
z_4M>~mgE9}szOTu9s}47U^{?609F9>1v2ilWmzX<0h*ecI!*FJg9lzwO0_qVZH<KN
zS`!{kH=1pmQpj<f0)X)*Yuze<o}r<kmyswG5~g~AKX)AG?q(j|wh;`;FfhS`U&`fj
zzdg_U(iBjHFhP4<$mMbs&+|St95Q3fcumcTs+VGUABwA`)~U*g0BtF>rBEUYk(}^9
zf$Fu7B+md?j1*{{Ix?ZPE|9!Va$jv<TU$G;wVow;nPjEj9#JYZp|vjfzju&4Dk2M7
z>mMZ3Bu^=&vH+m9o&|6R0Ao?81_s8Mn*d%1mK+A~48ZZ~fY$m2$&p4B`md?;`TV-C
zCL*#60MhAn*7r-wKS)Q-K9c|@Tk$DfA&KSX<y*FGE0VYU)2}A-XM>1*^Fv?*I0xXo
zuh?87g;6Q>2EbncnJNr`ufxN`-xC2E9UWaH=>*J5k`EHSIz*&cEs!FT9~&F<62E(F
h+g8P5@jz7j{R1|(*PiCCuG#<q002ovPDHLkV1g=uRB8YK
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..adbadcd4b8c77bd0510d5dc0db47c4470b3f8c32
GIT binary patch
literal 722
zc$@*!0xkWCP)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UAX9Co46?7=-`;0$)i)
zK~z}7?N&R86HydBcTAR~aSIDSohVqzf*@!ke#nA_pvC&Z52%HWMVJt>=7ns+gkW|^
zoOE^;A_x|OmQ%Qbg$TletytKJtgs@4WH;~FWMl|#lF806O%6O5?tSla?s@m!JA#04
z9A|;#`j~A$NFFv#vlBGF5%d7bheM{HBGLfR^V#+TxP~bZh)}&=pVwO7BnfY6t*>UY
z*=4PD#cv1jAaX*fRO*U|q<yA0xm<1y07S$Qk?%g=sYau5G*Ut&m;5S_eB${`)9h%i
zpZfiYL}Do@A(?bztJO-A+yLMy)B*4qz##y80sIEA1>j$eiO5IOG*3rDsM&0uCHXF3
z!dr%6%m;aGL9Xoj6g8R*`r0N^$hPeYfE7%KZ2-6P`TWaJ6xt;j07w9MZrk?#NjC2p
zM~38X$oLb#l*wd%xvu+ZDncQW@t4QNOeWKFUH3!aE7Mx94E3C_Rz1{N7Bvzhx^gUp
zW(v&|ibWxkRRC{yaK9&c4!~xpghup{s#2;#@&?Hx!>ix#pI1t)k-SW@_rDlnDpXZU
zRR-VtNS+Xp4W-mKl1Y+h48uqRfKqA=z&!wrM4=%v&|2RD@XB}OIDlsWPI?BV)C-c!
zK@{4ts7s~N$X^o?IS2sBWHLRdm&72E14D6E0jx&;?7jNvcDr{h%Q8sb9b~^9$+I6j
zx<$SWuD}9t0l?xwvGrIQqhT1Y0sH|l=aB*Mxlky4jfGILSllFO`-+t$AH_O4M5N|5
zND(QO%VjtA*<)FjQLELCVTKuIhzRX=d(Ls3g|OoN1+~ztDE&%C@c;k-07*qoM6N<$
Eg5WSa$^ZZW
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..16a670e49d84bf9b2efb36353c3b2d2a6999bf7e
GIT binary patch
literal 668
zc$@*80%QG&P)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UAX9CpFK@CFTGC0x3yE
zK~z}7?O45w6G0q(GiDdAvamTDK`a!(I}mNf4^|Kqto#5^P^+^E1VS_ua)}#GxFIn6
z7g&fOT3A@g7M@@w2nV)eVP|o|fgp*OeKr#a%jJ^I?Pi;OFtE(bZ+P?O_c1#HQ=;4L
zUL^Su$?#7~dAL%k{GHZ7CRqFqlEVRTJBfjqW|G#r1z-)cVHdzkwOW0hib4k@0{|re
zFSXW>rkQ+b5*d;QAv3!18=mL=4#V)vOoUP-GwL4KJkRTgVfZ=mkwsCoMiLpc^|YdF
zE+~x~AejrHLZL#TTofYN2Jn8&@F$X&0PLhnXrDaNR!X%<-X(b=-UfrgWu??6$(tnm
zd##bCLT#l~%YGjrc~%Iqt(5vf(jj?4O1S_4N~ui%4*@U}g<@n7MbSL~Z%0hd0C)l5
z{IEkQ^@`+^Bnpjn>PDln@6|*IaTEX?$62ucQnDLajIFZ)U?cOeANohH*Sqigz9jj;
z?tV9uu%B4Eh4^NVzz1*zz*Vc*RxXKAO8E}J9{}!<41lk-TJ3u-gzEMB4oN-YtR(p~
z*U}+`=nNC25Tem+HpAR&kMH}k)9IW<fdU0GLJ$P5F=jc<pSPKzwO({x_XB_>0B-=S
zl*{FQF10KO0@o(RCEIliz&3!#xnydR&q$t&-E~%tG1upQWX71&0JiM=Pn_salBbe9
zQl+8L^S#K}ns!V|xjHw6j4{h3C*65|kvu+&O8)`LK7Y0NE}ORi0000<MNUMnLSTZ2
CLLYVj
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3e04a099fd23dc59557ceeb61baa1c46db4fe5e5
GIT binary patch
literal 716
zc$@*u0yF)IP)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UAX9DkF}u?)m@#0$E8!
zK~z}7?N&W#6hRn$-*C6&8dF#pEd)_e1QQSiZNwk2vd|(C@dvb#NFZTTY`i&+#63<o
zN6xv<&dNp$K`XKF>}-U9tyrWJxgsJQmza4rd$26GhQ!-ji+ixJd>=EsdGo&S8$kks
zARtnL=XsKpQ~1x2OG=Q;gwRl-p+cD`L~;qh+l2H-k{1B1_mvRIq;E-Uy-4x~$;0t)
zYisMG*1AdZD#?vrd-PMGC9U;h_`jFrNfBvjt-q1XlRT%CDgc1ix(VPO0H&f)j0~)`
zw*b6~EI9$-Ie^pMfY$m2$%UOLlxXTwsU&|}C?fj-AfL|{Lcip~gN()YSq8A2df9jV
z(dl&V_`a`5-VIOxJC(BE4kGd;yaFG<B><O0#a1(Ej7q830Db{*x?})+_B`)vCWMN`
z;yTG%#H=LwFw@Z?B9(4~6p>Q7Tz;SV?D2hHRVtOE7-EPaQbMEAaEvh%{n}6dWpS-m
z8*?1z9e{BFF9F=1ot@ptWR^7=4JT}h<6&qDKnuWwOgc5mM<h?h-a6C9m@5OnGGokf
z0ILA<J&3N6Jm$J?dyon}?nNe?X$O^3(*sk;7&Ad~yEo5wl81JqlG=rLW@4cqA`$?I
zR@XiN*Hgc;YPC9Qt-TpFvbA<<Zf<VDTDur~$lp($(8$QhH4!O9LT~2h=bNE-jEJm7
za%X}dIFc$Ml9RDAf7;EtuG_ZOK8xmax!h!GrmolP1(GcQU4_~Jo&Y!iU=M(w05$>4
yL@Mr+>$+!CA+)lxa-QUe9Ugd7DK)y2YWo8b=X8xV&w3L80000<MNUMnLSTYF^E<@=
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..054193ec1b0478c2ef6a01ba86b6db253e2251a6
GIT binary patch
literal 813
zc$@((1JeA7P)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UAX9DlYH<l1Bgl0=h{=
zK~z}7?N~i%Q&AND&NT_mVh0DSgCGiuU<;z4i}*tXK|zOBMJuR-R0=Jxl-AtPrY1zw
zN9)Vx<{*OTAm}7-u!4gKLcvuWx`|Y%2&HLzKbIGHJest5udi8p;6k`3=j6NJ`OdkQ
z2<lj=R3c)sY&I+Pd@4*rk`n;l*KvO$c^1GznB1ztkJeigTI)Q?8zc_|*Xru(Ij!{!
z$txtQYvl+9sE$o&t@GaJT_lf*$h_A2C&?tq(@Lo{0BEge0Ne$@SQrX`fidP5fH%I7
zqX3=*I8ocsTE8SY+6+U9dX8K!CyfF{WDfu&lgYHFmxOnajzFGC0F#j!+JLaDB(b!#
zbh}U}D3W)))2~G7z(m+U5&7<wpa9@JfD0aDvrzzrW=JXZ7QjCMsTvpn-$q78ezXKo
zHk(}_Y5T-Vk`JQ}O%)|rM2fWmDI&SCu`w5|wnCwxipAm~Y}>YNTTE7|R8o%PbZu5X
zi4ttvc1J3e`T(F4z-s`#0|NuqmfU5PN+snD#ZGUl2f#dl2Q8V@Bp;DH9(e2YIgWE_
z%S+}s&Jh5!0Fr9}og;bJvaH3eWa#l)V7xnRpHixC%NTMTr;FrzZ=PQy_lIFgh0soa
zVC%PtlmYm=Yd3&vv6rk=DzzJ9Zu*66jOiI192_;q<O2`+`>_LRYiqkIB5B{&yP=_>
z8BaToh|KwXC(GsX!B_#2><+Z~)0)q+tVLtYGrvEPNOZ?0>gnm}G|71YHHH=eJOQv5
zz)k>v0W1UP_jTMC%d$?z0%&S#>I}(`O&)kzDb?Ogw>49;>mf9nY_{7r#E@;<c>v=f
zXWa^b-r?clSDV66L@>1r{Dp1X_crq79qWN183m00;FmL*%pccvzlH*|iD3NlxR}Xg
rs;=vPZn|W~nDGXGT18o<MyUS-xhv9^2RRlm00000NkvXXu0mjf(Dr8H
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a60c7244c2e4efa29934b7e1d9cf16f3020039ea
GIT binary patch
literal 670
zc$@*A0%84$P)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UAX9Dmio07k~f&0xL;G
zK~z}7?Uz4j6Hy$;Kku1@bg`r2AP9ou&@K+T333I&4i2e;baIeNA>l%ZhL9F7M8lc*
zvbnp62!akGH|XFXf>3aE>LyY_5dy8epMw`TLb1(VE?M%0gX8z^_v8D%zd!GtA|^b~
z>j17&swyInfH%OBQmRm|*I&eqn~CeFl=>nfh=>PV29^M_+3Xexpkq5~{Sx>M<OXDb
z&(&)6>r@EUYPFvt;)g0B|8S3l&`F$?Qcd7>_+D=`8UfRW=Xtu>Y@T6;8D>Zcy<RV8
zj9DC4Je9=R_x<C!T<$Hf06Yg)i^bw@l9-t!%7jC4AvCQ3JHVZ(OllFiFCyn7M+YLZ
zW{kNy@st^3&H-CMb|0eKB68Ms-TovMdaxgv@Ju_YwO*T;LdKXy5jp72^G!rf#ZgJe
zsGap8(|4s*8;Ew-G2nXYDQmS_^VZs%(L%P?u9QlpyVlyxs2#YSI-z_%e@!Vh7cspm
zm&@<N+A&J0?a11NcDsE#RYD?C7;5v!gEiN6`_|eg(e+FwQ%J3-yWQ@bi0l9Zh5Eol
z-~@0K_yz0%>yeK8=(_I3R0wrCol7F}Zp01mX|3l+>9$c)b|XfOW=HL|Ln-9@{wA;y
zbJqO<Rx6dtv#}_Ykj&r!f9m`Gt;2kL<RCI4l7vij<I9fY{0M^JQ!GMbBoi%<D~{vr
z20`#)<dj)!H-=`;xSm#Of39gD^Pj0a6+$zGW(p<6U+b<vY@@;Nf&c&j07*qoM6N<$
Ef?a1aF#rGn
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8296b2a7cc96ef63c3cce3d9d6de68ac738cca54
GIT binary patch
literal 727
zc$@*(0x127P)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UAX9D+oIlCi?&Y0%S=<
zK~z}7?U%o6Q&AMhKlho0X0d~V)j<#)M9_jL=prg)5EOK1RkVUSNTty7N<p}VrWT^<
zqxE%ja}Ysv(@8Q|!9kq*7dUhish~?~+TO3r3p_(?o4mYq$$<-xbARwX-}61^-3wjo
zTG#%yg@uJ&7>51rI?p8890WmME|>cVoCMwiL!+ak)g)(Tk}v~&h`<000xQ6yB!IkD
zH%fXU>9izbV>k@MD;-Z+7>37zB_P`X=(40^zVEMglA))KzyKIy4tbt8+%bm2FzlDK
zw9T>~k`A}RlGlQEM(SKYjWJ~)US0cv8>y$PR4Vm4=WfS^?3^1M8ykD<oGZrtz{Au5
z_4M>yH^$^+uJ_~P<BO4YLSxKwZ0>BiTt1pAAV~vtW&XT2=llMubM8faK9k7|q$cY5
z`T4x06`;n@D)0<A2<!#^0PDa=tm3}<zJD$iKy!0*7bJaZGT?R3^Lm@9wq{axvjvT2
zo2|ATF%$$r5twSR*KGhp6B83}+QLvmFts1}s~`v->}2tt?Z8M%0wx~#)k2~0t5T_a
zYY9*r!NlcpxlkxnE0xNZrc>seo2u(M?HZ+2?n7x=W{a-8D}cHTbs5?fh9pf#PoPHj
zS<*$|cUu8%(MP7OwM9v{Bps<Ao12@LthI}hu1TskI-{KoO<QY=(f2+{r;ITx*4poq
zvXahwo|gx()-D3~0j0uF9T=Q*cYt@XEhm7Nz?quETKihk<7OE8uc#*{C%3$s7-J3q
zWV6|Pq?b$-NMGGKv%qX8p3+rGtgWrxotc^OB;AXm-$+tre*rKzuUFH_Cz1dF002ov
JPDHLkV1m&EN1*@!
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7a96ab4431e36a36a025728a3e7be5be3e1dfe85
GIT binary patch
literal 541
zc$@(p0^<FNP)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UAX63n-AYG!y^;0jfzv
zK~z}7?U*}D13?sp&ulFG17asyNUZF{PRs+rCl;}?6&sO&5ZK|e5duSyU=gtPH`rK(
zB(_Ouny8S<LP@2ii5wd%*_dQE8x{A!Haic#J#**IodrVuF)6PDi^XCSK(t5mT{@j!
z@G`IE<71*8+rHI=*MTGhSu*Rl#Zc%_=uqg;zjNr<0lA)Kg+k#3!1)+f=rohb<oY^9
z@@^dQ(&=<=zrKsObu5)i56NV58o*M3JZD<#i-BW^<S~F50Gk28T-vs654G)W+kPjx
z51=t(m}>xso(r^mK0imYrj(i*0ZawJy4L#5SH)<ISyoEj0GRZVChC@Dt!b@ad}nGA
zsR20f;mkdNt$r{)cbS{Y<#Hn)k1GJHL&7`)SP_w@K{`i<3V=%GCXq<Y16Uj=>nha-
z5EqeFV23No0|0fB=<~di+!m2$;MX8y%oNEwfY~0<T>u-7<CMlyeuzk$<PLyW7iYSb
zW$k%^@l_8wj?*BS0?_^9&XI^*d7U@nC(Bi<)mAJPdsa$qf5PZ&He3AhDleDIrHnDV
f;h%|6p<MI<toFqng(5WR00000NkvXXu0mjfwCLu!
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..18883c7ee2c68894829a2c04bce138e24e3e5587
GIT binary patch
literal 539
zc$@(n0_6RPP)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UAX63=ewv7q|cb0jNnt
zK~z}7?Uy@C13?sp&ulFG17asyNUZF{PRs+rCl*@S1{;xp5ZK|e5f+9Z!D7MM-(X`E
zlGrAtX^euEg<_?pi5wd%Nldbv4MF$7HajzyZ_nJha~BwbT-V(*#_S?eq)3tefRx{b
zp6A^Gh<6!oX0zD^KXI)99~1XE_NylRE+iSsmRaMLLy<#~Ly<%O&Y`gb>UftGi^UTF
z=Ofsm(_Aj+_H>A3a}@c~YPD{EzKeC5SSpns(&_XxfTa+5&a~DSediF#V*oP%Hba29
zv~AlS=-At~{YmlwKx4=-*8mQEH)w@IVUA=?DK#|&m<oV(t@THsj?oyitdzO|Fd3js
z)Gf<e(^|g;uGAt@1CR;e%sqguUNBuxStpgt<wi1@Q~*{7gn0t6A|lWIOpXnd0F}y3
zDwUcCu-I4CRq7Q$QbZm@yIe_T0MtpM$Ma5dTSV?c{|z$6Op&YunC$}H2C(5cPH80V
zhlsqA+yU_3!I`#YS^Iuq0`)_V<1|R_0cihl=SW1Z{Kkz1sdCk7^)Zo1yeOr%zhQJf
dpZ9{q`~sCk#T`&IznB03002ovPDHLkV1i&h<%R$N
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..280061683950aeab528852f52af185b7cf579b7b
GIT binary patch
literal 562
zc$@(;0?qx2P)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UAX63>}F<X7B(20l!H^
zK~z}7?U*}j8$lFC&x}*#4;XhLDNItO3&u@|9vJd)NMToQjT;jL0l^NJm4jdqMx+p=
z&TmMQN=R~Rl~&^ixKd%`DlQ|1n<iDTt({#<F?c_iYVO=U^Ud9v*);^nd;b~OAxuMH
zSwx0Og6Bdqce~xaQmM2EJWmpDjJW`cB66Da88&dXsOl!rS5+poOI2MJk;9Puh7|JN
z&#P)5czg}?7<d!MaXU1(O#>t%7pnRmxV*xdv9)$R4NPhvfH;l^s=5Y@|8ZwqM82oZ
zJ4XifdcD&^p>S@DS^W#+YPDL6|E+qxzUICEK(1W5a)ryJ9oTBM4uPlFbRShJm1i?O
zI&OfO)OVvEq#dZLQ&}>5*J>ztD0e7#=-xSW=YXy}%bLyRC*aErR%oYMt=1<xq^d`=
zsF%@bbdcyXsNHU#l*{D>;KdYqcAaxy6W5Tcegqx?Z>IqBEsCNj=(Ufc=(nnF0E1hG
z`2lRDzMwT4jVG$QZ;YA01(+`I+Bx?t(~Z%4zhsQr10H7BCi>Re73bW~%saJ+>;sz_
zoH+*GO@ayf+0f~92E}600IvdJhQLb^IZG1!2Qp&I9?g;FxBvhE07*qoM6N<$f^D<$
AfB*mh
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0de0fed59472b4c13522e2d9ee129b8ab794b646
GIT binary patch
literal 553
zc$@(#0@nSBP)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UAX63@b+a^JxG80k%m*
zK~z}7?Uz4mQ&AYkf9J%(FHl_VQ0n9+ZespWuv&4blcUAOAs__q;pL_fI3y)>2sry0
zbZ`nux;CR(T7^yyN+&y-$m`-%a&vD^(pdC9aF+Z2xj&xsa?ZVm1hrbN0`LKN%<}av
zilUd(0ye24ilSet`T`g&8RjGKDk*5vs+-N`x~d)<W7d`c(+3_o=Y9qQ0eJ848)J@u
zo1rACI<(eqIp==N%ClLTiO4aqw}3OBfhTD&0EMg_d%fPMR4N(Z;hZpEfd?Y;ElYA?
zt^w%xkILop25>h^zA@$;D2d2f)_2%|S=a-Hs!GbbP}Lm~Ihm)w2^k3Q{hF!{f!hht
z6JR@z<L<n@Z3vKvoU7_n;9`n16Kn1B5SU;ffH;mvs=5nIF1hnsMBaz?Ei7`%4F-d=
zVzKz$7_;*S#?|Zf4u4yXMq}4||BPI@a^?C5WI_u&oz4lcnGim$R;zbbdY8?BNsG<Y
zjRn4uuVl;Yb(^8wq1>U|q5saIYX>y-E^D{jZ-B!U?9hI#R%@g>q^hT@n3wT*{3+9a
rS-0E$QmIsK0r#$u=fFAl_VUBueM`g1P>{Tv00000NkvXXu0mjfDb)Q{
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..857eab2a4af40d15563468a6d1e9bcc7863b92e4
GIT binary patch
literal 562
zc$@(;0?qx2P)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UAX63^>9?vbO*L0l!H^
zK~z}7?Uy@i8$lF>zZs?QA29AhQUs?;7u*@^K_GS<QaDvw<HiI*gkXouDj-;d5h?_(
z^BdBn5|Z3nrPbImxJr@W$}S^?n<hmtD`_>d{9+Gmv-i%OkHgs+*5Ii|qoL#KrBccG
z%zfkwq^itAcMd4l)_T4E31~2XeJ+>F)rk(N>d6hjFc=JuuD;8}HMUx<(?X%J1iYLh
z&z^H`KXHas^&{{Y*q8&%mmmm&xPl$EA_#&%s`>%wUo*@%U}vgO|F2rD_Ec35jWLVY
z0Mh|pJLi6T0|7))v|@}o02XFACVJM|SI)VMaeX$)FcCQfwr6nWJMd-_%*d}SPVIKP
zpUdS8ur?*k4`5Y9ekN(oOcj7m=OCZYKLcJQI(3aX2XZ2EmUIv6k%eubr>abNE>(3?
zM2=^^Iue9@QB`}ulM&EEU_A`O*0i&&50HqQtLj_eGRB#qwf4Oaj5iQK7>0dS-2#SJ
z+}Rb8ufB6Lvz&6>Zucyk&HggRZ2p6Bl}e?_ZL3<XZbeb_j#Q~qrFsA|z6+bp<}t85
zqI^;;7N6hfT{Z@0Qtf{IO53}Zq12(&p$F&CUnrZ&9FS>0ng9R*07*qoM6N<$g6ZP%
A*8l(j
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..cf3aa8bb65a35e2e38448a1308b993f12d5ca44f
GIT binary patch
literal 556
zc$@(&0@MA8P)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UAX64GD^XgUkQ`0l7&;
zK~z}7?U%i4Q&AYkf9J-*f1tRD4pJvKaVzEn!H<eVow^p6A_+p^9$s#Qz$Hi!5^(l!
zaB&Jrx;A68v<jUZlumXuk;lbBN@9|Gn^?<z;4bGq=kVjX?|ILA90}EGwe+`mrBZQ8
z_Pvr6ND|9Xzy(w0Q0CC3bLheWO)Or`X7d&Bb_IXvb+uZp&vZ!A(JJy~G#VY89m`Fc
z*y(gWmrA8;z}+SCyz$<@n>&Xjy#%fUkCy=RJ`BTfp<^G0;ZI51!0?=5J_0WmO6ot=
zXf$q0+IP;aodZk{c<8<Vkr)Udj^lgIxjo=&iZU?>g5ZJo{(I_5ZD#wxP6}r}0Z(SZ
zOg&|j)a`bMg+jpr_ZNiu0&JMs*Lf!A7D|9#Z?9M^-U9B-Rdt;^0SabzytK<z(he|?
z#EkD$(x#amroKAnNb)sF1K`FK=rQmpilWX++7B~3k@OTeo#4zk2!iKHU{du%Q4|d&
zZ2{vm?(CY`hot-F(p0&Azki(1=f64UHh;tTTCLXp=UraCUf+u2_!*fpWy*93<dQCI
ux7&xn`jqfdxm>=z>bL!R!r1@yl>P;4oyi>H_T-}g0000<MNUMnLSTZnr~kG9
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..da1ff4ddcdb68da59ecfcfd17df4038b4591fec7
GIT binary patch
literal 803
zc$@(v1Kj+HP)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UAX9Cm^C0!3_Wa0<cL$
zK~z}7?U+Ak6hRcmzc=0;xyBS0Mhig{6hQ-`ppE#469fe<5*3Z077__0YzT>&Be}T8
z>19dWbaoaZh!%oYvV{>WL=XbDVv$ZHLPQ9;B=gzq!E&5Q?soUK$-uxdvorkWd*6Gr
zdqBuGGc%KMUAGevH3_rWah#4!Ci5P^5dg0M^z`@lSHkR>3Zo2wcRmaNbOTrba6b%?
zYIY&Xha``YM4<P&u6wcNA#+{#5P&%V={lhEBoA7awbV+59@T>Z01?@vl<IAnLays}
zlAPP%v7aROHlvbi!aIF6L%&3%3?P_YI{{pcJ!GX)sofZJBWPq}O!vURz=$!X5F7_^
zFLt1|wzexGk_`;K9UL5-^}XYY$b4Y#M7dnvA1e^au9`G|Qk}CbYsnb%G&rA1rMhA>
z_4M>~mgE9}szOTu9s}47U^{?609F9>1v2ilWmzX<0h*ecI!*FJg9lzwO0_qVZH<KN
zS`!{kH=1pmQpj<f0)X)*Yuze<o}r<kmyswG5~g~AKX)AG?q(j|wh;`;FfhS`U&`fj
zzdg_U(iBjHFhP4<$mMbs&+|St95Q3fcumcTs+VGUABwA`)~U*g0BtF>rBEUYk(}^9
zf$Fu7B+md?j1*{{Ix?ZPE|9!Va$jv<TU$G;wVow;nPjEj9#JYZp|vjfzju&4Dk2M7
z>mMZ3Bu^=&vH+m9o&|6R0Ao?81_s8Mn*d%1mK+A~48ZZ~fY$m2$&p4B`md?;`TV-C
zCL*#60MhAn*7r-wKS)Q-K9c|@Tk$DfA&KSX<y*FGE0VYU)2}A-XM>1*^Fv?*I0xXo
zuh?87g;6Q>2EbncnJNr`ufxN`-xC2E9UWaH=>*J5k`EHSIz*&cEs!FT9~&F<62E(F
h+g8P5@jz7j{R1|(*PiCCuG#<q002ovPDHLkV1g=uRB8YK
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..adbadcd4b8c77bd0510d5dc0db47c4470b3f8c32
GIT binary patch
literal 722
zc$@*!0xkWCP)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UAX9Co46?7=-`;0$)i)
zK~z}7?N&R86HydBcTAR~aSIDSohVqzf*@!ke#nA_pvC&Z52%HWMVJt>=7ns+gkW|^
zoOE^;A_x|OmQ%Qbg$TletytKJtgs@4WH;~FWMl|#lF806O%6O5?tSla?s@m!JA#04
z9A|;#`j~A$NFFv#vlBGF5%d7bheM{HBGLfR^V#+TxP~bZh)}&=pVwO7BnfY6t*>UY
z*=4PD#cv1jAaX*fRO*U|q<yA0xm<1y07S$Qk?%g=sYau5G*Ut&m;5S_eB${`)9h%i
zpZfiYL}Do@A(?bztJO-A+yLMy)B*4qz##y80sIEA1>j$eiO5IOG*3rDsM&0uCHXF3
z!dr%6%m;aGL9Xoj6g8R*`r0N^$hPeYfE7%KZ2-6P`TWaJ6xt;j07w9MZrk?#NjC2p
zM~38X$oLb#l*wd%xvu+ZDncQW@t4QNOeWKFUH3!aE7Mx94E3C_Rz1{N7Bvzhx^gUp
zW(v&|ibWxkRRC{yaK9&c4!~xpghup{s#2;#@&?Hx!>ix#pI1t)k-SW@_rDlnDpXZU
zRR-VtNS+Xp4W-mKl1Y+h48uqRfKqA=z&!wrM4=%v&|2RD@XB}OIDlsWPI?BV)C-c!
zK@{4ts7s~N$X^o?IS2sBWHLRdm&72E14D6E0jx&;?7jNvcDr{h%Q8sb9b~^9$+I6j
zx<$SWuD}9t0l?xwvGrIQqhT1Y0sH|l=aB*Mxlky4jfGILSllFO`-+t$AH_O4M5N|5
zND(QO%VjtA*<)FjQLELCVTKuIhzRX=d(Ls3g|OoN1+~ztDE&%C@c;k-07*qoM6N<$
Eg5WSa$^ZZW
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..16a670e49d84bf9b2efb36353c3b2d2a6999bf7e
GIT binary patch
literal 668
zc$@*80%QG&P)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UAX9CpFK@CFTGC0x3yE
zK~z}7?O45w6G0q(GiDdAvamTDK`a!(I}mNf4^|Kqto#5^P^+^E1VS_ua)}#GxFIn6
z7g&fOT3A@g7M@@w2nV)eVP|o|fgp*OeKr#a%jJ^I?Pi;OFtE(bZ+P?O_c1#HQ=;4L
zUL^Su$?#7~dAL%k{GHZ7CRqFqlEVRTJBfjqW|G#r1z-)cVHdzkwOW0hib4k@0{|re
zFSXW>rkQ+b5*d;QAv3!18=mL=4#V)vOoUP-GwL4KJkRTgVfZ=mkwsCoMiLpc^|YdF
zE+~x~AejrHLZL#TTofYN2Jn8&@F$X&0PLhnXrDaNR!X%<-X(b=-UfrgWu??6$(tnm
zd##bCLT#l~%YGjrc~%Iqt(5vf(jj?4O1S_4N~ui%4*@U}g<@n7MbSL~Z%0hd0C)l5
z{IEkQ^@`+^Bnpjn>PDln@6|*IaTEX?$62ucQnDLajIFZ)U?cOeANohH*Sqigz9jj;
z?tV9uu%B4Eh4^NVzz1*zz*Vc*RxXKAO8E}J9{}!<41lk-TJ3u-gzEMB4oN-YtR(p~
z*U}+`=nNC25Tem+HpAR&kMH}k)9IW<fdU0GLJ$P5F=jc<pSPKzwO({x_XB_>0B-=S
zl*{FQF10KO0@o(RCEIliz&3!#xnydR&q$t&-E~%tG1upQWX71&0JiM=Pn_salBbe9
zQl+8L^S#K}ns!V|xjHw6j4{h3C*65|kvu+&O8)`LK7Y0NE}ORi0000<MNUMnLSTZ2
CLLYVj
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3e04a099fd23dc59557ceeb61baa1c46db4fe5e5
GIT binary patch
literal 716
zc$@*u0yF)IP)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UAX9DkF}u?)m@#0$E8!
zK~z}7?N&W#6hRn$-*C6&8dF#pEd)_e1QQSiZNwk2vd|(C@dvb#NFZTTY`i&+#63<o
zN6xv<&dNp$K`XKF>}-U9tyrWJxgsJQmza4rd$26GhQ!-ji+ixJd>=EsdGo&S8$kks
zARtnL=XsKpQ~1x2OG=Q;gwRl-p+cD`L~;qh+l2H-k{1B1_mvRIq;E-Uy-4x~$;0t)
zYisMG*1AdZD#?vrd-PMGC9U;h_`jFrNfBvjt-q1XlRT%CDgc1ix(VPO0H&f)j0~)`
zw*b6~EI9$-Ie^pMfY$m2$%UOLlxXTwsU&|}C?fj-AfL|{Lcip~gN()YSq8A2df9jV
z(dl&V_`a`5-VIOxJC(BE4kGd;yaFG<B><O0#a1(Ej7q830Db{*x?})+_B`)vCWMN`
z;yTG%#H=LwFw@Z?B9(4~6p>Q7Tz;SV?D2hHRVtOE7-EPaQbMEAaEvh%{n}6dWpS-m
z8*?1z9e{BFF9F=1ot@ptWR^7=4JT}h<6&qDKnuWwOgc5mM<h?h-a6C9m@5OnGGokf
z0ILA<J&3N6Jm$J?dyon}?nNe?X$O^3(*sk;7&Ad~yEo5wl81JqlG=rLW@4cqA`$?I
zR@XiN*Hgc;YPC9Qt-TpFvbA<<Zf<VDTDur~$lp($(8$QhH4!O9LT~2h=bNE-jEJm7
za%X}dIFc$Ml9RDAf7;EtuG_ZOK8xmax!h!GrmolP1(GcQU4_~Jo&Y!iU=M(w05$>4
yL@Mr+>$+!CA+)lxa-QUe9Ugd7DK)y2YWo8b=X8xV&w3L80000<MNUMnLSTYF^E<@=
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..054193ec1b0478c2ef6a01ba86b6db253e2251a6
GIT binary patch
literal 813
zc$@((1JeA7P)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UAX9DlYH<l1Bgl0=h{=
zK~z}7?N~i%Q&AND&NT_mVh0DSgCGiuU<;z4i}*tXK|zOBMJuR-R0=Jxl-AtPrY1zw
zN9)Vx<{*OTAm}7-u!4gKLcvuWx`|Y%2&HLzKbIGHJest5udi8p;6k`3=j6NJ`OdkQ
z2<lj=R3c)sY&I+Pd@4*rk`n;l*KvO$c^1GznB1ztkJeigTI)Q?8zc_|*Xru(Ij!{!
z$txtQYvl+9sE$o&t@GaJT_lf*$h_A2C&?tq(@Lo{0BEge0Ne$@SQrX`fidP5fH%I7
zqX3=*I8ocsTE8SY+6+U9dX8K!CyfF{WDfu&lgYHFmxOnajzFGC0F#j!+JLaDB(b!#
zbh}U}D3W)))2~G7z(m+U5&7<wpa9@JfD0aDvrzzrW=JXZ7QjCMsTvpn-$q78ezXKo
zHk(}_Y5T-Vk`JQ}O%)|rM2fWmDI&SCu`w5|wnCwxipAm~Y}>YNTTE7|R8o%PbZu5X
zi4ttvc1J3e`T(F4z-s`#0|NuqmfU5PN+snD#ZGUl2f#dl2Q8V@Bp;DH9(e2YIgWE_
z%S+}s&Jh5!0Fr9}og;bJvaH3eWa#l)V7xnRpHixC%NTMTr;FrzZ=PQy_lIFgh0soa
zVC%PtlmYm=Yd3&vv6rk=DzzJ9Zu*66jOiI192_;q<O2`+`>_LRYiqkIB5B{&yP=_>
z8BaToh|KwXC(GsX!B_#2><+Z~)0)q+tVLtYGrvEPNOZ?0>gnm}G|71YHHH=eJOQv5
zz)k>v0W1UP_jTMC%d$?z0%&S#>I}(`O&)kzDb?Ogw>49;>mf9nY_{7r#E@;<c>v=f
zXWa^b-r?clSDV66L@>1r{Dp1X_crq79qWN183m00;FmL*%pccvzlH*|iD3NlxR}Xg
rs;=vPZn|W~nDGXGT18o<MyUS-xhv9^2RRlm00000NkvXXu0mjf(Dr8H
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a60c7244c2e4efa29934b7e1d9cf16f3020039ea
GIT binary patch
literal 670
zc$@*A0%84$P)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UAX9Dmio07k~f&0xL;G
zK~z}7?Uz4j6Hy$;Kku1@bg`r2AP9ou&@K+T333I&4i2e;baIeNA>l%ZhL9F7M8lc*
zvbnp62!akGH|XFXf>3aE>LyY_5dy8epMw`TLb1(VE?M%0gX8z^_v8D%zd!GtA|^b~
z>j17&swyInfH%OBQmRm|*I&eqn~CeFl=>nfh=>PV29^M_+3Xexpkq5~{Sx>M<OXDb
z&(&)6>r@EUYPFvt;)g0B|8S3l&`F$?Qcd7>_+D=`8UfRW=Xtu>Y@T6;8D>Zcy<RV8
zj9DC4Je9=R_x<C!T<$Hf06Yg)i^bw@l9-t!%7jC4AvCQ3JHVZ(OllFiFCyn7M+YLZ
zW{kNy@st^3&H-CMb|0eKB68Ms-TovMdaxgv@Ju_YwO*T;LdKXy5jp72^G!rf#ZgJe
zsGap8(|4s*8;Ew-G2nXYDQmS_^VZs%(L%P?u9QlpyVlyxs2#YSI-z_%e@!Vh7cspm
zm&@<N+A&J0?a11NcDsE#RYD?C7;5v!gEiN6`_|eg(e+FwQ%J3-yWQ@bi0l9Zh5Eol
z-~@0K_yz0%>yeK8=(_I3R0wrCol7F}Zp01mX|3l+>9$c)b|XfOW=HL|Ln-9@{wA;y
zbJqO<Rx6dtv#}_Ykj&r!f9m`Gt;2kL<RCI4l7vij<I9fY{0M^JQ!GMbBoi%<D~{vr
z20`#)<dj)!H-=`;xSm#Of39gD^Pj0a6+$zGW(p<6U+b<vY@@;Nf&c&j07*qoM6N<$
Ef?a1aF#rGn
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8296b2a7cc96ef63c3cce3d9d6de68ac738cca54
GIT binary patch
literal 727
zc$@*(0x127P)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UAX9D+oIlCi?&Y0%S=<
zK~z}7?U%o6Q&AMhKlho0X0d~V)j<#)M9_jL=prg)5EOK1RkVUSNTty7N<p}VrWT^<
zqxE%ja}Ysv(@8Q|!9kq*7dUhish~?~+TO3r3p_(?o4mYq$$<-xbARwX-}61^-3wjo
zTG#%yg@uJ&7>51rI?p8890WmME|>cVoCMwiL!+ak)g)(Tk}v~&h`<000xQ6yB!IkD
zH%fXU>9izbV>k@MD;-Z+7>37zB_P`X=(40^zVEMglA))KzyKIy4tbt8+%bm2FzlDK
zw9T>~k`A}RlGlQEM(SKYjWJ~)US0cv8>y$PR4Vm4=WfS^?3^1M8ykD<oGZrtz{Au5
z_4M>yH^$^+uJ_~P<BO4YLSxKwZ0>BiTt1pAAV~vtW&XT2=llMubM8faK9k7|q$cY5
z`T4x06`;n@D)0<A2<!#^0PDa=tm3}<zJD$iKy!0*7bJaZGT?R3^Lm@9wq{axvjvT2
zo2|ATF%$$r5twSR*KGhp6B83}+QLvmFts1}s~`v->}2tt?Z8M%0wx~#)k2~0t5T_a
zYY9*r!NlcpxlkxnE0xNZrc>seo2u(M?HZ+2?n7x=W{a-8D}cHTbs5?fh9pf#PoPHj
zS<*$|cUu8%(MP7OwM9v{Bps<Ao12@LthI}hu1TskI-{KoO<QY=(f2+{r;ITx*4poq
zvXahwo|gx()-D3~0j0uF9T=Q*cYt@XEhm7Nz?quETKihk<7OE8uc#*{C%3$s7-J3q
zWV6|Pq?b$-NMGGKv%qX8p3+rGtgWrxotc^OB;AXm-$+tre*rKzuUFH_Cz1dF002ov
JPDHLkV1m&EN1*@!
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7a96ab4431e36a36a025728a3e7be5be3e1dfe85
GIT binary patch
literal 541
zc$@(p0^<FNP)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UAX63n-AYG!y^;0jfzv
zK~z}7?U*}D13?sp&ulFG17asyNUZF{PRs+rCl;}?6&sO&5ZK|e5duSyU=gtPH`rK(
zB(_Ouny8S<LP@2ii5wd%*_dQE8x{A!Haic#J#**IodrVuF)6PDi^XCSK(t5mT{@j!
z@G`IE<71*8+rHI=*MTGhSu*Rl#Zc%_=uqg;zjNr<0lA)Kg+k#3!1)+f=rohb<oY^9
z@@^dQ(&=<=zrKsObu5)i56NV58o*M3JZD<#i-BW^<S~F50Gk28T-vs654G)W+kPjx
z51=t(m}>xso(r^mK0imYrj(i*0ZawJy4L#5SH)<ISyoEj0GRZVChC@Dt!b@ad}nGA
zsR20f;mkdNt$r{)cbS{Y<#Hn)k1GJHL&7`)SP_w@K{`i<3V=%GCXq<Y16Uj=>nha-
z5EqeFV23No0|0fB=<~di+!m2$;MX8y%oNEwfY~0<T>u-7<CMlyeuzk$<PLyW7iYSb
zW$k%^@l_8wj?*BS0?_^9&XI^*d7U@nC(Bi<)mAJPdsa$qf5PZ&He3AhDleDIrHnDV
f;h%|6p<MI<toFqng(5WR00000NkvXXu0mjfwCLu!
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..18883c7ee2c68894829a2c04bce138e24e3e5587
GIT binary patch
literal 539
zc$@(n0_6RPP)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UAX63=ewv7q|cb0jNnt
zK~z}7?Uy@C13?sp&ulFG17asyNUZF{PRs+rCl*@S1{;xp5ZK|e5f+9Z!D7MM-(X`E
zlGrAtX^euEg<_?pi5wd%Nldbv4MF$7HajzyZ_nJha~BwbT-V(*#_S?eq)3tefRx{b
zp6A^Gh<6!oX0zD^KXI)99~1XE_NylRE+iSsmRaMLLy<#~Ly<%O&Y`gb>UftGi^UTF
z=Ofsm(_Aj+_H>A3a}@c~YPD{EzKeC5SSpns(&_XxfTa+5&a~DSediF#V*oP%Hba29
zv~AlS=-At~{YmlwKx4=-*8mQEH)w@IVUA=?DK#|&m<oV(t@THsj?oyitdzO|Fd3js
z)Gf<e(^|g;uGAt@1CR;e%sqguUNBuxStpgt<wi1@Q~*{7gn0t6A|lWIOpXnd0F}y3
zDwUcCu-I4CRq7Q$QbZm@yIe_T0MtpM$Ma5dTSV?c{|z$6Op&YunC$}H2C(5cPH80V
zhlsqA+yU_3!I`#YS^Iuq0`)_V<1|R_0cihl=SW1Z{Kkz1sdCk7^)Zo1yeOr%zhQJf
dpZ9{q`~sCk#T`&IznB03002ovPDHLkV1i&h<%R$N
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..280061683950aeab528852f52af185b7cf579b7b
GIT binary patch
literal 562
zc$@(;0?qx2P)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UAX63>}F<X7B(20l!H^
zK~z}7?U*}j8$lFC&x}*#4;XhLDNItO3&u@|9vJd)NMToQjT;jL0l^NJm4jdqMx+p=
z&TmMQN=R~Rl~&^ixKd%`DlQ|1n<iDTt({#<F?c_iYVO=U^Ud9v*);^nd;b~OAxuMH
zSwx0Og6Bdqce~xaQmM2EJWmpDjJW`cB66Da88&dXsOl!rS5+poOI2MJk;9Puh7|JN
z&#P)5czg}?7<d!MaXU1(O#>t%7pnRmxV*xdv9)$R4NPhvfH;l^s=5Y@|8ZwqM82oZ
zJ4XifdcD&^p>S@DS^W#+YPDL6|E+qxzUICEK(1W5a)ryJ9oTBM4uPlFbRShJm1i?O
zI&OfO)OVvEq#dZLQ&}>5*J>ztD0e7#=-xSW=YXy}%bLyRC*aErR%oYMt=1<xq^d`=
zsF%@bbdcyXsNHU#l*{D>;KdYqcAaxy6W5Tcegqx?Z>IqBEsCNj=(Ufc=(nnF0E1hG
z`2lRDzMwT4jVG$QZ;YA01(+`I+Bx?t(~Z%4zhsQr10H7BCi>Re73bW~%saJ+>;sz_
zoH+*GO@ayf+0f~92E}600IvdJhQLb^IZG1!2Qp&I9?g;FxBvhE07*qoM6N<$f^D<$
AfB*mh
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0de0fed59472b4c13522e2d9ee129b8ab794b646
GIT binary patch
literal 553
zc$@(#0@nSBP)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UAX63@b+a^JxG80k%m*
zK~z}7?Uz4mQ&AYkf9J%(FHl_VQ0n9+ZespWuv&4blcUAOAs__q;pL_fI3y)>2sry0
zbZ`nux;CR(T7^yyN+&y-$m`-%a&vD^(pdC9aF+Z2xj&xsa?ZVm1hrbN0`LKN%<}av
zilUd(0ye24ilSet`T`g&8RjGKDk*5vs+-N`x~d)<W7d`c(+3_o=Y9qQ0eJ848)J@u
zo1rACI<(eqIp==N%ClLTiO4aqw}3OBfhTD&0EMg_d%fPMR4N(Z;hZpEfd?Y;ElYA?
zt^w%xkILop25>h^zA@$;D2d2f)_2%|S=a-Hs!GbbP}Lm~Ihm)w2^k3Q{hF!{f!hht
z6JR@z<L<n@Z3vKvoU7_n;9`n16Kn1B5SU;ffH;mvs=5nIF1hnsMBaz?Ei7`%4F-d=
zVzKz$7_;*S#?|Zf4u4yXMq}4||BPI@a^?C5WI_u&oz4lcnGim$R;zbbdY8?BNsG<Y
zjRn4uuVl;Yb(^8wq1>U|q5saIYX>y-E^D{jZ-B!U?9hI#R%@g>q^hT@n3wT*{3+9a
rS-0E$QmIsK0r#$u=fFAl_VUBueM`g1P>{Tv00000NkvXXu0mjfDb)Q{
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..857eab2a4af40d15563468a6d1e9bcc7863b92e4
GIT binary patch
literal 562
zc$@(;0?qx2P)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UAX63^>9?vbO*L0l!H^
zK~z}7?Uy@i8$lF>zZs?QA29AhQUs?;7u*@^K_GS<QaDvw<HiI*gkXouDj-;d5h?_(
z^BdBn5|Z3nrPbImxJr@W$}S^?n<hmtD`_>d{9+Gmv-i%OkHgs+*5Ii|qoL#KrBccG
z%zfkwq^itAcMd4l)_T4E31~2XeJ+>F)rk(N>d6hjFc=JuuD;8}HMUx<(?X%J1iYLh
z&z^H`KXHas^&{{Y*q8&%mmmm&xPl$EA_#&%s`>%wUo*@%U}vgO|F2rD_Ec35jWLVY
z0Mh|pJLi6T0|7))v|@}o02XFACVJM|SI)VMaeX$)FcCQfwr6nWJMd-_%*d}SPVIKP
zpUdS8ur?*k4`5Y9ekN(oOcj7m=OCZYKLcJQI(3aX2XZ2EmUIv6k%eubr>abNE>(3?
zM2=^^Iue9@QB`}ulM&EEU_A`O*0i&&50HqQtLj_eGRB#qwf4Oaj5iQK7>0dS-2#SJ
z+}Rb8ufB6Lvz&6>Zucyk&HggRZ2p6Bl}e?_ZL3<XZbeb_j#Q~qrFsA|z6+bp<}t85
zqI^;;7N6hfT{Z@0Qtf{IO53}Zq12(&p$F&CUnrZ&9FS>0ng9R*07*qoM6N<$g6ZP%
A*8l(j
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..cf3aa8bb65a35e2e38448a1308b993f12d5ca44f
GIT binary patch
literal 556
zc$@(&0@MA8P)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-UAX64GD^XgUkQ`0l7&;
zK~z}7?U%i4Q&AYkf9J-*f1tRD4pJvKaVzEn!H<eVow^p6A_+p^9$s#Qz$Hi!5^(l!
zaB&Jrx;A68v<jUZlumXuk;lbBN@9|Gn^?<z;4bGq=kVjX?|ILA90}EGwe+`mrBZQ8
z_Pvr6ND|9Xzy(w0Q0CC3bLheWO)Or`X7d&Bb_IXvb+uZp&vZ!A(JJy~G#VY89m`Fc
z*y(gWmrA8;z}+SCyz$<@n>&Xjy#%fUkCy=RJ`BTfp<^G0;ZI51!0?=5J_0WmO6ot=
zXf$q0+IP;aodZk{c<8<Vkr)Udj^lgIxjo=&iZU?>g5ZJo{(I_5ZD#wxP6}r}0Z(SZ
zOg&|j)a`bMg+jpr_ZNiu0&JMs*Lf!A7D|9#Z?9M^-U9B-Rdt;^0SabzytK<z(he|?
z#EkD$(x#amroKAnNb)sF1K`FK=rQmpilWX++7B~3k@OTeo#4zk2!iKHU{du%Q4|d&
zZ2{vm?(CY`hot-F(p0&Azki(1=f64UHh;tTTCLXp=UraCUf+u2_!*fpWy*93<dQCI
ux7&xn`jqfdxm>=z>bL!R!r1@yl>P;4oyi>H_T-}g0000<MNUMnLSTZnr~kG9
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/resources/drawable/alert_app_animation.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+
+<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
+                android:oneshot="false">
+
+    <item android:drawable="@drawable/alert_app_animation_1" android:duration="150" />
+    <item android:drawable="@drawable/alert_app_animation_2" android:duration="150" />
+    <item android:drawable="@drawable/alert_app_animation_3" android:duration="150" />
+    <item android:drawable="@drawable/alert_app_animation_4" android:duration="150" />
+    <item android:drawable="@drawable/alert_app_animation_5" android:duration="150" />
+    <item android:drawable="@drawable/alert_app_animation_6" android:duration="150" />
+    <item android:drawable="@drawable/alert_app_animation_7" android:duration="150" />
+
+</animation-list>
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/resources/drawable/alert_download_animation.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+
+<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
+                android:oneshot="false">
+
+    <item android:drawable="@drawable/alert_download_animation_1" android:duration="150" />
+    <item android:drawable="@drawable/alert_download_animation_2" android:duration="150" />
+    <item android:drawable="@drawable/alert_download_animation_3" android:duration="150" />
+    <item android:drawable="@drawable/alert_download_animation_4" android:duration="150" />
+    <item android:drawable="@drawable/alert_download_animation_5" android:duration="150" />
+    <item android:drawable="@drawable/alert_download_animation_6" android:duration="150" />
+
+</animation-list>
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -4228,17 +4228,17 @@ Tab.prototype = {
   saveSessionZoom: function(aZoom) {
     let cwu = this.browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
     cwu.setResolution(aZoom / window.devicePixelRatio, aZoom / window.devicePixelRatio);
   },
 
   restoredSessionZoom: function() {
     let cwu = this.browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
 
-    if (this._restoreZoom && cwu.isHistoryRestored) {
+    if (this._restoreZoom && cwu.isResolutionSet) {
       return this._getGeckoZoom();
     }
     return null;
   },
 
   OnHistoryNewEntry: function(aUri) {
     this._sendHistoryEvent("New", { url: aUri.spec });
   },
--- a/mobile/android/locales/jar.mn
+++ b/mobile/android/locales/jar.mn
@@ -41,16 +41,17 @@
   locale/@AB_CD@/browser/webapp.properties        (%chrome/webapp.properties)
 #endif
 
 # overrides for toolkit l10n, also for en-US
 relativesrcdir toolkit/locales:
   locale/@AB_CD@/browser/overrides/about.dtd                       (%chrome/global/about.dtd)
   locale/@AB_CD@/browser/overrides/aboutAbout.dtd                  (%chrome/global/aboutAbout.dtd)
   locale/@AB_CD@/browser/overrides/aboutRights.dtd                 (%chrome/global/aboutRights.dtd)
+  locale/@AB_CD@/browser/overrides/charsetMenu.properties          (%chrome/global/charsetMenu.properties)
   locale/@AB_CD@/browser/overrides/commonDialogs.properties        (%chrome/global/commonDialogs.properties)
   locale/@AB_CD@/browser/overrides/intl.properties                 (%chrome/global/intl.properties)
   locale/@AB_CD@/browser/overrides/intl.css                        (%chrome/global/intl.css)
   locale/@AB_CD@/browser/overrides/passwordmgr.properties          (%chrome/passwordmgr/passwordmgr.properties)
   locale/@AB_CD@/browser/overrides/search/search.properties        (%chrome/search/search.properties)
   locale/@AB_CD@/browser/overrides/update/updates.properties       (%chrome/mozapps/update/updates.properties)
 # plugins
   locale/@AB_CD@/browser/overrides/plugins/plugins.dtd             (%chrome/mozapps/plugins/plugins.dtd)
@@ -65,16 +66,17 @@ relativesrcdir toolkit/locales:
   locale/@AB_CD@/browser/overrides/global/mozilla.dtd                (%chrome/global/mozilla.dtd)
 #about:telemetry
   locale/@AB_CD@/browser/overrides/global/aboutTelemetry.dtd         (%chrome/global/aboutTelemetry.dtd)
   locale/@AB_CD@/browser/overrides/global/aboutTelemetry.properties  (%chrome/global/aboutTelemetry.properties)
 
 % override chrome://global/locale/about.dtd chrome://browser/locale/overrides/about.dtd
 % override chrome://global/locale/aboutAbout.dtd chrome://browser/locale/overrides/aboutAbout.dtd
 % override chrome://global/locale/aboutRights.dtd chrome://browser/locale/overrides/aboutRights.dtd
+% override chrome://global/locale/charsetMenu.properties chrome://browser/locale/overrides/charsetMenu.properties
 % override chrome://global/locale/commonDialogs.properties chrome://browser/locale/overrides/commonDialogs.properties
 % override chrome://mozapps/locale/handling/handling.properties chrome://browser/locale/handling.properties
 % override chrome://global/locale/intl.properties chrome://browser/locale/overrides/intl.properties
 % override chrome://global/locale/intl.css chrome://browser/locale/overrides/intl.css
 % override chrome://passwordmgr/locale/passwordmgr.properties chrome://browser/locale/overrides/passwordmgr/passwordmgr.properties
 % override chrome://global/locale/search/search.properties chrome://browser/locale/overrides/search/search.properties
 % override chrome://mozapps/locale/update/updates.properties chrome://browser/locale/overrides/update/updates.properties
 % override chrome://mozapps/locale/plugins/plugins.dtd chrome://browser/locale/overrides/plugins/plugins.dtd
--- a/mobile/android/modules/WebappManager.jsm
+++ b/mobile/android/modules/WebappManager.jsm
@@ -346,18 +346,17 @@ this.WebappManager = {
 
     let data = JSON.stringify({ installed: installedApps });
 
     let notification;
     if (userInitiated) {
       notification = this._notify({
         title: Strings.GetStringFromName("checkingForUpdatesTitle"),
         message: Strings.GetStringFromName("checkingForUpdatesMessage"),
-        // TODO: replace this with an animated icon.
-        icon: "drawable://alert_app",
+        icon: "drawable://alert_app_animation",
         progress: NaN,
       });
     }
 
     let request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
                   createInstance(Ci.nsIXMLHttpRequest).
                   QueryInterface(Ci.nsIXMLHttpRequestEventTarget);
     request.mozBackgroundRequest = true;
@@ -387,20 +386,17 @@ this.WebappManager = {
 
   _updateApks: function(aApps) { return Task.spawn((function*() {
     // Notify the user that we're in the progress of downloading updates.
     let downloadingNames = [app.name for (app of aApps)].join(", ");
     let notification = this._notify({
       title: PluralForm.get(aApps.length, Strings.GetStringFromName("downloadingUpdateTitle")).
              replace("#1", aApps.length),
       message: Strings.formatStringFromName("downloadingUpdateMessage", [downloadingNames], 1),
-      // TODO: replace this with an animated icon.  UpdateService uses
-      // android.R.drawable.stat_sys_download, but I don't think we can reference
-      // a system icon with a drawable: URL here, so we'll have to craft our own.
-      icon: "drawable://alert_download",
+      icon: "drawable://alert_download_animation",
       // TODO: make this a determinate progress indicator once we can determine
       // the sizes of the APKs and observe their progress.
       progress: NaN,
     });
 
     // Download the APKs for the given apps.  We do this serially to avoid
     // saturating the user's network connection.
     // TODO: download APKs in parallel (or at least more than one at a time)
--- a/netwerk/protocol/http/Http2Session.cpp
+++ b/netwerk/protocol/http/Http2Session.cpp
@@ -121,16 +121,29 @@ Http2Session::Http2Session(nsAHttpTransa
 
     if (!aHttpTransaction->IsNullTransaction())
       AddStream(aHttpTransaction, firstPriority);
     mLastDataReadEpoch = mLastReadEpoch;
 
     mPingThreshold = gHttpHandler->SpdyPingThreshold();
 }
 
+// Copy the 32 bit number into the destination, using network byte order
+// in the destination.
+template<typename charType> static void
+CopyAsNetwork32(charType dest,   // where to store it
+                uint32_t number) // the 32 bit number in native format
+{
+  number = PR_htonl(number);
+  memcpy(dest, &number, sizeof(number));
+}
+
+template void CopyAsNetwork32(char *dest, uint32_t number);
+template void CopyAsNetwork32(uint8_t *dest, uint32_t number);
+
 PLDHashOperator
 Http2Session::ShutdownEnumerator(nsAHttpTransaction *key,
                                  nsAutoPtr<Http2Stream> &stream,
                                  void *closure)
 {
   Http2Session *self = static_cast<Http2Session *>(closure);
 
   // On a clean server hangup the server sets the GoAwayID to be the ID of
@@ -596,22 +609,21 @@ template<typename charType> void
 Http2Session::CreateFrameHeader(charType dest, uint16_t frameLength,
                                 uint8_t frameType, uint8_t frameFlags,
                                 uint32_t streamID)
 {
   MOZ_ASSERT(frameLength <= kMaxFrameData, "framelength too large");
   MOZ_ASSERT(!(streamID & 0x80000000));
 
   frameLength = PR_htons(frameLength);
-  streamID = PR_htonl(streamID);
 
   memcpy(dest, &frameLength, 2);
   dest[2] = frameType;
   dest[3] = frameFlags;
-  memcpy(dest + 4, &streamID, 4);
+  CopyAsNetwork32(dest + 4, streamID);
 }
 
 char *
 Http2Session::EnsureOutputBuffer(uint32_t spaceNeeded)
 {
   // this is an infallible allocation (if an allocation is
   // needed, which is probably isn't)
   EnsureBuffer(mOutputQueueBuffer, mOutputQueueUsed + spaceNeeded,
@@ -705,17 +717,17 @@ Http2Session::GeneratePriority(uint32_t 
   MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
   LOG3(("Http2Session::GeneratePriority %p %X %X\n",
         this, aID, aPriorityWeight));
 
   char *packet = EnsureOutputBuffer(13);
   mOutputQueueUsed += 13;
 
   CreateFrameHeader(packet, 5, FRAME_TYPE_PRIORITY, 0, aID);
-  memset(packet + 8, 0, 4);
+  CopyAsNetwork32(packet + 8, 0);
   memcpy(packet + 12, &aPriorityWeight, 1);
   LogIO(this, nullptr, "Generate Priority", packet, 13);
   FlushOutputQueue();
 }
 
 void
 Http2Session::GenerateRstStream(uint32_t aStatusCode, uint32_t aID)
 {
@@ -731,18 +743,17 @@ Http2Session::GenerateRstStream(uint32_t
   }
 
   LOG3(("Http2Session::GenerateRst %p 0x%X %d\n", this, aID, aStatusCode));
 
   char *packet = EnsureOutputBuffer(12);
   mOutputQueueUsed += 12;
   CreateFrameHeader(packet, 4, FRAME_TYPE_RST_STREAM, 0, aID);
 
-  aStatusCode = PR_htonl(aStatusCode);
-  memcpy(packet + 8, &aStatusCode, 4);
+  CopyAsNetwork32(packet + 8, aStatusCode);
 
   LogIO(this, nullptr, "Generate Reset", packet, 12);
   FlushOutputQueue();
 }
 
 void
 Http2Session::GenerateGoAway(uint32_t aStatusCode)
 {
@@ -750,22 +761,20 @@ Http2Session::GenerateGoAway(uint32_t aS
   LOG3(("Http2Session::GenerateGoAway %p code=%X\n", this, aStatusCode));
 
   char *packet = EnsureOutputBuffer(16);
   mOutputQueueUsed += 16;
 
   CreateFrameHeader(packet, 8, FRAME_TYPE_GOAWAY, 0, 0);
 
   // last-good-stream-id are bytes 8-11 reflecting pushes
-  uint32_t goAway = PR_htonl(mOutgoingGoAwayID);
-  memcpy(packet + 8, &goAway, 4);
+  CopyAsNetwork32(packet + 8, mOutgoingGoAwayID);
 
   // bytes 12-15 are the status code.
-  aStatusCode = PR_htonl(aStatusCode);
-  memcpy(packet + 12, &aStatusCode, 4);
+  CopyAsNetwork32(packet + 12, aStatusCode);
 
   LogIO(this, nullptr, "Generate GoAway", packet, 16);
   FlushOutputQueue();
 }
 
 // The Hello is comprised of 24 octets of magic, which are designed to
 // flush out silent but broken intermediaries, followed by a settings
 // frame which sets a small flow control window for pushes and a
@@ -807,18 +816,17 @@ Http2Session::SendHello()
     packet[8 + 5 * numberOfEntries] = SETTINGS_TYPE_MAX_CONCURRENT;
     // The value portion of the setting pair is already initialized to 0
     numberOfEntries++;
   }
 
   // Advertise the Push RWIN for the session, and on each new pull stream
   // send a window update with END_FLOW_CONTROL
   packet[8 + 5 * numberOfEntries] = SETTINGS_TYPE_INITIAL_WINDOW;
-  uint32_t rwin = PR_htonl(mPushAllowance);
-  memcpy(packet + 9 + 5 * numberOfEntries, &rwin, 4);
+  CopyAsNetwork32(packet + 9 + 5 * numberOfEntries, mPushAllowance);
   numberOfEntries++;
 
   // Explicitly signal that we do NOT support compressed data frames, even
   // though the default is to not support anyway.
   packet[8 + 5 * numberOfEntries] = SETTINGS_TYPE_COMPRESS_DATA;
   // The value portion of the setting pair is already initialized to 0
   numberOfEntries++;
 
@@ -830,26 +838,25 @@ Http2Session::SendHello()
   LogIO(this, nullptr, "Generate Settings", packet, 8 + dataLen);
 
   // now bump the local session window from 64KB
   uint32_t sessionWindowBump = ASpdySession::kInitialRwin - kDefaultRwin;
   if (kDefaultRwin >= ASpdySession::kInitialRwin)
     goto sendHello_complete;
 
   // send a window update for the session (Stream 0) for something large
-  sessionWindowBump = PR_htonl(sessionWindowBump);
   mLocalSessionWindow = ASpdySession::kInitialRwin;
 
   packet = mOutputQueueBuffer.get() + mOutputQueueUsed;
   CreateFrameHeader(packet, 4, FRAME_TYPE_WINDOW_UPDATE, 0, 0);
   mOutputQueueUsed += 12;
-  memcpy(packet + 8, &sessionWindowBump, 4);
+  CopyAsNetwork32(packet + 8, sessionWindowBump);
 
   LOG3(("Session Window increase at start of session %p %u\n",
-        this, PR_ntohl(sessionWindowBump)));
+        this, sessionWindowBump));
   LogIO(this, nullptr, "Session Window Bump ", packet, 12);
 
 sendHello_complete:
   FlushOutputQueue();
 }
 
 // perform a bunch of integrity checks on the stream.
 // returns true if passed, false (plus LOG and ABORT) if failed.
@@ -2475,18 +2482,17 @@ Http2Session::UpdateLocalStreamWindow(Ht
   stream->IncrementClientReceiveWindow(toack);
 
   // room for this packet needs to be ensured before calling this function
   char *packet = mOutputQueueBuffer.get() + mOutputQueueUsed;
   mOutputQueueUsed += 12;
   MOZ_ASSERT(mOutputQueueUsed <= mOutputQueueSize);
 
   CreateFrameHeader(packet, 4, FRAME_TYPE_WINDOW_UPDATE, 0, stream->StreamID());
-  toack = PR_htonl(toack);
-  memcpy(packet + 8, &toack, 4);
+  CopyAsNetwork32(packet + 8, toack);
 
   LogIO(this, stream, "Stream Window Update", packet, 12);
   // dont flush here, this write can commonly be coalesced with a
   // session window update to immediately follow.
 }
 
 void
 Http2Session::UpdateLocalSessionWindow(uint32_t bytes)
@@ -2514,18 +2520,17 @@ Http2Session::UpdateLocalSessionWindow(u
   mLocalSessionWindow += toack;
 
   // room for this packet needs to be ensured before calling this function
   char *packet = mOutputQueueBuffer.get() + mOutputQueueUsed;
   mOutputQueueUsed += 12;
   MOZ_ASSERT(mOutputQueueUsed <= mOutputQueueSize);
 
   CreateFrameHeader(packet, 4, FRAME_TYPE_WINDOW_UPDATE, 0, 0);
-  toack = PR_htonl(toack);
-  memcpy(packet + 8, &toack, 4);
+  CopyAsNetwork32(packet + 8, toack);
 
   LogIO(this, nullptr, "Session Window Update", packet, 12);
   // dont flush here, this write can commonly be coalesced with others
 }
 
 void
 Http2Session::UpdateLocalRwin(Http2Stream *stream, uint32_t bytes)
 {
--- a/security/certverifier/OCSPCache.cpp
+++ b/security/certverifier/OCSPCache.cpp
@@ -1,11 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* Copyright 2013 Mozilla Foundation
+/* This code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
--- a/security/certverifier/OCSPCache.h
+++ b/security/certverifier/OCSPCache.h
@@ -1,11 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* Copyright 2013 Mozilla Foundation
+/* This code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
--- a/security/pkix/include/pkix/ScopedPtr.h
+++ b/security/pkix/include/pkix/ScopedPtr.h
@@ -1,11 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* Copyright 2013 Mozilla Foundation
+/* This code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
--- a/security/pkix/include/pkix/bind.h
+++ b/security/pkix/include/pkix/bind.h
@@ -1,11 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* Copyright 2013 Mozilla Foundation
+/* This code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
--- a/security/pkix/include/pkix/enumclass.h
+++ b/security/pkix/include/pkix/enumclass.h
@@ -1,11 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* Copyright 2013 Mozilla Foundation
+/* This code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
--- a/security/pkix/include/pkix/nullptr.h
+++ b/security/pkix/include/pkix/nullptr.h
@@ -1,11 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* Copyright 2013 Mozilla Foundation
+/* This code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
--- a/security/pkix/include/pkix/pkix.h
+++ b/security/pkix/include/pkix/pkix.h
@@ -1,11 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* Copyright 2013 Mozilla Foundation
+/* This code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
--- a/security/pkix/include/pkix/pkixtypes.h
+++ b/security/pkix/include/pkix/pkixtypes.h
@@ -1,11 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* Copyright 2012 Mozilla Foundation
+/* This code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
--- a/security/pkix/lib/pkixbind.cpp
+++ b/security/pkix/lib/pkixbind.cpp
@@ -1,11 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* Copyright 2013 Mozilla Foundation
+/* This code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
--- a/security/pkix/lib/pkixbuild.cpp
+++ b/security/pkix/lib/pkixbuild.cpp
@@ -1,11 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* Copyright 2013 Mozilla Foundation
+/* This code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
--- a/security/pkix/lib/pkixcheck.cpp
+++ b/security/pkix/lib/pkixcheck.cpp
@@ -1,11 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* Copyright 2013 Mozilla Foundation
+/* This code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
--- a/security/pkix/lib/pkixcheck.h
+++ b/security/pkix/lib/pkixcheck.h
@@ -1,11 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* Copyright 2013 Mozilla Foundation
+/* This code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
--- a/security/pkix/lib/pkixder.cpp
+++ b/security/pkix/lib/pkixder.cpp
@@ -1,11 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* Copyright 2013 Mozilla Foundation
+/* This code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
--- a/security/pkix/lib/pkixder.h
+++ b/security/pkix/lib/pkixder.h
@@ -1,11 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* Copyright 2013 Mozilla Foundation
+/* This code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
--- a/security/pkix/lib/pkixkey.cpp
+++ b/security/pkix/lib/pkixkey.cpp
@@ -1,11 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* Copyright 2013 Mozilla Foundation
+/* This code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
--- a/security/pkix/lib/pkixocsp.cpp
+++ b/security/pkix/lib/pkixocsp.cpp
@@ -1,11 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* Copyright 2013 Mozilla Foundation
+/* This code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
--- a/security/pkix/lib/pkixutil.h
+++ b/security/pkix/lib/pkixutil.h
@@ -1,11 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* Copyright 2013 Mozilla Foundation
+/* This code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
--- a/security/pkix/test/gtest/nssgtest.cpp
+++ b/security/pkix/test/gtest/nssgtest.cpp
@@ -1,11 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* Copyright 2013 Mozilla Foundation
+/* This code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
--- a/security/pkix/test/gtest/nssgtest.h
+++ b/security/pkix/test/gtest/nssgtest.h
@@ -1,11 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* Copyright 2013 Mozilla Foundation
+/* This code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
--- a/security/pkix/test/gtest/pkixder_input_tests.cpp
+++ b/security/pkix/test/gtest/pkixder_input_tests.cpp
@@ -1,11 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* Copyright 2013 Mozilla Foundation
+/* This code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
--- a/security/pkix/test/gtest/pkixder_pki_types_tests.cpp
+++ b/security/pkix/test/gtest/pkixder_pki_types_tests.cpp
@@ -1,11 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* Copyright 2013 Mozilla Foundation
+/* This code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
--- a/security/pkix/test/gtest/pkixder_universal_types_tests.cpp
+++ b/security/pkix/test/gtest/pkixder_universal_types_tests.cpp
@@ -1,11 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* Copyright 2013 Mozilla Foundation
+/* This code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
--- a/security/pkix/test/lib/moz.build
+++ b/security/pkix/test/lib/moz.build
@@ -1,10 +1,17 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
-# Copyright 2013 Mozilla Foundation
+# This code is made available to you under your choice of the following sets
+# of licensing terms:
+#
+# 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/.
+#
+# Copyright 2013 Mozilla Contributors
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at
 #
 # http://www.apache.org/licenses/LICENSE-2.0
 #
 # Unless required by applicable law or agreed to in writing, software
--- a/security/pkix/test/lib/pkixtestutil.cpp
+++ b/security/pkix/test/lib/pkixtestutil.cpp
@@ -1,11 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* Copyright 2013 Mozilla Foundation
+/* This code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
--- a/security/pkix/test/lib/pkixtestutil.h
+++ b/security/pkix/test/lib/pkixtestutil.h
@@ -1,11 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* Copyright 2013 Mozilla Foundation
+/* This code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2013 Mozilla Contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
--- a/toolkit/components/search/nsSearchService.js
+++ b/toolkit/components/search/nsSearchService.js
@@ -2838,16 +2838,17 @@ SearchService.prototype = {
     }
     this._addObservers();
 
     gInitialized = true;
 
     this._initObservers.resolve(this._initRV);
 
     Services.obs.notifyObservers(null, SEARCH_SERVICE_TOPIC, "init-complete");
+    Services.telemetry.getHistogramById("SEARCH_SERVICE_INIT_SYNC").add(true);
 
     LOG("_syncInit end");
   },
 
   /**
    * Asynchronous implementation of the initializer.
    *
    * @returns {Promise} A promise, resolved successfully if the initialization
@@ -2861,16 +2862,18 @@ SearchService.prototype = {
       } catch (ex if ex.result != Cr.NS_ERROR_ALREADY_INITIALIZED) {
         this._initRV = Cr.NS_ERROR_FAILURE;
         LOG("_asyncInit: failure loading engines: " + ex);
       }
       this._addObservers();
       gInitialized = true;
       this._initObservers.resolve(this._initRV);
       Services.obs.notifyObservers(null, SEARCH_SERVICE_TOPIC, "init-complete");
+      Services.telemetry.getHistogramById("SEARCH_SERVICE_INIT_SYNC").add(false);
+
       LOG("_asyncInit: Completed _asyncInit");
     }.bind(this));
   },
 
 
   _engines: { },
   __sortedEngines: null,
   get _sortedEngines() {
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -3325,16 +3325,32 @@
     "expires_in_version": "never",
     "kind": "exponential",
     "low": 50,
     "high": "60000",
     "n_buckets": 20,
     "extended_statistics_ok": true,
     "description": "Widget: Time it takes for the message before a UI message (ms)"
   },
+  "FX_SESSION_RESTORE_STARTUP_INIT_SESSION_MS": {
+    "expires_in_version": "never",
+    "kind": "exponential",
+    "high": "30000",
+    "n_buckets": 20,
+    "extended_statistics_ok": true,
+    "description": "Session restore: Time it takes to prepare the data structures for restoring a session (ms)"
+  },
+  "FX_SESSION_RESTORE_STARTUP_ONLOAD_INITIAL_WINDOW_MS": {
+    "expires_in_version": "never",
+    "kind": "exponential",
+    "high": "30000",
+    "n_buckets": 20,
+    "extended_statistics_ok": true,
+    "description": "Session restore: Time it takes to finish restoration once we have first opened a window (ms)"
+  },
   "FX_SESSION_RESTORE_COLLECT_ALL_WINDOWS_DATA_MS": {
     "expires_in_version": "never",
     "kind": "exponential",
     "high": "30000",
     "n_buckets": 10,
     "extended_statistics_ok": true,
     "description": "Session restore: Time to collect all window data (ms)"
   },
@@ -4262,16 +4278,21 @@
   "SEARCH_SERVICE_INIT_MS": {
     "expires_in_version": "never",
     "kind": "exponential",
     "high": "1000",
     "n_buckets": 15,
     "extended_statistics_ok": true,
     "description": "Time (ms) it takes to initialize the search service"
   },
+  "SEARCH_SERVICE_INIT_SYNC": {
+    "expires_in_version": "35",
+    "kind": "boolean",
+    "description": "search service has been initialized synchronously"
+  },
   "SEARCH_SERVICE_BUILD_CACHE_MS": {
     "expires_in_version": "never",
     "kind": "exponential",
     "high": "1000",
     "n_buckets": 15,
     "extended_statistics_ok": true,
     "description": "Time (ms) it takes to build the cache of the search service"
   },
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/update/UpdaterHealthProvider.jsm
@@ -0,0 +1,69 @@
+/* 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";
+
+this.EXPORTED_SYMBOLS = [
+  "UpdateProvider",
+];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/Metrics.jsm", this);
+Cu.import("resource://gre/modules/Task.jsm", this);
+
+const DAILY_COUNTER_FIELD = {type: Metrics.Storage.FIELD_DAILY_COUNTER};
+const DAILY_DISCRETE_NUMERIC_FIELD = {type: Metrics.Storage.FIELD_DAILY_DISCRETE_NUMERIC};
+
+function UpdateMeasurement1() {
+  Metrics.Measurement.call(this);
+}
+
+UpdateMeasurement1.prototype = Object.freeze({
+  __proto__: Metrics.Measurement.prototype,
+
+  name: "update",
+  version: 1,
+
+  fields: {
+    updateCheckStartCount: DAILY_COUNTER_FIELD,
+    updateCheckSuccessCount: DAILY_COUNTER_FIELD,
+    updateCheckFailedCount: DAILY_COUNTER_FIELD,
+    updateCheckFailedStatuses: DAILY_DISCRETE_NUMERIC_FIELD,
+    completeUpdateStartCount: DAILY_COUNTER_FIELD,
+    partialUpdateStartCount: DAILY_COUNTER_FIELD,
+    completeUpdateSuccessCount: DAILY_COUNTER_FIELD,
+    partialUpdateSuccessCount: DAILY_COUNTER_FIELD,
+    updateFailedCount: DAILY_COUNTER_FIELD,
+    updateFailedStatuses: DAILY_DISCRETE_NUMERIC_FIELD,
+  },
+});
+
+this.UpdateProvider = function () {
+  Metrics.Provider.call(this);
+};
+UpdateProvider.prototype = Object.freeze({
+  __proto__: Metrics.Provider.prototype,
+
+  name: "org.mozilla.update",
+
+  measurementTypes: [
+    UpdateMeasurement1,
+  ],
+
+  recordUpdate: function (field, status) {
+    let m = this.getMeasurement(UpdateMeasurement1.prototype.name,
+                                UpdateMeasurement1.prototype.version);
+
+    return this.enqueueStorageOperation(function recordUpdateFields() {
+      return Task.spawn(function recordUpdateFieldsTask() {
+        yield m.incrementDailyCounter(field + "Count");
+
+        if ((field == "updateFailed" || field == "updateCheckFailed") && status) {
+          yield m.addDailyDiscreteNumeric(field + "Statuses", status);
+        }
+      }.bind(this));
+    }.bind(this));
+  },
+});
--- a/toolkit/mozapps/update/moz.build
+++ b/toolkit/mozapps/update/moz.build
@@ -41,9 +41,13 @@ if CONFIG['MOZ_UPDATER']:
         'nsUpdateService.manifest',
     ]
 
     EXTRA_PP_COMPONENTS += [
         'nsUpdateService.js',
         'nsUpdateServiceStub.js',
     ]
 
-JAR_MANIFESTS += ['jar.mn']
\ No newline at end of file
+    EXTRA_JS_MODULES += [
+      'UpdaterHealthProvider.jsm'
+    ]
+
+JAR_MANIFESTS += ['jar.mn']
--- a/toolkit/mozapps/update/nsUpdateService.js
+++ b/toolkit/mozapps/update/nsUpdateService.js
@@ -7,16 +7,17 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/FileUtils.jsm");
 Components.utils.import("resource://gre/modules/AddonManager.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://gre/modules/ctypes.jsm");
+Components.utils.import("resource://gre/modules/UpdaterHealthProvider.jsm");
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 const Cu = Components.utils;
 
 const UPDATESERVICE_CID = Components.ID("{B3C290A6-3943-4B89-8BBE-C01EB7B3B311}");
 const UPDATESERVICE_CONTRACTID = "@mozilla.org/updates/update-service;1";
@@ -253,16 +254,28 @@ const PING_BGUC_ADDON_PREF_DISABLED     
 const PING_BGUC_ADDON_SAME_APP_VER           = 27;
 // No incompatible add-ons found during incompatible check (background download)
 const PING_BGUC_CHECK_NO_INCOMPAT            = 28;
 // Incompatible add-ons found and all of them have updates (background download)
 const PING_BGUC_ADDON_UPDATES_FOR_INCOMPAT   = 29;
 // Incompatible add-ons found (update notification)
 const PING_BGUC_ADDON_HAVE_INCOMPAT          = 30;
 
+// Health report field names
+const UpdaterHealthReportFields = {
+  CHECK_START: "updateCheckStart",
+  CHECK_SUCCESS: "updateCheckSuccess",
+  CHECK_FAILED: "updateCheckFailed",
+  COMPLETE_START: "completeUpdateStart",
+  PARTIAL_START: "partialUpdateStart",
+  COMPLETE_SUCCESS: "completeUpdateSuccess",
+  PARTIAL_SUCCESS: "partialUpdateSuccess",
+  FAILED: "updateFailed"
+};
+
 var gLocale = null;
 var gUpdateMutexHandle = null;
 
 #ifdef MOZ_WIDGET_GONK
 var gSDCardMountLock = null;
 
 XPCOMUtils.defineLazyGetter(this, "gExtStorage", function aus_gExtStorage() {
     return Services.env.get("EXTERNAL_STORAGE");
@@ -935,16 +948,47 @@ function getStatusTextFromCode(code, def
     reason = gUpdateBundle.GetStringFromName("check_error-" + defaultCode);
     LOG("getStatusTextFromCode - transfer error: " + reason +
         ", default code: " + defaultCode);
   }
   return reason;
 }
 
 /**
+ * Record count in the health report.
+ * @param field
+ *        The field name to record
+ * @param status
+ *        Status code for errors, 0 otherwise
+ */
+function recordInHealthReport(field, status) {
+#ifdef MOZ_SERVICES_HEALTHREPORT
+  try {
+    LOG("recordInHealthReport - " + field + " - " + status);
+
+    let reporter = Cc["@mozilla.org/datareporting/service;1"]
+                      .getService().wrappedJSObject.healthReporter;
+
+    if (reporter) {
+      reporter.onInit().then(function recordUpdateInHealthReport() {
+        try {
+          reporter.getProvider("org.mozilla.update").recordUpdate(field, status);
+        } catch (ex) {
+          Cu.reportError(ex);
+        }
+      });
+    }
+  // If getting the heath reporter service fails, don't fail updating.
+  } catch (ex) {
+    LOG("recordInHealthReport - could not initialize health reporter");
+  }
+#endif
+}
+
+/**
  * Get the Active Updates directory
  * @return The active updates directory, as a nsIFile object
  */
 function getUpdatesDir() {
   // Right now, we only support downloading one patch at a time, so we always
   // use the same target directory.
   return getUpdateDirCreate([DIR_UPDATES, "0"]);
 }
@@ -3600,16 +3644,18 @@ Checker.prototype = {
       throw Cr.NS_ERROR_NULL_POINTER;
 
     Services.obs.notifyObservers(null, "update-check-start", null);
 
     var url = this.getUpdateURL(force);
     if (!url || (!this.enabled && !force))
       return;
 
+    recordInHealthReport(UpdaterHealthReportFields.CHECK_START, 0);
+
     this._request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
                     createInstance(Ci.nsISupports);
     // This is here to let unit test code override XHR
     if (this._request.wrappedJSObject) {
       this._request = this._request.wrappedJSObject;
     }
     this._request.open("GET", url, true);
     var allowNonBuiltIn = !getPref("getBoolPref",
@@ -3723,16 +3769,18 @@ Checker.prototype = {
       gCertUtils.checkCert(this._request.channel, allowNonBuiltIn, certs);
 
       if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_CERT_ERRORS))
         Services.prefs.clearUserPref(PREF_APP_UPDATE_CERT_ERRORS);
 
       if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_BACKGROUNDERRORS))
         Services.prefs.clearUserPref(PREF_APP_UPDATE_BACKGROUNDERRORS);
 
+      recordInHealthReport(UpdaterHealthReportFields.CHECK_SUCCESS, 0);
+
       // Tell the callback about the updates
       this._callback.onCheckComplete(event.target, updates, updates.length);
     }
     catch (e) {
       LOG("Checker:onLoad - there was a problem checking for updates. " +
           "Exception: " + e);
       var request = event.target;
       var status = this._getChannelStatus(request);
@@ -3743,16 +3791,19 @@ Checker.prototype = {
 
       if (this._isHttpStatusCode(status)) {
         update.errorCode = HTTP_ERROR_OFFSET + status;
       }
       if (e.result == Cr.NS_ERROR_ILLEGAL_VALUE) {
         update.errorCode = updates[0] ? CERT_ATTR_CHECK_FAILED_HAS_UPDATE
                                       : CERT_ATTR_CHECK_FAILED_NO_UPDATE;
       }
+
+      recordInHealthReport(UpdaterHealthReportFields.CHECK_FAILED, update.errorCode);
+
       this._callback.onError(request, update);
     }
 
     this._callback = null;
     this._request = null;
   },
 
   /**
@@ -3774,16 +3825,18 @@ Checker.prototype = {
 
     if (status == Cr.NS_ERROR_OFFLINE) {
       // We use a separate constant here because nsIUpdate.errorCode is signed
       update.errorCode = NETWORK_ERROR_OFFLINE;
     } else if (this._isHttpStatusCode(status)) {
       update.errorCode = HTTP_ERROR_OFFSET + status;
     }
 
+    recordInHealthReport(UpdaterHealthReportFields.CHECK_FAILED, update.errorCode);
+
     this._callback.onError(request, update);
 
     this._request = null;
   },
 
   /**
    * Whether or not we are allowed to do update checking.
    */
@@ -4088,16 +4141,20 @@ Downloader.prototype = {
     // to download.
     this._patch = this._selectPatch(update, updateDir);
     if (!this._patch) {
       LOG("Downloader:downloadUpdate - no patch to download");
       return readStatusFile(updateDir);
     }
     this.isCompleteUpdate = this._patch.type == "complete";
 
+    recordInHealthReport(
+      this.isCompleteUpdate ? UpdaterHealthReportFields.COMPLETE_START :
+                              UpdaterHealthReportFields.PARTIAL_START, 0);
+
     var patchFile = null;
 
 #ifdef MOZ_WIDGET_GONK
     let status = readStatusFile(updateDir);
     if (isInterruptedUpdate(status)) {
       LOG("Downloader:downloadUpdate - interruptted update");
       // The update was interrupted. Try to locate the existing patch file.
       // For an interrupted download, this allows a resume rather than a
@@ -4343,16 +4400,20 @@ Downloader.prototype = {
     var retryTimeout = getPref("getIntPref", PREF_APP_UPDATE_RETRY_TIMEOUT,
                                DEFAULT_UPDATE_RETRY_TIMEOUT);
     var maxFail = getPref("getIntPref", PREF_APP_UPDATE_SOCKET_ERRORS,
                           DEFAULT_SOCKET_MAX_ERRORS);
     LOG("Downloader:onStopRequest - status: " + status + ", " +
         "current fail: " + this.updateService._consecutiveSocketErrors + ", " +
         "max fail: " + maxFail + ", " + "retryTimeout: " + retryTimeout);
     if (Components.isSuccessCode(status)) {
+      recordInHealthReport(
+        this.isCompleteUpdate ? UpdaterHealthReportFields.COMPLETE_SUCCESS :
+                                UpdaterHealthReportFields.PARTIAL_SUCCESS, 0);
+
       if (this._verifyDownload()) {
         state = shouldUseService() ? STATE_PENDING_SVC : STATE_PENDING;
         if (this.background) {
           shouldShowPrompt = !getCanStageUpdates();
         }
 
         // Tell the updater.exe we're ready to apply.
         writeStatusFile(getUpdatesDir(), state);
@@ -4371,59 +4432,63 @@ Downloader.prototype = {
         this._update.statusText = message;
 
         if (this._update.isCompleteUpdate || this._update.patchCount != 2)
           deleteActiveUpdate = true;
 
         // Destroy the updates directory, since we're done with it.
         cleanUpUpdatesDir();
       }
-    } else if (status == Cr.NS_ERROR_OFFLINE) {
-      // Register an online observer to try again.
-      // The online observer will continue the incremental download by
-      // calling downloadUpdate on the active update which continues
-      // downloading the file from where it was.
-      LOG("Downloader:onStopRequest - offline, register online observer: true");
-      shouldRegisterOnlineObserver = true;
-      deleteActiveUpdate = false;
-    // Each of NS_ERROR_NET_TIMEOUT, ERROR_CONNECTION_REFUSED, and
-    // NS_ERROR_NET_RESET can be returned when disconnecting the internet while
-    // a download of a MAR is in progress.  There may be others but I have not
-    // encountered them during testing.
-    } else if ((status == Cr.NS_ERROR_NET_TIMEOUT ||
-                status == Cr.NS_ERROR_CONNECTION_REFUSED ||
-                status == Cr.NS_ERROR_NET_RESET) &&
-               this.updateService._consecutiveSocketErrors < maxFail) {
-      LOG("Downloader:onStopRequest - socket error, shouldRetrySoon: true");
-      shouldRetrySoon = true;
-      deleteActiveUpdate = false;
-    } else if (status != Cr.NS_BINDING_ABORTED &&
-               status != Cr.NS_ERROR_ABORT &&
-               status != Cr.NS_ERROR_DOCUMENT_NOT_CACHED) {
-      LOG("Downloader:onStopRequest - non-verification failure");
-      // Some sort of other failure, log this in the |statusText| property
-      state = STATE_DOWNLOAD_FAILED;
-
-      // XXXben - if |request| (The Incremental Download) provided a means
-      // for accessing the http channel we could do more here.
-
-      this._update.statusText = getStatusTextFromCode(status,
-                                                      Cr.NS_BINDING_FAILED);
+    } else {
+      recordInHealthReport(UpdaterHealthReportFields.FAILED, status);
+
+      if (status == Cr.NS_ERROR_OFFLINE) {
+        // Register an online observer to try again.
+        // The online observer will continue the incremental download by
+        // calling downloadUpdate on the active update which continues
+        // downloading the file from where it was.
+        LOG("Downloader:onStopRequest - offline, register online observer: true");
+        shouldRegisterOnlineObserver = true;
+        deleteActiveUpdate = false;
+      // Each of NS_ERROR_NET_TIMEOUT, ERROR_CONNECTION_REFUSED, and
+      // NS_ERROR_NET_RESET can be returned when disconnecting the internet while
+      // a download of a MAR is in progress.  There may be others but I have not
+      // encountered them during testing.
+      } else if ((status == Cr.NS_ERROR_NET_TIMEOUT ||
+                  status == Cr.NS_ERROR_CONNECTION_REFUSED ||
+                  status == Cr.NS_ERROR_NET_RESET) &&
+                 this.updateService._consecutiveSocketErrors < maxFail) {
+        LOG("Downloader:onStopRequest - socket error, shouldRetrySoon: true");
+        shouldRetrySoon = true;
+        deleteActiveUpdate = false;
+      } else if (status != Cr.NS_BINDING_ABORTED &&
+                 status != Cr.NS_ERROR_ABORT &&
+                 status != Cr.NS_ERROR_DOCUMENT_NOT_CACHED) {
+        LOG("Downloader:onStopRequest - non-verification failure");
+        // Some sort of other failure, log this in the |statusText| property
+        state = STATE_DOWNLOAD_FAILED;
+
+        // XXXben - if |request| (The Incremental Download) provided a means
+        // for accessing the http channel we could do more here.
+
+        this._update.statusText = getStatusTextFromCode(status,
+                                                        Cr.NS_BINDING_FAILED);
 
 #ifdef MOZ_WIDGET_GONK
-      // bug891009: On FirefoxOS, manaully retry OTA download will reuse
-      // the Update object. We need to remove selected patch so that download
-      // can be triggered again successfully.
-      this._update.selectedPatch.selected = false;
+        // bug891009: On FirefoxOS, manaully retry OTA download will reuse
+        // the Update object. We need to remove selected patch so that download
+        // can be triggered again successfully.
+        this._update.selectedPatch.selected = false;
 #endif
 
-      // Destroy the updates directory, since we're done with it.
-      cleanUpUpdatesDir();
-
-      deleteActiveUpdate = true;
+        // Destroy the updates directory, since we're done with it.
+        cleanUpUpdatesDir();
+
+        deleteActiveUpdate = true;
+      }
     }
     LOG("Downloader:onStopRequest - setting state to: " + state);
     this._patch.state = state;
     var um = Cc["@mozilla.org/updates/update-manager;1"].
              getService(Ci.nsIUpdateManager);
     if (deleteActiveUpdate) {
       this._update.installDate = (new Date()).getTime();
       um.activeUpdate = null;
--- a/toolkit/mozapps/update/nsUpdateService.manifest
+++ b/toolkit/mozapps/update/nsUpdateService.manifest
@@ -5,8 +5,11 @@ component {093C2356-4843-4C65-8709-D7DBC
 contract @mozilla.org/updates/update-manager;1 {093C2356-4843-4C65-8709-D7DBCBBE7DFB}
 component {898CDC9B-E43F-422F-9CC4-2F6291B415A3} nsUpdateService.js
 contract @mozilla.org/updates/update-checker;1 {898CDC9B-E43F-422F-9CC4-2F6291B415A3}
 component {27ABA825-35B5-4018-9FDD-F99250A0E722} nsUpdateService.js
 contract @mozilla.org/updates/update-prompt;1 {27ABA825-35B5-4018-9FDD-F99250A0E722}
 component {e43b0010-04ba-4da6-b523-1f92580bc150} nsUpdateServiceStub.js
 contract @mozilla.org/updates/update-service-stub;1 {e43b0010-04ba-4da6-b523-1f92580bc150}
 category profile-after-change nsUpdateServiceStub @mozilla.org/updates/update-service-stub;1
+#ifdef MOZ_SERVICES_HEALTHREPORT
+category healthreport-js-provider-default UpdateProvider resource://gre/modules/UpdaterHealthProvider.jsm
+#endif
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/update/tests/unit_aus_update/updateHealthReport.js
@@ -0,0 +1,91 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const {utils: Cu, classes: Cc, interfaces: Ci} = Components;
+
+
+Cu.import("resource://gre/modules/Metrics.jsm");
+Cu.import("resource://gre/modules/UpdaterHealthProvider.jsm");
+
+// Create a profile
+let gProfile = do_get_profile();
+
+function run_test() {
+  run_next_test();
+}
+
+add_test(function test_constructor() {
+  let provider = new UpdateProvider();
+  run_next_test();
+});
+
+add_task(function test_init() {
+  let storage = yield Metrics.Storage("init");
+  let provider = new UpdateProvider();
+  yield provider.init(storage);
+  yield provider.shutdown();
+
+  yield storage.close();
+});
+
+add_task(function test_collect() {
+  let storage = yield Metrics.Storage("collect");
+  let provider = new UpdateProvider();
+  yield provider.init(storage);
+
+  let now = new Date();
+
+  let m = provider.getMeasurement("update", 1);
+
+  let fieldcount = 0;
+  for (let field of ["updateCheckStart",
+                     "updateCheckSuccess",
+                     "completeUpdateStart",
+                     "partialUpdateStart",
+                     "completeUpdateSuccess",
+                     "partialUpdateSuccess"]) {
+    fieldcount++; // One new day per iteration
+
+    yield provider.recordUpdate(field, 0);
+
+    let data = yield m.getValues();
+    do_check_eq(data.days.size, 1);
+
+    let day = data.days.getDay(now);
+    do_check_eq(day.size, fieldcount);
+    do_check_eq(day.get(field + "Count"), 1);
+
+    yield provider.recordUpdate(field, 0);
+
+    data = yield m.getValues();
+    day = data.days.getDay(now);
+    do_check_eq(day.size, fieldcount);
+    do_check_eq(day.get(field + "Count"), 2);
+  }
+
+  for (let field of ["updateCheckFailed", "updateFailed"]) {
+    fieldcount += 2; // Two fields added per iteration
+
+    yield provider.recordUpdate(field, 500);
+
+    let data = yield m.getValues();
+    let day = data.days.getDay(now);
+    do_check_eq(day.size, fieldcount);
+
+    do_check_eq(day.get(field + "Statuses"), 500);
+
+    yield provider.recordUpdate(field, 800);
+
+    data = yield m.getValues();
+    day = data.days.getDay(now);
+    do_check_eq(day.size, fieldcount);
+    do_check_eq(day.get(field + "Statuses")[0], 500);
+    do_check_eq(day.get(field + "Statuses")[1], 800);
+  }
+
+  yield provider.shutdown();
+  yield storage.close();
+});
+
--- a/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.ini
+++ b/toolkit/mozapps/update/tests/unit_aus_update/xpcshell.ini
@@ -34,8 +34,10 @@ reason = custom nsIUpdatePrompt
 [uiOnlyAllowOneWindow.js]
 skip-if = toolkit == 'gonk'
 reason = custom nsIUpdatePrompt
 [uiUnsupportedAlreadyNotified.js]
 skip-if = toolkit == 'gonk'
 reason = custom nsIUpdatePrompt
 [updateRootDirMigration_win.js]
 run-if = os == 'win'
+[updateHealthReport.js]
+skip-if = ! healthreport
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -3584,16 +3584,25 @@ nsWindow::UpdateThemeGeometries(const ns
   }
 
   nsRefPtr<LayerManager> layerManager = GetLayerManager();
   if (layerManager) {
     layerManager->SetRegionToClear(clearRegion);
   }
 }
 
+uint32_t
+nsWindow::GetMaxTouchPoints() const
+{
+  if (IsWin7OrLater()) {
+    return GetSystemMetrics(SM_MAXIMUMTOUCHES);
+  }
+  return 0;
+}
+
 /**************************************************************
  **************************************************************
  **
  ** BLOCK: Moz Events
  **
  ** Moz GUI event management. 
  **
  **************************************************************
--- a/widget/windows/nsWindow.h
+++ b/widget/windows/nsWindow.h
@@ -192,16 +192,17 @@ public:
   virtual nsIMEUpdatePreference GetIMEUpdatePreference();
   NS_IMETHOD              GetNonClientMargins(nsIntMargin &margins);
   NS_IMETHOD              SetNonClientMargins(nsIntMargin &margins);
   void                    SetDrawsInTitlebar(bool aState);
   mozilla::TemporaryRef<mozilla::gfx::DrawTarget> StartRemoteDrawing() MOZ_OVERRIDE;
   virtual void            EndRemoteDrawing() MOZ_OVERRIDE;
 
   virtual void            UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries) MOZ_OVERRIDE;
+  virtual uint32_t        GetMaxTouchPoints() const MOZ_OVERRIDE;
 
   /**
    * Event helpers
    */
   virtual bool            DispatchMouseEvent(uint32_t aEventType, WPARAM wParam,
                                              LPARAM lParam,
                                              bool aIsContextMenuKey = false,
                                              int16_t aButton = mozilla::WidgetMouseEvent::eLeftButton,
--- a/widget/windows/nsWindowDefs.h
+++ b/widget/windows/nsWindowDefs.h
@@ -40,16 +40,21 @@
 // Internal message for ensuring the file picker is visible on multi monitor
 // systems, and when the screen resolution changes.
 #define MOZ_WM_ENSUREVISIBLE              (WM_APP+0x374F)
 
 #ifndef SM_CXPADDEDBORDER
 #define SM_CXPADDEDBORDER                 92
 #endif
 
+// require WINVER >= 0x601
+#ifndef SM_MAXIMUMTOUCHES
+#define SM_MAXIMUMTOUCHES                 95
+#endif
+
 #ifndef WM_THEMECHANGED
 #define WM_THEMECHANGED                   0x031A
 #endif
 
 #ifndef WM_GETOBJECT
 #define WM_GETOBJECT                      0x03d
 #endif