Merge mozilla-central to mozilla-inbound
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 12 Jan 2017 10:36:29 +0100
changeset 374134 311a9929ce5baae9f383eacc8109b60f6f472987
parent 374133 4a1f0be6fa1d318be2799b5066a098a9c931fa70 (current diff)
parent 374061 97d6f73643940256c0eb61e384c49bf6f6c49847 (diff)
child 374135 8cdcf83fd1659c563ad6569e5bd63ac99a73ba65
push id6996
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 20:48:21 +0000
treeherdermozilla-beta@d89512dab048 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone53.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to mozilla-inbound
third_party/rust/byteorder/Makefile
third_party/rust/byteorder/session.vim
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -956,25 +956,23 @@ pref("dom.ipc.plugins.sandbox-level.flas
 // See - security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
 // SetSecurityLevelForContentProcess() for what the different settings mean.
 #if defined(NIGHTLY_BUILD)
 pref("security.sandbox.content.level", 2);
 #else
 pref("security.sandbox.content.level", 1);
 #endif
 
-#if defined(MOZ_STACKWALKING)
 // This controls the depth of stack trace that is logged when Windows sandbox
 // logging is turned on.  This is only currently available for the content
 // process because the only other sandbox (for GMP) has too strict a policy to
 // allow stack tracing.  This does not require a restart to take effect.
 pref("security.sandbox.windows.log.stackTraceDepth", 0);
 #endif
 #endif
-#endif
 
 #if defined(XP_MACOSX) && defined(MOZ_SANDBOX) && defined(MOZ_CONTENT_SANDBOX)
 // This pref is discussed in bug 1083344, the naming is inspired from its
 // Windows counterpart, but on Mac it's an integer which means:
 // 0 -> "no sandbox"
 // 1 -> "preliminary content sandboxing enabled: write access to
 //       home directory is prevented"
 // 2 -> "preliminary content sandboxing enabled with profile protection:
--- a/browser/base/content/browser-syncui.js
+++ b/browser/base/content/browser-syncui.js
@@ -132,25 +132,25 @@ var gSyncUI = {
     // Otherwise we are configured for legacy Sync, which has no verification
     // concept.
     return Promise.resolve(false);
   },
 
   // Note that we don't show login errors in a notification bar here, but do
   // still need to track a login-failed state so the "Tools" menu updates
   // with the correct state.
-  _loginFailed() {
+  loginFailed() {
     // If Sync isn't already ready, we don't want to force it to initialize
     // by referencing Weave.Status - and it isn't going to be accurate before
     // Sync is ready anyway.
     if (!this.weaveService.ready) {
-      this.log.debug("_loginFailed has sync not ready, so returning false");
+      this.log.debug("loginFailed has sync not ready, so returning false");
       return false;
     }
-    this.log.debug("_loginFailed has sync state=${sync}",
+    this.log.debug("loginFailed has sync state=${sync}",
                    { sync: Weave.Status.login});
     return Weave.Status.login == Weave.LOGIN_FAILED_LOGIN_REJECTED;
   },
 
   // Kick off an update of the UI - does *not* return a promise.
   updateUI() {
     this._promiseUpdateUI().catch(err => {
       this.log.error("updateUI failed", err);
@@ -158,17 +158,17 @@ var gSyncUI = {
   },
 
   // Updates the UI - returns a promise.
   _promiseUpdateUI() {
     return this._needsSetup().then(needsSetup => {
       if (!gBrowser)
         return Promise.resolve();
 
-      let loginFailed = this._loginFailed();
+      let loginFailed = this.loginFailed();
 
       // Start off with a clean slate
       document.getElementById("sync-reauth-state").hidden = true;
       document.getElementById("sync-setup-state").hidden = true;
       document.getElementById("sync-syncnow-state").hidden = true;
 
       if (CloudSync && CloudSync.ready && CloudSync().adapters.count) {
         document.getElementById("sync-syncnow-state").hidden = false;
@@ -261,17 +261,17 @@ var gSyncUI = {
     });
   },
 
   // Handle clicking the toolbar button - which either opens the Sync setup
   // pages or forces a sync now. Does *not* return a promise as it is called
   // via the UI.
   handleToolbarButton() {
     this._needsSetup().then(needsSetup => {
-      if (needsSetup || this._loginFailed()) {
+      if (needsSetup || this.loginFailed()) {
         this.openSetup();
       } else {
         this.doSync();
       }
     }).catch(err => {
       this.log.error("Failed to handle toolbar button command", err);
     });
   },
@@ -375,17 +375,17 @@ var gSyncUI = {
 
     let email;
     try {
       email = Services.prefs.getCharPref("services.sync.username");
     } catch (ex) {}
 
     let needsSetup = yield this._needsSetup();
     let needsVerification = yield this._needsVerification();
-    let loginFailed = this._loginFailed();
+    let loginFailed = this.loginFailed();
     // This is a little messy as the Sync buttons are 1/2 Sync related and
     // 1/2 FxA related - so for some strings we use Sync strings, but for
     // others we reach into gFxAccounts for strings.
     let tooltiptext;
     if (needsVerification) {
       // "needs verification"
       tooltiptext = gFxAccounts.strings.formatStringFromName("verifyDescription", [email], 1);
     } else if (needsSetup) {
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -469,16 +469,19 @@
       <menuseparator/>
       <menuitem label="&syncedTabs.context.bookmarkSingleTab.label;"
                 accesskey="&syncedTabs.context.bookmarkSingleTab.accesskey;"
                 id="syncedTabsBookmarkSelected"/>
       <menuitem label="&syncedTabs.context.copy.label;"
                 accesskey="&syncedTabs.context.copy.accesskey;"
                 id="syncedTabsCopySelected"/>
       <menuseparator/>
+      <menuitem label="&syncedTabs.context.openAllInTabs.label;"
+                accesskey="&syncedTabs.context.openAllInTabs.accesskey;"
+                id="syncedTabsOpenAllInTabs"/>
       <menuitem label="&syncSyncNowItem.label;"
                 accesskey="&syncSyncNowItem.accesskey;"
                 id="syncedTabsRefresh"/>
     </menupopup>
     <menupopup id="SyncedTabsSidebarTabsFilterContext"
                class="textbox-contextmenu">
       <menuitem label="&undoCmd.label;"
                 accesskey="&undoCmd.accesskey;"
--- a/browser/components/customizableui/CustomizableUI.jsm
+++ b/browser/components/customizableui/CustomizableUI.jsm
@@ -33,16 +33,17 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 const kSpecialWidgetPfx = "customizableui-special-";
 
 const kPrefCustomizationState        = "browser.uiCustomization.state";
 const kPrefCustomizationAutoAdd      = "browser.uiCustomization.autoAdd";
 const kPrefCustomizationDebug        = "browser.uiCustomization.debug";
 const kPrefDrawInTitlebar            = "browser.tabs.drawInTitlebar";
+const kPrefSelectedThemeID           = "lightweightThemes.selectedThemeID";
 const kPrefWebIDEInNavbar            = "devtools.webide.widget.inNavbarByDefault";
 
 const kExpectedWindowURL = "chrome://browser/content/browser.xul";
 
 /**
  * The keys are the handlers that are fired when the event type (the value)
  * is fired on the subview. A widget that provides a subview has the option
  * of providing onViewShowing and onViewHiding event handlers.
@@ -1915,25 +1916,17 @@ var CustomizableUIInternal = {
   // Note that this does not populate gPlacements, which is done lazily so that
   // the legacy state can be migrated, which is only available once a browser
   // window is openned.
   // The panel area is an exception here, since it has no legacy state and is
   // built lazily - and therefore wouldn't otherwise result in restoring its
   // state immediately when a browser window opens, which is important for
   // other consumers of this API.
   loadSavedState() {
-    let state = null;
-    try {
-      state = Services.prefs.getCharPref(kPrefCustomizationState);
-    } catch (e) {
-      log.debug("No saved state found");
-      // This will fail if nothing has been customized, so silently fall back to
-      // the defaults.
-    }
-
+    let state = Services.prefs.getCharPref(kPrefCustomizationState);
     if (!state) {
       return;
     }
     try {
       gSavedState = JSON.parse(state);
       if (typeof gSavedState != "object" || gSavedState === null) {
         throw "Invalid saved state";
       }
@@ -2509,28 +2502,28 @@ var CustomizableUIInternal = {
     if (gSeenWidgets.size) {
       gDirty = true;
     }
 
     gResetting = false;
   },
 
   _resetUIState() {
-    try {
-      gUIStateBeforeReset.drawInTitlebar = Services.prefs.getBoolPref(kPrefDrawInTitlebar);
-      gUIStateBeforeReset.uiCustomizationState = Services.prefs.getCharPref(kPrefCustomizationState);
-      gUIStateBeforeReset.currentTheme = LightweightThemeManager.currentTheme;
-    } catch (e) { }
-
     this._resetExtraToolbars();
 
-    Services.prefs.clearUserPref(kPrefCustomizationState);
+    gUIStateBeforeReset.selectedThemeID = Services.prefs.getCharPref(kPrefSelectedThemeID);
+    let selectedThemeID = Services.prefs.getDefaultBranch("").getCharPref(kPrefSelectedThemeID);
+    LightweightThemeManager.currentTheme =
+      selectedThemeID ? LightweightThemeManager.getUsedTheme(selectedThemeID) : null;
+
+    gUIStateBeforeReset.drawInTitlebar = Services.prefs.getBoolPref(kPrefDrawInTitlebar);
     Services.prefs.clearUserPref(kPrefDrawInTitlebar);
-    LightweightThemeManager.currentTheme = null;
-    log.debug("State reset");
+
+    gUIStateBeforeReset.uiCustomizationState = Services.prefs.getCharPref(kPrefCustomizationState);
+    Services.prefs.clearUserPref(kPrefCustomizationState);
 
     // Reset placements to make restoring default placements possible.
     gPlacements = new Map();
     gDirtyAreaCache = new Set();
     gSeenWidgets = new Set();
     // Clear the saved state to ensure that defaults will be used.
     gSavedState = null;
     // Restore the state for each area to its defaults
@@ -2588,25 +2581,26 @@ var CustomizableUIInternal = {
     if (gUIStateBeforeReset.uiCustomizationState == null ||
         gUIStateBeforeReset.drawInTitlebar == null) {
       return;
     }
     gUndoResetting = true;
 
     let uiCustomizationState = gUIStateBeforeReset.uiCustomizationState;
     let drawInTitlebar = gUIStateBeforeReset.drawInTitlebar;
-    let currentTheme = gUIStateBeforeReset.currentTheme;
+    let selectedThemeID = gUIStateBeforeReset.selectedThemeID;
 
     // Need to clear the previous state before setting the prefs
     // because pref observers may check if there is a previous UI state.
     this._clearPreviousUIState();
 
     Services.prefs.setCharPref(kPrefCustomizationState, uiCustomizationState);
     Services.prefs.setBoolPref(kPrefDrawInTitlebar, drawInTitlebar);
-    LightweightThemeManager.currentTheme = currentTheme;
+    LightweightThemeManager.currentTheme =
+      selectedThemeID ? LightweightThemeManager.getUsedTheme(selectedThemeID) : null;
     this.loadSavedState();
     // If the user just customizes toolbar/titlebar visibility, gSavedState will be null
     // and we don't need to do anything else here:
     if (gSavedState) {
       for (let areaId of Object.keys(gSavedState.placements)) {
         let placements = gSavedState.placements[areaId];
         gPlacements.set(areaId, placements);
       }
@@ -2775,18 +2769,19 @@ var CustomizableUIInternal = {
       }
     }
 
     if (Services.prefs.prefHasUserValue(kPrefDrawInTitlebar)) {
       log.debug(kPrefDrawInTitlebar + " pref is non-default");
       return false;
     }
 
-    if (LightweightThemeManager.currentTheme) {
-      log.debug(LightweightThemeManager.currentTheme + " theme is non-default");
+    if (Services.prefs.getDefaultBranch("").getCharPref(kPrefSelectedThemeID) !=
+        Services.prefs.getCharPref(kPrefSelectedThemeID)) {
+      log.debug(kPrefSelectedThemeID + " pref is non-default");
       return false;
     }
 
     return true;
   },
 
   setToolbarVisibility(aToolbarId, aIsVisible) {
     // We only persist the attribute the first time.
--- a/browser/components/distribution.js
+++ b/browser/components/distribution.js
@@ -431,18 +431,18 @@ DistributionCustomizer.prototype = {
         }
         try {
           let value = this._ini.getString("LocalizablePreferences", key);
           if (value) {
             value = parseValue(value);
             value = value.replace(/%LOCALE%/g, this._locale);
             value = value.replace(/%LANGUAGE%/g, this._language);
             localizedStr.data = "data:text/plain," + key + "=" + value;
+            defaults._prefBranch.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedStr);
           }
-          defaults._prefBranch.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedStr);
         } catch (e) { /* ignore bad prefs and move on */ }
       }
     }
 
     return this._checkCustomizationComplete();
   },
 
   _checkCustomizationComplete: function DIST__checkCustomizationComplete() {
--- a/browser/components/extensions/ext-utils.js
+++ b/browser/components/extensions/ext-utils.js
@@ -705,16 +705,25 @@ ExtensionTabManager.prototype = {
       windowId: WindowManager.getId(window),
       selected: false,
       highlighted: false,
       active: false,
       pinned: false,
       incognito: Boolean(tab.state && tab.state.isPrivate),
     };
 
+    if (this.hasTabPermission(tab)) {
+      let entries = tab.state ? tab.state.entries : tab.entries;
+      result.url = entries[0].url;
+      result.title = entries[0].title;
+      if (tab.image) {
+        result.favIconUrl = tab.image;
+      }
+    }
+
     return result;
   },
 
   getTabs(window) {
     return Array.from(window.gBrowser.tabs)
                 .filter(tab => !tab.closing)
                 .map(tab => this.convert(tab));
   },
--- a/browser/components/extensions/test/browser/browser-common.ini
+++ b/browser/components/extensions/test/browser/browser-common.ini
@@ -58,16 +58,17 @@ support-files =
 [browser_ext_popup_corners.js]
 [browser_ext_popup_sendMessage.js]
 [browser_ext_popup_shutdown.js]
 [browser_ext_runtime_openOptionsPage.js]
 [browser_ext_runtime_openOptionsPage_uninstall.js]
 [browser_ext_runtime_setUninstallURL.js]
 [browser_ext_sessions_getRecentlyClosed.js]
 [browser_ext_sessions_getRecentlyClosed_private.js]
+[browser_ext_sessions_getRecentlyClosed_tabs.js]
 [browser_ext_sessions_restore.js]
 [browser_ext_simple.js]
 [browser_ext_tab_runtimeConnect.js]
 [browser_ext_tabs_audio.js]
 [browser_ext_tabs_captureVisibleTab.js]
 [browser_ext_tabs_create.js]
 [browser_ext_tabs_create_invalid_url.js]
 [browser_ext_tabs_detectLanguage.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_sessions_getRecentlyClosed_tabs.js
@@ -0,0 +1,96 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+function expectedTabInfo(tab, window) {
+  let browser = tab.linkedBrowser;
+  return {
+    url: browser.currentURI.spec,
+    title: browser.contentTitle,
+    favIconUrl: window.gBrowser.getIcon(tab),
+  };
+}
+
+function checkTabInfo(expected, actual) {
+  for (let prop in expected) {
+    is(actual[prop], expected[prop], `Expected value found for ${prop} of tab object.`);
+  }
+}
+
+add_task(async function test_sessions_get_recently_closed_tabs() {
+  async function background() {
+    browser.test.onMessage.addListener(async msg => {
+      if (msg == "check-sessions") {
+        let recentlyClosed = await browser.sessions.getRecentlyClosed();
+        browser.test.sendMessage("recentlyClosed", recentlyClosed);
+      }
+    });
+  }
+
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      permissions: ["sessions", "tabs"],
+    },
+    background,
+  });
+
+  let win = await BrowserTestUtils.openNewBrowserWindow();
+  await BrowserTestUtils.loadURI(win.gBrowser.selectedBrowser, "about:addons");
+  await BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
+  let expectedTabs = [];
+  let tab = win.gBrowser.selectedTab;
+  expectedTabs.push(expectedTabInfo(tab, win));
+
+  for (let url of ["about:robots", "about:mozilla"]) {
+    tab = await BrowserTestUtils.openNewForegroundTab(win.gBrowser, url);
+    expectedTabs.push(expectedTabInfo(tab, win));
+  }
+
+  await extension.startup();
+
+  // Test with a closed tab.
+  await BrowserTestUtils.removeTab(tab);
+
+  extension.sendMessage("check-sessions");
+  let recentlyClosed = await extension.awaitMessage("recentlyClosed");
+  let tabInfo = recentlyClosed[0].tab;
+  let expectedTab = expectedTabs.pop();
+  checkTabInfo(expectedTab, tabInfo);
+
+  // Test with a closed window containing tabs.
+  await BrowserTestUtils.closeWindow(win);
+
+  extension.sendMessage("check-sessions");
+  recentlyClosed = await extension.awaitMessage("recentlyClosed");
+  let tabInfos = recentlyClosed[0].window.tabs;
+  is(tabInfos.length, 2, "Expected number of tabs in closed window.");
+  for (let x = 0; x < tabInfos.length; x++) {
+    checkTabInfo(expectedTabs[x], tabInfos[x]);
+  }
+
+  await extension.unload();
+
+  // Test without tabs permission.
+  extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      permissions: ["sessions"],
+    },
+    background,
+  });
+
+  await extension.startup();
+
+  extension.sendMessage("check-sessions");
+  recentlyClosed = await extension.awaitMessage("recentlyClosed");
+  tabInfos = recentlyClosed[0].window.tabs;
+  is(tabInfos.length, 2, "Expected number of tabs in closed window.");
+  for (let tabInfo of tabInfos) {
+    for (let prop in expectedTabs[0]) {
+      is(undefined,
+         tabInfo[prop],
+         `${prop} of tab object is undefined without tabs permission.`);
+    }
+  }
+
+  await extension.unload();
+});
--- a/browser/components/preferences/in-content/tests/browser_advanced_siteData.js
+++ b/browser/components/preferences/in-content/tests/browser_advanced_siteData.js
@@ -31,28 +31,52 @@ const mockOfflineAppCacheHelper = {
   unregister() {
     OfflineAppCacheHelper.clear = this.originalClear;
   }
 };
 
 const mockSiteDataManager = {
   sites: new Map([
     [
+      "https://account.xyz.com/",
+      {
+        usage: 1024 * 200,
+        host: "account.xyz.com",
+        status: Ci.nsIPermissionManager.ALLOW_ACTION
+      }
+    ],
+    [
       "https://shopping.xyz.com/",
       {
-        usage: 102400,
+        usage: 1024 * 100,
         host: "shopping.xyz.com",
+        status: Ci.nsIPermissionManager.DENY_ACTION
+      }
+    ],
+    [
+      "https://video.bar.com/",
+      {
+        usage: 1024 * 20,
+        host: "video.bar.com",
         status: Ci.nsIPermissionManager.ALLOW_ACTION
       }
     ],
     [
       "https://music.bar.com/",
       {
-        usage: 10240,
+        usage: 1024 * 10,
         host: "music.bar.com",
+        status: Ci.nsIPermissionManager.DENY_ACTION
+      }
+    ],
+    [
+      "https://books.foo.com/",
+      {
+        usage: 1024 * 2,
+        host: "books.foo.com",
         status: Ci.nsIPermissionManager.ALLOW_ACTION
       }
     ],
     [
       "https://news.foo.com/",
       {
         usage: 1024,
         host: "news.foo.com",
@@ -299,8 +323,54 @@ add_task(function* () {
         Assert.lessOrEqual(result, 0, "Should sort sites in the ascending order by usage");
       } else {
         Assert.greaterOrEqual(result, 0, "Should sort sites in the descending order by usage");
       }
     }
   }
 });
 
+add_task(function* () {
+  yield SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
+
+  mockSiteDataManager.register();
+  let updatePromise = promiseSitesUpdated();
+  yield openPreferencesViaOpenPreferencesAPI("advanced", "networkTab", { leaveOpen: true });
+  yield updatePromise;
+
+  // Open the siteDataSettings subdialog
+  let doc = gBrowser.selectedBrowser.contentDocument;
+  let settingsBtn = doc.getElementById("siteDataSettings");
+  let dialogOverlay = doc.getElementById("dialogOverlay");
+  let dialogPromise = promiseLoadSubDialog("chrome://browser/content/preferences/siteDataSettings.xul");
+  settingsBtn.doCommand();
+  yield dialogPromise;
+  is(dialogOverlay.style.visibility, "visible", "The dialog should be visible");
+
+  let frameDoc = doc.getElementById("dialogFrame").contentDocument;
+  let searchBox = frameDoc.getElementById("searchBox");
+  let mockOrigins = Array.from(mockSiteDataManager.sites.keys());
+
+  searchBox.value = "xyz";
+  searchBox.doCommand();
+  assertSitesListed(mockOrigins.filter(o => o.includes("xyz")));
+
+  searchBox.value = "bar";
+  searchBox.doCommand();
+  assertSitesListed(mockOrigins.filter(o => o.includes("bar")));
+
+  searchBox.value = "";
+  searchBox.doCommand();
+  assertSitesListed(mockOrigins);
+
+  mockSiteDataManager.unregister();
+  yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
+
+  function assertSitesListed(origins) {
+    let sitesList = frameDoc.getElementById("sitesList");
+    let totalSitesNumber = sitesList.getElementsByTagName("richlistitem").length;
+    is(totalSitesNumber, origins.length, "Should list the right sites number");
+    origins.forEach(origin => {
+      let site = sitesList.querySelector(`richlistitem[data-origin="${origin}"]`);
+      ok(site instanceof XULElement, `Should list the site of ${origin}`);
+    });
+  }
+});
--- a/browser/components/preferences/siteDataSettings.css
+++ b/browser/components/preferences/siteDataSettings.css
@@ -1,12 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#searchBoxContainer {
+  -moz-box-align: center;
+}
+
 #sitesList {
   min-height: 20em;
 }
 
 #sitesList > richlistitem {
   -moz-binding: url("chrome://browser/content/preferences/siteListItem.xml#siteListItem");
 }
 
--- a/browser/components/preferences/siteDataSettings.js
+++ b/browser/components/preferences/siteDataSettings.js
@@ -18,34 +18,37 @@ let gSiteDataSettings = {
 
   // Array of meatdata of sites. Each array element is object holding:
   // - uri: uri of site; instance of nsIURI
   // - status: persistent-storage permission status
   // - usage: disk usage which site uses
   _sites: null,
 
   _list: null,
+  _searchBox: null,
 
   init() {
     function setEventListener(id, eventType, callback) {
       document.getElementById(id)
               .addEventListener(eventType, callback.bind(gSiteDataSettings));
     }
 
     this._list = document.getElementById("sitesList");
+    this._searchBox = document.getElementById("searchBox");
     SiteDataManager.getSites().then(sites => {
       this._sites = sites;
       let sortCol = document.getElementById("hostCol");
       this._sortSites(this._sites, sortCol);
       this._buildSitesList(this._sites);
     });
 
     setEventListener("hostCol", "click", this.onClickTreeCol);
     setEventListener("usageCol", "click", this.onClickTreeCol);
     setEventListener("statusCol", "click", this.onClickTreeCol);
+    setEventListener("searchBox", "command", this.onCommandSearch);
   },
 
   /**
    * @param sites {Array}
    * @param col {XULElement} the <treecol> being sorted on
    */
   _sortSites(sites, col) {
     let isCurrentSortCol = col.getAttribute("data-isCurrentSortCol")
@@ -84,32 +87,46 @@ let gSiteDataSettings = {
       c.removeAttribute("sortDirection");
       c.removeAttribute("data-isCurrentSortCol");
     });
     col.setAttribute("data-isCurrentSortCol", true);
     col.setAttribute("sortDirection", sortDirection);
     col.setAttribute("data-last-sortDirection", sortDirection);
   },
 
+  /**
+   * @param sites {Array} array of metadata of sites
+   */
   _buildSitesList(sites) {
     // Clear old entries.
-    while (this._list.childNodes.length > 1) {
-      this._list.removeChild(this._list.lastChild);
+    let oldItems = this._list.querySelectorAll("richlistitem");
+    for (let item of oldItems) {
+      item.remove();
     }
 
     let prefStrBundle = document.getElementById("bundlePreferences");
+    let keyword = this._searchBox.value.toLowerCase().trim();
     for (let data of sites) {
+      let host = data.uri.host;
+      if (keyword && !host.includes(keyword)) {
+        continue;
+      }
+
       let statusStrId = data.status === Ci.nsIPermissionManager.ALLOW_ACTION ? "important" : "default";
       let size = DownloadUtils.convertByteUnits(data.usage);
       let item = document.createElement("richlistitem");
       item.setAttribute("data-origin", data.uri.spec);
-      item.setAttribute("host", data.uri.host);
+      item.setAttribute("host", host);
       item.setAttribute("status", prefStrBundle.getString(statusStrId));
       item.setAttribute("usage", prefStrBundle.getFormattedString("siteUsage", size));
       this._list.appendChild(item);
     }
   },
 
   onClickTreeCol(e) {
     this._sortSites(this._sites, e.target);
     this._buildSitesList(this._sites);
+  },
+
+  onCommandSearch() {
+    this._buildSitesList(this._sites);
   }
 };
--- a/browser/components/preferences/siteDataSettings.xul
+++ b/browser/components/preferences/siteDataSettings.xul
@@ -21,16 +21,22 @@
 
   <stringbundle id="bundlePreferences"
                 src="chrome://browser/locale/preferences/preferences.properties"/>
 
   <vbox flex="1">
     <description>&settings.description;</description>
     <separator class="thin"/>
 
+    <hbox id="searchBoxContainer">
+      <label accesskey="&search.accesskey;" control="searchBox">&search.label;</label>
+      <textbox id="searchBox" type="search" flex="1"/>
+    </hbox>
+    <separator class="thin"/>
+
     <richlistbox id="sitesList" orient="vertical" flex="1">
       <listheader>
         <treecol flex="4" width="50" label="&hostCol.label;" id="hostCol"/>
         <treecol flex="2" width="50" label="&statusCol.label;" id="statusCol"/>
         <treecol flex="1" width="50" label="&usageCol.label;" id="usageCol"/>
       </listheader>
     </richlistbox>
   </vbox>
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -3608,17 +3608,17 @@ var SessionStoreInternal = {
    * @param aTab
    *        the tab to restore
    * @param aLoadArguments
    *        optional load arguments used for loadURI()
    * @param aReloadInFreshProcess
    *        true if we want to reload into a fresh process
    */
   restoreTabContent: function (aTab, aLoadArguments = null, aReloadInFreshProcess = false) {
-    if (aTab.hasAttribute("customizemode")) {
+    if (aTab.hasAttribute("customizemode") && !aLoadArguments) {
       return;
     }
 
     let browser = aTab.linkedBrowser;
     let window = aTab.ownerGlobal;
     let tabbrowser = window.gBrowser;
     let tabData = TabState.clone(aTab);
     let activeIndex = tabData.index - 1;
--- a/browser/components/syncedtabs/SyncedTabsDeckComponent.js
+++ b/browser/components/syncedtabs/SyncedTabsDeckComponent.js
@@ -67,16 +67,17 @@ SyncedTabsDeckComponent.prototype = {
 
   get container() {
     return this._deckView ? this._deckView.container : null;
   },
 
   init() {
     Services.obs.addObserver(this, this._SyncedTabs.TOPIC_TABS_CHANGED, false);
     Services.obs.addObserver(this, FxAccountsCommon.ONLOGIN_NOTIFICATION, false);
+    Services.obs.addObserver(this, "weave:service:login:change", false);
 
     // Go ahead and trigger sync
     this._SyncedTabs.syncTabs()
                     .catch(Cu.reportError);
 
     this._deckView = new this._DeckView(this._window, this.tabListComponent, {
       onAndroidClick: event => this.openAndroidLink(event),
       oniOSClick: event => this.openiOSLink(event),
@@ -89,42 +90,44 @@ SyncedTabsDeckComponent.prototype = {
     this._deckStore.setPanels(Object.keys(this.PANELS).map(k => this.PANELS[k]));
     // Set the initial panel to display
     this.updatePanel();
   },
 
   uninit() {
     Services.obs.removeObserver(this, this._SyncedTabs.TOPIC_TABS_CHANGED);
     Services.obs.removeObserver(this, FxAccountsCommon.ONLOGIN_NOTIFICATION);
+    Services.obs.removeObserver(this, "weave:service:login:change");
     this._deckView.destroy();
   },
 
   observe(subject, topic, data) {
     switch (topic) {
       case this._SyncedTabs.TOPIC_TABS_CHANGED:
         this._syncedTabsListStore.getData();
         this.updatePanel();
         break;
       case FxAccountsCommon.ONLOGIN_NOTIFICATION:
+      case "weave:service:login:change":
         this.updatePanel();
         break;
       default:
         break;
     }
   },
 
   // There's no good way to mock fxAccounts in browser tests where it's already
   // been instantiated, so we have this method for stubbing.
   _accountStatus() {
     return this._fxAccounts.accountStatus();
   },
 
   getPanelStatus() {
     return this._accountStatus().then(exists => {
-      if (!exists) {
+      if (!exists || this._getChromeWindow(this._window).gSyncUI.loginFailed()) {
         return this.PANELS.NOT_AUTHED_INFO;
       }
       if (!this._SyncedTabs.isConfiguredToSyncTabs) {
         return this.PANELS.TABS_DISABLED;
       }
       if (!this._SyncedTabs.hasSyncedThisSession) {
         return this.PANELS.TABS_FETCHING;
       }
--- a/browser/components/syncedtabs/TabListView.js
+++ b/browser/components/syncedtabs/TabListView.js
@@ -282,19 +282,17 @@ TabListView.prototype = {
         this.onOpenSelected(url, event);
       }
     }
 
     // Middle click on a client
     if (itemNode.classList.contains("client")) {
       let where = getChromeWindow(this._window).whereToOpenLink(event);
       if (where != "current") {
-        const tabs = itemNode.querySelector(".item-tabs-list").childNodes;
-        const urls = [...tabs].map(tab => tab.dataset.url);
-        this.props.onOpenTabs(urls, where);
+        this._openAllClientTabs(itemNode, where);
       }
     }
 
     if (event.target.classList.contains("item-twisty-container")
         && event.which != 2) {
       this.props.onToggleBranch(itemNode.dataset.id);
       return;
     }
@@ -350,16 +348,23 @@ TabListView.prototype = {
       let where = event.target.getAttribute("where");
       let params = {
         private: event.target.hasAttribute("private"),
       };
       this.props.onOpenTab(item.dataset.url, where, params);
     }
   },
 
+  onOpenAllInTabs() {
+    let item = this._getSelectedClientNode();
+    if (item) {
+      this._openAllClientTabs(item, "tab");
+    }
+  },
+
   onFilter(event) {
     let query = event.target.value;
     if (query) {
       this.props.onFilter(query);
     } else {
       this.props.onClearFilter();
     }
   },
@@ -378,16 +383,24 @@ TabListView.prototype = {
   _getSelectedTabNode() {
     let item = this.container.querySelector('.item.selected');
     if (this._isTab(item) && item.dataset.url) {
       return item;
     }
     return null;
   },
 
+  _getSelectedClientNode() {
+    let item = this.container.querySelector('.item.selected');
+    if (this._isClient(item)) {
+      return item;
+    }
+    return null;
+  },
+
   // Set up the custom context menu
   _setupContextMenu() {
     Services.els.addSystemEventListener(this._window, "contextmenu", this, false);
     for (let getMenu of [getContextMenu, getTabsFilterContextMenu]) {
       let menu = getMenu(this._window);
       menu.addEventListener("popupshowing", this, true);
       menu.addEventListener("command", this, true);
     }
@@ -456,16 +469,19 @@ TabListView.prototype = {
     let id = event.target.getAttribute("id");
     switch (id) {
       case "syncedTabsOpenSelected":
       case "syncedTabsOpenSelectedInTab":
       case "syncedTabsOpenSelectedInWindow":
       case "syncedTabsOpenSelectedInPrivateWindow":
         this.onOpenSelectedFromContextMenu(event);
         break;
+      case "syncedTabsOpenAllInTabs":
+        this.onOpenAllInTabs();
+        break;
       case "syncedTabsBookmarkSelected":
         this.onBookmarkTab();
         break;
       case "syncedTabsCopySelected":
         this.onCopyTabLocation();
         break;
       case "syncedTabsRefresh":
       case "syncedTabsRefreshFilter":
@@ -501,21 +517,28 @@ TabListView.prototype = {
 
   adjustContextMenu(menu) {
     let item = this.container.querySelector('.item.selected');
     let showTabOptions = this._isTab(item);
 
     let el = menu.firstChild;
 
     while (el) {
-      if (showTabOptions || el.getAttribute("id") === "syncedTabsRefresh") {
-        el.hidden = false;
-      } else {
-        el.hidden = true;
+      let show = false;
+      if (showTabOptions) {
+        if (el.getAttribute("id") != "syncedTabsOpenAllInTabs") {
+          show = true;
+        }
+      } else if (el.getAttribute("id") == "syncedTabsOpenAllInTabs") {
+        const tabs = item.querySelectorAll(".item-tabs-list > .item.tab");
+        show = tabs.length > 0;
+      } else if (el.getAttribute("id") == "syncedTabsRefresh") {
+        show = true;
       }
+      el.hidden = !show;
 
       el = el.nextSibling;
     }
   },
 
   /**
    * Find the parent item element, from a given child element.
    * @param {Element} node - Child element.
@@ -559,10 +582,20 @@ TabListView.prototype = {
   },
 
   _indexOfNode(parent, child) {
     return Array.prototype.indexOf.call(parent.childNodes, child);
   },
 
   _isTab(item) {
     return item && item.classList.contains("tab");
+  },
+
+  _isClient(item) {
+    return item && item.classList.contains("client");
+  },
+
+  _openAllClientTabs(clientNode, where) {
+    const tabs = clientNode.querySelector(".item-tabs-list").childNodes;
+    const urls = [...tabs].map(tab => tab.dataset.url);
+    this.props.onOpenTabs(urls, where);
   }
 };
--- a/browser/components/syncedtabs/test/browser/browser_sidebar_syncedtabslist.js
+++ b/browser/components/syncedtabs/test/browser/browser_sidebar_syncedtabslist.js
@@ -305,39 +305,59 @@ add_task(function* testSyncedTabsSidebar
     ["menuitem#syncedTabsOpenSelected", { hidden: false }],
     ["menuitem#syncedTabsOpenSelectedInTab", { hidden: false }],
     ["menuitem#syncedTabsOpenSelectedInWindow", { hidden: false }],
     ["menuitem#syncedTabsOpenSelectedInPrivateWindow", { hidden: false }],
     ["menuseparator", { hidden: false }],
     ["menuitem#syncedTabsBookmarkSelected", { hidden: false }],
     ["menuitem#syncedTabsCopySelected", { hidden: false }],
     ["menuseparator", { hidden: false }],
+    ["menuitem#syncedTabsOpenAllInTabs", { hidden: true }],
     ["menuitem#syncedTabsRefresh", { hidden: false }],
   ];
   yield* testContextMenu(syncedTabsDeckComponent,
                          "#SyncedTabsSidebarContext",
                          "#tab-7cqCr77ptzX3-0",
                          tabMenuItems);
 
-  info("Right-clicking a client shouldn't show any actions");
+  info("Right-clicking a client should show the Open All in Tabs action");
   let sidebarMenuItems = [
     ["menuitem#syncedTabsOpenSelected", { hidden: true }],
     ["menuitem#syncedTabsOpenSelectedInTab", { hidden: true }],
     ["menuitem#syncedTabsOpenSelectedInWindow", { hidden: true }],
     ["menuitem#syncedTabsOpenSelectedInPrivateWindow", { hidden: true }],
     ["menuseparator", { hidden: true }],
     ["menuitem#syncedTabsBookmarkSelected", { hidden: true }],
     ["menuitem#syncedTabsCopySelected", { hidden: true }],
     ["menuseparator", { hidden: true }],
+    ["menuitem#syncedTabsOpenAllInTabs", { hidden: false }],
+    ["menuitem#syncedTabsRefresh", { hidden: false }],
+  ];
+  yield* testContextMenu(syncedTabsDeckComponent,
+                         "#SyncedTabsSidebarContext",
+                         "#item-7cqCr77ptzX3",
+                         sidebarMenuItems);
+
+  info("Right-clicking a client without any tabs should not show the Open All in Tabs action");
+  let menuItems = [
+    ["menuitem#syncedTabsOpenSelected", { hidden: true }],
+    ["menuitem#syncedTabsOpenSelectedInTab", { hidden: true }],
+    ["menuitem#syncedTabsOpenSelectedInWindow", { hidden: true }],
+    ["menuitem#syncedTabsOpenSelectedInPrivateWindow", { hidden: true }],
+    ["menuseparator", { hidden: true }],
+    ["menuitem#syncedTabsBookmarkSelected", { hidden: true }],
+    ["menuitem#syncedTabsCopySelected", { hidden: true }],
+    ["menuseparator", { hidden: true }],
+    ["menuitem#syncedTabsOpenAllInTabs", { hidden: true }],
     ["menuitem#syncedTabsRefresh", { hidden: false }],
   ];
   yield* testContextMenu(syncedTabsDeckComponent,
                          "#SyncedTabsSidebarContext",
                          "#item-OL3EJCsdb2JD",
-                         sidebarMenuItems);
+                         menuItems);
 });
 
 add_task(testClean);
 
 function checkItem(node, item) {
   Assert.ok(node.classList.contains("item"),
     "Node should have .item class");
   if (item.client) {
--- a/browser/components/syncedtabs/test/xpcshell/test_SyncedTabsDeckComponent.js
+++ b/browser/components/syncedtabs/test/xpcshell/test_SyncedTabsDeckComponent.js
@@ -117,46 +117,68 @@ add_task(function* testObserver() {
   Assert.ok(listStore.getData.called, "gets list data");
   Assert.ok(component.updatePanel.calledTwice, "triggers panel update");
 
   Services.obs.notifyObservers(null, FxAccountsCommon.ONLOGIN_NOTIFICATION, "");
 
   Assert.ok(component.observe.calledWith(null, FxAccountsCommon.ONLOGIN_NOTIFICATION, ""),
     "component is notified of login");
   Assert.equal(component.updatePanel.callCount, 3, "triggers panel update again");
+
+  Services.obs.notifyObservers(null, "weave:service:login:change", "");
+
+  Assert.ok(component.observe.calledWith(null, "weave:service:login:change", ""),
+    "component is notified of login change");
+  Assert.equal(component.updatePanel.callCount, 4, "triggers panel update again");
 });
 
 add_task(function* testPanelStatus() {
   let deckStore = new SyncedTabsDeckStore();
   let listStore = new SyncedTabsListStore();
   let listComponent = {};
   let fxAccounts = {
     accountStatus() {}
   };
   let SyncedTabsMock = {
     getTabClients() {}
   };
+  let loginFailed = false;
+  let chromeWindowMock = {
+    gSyncUI: {
+      loginFailed() {
+        return loginFailed;
+      }
+    }
+  };
+  let getChromeWindowMock = sinon.stub();
+  getChromeWindowMock.returns(chromeWindowMock);
 
   sinon.stub(listStore, "getData");
 
 
   let component = new SyncedTabsDeckComponent({
     fxAccounts,
     deckStore,
     listComponent,
     SyncedTabs: SyncedTabsMock,
+    getChromeWindowMock
   });
 
   let isAuthed = false;
   sinon.stub(fxAccounts, "accountStatus", () => Promise.resolve(isAuthed));
   let result = yield component.getPanelStatus();
   Assert.equal(result, component.PANELS.NOT_AUTHED_INFO);
 
   isAuthed = true;
 
+  loginFailed = true;
+  result = yield component.getPanelStatus();
+  Assert.equal(result, component.PANELS.NOT_AUTHED_INFO);
+  loginFailed = false;
+
   SyncedTabsMock.isConfiguredToSyncTabs = false;
   result = yield component.getPanelStatus();
   Assert.equal(result, component.PANELS.TABS_DISABLED);
 
   SyncedTabsMock.isConfiguredToSyncTabs = true;
 
   SyncedTabsMock.hasSyncedThisSession = false;
   result = yield component.getPanelStatus();
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -751,29 +751,36 @@ you can use these alternative items. Oth
 <!ENTITY syncedTabs.sidebar.noclients.subtitle "Want to see your tabs from other devices here?">
 <!ENTITY syncedTabs.sidebar.notsignedin.label  "Sign in to view a list of tabs from your other devices.">
 <!ENTITY syncedTabs.sidebar.notabs.label       "No open tabs">
 <!ENTITY syncedTabs.sidebar.openprefs.label    "Open &syncBrand.shortName.label; Preferences">
 <!-- LOCALIZATION NOTE (syncedTabs.sidebar.tabsnotsyncing.label): This is shown
      when Sync is configured but syncing tabs is disabled. -->
 <!ENTITY syncedTabs.sidebar.tabsnotsyncing.label       "Turn on tab syncing to view a list of tabs from your other devices.">
 
+<!-- LOCALIZATION NOTE (syncedTabs.context.open.accesskey,
+                        syncedTabs.context.openAllInTabs.accesskey):
+     These access keys are identical because their associated menu items are
+     mutually exclusive -->
 <!ENTITY syncedTabs.context.open.label                       "Open">
 <!ENTITY syncedTabs.context.open.accesskey                   "O">
 <!ENTITY syncedTabs.context.openInNewTab.label               "Open in a New Tab">
 <!ENTITY syncedTabs.context.openInNewTab.accesskey           "w">
 <!ENTITY syncedTabs.context.openInNewWindow.label            "Open in a New Window">
 <!ENTITY syncedTabs.context.openInNewWindow.accesskey        "N">
 <!ENTITY syncedTabs.context.openInNewPrivateWindow.label     "Open in a New Private Window">
 <!ENTITY syncedTabs.context.openInNewPrivateWindow.accesskey "P">
 <!ENTITY syncedTabs.context.bookmarkSingleTab.label          "Bookmark This Tab…">
 <!ENTITY syncedTabs.context.bookmarkSingleTab.accesskey      "B">
 <!ENTITY syncedTabs.context.copy.label                       "Copy">
 <!ENTITY syncedTabs.context.copy.accesskey                   "C">
 
+<!ENTITY syncedTabs.context.openAllInTabs.label              "Open All in Tabs">
+<!ENTITY syncedTabs.context.openAllInTabs.accesskey          "O">
+
 
 <!ENTITY syncBrand.shortName.label    "Sync">
 
 <!ENTITY syncSignIn.label             "Sign In To &syncBrand.shortName.label;…">
 <!ENTITY syncSignIn.accesskey         "Y">
 <!ENTITY syncSyncNowItem.label        "Sync Now">
 <!ENTITY syncSyncNowItem.accesskey    "S">
 <!ENTITY syncReAuthItem.label         "Reconnect to &syncBrand.shortName.label;…">
--- a/browser/locales/en-US/chrome/browser/preferences/siteDataSettings.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/siteDataSettings.dtd
@@ -2,8 +2,10 @@
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <!ENTITY     window.title                  "Settings - Site Data">
 <!ENTITY     settings.description          "The following websites asked to store site data in your disk. You can specify which websites are allowed to store site data. Default site data is temporary and could be deleted automatically.">
 <!ENTITY     hostCol.label                 "Site">
 <!ENTITY     statusCol.label               "Status">
 <!ENTITY     usageCol.label                "Storage">
+<!ENTITY     search.label                  "Search:">
+<!ENTITY     search.accesskey              "S">
--- a/build/autoconf/frameptr.m4
+++ b/build/autoconf/frameptr.m4
@@ -24,19 +24,21 @@ AC_DEFUN([MOZ_SET_FRAMEPTR_FLAGS], [
     dnl Oy (Frame-Pointer Omission) is only support on x86 compilers
     *-mingw32*)
       MOZ_ENABLE_FRAME_PTR="-Oy-"
       MOZ_DISABLE_FRAME_PTR="-Oy"
     ;;
     esac
   fi
 
-  # if we are debugging, profiling or using sanitizers, we want a frame pointer.
+  # If we are debugging, profiling, using sanitizers, or on win32 we want a
+  # frame pointer.
   if test -z "$MOZ_OPTIMIZE" -o \
           -n "$MOZ_PROFILING" -o \
           -n "$MOZ_DEBUG" -o \
           -n "$MOZ_MSAN" -o \
-          -n "$MOZ_ASAN"; then
+          -n "$MOZ_ASAN" -o \
+          "$OS_ARCH:$CPU_ARCH" = "WINNT:x86"; then
     MOZ_FRAMEPTR_FLAGS="$MOZ_ENABLE_FRAME_PTR"
   else
     MOZ_FRAMEPTR_FLAGS="$MOZ_DISABLE_FRAME_PTR"
   fi
 ])
--- a/devtools/.eslintrc.js
+++ b/devtools/.eslintrc.js
@@ -278,16 +278,18 @@ module.exports = {
     "no-reserved-keys": "off",
     // Don't restrict usage of specified node modules (not a node environment).
     "no-restricted-modules": "off",
     // Disallow use of assignment in return statement. It is preferable for a
     // single line of code to have only one easily predictable effect.
     "no-return-assign": "error",
     // Allow use of javascript: urls.
     "no-script-url": "off",
+    // Disallow assignments like foo = foo
+    "no-self-assign": "error",
     // Disallow comparisons where both sides are exactly the same.
     "no-self-compare": "error",
     // Disallow use of comma operator.
     "no-sequences": "error",
     // Warn about declaration of variables already declared in the outer scope.
     // This isn't an error because it sometimes is useful to use the same name
     // in a small helper function rather than having to come up with another
     // random name.
@@ -327,16 +329,20 @@ module.exports = {
     "no-unreachable": "error",
     // Disallow global and local variables that aren't used, but allow unused
     // function arguments.
     "no-unused-vars": ["error", {"vars": "all", "args": "none"}],
     // Disallow flow control that escapes from "finally".
     "no-unsafe-finally": "error",
     // Allow using variables before they are defined.
     "no-use-before-define": "off",
+    // Disallow useless Function.prototype.{call/apply}
+    "no-useless-call": "error",
+    // Disallow useless return;
+    "no-useless-return": "error",
     // We use var-only-at-top-level instead of no-var as we allow top level
     // vars.
     "no-var": "off",
     // Allow using TODO/FIXME comments.
     "no-warning-comments": "off",
     // Disallow use of the with statement.
     "no-with": "error",
     // Don't require method and property shorthand syntax for object literals.
--- a/devtools/client/inspector/inspector-search.js
+++ b/devtools/client/inspector/inspector-search.js
@@ -538,12 +538,10 @@ SelectorAutocompleter.prototype = {
           result.suggestions[0][0] === firstPart) {
         result.suggestions = [];
       }
 
       // Wait for the autocomplete-popup to fire its popup-opened event, to make sure
       // the autoSelect item has been selected.
       return this._showPopup(result.suggestions, firstPart, state);
     });
-
-    return;
   }
 };
--- a/devtools/client/inspector/rules/rules.js
+++ b/devtools/client/inspector/rules/rules.js
@@ -1602,17 +1602,16 @@ RuleViewTool.prototype = {
     location.then(({ source, href, line, column }) => {
       let target = this.inspector.target;
       if (Tools.styleEditor.isTargetSupported(target)) {
         gDevTools.showToolbox(target, "styleeditor").then(function (toolbox) {
           let url = source || href;
           toolbox.getCurrentPanel().selectStyleSheet(url, line, column);
         });
       }
-      return;
     });
   },
 
   onPropertyChanged: function () {
     this.inspector.markDirty();
   },
 
   onViewRefreshed: function () {
--- a/devtools/client/memory/actions/snapshot.js
+++ b/devtools/client/memory/actions/snapshot.js
@@ -639,17 +639,16 @@ exports.fetchImmediatelyDominated = Task
     removeFromCache();
     dispatch({
       type: actions.FETCH_IMMEDIATELY_DOMINATED_END,
       id,
       path: response.path,
       nodes: response.nodes,
       moreChildrenAvailable: response.moreChildrenAvailable,
     });
-    return;
   }
 });
 
 /**
  * Compute and then fetch the dominator tree of the snapshot with the given
  * `id`.
  *
  * @param {HeapAnalysesClient} heapWorker
@@ -695,27 +694,25 @@ exports.refreshSelectedDominatorTree = f
 
     if (snapshot.dominatorTree &&
         !(snapshot.dominatorTree.state === dominatorTreeState.COMPUTED ||
           snapshot.dominatorTree.state === dominatorTreeState.LOADED ||
           snapshot.dominatorTree.state === dominatorTreeState.INCREMENTAL_FETCHING)) {
       return;
     }
 
+    // We need to check for the snapshot state because if there was an error,
+    // we can't continue and if we are still saving or reading the snapshot,
+    // then takeSnapshotAndCensus will finish the job for us
     if (snapshot.state === states.READ) {
       if (snapshot.dominatorTree) {
         yield dispatch(fetchDominatorTree(heapWorker, snapshot.id));
       } else {
         yield dispatch(computeAndFetchDominatorTree(heapWorker, snapshot.id));
       }
-    } else {
-        // If there was an error, we can't continue. If we are still saving or
-        // reading the snapshot, then takeSnapshotAndCensus will finish the job
-        // for us.
-      return;
     }
   };
 };
 
 /**
  * Select the snapshot with the given id.
  *
  * @param {snapshotId} id
--- a/devtools/client/netmonitor/request-utils.js
+++ b/devtools/client/netmonitor/request-utils.js
@@ -25,17 +25,17 @@ const { Task } = require("devtools/share
 function getKeyWithEvent(callback, onlySpaceOrReturn) {
   return function (event) {
     let key = event.target.getAttribute("data-key");
     let filterKeyboardEvent = !onlySpaceOrReturn ||
                               event.keyCode === KeyCodes.DOM_VK_SPACE ||
                               event.keyCode === KeyCodes.DOM_VK_RETURN;
 
     if (key && filterKeyboardEvent) {
-      callback.call(null, key);
+      callback(key);
     }
   };
 }
 
 /**
  * Extracts any urlencoded form data sections (e.g. "?foo=bar&baz=42") from a
  * POST request.
  *
--- a/devtools/client/responsive.html/test/browser/head.js
+++ b/devtools/client/responsive.html/test/browser/head.js
@@ -183,21 +183,31 @@ function getElRect(selector, win) {
   return el.getBoundingClientRect();
 }
 
 /**
  * Drag an element identified by 'selector' by [x,y] amount. Returns
  * the rect of the dragged element as it was before drag.
  */
 function dragElementBy(selector, x, y, win) {
+  let React = win.require("devtools/client/shared/vendor/react");
+  let { Simulate } = React.addons.TestUtils;
   let rect = getElRect(selector, win);
-  let startPoint = [ rect.left + rect.width / 2, rect.top + rect.height / 2 ];
-  let endPoint = [ startPoint[0] + x, startPoint[1] + y ];
+  let startPoint = {
+    clientX: rect.left + Math.floor(rect.width / 2),
+    clientY: rect.top + Math.floor(rect.height / 2),
+  };
+  let endPoint = [ startPoint.clientX + x, startPoint.clientY + y ];
 
-  EventUtils.synthesizeMouseAtPoint(...startPoint, { type: "mousedown" }, win);
+  let elem = win.document.querySelector(selector);
+
+  // mousedown is a React listener, need to use its testing tools to avoid races
+  Simulate.mouseDown(elem, startPoint);
+
+  // mousemove and mouseup are regular DOM listeners
   EventUtils.synthesizeMouseAtPoint(...endPoint, { type: "mousemove" }, win);
   EventUtils.synthesizeMouseAtPoint(...endPoint, { type: "mouseup" }, win);
 
   return rect;
 }
 
 function* testViewportResize(ui, selector, moveBy,
                              expectedViewportSize, expectedHandleMove) {
--- a/devtools/client/shared/components/tree.js
+++ b/devtools/client/shared/components/tree.js
@@ -440,38 +440,38 @@ module.exports = createClass({
       return;
     }
 
     this._preventArrowKeyScrolling(e);
 
     switch (e.key) {
       case "ArrowUp":
         this._focusPrevNode();
-        return;
+        break;
 
       case "ArrowDown":
         this._focusNextNode();
-        return;
+        break;
 
       case "ArrowLeft":
         if (this.props.isExpanded(this.props.focused)
             && this.props.getChildren(this.props.focused).length) {
           this._onCollapse(this.props.focused);
         } else {
           this._focusParentNode();
         }
-        return;
+        break;
 
       case "ArrowRight":
         if (!this.props.isExpanded(this.props.focused)) {
           this._onExpand(this.props.focused);
         } else {
           this._focusNextNode();
         }
-        return;
+        break;
     }
   },
 
   /**
    * Sets the previous node relative to the currently focused item, to focused.
    */
   _focusPrevNode: oncePerAnimationFrame(function () {
     // Start a depth first search and keep going until we reach the currently
--- a/devtools/client/shared/widgets/view-helpers.js
+++ b/devtools/client/shared/widgets/view-helpers.js
@@ -1519,35 +1519,35 @@ const WidgetMethods = exports.WidgetMeth
   _onWidgetKeyPress: function (name, event) {
     // Prevent scrolling when pressing navigation keys.
     ViewHelpers.preventScrolling(event);
 
     switch (event.keyCode) {
       case KeyCodes.DOM_VK_UP:
       case KeyCodes.DOM_VK_LEFT:
         this.focusPrevItem();
-        return;
+        break;
       case KeyCodes.DOM_VK_DOWN:
       case KeyCodes.DOM_VK_RIGHT:
         this.focusNextItem();
-        return;
+        break;
       case KeyCodes.DOM_VK_PAGE_UP:
         this.focusItemAtDelta(-(this.pageSize ||
                                (this.itemCount / PAGE_SIZE_ITEM_COUNT_RATIO)));
-        return;
+        break;
       case KeyCodes.DOM_VK_PAGE_DOWN:
         this.focusItemAtDelta(+(this.pageSize ||
                                (this.itemCount / PAGE_SIZE_ITEM_COUNT_RATIO)));
-        return;
+        break;
       case KeyCodes.DOM_VK_HOME:
         this.focusFirstVisibleItem();
-        return;
+        break;
       case KeyCodes.DOM_VK_END:
         this.focusLastVisibleItem();
-        return;
+        break;
     }
   },
 
   /**
    * The mousePress event listener for this container.
    * @param string name
    * @param MouseEvent event
    */
--- a/devtools/client/styleeditor/StyleEditorUtil.jsm
+++ b/devtools/client/styleeditor/StyleEditorUtil.jsm
@@ -225,10 +225,9 @@ function showFilePicker(path, toSave, pa
   if (toSave && suggestedFilename) {
     fp.defaultString = suggestedFilename;
   }
 
   fp.init(parentWindow, getString(key + ".title"), mode);
   fp.appendFilter(getString(key + ".filter"), "*.css");
   fp.appendFilters(fp.filterAll);
   fp.open(fpCallback);
-  return;
 }
--- a/devtools/client/webconsole/new-console-output/new-console-output-wrapper.js
+++ b/devtools/client/webconsole/new-console-output/new-console-output-wrapper.js
@@ -44,31 +44,25 @@ NewConsoleOutputWrapper.prototype = {
         emitNewMessage: (node, messageId) => {
           this.jsterm.hud.emit("new-messages", new Set([{
             node,
             messageId,
           }]));
         },
         hudProxyClient: this.jsterm.hud.proxy.client,
         onViewSourceInDebugger: frame => {
-          this.toolbox.viewSourceInDebugger.call(
-            this.toolbox,
-            frame.url,
-            frame.line
-          ).then(() =>
+          this.toolbox.viewSourceInDebugger(frame.url, frame.line).then(() =>
             this.jsterm.hud.emit("source-in-debugger-opened")
           );
         },
-        onViewSourceInScratchpad: frame => this.toolbox.viewSourceInScratchpad.call(
-          this.toolbox,
+        onViewSourceInScratchpad: frame => this.toolbox.viewSourceInScratchpad(
           frame.url,
           frame.line
         ),
-        onViewSourceInStyleEditor: frame => this.toolbox.viewSourceInStyleEditor.call(
-          this.toolbox,
+        onViewSourceInStyleEditor: frame => this.toolbox.viewSourceInStyleEditor(
           frame.url,
           frame.line
         ),
         openContextMenu: (e, message) => {
           let { screenX, screenY, target } = e;
 
           let messageEl = target.closest(".message");
           let clipboardText = messageEl ? messageEl.textContent : null;
@@ -87,17 +81,17 @@ NewConsoleOutputWrapper.prototype = {
           return menu;
         },
         openNetworkPanel: (requestId) => {
           return this.toolbox.selectTool("netmonitor").then(panel => {
             return panel.panelWin.NetMonitorController.inspectRequest(requestId);
           });
         },
         sourceMapService: this.toolbox ? this.toolbox._sourceMapService : null,
-        openLink: url => this.jsterm.hud.owner.openLink.call(this.jsterm.hud.owner, url),
+        openLink: url => this.jsterm.hud.owner.openLink(url),
         createElement: nodename => {
           return this.document.createElementNS("http://www.w3.org/1999/xhtml", nodename);
         },
         highlightDomElement: (grip, options = {}) => {
           return this.toolbox && this.toolbox.highlighterUtils
             ? this.toolbox.highlighterUtils.highlightDomValueGrip(grip, options)
             : null;
         },
--- a/devtools/shared/apps/app-actor-front.js
+++ b/devtools/shared/apps/app-actor-front.js
@@ -714,18 +714,16 @@ AppActorFront.prototype = {
           // Fake a appClose event if we didn't got one before uninstall
           if (app.running) {
             app.running = false;
             this._notifyListeners("appClose", app);
           }
           this._apps.delete(manifestURL);
           this._notifyListeners("appUninstall", app);
           break;
-        default:
-          return;
       }
     });
   },
 
   _notifyListeners: function (type, app) {
     this._listeners.forEach(f => {
       f(type, app);
     });
--- a/devtools/shared/event-emitter.js
+++ b/devtools/shared/event-emitter.js
@@ -127,17 +127,17 @@
      *        that this is needed) then use listener
      */
     once(event, listener) {
       let deferred = defer();
 
       let handler = (_, first, ...rest) => {
         this.off(event, handler);
         if (listener) {
-          listener.apply(null, [event, first, ...rest]);
+          listener(event, first, ...rest);
         }
         deferred.resolve(first);
       };
 
       handler._originalListener = listener;
       this.on(event, handler);
 
       return deferred.promise;
--- a/devtools/shared/security/auth.js
+++ b/devtools/shared/security/auth.js
@@ -375,17 +375,17 @@ OOBCert.Client.prototype = {
             // Server previously persisted Client as allowed
             // Step C.5
             // Debugging begins
             transport.hooks = null;
             deferred.resolve(transport);
             break;
           default:
             transport.close(new Error("Invalid auth result: " + authResult));
-            return;
+            break;
         }
       }.bind(this)),
       onClosed(reason) {
         closeDialog();
         // Transport died before auth completed
         transport.hooks = null;
         deferred.reject(reason);
       }
--- a/devtools/shared/task.js
+++ b/devtools/shared/task.js
@@ -153,17 +153,17 @@ var Task = {
    *          returned promise.
    *        - If you specify anything else, you get a promise that is already
    *          resolved with the specified value.
    *
    * @return A promise object where you can register completion callbacks to be
    *         called when the task terminates.
    */
   spawn: function (task) {
-    return createAsyncFunction(task).call(undefined);
+    return createAsyncFunction(task)();
   },
 
   /**
    * Create and return an 'async function' that starts a new task.
    *
    * This is similar to 'spawn' except that it doesn't immediately start
    * the task, it binds the task to the async function's 'this' object and
    * arguments, and it requires the task to be a function.
--- a/dom/animation/KeyframeEffectReadOnly.h
+++ b/dom/animation/KeyframeEffectReadOnly.h
@@ -15,18 +15,18 @@
 #include "nsTArray.h"
 #include "nsWrapperCache.h"
 #include "mozilla/AnimationPerformanceWarning.h"
 #include "mozilla/AnimationTarget.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ComputedTimingFunction.h"
 #include "mozilla/EffectCompositor.h"
 #include "mozilla/KeyframeEffectParams.h"
-#include "mozilla/ServoBindingTypes.h" // RawServoDeclarationBlock and
-                                       // associated RefPtrTraits
+// RawServoDeclarationBlock and associated RefPtrTraits
+#include "mozilla/ServoBindingTypes.h"
 #include "mozilla/StyleAnimationValue.h"
 #include "mozilla/dom/AnimationEffectReadOnly.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/Element.h"
 
 struct JSContext;
 class JSObject;
 class nsIContent;
@@ -118,16 +118,19 @@ struct Keyframe
 };
 
 struct AnimationPropertySegment
 {
   float mFromKey, mToKey;
   // NOTE: In the case that no keyframe for 0 or 1 offset is specified
   // the unit of mFromValue or mToValue is eUnit_Null.
   StyleAnimationValue mFromValue, mToValue;
+  // FIXME add a deep == impl for RawServoAnimationValue
+  RefPtr<RawServoAnimationValue> mServoFromValue, mServoToValue;
+
   Maybe<ComputedTimingFunction> mTimingFunction;
   dom::CompositeOperation mFromComposite = dom::CompositeOperation::Replace;
   dom::CompositeOperation mToComposite = dom::CompositeOperation::Replace;
 
   bool operator==(const AnimationPropertySegment& aOther) const
   {
     return mFromKey == aOther.mFromKey &&
            mToKey == aOther.mToKey &&
--- a/dom/animation/KeyframeUtils.cpp
+++ b/dom/animation/KeyframeUtils.cpp
@@ -5,28 +5,30 @@
 
 #include "mozilla/KeyframeUtils.h"
 
 #include "mozilla/AnimationUtils.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/Move.h"
 #include "mozilla/RangedArray.h"
 #include "mozilla/ServoBindings.h"
+#include "mozilla/ServoBindingTypes.h"
 #include "mozilla/StyleAnimationValue.h"
 #include "mozilla/TimingParams.h"
 #include "mozilla/dom/BaseKeyframeTypesBinding.h" // For FastBaseKeyframe etc.
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/KeyframeEffectBinding.h"
 #include "mozilla/dom/KeyframeEffectReadOnly.h" // For PropertyValuesPair etc.
 #include "jsapi.h" // For ForOfIterator etc.
 #include "nsClassHashtable.h"
 #include "nsCSSParser.h"
 #include "nsCSSPropertyIDSet.h"
 #include "nsCSSProps.h"
 #include "nsCSSPseudoElements.h" // For CSSPseudoElementType
+#include "nsStyleContext.h"
 #include "nsTArray.h"
 #include <algorithm> // For std::stable_sort
 
 namespace mozilla {
 
 // ------------------------------------------------------------------
 //
 // Internal data types
@@ -265,16 +267,18 @@ struct AdditionalProperty
  *
  * KeyframeValueEntry is used in GetAnimationPropertiesFromKeyframes
  * to gather data for each individual segment.
  */
 struct KeyframeValueEntry
 {
   nsCSSPropertyID mProperty;
   StyleAnimationValue mValue;
+  RefPtr<RawServoAnimationValue> mServoValue;
+
   float mOffset;
   Maybe<ComputedTimingFunction> mTimingFunction;
   dom::CompositeOperation mComposite;
 
   struct PropertyOffsetComparator
   {
     static bool Equals(const KeyframeValueEntry& aLhs,
                        const KeyframeValueEntry& aRhs)
@@ -595,16 +599,26 @@ KeyframeUtils::GetComputedKeyframeValues
   MOZ_ASSERT(aStyleContext);
   MOZ_ASSERT(aElement);
 
   StyleBackendType styleBackend = aElement->OwnerDoc()->GetStyleBackendType();
 
   const size_t len = aKeyframes.Length();
   nsTArray<ComputedKeyframeValues> result(len);
 
+  const ServoComputedValues* currentStyle = nullptr;
+  const ServoComputedValues* parentStyle = nullptr;
+
+  if (styleBackend == StyleBackendType::Servo) {
+    currentStyle = aStyleContext->StyleSource().AsServoComputedValues();
+    if (aStyleContext->GetParent()) {
+      parentStyle = aStyleContext->GetParent()->StyleSource().AsServoComputedValues();
+    }
+  }
+
   for (const Keyframe& frame : aKeyframes) {
     nsCSSPropertyIDSet propertiesOnThisKeyframe;
     ComputedKeyframeValues* computedValues = result.AppendElement();
     for (const PropertyValuePair& pair :
            PropertyPriorityIterator(frame.mPropertyValues)) {
       MOZ_ASSERT(!pair.mServoDeclarationBlock ||
                  styleBackend == StyleBackendType::Servo,
                  "Animation values were parsed using Servo backend but target"
@@ -619,16 +633,21 @@ KeyframeUtils::GetComputedKeyframeValues
       nsTArray<PropertyStyleAnimationValuePair> values;
 
       if (styleBackend == StyleBackendType::Servo) {
         if (!StyleAnimationValue::ComputeValues(pair.mProperty,
               CSSEnabledState::eForAllContent, aStyleContext,
               *pair.mServoDeclarationBlock, values)) {
           continue;
         }
+        Servo_AnimationValues_Populate(&values,
+                                       pair.mServoDeclarationBlock,
+                                       currentStyle,
+                                       parentStyle,
+                                       aStyleContext->PresContext());
       } else {
         // For shorthands, we store the string as a token stream so we need to
         // extract that first.
         if (nsCSSProps::IsShorthand(pair.mProperty)) {
           nsCSSValueTokenStream* tokenStream = pair.mValue.GetTokenStreamValue();
           if (!StyleAnimationValue::ComputeValues(pair.mProperty,
                 CSSEnabledState::eForAllContent, aElement, aStyleContext,
                 tokenStream->mTokenStream, /* aUseSVGMode */ false, values) ||
@@ -648,18 +667,18 @@ KeyframeUtils::GetComputedKeyframeValues
       }
 
       for (auto& value : values) {
         // If we already got a value for this property on the keyframe,
         // skip this one.
         if (propertiesOnThisKeyframe.HasProperty(value.mProperty)) {
           continue;
         }
-        computedValues->AppendElement(value);
         propertiesOnThisKeyframe.AddProperty(value.mProperty);
+        computedValues->AppendElement(Move(value));
       }
     }
   }
 
   MOZ_ASSERT(result.Length() == aKeyframes.Length(), "Array length mismatch");
   return result;
 }
 
@@ -680,16 +699,17 @@ KeyframeUtils::GetAnimationPropertiesFro
     const Keyframe& frame = aKeyframes[i];
     for (auto& value : aComputedValues[i]) {
       MOZ_ASSERT(frame.mComputedOffset != Keyframe::kComputedOffsetNotSet,
                  "Invalid computed offset");
       KeyframeValueEntry* entry = entries.AppendElement();
       entry->mOffset = frame.mComputedOffset;
       entry->mProperty = value.mProperty;
       entry->mValue = value.mValue;
+      entry->mServoValue = value.mServoValue;
       entry->mTimingFunction = frame.mTimingFunction;
       entry->mComposite =
         frame.mComposite ? frame.mComposite.value() : aEffectComposite;
     }
   }
 
   nsTArray<AnimationProperty> result;
   BuildSegmentsFromValueEntries(entries, result);
@@ -1366,23 +1386,25 @@ BuildSegmentsFromValueEntries(nsTArray<K
       lastProperty = aEntries[i].mProperty;
     }
 
     MOZ_ASSERT(animationProperty, "animationProperty should be valid pointer.");
 
     // Now generate the segment.
     AnimationPropertySegment* segment =
       animationProperty->mSegments.AppendElement();
-    segment->mFromKey   = aEntries[i].mOffset;
-    segment->mToKey     = aEntries[j].mOffset;
-    segment->mFromValue = aEntries[i].mValue;
-    segment->mToValue   = aEntries[j].mValue;
+    segment->mFromKey        = aEntries[i].mOffset;
+    segment->mToKey          = aEntries[j].mOffset;
+    segment->mFromValue      = aEntries[i].mValue;
+    segment->mToValue        = aEntries[j].mValue;
+    segment->mServoFromValue = aEntries[i].mServoValue;
+    segment->mServoToValue   = aEntries[j].mServoValue;
     segment->mTimingFunction = aEntries[i].mTimingFunction;
-    segment->mFromComposite = aEntries[i].mComposite;
-    segment->mToComposite = aEntries[j].mComposite;
+    segment->mFromComposite  = aEntries[i].mComposite;
+    segment->mToComposite    = aEntries[j].mComposite;
 
     i = j;
   }
 }
 
 /**
  * Converts a JS object representing a property-indexed keyframe into
  * an array of Keyframe objects.
--- a/dom/media/GraphDriver.cpp
+++ b/dom/media/GraphDriver.cpp
@@ -510,17 +510,19 @@ AsyncCubebTask::EnsureThread()
 NS_IMETHODIMP
 AsyncCubebTask::Run()
 {
   MOZ_ASSERT(mDriver);
 
   switch(mOperation) {
     case AsyncCubebOperation::INIT: {
       LIFECYCLE_LOG("AsyncCubebOperation::INIT driver=%p\n", mDriver.get());
-      mDriver->Init();
+      if (!mDriver->Init()) {
+        return NS_ERROR_FAILURE;
+      }
       mDriver->CompleteAudioContextOperations(mOperation);
       break;
     }
     case AsyncCubebOperation::SHUTDOWN: {
       LIFECYCLE_LOG("AsyncCubebOperation::SHUTDOWN driver=%p\n", mDriver.get());
       mDriver->Stop();
 
       mDriver->CompleteAudioContextOperations(mOperation);
@@ -589,26 +591,26 @@ bool IsMacbookOrMacbookAir()
       }
     }
     return false;
   }
 #endif
   return false;
 }
 
-void
+bool
 AudioCallbackDriver::Init()
 {
   cubeb* cubebContext = CubebUtils::GetCubebContext();
   if (!cubebContext) {
     NS_WARNING("Could not get cubeb context.");
     if (!mFromFallback) {
       CubebUtils::ReportCubebStreamInitFailure(true);
     }
-    return;
+    return false;
   }
 
   cubeb_stream_params output;
   cubeb_stream_params input;
   uint32_t latency_frames;
   bool firstStream = CubebUtils::GetFirstStream();
 
   MOZ_ASSERT(!NS_IsMainThread(),
@@ -619,17 +621,17 @@ AudioCallbackDriver::Init()
 #if defined(__ANDROID__)
 #if defined(MOZ_B2G)
   output.stream_type = CubebUtils::ConvertChannelToCubebType(mAudioChannel);
 #else
   output.stream_type = CUBEB_STREAM_TYPE_MUSIC;
 #endif
   if (output.stream_type == CUBEB_STREAM_TYPE_MAX) {
     NS_WARNING("Bad stream type");
-    return;
+    return false;
   }
 #else
   (void)mAudioChannel;
 #endif
 
   output.channels = mGraphImpl->AudioChannelCount();
   if (AUDIO_OUTPUT_FORMAT == AUDIO_FORMAT_S16) {
     output.format = CUBEB_SAMPLE_S16NE;
@@ -638,17 +640,17 @@ AudioCallbackDriver::Init()
   }
 
   Maybe<uint32_t> latencyPref = CubebUtils::GetCubebMSGLatencyInFrames();
   if (latencyPref) {
     latency_frames = latencyPref.value();
   } else {
     if (cubeb_get_min_latency(cubebContext, output, &latency_frames) != CUBEB_OK) {
       NS_WARNING("Could not get minimal latency from cubeb.");
-      return;
+      return false;
     }
   }
 
   // Macbook and MacBook air don't have enough CPU to run very low latency
   // MediaStreamGraphs, cap the minimal latency to 512 frames int this case.
   if (IsMacbookOrMacbookAir()) {
     latency_frames = std::max((uint32_t) 512, latency_frames);
   }
@@ -707,29 +709,33 @@ AudioCallbackDriver::Init()
       // Fall back to a driver using a normal thread.
       MonitorAutoLock lock(GraphImpl()->GetMonitor());
       SystemClockDriver* nextDriver = new SystemClockDriver(GraphImpl());
       SetNextDriver(nextDriver);
       nextDriver->MarkAsFallback();
       nextDriver->SetGraphTime(this, mIterationStart, mIterationEnd);
       mGraphImpl->SetCurrentDriver(nextDriver);
       nextDriver->Start();
-      return;
+      return true;
     }
   }
   bool aec;
   Unused << mGraphImpl->AudioTrackPresent(aec);
   SetMicrophoneActive(aec);
 
   cubeb_stream_register_device_changed_callback(mAudioStream,
                                                 AudioCallbackDriver::DeviceChangedCallback_s);
 
-  StartStream();
+  if (!StartStream()) {
+    STREAM_LOG(LogLevel::Warning, ("AudioCallbackDriver couldn't start stream."));
+    return false;
+  }
 
   STREAM_LOG(LogLevel::Debug, ("AudioCallbackDriver started."));
+  return true;
 }
 
 
 void
 AudioCallbackDriver::Destroy()
 {
   STREAM_LOG(LogLevel::Debug, ("AudioCallbackDriver destroyed."));
   mAudioInput = nullptr;
@@ -766,28 +772,30 @@ AudioCallbackDriver::Start()
 
   LIFECYCLE_LOG("Starting new audio driver off main thread, "
                 "to ensure it runs after previous shutdown.");
   RefPtr<AsyncCubebTask> initEvent =
     new AsyncCubebTask(AsAudioCallbackDriver(), AsyncCubebOperation::INIT);
   initEvent->Dispatch();
 }
 
-void
+bool
 AudioCallbackDriver::StartStream()
 {
   if (cubeb_stream_start(mAudioStream) != CUBEB_OK) {
-    MOZ_CRASH("Could not start cubeb stream for MSG.");
+    NS_WARNING("Could not start cubeb stream for MSG.");
+    return false;
   }
 
   {
     MonitorAutoLock mon(mGraphImpl->GetMonitor());
     mStarted = true;
     mWaitState = WAITSTATE_RUNNING;
   }
+  return true;
 }
 
 void
 AudioCallbackDriver::Stop()
 {
   if (cubeb_stream_stop(mAudioStream) != CUBEB_OK) {
     NS_WARNING("Could not stop cubeb stream for MSG.");
   }
--- a/dom/media/GraphDriver.h
+++ b/dom/media/GraphDriver.h
@@ -462,19 +462,19 @@ private:
    * On certain MacBookPro, the microphone is located near the left speaker.
    * We need to pan the sound output to the right speaker if we are using the
    * mic and the built-in speaker, or we will have terrible echo.  */
   void PanOutputIfNeeded(bool aMicrophoneActive);
   /**
    * This is called when the output device used by the cubeb stream changes. */
   void DeviceChangedCallback();
   /* Start the cubeb stream */
-  void StartStream();
+  bool StartStream();
   friend class AsyncCubebTask;
-  void Init();
+  bool Init();
   /* MediaStreamGraphs are always down/up mixed to stereo for now. */
   static const uint32_t ChannelCount = 2;
   /* The size of this buffer comes from the fact that some audio backends can
    * call back with a number of frames lower than one block (128 frames), so we
    * need to keep at most two block in the SpillBuffer, because we always round
    * up to block boundaries during an iteration.
    * This is only ever accessed on the audio callback thread. */
   SpillBuffer<AudioDataValue, WEBAUDIO_BLOCK_SIZE * 2, ChannelCount> mScratchBuffer;
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -21,16 +21,17 @@
 #include "mediasink/OutputStreamManager.h"
 #include "mediasink/VideoSink.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Logging.h"
 #include "mozilla/mozalloc.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/SharedThreadPool.h"
+#include "mozilla/Sprintf.h"
 #include "mozilla/TaskQueue.h"
 
 #include "nsComponentManagerUtils.h"
 #include "nsContentUtils.h"
 #include "nsIEventTarget.h"
 #include "nsITimer.h"
 #include "nsPrintfCString.h"
 #include "nsTArray.h"
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -439,21 +439,21 @@ class RTCPeerConnection {
 
     this.__DOM_IMPL__._innerObject = this;
     this._observer = new this._win.PeerConnectionObserver(this.__DOM_IMPL__);
 
     var location = "" + this._win.location;
 
     // Warn just once per PeerConnection about deprecated getStats usage.
     this._warnDeprecatedStatsAccessNullable = { warn: () =>
-      this.logWarning("non-maplike pc.getStats access is deprecated! " +
+      this.logWarning("non-maplike pc.getStats access is deprecated, and will be removed in the near future! " +
                       "See http://w3c.github.io/webrtc-pc/#getstats-example for usage.") };
 
     this._warnDeprecatedStatsCallbacksNullable = { warn: () =>
-      this.logWarning("Callback-based pc.getStats is deprecated! Use promise-version! " +
+      this.logWarning("Callback-based pc.getStats is deprecated, and will be removed in the near future! Use promise-version! " +
                       "See http://w3c.github.io/webrtc-pc/#getstats-example for usage.") };
 
     // Add a reference to the PeerConnection to global list (before init).
     _globalPCList.addPC(this);
 
     this._impl.initialize(this._observer, this._win, rtcConfig,
                           Services.tm.currentThread);
 
--- a/dom/media/test/seek_support.js
+++ b/dom/media/test/seek_support.js
@@ -1,20 +1,10 @@
-SimpleTest.requestLongerTimeout(3);
 var manager = new MediaTestManager;
 
-// https://bugzilla.mozilla.org/show_bug.cgi?id=634747
-if (navigator.platform.startsWith("Win")) {
-  SimpleTest.expectAssertions(0, 5);
-} else {
-  // This is "###!!! ASSERTION: Page read cursor should be inside range: 'mPageOffset <= endOffset'"
-  // https://bugzilla.mozilla.org/show_bug.cgi?id=846769
-  SimpleTest.expectAssertions(0, 5);
-}
-
 function createTestArray() {
   var tests = [];
   var tmpVid = document.createElement("video");
 
   for (var testNum=0; testNum<gSeekTests.length; testNum++) {
     var test = gSeekTests[testNum];
     if (!tmpVid.canPlayType(test.type)) {
       continue;
--- a/dom/security/test/hsts/browser.ini
+++ b/dom/security/test/hsts/browser.ini
@@ -12,8 +12,9 @@ support-files =
 [browser_hsts-priming_block_active.js]
 [browser_hsts-priming_hsts_after_mixed.js]
 [browser_hsts-priming_allow_display.js]
 [browser_hsts-priming_block_display.js]
 [browser_hsts-priming_block_active_css.js]
 [browser_hsts-priming_block_active_with_redir_same.js]
 [browser_hsts-priming_no-duplicates.js]
 [browser_hsts-priming_cache-timeout.js]
+[browser_hsts-priming_timeout.js]
--- a/dom/security/test/hsts/browser_hsts-priming_no-duplicates.js
+++ b/dom/security/test/hsts/browser_hsts-priming_no-duplicates.js
@@ -14,17 +14,15 @@ add_task(function*() {
   let which = "block_display";
 
   SetupPrefTestEnvironment(which);
 
   for (let server of Object.keys(test_servers)) {
     yield execute_test(server, test_settings[which].mimetype);
   }
 
-  test_settings[which].priming = {};
-
   // run the tests twice to validate the cache is being used
   for (let server of Object.keys(test_servers)) {
     yield execute_test(server, test_settings[which].mimetype);
   }
 
   SpecialPowers.popPrefEnv();
 });
new file mode 100644
--- /dev/null
+++ b/dom/security/test/hsts/browser_hsts-priming_timeout.js
@@ -0,0 +1,24 @@
+/*
+ * Description of the test:
+ *   Only one request should be sent per host, even if we run the test more
+ *   than once.
+ */
+'use strict';
+
+//jscs:disable
+add_task(function*() {
+  //jscs:enable
+  Observer.add_observers(Services);
+  registerCleanupFunction(do_cleanup);
+
+  let which = "timeout";
+
+  SetupPrefTestEnvironment(which, [["security.mixed_content.hsts_priming_request_timeout",
+                1000]]);
+
+  for (let server of Object.keys(test_servers)) {
+    yield execute_test(server, test_settings[which].mimetype);
+  }
+
+  SpecialPowers.popPrefEnv();
+});
--- a/dom/security/test/hsts/file_priming-top.html
+++ b/dom/security/test/hsts/file_priming-top.html
@@ -32,24 +32,28 @@ var args = parse_query_string();
 var subresources = {
   css: { mimetype: 'text/css', file: 'file_stylesheet.css' },
   img: { mimetype: 'image/png', file: 'file_1x1.png' },
   script: { mimetype: 'text/javascript', file: 'file_priming.js' },
 };
 
 function handler(ev) {
   console.log("HSTS_PRIMING: Blocked "+args.id);
+  let elem = document.getElementById(args.id);
+  elem.parentElement.removeChild(elem);
 }
 
 function loadCss(src) {
   let head = document.getElementsByTagName("head")[0];
   let link = document.createElement("link");
   link.setAttribute("rel", "stylesheet");
+  link.setAttribute("id", args.id);
   link.setAttribute("type", subresources[args.type].mimetype);
   link.setAttribute("href", src);
+  link.onerror = handler;
   head.appendChild(link);
 }
 
 function loadResource(src) {
   let content = document.getElementById("content");
   let testElem = document.createElement(args.type);
   testElem.setAttribute("id", args.id);
   testElem.setAttribute("charset", "UTF-8");
@@ -62,16 +66,17 @@ function loadTest() {
   let subresource = subresources[args.type];
 
   let src = "http://"
     + args.host
     + "/browser/dom/security/test/hsts/file_testserver.sjs"
     + "?file=" +escape("browser/dom/security/test/hsts/" + subresource.file)
     + "&primer=" + escape(args.id)
     + "&mimetype=" + escape(subresource.mimetype)
+    + "&timeout=" + escape(args.timeout)
     ;
   if (args.type == 'css') {
     loadCss(src);
     return;
   }
 
   loadResource(src);
 }
--- a/dom/security/test/hsts/file_stylesheet.css
+++ b/dom/security/test/hsts/file_stylesheet.css
@@ -0,0 +1,1 @@
+body {}
--- a/dom/security/test/hsts/file_testserver.sjs
+++ b/dom/security/test/hsts/file_testserver.sjs
@@ -22,45 +22,63 @@ function loadFromFile(path) {
   var test = NetUtil.readInputStreamToString(testFileStream, testFileStream.available());
   return test;
 }
 
 function handleRequest(request, response)
 {
   const query = new URLSearchParams(request.queryString);
 
-  redir = query.get('redir');
-  if (redir == 'same') {
-    query.delete("redir");
-    response.setStatus(302);
-    let newURI = request.uri;
-    newURI.queryString = query.serialize();
-    response.setHeader("Location", newURI.spec)
-  }
+  var timeout = parseInt(query.get('timeout'));
+  response.processAsync();
+
+  timer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
+  timer.initWithCallback(function()
+    {
+      if (!response) {
+        return;
+      }
 
-  // avoid confusing cache behaviors
-  response.setHeader("Cache-Control", "no-cache", false);
+      // avoid confusing cache behaviors
+      response.setHeader("Cache-Control", "no-cache", false);
+
+      redir = query.get('redir');
+      if (redir == 'same') {
+        query.delete("redir");
+        response.setStatus(302);
+        let newURI = request.uri;
+        newURI.queryString = query.serialize();
+        response.setHeader("Location", newURI.spec)
+        response.write('xyzzy');
+        response.finish();
+        return;
+      }
 
-  // if we have a priming header, check for required behavior
-  // and set header appropriately
-  if (request.hasHeader('Upgrade-Insecure-Requests')) {
-    var expected = query.get('primer');
-    if (expected == 'prime-hsts') {
-      // set it for 5 minutes
-      response.setHeader("Strict-Transport-Security", "max-age="+(60*5), false);
-    } else if (expected == 'reject-upgrade') {
-      response.setHeader("Strict-Transport-Security", "max-age=0", false);
-    }
-    response.write('');
-    return;
-  }
+      // if we have a priming header, check for required behavior
+      // and set header appropriately
+      if (request.hasHeader('Upgrade-Insecure-Requests')) {
+        var expected = query.get('primer');
+        if (expected == 'prime-hsts') {
+          // set it for 5 minutes
+          response.setHeader("Strict-Transport-Security", "max-age="+(60*5), false);
+        } else if (expected == 'reject-upgrade') {
+          response.setHeader("Strict-Transport-Security", "max-age=0", false);
+        }
+        response.write('xyzzy');
+        response.finish();
+        return;
+      }
 
-  var file = query.get('file');
-  if (file) {
-    var mimetype = unescape(query.get('mimetype'));
-    response.setHeader("Content-Type", mimetype, false);
-    response.write(loadFromFile(unescape(file)));
-    return;
-  }
+      var file = query.get('file');
+      if (file) {
+        var mimetype = unescape(query.get('mimetype'));
+        response.setHeader("Content-Type", mimetype, false);
+        let contents = loadFromFile(unescape(file));
+        response.write(contents);
+        response.finish();
+        return;
+      }
 
-  response.setHeader("Content-Type", "application/json", false);
-  response.write('{}');
+      response.setHeader("Content-Type", "application/json", false);
+      response.write('{}');
+      response.finish();
+    }, timeout, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
 }
--- a/dom/security/test/hsts/head.js
+++ b/dom/security/test/hsts/head.js
@@ -42,108 +42,164 @@ var test_servers = {
 var test_settings = {
   // mixed active content is allowed, priming will upgrade
   allow_active: {
     block_active: false,
     block_display: false,
     use_hsts: true,
     send_hsts_priming: true,
     type: 'script',
+    timeout: 0,
     result: {
       'no-ssl': 'insecure',
       'reject-upgrade': 'insecure',
       'prime-hsts': 'secure',
     },
   },
   // mixed active content is blocked, priming will upgrade
   block_active: {
     block_active: true,
     block_display: false,
     use_hsts: true,
     send_hsts_priming: true,
     type: 'script',
+    timeout: 0,
     result: {
       'no-ssl': 'blocked',
       'reject-upgrade': 'blocked',
       'prime-hsts': 'secure',
     },
   },
   // keep the original order of mixed-content and HSTS, but send
   // priming requests
   hsts_after_mixed: {
     block_active: true,
     block_display: false,
     use_hsts: false,
     send_hsts_priming: true,
     type: 'script',
+    timeout: 0,
     result: {
       'no-ssl': 'blocked',
       'reject-upgrade': 'blocked',
       'prime-hsts': 'blocked',
     },
   },
   // mixed display content is allowed, priming will upgrade
   allow_display: {
     block_active: true,
     block_display: false,
     use_hsts: true,
     send_hsts_priming: true,
     type: 'img',
+    timeout: 0,
     result: {
       'no-ssl': 'insecure',
       'reject-upgrade': 'insecure',
       'prime-hsts': 'secure',
     },
   },
   // mixed display content is blocked, priming will upgrade
   block_display: {
     block_active: true,
     block_display: true,
     use_hsts: true,
     send_hsts_priming: true,
     type: 'img',
+    timeout: 0,
     result: {
       'no-ssl': 'blocked',
       'reject-upgrade': 'blocked',
       'prime-hsts': 'secure',
     },
   },
   // mixed active content is blocked, priming will upgrade (css)
   block_active_css: {
     block_active: true,
-    block_display: false,
+    block_display: true,
     use_hsts: true,
     send_hsts_priming: true,
     type: 'css',
+    timeout: 0,
     result: {
       'no-ssl': 'blocked',
       'reject-upgrade': 'blocked',
       'prime-hsts': 'secure',
     },
   },
   // mixed active content is blocked, priming will upgrade
   // redirect to the same host
   block_active_with_redir_same: {
     block_active: true,
     block_display: false,
     use_hsts: true,
     send_hsts_priming: true,
     type: 'script',
     redir: 'same',
+    timeout: 0,
     result: {
       'no-ssl': 'blocked',
       'reject-upgrade': 'blocked',
       'prime-hsts': 'secure',
     },
   },
+  // mixed active content is blocked, priming will upgrade
+  // redirect to the same host
+  timeout: {
+    block_active: true,
+    block_display: true,
+    use_hsts: true,
+    send_hsts_priming: true,
+    type: 'script',
+    timeout: 100000,
+    result: {
+      'no-ssl': 'blocked',
+      'reject-upgrade': 'blocked',
+      'prime-hsts': 'blocked',
+    },
+  },
 }
 // track which test we are on
 var which_test = "";
 
-const Observer = {
+/**
+ * A stream listener that just forwards all calls
+ */
+var StreamListener = function(subject) {
+  let channel = subject.QueryInterface(Ci.nsIHttpChannel);
+  let traceable = subject.QueryInterface(Ci.nsITraceableChannel);
+
+  this.uri = channel.URI.asciiSpec;
+  this.listener = traceable.setNewListener(this);
+  return this;
+};
+
+// Next three methods are part of `nsIStreamListener` interface and are
+// invoked by `nsIInputStreamPump.asyncRead`.
+StreamListener.prototype.onDataAvailable = function(request, context, input, offset, count) {
+  let listener = this.listener;
+  listener.onDataAvailable(request, context, input, offset, count);
+};
+
+// Next two methods implement `nsIRequestObserver` interface and are invoked
+// by `nsIInputStreamPump.asyncRead`.
+StreamListener.prototype.onStartRequest = function(request, context) {
+  let listener = this.listener;
+  listener.onStartRequest(request, context);
+};
+
+// Called to signify the end of an asynchronous request. We only care to
+// discover errors.
+StreamListener.prototype.onStopRequest = function(request, context, status) {
+  let listener = this.listener;
+  listener.onStopRequest(request, context, status);
+};
+
+var Observer = {
+  listeners: {},
   observe: function (subject, topic, data) {
     switch (topic) {
       case 'console-api-log-event':
         return Observer.console_api_log_event(subject, topic, data);
       case 'http-on-examine-response':
         return Observer.http_on_examine_response(subject, topic, data);
       case 'http-on-modify-request':
         return Observer.http_on_modify_request(subject, topic, data);
@@ -186,34 +242,45 @@ const Observer = {
       if (re.test(uri)) {
         return test_servers[item];
       }
     }
     return null;
   },
   http_on_modify_request: function (subject, topic, data) {
     let channel = subject.QueryInterface(Ci.nsIHttpChannel);
-    if (channel.requestMethod != 'HEAD') {
-      return;
-    }
+    let uri = channel.URI.asciiSpec;
 
     let curTest = this.get_current_test(channel.URI.asciiSpec);
 
     if (!curTest) {
       return;
     }
+    
+    if (!(uri in this.listeners)) {
+      // Add an nsIStreamListener to ensure that the listener is not NULL
+      this.listeners[uri] = new StreamListener(subject);
+    }
 
+    if (channel.requestMethod != 'HEAD') {
+      return;
+    }
+    if (typeof ok === 'undefined') {
+      // we are in the wrong thread and ok and is not available
+      return;
+    }
     ok(!(curTest.id in test_settings[which_test].priming), "Already saw a priming request for " + curTest.id);
     test_settings[which_test].priming[curTest.id] = true;
   },
   // When we see a response come back, peek at the response and test it is secure
   // or insecure as needed. Addtionally, watch the response for priming requests.
   http_on_examine_response: function (subject, topic, data) {
     let channel = subject.QueryInterface(Ci.nsIHttpChannel);
     let curTest = this.get_current_test(channel.URI.asciiSpec);
+    let uri = channel.URI.asciiSpec;
 
     if (!curTest) {
       return;
     }
 
     let result = (channel.URI.asciiSpec.startsWith('https:')) ? "secure" : "insecure";
 
     // This is a priming request, go ahead and validate we were supposed to see
@@ -222,16 +289,19 @@ const Observer = {
       is(true, curTest.response, "HSTS priming response found " + curTest.id);
       return;
     }
 
     // This is the response to our query, make sure it matches
     is(result, test_settings[which_test].result[curTest.id],
         "HSTS priming result " + which_test + ":" + curTest.id);
     test_settings[which_test].finished[curTest.id] = result;
+    if (this.listeners[uri]) {
+      this.listeners[uri] = undefined;
+    }
   },
 };
 
 // opens `uri' in a new tab and focuses it.
 // returns the newly opened tab
 function openTab(uri) {
   let tab = gBrowser.addTab(uri);
 
@@ -267,41 +337,43 @@ function SetupPrefTestEnvironment(which,
 
   var prefs = [["security.mixed_content.block_active_content",
                 settings.block_active],
                ["security.mixed_content.block_display_content",
                 settings.block_display],
                ["security.mixed_content.use_hsts",
                 settings.use_hsts],
                ["security.mixed_content.send_hsts_priming",
-                settings.send_hsts_priming]];
+                settings.send_hsts_priming],
+  ];
 
   if (additional_prefs) {
     for (let idx in additional_prefs) {
       prefs.push(additional_prefs[idx]);
     }
   }
 
-  console.log("prefs=%s", prefs);
-
   SpecialPowers.pushPrefEnv({'set': prefs});
 }
 
 // make the top-level test uri
-function build_test_uri(base_uri, host, test_id, type) {
+function build_test_uri(base_uri, host, test_id, type, timeout) {
   return base_uri +
           "?host=" + escape(host) +
           "&id=" + escape(test_id) +
-          "&type=" + escape(type);
+          "&type=" + escape(type) +
+          "&timeout=" + escape(timeout)
+    ;
 }
 
 // open a new tab, load the test, and wait for it to finish
 function execute_test(test, mimetype) {
   var src = build_test_uri(TOP_URI, test_servers[test].host,
-      test, test_settings[which_test].type);
+      test, test_settings[which_test].type,
+      test_settings[which_test].timeout);
 
   let tab = openTab(src);
   test_servers[test]['tab'] = tab;
 
   let browser = gBrowser.getBrowserForTab(tab);
   yield BrowserTestUtils.browserLoaded(browser);
 
   yield BrowserTestUtils.removeTab(tab);
--- a/gfx/layers/ipc/PAPZCTreeManager.ipdl
+++ b/gfx/layers/ipc/PAPZCTreeManager.ipdl
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include "mozilla/GfxMessageUtils.h";
 include "ipc/nsGUIEventIPC.h";
+include "mozilla/dom/TabMessageUtils.h"; // Needed for IPC::ParamTraits<nsEventStatus>.
 
 include protocol PCompositorBridge;
 
 using CSSRect from "Units.h";
 using LayoutDeviceCoord from "Units.h";
 using LayoutDeviceIntPoint from "Units.h";
 using mozilla::LayoutDevicePoint from "Units.h";
 using ScreenPoint from "Units.h";
--- a/js/src/jit/ExecutableAllocatorWin.cpp
+++ b/js/src/jit/ExecutableAllocatorWin.cpp
@@ -20,19 +20,17 @@
  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifdef MOZ_STACKWALKING
 #include "mozilla/StackWalk_windows.h"
-#endif
 
 #include "mozilla/WindowsVersion.h"
 
 #include "jsfriendapi.h"
 #include "jsmath.h"
 #include "jswin.h"
 
 #include "jit/ExecutableAllocator.h"
@@ -166,45 +164,37 @@ RegisterExecutableMemory(void* p, size_t
     r->thunk[10] = 0xff;
     r->thunk[11] = 0xe0;
 
     if (!VirtualProtect(p, pageSize, PAGE_EXECUTE_READ, &oldProtect))
         return false;
 
     // XXX NB: The profiler believes this function is only called from the main
     // thread. If that ever becomes untrue, SPS must be updated immediately.
-#ifdef MOZ_STACKWALKING
     AcquireStackWalkWorkaroundLock();
-#endif
 
     bool success = RtlAddFunctionTable(&r->runtimeFunction, 1, reinterpret_cast<DWORD64>(p));
 
-#ifdef MOZ_STACKWALKING
     ReleaseStackWalkWorkaroundLock();
-#endif
 
     return success;
 }
 
 static void
 UnregisterExecutableMemory(void* p, size_t bytes, size_t pageSize)
 {
     ExceptionHandlerRecord* r = reinterpret_cast<ExceptionHandlerRecord*>(p);
 
     // XXX NB: The profiler believes this function is only called from the main
     // thread. If that ever becomes untrue, SPS must be updated immediately.
-#ifdef MOZ_STACKWALKING
     AcquireStackWalkWorkaroundLock();
-#endif
 
     RtlDeleteFunctionTable(&r->runtimeFunction);
 
-#ifdef MOZ_STACKWALKING
     ReleaseStackWalkWorkaroundLock();
-#endif
 }
 #endif
 
 void*
 js::jit::AllocateExecutableMemory(void* addr, size_t bytes, unsigned permissions, const char* tag,
                                   size_t pageSize)
 {
     MOZ_ASSERT(bytes % pageSize == 0);
--- a/js/src/old-configure.in
+++ b/js/src/old-configure.in
@@ -1507,43 +1507,16 @@ fi # COMPILE_ENVIRONMENT
 
 AC_SUBST(MOZ_OPTIMIZE)
 AC_SUBST(MOZ_FRAMEPTR_FLAGS)
 AC_SUBST(MOZ_OPTIMIZE_FLAGS)
 AC_SUBST(MOZ_OPTIMIZE_LDFLAGS)
 AC_SUBST(MOZ_PGO_OPTIMIZE_FLAGS)
 
 dnl ========================================================
-dnl = Enable NS_StackWalk.
-dnl ========================================================
-
-# On Windows, NS_StackWalk will only work correctly if we have frame pointers
-# available. That will only be true for non-optimized builds, debug builds or
-# builds with --enable-profiling in the .mozconfig (which is turned on in
-# Nightly by default.)
-case "$OS_TARGET" in
-WINNT)
-    if test -z "$MOZ_OPTIMIZE" -o -n "$MOZ_PROFILING" -o -n "$MOZ_DEBUG"; then
-        MOZ_STACKWALKING=1
-    else
-        MOZ_STACKWALKING=
-    fi
-    ;;
-*)
-    MOZ_STACKWALKING=1
-    ;;
-esac
-
-if test -n "$MOZ_STACKWALKING"; then
-    AC_DEFINE(MOZ_STACKWALKING)
-fi
-
-AC_SUBST(MOZ_STACKWALKING)
-
-dnl ========================================================
 dnl = Disable trace logging
 dnl ========================================================
 ENABLE_TRACE_LOGGING=1
 MOZ_ARG_DISABLE_BOOL(trace-logging,
 [  --disable-trace-logging   Disable trace logging],
     ENABLE_TRACE_LOGGING= )
 
 AC_SUBST(ENABLE_TRACE_LOGGING)
--- a/layout/generic/nsTextFrameUtils.cpp
+++ b/layout/generic/nsTextFrameUtils.cpp
@@ -10,56 +10,192 @@
 #include "nsIContent.h"
 #include "nsStyleStruct.h"
 #include "nsTextFragment.h"
 #include "nsUnicharUtils.h"
 #include <algorithm>
 
 using namespace mozilla;
 
-static bool IsDiscardable(char16_t ch, uint32_t* aFlags)
+static bool
+IsDiscardable(char16_t ch, uint32_t* aFlags)
 {
   // Unlike IS_DISCARDABLE, we don't discard \r. \r will be ignored by gfxTextRun
   // and discarding it would force us to copy text in many cases of preformatted
   // text containing \r\n.
   if (ch == CH_SHY) {
     *aFlags |= nsTextFrameUtils::TEXT_HAS_SHY;
     return true;
   }
   return IsBidiControl(ch);
 }
 
-static bool IsDiscardable(uint8_t ch, uint32_t* aFlags)
+static bool
+IsDiscardable(uint8_t ch, uint32_t* aFlags)
 {
   if (ch == CH_SHY) {
     *aFlags |= nsTextFrameUtils::TEXT_HAS_SHY;
     return true;
   }
   return false;
 }
 
-char16_t*
-nsTextFrameUtils::TransformText(const char16_t* aText, uint32_t aLength,
-                                char16_t* aOutput,
+static bool
+IsSegmentBreak(char16_t aCh)
+{
+  return aCh == '\n' || aCh == '\r';
+}
+
+static bool
+IsSpaceOrTab(char16_t aCh)
+{
+  return aCh == ' ' || aCh == '\t';
+}
+
+static bool
+IsSpaceOrTabOrSegmentBreak(char16_t aCh)
+{
+  return IsSpaceOrTab(aCh) || IsSegmentBreak(aCh);
+}
+
+template<class CharT>
+static CharT*
+TransformWhiteSpaces(const CharT* aText, uint32_t aLength,
+                     uint32_t aBegin, uint32_t aEnd,
+                     bool aHasSegmentBreak,
+                     bool& aInWhitespace,
+                     CharT* aOutput,
+                     uint32_t& aFlags,
+                     nsTextFrameUtils::CompressionMode aCompression,
+                     gfxSkipChars* aSkipChars)
+{
+  MOZ_ASSERT(aCompression == nsTextFrameUtils::COMPRESS_WHITESPACE ||
+             aCompression == nsTextFrameUtils::COMPRESS_WHITESPACE_NEWLINE,
+             "whitespaces should be skippable!!");
+  // Get the context preceding/following this white space range.
+  // For 8-bit text (sizeof CharT == 1), the checks here should get optimized
+  // out, and isSegmentBreakSkippable should be initialized to be 'false'.
+  bool isSegmentBreakSkippable =
+    sizeof(CharT) > 1 &&
+    ((aBegin > 0 && IS_ZERO_WIDTH_SPACE(aText[aBegin - 1])) ||
+     (aEnd < aLength && IS_ZERO_WIDTH_SPACE(aText[aEnd])));
+  if (sizeof(CharT) > 1 && !isSegmentBreakSkippable &&
+      aBegin > 0 && aEnd < aLength) {
+    uint32_t ucs4before;
+    uint32_t ucs4after;
+    if (aBegin > 1 &&
+        NS_IS_LOW_SURROGATE(aText[aBegin - 1]) &&
+        NS_IS_HIGH_SURROGATE(aText[aBegin - 2])) {
+      ucs4before = SURROGATE_TO_UCS4(aText[aBegin - 2], aText[aBegin - 1]);
+    } else {
+      ucs4before = aText[aBegin - 1];
+    }
+    if (aEnd + 1 < aLength &&
+        NS_IS_HIGH_SURROGATE(aText[aEnd]) &&
+        NS_IS_LOW_SURROGATE(aText[aEnd + 1])) {
+      ucs4after = SURROGATE_TO_UCS4(aText[aEnd], aText[aEnd + 1]);
+    } else {
+      ucs4after = aText[aEnd];
+    }
+    // Discard newlines between characters that have F, W, or H
+    // EastAsianWidth property and neither side is Hangul.
+    isSegmentBreakSkippable = IsSegmentBreakSkipChar(ucs4before) &&
+                              IsSegmentBreakSkipChar(ucs4after);
+  }
+
+  for (uint32_t i = aBegin; i < aEnd; ++i) {
+    CharT ch = aText[i];
+    bool keepChar = false;
+    bool keepTransformedWhiteSpace = false;
+    if (IsDiscardable(ch, &aFlags)) {
+      aSkipChars->SkipChar();
+      continue;
+    }
+    if (IsSpaceOrTab(ch)) {
+      if (aHasSegmentBreak) {
+        // If white-space is set to normal, nowrap, or pre-line, white space
+        // characters are considered collapsible and all spaces and tabs
+        // immediately preceding or following a segment break are removed.
+        aSkipChars->SkipChar();
+        continue;
+      }
+
+      if (aInWhitespace) {
+        aSkipChars->SkipChar();
+        continue;
+      } else {
+        keepTransformedWhiteSpace = true;
+      }
+    } else {
+      // Apply Segment Break Transformation Rules (CSS Text 3 - 4.1.2) for
+      // segment break characters.
+      if (aCompression == nsTextFrameUtils::COMPRESS_WHITESPACE ||
+          // XXX: According to CSS Text 3, a lone CR should not always be
+          //      kept, but still go through the Segment Break Transformation
+          //      Rules. However, this is what current modern browser engines
+          //      (webkit/blink/edge) do. So, once we can get some clarity
+          //      from the specification issue, we should either remove the
+          //      lone CR condition here, or leave it here with this comment
+          //      being rephrased.
+          //      Please see https://github.com/w3c/csswg-drafts/issues/855.
+          ch == '\r') {
+        keepChar = true;
+      } else {
+        // aCompression == COMPRESS_WHITESPACE_NEWLINE
+
+        // Any collapsible segment break immediately following another
+        // collapsible segment break is removed.  Then the remaining segment
+        // break is either transformed into a space (U+0020) or removed
+        // depending on the context before and after the break.
+        if (isSegmentBreakSkippable || aInWhitespace) {
+          aSkipChars->SkipChar();
+          continue;
+        }
+        isSegmentBreakSkippable = true;
+        keepTransformedWhiteSpace = true;
+      }
+    }
+
+    if (keepChar) {
+      *aOutput++ = ch;
+      aSkipChars->KeepChar();
+      aInWhitespace = IsSpaceOrTab(ch);
+    } else if (keepTransformedWhiteSpace) {
+      if (ch != ' ') {
+        aFlags |= nsTextFrameUtils::TEXT_WAS_TRANSFORMED;
+      }
+      *aOutput++ = ' ';
+      aSkipChars->KeepChar();
+      aInWhitespace = true;
+    } else {
+      MOZ_ASSERT_UNREACHABLE("Should've skipped the character!!");
+    }
+  }
+  return aOutput;
+}
+
+template<class CharT>
+CharT*
+nsTextFrameUtils::TransformText(const CharT* aText, uint32_t aLength,
+                                CharT* aOutput,
                                 CompressionMode aCompression,
                                 uint8_t* aIncomingFlags,
                                 gfxSkipChars* aSkipChars,
                                 uint32_t* aAnalysisFlags)
 {
   uint32_t flags = 0;
-  char16_t* outputStart = aOutput;
+  CharT* outputStart = aOutput;
 
   bool lastCharArabic = false;
-
   if (aCompression == COMPRESS_NONE ||
       aCompression == COMPRESS_NONE_TRANSFORM_TO_SPACE) {
     // Skip discardables.
     uint32_t i;
     for (i = 0; i < aLength; ++i) {
-      char16_t ch = aText[i];
+      CharT ch = aText[i];
       if (IsDiscardable(ch, &flags)) {
         aSkipChars->SkipChar();
       } else {
         aSkipChars->KeepChar();
         if (ch > ' ') {
           lastCharArabic = IS_ARABIC_CHAR(ch);
         } else if (aCompression == COMPRESS_NONE_TRANSFORM_TO_SPACE) {
           if (ch == '\t' || ch == '\n') {
@@ -80,78 +216,82 @@ nsTextFrameUtils::TransformText(const ch
     } else {
       *aIncomingFlags &= ~INCOMING_ARABICCHAR;
     }
     *aIncomingFlags &= ~INCOMING_WHITESPACE;
   } else {
     bool inWhitespace = (*aIncomingFlags & INCOMING_WHITESPACE) != 0;
     uint32_t i;
     for (i = 0; i < aLength; ++i) {
-      char16_t ch = aText[i];
-      bool nowInWhitespace;
-      if (ch == ' ' &&
-          (i + 1 >= aLength ||
-           !IsSpaceCombiningSequenceTail(&aText[i + 1], aLength - (i + 1)))) {
-        nowInWhitespace = true;
-      } else if (ch == '\n' && aCompression == COMPRESS_WHITESPACE_NEWLINE) {
-        if ((i > 0 && IS_ZERO_WIDTH_SPACE(aText[i - 1])) ||
-            (i + 1 < aLength && IS_ZERO_WIDTH_SPACE(aText[i + 1]))) {
-          aSkipChars->SkipChar();
-          continue;
-        }
-        uint32_t ucs4before;
-        uint32_t ucs4after;
-        if (i > 1 &&
-            NS_IS_LOW_SURROGATE(aText[i - 1]) &&
-            NS_IS_HIGH_SURROGATE(aText[i - 2])) {
-          ucs4before = SURROGATE_TO_UCS4(aText[i - 2], aText[i - 1]);
-        } else if (i > 0) {
-          ucs4before = aText[i - 1];
-        }
-        if (i + 2 < aLength &&
-            NS_IS_HIGH_SURROGATE(aText[i + 1]) &&
-            NS_IS_LOW_SURROGATE(aText[i + 2])) {
-          ucs4after = SURROGATE_TO_UCS4(aText[i + 1], aText[i + 2]);
-        } else if (i + 1 < aLength) {
-          ucs4after = aText[i + 1];
+      CharT ch = aText[i];
+      // CSS Text 3 - 4.1. The White Space Processing Rules
+      // White space processing in CSS affects only the document white space
+      // characters: spaces (U+0020), tabs (U+0009), and segment breaks.
+      // Since we need the context of segment breaks and their surrounding
+      // white spaces to proceed the white space processing, a consecutive run
+      // of spaces/tabs/segment breaks is collected in a first pass loop, then
+      // we apply the collapsing and transformation rules to this run in a
+      // second pass loop.
+      if (IsSpaceOrTabOrSegmentBreak(ch)) {
+        bool keepLastSpace = false;
+        bool hasSegmentBreak = IsSegmentBreak(ch);
+        uint32_t countTrailingDiscardables = 0;
+        uint32_t j;
+        for (j = i + 1; j < aLength &&
+                        (IsSpaceOrTabOrSegmentBreak(aText[j]) ||
+                         IsDiscardable(aText[j], &flags));
+             j++) {
+          if (IsSegmentBreak(aText[j])) {
+            hasSegmentBreak = true;
+          }
         }
-        if (i > 0 && IsSegmentBreakSkipChar(ucs4before) &&
-            i + 1 < aLength && IsSegmentBreakSkipChar(ucs4after)) {
-          // Discard newlines between characters that have F, W, or H
-          // EastAsianWidth property and neither side is Hangul.
-          aSkipChars->SkipChar();
-          continue;
+        // Exclude trailing discardables before checking space combining
+        // sequence tail.
+        for (; IsDiscardable(aText[j - 1], &flags); j--) {
+          countTrailingDiscardables++;
         }
-        nowInWhitespace = true;
-      } else {
-        nowInWhitespace = ch == '\t';
-      }
-
-      if (!nowInWhitespace) {
-        if (IsDiscardable(ch, &flags)) {
-          aSkipChars->SkipChar();
-          nowInWhitespace = inWhitespace;
-        } else {
-          *aOutput++ = ch;
-          aSkipChars->KeepChar();
-          lastCharArabic = IS_ARABIC_CHAR(ch);
+        // If the last white space is followed by a combining sequence tail,
+        // exclude it from the range of TransformWhiteSpaces.
+        if (sizeof(CharT) > 1 && aText[j - 1] == ' ' && j < aLength &&
+            IsSpaceCombiningSequenceTail(&aText[j], aLength - j)) {
+          keepLastSpace = true;
+          j--;
         }
-      } else {
-        if (inWhitespace) {
-          aSkipChars->SkipChar();
-        } else {
-          if (ch != ' ') {
-            flags |= TEXT_WAS_TRANSFORMED;
-          }
+        if (j > i) {
+          aOutput = TransformWhiteSpaces(aText, aLength, i, j, hasSegmentBreak,
+                                         inWhitespace, aOutput, flags,
+                                         aCompression, aSkipChars);
+        }
+        // We need to keep KeepChar()/SkipChar() in order, so process the
+        // last white space first, then process the trailing discardables.
+        if (keepLastSpace) {
+          keepLastSpace = false;
           *aOutput++ = ' ';
           aSkipChars->KeepChar();
+          lastCharArabic = false;
+          j++;
         }
+        for (; countTrailingDiscardables > 0; countTrailingDiscardables--) {
+          aSkipChars->SkipChar();
+          j++;
+        }
+        i = j - 1;
+        continue;
       }
-      inWhitespace = nowInWhitespace;
+      // Process characters other than the document white space characters.
+      if (IsDiscardable(ch, &flags)) {
+        aSkipChars->SkipChar();
+      } else {
+        *aOutput++ = ch;
+        aSkipChars->KeepChar();
+      }
+      lastCharArabic = IS_ARABIC_CHAR(ch);
+      inWhitespace = false;
     }
+
     if (lastCharArabic) {
       *aIncomingFlags |= INCOMING_ARABICCHAR;
     } else {
       *aIncomingFlags &= ~INCOMING_ARABICCHAR;
     }
     if (inWhitespace) {
       *aIncomingFlags |= INCOMING_WHITESPACE;
     } else {
@@ -160,95 +300,38 @@ nsTextFrameUtils::TransformText(const ch
   }
 
   if (outputStart + aLength != aOutput) {
     flags |= TEXT_WAS_TRANSFORMED;
   }
   *aAnalysisFlags = flags;
   return aOutput;
 }
-
-uint8_t*
+/*
+ * NOTE: This template is part of public API of nsTextFrameUtils, while
+ * its function body is not available in the header. It may stop working
+ * (fail to resolve symbol in link time) once its callsites are moved to a
+ * different translation unit (e.g. a different unified source file).
+ * Explicit instantiating this function template with `uint8_t` and `char16_t`
+ * could prevent us from the potential risk.
+ */
+template uint8_t*
 nsTextFrameUtils::TransformText(const uint8_t* aText, uint32_t aLength,
                                 uint8_t* aOutput,
                                 CompressionMode aCompression,
                                 uint8_t* aIncomingFlags,
                                 gfxSkipChars* aSkipChars,
-                                uint32_t* aAnalysisFlags)
-{
-  uint32_t flags = 0;
-  uint8_t* outputStart = aOutput;
-
-  if (aCompression == COMPRESS_NONE ||
-      aCompression == COMPRESS_NONE_TRANSFORM_TO_SPACE) {
-    // Skip discardables.
-    uint32_t i;
-    for (i = 0; i < aLength; ++i) {
-      uint8_t ch = aText[i];
-      if (IsDiscardable(ch, &flags)) {
-        aSkipChars->SkipChar();
-      } else {
-        aSkipChars->KeepChar();
-        if (aCompression == COMPRESS_NONE_TRANSFORM_TO_SPACE) {
-          if (ch == '\t' || ch == '\n') {
-            ch = ' ';
-            flags |= TEXT_WAS_TRANSFORMED;
-          }
-        } else {
-          // aCompression == COMPRESS_NONE
-          if (ch == '\t') {
-            flags |= TEXT_HAS_TAB;
-          }
-        }
-        *aOutput++ = ch;
-      }
-    }
-    *aIncomingFlags &= ~(INCOMING_ARABICCHAR | INCOMING_WHITESPACE);
-  } else {
-    bool inWhitespace = (*aIncomingFlags & INCOMING_WHITESPACE) != 0;
-    uint32_t i;
-    for (i = 0; i < aLength; ++i) {
-      uint8_t ch = aText[i];
-      bool nowInWhitespace = ch == ' ' || ch == '\t' ||
-        (ch == '\n' && aCompression == COMPRESS_WHITESPACE_NEWLINE);
-      if (!nowInWhitespace) {
-        if (IsDiscardable(ch, &flags)) {
-          aSkipChars->SkipChar();
-          nowInWhitespace = inWhitespace;
-        } else {
-          *aOutput++ = ch;
-          aSkipChars->KeepChar();
-        }
-      } else {
-        if (inWhitespace) {
-          aSkipChars->SkipChar();
-        } else {
-          if (ch != ' ') {
-            flags |= TEXT_WAS_TRANSFORMED;
-          }
-          *aOutput++ = ' ';
-          aSkipChars->KeepChar();
-        }
-      }
-      inWhitespace = nowInWhitespace;
-    }
-    *aIncomingFlags &= ~INCOMING_ARABICCHAR;
-    if (inWhitespace) {
-      *aIncomingFlags |= INCOMING_WHITESPACE;
-    } else {
-      *aIncomingFlags &= ~INCOMING_WHITESPACE;
-    }
-  }
-
-  if (outputStart + aLength != aOutput) {
-    flags |= TEXT_WAS_TRANSFORMED;
-  }
-  *aAnalysisFlags = flags;
-  return aOutput;
-}
+                                uint32_t* aAnalysisFlags);
+template char16_t*
+nsTextFrameUtils::TransformText(const char16_t* aText, uint32_t aLength,
+                                char16_t* aOutput,
+                                CompressionMode aCompression,
+                                uint8_t* aIncomingFlags,
+                                gfxSkipChars* aSkipChars,
+                                uint32_t* aAnalysisFlags);
 
 uint32_t
 nsTextFrameUtils::ComputeApproximateLengthWithWhitespaceCompression(
                     nsIContent *aContent, const nsStyleText *aStyleText)
 {
   const nsTextFragment *frag = aContent->GetText();
   // This is an approximation so we don't really need anything
   // too fancy here.
--- a/layout/generic/nsTextFrameUtils.h
+++ b/layout/generic/nsTextFrameUtils.h
@@ -82,51 +82,49 @@ public:
   IsSpaceCombiningSequenceTail(const char16_t* aChars, int32_t aLength) {
     return aLength > 0 &&
       (mozilla::unicode::IsClusterExtender(aChars[0]) ||
        (IsBidiControl(aChars[0]) &&
         IsSpaceCombiningSequenceTail(aChars + 1, aLength - 1)
        )
       );
   }
+  static bool
+  IsSpaceCombiningSequenceTail(const uint8_t* aChars, int32_t aLength) {
+    return false;
+  }
 
   enum CompressionMode {
     COMPRESS_NONE,
     COMPRESS_WHITESPACE,
     COMPRESS_WHITESPACE_NEWLINE,
     COMPRESS_NONE_TRANSFORM_TO_SPACE
   };
 
   /**
    * Create a text run from a run of Unicode text. The text may have whitespace
    * compressed. A preformatted tab is sent to the text run as a single space.
    * (Tab spacing must be performed by textframe later.) Certain other
    * characters are discarded.
-   * 
+   *
    * @param aCompression control what is compressed to a
    * single space character: no compression, compress spaces (not followed
    * by combining mark) and tabs, compress those plus newlines, or
    * no compression except newlines are discarded.
    * @param aIncomingFlags a flag indicating whether there was whitespace
    * or an Arabic character preceding this text. We set it to indicate if
    * there's an Arabic character or whitespace preceding the end of this text.
    */
-  static char16_t* TransformText(const char16_t* aText, uint32_t aLength,
-                                 char16_t* aOutput,
-                                 CompressionMode aCompression,
-                                 uint8_t* aIncomingFlags,
-                                 gfxSkipChars* aSkipChars,
-                                 uint32_t* aAnalysisFlags);
-
-  static uint8_t* TransformText(const uint8_t* aText, uint32_t aLength,
-                                uint8_t* aOutput,
-                                CompressionMode aCompression,
-                                uint8_t* aIncomingFlags,
-                                gfxSkipChars* aSkipChars,
-                                uint32_t* aAnalysisFlags);
+  template<class CharT>
+  static CharT* TransformText(const CharT* aText, uint32_t aLength,
+                              CharT* aOutput,
+                              CompressionMode aCompression,
+                              uint8_t* aIncomingFlags,
+                              gfxSkipChars* aSkipChars,
+                              uint32_t* aAnalysisFlags);
 
   static void
   AppendLineBreakOffset(nsTArray<uint32_t>* aArray, uint32_t aOffset)
   {
     if (aArray->Length() > 0 && (*aArray)[aArray->Length() - 1] == aOffset)
       return;
     aArray->AppendElement(aOffset);
   }
--- a/layout/reftests/w3c-css/submitted/reftest.list
+++ b/layout/reftests/w3c-css/submitted/reftest.list
@@ -51,17 +51,22 @@ include ruby/reftest.list
 
 # Selectors Level 4
 include selectors4/reftest.list
 
 # Shapes Level 1
 include shapes1/reftest.list
 
 # Text Level 3
-include text3/reftest.list
+# After Bug 1316482, we've added a large number of tests in this folder, which
+# indirectly causes frequent reftest failures on win7 debug. (see Bug 1300355)
+# Since the root cause is not these tests, skip them on win7 debug for now.
+# Once we come up with a better solution, we should re-enable this folder on
+# win7 debug.
+skip-if(winWidget&&isDebugBuild) include text3/reftest.list
 
 # Text Decoration Level 3
 include text-decor-3/reftest.list
 
 # Transforms
 include transforms/reftest.list
 
 # User Interface Level 3
--- a/layout/reftests/w3c-css/submitted/text3/reftest.list
+++ b/layout/reftests/w3c-css/submitted/text3/reftest.list
@@ -1,8 +1,67 @@
 == text-align-match-parent-01.html text-align-match-parent-ref.html
 == text-align-match-parent-02.html text-align-match-parent-ref.html
 == text-align-match-parent-03.html text-align-match-parent-ref.html
 == text-align-match-parent-04.html text-align-match-parent-ref.html
 == text-align-match-parent-root-ltr.html text-align-match-parent-root-ltr-ref.html
 == text-align-match-parent-root-rtl.html text-align-match-parent-root-rtl-ref.html
 
 == text-word-spacing-001.html text-word-spacing-ref.html
+
+== segment-break-transformation-removable-1.html segment-break-transformation-removable-ref.html
+== segment-break-transformation-removable-2.html segment-break-transformation-removable-ref.html
+== segment-break-transformation-removable-3.html segment-break-transformation-removable-ref.html
+== segment-break-transformation-removable-4.html segment-break-transformation-removable-ref.html
+== segment-break-transformation-unremovable-1.html segment-break-transformation-unremovable-ref.html
+== segment-break-transformation-unremovable-2.html segment-break-transformation-unremovable-ref.html
+== segment-break-transformation-unremovable-3.html segment-break-transformation-unremovable-ref.html
+== segment-break-transformation-unremovable-4.html segment-break-transformation-unremovable-ref.html
+
+== segment-break-transformation-rules-001.html segment-break-transformation-rules-001-ref.html
+== segment-break-transformation-rules-002.html segment-break-transformation-rules-002-ref.html
+== segment-break-transformation-rules-003.html segment-break-transformation-rules-003-ref.html
+== segment-break-transformation-rules-004.html segment-break-transformation-rules-004-ref.html
+== segment-break-transformation-rules-005.html segment-break-transformation-rules-005-ref.html
+== segment-break-transformation-rules-006.html segment-break-transformation-rules-006-ref.html
+== segment-break-transformation-rules-007.html segment-break-transformation-rules-007-ref.html
+== segment-break-transformation-rules-008.html segment-break-transformation-rules-008-ref.html
+== segment-break-transformation-rules-009.html segment-break-transformation-rules-009-ref.html
+== segment-break-transformation-rules-010.html segment-break-transformation-rules-010-ref.html
+== segment-break-transformation-rules-011.html segment-break-transformation-rules-011-ref.html
+== segment-break-transformation-rules-012.html segment-break-transformation-rules-012-ref.html
+== segment-break-transformation-rules-013.html segment-break-transformation-rules-013-ref.html
+== segment-break-transformation-rules-014.html segment-break-transformation-rules-014-ref.html
+== segment-break-transformation-rules-015.html segment-break-transformation-rules-015-ref.html
+== segment-break-transformation-rules-016.html segment-break-transformation-rules-016-ref.html
+== segment-break-transformation-rules-017.html segment-break-transformation-rules-017-ref.html
+== segment-break-transformation-rules-018.html segment-break-transformation-rules-018-ref.html
+== segment-break-transformation-rules-019.html segment-break-transformation-rules-019-ref.html
+== segment-break-transformation-rules-020.html segment-break-transformation-rules-020-ref.html
+== segment-break-transformation-rules-021.html segment-break-transformation-rules-021-ref.html
+== segment-break-transformation-rules-022.html segment-break-transformation-rules-022-ref.html
+== segment-break-transformation-rules-023.html segment-break-transformation-rules-023-ref.html
+== segment-break-transformation-rules-024.html segment-break-transformation-rules-024-ref.html
+== segment-break-transformation-rules-025.html segment-break-transformation-rules-025-ref.html
+== segment-break-transformation-rules-026.html segment-break-transformation-rules-026-ref.html
+== segment-break-transformation-rules-027.html segment-break-transformation-rules-027-ref.html
+== segment-break-transformation-rules-028.html segment-break-transformation-rules-028-ref.html
+== segment-break-transformation-rules-029.html segment-break-transformation-rules-029-ref.html
+== segment-break-transformation-rules-030.html segment-break-transformation-rules-030-ref.html
+== segment-break-transformation-rules-031.html segment-break-transformation-rules-031-ref.html
+== segment-break-transformation-rules-032.html segment-break-transformation-rules-032-ref.html
+== segment-break-transformation-rules-033.html segment-break-transformation-rules-033-ref.html
+== segment-break-transformation-rules-034.html segment-break-transformation-rules-034-ref.html
+== segment-break-transformation-rules-035.html segment-break-transformation-rules-035-ref.html
+== segment-break-transformation-rules-036.html segment-break-transformation-rules-036-ref.html
+== segment-break-transformation-rules-037.html segment-break-transformation-rules-037-ref.html
+== segment-break-transformation-rules-038.html segment-break-transformation-rules-038-ref.html
+== segment-break-transformation-rules-039.html segment-break-transformation-rules-039-ref.html
+== segment-break-transformation-rules-040.html segment-break-transformation-rules-040-ref.html
+== segment-break-transformation-rules-041.html segment-break-transformation-rules-041-ref.html
+== segment-break-transformation-rules-042.html segment-break-transformation-rules-042-ref.html
+== segment-break-transformation-rules-043.html segment-break-transformation-rules-043-ref.html
+== segment-break-transformation-rules-044.html segment-break-transformation-rules-044-ref.html
+== segment-break-transformation-rules-045.html segment-break-transformation-rules-045-ref.html
+== segment-break-transformation-rules-046.html segment-break-transformation-rules-046-ref.html
+== segment-break-transformation-rules-047.html segment-break-transformation-rules-047-ref.html
+== segment-break-transformation-rules-048.html segment-break-transformation-rules-048-ref.html
+== segment-break-transformation-rules-049.html segment-break-transformation-rules-049-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-removable-1.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Text 4.1.2. Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<link rel="stylesheet" type="text/css" href="support/ahem.css">
+<link rel="match" href="segment-break-transformation-removable-ref.html">
+<meta name="assert" content="Test checks that a collapsible segment break should be removed correctly,
+if the character immediately before/after the segment break is the zero-width space character (U+200B),
+or both the character before/after the segment break is F, W, or H (not A), and neither side is Hangul.">
+<style> p { line-height: 1; font-family: ahem; } </style>
+</head>
+<body>
+<div>Test passes if there is <b>no</b> white space between 2nd and 3rd CJK character.
+<!--Some[LF]Chinese-->
+<p>&#x4e00;&#x4e9b;&#x000a;&#x4e2d;&#x6587;</p>
+<!--Some[ZWSP][LF]Chinese-->
+<p>&#x4e00;&#x4e9b;&#x200b;&#x000a;&#x4e2d;&#x6587;</p>
+<!--Some[LF][ZWSP]Chinese-->
+<p>&#x4e00;&#x4e9b;&#x000a;&#x200b;&#x4e2d;&#x6587;</p>
+<!--Some[ZWSP][LF]Hangul-->
+<p>&#x4e00;&#x4e9b;&#x200b;&#x000a;&#xc5b8;&#xbb38;</p>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-removable-2.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Text 4.1.2. Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<link rel="stylesheet" type="text/css" href="support/ahem.css">
+<link rel="match" href="segment-break-transformation-removable-ref.html">
+<meta name="assert" content="Test checks that multiple segment breaks should be removed correctly,
+if the character immediately before/after the segment breaks is the zero-width space character (U+200B),
+or both the character before/after the segment breaks is F, W, or H (not A), and neither side is Hangul.">
+<style> p { line-height: 1; font-family: ahem; } </style>
+</head>
+<body>
+<div>Test passes if there is <b>no</b> white space between 2nd and 3rd CJK character.
+<!--Some[LF][LF][LF]Chinese-->
+<p>&#x4e00;&#x4e9b;&#x000a;&#x000a;&#x000a;&#x4e2d;&#x6587;</p>
+<!--Some[ZWSP][LF][LF][LF]Chinese-->
+<p>&#x4e00;&#x4e9b;&#x200b;&#x000a;&#x000a;&#x000a;&#x4e2d;&#x6587;</p>
+<!--Some[LF][LF][LF][ZWSP]Chinese-->
+<p>&#x4e00;&#x4e9b;&#x000a;&#x000a;&#x000a;&#x200b;&#x4e2d;&#x6587;</p>
+<!--Some[ZWSP][LF][LF][LF]Hangul-->
+<p>&#x4e00;&#x4e9b;&#x200b;&#x000a;&#x000a;&#x000a;&#xc5b8;&#xbb38;</p>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-removable-3.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Text 4.1.2. Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<link rel="stylesheet" type="text/css" href="support/ahem.css">
+<link rel="match" href="segment-break-transformation-removable-ref.html">
+<meta name="assert" content="Test checks that a sequence which consists of a collapsible segment break
+surrounded by multiple white spaces should be removed correctly,
+if the character immediately before/after the sequence is the zero-width space character (U+200B),
+or both the character before/after the sequence is F, W, or H (not A), and neither side is Hangul.">
+<style> p { line-height: 1; font-family: ahem; } </style>
+</head>
+<body>
+<div>Test passes if there is <b>no</b> white space between 2nd and 3rd CJK character.
+<!--Some[WS][WS][LF][WS][WS]Chinese-->
+<p>&#x4e00;&#x4e9b;&#x0020;&#x0020;&#x000a;&#x0020;&#x0020;&#x4e2d;&#x6587;</p>
+<!--Some[ZWSP][WS][WS][LF][WS][WS]Chinese-->
+<p>&#x4e00;&#x4e9b;&#x200b;&#x0020;&#x0020;&#x000a;&#x0020;&#x0020;&#x4e2d;&#x6587;</p>
+<!--Some[WS][WS][LF][WS][WS][ZWSP]Chinese-->
+<p>&#x4e00;&#x4e9b;&#x0020;&#x0020;&#x000a;&#x0020;&#x0020;&#x200b;&#x4e2d;&#x6587;</p>
+<!--Some[ZWSP][WS][WS][LF][WS][WS]Hangul-->
+<p>&#x4e00;&#x4e9b;&#x200b;&#x0020;&#x0020;&#x000a;&#x0020;&#x0020;&#xc5b8;&#xbb38;</p>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-removable-4.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Text 4.1.2. Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<link rel="stylesheet" type="text/css" href="support/ahem.css">
+<link rel="match" href="segment-break-transformation-removable-ref.html">
+<meta name="assert" content="Test checks that a sequence which consists of multiple collapsible
+segment breaks mixed with multiple white spaces should be removed correctly,
+if the character immediately before/after the sequence is the zero-width space character (U+200B),
+or both the character before/after the sequence is F, W, or H (not A), and neither side is Hangul.">
+<style> p { line-height: 1; font-family: ahem; } </style>
+</head>
+<body>
+<div>Test passes if there is <b>no</b> white space between 2nd and 3rd CJK character.
+<!--Some[WS][LF][WS][LF][WS][LF][WS]Chinese-->
+<p>&#x4e00;&#x4e9b;&#x0020;&#x000a;&#x0020;&#x000a;&#x0020;&#x000a;&#x0020;&#x4e2d;&#x6587;</p>
+<!--Some[ZWSP][WS][LF][WS][LF][WS][LF][WS]Chinese-->
+<p>&#x4e00;&#x4e9b;&#x200b;&#x0020;&#x000a;&#x0020;&#x000a;&#x0020;&#x000a;&#x0020;&#x4e2d;&#x6587;</p>
+<!--Some[WS][LF][WS][LF][WS][LF][WS][ZWSP]Chinese-->
+<p>&#x4e00;&#x4e9b;&#x0020;&#x000a;&#x0020;&#x000a;&#x0020;&#x000a;&#x0020;&#x200b;&#x4e2d;&#x6587;</p>
+<!--Some[ZWSP][WS][LF][WS][LF][WS][LF][WS]Hangul-->
+<p>&#x4e00;&#x4e9b;&#x200b;&#x0020;&#x000a;&#x0020;&#x000a;&#x0020;&#x000a;&#x0020;&#xc5b8;&#xbb38;</p>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-removable-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Text 4.1.2. Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { line-height: 1; font-family: ahem; } </style>
+</head>
+<body>
+<div>Test passes if there is <b>no</b> white space between 2nd and 3rd CJK character.
+<!--Some Chinese-->
+<p>&#x4e00;&#x4e9b;&#x4e2d;&#x6587;</p>
+<!--Some Chinese-->
+<p>&#x4e00;&#x4e9b;&#x4e2d;&#x6587;</p>
+<!--Some Chinese-->
+<p>&#x4e00;&#x4e9b;&#x4e2d;&#x6587;</p>
+<!--Some Hangul-->
+<p>&#x4e00;&#x4e9b;&#xc5b8;&#xbb38;</p>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-001-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is NO white space between the two strings below.
+<p>FULLWIDTHFULLWIDTH</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-001.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Full-width (F)/East Asian Full-width (F) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-001-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is NO white space between the two strings below.
+<p>FULLWIDTH&#x000a;FULLWIDTH</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-002-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is NO white space between the two strings below.
+<p>FULLWIDTHテスト</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-002.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Full-width (F)/East Asian Half-width (H) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-002-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is NO white space between the two strings below.
+<p>FULLWIDTH&#x000a;テスト</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-003-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is NO white space between the two strings below.
+<p>FULLWIDTH測試</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-003.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Full-width (F)/East Asian Wide (W) except Hangul in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-003-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is NO white space between the two strings below.
+<p>FULLWIDTH&#x000a;測試</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-004-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>FULLWIDTH&#x0020;narrow</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-004.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Full-width (F)/East Asian Narrow (Na) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-004-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>FULLWIDTH&#x000a;narrow</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-005-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>FULLWIDTH&#x0020;■</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-005.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Full-width (F)/East Asian Ambiguous (A) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-005-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>FULLWIDTH&#x000a;■</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-006-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>FULLWIDTH&#x0020;آزمون</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-006.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Full-width (F)/Not East Asian (Neutral) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-006-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>FULLWIDTH&#x000a;آزمون</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-007-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>FULLWIDTH&#x0020;테스트</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-007.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Full-width (F)/Hangul in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-007-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>FULLWIDTH&#x000a;테스트</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-008-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is NO white space between the two strings below.
+<p>テストFULLWIDTH</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-008.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Half-width (H)/East Asian Full-width (F) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-008-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is NO white space between the two strings below.
+<p>テスト&#x000a;FULLWIDTH</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-009-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is NO white space between the two strings below.
+<p>テストテスト</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-009.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Half-width (H)/East Asian Half-width (H) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-009-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is NO white space between the two strings below.
+<p>テスト&#x000a;テスト</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-010-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is NO white space between the two strings below.
+<p>テスト測試</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-010.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Half-width (H)/East Asian Wide (W) except Hangul in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-010-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is NO white space between the two strings below.
+<p>テスト&#x000a;測試</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-011-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>テスト&#x0020;narrow</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-011.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Half-width (H)/East Asian Narrow (Na) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-011-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>テスト&#x000a;narrow</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-012-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>テスト&#x0020;■</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-012.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Half-width (H)/East Asian Ambiguous (A) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-012-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>テスト&#x000a;■</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-013-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>テスト&#x0020;آزمون</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-013.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Half-width (H)/Not East Asian (Neutral) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-013-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>テスト&#x000a;آزمون</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-014-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>テスト&#x0020;테스트</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-014.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Half-width (H)/Hangul in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-014-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>テスト&#x000a;테스트</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-015-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is NO white space between the two strings below.
+<p>測試FULLWIDTH</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-015.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Wide (W) except Hangul/East Asian Full-width (F) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-015-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is NO white space between the two strings below.
+<p>測試&#x000a;FULLWIDTH</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-016-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is NO white space between the two strings below.
+<p>測試テスト</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-016.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Wide (W) except Hangul/East Asian Half-width (H) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-016-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is NO white space between the two strings below.
+<p>測試&#x000a;テスト</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-017-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is NO white space between the two strings below.
+<p>測試測試</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-017.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Wide (W) except Hangul/East Asian Wide (W) except Hangul in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-017-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is NO white space between the two strings below.
+<p>測試&#x000a;測試</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-018-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>測試&#x0020;narrow</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-018.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Wide (W) except Hangul/East Asian Narrow (Na) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-018-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>測試&#x000a;narrow</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-019-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>測試&#x0020;■</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-019.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Wide (W) except Hangul/East Asian Ambiguous (A) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-019-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>測試&#x000a;■</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-020-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>測試&#x0020;آزمون</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-020.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Wide (W) except Hangul/Not East Asian (Neutral) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-020-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>測試&#x000a;آزمون</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-021-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>測試&#x0020;테스트</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-021.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Wide (W) except Hangul/Hangul in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-021-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>測試&#x000a;테스트</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-022-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>narrow&#x0020;FULLWIDTH</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-022.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Narrow (Na)/East Asian Full-width (F) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-022-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>narrow&#x000a;FULLWIDTH</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-023-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>narrow&#x0020;テスト</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-023.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Narrow (Na)/East Asian Half-width (H) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-023-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>narrow&#x000a;テスト</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-024-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>narrow&#x0020;測試</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-024.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Narrow (Na)/East Asian Wide (W) except Hangul in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-024-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>narrow&#x000a;測試</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-025-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>narrow&#x0020;narrow</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-025.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Narrow (Na)/East Asian Narrow (Na) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-025-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>narrow&#x000a;narrow</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-026-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>narrow&#x0020;■</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-026.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Narrow (Na)/East Asian Ambiguous (A) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-026-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>narrow&#x000a;■</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-027-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>narrow&#x0020;آزمون</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-027.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Narrow (Na)/Not East Asian (Neutral) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-027-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>narrow&#x000a;آزمون</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-028-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>narrow&#x0020;테스트</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-028.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Narrow (Na)/Hangul in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-028-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>narrow&#x000a;테스트</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-029-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>■&#x0020;FULLWIDTH</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-029.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Ambiguous (A)/East Asian Full-width (F) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-029-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>■&#x000a;FULLWIDTH</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-030-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>■&#x0020;テスト</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-030.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Ambiguous (A)/East Asian Half-width (H) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-030-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>■&#x000a;テスト</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-031-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>■&#x0020;測試</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-031.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Ambiguous (A)/East Asian Wide (W) except Hangul in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-031-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>■&#x000a;測試</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-032-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>■&#x0020;narrow</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-032.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Ambiguous (A)/East Asian Narrow (Na) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-032-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>■&#x000a;narrow</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-033-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>■&#x0020;■</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-033.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Ambiguous (A)/East Asian Ambiguous (A) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-033-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>■&#x000a;■</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-034-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>■&#x0020;آزمون</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-034.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Ambiguous (A)/Not East Asian (Neutral) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-034-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>■&#x000a;آزمون</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-035-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>■&#x0020;테스트</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-035.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with East Asian Ambiguous (A)/Hangul in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-035-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>■&#x000a;테스트</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-036-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>آزمون&#x0020;FULLWIDTH</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-036.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with Not East Asian (Neutral)/East Asian Full-width (F) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-036-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>آزمون&#x000a;FULLWIDTH</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-037-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>آزمون&#x0020;テスト</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-037.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with Not East Asian (Neutral)/East Asian Half-width (H) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-037-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>آزمون&#x000a;テスト</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-038-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>آزمون&#x0020;測試</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-038.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with Not East Asian (Neutral)/East Asian Wide (W) except Hangul in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-038-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>آزمون&#x000a;測試</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-039-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>آزمون&#x0020;narrow</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-039.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with Not East Asian (Neutral)/East Asian Narrow (Na) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-039-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>آزمون&#x000a;narrow</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-040-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>آزمون&#x0020;■</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-040.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with Not East Asian (Neutral)/East Asian Ambiguous (A) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-040-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>آزمون&#x000a;■</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-041-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>آزمون&#x0020;آزمون</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-041.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with Not East Asian (Neutral)/Not East Asian (Neutral) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-041-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>آزمون&#x000a;آزمون</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-042-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>آزمون&#x0020;테스트</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-042.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with Not East Asian (Neutral)/Hangul in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-042-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>آزمون&#x000a;테스트</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-043-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>테스트&#x0020;FULLWIDTH</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-043.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with Hangul/East Asian Full-width (F) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-043-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>테스트&#x000a;FULLWIDTH</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-044-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>테스트&#x0020;テスト</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-044.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with Hangul/East Asian Half-width (H) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-044-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>테스트&#x000a;テスト</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-045-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>테스트&#x0020;測試</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-045.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with Hangul/East Asian Wide (W) except Hangul in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-045-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>테스트&#x000a;測試</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-046-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>테스트&#x0020;narrow</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-046.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with Hangul/East Asian Narrow (Na) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-046-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>테스트&#x000a;narrow</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-047-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>테스트&#x0020;■</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-047.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with Hangul/East Asian Ambiguous (A) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-047-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>테스트&#x000a;■</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-048-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>테스트&#x0020;آزمون</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-048.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with Hangul/Not East Asian (Neutral) in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-048-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>테스트&#x000a;آزمون</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-049-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>테스트&#x0020;테스트</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-rules-049.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with Hangul/Hangul in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-049-ref.html">
+<style> p { font-family: ahem; } </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>테스트&#x000a;테스트</p>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-unremovable-1.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Text 4.1.2. Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<link rel="stylesheet" type="text/css" href="support/ahem.css">
+<link rel="match" href="segment-break-transformation-unremovable-ref.html">
+<meta name="assert" content="Test checks that a collapsible segment break should be converted to a white space (U+0020),
+if both the character before/after the segment break is Hangul.">
+<style> p { font-family: ahem; } </style>
+</head>
+<body>
+<div>Test passes if there is <b>one</b> white space between 2nd and 3rd CJK character.
+<!--Some[LF]Hangul-->
+<p>&#x4e00;&#x4e9b;&#x000a;&#xc5b8;&#xbb38;</p>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-unremovable-2.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Text 4.1.2. Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<link rel="stylesheet" type="text/css" href="support/ahem.css">
+<link rel="match" href="segment-break-transformation-unremovable-ref.html">
+<meta name="assert" content="Test checks that multiple segment breaks should be converted to a white space (U+0020),
+if both the character before/after the segment breaks is Hangul.">
+<style> p { font-family: ahem; } </style>
+</head>
+<body>
+<div>Test passes if there is <b>one</b> white space between 2nd and 3rd CJK character.
+<!--Some[LF][LF][LF]Hangul-->
+<p>&#x4e00;&#x4e9b;&#x000a;&#x000a;&#x000a;&#xc5b8;&#xbb38;</p>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-unremovable-3.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Text 4.1.2. Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<link rel="stylesheet" type="text/css" href="support/ahem.css">
+<link rel="match" href="segment-break-transformation-unremovable-ref.html">
+<meta name="assert" content="Test checks that a sequence which consists of a collapsible segment break
+surrounded by multiple white spaces should be converted to a white space (U+0020),
+if both the character before/after the sequence is Hangul.">
+<style> p { font-family: ahem; } </style>
+</head>
+<body>
+<div>Test passes if there is <b>one</b> white space between 2nd and 3rd CJK character.
+<!--Some[WS][WS][LF][WS][WS]Hangul-->
+<p>&#x4e00;&#x4e9b;&#x0020;&#x0020;&#x000a;&#x0020;&#x0020;&#xc5b8;&#xbb38;</p>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-unremovable-4.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Text 4.1.2. Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<link rel="stylesheet" type="text/css" href="support/ahem.css">
+<link rel="match" href="segment-break-transformation-unremovable-ref.html">
+<meta name="assert" content="Test checks that a sequence which consists of multiple collapsible
+segment breaks mixed with multiple white spaces should be converted to a white space (U+0020),
+if both the character before/after the sequence is Hangul.">
+<style> p { font-family: ahem; } </style>
+</head>
+<body>
+<div>Test passes if there is <b>one</b> white space between 2nd and 3rd CJK character.
+<!--Some[WS][LF][WS][LF][WS][LF][WS]Hangul-->
+<p>&#x4e00;&#x4e9b;&#x0020;&#x000a;&#x0020;&#x000a;&#x0020;&#x000a;&#x0020;&#xc5b8;&#xbb38;</p>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/segment-break-transformation-unremovable-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Text 4.1.2. Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p { font-family: ahem; } </style>
+</head>
+<body>
+<div>Test passes if there is <b>one</b> white space between 2nd and 3rd CJK character.
+<!--Some Hangul-->
+<p>&#x4e00;&#x4e9b;&nbsp;&#xc5b8;&#xbb38;</p>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/text3/support/generate-segment-break-transformation-rules-tests.py
@@ -0,0 +1,109 @@
+#!/usr/bin/env python
+# - * - coding: UTF-8 - * -
+
+"""
+This script generates tests segment-break-transformation-rules-001 ~ 049 which
+cover all possible combinations of characters at two sides of segment breaks.
+More specifically, there are seven types of characters involve in these rules:
+
+1. East Asian Full-width (F)
+2. East Asian Half-width (H)
+3. East Asian Wide (W) except Hangul
+4. East Asian Narrow (Na)
+5. East Asian Ambiguous (A)
+6. Not East Asian (Neutral)
+7. Hangul
+
+So there are 49 different combinations. It outputs a list of all
+tests it generated in the format of Mozilla reftest.list to the stdout.
+"""
+
+from __future__ import unicode_literals
+
+TEST_FILE = 'segment-break-transformation-rules-{:03}.html'
+TEST_TEMPLATE = '''<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Test: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#line-break-transform">
+<meta name="assert" content="'segment-break-transformation-rules: with {prev}/{next} in front/back of the semgment break.">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<link rel="match" href="segment-break-transformation-rules-{index:03}-ref.html">
+<style> p {{ font-family: ahem; }} </style>
+<div>Pass if there is {expect} white space between the two strings below.
+<p>{prevchar}&#x000a;{nextchar}</p>
+</div>
+'''
+
+REF_FILE = 'segment-break-transformation-rules-{:03}-ref.html'
+REF_TEMPLATE_REMOVE = '''<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p {{ font-family: ahem; }} </style>
+<div>Pass if there is NO white space between the two strings below.
+<p>{0}{1}</p>
+</div>
+'''
+REF_TEMPLATE_KEEP = '''<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Reftest Reference: Segment Break Transformation Rules</title>
+<link rel="author" title="Chun-Min (Jeremy) Chen" href="mailto:jeremychen@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org">
+<link rel="stylesheet" type="text/css" href="support/ahem.css" />
+<style> p {{ font-family: ahem; }} </style>
+<div>Pass if there is ONE white space between the two strings below.
+<p>{0}{2}{1}</p>
+</div>
+'''
+
+CHAR_SET = [
+        ('East Asian Full-width (F)',         'FULLWIDTH'),
+        ('East Asian Half-width (H)',         'テスト'),
+        ('East Asian Wide (W) except Hangul', '測試'),
+        ('East Asian Narrow (Na)',            'narrow'),
+        ('East Asian Ambiguous (A)',          '■'),
+        ('Not East Asian (Neutral)',          'آزمون'),
+        ('Hangul',                            '테스트'),
+        ]
+
+def write_file(filename, content):
+    with open(filename, 'wb') as f:
+        f.write(content.encode('UTF-8'))
+
+print("# START tests from {}".format(__file__))
+global idx
+idx = 0
+for i, (prevtype, prevchars) in enumerate(CHAR_SET):
+    for j, (nextype, nextchars) in enumerate(CHAR_SET):
+        idx += 1
+        reffilename = REF_FILE.format(idx)
+        testfilename = TEST_FILE.format(idx)
+        # According to CSS Text 3 - 4.1.2. Segment Break Transformation Rules,
+        # if the East Asian Width property of both the character before and
+        # after the segment break is F, W, or H (not A), and neither side is
+        # Hangul, then the segment break is removed. Otherwise, the segment
+        # break is converted to a space (U+0020).
+        if i < 3 and j < 3:
+            write_file(reffilename,
+                       REF_TEMPLATE_REMOVE.format(prevchars, nextchars))
+            write_file(testfilename,
+                       TEST_TEMPLATE.format(index=idx, prev=prevtype,
+                                            next=nextype,
+                                            prevchar=prevchars,
+                                            nextchar=nextchars,
+                                            expect='NO'))
+        else:
+            write_file(reffilename,
+                       REF_TEMPLATE_KEEP.format(prevchars, nextchars, '&#x0020;'))
+            write_file(testfilename,
+                       TEST_TEMPLATE.format(index=idx, prev=prevtype,
+                                            next=nextype,
+                                            prevchar=prevchars,
+                                            nextchar=nextchars,
+                                            expect='ONE'))
+        print("== {} {}".format(testfilename, reffilename))
+print("# END tests from {}".format(__file__))
--- a/layout/style/ServoArcTypeList.h
+++ b/layout/style/ServoArcTypeList.h
@@ -7,8 +7,9 @@
 /* a list of all Servo Arc types used in stylo bindings for preprocessing */
 
 SERVO_ARC_TYPE(CssRules, ServoCssRules)
 SERVO_ARC_TYPE(StyleSheet, RawServoStyleSheet)
 SERVO_ARC_TYPE(ComputedValues, ServoComputedValues)
 SERVO_ARC_TYPE(DeclarationBlock, RawServoDeclarationBlock)
 SERVO_ARC_TYPE(StyleRule, RawServoStyleRule)
 SERVO_ARC_TYPE(ImportRule, RawServoImportRule)
+SERVO_ARC_TYPE(AnimationValue, RawServoAnimationValue)
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -102,16 +102,24 @@ SERVO_BINDING_FUNC(Servo_ParseProperty,
                    ThreadSafeURIHolder* referrer,
                    ThreadSafePrincipalHolder* principal)
 SERVO_BINDING_FUNC(Servo_RestyleWithAddedDeclaration,
                    ServoComputedValuesStrong,
                    RawServoStyleSetBorrowed set,
                    RawServoDeclarationBlockBorrowed declarations,
                    ServoComputedValuesBorrowed previous_style)
 
+// AnimationValues handling
+SERVO_BINDING_FUNC(Servo_AnimationValues_Populate, void,
+                   RawGeckoAnimationValueListBorrowedMut,
+                   RawServoDeclarationBlockBorrowed,
+                   ServoComputedValuesBorrowed,
+                   ServoComputedValuesBorrowedOrNull,
+                   RawGeckoPresContextBorrowed)
+
 // Style attribute
 SERVO_BINDING_FUNC(Servo_ParseStyleAttribute, RawServoDeclarationBlockStrong,
                    const nsACString* data)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_CreateEmpty,
                    RawServoDeclarationBlockStrong)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_Clone, RawServoDeclarationBlockStrong,
                    RawServoDeclarationBlockBorrowed declarations)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_Equals, bool,
--- a/layout/style/ServoBindingTypes.h
+++ b/layout/style/ServoBindingTypes.h
@@ -3,44 +3,49 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_ServoBindingTypes_h
 #define mozilla_ServoBindingTypes_h
 
 #include "mozilla/RefPtr.h"
+#include "mozilla/ServoTypes.h"
 #include "mozilla/UniquePtr.h"
+#include "nsTArray.h"
 
+struct RawServoAnimationValue;
 struct RawServoStyleSet;
 
 #define SERVO_ARC_TYPE(name_, type_) struct type_;
 #include "mozilla/ServoArcTypeList.h"
 #undef SERVO_ARC_TYPE
 
 namespace mozilla {
   class ServoElementSnapshot;
 namespace dom {
 class Element;
 class StyleChildrenIterator;
 } // namespace dom
+struct PropertyStyleAnimationValuePair;
 } // namespace mozilla
 
 class nsCSSValue;
 class nsIDocument;
 class nsINode;
 class nsPresContext;
 
 using mozilla::dom::StyleChildrenIterator;
 using mozilla::ServoElementSnapshot;
 
 typedef nsINode RawGeckoNode;
 typedef mozilla::dom::Element RawGeckoElement;
 typedef nsIDocument RawGeckoDocument;
 typedef nsPresContext RawGeckoPresContext;
+typedef nsTArray<mozilla::PropertyStyleAnimationValuePair> RawGeckoAnimationValueList;
 
 // We have these helper types so that we can directly generate
 // things like &T or Borrowed<T> on the Rust side in the function, providing
 // additional safety benefits.
 //
 // FFI has a problem with templated types, so we just use raw pointers here.
 //
 // The "Borrowed" types generate &T or Borrowed<T> in the nullable case.
@@ -98,16 +103,17 @@ DECL_BORROWED_REF_TYPE_FOR(RawGeckoEleme
 DECL_NULLABLE_BORROWED_REF_TYPE_FOR(RawGeckoElement)
 DECL_BORROWED_REF_TYPE_FOR(RawGeckoDocument)
 DECL_NULLABLE_BORROWED_REF_TYPE_FOR(RawGeckoDocument)
 DECL_BORROWED_MUT_REF_TYPE_FOR(StyleChildrenIterator)
 DECL_BORROWED_MUT_REF_TYPE_FOR(ServoElementSnapshot)
 DECL_BORROWED_REF_TYPE_FOR(nsCSSValue)
 DECL_BORROWED_MUT_REF_TYPE_FOR(nsCSSValue)
 DECL_BORROWED_REF_TYPE_FOR(RawGeckoPresContext)
+DECL_BORROWED_MUT_REF_TYPE_FOR(RawGeckoAnimationValueList)
 
 #undef DECL_ARC_REF_TYPE_FOR
 #undef DECL_OWNED_REF_TYPE_FOR
 #undef DECL_NULLABLE_OWNED_REF_TYPE_FOR
 #undef DECL_BORROWED_REF_TYPE_FOR
 #undef DECL_NULLABLE_BORROWED_REF_TYPE_FOR
 #undef DECL_BORROWED_MUT_REF_TYPE_FOR
 #undef DECL_NULLABLE_BORROWED_MUT_REF_TYPE_FOR
@@ -125,23 +131,27 @@ DECL_BORROWED_REF_TYPE_FOR(RawGeckoPresC
     static void Release(type_* aPtr) {               \
       Servo_##name_##_Release(aPtr);                 \
     }                                                \
   };                                                 \
   }
 #include "mozilla/ServoArcTypeList.h"
 #undef SERVO_ARC_TYPE
 
-extern "C" void Servo_StyleSet_Drop(RawServoStyleSetOwned ptr);
+#define DEFINE_BOXED_TYPE(name_, type_)                     \
+  extern "C" void Servo_##name_##_Drop(type_##Owned ptr);   \
+  namespace mozilla {                                       \
+  template<>                                                \
+  class DefaultDelete<type_>                                \
+  {                                                         \
+  public:                                                   \
+    void operator()(type_* aPtr) const                      \
+    {                                                       \
+      Servo_##name_##_Drop(aPtr);                           \
+    }                                                       \
+  };                                                        \
+  }
 
-namespace mozilla {
-template<>
-class DefaultDelete<RawServoStyleSet>
-{
-public:
-  void operator()(RawServoStyleSet* aPtr) const
-  {
-    Servo_StyleSet_Drop(aPtr);
-  }
-};
-}
+DEFINE_BOXED_TYPE(StyleSet, RawServoStyleSet);
+
+#undef DEFINE_BOXED_TYPE
 
 #endif // mozilla_ServoBindingTypes_h
--- a/layout/style/StyleAnimationValue.h
+++ b/layout/style/StyleAnimationValue.h
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* Utilities for animation of computed style values */
 
 #ifndef mozilla_StyleAnimationValue_h_
 #define mozilla_StyleAnimationValue_h_
 
 #include "mozilla/gfx/MatrixFwd.h"
+#include "mozilla/ServoBindingTypes.h"
 #include "mozilla/UniquePtr.h"
 #include "nsStringFwd.h"
 #include "nsStringBuffer.h"
 #include "nsCoord.h"
 #include "nsColor.h"
 #include "nsCSSProps.h"
 #include "nsCSSValue.h"
 #include "nsStyleCoord.h"
@@ -580,12 +581,13 @@ private:
     return aUnit == eUnit_UnparsedString;
   }
 };
 
 struct PropertyStyleAnimationValuePair
 {
   nsCSSPropertyID mProperty;
   StyleAnimationValue mValue;
+  RefPtr<RawServoAnimationValue> mServoValue;
 };
 } // namespace mozilla
 
 #endif
--- a/media/libstagefright/binding/include/mp4parse.h
+++ b/media/libstagefright/binding/include/mp4parse.h
@@ -93,16 +93,19 @@ typedef struct mp4parse_io {
 } mp4parse_io;
 
 /// Allocate an `mp4parse_parser*` to read from the supplied `mp4parse_io`.
 mp4parse_parser* mp4parse_new(mp4parse_io const* io);
 
 /// Free an `mp4parse_parser*` allocated by `mp4parse_new()`.
 void mp4parse_free(mp4parse_parser* parser);
 
+/// Enable mp4_parser log.
+void mp4parse_log(bool enable);
+
 /// Run the `mp4parse_parser*` allocated by `mp4parse_new()` until EOF or error.
 mp4parse_error mp4parse_read(mp4parse_parser* parser);
 
 /// Return the number of tracks parsed by previous `mp4parse_read()` call.
 mp4parse_error mp4parse_get_track_count(mp4parse_parser const* parser, uint32_t* count);
 
 /// Fill the supplied `mp4parse_track_info` with metadata for `track`.
 mp4parse_error mp4parse_get_track_info(mp4parse_parser* parser, uint32_t track_index, mp4parse_track_info* info);
--- a/media/libstagefright/binding/mp4parse-cargo.patch
+++ b/media/libstagefright/binding/mp4parse-cargo.patch
@@ -1,23 +1,23 @@
 diff --git a/media/libstagefright/binding/mp4parse/Cargo.toml b/media/libstagefright/binding/mp4parse/Cargo.toml
 index ff9422c..814c4c6 100644
 --- a/media/libstagefright/binding/mp4parse/Cargo.toml
 +++ b/media/libstagefright/binding/mp4parse/Cargo.toml
 @@ -18,18 +18,12 @@ exclude = [
  ]
  
  [dependencies]
--byteorder = "0.5.0"
+-byteorder = "1.0.0"
 -afl = { version = "0.1.1", optional = true }
 -afl-plugin = { version = "0.1.1", optional = true }
 -abort_on_panic = { version = "1.0.0", optional = true }
--bitreader = { version = "0.1.0" }
-+byteorder = "0.5.0"
-+bitreader = { version = "0.1.0" }
+-bitreader = { version = "0.2.0" }
++byteorder = "1.0.0"
++bitreader = { version = "0.2.0" }
 
  [dev-dependencies]
  test-assembler = "0.1.2"
  
 -[features]
 -fuzz = ["afl", "afl-plugin", "abort_on_panic"]
 -
  # Somewhat heavy-handed, but we want at least -Z force-overflow-checks=on.
@@ -29,17 +29,17 @@ index aeeebc65..5c0836a 100644
 +++ b/media/libstagefright/binding/mp4parse_capi/Cargo.toml
 @@ -18,18 +18,10 @@ exclude = [
    "*.mp4",
  ]
  
 -build = "build.rs"
 -
  [dependencies]
- byteorder = "0.5.0"
+ byteorder = "1.0.0"
  "mp4parse" = {version = "0.6.0", path = "../mp4parse"}
  
 -[build-dependencies]
 -rusty-cheddar = "0.3.2"
 -
 -[features]
 -fuzz = ["mp4parse/fuzz"]
 -
--- a/media/libstagefright/binding/mp4parse/Cargo.toml
+++ b/media/libstagefright/binding/mp4parse/Cargo.toml
@@ -14,17 +14,17 @@ license = "MPL-2.0"
 repository = "https://github.com/mozilla/mp4parse-rust"
 
 # Avoid complaints about trying to package test files.
 exclude = [
   "*.mp4",
 ]
 
 [dependencies]
-byteorder = "0.5.0"
-bitreader = { version = "0.1.0" }
+byteorder = "1.0.0"
+bitreader = { version = "0.2.0" }
 
 [dev-dependencies]
 test-assembler = "0.1.2"
 
 # Somewhat heavy-handed, but we want at least -Z force-overflow-checks=on.
 [profile.release]
 debug-assertions = true
--- a/media/libstagefright/binding/mp4parse/src/boxes.rs
+++ b/media/libstagefright/binding/mp4parse/src/boxes.rs
@@ -1,29 +1,99 @@
 // 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 https://mozilla.org/MPL/2.0/.
+use std::fmt;
 
 macro_rules! box_database {
     ($($boxenum:ident $boxtype:expr),*,) => {
-        #[derive(Debug, Clone, Copy, PartialEq)]
+        #[derive(Clone, Copy, PartialEq)]
         pub enum BoxType {
             $($boxenum),*,
             UnknownBox(u32),
         }
 
         impl From<u32> for BoxType {
             fn from(t: u32) -> BoxType {
                 use self::BoxType::*;
                 match t {
                     $($boxtype => $boxenum),*,
                     _ => UnknownBox(t),
                 }
             }
         }
+
+        impl Into<u32> for BoxType {
+            fn into(self) -> u32 {
+                use self::BoxType::*;
+                match self {
+                    $($boxenum => $boxtype),*,
+                    UnknownBox(t) => t,
+                }
+            }
+        }
+
+        impl fmt::Debug for BoxType {
+            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+                let fourcc: FourCC = From::from(self.clone());
+                write!(f, "{}", fourcc)
+            }
+        }
+    }
+}
+
+#[derive(Default, PartialEq)]
+pub struct FourCC {
+    pub value: String
+}
+
+impl From<u32> for FourCC {
+    fn from(number: u32) -> FourCC {
+        let mut box_chars = Vec::new();
+        for x in 0..4 {
+            let c = (number >> x * 8 & 0x000000FF) as u8;
+            box_chars.push(c);
+        }
+        box_chars.reverse();
+
+        let box_string = match String::from_utf8(box_chars) {
+            Ok(t) => t,
+            _ => String::from("null"), // error to retrieve fourcc
+        };
+
+        FourCC {
+            value: box_string
+        }
+    }
+}
+
+impl From<BoxType> for FourCC {
+    fn from(t: BoxType) -> FourCC {
+        let box_num: u32 = Into::into(t);
+        From::from(box_num)
+    }
+}
+
+impl<'a> From<&'a str> for FourCC {
+    fn from(v: &'a str) -> FourCC {
+        FourCC {
+            value: v.to_owned()
+        }
+    }
+}
+
+impl fmt::Debug for FourCC {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self.value)
+    }
+}
+
+impl fmt::Display for FourCC {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self.value)
     }
 }
 
 box_database!(
     FileTypeBox                       0x66747970, // "ftyp"
     MovieBox                          0x6d6f6f76, // "moov"
     MovieHeaderBox                    0x6d766864, // "mvhd"
     TrackBox                          0x7472616b, // "trak"
--- a/media/libstagefright/binding/mp4parse/src/lib.rs
+++ b/media/libstagefright/binding/mp4parse/src/lib.rs
@@ -12,17 +12,17 @@ extern crate byteorder;
 extern crate bitreader;
 use byteorder::{ReadBytesExt, WriteBytesExt};
 use bitreader::{BitReader, ReadInto};
 use std::io::{Read, Take};
 use std::io::Cursor;
 use std::cmp;
 
 mod boxes;
-use boxes::BoxType;
+use boxes::{BoxType, FourCC};
 
 // Unit tests.
 #[cfg(test)]
 mod tests;
 
 // Arbitrary buffer size limit used for raw read_bufs on a box.
 const BUF_SIZE_LIMIT: u64 = 1024 * 1024;
 
@@ -101,19 +101,19 @@ struct BoxHeader {
     size: u64,
     /// Offset to the start of the contained data (or header size).
     offset: u64,
 }
 
 /// File type box 'ftyp'.
 #[derive(Debug)]
 struct FileTypeBox {
-    major_brand: u32,
+    major_brand: FourCC,
     minor_version: u32,
-    compatible_brands: Vec<u32>,
+    compatible_brands: Vec<FourCC>,
 }
 
 /// Movie header box 'mvhd'.
 #[derive(Debug)]
 struct MovieHeaderBox {
     pub timescale: u32,
     duration: u64,
 }
@@ -191,17 +191,17 @@ struct TimeToSampleBox {
 struct Sample {
     sample_count: u32,
     sample_delta: u32,
 }
 
 // Handler reference box 'hdlr'
 #[derive(Debug)]
 struct HandlerBox {
-    handler_type: u32,
+    handler_type: FourCC,
 }
 
 // Sample description box 'stsd'
 #[derive(Debug)]
 struct SampleDescriptionBox {
     descriptions: Vec<SampleEntry>,
 }
 
@@ -471,16 +471,25 @@ impl<'a, T: Read> BMFFBox<'a, T> {
         &self.head
     }
 
     fn box_iter<'b>(&'b mut self) -> BoxIter<BMFFBox<'a, T>> {
         BoxIter::new(self)
     }
 }
 
+impl<'a, T: Read> Drop for BMFFBox<'a, T> {
+    fn drop(&mut self) {
+        if self.content.limit() > 0 {
+            let name: FourCC = From::from(self.head.name);
+            log!("Dropping {} bytes in '{}'", self.content.limit(), name);
+        }
+    }
+}
+
 /// Read and parse a box header.
 ///
 /// Call this first to determine the type of a particular mp4 box
 /// and its length. Used internally for dispatching to specific
 /// parsers for the internal content, or to get the length to
 /// skip unknown or uninteresting boxes.
 fn read_box_header<T: ReadBytesExt>(src: &mut T) -> Result<BoxHeader> {
     let size32 = be_u32(src)?;
@@ -788,19 +797,20 @@ fn read_mdia<T: Read>(f: &mut BMFFBox<T>
             BoxType::MediaHeaderBox => {
                 let (mdhd, duration, timescale) = parse_mdhd(&mut b, track)?;
                 track.duration = duration;
                 track.timescale = timescale;
                 log!("{:?}", mdhd);
             }
             BoxType::HandlerBox => {
                 let hdlr = read_hdlr(&mut b)?;
-                match hdlr.handler_type {
-                    0x76696465 /* 'vide' */ => track.track_type = TrackType::Video,
-                    0x736f756e /* 'soun' */ => track.track_type = TrackType::Audio,
+
+                match hdlr.handler_type.value.as_ref() {
+                    "vide" => track.track_type = TrackType::Video,
+                    "soun" => track.track_type = TrackType::Audio,
                     _ => (),
                 }
                 log!("{:?}", hdlr);
             }
             BoxType::MediaInformationBox => read_minf(&mut b, track)?,
             _ => skip_box_content(&mut b)?,
         };
         check_parser_state!(b.content);
@@ -869,20 +879,20 @@ fn read_ftyp<T: Read>(src: &mut BMFFBox<
     let bytes_left = src.bytes_left();
     if bytes_left % 4 != 0 {
         return Err(Error::InvalidData("invalid ftyp size"));
     }
     // Is a brand_count of zero valid?
     let brand_count = bytes_left / 4;
     let mut brands = Vec::new();
     for _ in 0..brand_count {
-        brands.push(be_u32(src)?);
+        brands.push(From::from(be_u32(src)?));
     }
     Ok(FileTypeBox {
-        major_brand: major,
+        major_brand: From::from(major),
         minor_version: minor,
         compatible_brands: brands,
     })
 }
 
 /// Parse an mvhd box.
 fn read_mvhd<T: Read>(src: &mut BMFFBox<T>) -> Result<MovieHeaderBox> {
     let (version, _) = read_fullbox_extra(src)?;
@@ -1271,25 +1281,80 @@ fn read_ds_descriptor(data: &[u8], esds:
         0x0F => {
             Some(ReadInto::read(bit_reader, 24)?)
         },
         _ => {
             frequency_table.iter().find(|item| item.0 == sample_index).map(|x| x.1)
         },
     };
 
-    let channel_counts: u16 = ReadInto::read(bit_reader, 4)?;
+    let mut channel_counts: u16 = ReadInto::read(bit_reader, 4)?;
+
+    // parsing GASpecificConfig
+    bit_reader.skip(1)?;        // frameLengthFlag
+    let depend_on_core_order: u8 = ReadInto::read(bit_reader, 1)?;
+    if depend_on_core_order > 0 {
+        bit_reader.skip(14)?;   // codeCoderDelay
+    }
+    bit_reader.skip(1)?;        // extensionFlag
+
+    // When channel_counts is 0, we need to parse the program_config_element
+    // to calculate the channel counts.
+    if channel_counts == 0 {
+        log!("Parsing program_config_element for channel counts");
+
+        bit_reader.skip(4)?;    // element_instance_tag
+        bit_reader.skip(2)?;    // object_type
+        bit_reader.skip(4)?;    // sampling_frequency_index
+        let num_front_channel: u8 = ReadInto::read(bit_reader, 4)?;
+        let num_side_channel: u8 = ReadInto::read(bit_reader, 4)?;
+        let num_back_channel:u8 = ReadInto::read(bit_reader, 4)?;
+        let num_lfe_channel: u8 = ReadInto::read(bit_reader, 2)?;
+        bit_reader.skip(3)?;    // num_assoc_data
+        bit_reader.skip(4)?;    // num_valid_cc
+
+        let mono_mixdown_present: bool = ReadInto::read(bit_reader, 1)?;
+        if mono_mixdown_present {
+            bit_reader.skip(4)?;    // mono_mixdown_element_number
+        }
+
+        let stereo_mixdown_present: bool = ReadInto::read(bit_reader, 1)?;
+        if stereo_mixdown_present {
+            bit_reader.skip(4)?;    // stereo_mixdown_element_number
+        }
+
+        let matrix_mixdown_idx_present: bool = ReadInto::read(bit_reader, 1)?;
+        if matrix_mixdown_idx_present {
+            bit_reader.skip(2)?;    // matrix_mixdown_idx
+            bit_reader.skip(1)?;    // pseudo_surround_enable
+        }
+
+        channel_counts += read_surround_channel_count(bit_reader, num_front_channel)?;
+        channel_counts += read_surround_channel_count(bit_reader, num_side_channel)?;
+        channel_counts += read_surround_channel_count(bit_reader, num_back_channel)?;
+        channel_counts += read_surround_channel_count(bit_reader, num_lfe_channel)?;
+    }
 
     esds.audio_object_type = Some(audio_object_type);
     esds.audio_sample_rate = sample_frequency;
     esds.audio_channel_count = Some(channel_counts);
 
     Ok(())
 }
 
+fn read_surround_channel_count(bit_reader: &mut BitReader, channels: u8) -> Result<u16> {
+    let mut count = 0;
+    for _ in 0..channels {
+        let is_cpe: bool = ReadInto::read(bit_reader, 1)?;
+        count += if is_cpe { 2 } else { 1 };
+        bit_reader.skip(4)?;
+    }
+    Ok(count)
+}
+
 fn read_dc_descriptor(data: &[u8], esds: &mut ES_Descriptor) -> Result<()> {
     let des = &mut Cursor::new(data);
     let object_profile = des.read_u8()?;
 
     // Skip uninteresting fields.
     skip(des, 12)?;
 
     if data.len() > des.position() as usize {
@@ -1465,17 +1530,17 @@ pub fn serialize_opus_header<W: byteorde
 
 /// Parse a hdlr box.
 fn read_hdlr<T: Read>(src: &mut BMFFBox<T>) -> Result<HandlerBox> {
     let (_, _) = read_fullbox_extra(src)?;
 
     // Skip uninteresting fields.
     skip(src, 4)?;
 
-    let handler_type = be_u32(src)?;
+    let handler_type = FourCC::from(be_u32(src)?);
 
     // Skip uninteresting fields.
     skip(src, 12)?;
 
     let bytes_left = src.bytes_left();
     let _name = read_null_terminated_string(src, bytes_left)?;
 
     Ok(HandlerBox {
--- a/media/libstagefright/binding/mp4parse/src/tests.rs
+++ b/media/libstagefright/binding/mp4parse/src/tests.rs
@@ -7,17 +7,17 @@
 
 use std::io::Cursor;
 use super::read_mp4;
 use super::MediaContext;
 use super::Error;
 extern crate test_assembler;
 use self::test_assembler::*;
 
-use boxes::BoxType;
+use boxes::{BoxType, FourCC};
 
 enum BoxSize {
     Short(u32),
     Long(u64),
     UncheckedShort(u32),
     UncheckedLong(u64),
     Auto,
 }
@@ -125,21 +125,21 @@ fn read_ftyp() {
          .append_bytes(b"isom")
          .append_bytes(b"mp42")
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     assert_eq!(stream.head.name, BoxType::FileTypeBox);
     assert_eq!(stream.head.size, 24);
     let parsed = super::read_ftyp(&mut stream).unwrap();
-    assert_eq!(parsed.major_brand, 0x6d703432); // mp42
+    assert_eq!(parsed.major_brand, FourCC::from("mp42")); // mp42
     assert_eq!(parsed.minor_version, 0);
     assert_eq!(parsed.compatible_brands.len(), 2);
-    assert_eq!(parsed.compatible_brands[0], 0x69736f6d); // isom
-    assert_eq!(parsed.compatible_brands[1], 0x6d703432); // mp42
+    assert_eq!(parsed.compatible_brands[0], FourCC::from("isom")); // isom
+    assert_eq!(parsed.compatible_brands[1], FourCC::from("mp42")); // mp42
 }
 
 #[test]
 fn read_truncated_ftyp() {
     // We declare a 24 byte box, but only write 20 bytes.
     let mut stream = make_box(BoxSize::UncheckedShort(24), b"ftyp", |s| {
         s.append_bytes(b"mp42")
             .B32(0) // minor version
@@ -167,21 +167,21 @@ fn read_ftyp_case() {
          .append_bytes(b"ISOM")
          .append_bytes(b"MP42")
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     assert_eq!(stream.head.name, BoxType::FileTypeBox);
     assert_eq!(stream.head.size, 24);
     let parsed = super::read_ftyp(&mut stream).unwrap();
-    assert_eq!(parsed.major_brand, 0x4d503432);
+    assert_eq!(parsed.major_brand, FourCC::from("MP42"));
     assert_eq!(parsed.minor_version, 0);
     assert_eq!(parsed.compatible_brands.len(), 2);
-    assert_eq!(parsed.compatible_brands[0], 0x49534f4d); // ISOM
-    assert_eq!(parsed.compatible_brands[1], 0x4d503432); // MP42
+    assert_eq!(parsed.compatible_brands[0], FourCC::from("ISOM")); // ISOM
+    assert_eq!(parsed.compatible_brands[1], FourCC::from("MP42")); // MP42
 }
 
 #[test]
 fn read_elst_v0() {
     let mut stream = make_fullbox(BoxSize::Short(28), b"elst", 0, |s| {
         s.B32(1) // list count
           // first entry
          .B32(1234) // duration
@@ -399,17 +399,17 @@ fn read_hdlr() {
          .append_bytes(b"VideoHandler")
          .B8(0) // null-terminate string
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     assert_eq!(stream.head.name, BoxType::HandlerBox);
     assert_eq!(stream.head.size, 45);
     let parsed = super::read_hdlr(&mut stream).unwrap();
-    assert_eq!(parsed.handler_type, 0x76696465); // vide
+    assert_eq!(parsed.handler_type, FourCC::from("vide"));
 }
 
 #[test]
 fn read_hdlr_short_name() {
     let mut stream = make_fullbox(BoxSize::Short(33), b"hdlr", 0, |s| {
         s.B32(0)
          .append_bytes(b"vide")
          .B32(0)
@@ -417,34 +417,34 @@ fn read_hdlr_short_name() {
          .B32(0)
          .B8(0) // null-terminate string
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     assert_eq!(stream.head.name, BoxType::HandlerBox);
     assert_eq!(stream.head.size, 33);
     let parsed = super::read_hdlr(&mut stream).unwrap();
-    assert_eq!(parsed.handler_type, 0x76696465); // vide
+    assert_eq!(parsed.handler_type, FourCC::from("vide"));
 }
 
 #[test]
 fn read_hdlr_zero_length_name() {
     let mut stream = make_fullbox(BoxSize::Short(32), b"hdlr", 0, |s| {
         s.B32(0)
          .append_bytes(b"vide")
          .B32(0)
          .B32(0)
          .B32(0)
     });
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     assert_eq!(stream.head.name, BoxType::HandlerBox);
     assert_eq!(stream.head.size, 32);
     let parsed = super::read_hdlr(&mut stream).unwrap();
-    assert_eq!(parsed.handler_type, 0x76696465); // vide
+    assert_eq!(parsed.handler_type, FourCC::from("vide"));
 }
 
 fn flac_streaminfo() -> Vec<u8> {
     vec![
         0x10, 0x00, 0x10, 0x00, 0x00, 0x0a, 0x11, 0x00,
         0x38, 0x32, 0x0a, 0xc4, 0x42, 0xf0, 0x00, 0xc9,
         0xdf, 0xae, 0xb5, 0x66, 0xfc, 0x02, 0x15, 0xa3,
         0xb1, 0x54, 0x61, 0x47, 0x0f, 0xfb, 0x05, 0x00,
@@ -853,8 +853,34 @@ fn read_qt_wave_atom() {
 
     let mut iter = super::BoxIter::new(&mut stream);
     let mut stream = iter.next_box().unwrap().unwrap();
     let mut track = super::Track::new(0);
     super::read_audio_sample_entry(&mut stream, &mut track)
           .expect("fail to read qt wave atom");
     assert_eq!(track.codec_type, super::CodecType::MP3);
 }
+
+#[test]
+fn read_esds() {
+    let aac_esds =
+        vec![
+            0x03, 0x24, 0x00, 0x00, 0x00, 0x04, 0x1c, 0x40,
+            0x15, 0x00, 0x12, 0x00, 0x00, 0x01, 0xf4, 0x00,
+            0x00, 0x01, 0xf4, 0x00, 0x05, 0x0d, 0x13, 0x00,
+            0x05, 0x88, 0x05, 0x00, 0x48, 0x21, 0x10, 0x00,
+            0x56, 0xe5, 0x98, 0x06, 0x01, 0x02,
+        ];
+    let mut stream = make_box(BoxSize::Auto, b"esds", |s| {
+        s.B32(0) // reserved
+         .append_bytes(aac_esds.as_slice())
+    });
+    let mut iter = super::BoxIter::new(&mut stream);
+    let mut stream = iter.next_box().unwrap().unwrap();
+
+    let es = super::read_esds(&mut stream).unwrap();
+
+    assert_eq!(es.audio_codec, super::CodecType::AAC);
+    assert_eq!(es.audio_object_type, Some(2));
+    assert_eq!(es.audio_sample_rate, Some(24000));
+    assert_eq!(es.audio_channel_count, Some(6));
+    assert_eq!(es.codec_esds, aac_esds);
+}
--- a/media/libstagefright/binding/mp4parse_capi/Cargo.toml
+++ b/media/libstagefright/binding/mp4parse_capi/Cargo.toml
@@ -14,14 +14,14 @@ license = "MPL-2.0"
 repository = "https://github.com/mozilla/mp4parse-rust"
 
 # Avoid complaints about trying to package test files.
 exclude = [
   "*.mp4",
 ]
 
 [dependencies]
-byteorder = "0.5.0"
+byteorder = "1.0.0"
 "mp4parse" = {version = "0.6.0", path = "../mp4parse"}
 
 # Somewhat heavy-handed, but we want at least -Z force-overflow-checks=on.
 [profile.release]
 debug-assertions = true
--- a/media/libstagefright/binding/mp4parse_capi/src/lib.rs
+++ b/media/libstagefright/binding/mp4parse_capi/src/lib.rs
@@ -262,26 +262,33 @@ pub unsafe extern fn mp4parse_new(io: *c
     }
     let parser = Box::new(mp4parse_parser(Wrap {
         context: MediaContext::new(),
         io: (*io).clone(),
         poisoned: false,
         opus_header: HashMap::new(),
         pssh_data: Vec::new(),
     }));
+
     Box::into_raw(parser)
 }
 
 /// Free an `mp4parse_parser*` allocated by `mp4parse_new()`.
 #[no_mangle]
 pub unsafe extern fn mp4parse_free(parser: *mut mp4parse_parser) {
     assert!(!parser.is_null());
     let _ = Box::from_raw(parser);
 }
 
+/// Enable mp4_parser log.
+#[no_mangle]
+pub unsafe extern fn mp4parse_log(enable: bool) {
+    mp4parse::set_debug_mode(enable);
+}
+
 /// Run the `mp4parse_parser*` allocated by `mp4parse_new()` until EOF or error.
 #[no_mangle]
 pub unsafe extern fn mp4parse_read(parser: *mut mp4parse_parser) -> mp4parse_error {
     // Validate arguments from C.
     if parser.is_null() || (*parser).poisoned() {
         return MP4PARSE_ERROR_BADARG;
     }
 
--- a/mobile/android/base/java/org/mozilla/gecko/home/activitystream/StreamRecyclerAdapter.java
+++ b/mobile/android/base/java/org/mozilla/gecko/home/activitystream/StreamRecyclerAdapter.java
@@ -117,29 +117,32 @@ public class StreamRecyclerAdapter exten
         }
 
         int actualPosition = translatePositionToCursor(position);
         highlightsCursor.moveToPosition(actualPosition);
 
         final String url = highlightsCursor.getString(
                 highlightsCursor.getColumnIndexOrThrow(BrowserContract.Combined.URL));
 
-        onUrlOpenListener.onUrlOpen(url, EnumSet.of(HomePager.OnUrlOpenListener.Flags.ALLOW_SWITCH_TO_TAB));
-
         ActivityStreamTelemetry.Extras.Builder extras = ActivityStreamTelemetry.Extras.builder()
                 .forHighlightSource(Utils.highlightSource(highlightsCursor))
                 .set(ActivityStreamTelemetry.Contract.SOURCE_TYPE, ActivityStreamTelemetry.Contract.TYPE_HIGHLIGHTS)
                 .set(ActivityStreamTelemetry.Contract.ACTION_POSITION, actualPosition)
                 .set(ActivityStreamTelemetry.Contract.COUNT, highlightsCursor.getCount());
 
         Telemetry.sendUIEvent(
                 TelemetryContract.Event.LOAD_URL,
                 TelemetryContract.Method.LIST_ITEM,
                 extras.build()
         );
+
+        // NB: This is hacky. We need to process telemetry data first, otherwise we run a risk of
+        // not having a cursor to work with once url is opened and BrowserApp closes A-S home screen
+        // and clears its resources (read: cursors). See Bug 1326018.
+        onUrlOpenListener.onUrlOpen(url, EnumSet.of(HomePager.OnUrlOpenListener.Flags.ALLOW_SWITCH_TO_TAB));
     }
 
     @Override
     public int getItemCount() {
         final int highlightsCount;
 
         if (highlightsCursor != null) {
             highlightsCount = highlightsCursor.getCount();
--- a/modules/libmar/tests/moz.build
+++ b/modules/libmar/tests/moz.build
@@ -1,29 +1,12 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
 
-DEFINES['BIN_SUFFIX'] = CONFIG['BIN_SUFFIX']
-
 if CONFIG['OS_TARGET'] != 'Android':
-    nss_files = ['nss3']
-    if not CONFIG['MOZ_FOLD_LIBS']:
-        nss_files.extend([
-            'nssutil3',
-            'plc4',
-            'nspr4',
-            'plds4',
-        ])
-    TEST_HARNESS_FILES.xpcshell.modules.libmar.tests.unit += sorted(
-        ['!/dist/bin/%s%s%s' % (
-            CONFIG['DLL_PREFIX'],
-            name,
-            CONFIG['DLL_SUFFIX'],
-        ) for name in nss_files]
-    )
     TEST_HARNESS_FILES.xpcshell.modules.libmar.tests.unit += [
         '!../tool/signmar%s' % CONFIG['BIN_SUFFIX'],
     ]
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -5541,18 +5541,21 @@ pref("security.mixed_content.send_hsts_p
 // Don't change the order of evaluation of mixed-content and HSTS upgrades in
 // order to be most compatible with current standards
 pref("security.mixed_content.use_hsts", false);
 #else
 // Change the order of evaluation so HSTS upgrades happen before
 // mixed-content blocking
 pref("security.mixed_content.use_hsts", true);
 #endif
-// Approximately 1 week default cache for HSTS priming failures
+// Approximately 1 week default cache for HSTS priming failures, in seconds
 pref ("security.mixed_content.hsts_priming_cache_timeout", 10080);
+// Force the channel to timeout in 3 seconds if we have not received
+// expects a time in milliseconds
+pref ("security.mixed_content.hsts_priming_request_timeout", 3000);
 
 // Disable Storage api in release builds.
 #ifdef NIGHTLY_BUILD
 pref("dom.storageManager.enabled", true);
 #else
 pref("dom.storageManager.enabled", false);
 #endif
 
--- a/mozglue/misc/StackWalk.h
+++ b/mozglue/misc/StackWalk.h
@@ -47,18 +47,16 @@ typedef void
  *                      stack, this should be nullptr unless you really know
  *                      what you're doing! This needs to be a pointer to a
  *                      CONTEXT on Windows and should not be passed on other
  *                      platforms.
  *
  * May skip some stack frames due to compiler optimizations or code
  * generation.
  *
- * Note: this (and other helper methods) will only be available when
- * MOZ_STACKWALKING is defined, so any new consumers must #if based on that.
  */
 MFBT_API bool
 MozStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames,
              uint32_t aMaxFrames, void* aClosure, uintptr_t aThread,
              void* aPlatformData);
 
 typedef struct
 {
--- a/mozglue/misc/moz.build
+++ b/mozglue/misc/moz.build
@@ -7,16 +7,17 @@ EXPORTS.mozilla += [
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     EXPORTS.mozilla += [
         'StackWalk_windows.h',
         'TimeStamp_windows.h',
     ]
 
 SOURCES += [
+    'StackWalk.cpp',
     'TimeStamp.cpp',
 ]
 
 OS_LIBS += CONFIG['REALTIME_LIBS']
 
 DEFINES['IMPL_MFBT'] = True
 
 if CONFIG['OS_ARCH'] == 'WINNT':
@@ -29,18 +30,8 @@ elif CONFIG['HAVE_CLOCK_MONOTONIC']:
         'TimeStamp_posix.cpp',
     ]
 elif CONFIG['OS_ARCH'] == 'Darwin':
     SOURCES += [
         'TimeStamp_darwin.cpp',
     ]
 elif CONFIG['COMPILE_ENVIRONMENT']:
     error('No TimeStamp implementation on this platform.  Build will not succeed')
-
-# MOZ_STACKWALKING is defined in configure.in when the build configuration meets
-# the conditions for GeckoStackWalk to work correctly.
-# We exclude this file from other build configurations so that if somebody adds a
-# new usage of NS_StackWalk it will cause a link error, which is better than having
-# GeckoStackWalk silently return garbage at runtime.
-if CONFIG['MOZ_STACKWALKING']:
-    SOURCES += [
-        'StackWalk.cpp',
-    ]
--- a/netwerk/base/nsUDPSocket.cpp
+++ b/netwerk/base/nsUDPSocket.cpp
@@ -66,16 +66,32 @@ ResolveHost(const nsACString &host, nsID
   }
 
   nsCOMPtr<nsICancelable> tmpOutstanding;
   return dns->AsyncResolve(host, 0, listener, nullptr,
                            getter_AddRefs(tmpOutstanding));
 
 }
 
+static nsresult
+CheckIOStatus(const NetAddr *aAddr)
+{
+  MOZ_ASSERT(gIOService);
+
+  if (gIOService->IsNetTearingDown()) {
+    return NS_ERROR_FAILURE;
+  }
+
+  if (gIOService->IsOffline() && !IsLoopBackAddress(aAddr)) {
+    return NS_ERROR_OFFLINE;
+  }
+
+  return NS_OK;
+}
+
 //-----------------------------------------------------------------------------
 
 class SetSocketOptionRunnable : public Runnable
 {
 public:
   SetSocketOptionRunnable(nsUDPSocket* aSocket, const PRSocketOptionData& aOpt)
     : mSocket(aSocket)
     , mOpt(aOpt)
@@ -315,18 +331,19 @@ nsUDPSocket::OnMsgAttach()
 nsresult
 nsUDPSocket::TryAttach()
 {
   nsresult rv;
 
   if (!gSocketTransportService)
     return NS_ERROR_FAILURE;
 
-  if (gIOService->IsNetTearingDown()) {
-    return NS_ERROR_FAILURE;
+  rv = CheckIOStatus(&mAddr);
+  if (NS_FAILED(rv)) {
+    return rv;
   }
 
   //
   // find out if it is going to be ok to attach another socket to the STS.
   // if not then we have to wait for the STS to tell us that it is ok.
   // the notification is asynchronous, which means that when we could be
   // in a race to call AttachSocket once notified.  for this reason, when
   // we get notified, we just re-enter this function.  as a result, we are
@@ -525,17 +542,17 @@ nsUDPSocket::OnSocketDetached(PRFileDesc
     }
   }
 }
 
 void
 nsUDPSocket::IsLocal(bool *aIsLocal)
 {
   // If bound to loopback, this UDP socket only accepts local connections.
-  *aIsLocal = mAddr.raw.family == nsINetAddr::FAMILY_LOCAL;
+  *aIsLocal = IsLoopBackAddress(&mAddr);
 }
 
 //-----------------------------------------------------------------------------
 // nsSocket::nsISupports
 //-----------------------------------------------------------------------------
 
 NS_IMPL_ISUPPORTS(nsUDPSocket, nsIUDPSocket)
 
@@ -568,40 +585,54 @@ NS_IMETHODIMP
 nsUDPSocket::Init2(const nsACString& aAddr, int32_t aPort, nsIPrincipal *aPrincipal,
                    bool aAddressReuse, uint8_t aOptionalArgc)
 {
   if (NS_WARN_IF(aAddr.IsEmpty())) {
     return NS_ERROR_INVALID_ARG;
   }
 
   PRNetAddr prAddr;
+  memset(&prAddr, 0, sizeof(prAddr));
   if (PR_StringToNetAddr(aAddr.BeginReading(), &prAddr) != PR_SUCCESS) {
     return NS_ERROR_FAILURE;
   }
 
-  NetAddr addr;
-
-  if (aPort < 0)
+  if (aPort < 0) {
     aPort = 0;
+  }
 
-  addr.raw.family = AF_INET;
-  addr.inet.port = htons(aPort);
-  addr.inet.ip = prAddr.inet.ip;
+  switch (prAddr.raw.family) {
+    case PR_AF_INET:
+      prAddr.inet.port = PR_htons(aPort);
+      break;
+    case PR_AF_INET6:
+      prAddr.ipv6.port = PR_htons(aPort);
+      break;
+    default:
+      MOZ_ASSERT_UNREACHABLE("Dont accept address other than IPv4 and IPv6");
+      return NS_ERROR_ILLEGAL_VALUE;
+  }
+
+  NetAddr addr;
+  PRNetAddrToNetAddr(&prAddr, &addr);
 
   return InitWithAddress(&addr, aPrincipal, aAddressReuse, aOptionalArgc);
 }
 
 NS_IMETHODIMP
 nsUDPSocket::InitWithAddress(const NetAddr *aAddr, nsIPrincipal *aPrincipal,
                              bool aAddressReuse, uint8_t aOptionalArgc)
 {
   NS_ENSURE_TRUE(mFD == nullptr, NS_ERROR_ALREADY_INITIALIZED);
 
-  if (gIOService->IsNetTearingDown()) {
-    return NS_ERROR_FAILURE;
+  nsresult rv;
+
+  rv = CheckIOStatus(aAddr);
+  if (NS_FAILED(rv)) {
+    return rv;
   }
 
   bool addressReuse = (aOptionalArgc == 1) ? aAddressReuse : true;
 
   //
   // configure listening socket...
   //
 
@@ -670,16 +701,23 @@ nsUDPSocket::Connect(const NetAddr *aAdd
   UDPSOCKET_LOG(("nsUDPSocket::Connect [this=%p]\n", this));
 
   NS_ENSURE_ARG(aAddr);
 
   if (NS_WARN_IF(!mFD)) {
     return NS_ERROR_NOT_INITIALIZED;
   }
 
+  nsresult rv;
+
+  rv = CheckIOStatus(aAddr);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
   bool onSTSThread = false;
   mSts->IsOnCurrentThread(&onSTSThread);
   NS_ASSERTION(onSTSThread, "NOT ON STS THREAD");
   if (!onSTSThread) {
     return NS_ERROR_FAILURE;
   }
 
   PRNetAddr prAddr;
--- a/netwerk/base/security-prefs.js
+++ b/netwerk/base/security-prefs.js
@@ -49,18 +49,18 @@ pref("security.enterprise_roots.enabled"
 
 pref("security.OCSP.enabled", 1);
 pref("security.OCSP.require", false);
 pref("security.OCSP.GET.enabled", false);
 
 pref("security.pki.cert_short_lifetime_in_days", 10);
 // NB: Changes to this pref affect CERT_CHAIN_SHA1_POLICY_STATUS telemetry.
 // See the comment in CertVerifier.cpp.
-// 4 = allow SHA-1 for certificates issued before 2016 or by an imported root.
-pref("security.pki.sha1_enforcement_level", 4);
+// 3 = only allow SHA-1 for certificates issued by an imported root.
+pref("security.pki.sha1_enforcement_level", 3);
 
 // security.pki.name_matching_mode controls how the platform matches hostnames
 // to name information in TLS certificates. The possible values are:
 // 0: always fall back to the subject common name if necessary (as in, if the
 //    subject alternative name extension is either not present or does not
 //    contain any DNS names or IP addresses)
 // 1: fall back to the subject common name for certificates valid before 23
 //    August 2016 if necessary
--- a/netwerk/protocol/http/HSTSPrimerListener.cpp
+++ b/netwerk/protocol/http/HSTSPrimerListener.cpp
@@ -10,55 +10,88 @@
 #include "nsIHstsPrimingCallback.h"
 #include "nsIPrincipal.h"
 #include "nsSecurityHeaderParser.h"
 #include "nsISiteSecurityService.h"
 #include "nsISocketProvider.h"
 #include "nsISSLStatus.h"
 #include "nsISSLStatusProvider.h"
 #include "nsStreamUtils.h"
+#include "nsStreamListenerWrapper.h"
 #include "nsHttpChannel.h"
 #include "LoadInfo.h"
+#include "mozilla/Unused.h"
 
 namespace mozilla {
 namespace net {
 
 using namespace mozilla;
 
 NS_IMPL_ISUPPORTS(HSTSPrimingListener, nsIStreamListener,
-                  nsIRequestObserver, nsIInterfaceRequestor)
+                  nsIRequestObserver, nsIInterfaceRequestor,
+                  nsITimerCallback)
+
+// default to 3000ms, same as the preference
+uint32_t HSTSPrimingListener::sHSTSPrimingTimeout = 3000;
+
+
+HSTSPrimingListener::HSTSPrimingListener(nsIHstsPrimingCallback* aCallback)
+  : mCallback(aCallback)
+{
+  static nsresult rv =
+    Preferences::AddUintVarCache(&sHSTSPrimingTimeout,
+        "security.mixed_content.hsts_priming_request_timeout");
+  Unused << rv;
+}
 
 NS_IMETHODIMP
 HSTSPrimingListener::GetInterface(const nsIID & aIID, void **aResult)
 {
   return QueryInterface(aIID, aResult);
 }
 
-NS_IMETHODIMP
-HSTSPrimingListener::OnStartRequest(nsIRequest *aRequest,
-                                    nsISupports *aContext)
+void
+HSTSPrimingListener::ReportTiming(nsresult aResult)
 {
-  nsresult primingResult = CheckHSTSPrimingRequestStatus(aRequest);
-  nsCOMPtr<nsIHstsPrimingCallback> callback(mCallback);
-  mCallback = nullptr;
-
   nsCOMPtr<nsITimedChannel> timingChannel =
-    do_QueryInterface(callback);
+    do_QueryInterface(mCallback);
   if (timingChannel) {
     TimeStamp channelCreationTime;
     nsresult rv = timingChannel->GetChannelCreation(&channelCreationTime);
     if (NS_SUCCEEDED(rv) && !channelCreationTime.IsNull()) {
       PRUint32 interval =
         (PRUint32) (TimeStamp::Now() - channelCreationTime).ToMilliseconds();
       Telemetry::Accumulate(Telemetry::HSTS_PRIMING_REQUEST_DURATION,
-          (NS_SUCCEEDED(primingResult)) ? NS_LITERAL_CSTRING("success")
-                                        : NS_LITERAL_CSTRING("failure"),
+          (NS_SUCCEEDED(aResult)) ? NS_LITERAL_CSTRING("success")
+                                  : NS_LITERAL_CSTRING("failure"),
           interval);
     }
   }
+}
+
+NS_IMETHODIMP
+HSTSPrimingListener::OnStartRequest(nsIRequest *aRequest,
+                                    nsISupports *aContext)
+{
+  nsCOMPtr<nsIHstsPrimingCallback> callback;
+  callback.swap(mCallback);
+
+  if (mHSTSPrimingTimer) {
+    Unused << mHSTSPrimingTimer->Cancel();
+    mHSTSPrimingTimer = nullptr;
+  }
+
+  // if callback is null, we have already canceled this request and reported
+  // the failure
+  if (!callback) {
+    return NS_OK;
+  }
+
+  nsresult primingResult = CheckHSTSPrimingRequestStatus(aRequest);
+  ReportTiming(primingResult);
 
   if (NS_FAILED(primingResult)) {
     LOG(("HSTS Priming Failed (request was not approved)"));
     return callback->OnHSTSPrimingFailed(primingResult, false);
   }
 
   LOG(("HSTS Priming Succeeded (request was approved)"));
   return callback->OnHSTSPrimingSucceeded(false);
@@ -134,22 +167,50 @@ HSTSPrimingListener::OnDataAvailable(nsI
                                      nsIInputStream *inStr,
                                      uint64_t sourceOffset,
                                      uint32_t count)
 {
   uint32_t totalRead;
   return inStr->ReadSegments(NS_DiscardSegment, nullptr, count, &totalRead);
 }
 
+/** nsITimerCallback **/
+NS_IMETHODIMP
+HSTSPrimingListener::Notify(nsITimer* timer)
+{
+  nsresult rv;
+  nsCOMPtr<nsIHstsPrimingCallback> callback;
+  callback.swap(mCallback);
+  if (!callback) {
+    // we already processed this channel
+    return NS_OK;
+  }
+
+  ReportTiming(NS_ERROR_HSTS_PRIMING_TIMEOUT);
+
+  if (mPrimingChannel) {
+    rv = mPrimingChannel->Cancel(NS_ERROR_HSTS_PRIMING_TIMEOUT);
+    if (NS_FAILED(rv)) {
+      NS_ERROR("HSTS Priming timed out, and we got an error canceling the priming channel.");
+    }
+  }
+
+  rv = callback->OnHSTSPrimingFailed(NS_ERROR_HSTS_PRIMING_TIMEOUT, false);
+  if (NS_FAILED(rv)) {
+    NS_ERROR("HSTS Priming timed out, and we got an error reporting the failure.");
+  }
+
+  return NS_OK; // unused
+}
+
 // static
 nsresult
 HSTSPrimingListener::StartHSTSPriming(nsIChannel* aRequestChannel,
                                       nsIHstsPrimingCallback* aCallback)
 {
-
   nsCOMPtr<nsIURI> finalChannelURI;
   nsresult rv = NS_GetFinalChannelURI(aRequestChannel, getter_AddRefs(finalChannelURI));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIURI> uri;
   rv = NS_GetSecureUpgradedURI(finalChannelURI, getter_AddRefs(uri));
   NS_ENSURE_SUCCESS(rv,rv);
 
@@ -225,16 +286,18 @@ HSTSPrimingListener::StartHSTSPriming(ns
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Set method and headers
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(primingChannel);
   if (!httpChannel) {
     NS_ERROR("HSTSPrimingListener: Failed to QI to nsIHttpChannel!");
     return NS_ERROR_FAILURE;
   }
+  nsCOMPtr<nsIHttpChannelInternal> internal = do_QueryInterface(primingChannel);
+  NS_ENSURE_STATE(internal);
 
   // Currently using HEAD per the draft, but under discussion to change to GET
   // with credentials so if the upgrade is approved the result is already cached.
   rv = httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("HEAD"));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = httpChannel->
     SetRequestHeader(NS_LITERAL_CSTRING("Upgrade-Insecure-Requests"),
@@ -244,30 +307,51 @@ HSTSPrimingListener::StartHSTSPriming(ns
   // attempt to set the class of service flags on the new channel
   nsCOMPtr<nsIClassOfService> requestClass = do_QueryInterface(aRequestChannel);
   if (!requestClass) {
     NS_ERROR("HSTSPrimingListener: aRequestChannel is not an nsIClassOfService");
     return NS_ERROR_FAILURE;
   }
   nsCOMPtr<nsIClassOfService> primingClass = do_QueryInterface(httpChannel);
   if (!primingClass) {
-    NS_ERROR("HSTSPrimingListener: aRequestChannel is not an nsIClassOfService");
+    NS_ERROR("HSTSPrimingListener: httpChannel is not an nsIClassOfService");
     return NS_ERROR_FAILURE;
   }
 
   uint32_t classFlags = 0;
   rv = requestClass ->GetClassFlags(&classFlags);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = primingClass->SetClassFlags(classFlags);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // Set up listener which will start the original channel
-  nsCOMPtr<nsIStreamListener> primingListener(new HSTSPrimingListener(aCallback));
+  // The priming channel should have highest priority so that it completes as
+  // quickly as possible, allowing the load to proceed.
+  nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(primingChannel);
+  if (p) {
+    uint32_t priority = nsISupportsPriority::PRIORITY_HIGHEST;
+
+    p->SetPriority(priority);
+  }
 
+  // Set up listener which will start the original channel
+  HSTSPrimingListener* listener = new HSTSPrimingListener(aCallback);
   // Start priming
-  rv = primingChannel->AsyncOpen2(primingListener);
+  rv = primingChannel->AsyncOpen2(listener);
   NS_ENSURE_SUCCESS(rv, rv);
+  listener->mPrimingChannel.swap(primingChannel);
+
+  nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
+  NS_ENSURE_STATE(timer);
+
+  rv = timer->InitWithCallback(listener,
+                               sHSTSPrimingTimeout,
+                               nsITimer::TYPE_ONE_SHOT);
+  if (NS_FAILED(rv)) {
+    NS_ERROR("HSTS Priming failed to initialize channel cancellation timer");
+  }
+
+  listener->mHSTSPrimingTimer.swap(timer);
 
   return NS_OK;
 }
 
 } // namespace net
 } // namespace mozilla
--- a/netwerk/protocol/http/HSTSPrimerListener.h
+++ b/netwerk/protocol/http/HSTSPrimerListener.h
@@ -44,36 +44,41 @@ enum HSTSPrimingResult {
   // of mixed-content and hsts, and mixed-content blocks the load
   eHSTS_PRIMING_SUCCEEDED_BLOCK   = 5,
   // When priming succeeds, but preferences require preservation of the order
   // of mixed-content and hsts, and mixed-content allows the load over http
   eHSTS_PRIMING_SUCCEEDED_HTTP    = 6,
   // HSTS priming failed, and the load is blocked by mixed-content
   eHSTS_PRIMING_FAILED_BLOCK      = 7,
   // HSTS priming failed, and the load is allowed by mixed-content
-  eHSTS_PRIMING_FAILED_ACCEPT     = 8
+  eHSTS_PRIMING_FAILED_ACCEPT     = 8,
+  // The HSTS Priming request timed out, and the load is blocked by
+  // mixed-content
+  eHSTS_PRIMING_TIMEOUT_BLOCK     = 9,
+  // The HSTS Priming request timed out, and the load is allowed by
+  // mixed-content
+  eHSTS_PRIMING_TIMEOUT_ACCEPT    = 10
 };
 
 //////////////////////////////////////////////////////////////////////////
 // Class used as streamlistener and notification callback when
 // doing the HEAD request for an HSTS Priming check. Needs to be an
 // nsIStreamListener in order to receive events from AsyncOpen2
 class HSTSPrimingListener final : public nsIStreamListener,
-                                  public nsIInterfaceRequestor
+                                  public nsIInterfaceRequestor,
+                                  public nsITimerCallback
 {
 public:
-  explicit HSTSPrimingListener(nsIHstsPrimingCallback* aCallback)
-   : mCallback(aCallback)
-  {
-  }
+  explicit HSTSPrimingListener(nsIHstsPrimingCallback* aCallback);
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSISTREAMLISTENER
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSIINTERFACEREQUESTOR
+  NS_DECL_NSITIMERCALLBACK
 
 private:
   ~HSTSPrimingListener() {}
 
   // Only nsHttpChannel can invoke HSTS priming
   friend class mozilla::net::nsHttpChannel;
 
   /**
@@ -91,18 +96,38 @@ private:
                                    nsIHstsPrimingCallback* aCallback);
 
   /**
    * Given a request, return NS_OK if it has resulted in a cached HSTS update.
    * We don't need to check for the header as that has already been done for us.
    */
   nsresult CheckHSTSPrimingRequestStatus(nsIRequest* aRequest);
 
+  // send telemetry about how long HSTS priming requests take
+  void ReportTiming(nsresult aResult);
+
   /**
    * the nsIHttpChannel to notify with the result of HSTS priming.
    */
   nsCOMPtr<nsIHstsPrimingCallback> mCallback;
+
+  /**
+   * Keep a handle to the priming channel so we can cancel it on timeout
+   */
+  nsCOMPtr<nsIChannel> mPrimingChannel;
+
+  /**
+   * Keep a handle to the timer around so it can be canceled if we don't time
+   * out.
+   */
+  nsCOMPtr<nsITimer> mHSTSPrimingTimer;
+
+  /**
+   * How long (in ms) before an HSTS Priming channel times out.
+   * Preference: security.mixed_content.hsts_priming_request_timeout
+   */
+  static uint32_t sHSTSPrimingTimeout;
 };
 
 
 }} // mozilla::net
 
 #endif // HSTSPrimingListener_h__
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -8089,29 +8089,34 @@ nsHttpChannel::OnHSTSPrimingSucceeded(bo
  */
 nsresult
 nsHttpChannel::OnHSTSPrimingFailed(nsresult aError, bool aCached)
 {
     bool wouldBlock = mLoadInfo->GetMixedContentWouldBlock();
 
     LOG(("HSTS Priming Failed [this=%p], %s the load", this,
                 (wouldBlock) ? "blocking" : "allowing"));
-    if (aCached) {
+    if (aError == NS_ERROR_HSTS_PRIMING_TIMEOUT) {
+        // A priming request was sent, but timed out
+        Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_RESULT,
+                (wouldBlock) ?  HSTSPrimingResult::eHSTS_PRIMING_TIMEOUT_BLOCK :
+                HSTSPrimingResult::eHSTS_PRIMING_TIMEOUT_ACCEPT);
+    } else if (aCached) {
         // Between the time we marked for priming and started the priming request,
         // the host was found to not allow the upgrade, probably from another
         // priming request.
         Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_RESULT,
                 (wouldBlock) ?  HSTSPrimingResult::eHSTS_PRIMING_CACHED_BLOCK :
-                                HSTSPrimingResult::eHSTS_PRIMING_CACHED_NO_UPGRADE);
+                HSTSPrimingResult::eHSTS_PRIMING_CACHED_NO_UPGRADE);
     } else {
         // A priming request was sent, and no HSTS header was found that allows
         // the upgrade.
         Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_RESULT,
                 (wouldBlock) ?  HSTSPrimingResult::eHSTS_PRIMING_FAILED_BLOCK :
-                                HSTSPrimingResult::eHSTS_PRIMING_FAILED_ACCEPT);
+                HSTSPrimingResult::eHSTS_PRIMING_FAILED_ACCEPT);
     }
 
     // Don't visit again for at least
     // security.mixed_content.hsts_priming_cache_timeout seconds.
     nsISiteSecurityService* sss = gHttpHandler->GetSSService();
     NS_ENSURE_TRUE(sss, NS_ERROR_OUT_OF_MEMORY);
     nsresult rv = sss->CacheNegativeHSTSResult(mURI,
             nsMixedContentBlocker::sHSTSPrimingCacheTimeout);
--- a/netwerk/protocol/http/nsIHstsPrimingCallback.idl
+++ b/netwerk/protocol/http/nsIHstsPrimingCallback.idl
@@ -28,16 +28,17 @@ interface nsIHstsPrimingCallback : nsISu
    *
    * May be invoked synchronously if HSTS priming has already been performed
    * for the host.
    *
    * @param aCached whether the result was already in the HSTS cache
    */
   [noscript, nostdcall]
   void onHSTSPrimingSucceeded(in bool aCached);
+
   /**
    * HSTS priming has seen no STS header, the request itself has failed,
    * or some other failure which does not constitute a positive signal that the
    * site can be upgraded safely to HTTPS. The request may still be allowed
    * based on the user's preferences.
    *
    * May be invoked synchronously if HSTS priming has already been performed
    * for the host.
new file mode 100644
--- /dev/null
+++ b/netwerk/test/unit/test_udpsocket_offline.js
@@ -0,0 +1,81 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+/* jshint esnext:true, globalstrict:true, moz:true, undef:true, unused:true */
+/* globals Cc, Cu, Ci, Assert, run_next_test, add_test, do_register_cleanup */
+'use strict';
+
+/* globals Services */
+Cu.import('resource://gre/modules/Services.jsm');
+
+add_test(function test_ipv4_any() {
+  let socket = Cc['@mozilla.org/network/udp-socket;1'].createInstance(Ci.nsIUDPSocket);
+
+  Assert.throws(() => {
+    socket.init(-1, false, Services.scriptSecurityManager.getSystemPrincipal());
+  }, /NS_ERROR_OFFLINE/);
+
+  run_next_test();
+});
+
+add_test(function test_ipv6_any() {
+  let socket = Cc['@mozilla.org/network/udp-socket;1'].createInstance(Ci.nsIUDPSocket);
+
+  Assert.throws(() => {
+    socket.init2('::', -1, Services.scriptSecurityManager.getSystemPrincipal());
+  }, /NS_ERROR_OFFLINE/);
+
+  run_next_test();
+});
+
+add_test(function test_ipv4() {
+  let socket = Cc['@mozilla.org/network/udp-socket;1'].createInstance(Ci.nsIUDPSocket);
+
+  Assert.throws(() => {
+    socket.init2('240.0.0.1', -1, Services.scriptSecurityManager.getSystemPrincipal());
+  }, /NS_ERROR_OFFLINE/);
+
+  run_next_test();
+});
+
+add_test(function test_ipv6() {
+  let socket = Cc['@mozilla.org/network/udp-socket;1'].createInstance(Ci.nsIUDPSocket);
+
+  Assert.throws(() => {
+    socket.init2('2001:db8::1', -1, Services.scriptSecurityManager.getSystemPrincipal());
+  }, /NS_ERROR_OFFLINE/);
+
+  run_next_test();
+});
+
+add_test(function test_ipv4_loopback() {
+  let socket = Cc['@mozilla.org/network/udp-socket;1'].createInstance(Ci.nsIUDPSocket);
+
+  try {
+    socket.init2('127.0.0.1', -1, Services.scriptSecurityManager.getSystemPrincipal(), true);
+  } catch (e) {
+    Assert.ok(false, 'unexpected exception: ' + e);
+  }
+
+  run_next_test();
+});
+
+add_test(function test_ipv6_loopback() {
+  let socket = Cc['@mozilla.org/network/udp-socket;1'].createInstance(Ci.nsIUDPSocket);
+
+  try {
+    socket.init2('::1', -1, Services.scriptSecurityManager.getSystemPrincipal(), true);
+  } catch (e) {
+    Assert.ok(false, 'unexpected exception: ' + e);
+  }
+
+  run_next_test();
+});
+
+function run_test(){ // jshint ignore:line
+  Services.io.offline = true;
+  do_register_cleanup(() => {
+    Services.io.offline = false;
+  });
+  run_next_test();
+}
--- a/netwerk/test/unit/xpcshell.ini
+++ b/netwerk/test/unit/xpcshell.ini
@@ -169,16 +169,17 @@ skip-if = os == "android"
 [test_bug770243.js]
 [test_bug894586.js]
 # Allocating 4GB might actually succeed on 64 bit machines
 skip-if = bits != 32
 [test_bug935499.js]
 [test_bug1064258.js]
 [test_bug1218029.js]
 [test_udpsocket.js]
+[test_udpsocket_offline.js]
 [test_doomentry.js]
 [test_cacheflags.js]
 [test_cache_jar.js]
 [test_channel_close.js]
 [test_compareURIs.js]
 [test_compressappend.js]
 [test_content_encoding_gzip.js]
 [test_content_sniffer.js]
--- a/old-configure.in
+++ b/old-configure.in
@@ -4152,43 +4152,16 @@ fi # COMPILE_ENVIRONMENT
 
 AC_SUBST(MOZ_OPTIMIZE)
 AC_SUBST(MOZ_FRAMEPTR_FLAGS)
 AC_SUBST(MOZ_OPTIMIZE_FLAGS)
 AC_SUBST(MOZ_OPTIMIZE_LDFLAGS)
 AC_SUBST(MOZ_PGO_OPTIMIZE_FLAGS)
 
 dnl ========================================================
-dnl = Enable NS_StackWalk.
-dnl ========================================================
-
-# On Windows, NS_StackWalk will only work correctly if we have frame pointers
-# available. That will only be true for non-optimized builds, debug builds or
-# builds with --enable-profiling in the .mozconfig (which is turned on in
-# Nightly by default.)
-case "$OS_TARGET" in
-WINNT)
-    if test -z "$MOZ_OPTIMIZE" -o -n "$MOZ_PROFILING" -o -n "$MOZ_DEBUG"; then
-        MOZ_STACKWALKING=1
-    else
-        MOZ_STACKWALKING=
-    fi
-    ;;
-*)
-    MOZ_STACKWALKING=1
-    ;;
-esac
-
-if test -n "$MOZ_STACKWALKING"; then
-    AC_DEFINE(MOZ_STACKWALKING)
-fi
-
-AC_SUBST(MOZ_STACKWALKING)
-
-dnl ========================================================
 dnl = Disable treating compiler warnings as errors
 dnl ========================================================
 if test -z "$MOZ_ENABLE_WARNINGS_AS_ERRORS"; then
    WARNINGS_AS_ERRORS=''
 fi
 
 dnl ========================================================
 dnl = Enable runtime logging
--- a/security/certverifier/CertVerifier.cpp
+++ b/security/certverifier/CertVerifier.cpp
@@ -639,21 +639,19 @@ CertVerifier::VerifyCert(CERTCertificate
         break;
       }
 
       if (keySizeStatus) {
         *keySizeStatus = KeySizeStatus::AlreadyBad;
       }
       // The telemetry probe CERT_CHAIN_SHA1_POLICY_STATUS gives us feedback on
       // the result of setting a specific policy. However, we don't want noise
-      // from users who have manually set the policy to Allowed or Forbidden, so
-      // we only collect for ImportedRoot or ImportedRootOrBefore2016.
-      if (sha1ModeResult &&
-          (mSHA1Mode == SHA1Mode::ImportedRoot ||
-           mSHA1Mode == SHA1Mode::ImportedRootOrBefore2016)) {
+      // from users who have manually set the policy to something other than the
+      // default, so we only collect for ImportedRoot (which is the default).
+      if (sha1ModeResult && mSHA1Mode == SHA1Mode::ImportedRoot) {
         *sha1ModeResult = SHA1ModeResult::Failed;
       }
 
       break;
     }
 
     case certificateUsageSSLCA: {
       NSSCertDBTrustDomain trustDomain(trustSSL, defaultOCSPFetching,
--- a/security/sandbox/chromium-shim/sandbox/win/loggingCallbacks.h
+++ b/security/sandbox/chromium-shim/sandbox/win/loggingCallbacks.h
@@ -10,69 +10,63 @@
 #include <sstream>
 #include <iostream>
 
 #include "mozilla/Logging.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/sandboxing/loggingTypes.h"
 #include "nsContentUtils.h"
 
-#ifdef MOZ_STACKWALKING
 #include "mozilla/StackWalk.h"
-#endif
 
 namespace mozilla {
 
 static LazyLogModule sSandboxTargetLog("SandboxTarget");
 
 #define LOG_D(...) MOZ_LOG(sSandboxTargetLog, LogLevel::Debug, (__VA_ARGS__))
 
 namespace sandboxing {
 
-#ifdef MOZ_STACKWALKING
 static uint32_t sStackTraceDepth = 0;
 
 // NS_WalkStackCallback to write a formatted stack frame to an ostringstream.
 static void
 StackFrameToOStringStream(uint32_t aFrameNumber, void* aPC, void* aSP,
                           void* aClosure)
 {
   std::ostringstream* stream = static_cast<std::ostringstream*>(aClosure);
   MozCodeAddressDetails details;
   char buf[1024];
   MozDescribeCodeAddress(aPC, &details);
   MozFormatCodeAddressDetails(buf, sizeof(buf), aFrameNumber, aPC, &details);
   *stream << std::endl << "--" << buf;
   stream->flush();
 }
-#endif
 
 // Log to the browser console and, if DEBUG build, stderr.
 static void
 Log(const char* aMessageType,
     const char* aFunctionName,
     const char* aContext,
     const bool aShouldLogStackTrace = false,
     uint32_t aFramesToSkip = 0)
 {
   std::ostringstream msgStream;
   msgStream << "Process Sandbox " << aMessageType << ": " << aFunctionName;
   if (aContext) {
     msgStream << " for : " << aContext;
   }
 
-#ifdef MOZ_STACKWALKING
   if (aShouldLogStackTrace) {
     if (sStackTraceDepth) {
       msgStream << std::endl << "Stack Trace:";
       MozStackWalk(StackFrameToOStringStream, aFramesToSkip, sStackTraceDepth,
                    &msgStream, 0, nullptr);
     }
   }
-#endif
 
   std::string msg = msgStream.str();
 #if defined(DEBUG)
   // Use NS_DebugBreak directly as we want child process prefix, but not source
   // file or line number.
   NS_DebugBreak(NS_DEBUG_WARNING, nullptr, msg.c_str(), nullptr, -1);
 #endif
 
@@ -91,17 +85,17 @@ InitLoggingIfRequired(ProvideLogFunction
   if (!aProvideLogFunctionCb) {
     return;
   }
 
   if (Preferences::GetBool("security.sandbox.windows.log") ||
       PR_GetEnv("MOZ_WIN_SANDBOX_LOGGING")) {
     aProvideLogFunctionCb(Log);
 
-#if defined(MOZ_CONTENT_SANDBOX) && defined(MOZ_STACKWALKING)
+#if defined(MOZ_CONTENT_SANDBOX)
     // We can only log the stack trace on process types where we know that the
     // sandbox won't prevent it.
     if (XRE_IsContentProcess()) {
       Preferences::AddUintVarCache(&sStackTraceDepth,
         "security.sandbox.windows.log.stackTraceDepth");
     }
 #endif
   }
--- a/security/sandbox/moz.build
+++ b/security/sandbox/moz.build
@@ -1,14 +1,16 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
+
 with Files('**'):
     BUG_COMPONENT = ('Core', 'Security: Process Sandboxing')
 
 if CONFIG['OS_ARCH'] == 'Linux':
     DIRS += ['linux']
 elif CONFIG['OS_ARCH'] == 'Darwin':
     DIRS += ['mac']
 elif CONFIG['OS_ARCH'] == 'WINNT':
new file mode 100644
--- /dev/null
+++ b/security/sandbox/test/browser.ini
@@ -0,0 +1,11 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+[DEFAULT]
+tags = contentsandbox
+support-files =
+  browser_content_sandbox_utils.js
+
+skip-if = !e10s
+[browser_content_sandbox_fs.js]
+skip-if = !e10s
+[browser_content_sandbox_syscalls.js]
new file mode 100644
--- /dev/null
+++ b/security/sandbox/test/browser_content_sandbox_fs.js
@@ -0,0 +1,169 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+var prefs = Cc["@mozilla.org/preferences-service;1"]
+            .getService(Ci.nsIPrefBranch);
+
+Services.scriptloader.loadSubScript("chrome://mochitests/content/browser/" +
+    "security/sandbox/test/browser_content_sandbox_utils.js", this);
+
+/*
+ * This test exercises file I/O from the content process using OS.File
+ * methods to validate that calls that are meant to be blocked by content
+ * sandboxing are blocked.
+ */
+
+// Creates file at |path| and returns a promise that resolves with true
+// if the file was successfully created, otherwise false. Include imports
+// so this can be safely serialized and run remotely by ContentTask.spawn.
+function createFile(path) {
+  Components.utils.import("resource://gre/modules/osfile.jsm");
+  let encoder = new TextEncoder();
+  let array = encoder.encode("WRITING FROM CONTENT PROCESS");
+  return OS.File.writeAtomic(path, array).then(function(value) {
+    return true;
+  }, function(reason) {
+    return false;
+  });
+}
+
+// Deletes file at |path| and returns a promise that resolves with true
+// if the file was successfully deleted, otherwise false. Include imports
+// so this can be safely serialized and run remotely by ContentTask.spawn.
+function deleteFile(path) {
+  Components.utils.import("resource://gre/modules/osfile.jsm");
+  return OS.File.remove(path, {ignoreAbsent: false}).then(function(value) {
+    return true;
+  }).catch(function(err) {
+    return false;
+  });
+}
+
+// Returns true if the current content sandbox level, passed in
+// the |level| argument, supports filesystem sandboxing.
+function isContentFileIOSandboxed(level) {
+  let fileIOSandboxMinLevel = 0;
+
+  // Set fileIOSandboxMinLevel to the lowest level that has
+  // content filesystem sandboxing enabled. For now, this
+  // varies across Windows, Mac, Linux, other.
+  switch (Services.appinfo.OS) {
+    case "WINNT":
+      fileIOSandboxMinLevel = 1;
+      break;
+    case "Darwin":
+      fileIOSandboxMinLevel = 1;
+      break;
+    case "Linux":
+      fileIOSandboxMinLevel = 2;
+      break;
+    default:
+      Assert.ok(false, "Unknown OS");
+  }
+
+  return (level >= fileIOSandboxMinLevel);
+}
+
+//
+// Drive tests for a single content process.
+//
+// Tests attempting to write to a file in the home directory from the
+// content process--expected to fail.
+//
+// Tests attempting to write to a file in the content temp directory
+// from the content process--expected to succeed. On Mac and Windows,
+// use "ContentTmpD", but on Linux use "TmpD" until Linux uses the
+// content temp dir key.
+//
+add_task(function*() {
+  // This test is only relevant in e10s
+  if (!gMultiProcessBrowser) {
+    ok(false, "e10s is enabled");
+    info("e10s is not enabled, exiting");
+    return;
+  }
+
+  let level = 0;
+  let prefExists = true;
+
+  // Read the security.sandbox.content.level pref.
+  // If the pref isn't set and we're running on Linux on !isNightly(),
+  // exit without failing. The Linux content sandbox is only enabled
+  // on Nightly at this time.
+  try {
+    level = prefs.getIntPref("security.sandbox.content.level");
+  } catch (e) {
+    prefExists = false;
+  }
+
+  // Special case Linux on !isNightly
+  if (isLinux() && !isNightly()) {
+    todo(prefExists, "pref security.sandbox.content.level exists");
+    if (!prefExists) {
+      return;
+    }
+  }
+
+  ok(prefExists, "pref security.sandbox.content.level exists");
+  if (!prefExists) {
+    return;
+  }
+
+  // Special case Linux on !isNightly
+  if (isLinux() && !isNightly()) {
+    todo(level > 0, "content sandbox enabled for !nightly.");
+    return;
+  }
+
+  info(`security.sandbox.content.level=${level}`);
+  ok(level > 0, "content sandbox is enabled.");
+  if (level == 0) {
+    info("content sandbox is not enabled, exiting");
+    return;
+  }
+
+  let isFileIOSandboxed = isContentFileIOSandboxed(level);
+
+  // Special case Linux on !isNightly
+  if (isLinux() && !isNightly()) {
+    todo(isFileIOSandboxed, "content file I/O sandbox enabled for !nightly.");
+    return;
+  }
+
+  // Content sandbox enabled, but level doesn't include file I/O sandboxing.
+  ok(isFileIOSandboxed, "content file I/O sandboxing is enabled.");
+  if (!isFileIOSandboxed) {
+    info("content sandbox level too low for file I/O tests, exiting\n");
+    return;
+  }
+
+  let browser = gBrowser.selectedBrowser;
+
+  {
+    // test if the content process can create in $HOME, this should fail
+    let homeFile = fileInHomeDir();
+    let path = homeFile.path;
+    let fileCreated = yield ContentTask.spawn(browser, path, createFile);
+    ok(fileCreated == false, "creating a file in home dir is not permitted");
+    if (fileCreated == true) {
+      // content process successfully created the file, now remove it
+      homeFile.remove(false);
+    }
+  }
+
+  {
+    // test if the content process can create a temp file, should pass
+    let path = fileInTempDir().path;
+    let fileCreated = yield ContentTask.spawn(browser, path, createFile);
+    if (!fileCreated && isWin()) {
+      // TODO: fix 1329294 and enable this test for Windows.
+      // Not using todo() because this only fails on automation.
+      info("ignoring failure to write to content temp due to 1329294\n");
+      return;
+    }
+    ok(fileCreated == true, "creating a file in content temp is permitted");
+    // now delete the file
+    let fileDeleted = yield ContentTask.spawn(browser, path, deleteFile);
+    ok(fileDeleted == true, "deleting a file in content temp is permitted");
+  }
+});
new file mode 100644
--- /dev/null
+++ b/security/sandbox/test/browser_content_sandbox_syscalls.js
@@ -0,0 +1,223 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+var prefs = Cc["@mozilla.org/preferences-service;1"]
+            .getService(Ci.nsIPrefBranch);
+
+Services.scriptloader.loadSubScript("chrome://mochitests/content/browser/" +
+    "security/sandbox/test/browser_content_sandbox_utils.js", this);
+
+/*
+ * This test is for executing system calls in content processes to validate
+ * that calls that are meant to be blocked by content sandboxing are blocked.
+ * We use the term system calls loosely so that any OS API call such as
+ * fopen could be included.
+ */
+
+// Calls the native execv library function. Include imports so this can be
+// safely serialized and run remotely by ContentTask.spawn.
+function callExec(args) {
+  Components.utils.import("resource://gre/modules/ctypes.jsm");
+  let {lib, cmd} = args;
+  let libc = ctypes.open(lib);
+  let exec = libc.declare("execv", ctypes.default_abi,
+      ctypes.int, ctypes.char.ptr);
+  let rv = exec(cmd);
+  libc.close();
+  return (rv);
+}
+
+// Calls the native fork syscall.
+function callFork(args) {
+  Components.utils.import("resource://gre/modules/ctypes.jsm");
+  let {lib} = args;
+  let libc = ctypes.open(lib);
+  let fork = libc.declare("fork", ctypes.default_abi, ctypes.int);
+  let rv = fork();
+  libc.close();
+  return (rv);
+}
+
+// Calls the native open/close syscalls.
+function callOpen(args) {
+  Components.utils.import("resource://gre/modules/ctypes.jsm");
+  let {lib, path, flags} = args;
+  let libc = ctypes.open(lib);
+  let open = libc.declare("open", ctypes.default_abi,
+                          ctypes.int, ctypes.char.ptr, ctypes.int);
+  let close = libc.declare("close", ctypes.default_abi,
+                           ctypes.int, ctypes.int);
+  let fd = open(path, flags);
+  close(fd);
+  libc.close();
+  return (fd);
+}
+
+// open syscall flags
+function openWriteCreateFlags() {
+  Assert.ok(isMac() || isLinux());
+  if (isMac()) {
+    let O_WRONLY = 0x001;
+    let O_CREAT  = 0x200;
+    return (O_WRONLY | O_CREAT);
+  } else {
+    // Linux
+    let O_WRONLY = 0x01;
+    let O_CREAT  = 0x40;
+    return (O_WRONLY | O_CREAT);
+  }
+}
+
+// Returns the name of the native library needed for native syscalls
+function getOSLib() {
+  switch (Services.appinfo.OS) {
+    case "WINNT":
+      return "kernel32.dll";
+    case "Darwin":
+      return "libc.dylib";
+    case "Linux":
+      return "libc.so.6";
+    default:
+      Assert.ok(false, "Unknown OS");
+  }
+}
+
+// Returns a harmless command to execute with execv
+function getOSExecCmd() {
+  Assert.ok(!isWin());
+  return ("/bin/cat");
+}
+
+// Returns true if the current content sandbox level, passed in
+// the |level| argument, supports syscall sandboxing.
+function areContentSyscallsSandboxed(level) {
+  let syscallsSandboxMinLevel = 0;
+
+  // Set syscallsSandboxMinLevel to the lowest level that has
+  // syscall sandboxing enabled. For now, this varies across
+  // Windows, Mac, Linux, other.
+  switch (Services.appinfo.OS) {
+    case "WINNT":
+      syscallsSandboxMinLevel = 1;
+      break;
+    case "Darwin":
+      syscallsSandboxMinLevel = 1;
+      break;
+    case "Linux":
+      syscallsSandboxMinLevel = 2;
+      break;
+    default:
+      Assert.ok(false, "Unknown OS");
+  }
+
+  return (level >= syscallsSandboxMinLevel);
+}
+
+//
+// Drive tests for a single content process.
+//
+// Tests executing OS API calls in the content process. Limited to Mac
+// and Linux calls for now.
+//
+add_task(function*() {
+  // This test is only relevant in e10s
+  if (!gMultiProcessBrowser) {
+    ok(false, "e10s is enabled");
+    info("e10s is not enabled, exiting");
+    return;
+  }
+
+  let level = 0;
+  let prefExists = true;
+
+  // Read the security.sandbox.content.level pref.
+  // If the pref isn't set and we're running on Linux on !isNightly(),
+  // exit without failing. The Linux content sandbox is only enabled
+  // on Nightly at this time.
+  try {
+    level = prefs.getIntPref("security.sandbox.content.level");
+  } catch (e) {
+    prefExists = false;
+  }
+
+  // Special case Linux on !isNightly
+  if (isLinux() && !isNightly()) {
+    todo(prefExists, "pref security.sandbox.content.level exists");
+    if (!prefExists) {
+      return;
+    }
+  }
+
+  ok(prefExists, "pref security.sandbox.content.level exists");
+  if (!prefExists) {
+    return;
+  }
+
+  // Special case Linux on !isNightly
+  if (isLinux() && !isNightly()) {
+    todo(level > 0, "content sandbox enabled for !nightly.");
+    return;
+  }
+
+  info(`security.sandbox.content.level=${level}`);
+  ok(level > 0, "content sandbox is enabled.");
+  if (level == 0) {
+    info("content sandbox is not enabled, exiting");
+    return;
+  }
+
+  let areSyscallsSandboxed = areContentSyscallsSandboxed(level);
+
+  // Special case Linux on !isNightly
+  if (isLinux() && !isNightly()) {
+    todo(areSyscallsSandboxed, "content syscall sandbox enabled for !nightly.");
+    return;
+  }
+
+  // Content sandbox enabled, but level doesn't include syscall sandboxing.
+  ok(areSyscallsSandboxed, "content syscall sandboxing is enabled.");
+  if (!areSyscallsSandboxed) {
+    info("content sandbox level too low for syscall tests, exiting\n");
+    return;
+  }
+
+  let browser = gBrowser.selectedBrowser;
+  let lib = getOSLib();
+
+  // use execv syscall
+  // (causes content process to be killed on Linux)
+  if (isMac()) {
+    // exec something harmless, this should fail
+    let cmd = getOSExecCmd();
+    let rv = yield ContentTask.spawn(browser, {lib, cmd}, callExec);
+    ok(rv == -1, `exec(${cmd}) is not permitted`);
+  }
+
+  // use open syscall
+  if (isLinux() || isMac())
+  {
+    // open a file for writing in $HOME, this should fail
+    let path = fileInHomeDir().path;
+    let flags = openWriteCreateFlags();
+    let fd = yield ContentTask.spawn(browser, {lib, path, flags}, callOpen);
+    ok(fd < 0, "opening a file for writing in home is not permitted");
+  }
+
+  // use open syscall
+  if (isLinux() || isMac())
+  {
+    // open a file for writing in the content temp dir, this should work
+    // and the open handler in the content process closes the file for us
+    let path = fileInTempDir().path;
+    let flags = openWriteCreateFlags();
+    let fd = yield ContentTask.spawn(browser, {lib, path, flags}, callOpen);
+    ok(fd >= 0, "opening a file for writing in content temp is permitted");
+  }
+
+  // use fork syscall
+  if (isLinux() || isMac())
+  {
+    let rv = yield ContentTask.spawn(browser, {lib}, callFork);
+    ok(rv == -1, "calling fork is not permitted");
+  }
+});
new file mode 100644
--- /dev/null
+++ b/security/sandbox/test/browser_content_sandbox_utils.js
@@ -0,0 +1,57 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const uuidGenerator = Cc["@mozilla.org/uuid-generator;1"]
+                      .getService(Ci.nsIUUIDGenerator);
+
+/*
+ * Utility functions for the browser content sandbox tests.
+ */
+
+function isMac() { return Services.appinfo.OS == "Darwin" }
+function isWin() { return Services.appinfo.OS == "WINNT" }
+function isLinux() { return Services.appinfo.OS == "Linux" }
+
+function isNightly() {
+  let version = SpecialPowers.Cc["@mozilla.org/xre/app-info;1"].
+    getService(SpecialPowers.Ci.nsIXULAppInfo).version;
+  return (version.endsWith("a1"));
+}
+
+function uuid() {
+  return uuidGenerator.generateUUID().toString();
+}
+
+// Returns a file object for a new file in the home dir ($HOME/<UUID>).
+function fileInHomeDir() {
+  // get home directory, make sure it exists
+  let homeDir = Services.dirsvc.get("Home", Ci.nsILocalFile);
+  Assert.ok(homeDir.exists(), "Home dir exists");
+  Assert.ok(homeDir.isDirectory(), "Home dir is a directory");
+
+  // build a file object for a new file named $HOME/<UUID>
+  let homeFile = homeDir.clone();
+  homeFile.appendRelativePath(uuid());
+  Assert.ok(!homeFile.exists(), homeFile.path + " does not exist");
+  return (homeFile);
+}
+
+// Returns a file object for a new file in the content temp dir (.../<UUID>).
+function fileInTempDir() {
+  let contentTempKey = "ContentTmpD";
+  if (Services.appinfo.OS == "Linux") {
+    // Linux builds don't use the content-specific temp key
+    contentTempKey = "TmpD";
+  }
+
+  // get the content temp dir, make sure it exists
+  let ctmp = Services.dirsvc.get(contentTempKey, Ci.nsILocalFile);
+  Assert.ok(ctmp.exists(), "Content temp dir exists");
+  Assert.ok(ctmp.isDirectory(), "Content temp dir is a directory");
+
+  // build a file object for a new file in content temp
+  let tempFile = ctmp.clone();
+  tempFile.appendRelativePath(uuid());
+  Assert.ok(!tempFile.exists(), tempFile.path + " does not exist");
+  return (tempFile);
+}
--- a/taskcluster/taskgraph/transforms/signing.py
+++ b/taskcluster/taskgraph/transforms/signing.py
@@ -75,17 +75,17 @@ def validate(config, jobs):
 def make_task_description(config, jobs):
     for job in jobs:
         dep_job = job['dependent-task']
 
         signing_format_scopes = []
         formats = set([])
         for artifacts in job['upstream-artifacts']:
             for f in artifacts['formats']:
-                formats.update(f)  # Add each format only once
+                formats.add(f)  # Add each format only once
         for format in formats:
             signing_format_scopes.append("project:releng:signing:format:{}".format(format))
 
         treeherder = job.get('treeherder', {})
         treeherder.setdefault('symbol', 'tc(Ns)')
         dep_th_platform = dep_job.task.get('extra', {}).get(
             'treeherder', {}).get('machine', {}).get('platform', '')
         treeherder.setdefault('platform', "{}/opt".format(dep_th_platform))
--- a/testing/marionette/browser.js
+++ b/testing/marionette/browser.js
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {utils: Cu} = Components;
 
 Cu.import("chrome://marionette/content/element.js");
+Cu.import("chrome://marionette/content/error.js");
 Cu.import("chrome://marionette/content/frame.js");
 
 this.EXPORTED_SYMBOLS = ["browser"];
 
 this.browser = {};
 
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
@@ -143,28 +144,60 @@ browser.Context = class {
         break;
 
       case "Fennec":
         this.browser = win.BrowserApp;
         break;
     }
   }
 
+  /**
+   * Close the current window.
+   *
+   * @return {Promise}
+   *     A promise which is resolved when the current window has been closed.
+   */
+  closeWindow() {
+    return new Promise(resolve => {
+      this.window.addEventListener("unload", ev => {
+        resolve();
+      }, {once: true});
+      this.window.close();
+    });
+  }
+
   /** Called when we start a session with this browser. */
   startSession(newSession, win, callback) {
     callback(win, newSession);
   }
 
-  /** Closes current tab. */
+  /**
+   * Close the current tab.
+   *
+   * @return {Promise}
+   *     A promise which is resolved when the current tab has been closed.
+   */
   closeTab() {
-    if (this.browser &&
-        this.browser.removeTab &&
-        this.tab !== null && (this.driver.appName != "B2G")) {
-      this.browser.removeTab(this.tab);
+    // If the current window is not a browser then close it directly. Do the
+    // same if only one remaining tab is open, or no tab selected at all.
+    if (!this.browser || !this.tab || this.browser.browsers.length == 1) {
+      return this.closeWindow();
     }
+
+    return new Promise((resolve, reject) => {
+      if (this.browser.removeTab) {
+        this.tab.addEventListener("TabClose", ev => {
+          resolve();
+        }, {once: true});
+        this.browser.removeTab(this.tab);
+      } else {
+        reject(new UnsupportedOperationError(
+            `closeTab() not supported in ${this.driver.appName}`));
+      }
+    });
   }
 
   /**
    * Opens a tab with given URI.
    *
    * @param {string} uri
    *      URI to open.
    */
--- a/testing/marionette/client/marionette_driver/marionette.py
+++ b/testing/marionette/client/marionette_driver/marionette.py
@@ -1450,51 +1450,53 @@ class Marionette(object):
         If called in the content context it will return a list of
         references to all available browser windows.  Called in the
         chrome context, it will list all available windows, not just
         browser windows (e.g. not just navigator.browser).
 
         Each window handle is assigned by the server, and the list of
         strings returned does not have a guaranteed ordering.
 
-        :returns: unordered list of unique window handles as strings
+        :returns: Unordered list of unique window handles as strings
         """
         return self._send_message(
             "getWindowHandles", key="value" if self.protocol == 1 else None)
 
     @property
     def chrome_window_handles(self):
         """Get a list of currently open chrome windows.
 
         Each window handle is assigned by the server, and the list of
         strings returned does not have a guaranteed ordering.
 
-        :returns: unordered list of unique window handles as strings
+        :returns: Unordered list of unique chrome window handles as strings
         """
         return self._send_message(
             "getChromeWindowHandles", key="value" if self.protocol == 1 else None)
 
     @property
     def page_source(self):
         """A string representation of the DOM."""
         return self._send_message("getPageSource", key="value")
 
     def close(self):
         """Close the current window, ending the session if it's the last
         window currently open.
 
+        :returns: Unordered list of remaining unique window handles as strings
         """
-        self._send_message("close")
+        return self._send_message("close")
 
     def close_chrome_window(self):
         """Close the currently selected chrome window, ending the session
         if it's the last window open.
 
+        :returns: Unordered list of remaining unique chrome window handles as strings
         """
-        self._send_message("closeChromeWindow")
+        return self._send_message("closeChromeWindow")
 
     def set_context(self, context):
         """Sets the context that Marionette commands are running in.
 
         :param context: Context, may be one of the class properties
             `CONTEXT_CHROME` or `CONTEXT_CONTENT`.
 
         Usage example::
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -157,16 +157,83 @@ this.GeckoDriver = function (appName, se
 };
 
 Object.defineProperty(GeckoDriver.prototype, "a11yChecks", {
   get: function () {
     return this.capabilities.get("moz:accessibilityChecks");
   }
 });
 
+Object.defineProperty(GeckoDriver.prototype, "proxy", {
+  get: function () {
+    return this.capabilities.get("proxy");
+  }
+});
+
+Object.defineProperty(GeckoDriver.prototype, "secureTLS", {
+  get: function () {
+    return !this.capabilities.get("acceptInsecureCerts");
+  }
+});
+
+Object.defineProperty(GeckoDriver.prototype, "timeouts", {
+  get: function () {
+    return this.capabilities.get("timeouts");
+  },
+
+  set: function (newTimeouts) {
+    this.capabilities.set("timeouts", newTimeouts);
+  },
+});
+
+Object.defineProperty(GeckoDriver.prototype, "windowHandles", {
+  get: function () {
+    let hs = [];
+    let winEn = Services.wm.getEnumerator(null);
+
+    while (winEn.hasMoreElements()) {
+      let win = winEn.getNext();
+      if (win.gBrowser) {
+        let tabbrowser = win.gBrowser;
+        for (let i = 0; i < tabbrowser.browsers.length; ++i) {
+          let winId = this.getIdForBrowser(tabbrowser.getBrowserAtIndex(i));
+          if (winId !== null) {
+            hs.push(winId);
+          }
+        }
+      } else {
+        // For other chrome windows beside the browser window, only count the window itself.
+        let winId = win.QueryInterface(Ci.nsIInterfaceRequestor)
+            .getInterface(Ci.nsIDOMWindowUtils)
+            .outerWindowID;
+        hs.push(winId.toString());
+      }
+    }
+
+    return hs;
+  },
+});
+
+Object.defineProperty(GeckoDriver.prototype, "chromeWindowHandles", {
+  get : function () {
+    let hs = [];
+    let winEn = Services.wm.getEnumerator(null);
+
+    while (winEn.hasMoreElements()) {
+      let foundWin = winEn.getNext();
+      let winId = foundWin.QueryInterface(Ci.nsIInterfaceRequestor)
+          .getInterface(Ci.nsIDOMWindowUtils)
+          .outerWindowID;
+      hs.push(winId.toString());
+    }
+
+    return hs;
+  },
+});
+
 GeckoDriver.prototype.QueryInterface = XPCOMUtils.generateQI([
   Ci.nsIMessageListener,
   Ci.nsIObserver,
   Ci.nsISupportsWeakReference,
 ]);
 
 /**
  * Switches to the global ChromeMessageBroadcaster, potentially replacing
@@ -486,38 +553,16 @@ GeckoDriver.prototype.listeningPromise =
     let cb = () => {
       this.mm.removeMessageListener(li, cb);
       resolve();
     };
     this.mm.addMessageListener(li, cb);
   });
 };
 
-Object.defineProperty(GeckoDriver.prototype, "timeouts", {
-  get: function () {
-    return this.capabilities.get("timeouts");
-  },
-
-  set: function (newTimeouts) {
-    this.capabilities.set("timeouts", newTimeouts);
-  },
-});
-
-Object.defineProperty(GeckoDriver.prototype, "secureTLS", {
-  get: function () {
-    return !this.capabilities.get("acceptInsecureCerts");
-  }
-});
-
-Object.defineProperty(GeckoDriver.prototype, "proxy", {
-  get: function () {
-    return this.capabilities.get("proxy");
-  }
-});
-
 /** Create a new session. */
 GeckoDriver.prototype.newSession = function*(cmd, resp) {
   if (this.sessionId) {
     throw new SessionNotCreatedError("Maximum number of active sessions");
   }
 
   this.sessionId = cmd.parameters.sessionId ||
       cmd.parameters.session_id ||
@@ -1003,105 +1048,85 @@ GeckoDriver.prototype.goForward = functi
 /** Refresh the page. */
 GeckoDriver.prototype.refresh = function*(cmd, resp) {
   assert.content(this.context);
 
   yield this.listener.refresh();
 };
 
 /**
+ * Forces an update for the given browser's id.
+ */
+GeckoDriver.prototype.updateIdForBrowser = function (browser, newId) {
+  this._browserIds.set(browser.permanentKey, newId);
+};
+
+/**
+ * Retrieves a listener id for the given xul browser element. In case
+ * the browser is not known, an attempt is made to retrieve the id from
+ * a CPOW, and null is returned if this fails.
+ */
+GeckoDriver.prototype.getIdForBrowser = function (browser) {
+  if (browser === null) {
+    return null;
+  }
+  let permKey = browser.permanentKey;
+  if (this._browserIds.has(permKey)) {
+    return this._browserIds.get(permKey);
+  }
+
+  let winId = browser.outerWindowID;
+  if (winId) {
+    winId = winId.toString();
+    this._browserIds.set(permKey, winId);
+    return winId;
+  }
+  return null;
+},
+
+/**
  * Get the current window's handle. On desktop this typically corresponds
  * to the currently selected tab.
  *
  * Return an opaque server-assigned identifier to this window that
  * uniquely identifies it within this Marionette instance.  This can
  * be used to switch to this window at a later point.
  *
  * @return {string}
  *     Unique window handle.
  */
 GeckoDriver.prototype.getWindowHandle = function (cmd, resp) {
   // curFrameId always holds the current tab.
-  if (this.curBrowser.curFrameId && this.appName != "B2G") {
+  if (this.curBrowser.curFrameId) {
     resp.body.value = this.curBrowser.curFrameId;
     return;
   }
 
   for (let i in this.browsers) {
     if (this.curBrowser == this.browsers[i]) {
       resp.body.value = i;
       return;
     }
   }
 };
 
 /**
- * Forces an update for the given browser's id.
- */
-GeckoDriver.prototype.updateIdForBrowser = function (browser, newId) {
-  this._browserIds.set(browser.permanentKey, newId);
-};
-
-/**
- * Retrieves a listener id for the given xul browser element. In case
- * the browser is not known, an attempt is made to retrieve the id from
- * a CPOW, and null is returned if this fails.
- */
-GeckoDriver.prototype.getIdForBrowser = function getIdForBrowser(browser) {
-  if (browser === null) {
-    return null;
-  }
-  let permKey = browser.permanentKey;
-  if (this._browserIds.has(permKey)) {
-    return this._browserIds.get(permKey);
-  }
-
-  let winId = browser.outerWindowID;
-  if (winId) {
-    winId += "";
-    this._browserIds.set(permKey, winId);
-    return winId;
-  }
-  return null;
-},
-
-/**
- * Get a list of top-level browsing contexts.  On desktop this typically
- * corresponds to the set of open tabs.
+ * Get a list of top-level browsing contexts. On desktop this typically
+ * corresponds to the set of open tabs for browser windows, or the window itself
+ * for non-browser chrome windows.
  *
  * Each window handle is assigned by the server and is guaranteed unique,
  * however the return array does not have a specified ordering.
  *
  * @return {Array.<string>}
  *     Unique window handles.
  */
 GeckoDriver.prototype.getWindowHandles = function (cmd, resp) {
-  let hs = [];
-  let winEn = Services.wm.getEnumerator(null);
-  while (winEn.hasMoreElements()) {
-    let win = winEn.getNext();
-    if (win.gBrowser && this.appName != "B2G") {
-      let tabbrowser = win.gBrowser;
-      for (let i = 0; i < tabbrowser.browsers.length; ++i) {
-        let winId = this.getIdForBrowser(tabbrowser.getBrowserAtIndex(i));
-        if (winId !== null) {
-          hs.push(winId);
-        }
-      }
-    } else {
-      // XUL Windows, at least, do not have gBrowser
-      let winId = win.QueryInterface(Ci.nsIInterfaceRequestor)
-          .getInterface(Ci.nsIDOMWindowUtils)
-          .outerWindowID;
-      winId += (this.appName == "B2G") ? "-b2g" : "";
-      hs.push(winId);
-    }
-  }
-  resp.body = hs;
-};
+  return this.windowHandles;
+}
 
 /**
  * Get the current window's handle.  This corresponds to a window that
  * may itself contain tabs.
  *
  * Return an opaque server-assigned identifier to this window that
  * uniquely identifies it within this Marionette instance.  This can
  * be used to switch to this window at a later point.
@@ -1121,28 +1146,18 @@ GeckoDriver.prototype.getChromeWindowHan
 /**
  * Returns identifiers for each open chrome window for tests interested in
  * managing a set of chrome windows and tabs separately.
  *
  * @return {Array.<string>}
  *     Unique window handles.
  */
 GeckoDriver.prototype.getChromeWindowHandles = function (cmd, resp) {
-  let hs = [];
-  let winEn = Services.wm.getEnumerator(null);
-  while (winEn.hasMoreElements()) {
-    let foundWin = winEn.getNext();
-    let winId = foundWin.QueryInterface(Ci.nsIInterfaceRequestor)
-        .getInterface(Ci.nsIDOMWindowUtils)
-        .outerWindowID;
-    winId = winId + ((this.appName == "B2G") ? "-b2g" : "");
-    hs.push(winId);
-  }
-  resp.body = hs;
-};
+  return this.chromeWindowHandles;
+}
 
 /**
  * Get the current window position.
  *
  * @return {Object.<string, number>}
  *     Object with |x| and |y| coordinates.
  */
 GeckoDriver.prototype.getWindowPosition = function (cmd, resp) {
@@ -2076,96 +2091,92 @@ GeckoDriver.prototype.deleteCookie = fun
     return true;
   };
 
   this.mm.addMessageListener("Marionette:deleteCookie", cb);
   yield this.listener.deleteCookie(cmd.parameters.name);
 };
 
 /**
- * Close the current window, ending the session if it's the last
- * window currently open.
+ * Close the currently selected tab/window.
  *
- * On B2G this method is a noop and will return immediately.
+ * With multiple open tabs present the currently selected tab will be closed.
+ * Otherwise the window itself will be closed. If it is the last window
+ * currently open, the window will not be closed to prevent a shutdown of the
+ * application. Instead the returned list of window handles is empty.
+ *
+ * @return {Array.<string>}
+ *     Unique window handles of remaining windows.
  */
 GeckoDriver.prototype.close = function (cmd, resp) {
-  // can't close windows on B2G
-  if (this.appName == "B2G") {
-    return;
-  }
-
   let nwins = 0;
   let winEn = Services.wm.getEnumerator(null);
+
   while (winEn.hasMoreElements()) {
     let win = winEn.getNext();
 
-    // count both windows and tabs
+    // For browser windows count the tabs. Otherwise take the window itself.
     if (win.gBrowser) {
       nwins += win.gBrowser.browsers.length;
     } else {
       nwins++;
     }
   }
 
-  // if there is only 1 window left, delete the session
+  // If there is only 1 window left, do not close it. Instead return a faked
+  // empty array of window handles. This will instruct geckodriver to terminate
+  // the application.
   if (nwins == 1) {
-    this.sessionTearDown();
-    return;
+    return [];
   }
 
-  try {
-    if (this.mm != globalMessageManager) {
-      this.mm.removeDelayedFrameScript(FRAME_SCRIPT);
-    }
+  if (this.mm != globalMessageManager) {
+    this.mm.removeDelayedFrameScript(FRAME_SCRIPT);
+  }
 
-    if (this.curBrowser.tab) {
-      this.curBrowser.closeTab();
-    } else {
-      this.getCurrentWindow().close();
-    }
-  } catch (e) {
-    throw new UnknownError(`Could not close window: ${e.message}`);
-  }
+  return this.curBrowser.closeTab().then(() => this.windowHandles);
 };
 
 /**
- * Close the currently selected chrome window, ending the session if it's the last
- * window currently open.
+ * Close the currently selected chrome window.
  *
- * On B2G this method is a noop and will return immediately.
+ * If it is the last window currently open, the chrome window will not be
+ * closed to prevent a shutdown of the application. Instead the returned
+ * list of chrome window handles is empty.
+ *
+ * @return {Array.<string>}
+ *     Unique chrome window handles of remaining chrome windows.
  */
 GeckoDriver.prototype.closeChromeWindow = function (cmd, resp) {
-  // can't close windows on B2G
-  if (this.appName == "B2G") {
-    return;
-  }
+  assert.firefox();
 
   // Get the total number of windows
   let nwins = 0;
   let winEn = Services.wm.getEnumerator(null);
+
   while (winEn.hasMoreElements()) {
     nwins++;
     winEn.getNext();
   }
 
-  // if there is only 1 window left, delete the session
+  // If there is only 1 window left, do not close it. Instead return a faked
+  // empty array of window handles. This will instruct geckodriver to terminate
+  // the application.
   if (nwins == 1) {
-    this.sessionTearDown();
-    return;
+    return [];
   }
 
-  try {
-    // reset frame to the top-most frame
-    this.curFrame = null;
+  // reset frame to the top-most frame
+  this.curFrame = null;
 
+  if (this.mm != globalMessageManager) {
     this.mm.removeDelayedFrameScript(FRAME_SCRIPT);
-    this.getCurrentWindow().close();
-  } catch (e) {
-    throw new UnknownError(`Could not close window: ${e.message}`);
   }
+
+  return this.curBrowser.closeWindow().then(() => this.chromeWindowHandles);
 };
 
 /**
  * Deletes the session.
  *
  * If it is a desktop environment, it will close all listeners.
  *
  * If it is a B2G environment, it will make the main content listener
--- a/testing/marionette/harness/marionette_harness/__init__.py
+++ b/testing/marionette/harness/marionette_harness/__init__.py
@@ -3,16 +3,17 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 __version__ = '4.0.0'
 
 from .marionette_test import (
     CommonTestCase,
     expectedFailure,
     MarionetteTestCase,
+    parameterized,
     run_if_e10s,
     run_if_manage_instance,
     skip,
     skip_if_chrome,
     skip_if_desktop,
     skip_if_e10s,
     skip_if_mobile,
     SkipTest,
--- a/testing/marionette/harness/marionette_harness/runner/mixins/window_manager.py
+++ b/testing/marionette/harness/marionette_harness/runner/mixins/window_manager.py
@@ -91,17 +91,17 @@ class WindowManagerMixin(object):
             [new_tab] = list(set(self.marionette.window_handles) - set(current_tabs))
 
             return new_tab
 
     def open_window(self, trigger=None):
         current_windows = self.marionette.chrome_window_handles
 
         def loaded(handle):
-            with self.marionette.using_context('chrome'):
+            with self.marionette.using_context("chrome"):
                 return self.marionette.execute_script("""
                   Components.utils.import("resource://gre/modules/Services.jsm");
 
                   let win = Services.wm.getOuterWindowWithId(Number(arguments[0]));
                   return win.document.readyState == "complete";
                 """, script_args=[handle])
 
         try:
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_execute_script.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_execute_script.py
@@ -4,17 +4,17 @@
 
 import os
 import urllib
 
 from marionette_driver import By, errors
 from marionette_driver.marionette import HTMLElement
 from marionette_driver.wait import Wait
 
-from marionette_harness import MarionetteTestCase, WindowManagerMixin
+from marionette_harness import MarionetteTestCase, skip_if_mobile, WindowManagerMixin
 
 
 def inline(doc):
     return "data:text/html;charset=utf-8,{}".format(urllib.quote(doc))
 
 
 elements = inline("<p>foo</p> <p>bar</p>")
 
@@ -38,22 +38,28 @@ class TestExecuteSimpleTestContent(Mario
                 """, filename="file.js")
             self.assertFalse(True)
         except errors.JavascriptException as e:
             self.assertIn("throwHere is not defined", e.message)
             self.assertIn("@file.js:2", e.stacktrace)
 
 
 class TestExecuteContent(MarionetteTestCase):
+
+    def assert_is_defined(self, property, sandbox="default"):
+        self.assertTrue(self.marionette.execute_script(
+            "return typeof arguments[0] != 'undefined'", [property], sandbox=sandbox),
+            "property {} is undefined".format(property))
+
     def test_return_number(self):
         self.assertEqual(1, self.marionette.execute_script("return 1"))
         self.assertEqual(1.5, self.marionette.execute_script("return 1.5"))
 
     def test_return_boolean(self):
-        self.assertEqual(True, self.marionette.execute_script("return true"))
+        self.assertTrue(self.marionette.execute_script("return true"))
 
     def test_return_string(self):
         self.assertEqual("foo", self.marionette.execute_script("return 'foo'"))
 
     def test_return_array(self):
         self.assertEqual(
             [1, 2], self.marionette.execute_script("return [1, 2]"))
         self.assertEqual(
@@ -74,53 +80,46 @@ class TestExecuteContent(MarionetteTestC
             {"foo": 1.5}, self.marionette.execute_script("return {foo: 1.5}"))
         self.assertEqual(
             {"foo": True}, self.marionette.execute_script("return {foo: true}"))
         self.assertEqual(
             {"foo": "bar"}, self.marionette.execute_script("return {foo: 'bar'}"))
         self.assertEqual(
             {"foo": [1, 2]}, self.marionette.execute_script("return {foo: [1, 2]}"))
         self.assertEqual(
-            {"foo": {"bar": [1, 2]}}, self.marionette.execute_script("return {foo: {bar: [1, 2]}}"))
+            {"foo": {"bar": [1, 2]}},
+            self.marionette.execute_script("return {foo: {bar: [1, 2]}}"))
 
     def test_no_return_value(self):
         self.assertIsNone(self.marionette.execute_script("true"))
 
     def test_argument_null(self):
-        self.assertEqual(
-            None, self.marionette.execute_script("return arguments[0]", [None]))
+        self.assertIsNone(self.marionette.execute_script("return arguments[0]", [None]))
 
     def test_argument_number(self):
         self.assertEqual(
             1, self.marionette.execute_script("return arguments[0]", [1]))
         self.assertEqual(
             1.5, self.marionette.execute_script("return arguments[0]", [1.5]))
 
     def test_argument_boolean(self):
-        self.assertEqual(
-            True, self.marionette.execute_script("return arguments[0]", [True]))
+        self.assertTrue(self.marionette.execute_script("return arguments[0]", [True]))
 
     def test_argument_string(self):
         self.assertEqual(
             "foo", self.marionette.execute_script("return arguments[0]", ["foo"]))
 
     def test_argument_array(self):
         self.assertEqual(
             [1, 2], self.marionette.execute_script("return arguments[0]", [[1, 2]]))
 
     def test_argument_object(self):
         self.assertEqual({"foo": 1}, self.marionette.execute_script(
             "return arguments[0]", [{"foo": 1}]))
 
-    def assert_is_defined(self, property, sandbox="default"):
-        self.assertTrue(self.marionette.execute_script(
-            "return typeof {} != 'undefined'".format(property),
-            sandbox=sandbox),
-                        "property {} is undefined".format(property))
-
     def test_globals(self):
         for property in globals:
             self.assert_is_defined(property)
         self.assert_is_defined("Components")
         self.assert_is_defined("window.wrappedJSObject")
 
     def test_system_globals(self):
         for property in globals:
@@ -128,31 +127,30 @@ class TestExecuteContent(MarionetteTestC
         self.assert_is_defined("Components", sandbox="system")
         self.assert_is_defined("window.wrappedJSObject")
 
     def test_exception(self):
         self.assertRaises(errors.JavascriptException,
                           self.marionette.execute_script, "return foo")
 
     def test_stacktrace(self):
-        try:
+        with self.assertRaises(errors.JavascriptException) as cm:
             self.marionette.execute_script("return b")
-            self.assertFalse(True)
-        except errors.JavascriptException as e:
-            # by default execute_script pass the name of the python file
-            self.assertIn(
-                os.path.basename(__file__.replace(".pyc", ".py")), e.stacktrace)
-            self.assertIn("b is not defined", e.message)
-            self.assertIn("return b", e.stacktrace)
+
+        # by default execute_script pass the name of the python file
+        self.assertIn(os.path.basename(__file__.replace(".pyc", ".py")),
+                      cm.exception.stacktrace)
+        self.assertIn("b is not defined", cm.exception.message)
+        self.assertIn("return b", cm.exception.stacktrace)
 
     def test_permission(self):
         with self.assertRaises(errors.JavascriptException):
             self.marionette.execute_script("""
-                let prefs = Components.classes["@mozilla.org/preferences-service;1"]
-                    .getService(Components.interfaces.nsIPrefBranch)""")
+                var c = Components.classes["@mozilla.org/preferences-service;1"];
+            """)
 
     def test_return_web_element(self):
         self.marionette.navigate(elements)
         expected = self.marionette.find_element(By.TAG_NAME, "p")
         actual = self.marionette.execute_script(
             "return document.querySelector('p')")
         self.assertEqual(expected, actual)
 
@@ -186,25 +184,28 @@ class TestExecuteContent(MarionetteTestC
 
     def test_sandbox_refresh_arguments(self):
         self.marionette.execute_script(
             "this.foobar = [arguments[0], arguments[1]]", [23, 42])
         self.assertEqual(self.marionette.execute_script(
             "return this.foobar", new_sandbox=False), [23, 42])
 
     def test_wrappedjsobject(self):
-        self.marionette.execute_script("window.wrappedJSObject.foo = 3")
-        self.assertEqual(
-            3, self.marionette.execute_script("return window.wrappedJSObject.foo"))
+        try:
+            self.marionette.execute_script("window.wrappedJSObject.foo = 3")
+            self.assertEqual(
+                self.marionette.execute_script("return window.wrappedJSObject.foo"), 3)
+        finally:
+            self.marionette.execute_script("delete window.wrappedJSObject.foo")
 
     def test_system_sandbox_wrappedjsobject(self):
         self.marionette.execute_script(
             "window.wrappedJSObject.foo = 4", sandbox="system")
-        self.assertEqual(4, self.marionette.execute_script(
-            "return window.wrappedJSObject.foo", sandbox="system"))
+        self.assertEqual(self.marionette.execute_script(
+            "return window.wrappedJSObject.foo", sandbox="system"), 4)
 
     def test_system_dead_object(self):
         self.marionette.execute_script(
             "window.wrappedJSObject.foo = function() { return 'yo' }",
             sandbox="system")
         self.marionette.execute_script(
             "dump(window.wrappedJSObject.foo)", sandbox="system")
 
@@ -225,20 +226,19 @@ class TestExecuteContent(MarionetteTestC
 
         send("window.foo = 1")
         foo = send("return window.foo")
         self.assertEqual(1, foo)
 
         for property in globals:
             exists = send("return typeof {} != 'undefined'".format(property))
             self.assertTrue(exists, "property {} is undefined".format(property))
-        # TODO(ato): For some reason this fails, probably Sandbox bug?
-        # self.assertTrue(send("return typeof Components == 'undefined'"))
-        self.assertTrue(
-            send("return typeof window.wrappedJSObject == 'undefined'"))
+
+        self.assertTrue(send("return typeof Components.utils == 'undefined'"))
+        self.assertTrue(send("return typeof window.wrappedJSObject == 'undefined'"))
 
     def test_no_callback(self):
         self.assertTrue(self.marionette.execute_script(
             "return typeof arguments[0] == 'undefined'"))
 
     def test_window_set_timeout_is_not_cancelled(self):
         def content_timeout_triggered(mn):
             return mn.execute_script("return window.n", sandbox=None) > 0
@@ -265,54 +265,67 @@ class TestExecuteContent(MarionetteTestC
 
 class TestExecuteChrome(WindowManagerMixin, TestExecuteContent):
 
     def setUp(self):
         super(TestExecuteChrome, self).setUp()
 
         self.marionette.set_context("chrome")
 
+    def tearDown(self):
+        super(TestExecuteChrome, self).tearDown()
+
+    def test_permission(self):
+        self.assertEqual(1, self.marionette.execute_script("""
+            var c = Components.classes["@mozilla.org/preferences-service;1"]; return 1;"""))
+
+    @skip_if_mobile("New windows not supported in Fennec")
+    def test_unmarshal_element_collection(self):
+
         def open_window_with_js():
             self.marionette.execute_script(
                 "window.open('chrome://marionette/content/test.xul', 'xul', 'chrome');")
 
-        new_window = self.open_window(trigger=open_window_with_js)
-        self.marionette.switch_to_window(new_window)
-
-    def tearDown(self):
-        self.close_all_windows()
-        super(TestExecuteChrome, self).tearDown()
+        try:
+            win = self.open_window(trigger=open_window_with_js)
+            self.marionette.switch_to_window(win)
 
-    def test_permission(self):
-        self.assertEqual(1, self.marionette.execute_script(
-            "var c = Components.classes; return 1;"))
+            expected = self.marionette.find_elements(By.TAG_NAME, "textbox")
+            actual = self.marionette.execute_script(
+                "return document.querySelectorAll('textbox')")
+            self.assertEqual(expected, actual)
 
-    def test_unmarshal_element_collection(self):
-        expected = self.marionette.find_elements(By.TAG_NAME, "textbox")
-        actual = self.marionette.execute_script(
-            "return document.querySelectorAll('textbox')")
-        self.assertEqual(expected, actual)
+        finally:
+            self.close_all_windows()
 
     def test_async_script_timeout(self):
         with self.assertRaises(errors.ScriptTimeoutException):
             self.marionette.execute_async_script("""
                 var cb = arguments[arguments.length - 1];
                 setTimeout(function() { cb() }, 250);
                 """, script_timeout=100)
 
+    @skip_if_mobile("New windows not supported in Fennec")
     def test_invalid_chrome_handle(self):
-        # Close second chrome window and don't switch back to the original one
-        self.marionette.close_chrome_window()
-        self.assertEqual(len(self.marionette.chrome_window_handles), 1)
+        try:
+            win = self.open_window()
+            self.marionette.switch_to_window(win)
 
-        # Call execute_script on an invalid chrome handle
-        with self.marionette.using_context('chrome'):
-            self.marionette.execute_script("""
-                return true;
-            """)
+            # Close new window and don't switch back to the original one
+            self.marionette.close_chrome_window()
+            self.assertNotEqual(self.start_window, win)
+
+            # Call execute_script on an invalid chrome handle
+            with self.marionette.using_context('chrome'):
+                self.marionette.execute_script("""
+                    return true;
+                """)
+
+        finally:
+            self.close_all_windows()
 
     def test_lasting_side_effects(self):
         pass
 
     def test_return_web_element(self):
         pass
 
     def test_return_web_element_array(self):
@@ -321,16 +334,17 @@ class TestExecuteChrome(WindowManagerMix
     def test_return_web_element_nodelist(self):
         pass
 
     def test_window_set_timeout_is_not_cancelled(self):
         pass
 
 
 class TestElementCollections(MarionetteTestCase):
+
     def assertSequenceIsInstance(self, seq, typ):
         for item in seq:
             self.assertIsInstance(item, typ)
 
     def test_array(self):
         self.marionette.navigate(inline("<p>foo <p>bar"))
         els = self.marionette.execute_script("return Array.from(document.querySelectorAll('p'))")
         self.assertIsInstance(els, list)
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_prefs.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_prefs.py
@@ -71,18 +71,18 @@ class TestPreferences(MarionetteTestCase
         self.assertEqual(self.marionette.get_pref(pref_default, default_branch=True),
                          "default_value")
 
         self.marionette.clear_pref(pref_default)
         self.assertEqual(self.marionette.get_pref(pref_default), "default_value")
 
     def test_get_pref_value_type(self):
         # Without a given value type the properties URL will be returned only
-        pref_complex = "browser.startup.homepage"
-        properties_file = "chrome://branding/locale/browserconfig.properties"
+        pref_complex = "browser.menu.showCharacterEncoding"
+        properties_file = "chrome://browser/locale/browser.properties"
         self.assertEqual(self.marionette.get_pref(pref_complex, default_branch=True),
                          properties_file)
 
         # Otherwise the property named like the pref will be translated
         value = self.marionette.get_pref(pref_complex, default_branch=True,
                                          value_type="nsIPrefLocalizedString")
         self.assertNotEqual(value, properties_file)
 
new file mode 100644
--- /dev/null
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_window_close_chrome.py
@@ -0,0 +1,80 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from marionette_harness import MarionetteTestCase, WindowManagerMixin
+
+
+class TestCloseWindow(WindowManagerMixin, MarionetteTestCase):
+
+    def setUp(self):
+        super(TestCloseWindow, self).setUp()
+
+        self.marionette.set_context("chrome")
+
+    def tearDown(self):
+        self.close_all_windows()
+        self.close_all_tabs()
+
+        super(TestCloseWindow, self).tearDown()
+
+    def test_close_chrome_window_for_browser_window(self):
+        win = self.open_window()
+        self.marionette.switch_to_window(win)
+
+        self.assertNotIn(win, self.marionette.window_handles)
+        chrome_window_handles = self.marionette.close_chrome_window()
+        self.assertNotIn(win, chrome_window_handles)
+        self.assertListEqual(self.start_windows, chrome_window_handles)
+        self.assertNotIn(win, self.marionette.window_handles)
+
+    def test_close_chrome_window_for_non_browser_window(self):
+
+        def open_window_with_js():
+            self.marionette.execute_script("""
+              window.open('chrome://marionette/content/test.xul',
+                          'foo', 'chrome,centerscreen');
+            """)
+
+        win = self.open_window(trigger=open_window_with_js)
+        self.marionette.switch_to_window(win)
+
+        self.assertIn(win, self.marionette.window_handles)
+        chrome_window_handles = self.marionette.close_chrome_window()
+        self.assertNotIn(win, chrome_window_handles)
+        self.assertListEqual(self.start_windows, chrome_window_handles)
+        self.assertNotIn(win, self.marionette.window_handles)
+
+    def test_close_chrome_window_for_last_open_window(self):
+        self.close_all_windows()
+
+        self.assertListEqual([], self.marionette.close_chrome_window())
+        self.assertListEqual([self.start_tab], self.marionette.window_handles)
+        self.assertListEqual([self.start_window], self.marionette.chrome_window_handles)
+        self.assertIsNotNone(self.marionette.session)
+
+    def test_close_window_for_browser_tab(self):
+        tab = self.open_tab()
+        self.marionette.switch_to_window(tab)
+
+        window_handles = self.marionette.close()
+        self.assertNotIn(tab, window_handles)
+        self.assertListEqual(self.start_tabs, window_handles)
+
+    def test_close_window_for_browser_window_with_single_tab(self):
+        win = self.open_window()
+        self.marionette.switch_to_window(win)
+
+        self.assertEqual(len(self.start_tabs) + 1, len(self.marionette.window_handles))
+        window_handles = self.marionette.close()
+        self.assertNotIn(win, window_handles)
+        self.assertListEqual(self.start_tabs, window_handles)
+        self.assertListEqual(self.start_windows, self.marionette.chrome_window_handles)
+
+    def test_close_window_for_last_open_tab(self):
+        self.close_all_tabs()
+
+        self.assertListEqual([], self.marionette.close())
+        self.assertListEqual([self.start_tab], self.marionette.window_handles)
+        self.assertListEqual([self.start_window], self.marionette.chrome_window_handles)
+        self.assertIsNotNone(self.marionette.session)
new file mode 100644
--- /dev/null
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_window_close_content.py
@@ -0,0 +1,80 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from marionette_harness import MarionetteTestCase, skip_if_mobile, WindowManagerMixin
+
+
+class TestCloseWindow(WindowManagerMixin, MarionetteTestCase):
+
+    def tearDown(self):
+        self.close_all_windows()
+        self.close_all_tabs()
+
+        super(TestCloseWindow, self).tearDown()
+
+    @skip_if_mobile("Interacting with chrome windows not available for Fennec")
+    def test_close_chrome_window_for_browser_window(self):
+        win = self.open_window()
+        self.marionette.switch_to_window(win)
+
+        self.assertNotIn(win, self.marionette.window_handles)
+        chrome_window_handles = self.marionette.close_chrome_window()
+        self.assertNotIn(win, chrome_window_handles)
+        self.assertListEqual(self.start_windows, chrome_window_handles)
+        self.assertNotIn(win, self.marionette.window_handles)
+
+    @skip_if_mobile("Interacting with chrome windows not available for Fennec")
+    def test_close_chrome_window_for_non_browser_window(self):
+
+        def open_window_with_js():
+            with self.marionette.using_context("chrome"):
+                self.marionette.execute_script("""
+                  window.open('chrome://marionette/content/test.xul',
+                              'foo', 'chrome,centerscreen');
+                """)
+
+        win = self.open_window(trigger=open_window_with_js)
+        self.marionette.switch_to_window(win)
+
+        self.assertIn(win, self.marionette.window_handles)
+        chrome_window_handles = self.marionette.close_chrome_window()
+        self.assertNotIn(win, chrome_window_handles)
+        self.assertListEqual(self.start_windows, chrome_window_handles)
+        self.assertNotIn(win, self.marionette.window_handles)
+
+    @skip_if_mobile("Interacting with chrome windows not available for Fennec")
+    def test_close_chrome_window_for_last_open_window(self):
+        self.close_all_windows()
+
+        self.assertListEqual([], self.marionette.close_chrome_window())
+        self.assertListEqual([self.start_tab], self.marionette.window_handles)
+        self.assertListEqual([self.start_window], self.marionette.chrome_window_handles)
+        self.assertIsNotNone(self.marionette.session)
+
+    @skip_if_mobile("Needs application independent method to open a new tab")
+    def test_close_window_for_browser_tab(self):
+        tab = self.open_tab()
+        self.marionette.switch_to_window(tab)
+
+        window_handles = self.marionette.close()
+        self.assertNotIn(tab, window_handles)
+        self.assertListEqual(self.start_tabs, window_handles)
+
+    def test_close_window_for_browser_window_with_single_tab(self):
+        win = self.open_window()
+        self.marionette.switch_to_window(win)
+
+        self.assertEqual(len(self.start_tabs) + 1, len(self.marionette.window_handles))
+        window_handles = self.marionette.close()
+        self.assertNotIn(win, window_handles)
+        self.assertListEqual(self.start_tabs, window_handles)
+        self.assertListEqual(self.start_windows, self.marionette.chrome_window_handles)
+
+    def test_close_window_for_last_open_tab(self):
+        self.close_all_tabs()
+
+        self.assertListEqual([], self.marionette.close())
+        self.assertListEqual([self.start_tab], self.marionette.window_handles)
+        self.assertListEqual([self.start_window], self.marionette.chrome_window_handles)
+        self.assertIsNotNone(self.marionette.session)
--- a/testing/marionette/harness/marionette_harness/tests/unit/unit-tests.ini
+++ b/testing/marionette/harness/marionette_harness/tests/unit/unit-tests.ini
@@ -65,16 +65,19 @@ skip-if = appname == 'fennec'
 [test_pagesource_chrome.py]
 skip-if = appname == 'fennec'
 
 [test_visibility.py]
 [test_window_switching.py]
 skip-if = appname == 'fennec'
 [test_window_management.py]
 skip-if = appname == 'fennec'
+[test_window_close_chrome.py]
+skip-if = appname == 'fennec'
+[test_window_close_content.py]
 [test_window_position.py]
 skip-if = appname == 'fennec'
 [test_window_handles.py]
 skip-if = appname == 'fennec'
 
 [test_screenshot.py]
 [test_cookies.py]
 [test_window_title.py]
@@ -98,16 +101,17 @@ skip-if = true # Bug 925688
 skip-if = manage_instance == false || appname == 'fennec' # Bug 1298921 and bug 1322993
 [test_quit_restart.py]
 skip-if = manage_instance == false || appname == 'fennec' # Bug 1298921 and bug 1322993
 [test_set_window_size.py]
 skip-if = os == "linux" || appname == 'fennec' # Bug 1085717
 [test_with_using_context.py]
 
 [test_modal_dialogs.py]
+skip-if = appname == 'fennec' # Bug 1325738
 [test_key_actions.py]
 [test_mouse_action.py]
 skip-if = appname == 'fennec'
 [test_teardown_context_preserved.py]
 [test_file_upload.py]
 skip-if = appname == 'fennec' || os == "win" # http://bugs.python.org/issue14574
 
 [test_execute_sandboxes.py]
--- a/testing/mochitest/runtests.py
+++ b/testing/mochitest/runtests.py
@@ -46,17 +46,17 @@ from manifestparser.filters import (
     pathprefix,
     subsuite,
     tags,
 )
 
 try:
     from marionette_driver.addons import Addons
     from marionette_harness import Marionette
-except ImportError, e:
+except ImportError as e:
     # Defer ImportError until attempt to use Marionette
     def reraise(*args, **kwargs):
         raise(e)
     Marionette = reraise
 
 from leaks import ShutdownLeaks, LSANLeaks
 from mochitest_options import (
     MochitestArgumentParser, build_obj, get_default_valgrind_suppression_files
@@ -786,17 +786,17 @@ class MochitestDesktop(object):
         self.websocketProcessBridge = None
         self.sslTunnel = None
         self._active_tests = None
         self._locations = None
 
         self.marionette = None
         self.start_script = None
         self.mozLogs = None
-        self.start_script_args = []
+        self.start_script_kwargs = {}
         self.urlOpts = []
 
         if self.log is None:
             commandline.log_formatters["tbpl"] = (
                 MochitestFormatter,
                 "Mochitest specific tbpl formatter")
             self.log = commandline.setup_logging("mochitest",
                                                  logger_options,
@@ -845,17 +845,17 @@ class MochitestDesktop(object):
         return test_environment(**kwargs)
 
     def extraPrefs(self, extraPrefs):
         """interpolate extra preferences from option strings"""
 
         try:
             return dict(parseKeyValue(extraPrefs, context='--setpref='))
         except KeyValueParseError as e:
-            print str(e)
+            print(str(e))
             sys.exit(1)
 
     def getFullPath(self, path):
         " Get an absolute path relative to self.oldcwd."
         return os.path.normpath(
             os.path.join(
                 self.oldcwd,
                 os.path.expanduser(path)))
@@ -1009,18 +1009,21 @@ class MochitestDesktop(object):
             self.testRoot = options.flavor
 
             if options.flavor == 'browser' and options.immersiveMode:
                 self.testRoot = 'metro'
         else:
             self.testRoot = self.TEST_PATH
         self.testRootAbs = os.path.join(SCRIPT_DIR, self.testRoot)
 
-    def buildTestURL(self, options):
-        testHost = "http://mochi.test:8888"
+    def buildTestURL(self, options, scheme='http'):
+        if scheme == 'https':
+            testHost = "https://example.com:443"
+        else:
+            testHost = "http://mochi.test:8888"
         testURL = "/".join([testHost, self.TEST_PATH])
 
         if len(options.test_paths) == 1:
             if options.repeat > 0 and os.path.isfile(
                 os.path.join(
                     self.oldcwd,
                     os.path.dirname(__file__),
                     self.TEST_PATH,
@@ -1032,38 +1035,39 @@ class MochitestDesktop(object):
         if options.flavor in ('a11y', 'chrome'):
             testURL = "/".join([testHost, self.CHROME_PATH])
         elif options.flavor in ('browser', 'jetpack-addon', 'jetpack-package'):
             testURL = "about:blank"
         if options.nested_oop:
             testURL = "/".join([testHost, self.NESTED_OOP_TEST_PATH])
         return testURL
 
-    def buildTestPath(self, options, testsToFilter=None, disabled=True):
+    def getTestsByScheme(self, options, testsToFilter=None, disabled=True):
         """ Build the url path to the specific test harness and test file or directory
             Build a manifest of tests to run and write out a json file for the harness to read
             testsToFilter option is used to filter/keep the tests provided in the list
 
             disabled -- This allows to add all disabled tests on the build side
                         and then on the run side to only run the enabled ones
         """
 
         tests = self.getActiveTests(options, disabled)
         paths = []
         for test in tests:
             if testsToFilter and (test['path'] not in testsToFilter):
                 continue
             paths.append(test)
 
-        # Bug 883865 - add this functionality into manifestparser
-        with open(os.path.join(SCRIPT_DIR, options.testRunManifestFile), 'w') as manifestFile:
-            manifestFile.write(json.dumps({'tests': paths}))
-        options.manifestFile = options.testRunManifestFile
-
-        return self.buildTestURL(options)
+        # Generate test by schemes
+        for (scheme, grouped_tests) in self.groupTestsByScheme(paths).items():
+            # Bug 883865 - add this functionality into manifestparser
+            with open(os.path.join(SCRIPT_DIR, options.testRunManifestFile), 'w') as manifestFile:
+                manifestFile.write(json.dumps({'tests': grouped_tests}))
+            options.manifestFile = options.testRunManifestFile
+            yield (scheme, grouped_tests)
 
     def startWebSocketServer(self, options, debuggerInfo):
         """ Launch the websocket server """
         self.wsserver = WebSocketServer(
             options,
             SCRIPT_DIR,
             self.log,
             debuggerInfo)
@@ -1384,16 +1388,18 @@ toolbar#nav-bar {
                     (test['name'], test['manifest']))
                 continue
 
             testob = {'path': tp}
             if 'disabled' in test:
                 testob['disabled'] = test['disabled']
             if 'expected' in test:
                 testob['expected'] = test['expected']
+            if 'scheme' in test:
+                testob['scheme'] = test['scheme']
             paths.append(testob)
 
         def path_sort(ob1, ob2):
             path1 = ob1['path'].split('/')
             path2 = ob2['path'].split('/')
             return cmp(path1, path2)
 
         paths.sort(path_sort)
@@ -1557,17 +1563,17 @@ toolbar#nav-bar {
 
         if os.path.isfile(self.start_script):
             with open(self.start_script, 'r') as fh:
                 script = fh.read()
         else:
             script = self.start_script
 
         with self.marionette.using_context('chrome'):
-            return self.marionette.execute_script(script, script_args=self.start_script_args)
+            return self.marionette.execute_script(script, script_args=(self.start_script_kwargs, ))
 
     def fillCertificateDB(self, options):
         # TODO: move -> mozprofile:
         # https://bugzilla.mozilla.org/show_bug.cgi?id=746243#c35
 
         pwfilePath = os.path.join(options.profilePath, ".crtdbpw")
         with open(pwfilePath, "w") as pwfile:
             pwfile.write("\n")
@@ -1934,17 +1940,17 @@ toolbar#nav-bar {
 
             # build command line
             cmd = os.path.abspath(app)
             args = list(extraArgs)
             args.append('-marionette')
             # TODO: mozrunner should use -foreground at least for mac
             # https://bugzilla.mozilla.org/show_bug.cgi?id=916512
             args.append('-foreground')
-            self.start_script_args.append(testUrl or 'about:blank')
+            self.start_script_kwargs['testUrl'] = testUrl or 'about:blank'
 
             if detectShutdownLeaks and not self.disable_leak_checking:
                 shutdownLeaks = ShutdownLeaks(self.log)
             else:
                 shutdownLeaks = None
 
             if mozinfo.info["asan"] and (mozinfo.isLinux or mozinfo.isMac) \
                     and not self.disable_leak_checking:
@@ -1998,17 +2004,17 @@ toolbar#nav-bar {
                          interactive=interactive,
                          outputTimeout=timeout)
             proc = runner.process_handler
             self.log.info("runtests.py | Application pid: %d" % proc.pid)
             self.log.process_start("Main app process")
 
             # start marionette and kick off the tests
             marionette_args = marionette_args or {}
-            port_timeout = marionette_args.pop('port_timeout')
+            port_timeout = marionette_args.pop('port_timeout', 60)
             self.marionette = Marionette(**marionette_args)
             self.marionette.start_session(timeout=port_timeout)
 
             # install specialpowers and mochikit as temporary addons
             addons = Addons(self.marionette)
 
             if mozinfo.info.get('toolkit') != 'gonk':
                 addons.install(os.path.join(here, 'extensions', 'specialpowers'), temp=True)
@@ -2164,16 +2170,30 @@ toolbar#nav-bar {
         # We need to print the summary only if options.bisectChunk has a value.
         # Also we need to make sure that we do not print the summary in between
         # running tests via --run-by-dir.
         if options.bisectChunk and options.bisectChunk in self.result:
             bisect.print_summary()
 
         return result
 
+    def groupTestsByScheme(self, tests):
+        """
+        split tests into groups by schemes. test is classified as http if
+        no scheme specified
+        """
+        httpTests = []
+        httpsTests = []
+        for test in tests:
+            if not test.get('scheme') or test.get('scheme') == 'http':
+                httpTests.append(test)
+            elif test.get('scheme') == 'https':
+                httpsTests.append(test)
+        return {'http': httpTests, 'https': httpsTests}
+
     def runTests(self, options):
         """ Prepare, configure, run tests and cleanup """
 
         # a11y and chrome tests don't run with e10s enabled in CI. Need to set
         # this here since |mach mochitest| sets the flavor after argument parsing.
         if options.flavor in ('a11y', 'chrome'):
             options.e10s = False
         mozinfo.update({"e10s": options.e10s})  # for test manifest parsing.
@@ -2198,17 +2218,17 @@ toolbar#nav-bar {
         if not options.runByDir:
             return self.runMochitests(options, testsToRun)
 
         # code for --run-by-dir
         dirs = self.getDirectories(options)
 
         result = 1  # default value, if no tests are run.
         for d in dirs:
-            print "dir: %s" % d
+            print("dir: %s" % d)
 
             # BEGIN LEAKCHECK HACK
             # Leak checking was broken in mochitest unnoticed for a length of time. During
             # this time, several leaks slipped through. The leak checking was fixed by bug
             # 1325148, but it couldn't land until all the regressions were also fixed or
             # backed out. Rather than waiting and risking new regressions, in the meantime
             # this code will selectively disable leak checking on flavors/directories where
             # known regressions exist. At least this way we can prevent further damage while
@@ -2242,30 +2262,30 @@ toolbar#nav-bar {
 
             if result == -1:
                 break
 
         e10s_mode = "e10s" if options.e10s else "non-e10s"
 
         # printing total number of tests
         if options.flavor == 'browser':
-            print "TEST-INFO | checking window state"
-            print "Browser Chrome Test Summary"
-            print "\tPassed: %s" % self.countpass
-            print "\tFailed: %s" % self.countfail
-            print "\tTodo: %s" % self.counttodo
-            print "\tMode: %s" % e10s_mode
-            print "*** End BrowserChrome Test Results ***"
+            print("TEST-INFO | checking window state")
+            print("Browser Chrome Test Summary")
+            print("\tPassed: %s" % self.countpass)
+            print("\tFailed: %s" % self.countfail)
+            print("\tTodo: %s" % self.counttodo)
+            print("\tMode: %s" % e10s_mode)
+            print("*** End BrowserChrome Test Results ***")
         else:
-            print "0 INFO TEST-START | Shutdown"
-            print "1 INFO Passed:  %s" % self.countpass
-            print "2 INFO Failed:  %s" % self.countfail
-            print "3 INFO Todo:    %s" % self.counttodo
-            print "4 INFO Mode:    %s" % e10s_mode
-            print "5 INFO SimpleTest FINISHED"
+            print("0 INFO TEST-START | Shutdown")
+            print("1 INFO Passed:  %s" % self.countpass)
+            print("2 INFO Failed:  %s" % self.countfail)
+            print("3 INFO Todo:    %s" % self.counttodo)
+            print("4 INFO Mode:    %s" % e10s_mode)
+            print("5 INFO SimpleTest FINISHED")
 
         return result
 
     def doTests(self, options, testsToFilter=None):
         # A call to initializeLooping method is required in case of --run-by-dir or --bisect-chunk
         # since we need to initialize variables for each loop.
         if options.bisectChunk or options.runByDir:
             self.initializeLooping(options)
@@ -2334,38 +2354,16 @@ toolbar#nav-bar {
 
         if self.mozLogs:
             self.browserEnv["MOZ_LOG_FILE"] = "{}/moz-pid=%PID-uid={}.log".format(
                 self.browserEnv["MOZ_UPLOAD_DIR"], str(uuid.uuid4()))
 
         try:
             self.startServers(options, debuggerInfo)
 
-            # testsToFilter parameter is used to filter out the test list that
-            # is sent to buildTestPath
-            testURL = self.buildTestPath(options, testsToFilter)
-
-            # read the number of tests here, if we are not going to run any,
-            # terminate early
-            if os.path.exists(
-                os.path.join(
-                    SCRIPT_DIR,
-                    options.testRunManifestFile)):
-                with open(os.path.join(SCRIPT_DIR, options.testRunManifestFile)) as fHandle:
-                    tests = json.load(fHandle)
-                count = 0
-                for test in tests['tests']:
-                    count += 1
-                if count == 0:
-                    return 1
-
-            self.buildURLOptions(options, self.browserEnv)
-            if self.urlOpts:
-                testURL += "?" + "&".join(self.urlOpts)
-
             if options.immersiveMode:
                 options.browserArgs.extend(('-firefoxpath', options.app))
                 options.app = self.immersiveHelperPath
 
             if options.jsdebugger:
                 options.browserArgs.extend(['-jsdebugger'])
 
             # Remove the leak detection file so it can't "leak" to the tests run.
@@ -2384,47 +2382,61 @@ toolbar#nav-bar {
 
             # Detect shutdown leaks for m-bc runs if
             # code coverage is not enabled.
             detectShutdownLeaks = False
             if options.jscov_dir_prefix is None:
                 detectShutdownLeaks = mozinfo.info[
                     "debug"] and options.flavor == 'browser'
 
-            self.start_script_args.append(self.normflavor(options.flavor))
+            self.start_script_kwargs['flavor'] = self.normflavor(options.flavor)
             marionette_args = {
                 'symbols_path': options.symbolsPath,
                 'socket_timeout': options.marionette_socket_timeout,
                 'port_timeout': options.marionette_port_timeout,
             }
 
             if options.marionette:
                 host, port = options.marionette.split(':')
                 marionette_args['host'] = host
                 marionette_args['port'] = int(port)
 
-            self.log.info("runtests.py | Running with e10s: {}".format(options.e10s))
-            self.log.info("runtests.py | Running tests: start.\n")
-            status = self.runApp(testURL,
-                                 self.browserEnv,
-                                 options.app,
-                                 profile=self.profile,
-                                 extraArgs=options.browserArgs,
-                                 utilityPath=options.utilityPath,
-                                 debuggerInfo=debuggerInfo,
-                                 valgrindPath=valgrindPath,
-                                 valgrindArgs=valgrindArgs,
-                                 valgrindSuppFiles=valgrindSuppFiles,
-                                 symbolsPath=options.symbolsPath,
-                                 timeout=timeout,
-                                 detectShutdownLeaks=detectShutdownLeaks,
-                                 screenshotOnFail=options.screenshotOnFail,
-                                 bisectChunk=options.bisectChunk,
-                                 marionette_args=marionette_args,
-                                 )
+            # testsToFilter parameter is used to filter out the test list that
+            # is sent to getTestsByScheme
+            for (scheme, tests) in self.getTestsByScheme(options, testsToFilter):
+                # read the number of tests here, if we are not going to run any,
+                # terminate early
+                if not tests:
+                    continue
+
+                testURL = self.buildTestURL(options, scheme=scheme)
+
+                self.buildURLOptions(options, self.browserEnv)
+                if self.urlOpts:
+                    testURL += "?" + "&".join(self.urlOpts)
+
+                self.log.info("runtests.py | Running with e10s: {}".format(options.e10s))
+                self.log.info("runtests.py | Running tests: start.\n")
+                status = self.runApp(testURL,
+                                     self.browserEnv,
+                                     options.app,
+                                     profile=self.profile,
+                                     extraArgs=options.browserArgs,
+                                     utilityPath=options.utilityPath,
+                                     debuggerInfo=debuggerInfo,
+                                     valgrindPath=valgrindPath,
+                                     valgrindArgs=valgrindArgs,
+                                     valgrindSuppFiles=valgrindSuppFiles,
+                                     symbolsPath=options.symbolsPath,
+                                     timeout=timeout,
+                                     detectShutdownLeaks=detectShutdownLeaks,
+                                     screenshotOnFail=options.screenshotOnFail,
+                                     bisectChunk=options.bisectChunk,
+                                     marionette_args=marionette_args,
+                                     )
         except KeyboardInterrupt:
             self.log.info("runtests.py | Received keyboard interrupt.\n")
             status = -1
         except:
             traceback.print_exc()
             self.log.error(
                 "Automation Error: Received unexpected exception while running application\n")
             status = 1
--- a/testing/mochitest/start_desktop.js
+++ b/testing/mochitest/start_desktop.js
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-const flavor  = __webDriverArguments[0]
-const url = __webDriverArguments[1]
+const flavor  = __webDriverArguments[0]["flavor"];
+const url = __webDriverArguments[0]["testUrl"];
 
 let wm = Cc["@mozilla.org/appshell/window-mediator;1"]
           .getService(Ci.nsIWindowMediator);
 let win = wm.getMostRecentWindow("navigator:browser");
 
 // mochikit's bootstrap.js has set up a listener for this event. It's
 // used so bootstrap.js knows which flavor and url to load.
 let ev = new CustomEvent('mochitest-load', {'detail': [flavor, url]});
--- a/testing/mochitest/tests/SimpleTest/setup.js
+++ b/testing/mochitest/tests/SimpleTest/setup.js
@@ -155,17 +155,17 @@ TestRunner.logger.addListener("dumpListe
 
 var gTestList = [];
 var RunSet = {};
 RunSet.runall = function(e) {
   // Filter tests to include|exclude tests based on data in params.filter.
   // This allows for including or excluding tests from the gTestList
   // TODO Only used by ipc tests, remove once those are implemented sanely
   if (params.testManifest) {
-    getTestManifest("http://mochi.test:8888/" + params.testManifest, params, function(filter) { gTestList = filterTests(filter, gTestList, params.runOnly); RunSet.runtests(); });
+    getTestManifest(getTestManifestURL(params.testManifest), params, function(filter) { gTestList = filterTests(filter, gTestList, params.runOnly); RunSet.runtests(); });
   } else {
     RunSet.runtests();
   }
 }
 
 RunSet.runtests = function(e) {
   // Which tests we're going to run
   var my_tests = gTestList;
@@ -230,17 +230,17 @@ function toggleNonTests (e) {
   } else {
     $("toggleNonTests").innerHTML = "Show Non-Tests";
   }
 }
 
 // hook up our buttons
 function hookup() {
   if (params.manifestFile) {
-    getTestManifest("http://mochi.test:8888/" + params.manifestFile, params, hookupTests);
+    getTestManifest(getTestManifestURL(params.manifestFile), params, hookupTests);
   } else {
     hookupTests(gTestList);
   }
 }
 
 function hookupTests(testList) {
   if (testList.length > 0) {
     gTestList = testList;
@@ -253,8 +253,18 @@ function hookupTests(testList) {
 
   document.getElementById('runtests').onclick = RunSet.reloadAndRunAll;
   document.getElementById('toggleNonTests').onclick = toggleNonTests;
   // run automatically if autorun specified
   if (params.autorun) {
     RunSet.runall();
   }
 }
+
+function getTestManifestURL(path) {
+  // The test manifest url scheme should be the same protocol as the containing
+  // window... unless it's not http(s)
+  if (window.location.protocol == "http:" ||
+      window.location.protocol == "https:") {
+    return window.location.protocol + "//" + window.location.host + "/" + path;
+  }
+  return "http://mochi.test:8888/" + path;
+}
--- a/testing/mozharness/scripts/mobile_l10n.py
+++ b/testing/mozharness/scripts/mobile_l10n.py
@@ -5,17 +5,16 @@
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 # ***** END LICENSE BLOCK *****
 """mobile_l10n.py
 
 This currently supports nightly and release single locale repacks for
 Android.  This also creates nightly updates.
 """
 
-from copy import deepcopy
 import glob
 import os
 import re
 import subprocess
 import sys
 import time
 import shlex
 
@@ -246,28 +245,61 @@ class MobileSingleLocale(MockMixin, Loca
         output = self._query_make_ident_output()
         for line in output.splitlines():
             m = r.match(line)
             if m:
                 self.buildid = m.groups()[0]
         return self.buildid
 
     def query_revision(self):
-        """Get revision from the objdir.
-        Only valid after setup is run.
+        """ Get the gecko revision in this order of precedence
+              * cached value
+              * command line arg --revision   (development, taskcluster)
+              * buildbot properties           (try with buildbot forced build)
+              * buildbot change               (try with buildbot scheduler)
+              * from the en-US build          (m-c & m-a)
+
+        This will fail the last case if the build hasn't been pulled yet.
         """
         if self.revision:
             return self.revision
-        r = re.compile(r"gecko_revision ([0-9a-f]+\+?)")
+
+        self.read_buildbot_config()
+        config = self.config
+        revision = None
+        if config.get("revision"):
+            revision = config["revision"]
+        elif 'revision' in self.buildbot_properties:
+            revision = self.buildbot_properties['revision']
+        elif (self.buildbot_config and
+                  self.buildbot_config.get('sourcestamp', {}).get('revision')):
+            revision = self.buildbot_config['sourcestamp']['revision']
+        elif self.buildbot_config and self.buildbot_config.get('revision'):
+            revision = self.buildbot_config['revision']
+        elif config.get("update_gecko_source_to_enUS", True):
+            revision = self._query_enUS_revision()
+
+        if not revision:
+            self.fatal("Can't determine revision!")
+        self.revision = str(revision)
+        return self.revision
+
+    def _query_enUS_revision(self):
+        """Get revision from the objdir.
+        Only valid after setup is run.
+       """
+        if self.enUS_revision:
+            return self.enUS_revision
+        r = re.compile(r"^gecko_revision ([0-9a-f]+\+?)$")
         output = self._query_make_ident_output()
         for line in output.splitlines():
-            m = r.match(line)
-            if m:
-                self.revision = m.groups()[0]
-        return self.revision
+            match = r.match(line)
+            if match:
+                self.enUS_revision = match.groups()[0]
+        return self.enUS_revision
 
     def _query_make_variable(self, variable, make_args=None):
         make = self.query_exe('make')
         env = self.query_repack_env()
         dirs = self.query_abs_dirs()
         if make_args is None:
             make_args = []
         # TODO error checking
@@ -359,22 +391,33 @@ class MobileSingleLocale(MockMixin, Loca
 
     def pull(self):
         c = self.config
         dirs = self.query_abs_dirs()
         repos = []
         replace_dict = {}
         if c.get("user_repo_override"):
             replace_dict['user_repo_override'] = c['user_repo_override']
-            # deepcopy() needed because of self.config lock bug :(
-            for repo_dict in deepcopy(c['repos']):
-                repo_dict['repo'] = repo_dict['repo'] % replace_dict
-                repos.append(repo_dict)
-        else:
-            repos = c['repos']
+        # this is OK so early because we get it from buildbot, or
+        # the command line for local dev
+        replace_dict['revision'] = self.query_revision()
+
+        for repository in c['repos']:
+            current_repo = {}
+            for key, value in repository.iteritems():
+                try:
+                    current_repo[key] = value % replace_dict
+                except TypeError:
+                    # pass through non-interpolables, like booleans
+                    current_repo[key] = value
+                except KeyError:
+                    self.error('not all the values in "{0}" can be replaced. Check your configuration'.format(value))
+                    raise
+            repos.append(current_repo)
+        self.info("repositories: %s" % repos)
         self.vcs_checkout_repos(repos, parent_dir=dirs['abs_work_dir'],
                                 tag_override=c.get('tag_override'))
 
     def clone_locales(self):
         self.pull_locale_source()
 
     # list_locales() is defined in LocalesMixin.
 
@@ -432,17 +475,17 @@ class MobileSingleLocale(MockMixin, Loca
                            cwd=dirs['abs_locales_dir'],
                            env=env,
                            error_list=MakefileErrorList,
                            halt_on_failure=True)
 
         # on try we want the source we already have, otherwise update to the
         # same as the en-US binary
         if self.config.get("update_gecko_source_to_enUS", True):
-            revision = self.query_revision()
+            revision = self.query_enUS_revision()
             if not revision:
                 self.fatal("Can't determine revision!")
             hg = self.query_exe("hg")
             # TODO do this through VCSMixin instead of hardcoding hg
             self.run_command_m([hg, "update", "-r", revision],
                                cwd=dirs["abs_mozilla_dir"],
                                env=env,
                                error_list=BaseErrorList,
--- a/third_party/rust/bitreader/.cargo-checksum.json
+++ b/third_party/rust/bitreader/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"f9b1ca6ae27d1c18215265024629a8960c31379f206d9ed20f64e0b2dcf79805","Cargo.toml":"958f2305ab8afcf59f3eeef619f95e511ee2721654417784bbec5ef135fe608b","LICENSE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","README.md":"dc19fd728ea91808d5f4109b9343f6a6bfb931f20a3094f4d5d77f9343b09579","src/lib.rs":"343e09a0e40a7d88e69e346bcc0816260e91abafbc9fe854b3aae16305cb717e","src/tests.rs":"bf0d60d6b70f79eb36a394ba51eae7c36e185778f31ef9bfba12399ec60b6e75"},"package":"b245039eddbd1a051b8bfa5d5b6afaad6d34d172057a15d561e80b50b4978e8d"}
\ No newline at end of file
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"f9b1ca6ae27d1c18215265024629a8960c31379f206d9ed20f64e0b2dcf79805",".travis.yml":"f79c29325421aef57d8191a6a19450b62a431a78a6a5be39f5e8ec259316cdac","Cargo.toml":"672e17bc43e09796c9af69270ab47db16b77da461176ca8692ac211f6b7c09f5","LICENSE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","README.md":"979a08488d27db4ea70e4db255ea759d7f4c4c0b65b53e32bd3743117538d20b","src/lib.rs":"62b815c44f50074bc199b6abe9ef2728c3e5dad9539ebe9107b3d818c32c453f","src/tests.rs":"e90f5e1ccbc4c41c42cb3ad0f88aee26b1e08e953b7979a4ddbe0a0826ddbad4"},"package":"8319aa6588c40cce19a135009ec70dc730a34ed9d27bab2409298b948546da7a"}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/third_party/rust/bitreader/.travis.yml
@@ -0,0 +1,4 @@
+language: rust
+rust:
+  - stable
+  - nightly
--- a/third_party/rust/bitreader/Cargo.toml
+++ b/third_party/rust/bitreader/Cargo.toml
@@ -1,18 +1,19 @@
 [package]
 name = "bitreader"
-version = "0.1.0"
+version = "0.2.0"
 authors = ["Ilkka Rauta <ilkka.rauta@gmail.com>"]
 
 description = """
 BitReader helps reading individual bits from a slice of bytes.
 
 You can read "unusual" numbers of bits from the byte slice, for example 13 bits
 at once. The reader internally keeps track of position within the buffer.
 """
 
+documentation = "https://docs.rs/bitreader"
 homepage = "https://github.com/irauta/bitreader"
 repository = "https://github.com/irauta/bitreader"
 
 keywords = ["bit", "bits", "bitstream"]
 
 license = "Apache-2.0"
--- a/third_party/rust/bitreader/README.md
+++ b/third_party/rust/bitreader/README.md
@@ -1,19 +1,23 @@
 # BitReader
 
 BitReader is a helper type to extract strings of bits from a slice of bytes.
 
+[![Published Package](https://img.shields.io/crates/v/bitreader.svg)](https://crates.io/crates/bitreader)
+[![Documentation](https://docs.rs/bitreader/badge.svg)](https://docs.rs/bitreader)
+[![Build Status](https://travis-ci.org/irauta/bitreader.svg)](https://travis-ci.org/irauta/bitreader)
+
 Here is how you read first a single bit, then three bits and finally four bits from a byte buffer:
 
     use bitreader::BitReader;
 
     let slice_of_u8 = &[0b1000_1111];
     let mut reader = BitReader::new(slice_of_u8);
 
     // You obviously should use try! or some other error handling mechanism here
     let a_single_bit = reader.read_u8(1).unwrap(); // 1
     let more_bits = reader.read_u8(3).unwrap(); // 0
     let last_bits_of_byte = reader.read_u8(4).unwrap(); // 0b1111
 
 You can naturally read bits from longer buffer of data than just a single byte.
 
-As you read bits, the internal cursor of BitReader moves on along the stream of bits. Little endian format is assumed when reading the multi-byte values. BitReader supports reading maximum of 64 bits at a time (with read_u64). Reading signed values directly is not supported at the moment.
+As you read bits, the internal cursor of BitReader moves on along the stream of bits. Little endian format is assumed when reading the multi-byte values. BitReader supports reading maximum of 64 bits at a time (with read_u64).
--- a/third_party/rust/bitreader/src/lib.rs
+++ b/third_party/rust/bitreader/src/lib.rs
@@ -156,16 +156,25 @@ impl<'a> BitReader<'a> {
 
     /// Read at most 64 bits into a i64.
     /// Assumes the bits are stored in two's complement format.
     pub fn read_i64(&mut self, bit_count: u8) -> Result<i64> {
         let value = try!(self.read_signed_value(bit_count, 64));
         Ok(value)
     }
 
+    /// Read a single bit as a boolean value.
+    /// Interprets 1 as true and 0 as false.
+    pub fn read_bool(&mut self) -> Result<bool> {
+        match try!(self.read_value(1, 1)) {
+            0 => Ok(false),
+            _ => Ok(true),
+        }
+    }
+
     /// Skip arbitrary number of bits. However, you can skip at most to the end of the byte slice.
     pub fn skip(&mut self, bit_count: u64) -> Result<()> {
         let end_position = self.position + bit_count;
         if end_position > self.bytes.len() as u64 * 8 {
             return Err(BitReaderError::NotEnoughData {
                 position: self.position,
                 length: (self.bytes.len() * 8) as u64,
                 requested: bit_count,
@@ -278,34 +287,38 @@ impl fmt::Display for BitReaderError {
         }
     }
 }
 
 /// Helper trait to allow reading bits into a variable without explicitly mentioning its type.
 ///
 /// If you can't or want, for some reason, to use BitReader's read methods (`read_u8` etc.) but
 /// want to rely on type inference instead, you can use the ReadInto trait. The trait is
-/// implemented for all basic integer types (8/16/32/64 bits, signed/unsigned).
+/// implemented for all basic integer types (8/16/32/64 bits, signed/unsigned)
+/// and the boolean type.
 ///
 /// ```
 /// use bitreader::{BitReader,ReadInto};
 ///
-/// let slice_of_u8 = &[0b1100_0000];
+/// let slice_of_u8 = &[0b1110_0000];
 /// let mut reader = BitReader::new(slice_of_u8);
 ///
 /// struct Foo {
-///     bar: u8
+///     bar: u8,
+///     valid: bool,
 /// }
 ///
 /// // No type mentioned here, instead the type of bits is inferred from the type of Foo::bar,
 /// // and consequently the correct "overload" is used.
 /// let bits = ReadInto::read(&mut reader, 2).unwrap();
+/// let valid = ReadInto::read(&mut reader, 1).unwrap();
 ///
-/// let foo = Foo { bar: bits };
-/// assert_eq!(foo.bar, 3)
+/// let foo = Foo { bar: bits, valid: valid };
+/// assert_eq!(foo.bar, 3);
+/// assert!(foo.valid);
 /// ```
 pub trait ReadInto
     where Self: Sized
 {
     fn read(reader: &mut BitReader, bits: u8) -> Result<Self>;
 }
 
 // There's eight almost identical implementations, let's make this easier.
@@ -323,8 +336,18 @@ impl_read_into!(u8, read_u8);
 impl_read_into!(u16, read_u16);
 impl_read_into!(u32, read_u32);
 impl_read_into!(u64, read_u64);
 
 impl_read_into!(i8, read_i8);
 impl_read_into!(i16, read_i16);
 impl_read_into!(i32, read_i32);
 impl_read_into!(i64, read_i64);
+
+// We can't cast to bool, so this requires a separate method.
+impl ReadInto for bool {
+    fn read(reader: &mut BitReader, bits: u8) -> Result<Self> {
+        match try!(reader.read_u8(bits)) {
+            0 => Ok(false),
+            _ => Ok(true),
+        }
+    }
+}
--- a/third_party/rust/bitreader/src/tests.rs
+++ b/third_party/rust/bitreader/src/tests.rs
@@ -36,17 +36,17 @@ fn read_buffer() {
     assert_eq!(reader.read_u8(3).unwrap(), 0b100);
 
     assert!(reader.is_aligned(1));
 
     assert_eq!(reader.read_u32(32).unwrap(), 0b1001_1001_1001_1001_1001_1001_1001_1001);
 
     assert_eq!(reader.read_u8(4).unwrap(), 0b1110);
     assert_eq!(reader.read_u8(3).unwrap(), 0b011);
-    assert_eq!(reader.read_u8(1).unwrap(), 0b1);
+    assert_eq!(reader.read_bool().unwrap(), true);
 
     // Could also be 8 at this point!
     assert!(reader.is_aligned(4));
 }
 
 #[test]
 fn try_all_sizes() {
     let bytes = &[
@@ -78,28 +78,32 @@ fn try_all_sizes() {
     for byte in bytes {
         assert_eq!(reader.read_u8(8).unwrap(), *byte);
     }
 }
 
 #[test]
 fn skipping_and_zero_reads() {
     let bytes = &[
-        0b1011_0101, 0b1110_1010, 0b1010_1100,
+        0b1011_0101, 0b1110_1010, 0b1010_1100, 0b0011_0101,
     ];
 
     let mut reader = BitReader::new(bytes);
 
     assert_eq!(reader.read_u8(4).unwrap(), 0b1011);
     // Reading zero bits should be a no-op
     assert_eq!(reader.read_u8(0).unwrap(), 0b0);
     assert_eq!(reader.read_u8(4).unwrap(), 0b0101);
     reader.skip(3).unwrap(); // 0b111
     assert_eq!(reader.read_u16(10).unwrap(), 0b0101010101);
     assert_eq!(reader.read_u8(3).unwrap(), 0b100);
+    reader.skip(4).unwrap(); // 0b0011
+    assert_eq!(reader.read_u32(2).unwrap(), 0b01);
+    assert_eq!(reader.read_bool().unwrap(), false);
+    assert_eq!(reader.read_bool().unwrap(), true);
 }
 
 #[test]
 fn errors() {
     let bytes = &[
         0b1011_0101, 0b1110_1010, 0b1010_1100,
     ];
 
@@ -133,8 +137,22 @@ fn signed_values() {
             (x >> 8) as u8,
             x as u8,
         ];
         let mut reader = BitReader::new(bytes);
         assert_eq!(reader.read_u8(4).unwrap(), if x < 0 { 0b1111 } else { 0 });
         assert_eq!(reader.read_i16(12).unwrap(), x);
     }
 }
+
+#[test]
+fn boolean_values() {
+    let bytes: Vec<u8> = (0..16).collect();
+    let mut reader = BitReader::new(&bytes);
+    for v in &bytes {
+        assert_eq!(reader.read_bool().unwrap(), false);
+        reader.skip(3).unwrap();
+        assert_eq!(reader.read_bool().unwrap(), v & 0x08 == 8);
+        assert_eq!(reader.read_bool().unwrap(), v & 0x04 == 4);
+        assert_eq!(reader.read_bool().unwrap(), v & 0x02 == 2);
+        assert_eq!(reader.read_bool().unwrap(), v & 0x01 == 1);
+    }
+}
--- a/third_party/rust/byteorder/.cargo-checksum.json
+++ b/third_party/rust/byteorder/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"2879af3c0512f976015d532e2d768f04ff22fdcf8745b69b955b78fda321c3fb",".travis.yml":"81545ce3c6c72111a68434464c3f9fa8df9cbe39759a081fac527628ab21ae0c","COPYING":"01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f","Cargo.toml":"a7282931b50dff2e463f82baaed95a9d76636bc0fef3e921acd8ca69eab32b83","LICENSE-MIT":"0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f","Makefile":"a45a128685a2ae7d4fa39d310786674417ee113055ef290a11f88002285865fc","README.md":"fbcc46b6d0a585096737f50922818b59016b69d959b05f1b29863b2af8e4da43","UNLICENSE":"7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c","benches/bench.rs":"f583692d829c8dfe19b1d5b9e968ccf5c74d6733367ca183edff74041a6afedd","session.vim":"95cb1d7caf0ff7fbe76ec911988d908ddd883381c925ba64b537695bc9f021c4","src/lib.rs":"ef9e7a218fa3a4912c47f6840d32b975940d98277b6c9be85e8d7d045552eb87","src/new.rs":"161c21b7ebb5668c7cc70b46b0eb37709e06bb9c854f2fdfc6ce3d3babcbf3de"},"package":"0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855"}
\ No newline at end of file
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"2879af3c0512f976015d532e2d768f04ff22fdcf8745b69b955b78fda321c3fb",".travis.yml":"c8243fb884ca390f5a7b8cc45e1c0d5bbbdd7e4e82ada2dc1880b3a904c9ce12","COPYING":"01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f","Cargo.toml":"b6cd79e1f2a93cd8a5c6e6dd7985c46fc26e442ae5b8ed4a0ff37a4ad4708023","LICENSE-MIT":"0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f","README.md":"0559514b9d7488e96fb7a2f3c043a62fadf3495a1e10602d109ce79ee67da998","UNLICENSE":"7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c","benches/bench.rs":"f583692d829c8dfe19b1d5b9e968ccf5c74d6733367ca183edff74041a6afedd","src/lib.rs":"b038b8a84b2b7b2143b2835185b3cbbacaf056fa8a2f03bec84bfd79c913c726","src/new.rs":"161c21b7ebb5668c7cc70b46b0eb37709e06bb9c854f2fdfc6ce3d3babcbf3de"},"package":"c40977b0ee6b9885c9013cd41d9feffdd22deb3bb4dc3a71d901cc7a77de18c8"}
\ No newline at end of file
--- a/third_party/rust/byteorder/.travis.yml
+++ b/third_party/rust/byteorder/.travis.yml
@@ -1,15 +1,15 @@
 language: rust
-matrix:
-  include:
-    - rust: "nightly"
-      env: TEST_SUITE=suite_nightly
-    - rust: "beta"
-      env: TEST_SUITE=suite_beta
-    - rust: "stable"
-      env: TEST_SUITE=suite_stable
+rust:
+  - 1.12.0
+  - stable
+  - beta
+  - nightly
 script:
   - cargo build --verbose
+  - cargo doc
   - cargo test --verbose
-  - if [ "$TEST_SUITE" = "suite_nightly" ]; then
+  - cargo test --verbose --no-default-features --lib
+  - if [ "$TRAVIS_RUST_VERSION" = "nightly" ]; then
       cargo bench --verbose;
+      cargo bench --verbose --no-default-features;
     fi
--- a/third_party/rust/byteorder/Cargo.toml
+++ b/third_party/rust/byteorder/Cargo.toml
@@ -1,25 +1,26 @@
 [package]
 name = "byteorder"
-version = "0.5.3"  #:version
+version = "1.0.0"  #:version
 authors = ["Andrew Gallant <jamslam@gmail.com>"]
 description = "Library for reading/writing numbers in big-endian and little-endian."
-documentation = "http://burntsushi.net/rustdoc/byteorder/"
+documentation = "https://docs.rs/byteorder"
 homepage = "https://github.com/BurntSushi/byteorder"
 repository = "https://github.com/BurntSushi/byteorder"
 readme = "README.md"
 keywords = ["byte", "endian", "big-endian", "little-endian", "binary"]
 license = "Unlicense/MIT"
 
 [lib]
 name = "byteorder"
+bench = false
 
 [dev-dependencies]
-quickcheck = "0.2"
+quickcheck = "0.4"
 rand = "0.3"
 
 [features]
 default = ["std"]
 std = []
 
 [profile.bench]
 opt-level = 3
deleted file mode 100644
--- a/third_party/rust/byteorder/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-all:
-	echo Nothing to do...
-
-ctags:
-	ctags --recurse --options=ctags.rust --languages=Rust
-
-docs:
-	cargo doc
-	in-dir ./target/doc fix-perms
-	rscp ./target/doc/* gopher:~/www/burntsushi.net/rustdoc/
-
-push:
-	git push origin master
-	git push github master
--- a/third_party/rust/byteorder/README.md
+++ b/third_party/rust/byteorder/README.md
@@ -1,34 +1,31 @@
 This crate provides convenience methods for encoding and decoding numbers in
-either big-endian or little-endian order. This is meant to replace the old
-methods defined on the standard library `Reader` and `Writer` traits.
+either big-endian or little-endian order.
 
 [![Build status](https://api.travis-ci.org/BurntSushi/byteorder.png)](https://travis-ci.org/BurntSushi/byteorder)
 [![](http://meritbadge.herokuapp.com/byteorder)](https://crates.io/crates/byteorder)
 
 Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org).
 
 
 ### Documentation
 
-[http://burntsushi.net/rustdoc/byteorder/](http://burntsushi.net/rustdoc/byteorder/).
-
-The documentation includes examples.
+https://docs.rs/byteorder
 
 
 ### Installation
 
 This crate works with Cargo and is on
-[crates.io](https://crates.io/crates/byteorder). The package is regularly
-updated.  Add it to your `Cargo.toml` like so:
+[crates.io](https://crates.io/crates/byteorder). Add it to your `Cargo.toml`
+like so:
 
 ```toml
 [dependencies]
-byteorder = "0.5"
+byteorder = "1"
 ```
 
 If you want to augment existing `Read` and `Write` traits, then import the
 extension methods like so:
 
 ```rust
 extern crate byteorder;
 
@@ -50,10 +47,10 @@ assert_eq!(768, rdr.read_u16::<BigEndian
 
 ### `no_std` crates
 
 This crate has a feature, `std`, that is enabled by default. To use this crate
 in a `no_std` context, add the following to your `Cargo.toml`:
 
 ```toml
 [dependencies]
-byteorder = { version = "0.5", default-features = false }
+byteorder = { version = "1", default-features = false }
 ```
deleted file mode 100644
--- a/third_party/rust/byteorder/session.vim
+++ /dev/null
@@ -1,1 +0,0 @@
-au BufWritePost *.rs silent!make ctags > /dev/null 2>&1
--- a/third_party/rust/byteorder/src/lib.rs
+++ b/third_party/rust/byteorder/src/lib.rs
@@ -31,26 +31,24 @@ use byteorder::{LittleEndian, WriteBytes
 
 let mut wtr = vec![];
 wtr.write_u16::<LittleEndian>(517).unwrap();
 wtr.write_u16::<LittleEndian>(768).unwrap();
 assert_eq!(wtr, vec![5, 2, 0, 3]);
 ```
 */
 
-#![crate_name = "byteorder"]
-#![doc(html_root_url = "http://burntsushi.net/rustdoc/byteorder")]
-
+#![deny(missing_docs)]
 #![cfg_attr(not(feature = "std"), no_std)]
 
-#![deny(missing_docs)]
-
 #[cfg(feature = "std")]
 extern crate core;
 
+use core::fmt::Debug;
+use core::hash::Hash;
 use core::mem::transmute;
 use core::ptr::copy_nonoverlapping;
 
 #[cfg(feature = "std")]
 pub use new::{ReadBytesExt, WriteBytesExt};
 
 #[cfg(feature = "std")]
 mod new;
@@ -113,17 +111,18 @@ fn pack_size(n: u64) -> usize {
 ///
 /// ```rust
 /// use byteorder::{ByteOrder, BigEndian};
 ///
 /// let mut buf = [0; 2];
 /// BigEndian::write_i16(&mut buf, -50_000);
 /// assert_eq!(-50_000, BigEndian::read_i16(&buf));
 /// ```
-pub trait ByteOrder {
+pub trait ByteOrder
+    : Clone + Copy + Debug + Default + Eq + Hash + Ord + PartialEq + PartialOrd {
     /// Reads an unsigned 16 bit integer from `buf`.
     ///
     /// Panics when `buf.len() < 2`.
     fn read_u16(buf: &[u8]) -> u16;
 
     /// Reads an unsigned 32 bit integer from `buf`.
     ///
     /// Panics when `buf.len() < 4`.
@@ -259,23 +258,37 @@ pub trait ByteOrder {
         Self::write_u64(buf, unsafe { transmute(n) })
     }
 }
 
 /// Defines big-endian serialization.
 ///
 /// Note that this type has no value constructor. It is used purely at the
 /// type level.
-#[allow(missing_copy_implementations)] pub enum BigEndian {}
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub enum BigEndian {}
+
+impl Default for BigEndian {
+    fn default() -> BigEndian {
+        unreachable!()
+    }
+}
 
 /// Defines little-endian serialization.
 ///
 /// Note that this type has no value constructor. It is used purely at the
 /// type level.
-#[allow(missing_copy_implementations)] pub enum LittleEndian {}
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub enum LittleEndian {}
+
+impl Default for LittleEndian {
+    fn default() -> LittleEndian {
+        unreachable!()
+    }
+}
 
 /// Defines network byte order serialization.
 ///
 /// Network byte order is defined by [RFC 1700][1] to be big-endian, and is
 /// referred to in several protocol specifications.  This type is an alias of
 /// BigEndian.
 ///
 /// [1]: https://tools.ietf.org/html/rfc1700
@@ -434,23 +447,23 @@ impl ByteOrder for LittleEndian {
     }
 }
 
 #[cfg(test)]
 mod test {
     extern crate quickcheck;
     extern crate rand;
 
-    use test::rand::thread_rng;
-    use test::quickcheck::{QuickCheck, StdGen, Testable};
+    use self::rand::thread_rng;
+    use self::quickcheck::{QuickCheck, StdGen, Testable};
 
-    const U64_MAX: u64 = ::std::u64::MAX;
-    const I64_MAX: u64 = ::std::i64::MAX as u64;
+    pub const U64_MAX: u64 = ::core::u64::MAX;