Bug 1407351 - Back out to avoid a merge conflict with bug 1406212. I'll reland tomorrow
authorFelipe Gomes <felipc@gmail.com>
Thu, 12 Oct 2017 21:59:18 -0300
changeset 436796 6a58f8ab311d961a12584fd91b05b8c5c6aa2bf0
parent 436795 fc53699b7d1fbb7dbb26d15adb9ef52d1eb24fa4
child 436797 20296803e9e37fa5e33eb36876e5b2416d6078f8
push id8114
push userjlorenzo@mozilla.com
push dateThu, 02 Nov 2017 16:33:21 +0000
treeherdermozilla-beta@73e0d89a540f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1407351, 1406212
milestone58.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
Bug 1407351 - Back out to avoid a merge conflict with bug 1406212. I'll reland tomorrow MozReview-Commit-ID: 612TlR0MgR4
browser/base/content/browser-menubar.inc
browser/base/content/browser-sets.inc
browser/base/content/browser.js
browser/base/content/browser.xul
browser/base/content/tabbrowser.xml
browser/components/customizableui/CustomizableUI.jsm
browser/components/customizableui/CustomizableWidgets.jsm
browser/components/customizableui/test/head.js
browser/components/preferences/in-content/main.js
browser/components/preferences/in-content/main.xul
browser/locales/en-US/chrome/browser/browser.dtd
browser/locales/en-US/chrome/browser/customizableui/customizableWidgets.properties
browser/locales/en-US/chrome/browser/preferences/main.dtd
browser/themes/shared/toolbarbutton-icons.inc.css
devtools/client/locales/en-US/performance.dtd
devtools/client/performance/performance-controller.js
devtools/client/performance/performance.xul
devtools/client/performance/test/browser_perf-recording-notices-05.js
devtools/client/themes/performance.css
moz.configure
toolkit/modules/AppConstants.jsm
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -29,16 +29,22 @@
                           accesskey="&newNavigatorCmd.accesskey;"
                           key="key_newNavigator"
                           command="cmd_newNavigator"/>
                 <menuitem id="menu_newPrivateWindow"
                           label="&newPrivateWindow.label;"
                           accesskey="&newPrivateWindow.accesskey;"
                           command="Tools:PrivateBrowsing"
                           key="key_privatebrowsing"/>
+#ifdef E10S_TESTING_ONLY
+                <menuitem id="menu_newNonRemoteWindow"
+                          label="&newNonRemoteWindow.label;"
+                          hidden="true"
+                          command="Tools:NonRemoteWindow"/>
+#endif
 #ifdef MAC_NON_BROWSER_WINDOW
                 <menuitem id="menu_openLocation"
                           label="&openLocationCmd.label;"
                           command="Browser:OpenLocation"
                           key="focusURLBar"/>
 #endif
                 <menuitem id="menu_openFile"
                           label="&openFileCmd.label;"
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -97,16 +97,20 @@
 
     <command id="Tools:Search" oncommand="BrowserSearch.webSearch();"/>
     <command id="Tools:Downloads" oncommand="BrowserDownloadsUI();"/>
     <command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/>
     <command id="Tools:Sanitize"
      oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/>
     <command id="Tools:PrivateBrowsing"
       oncommand="OpenBrowserWindow({private: true});"/>
+#ifdef E10S_TESTING_ONLY
+    <command id="Tools:NonRemoteWindow"
+      oncommand="OpenBrowserWindow({remote: false});"/>
+#endif
     <command id="History:UndoCloseTab" oncommand="undoCloseTab();"/>
     <command id="History:UndoCloseWindow" oncommand="undoCloseWindow();"/>
   </commandset>
 
   <commandset id="placesCommands">
     <command id="Browser:ShowAllBookmarks"
              oncommand="PlacesCommandHook.showPlacesOrganizer('UnfiledBookmarks');"/>
     <command id="Browser:ShowAllHistory"
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1460,16 +1460,19 @@ var gBrowserInit = {
     Services.obs.addObserver(gXPInstallObserver, "addon-install-failed");
     Services.obs.addObserver(gXPInstallObserver, "addon-install-confirmation");
     Services.obs.addObserver(gXPInstallObserver, "addon-install-complete");
     window.messageManager.addMessageListener("Browser:URIFixup", gKeywordURIFixup);
 
     BrowserOffline.init();
     IndexedDBPromptHelper.init();
 
+    if (AppConstants.E10S_TESTING_ONLY)
+      gRemoteTabsUI.init();
+
     // Initialize the full zoom setting.
     // We do this before the session restore service gets initialized so we can
     // apply full zoom settings to tabs restored by the session restore service.
     FullZoom.init();
     PanelUI.init();
 
     UpdateUrlbarSearchSplitterState();
 
@@ -1972,16 +1975,19 @@ if (AppConstants.platform == "macosx") {
     this._delayedStartupTimeoutId = null;
 
     // initialise the offline listener
     BrowserOffline.init();
 
     // initialize the private browsing UI
     gPrivateBrowsingUI.init();
 
+    if (AppConstants.E10S_TESTING_ONLY) {
+      gRemoteTabsUI.init();
+    }
   };
 
   gBrowserInit.nonBrowserWindowShutdown = function() {
     let dockSupport = Cc["@mozilla.org/widget/macdocksupport;1"]
                       .getService(Ci.nsIMacDockSupport);
     dockSupport.dockMenu = null;
 
     // If nonBrowserWindowDelayedStartup hasn't run yet, we have no work to do -
@@ -8182,16 +8188,37 @@ var gPrivateBrowsingUI = {
     }
     if (!urlBarSearchParam.includes("private-window")) {
       urlBarSearchParam += " private-window";
     }
     gURLBar.setAttribute("autocompletesearchparam", urlBarSearchParam);
   }
 };
 
+var gRemoteTabsUI = {
+  init() {
+    if (window.location.href != getBrowserURL() &&
+        // Also check hidden window for the Mac no-window case
+        window.location.href != "chrome://browser/content/hiddenWindow.xul") {
+      return;
+    }
+
+    if (AppConstants.platform == "macosx" &&
+        Services.prefs.getBoolPref("layers.acceleration.disabled")) {
+      // On OS X, "Disable Hardware Acceleration" also disables OMTC and forces
+      // a fallback to Basic Layers. This is incompatible with e10s.
+      return;
+    }
+
+    let newNonRemoteWindow = document.getElementById("menu_newNonRemoteWindow");
+    let autostart = Services.appinfo.browserTabsRemoteAutostart;
+    newNonRemoteWindow.hidden = !autostart;
+  }
+};
+
 /**
  * Switch to a tab that has a given URI, and focuses its browser window.
  * If a matching tab is in this window, it will be switched to. Otherwise, other
  * windows will be searched.
  *
  * @param aURI
  *        URI to search for
  * @param aOpenNew
@@ -8439,16 +8466,26 @@ var TabContextMenu = {
 
     var menuItems = aPopupMenu.getElementsByAttribute("tbattr", "tabbrowser-multiple");
     for (let menuItem of menuItems)
       menuItem.disabled = disabled;
 
     if (this.contextTab.hasAttribute("customizemode"))
       document.getElementById("context_openTabInWindow").disabled = true;
 
+    if (AppConstants.E10S_TESTING_ONLY) {
+      menuItems = aPopupMenu.getElementsByAttribute("tbattr", "tabbrowser-remote");
+      for (let menuItem of menuItems) {
+        menuItem.hidden = !gMultiProcessBrowser;
+        if (menuItem.id == "context_openNonRemoteWindow") {
+          menuItem.disabled = !!parseInt(this.contextTab.getAttribute("usercontextid"));
+        }
+      }
+    }
+
     disabled = gBrowser.visibleTabs.length == 1;
     menuItems = aPopupMenu.getElementsByAttribute("tbattr", "tabbrowser-multiple-visible");
     for (let menuItem of menuItems)
       menuItem.disabled = disabled;
 
     // Session store
     document.getElementById("context_undoCloseTab").disabled =
       SessionStore.getClosedTabCount(window) == 0;
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -91,16 +91,22 @@
                 oncommand="gBrowser.unpinTab(TabContextMenu.contextTab);"/>
       <menuitem id="context_duplicateTab" label="&duplicateTab.label;"
                 accesskey="&duplicateTab.accesskey;"
                 oncommand="duplicateTabIn(TabContextMenu.contextTab, 'tab');"/>
       <menuitem id="context_openTabInWindow" label="&moveToNewWindow.label;"
                 accesskey="&moveToNewWindow.accesskey;"
                 tbattr="tabbrowser-multiple"
                 oncommand="gBrowser.replaceTabWithWindow(TabContextMenu.contextTab);"/>
+#ifdef E10S_TESTING_ONLY
+      <menuitem id="context_openNonRemoteWindow" label="Open in new non-e10s window"
+                tbattr="tabbrowser-remote"
+                hidden="true"
+                oncommand="gBrowser.openNonRemoteWindow(TabContextMenu.contextTab);"/>
+#endif
       <menuseparator id="context_sendTabToDevice_separator"/>
       <menu id="context_sendTabToDevice" label="&sendTabToDevice.label;"
             accesskey="&sendTabToDevice.accesskey;">
         <menupopup id="context_sendTabToDevicePopupMenu"
                    onpopupshowing="gSync.populateSendTabToDevicesMenu(event.target, TabContextMenu.contextTab.linkedBrowser.currentURI.spec, TabContextMenu.contextTab.linkedBrowser.contentTitle);"/>
       </menu>
       <menuseparator/>
       <menuitem id="context_reloadAllTabs" label="&reloadAllTabs.label;" accesskey="&reloadAllTabs.accesskey;"
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -3949,16 +3949,30 @@
             }
 
             // tell a new window to take the "dropped" tab
             return window.openDialog(getBrowserURL(), "_blank", options, aTab);
           ]]>
         </body>
       </method>
 
+      <!-- Opens a given tab to a non-remote window. -->
+      <method name="openNonRemoteWindow">
+        <parameter name="aTab"/>
+        <body>
+          <![CDATA[
+            if (!AppConstants.E10S_TESTING_ONLY) {
+              throw "This method is intended only for e10s testing!";
+            }
+            let url = aTab.linkedBrowser.currentURI.spec;
+            return window.openDialog("chrome://browser/content/", "_blank", "chrome,all,dialog=no,non-remote", url);
+          ]]>
+        </body>
+      </method>
+
       <method name="moveTabTo">
         <parameter name="aTab"/>
         <parameter name="aIndex"/>
         <parameter name="aKeepRelatedTabs"/>
         <body>
         <![CDATA[
           var oldPosition = aTab._tPos;
           if (oldPosition == aIndex)
@@ -5525,21 +5539,24 @@
                   "tabs.unmuteAudio.background.tooltip" :
                   "tabs.muteAudio.background.tooltip";
               }
 
               label = this.mStringBundle.getString(stringID);
             }
           } else {
             label = tab._fullLabel || tab.getAttribute("label");
-            if (AppConstants.NIGHTLY_BUILD &&
+            if (AppConstants.E10S_TESTING_ONLY &&
                 tab.linkedBrowser &&
-                tab.linkedBrowser.isRemoteBrowser &&
-                tab.linkedBrowser.frameLoader) {
-              label += " (pid " + tab.linkedBrowser.frameLoader.tabParent.osPid + ")";
+                tab.linkedBrowser.isRemoteBrowser) {
+              label += " - e10s";
+              if (tab.linkedBrowser.frameLoader &&
+                  Services.appinfo.maxWebProcessCount > 1) {
+                label += " (" + tab.linkedBrowser.frameLoader.tabParent.osPid + ")";
+              }
             }
             if (tab.userContextId) {
               label = this.mStringBundle.getFormattedString("tabs.containers.tooltip", [label, ContextualIdentityService.getUserContextLabel(tab.userContextId)]);
             }
           }
 
           event.target.setAttribute("label", label);
         ]]></body>
--- a/browser/components/customizableui/CustomizableUI.jsm
+++ b/browser/components/customizableui/CustomizableUI.jsm
@@ -54,17 +54,17 @@ const kSubviewEvents = [
   "ViewShowing",
   "ViewHiding"
 ];
 
 /**
  * The current version. We can use this to auto-add new default widgets as necessary.
  * (would be const but isn't because of testing purposes)
  */
-var kVersion = 13;
+var kVersion = 12;
 
 /**
  * Buttons removed from built-ins by version they were removed. kVersion must be
  * bumped any time a new id is added to this. Use the button id as key, and
  * version the button is removed in as the value.  e.g. "pocket-button": 5
  */
 var ObsoleteBuiltinButtons = {
 };
@@ -340,16 +340,17 @@ var CustomizableUIInternal = {
         "save-page-button",
         "print-button",
         "history-panelmenu",
         "fullscreen-button",
         "find-button",
         "preferences-button",
         "add-ons-button",
         "sync-button",
+        "e10s-button",
       ];
 
       if (!AppConstants.MOZ_DEV_EDITION) {
         defaultPlacements.splice(-1, 0, "developer-button");
       }
 
       let showCharacterEncoding = Services.prefs.getComplexValue(
         "browser.menu.showCharacterEncoding",
@@ -446,27 +447,16 @@ var CustomizableUIInternal = {
         for (let button of removedButtons) {
           let buttonIndex = placements.indexOf(button);
           if (buttonIndex != -1) {
             placements.splice(buttonIndex, 1);
           }
         }
       }
     }
-
-    // Remove the old placements from the now-gone Nightly-only
-    // "New non-e10s window" button.
-    if (currentVersion < 13 && gSavedState.placements) {
-      for (let placements of Object.values(gSavedState.placements)) {
-        let buttonIndex = placements.indexOf("e10s-button");
-        if (buttonIndex != -1) {
-          placements.spice(buttonIndex, 1);
-        }
-      }
-    }
   },
 
   /**
    * _markObsoleteBuiltinButtonsSeen
    * when upgrading, ensure obsoleted buttons are in seen state.
    */
   _markObsoleteBuiltinButtonsSeen() {
     if (!gSavedState)
--- a/browser/components/customizableui/CustomizableWidgets.jsm
+++ b/browser/components/customizableui/CustomizableWidgets.jsm
@@ -992,8 +992,26 @@ if (Services.prefs.getBoolPref("privacy.
       forgetButton.addEventListener("command", this);
     },
     onViewHiding(aEvent) {
       let forgetButton = aEvent.target.querySelector("#PanelUI-panic-view-button");
       forgetButton.removeEventListener("command", this);
     },
   });
 }
+
+if (AppConstants.E10S_TESTING_ONLY) {
+  if (Services.appinfo.browserTabsRemoteAutostart) {
+    CustomizableWidgets.push({
+      id: "e10s-button",
+      defaultArea: CustomizableUI.AREA_PANEL,
+      onBuild(aDocument) {
+        let node = aDocument.createElementNS(kNSXUL, "toolbarbutton");
+        node.setAttribute("label", CustomizableUI.getLocalizedProperty(this, "label"));
+        node.setAttribute("tooltiptext", CustomizableUI.getLocalizedProperty(this, "tooltiptext"));
+      },
+      onCommand(aEvent) {
+        let win = aEvent.view;
+        win.OpenBrowserWindow({remote: false});
+      },
+    });
+  }
+}
--- a/browser/components/customizableui/test/head.js
+++ b/browser/components/customizableui/test/head.js
@@ -12,16 +12,21 @@ Cu.import("resource://gre/modules/AppCon
 var {Promise, CustomizableUI, AppConstants} = tmp;
 
 var EventUtils = {};
 Services.scriptloader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/EventUtils.js", EventUtils);
 
 Services.prefs.setBoolPref("browser.uiCustomization.skipSourceNodeCheck", true);
 registerCleanupFunction(() => Services.prefs.clearUserPref("browser.uiCustomization.skipSourceNodeCheck"));
 
+// Remove temporary e10s related new window options in customize ui,
+// they break a lot of tests.
+CustomizableUI.destroyWidget("e10s-button");
+CustomizableUI.removeWidgetFromArea("e10s-button");
+
 var {synthesizeDragStart, synthesizeDrop} = EventUtils;
 
 const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 const kTabEventFailureTimeoutInMs = 20000;
 
 const kForceOverflowWidthPx = 300;
 
 function createDummyXULButton(id, label, win = window) {
--- a/browser/components/preferences/in-content/main.js
+++ b/browser/components/preferences/in-content/main.js
@@ -92,16 +92,21 @@ const ICON_URL_APP = AppConstants.platfo
 
 // For CSS. Can be one of "ask", "save", "plugin" or "feed". If absent, the icon URL
 // was set by us to a custom handler icon and CSS should not try to override it.
 const APP_ICON_ATTR_NAME = "appHandlerIcon";
 
 XPCOMUtils.defineLazyModuleGetter(this, "OS",
   "resource://gre/modules/osfile.jsm");
 
+if (AppConstants.E10S_TESTING_ONLY) {
+  XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
+    "resource://gre/modules/UpdateUtils.jsm");
+}
+
 if (AppConstants.MOZ_DEV_EDITION) {
   XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts",
     "resource://gre/modules/FxAccounts.jsm");
 }
 
 // A promise that resolves when the list of application handlers is loaded.
 // We store this in a global so tests can await it.
 var promiseLoadHandlersList;
@@ -309,16 +314,36 @@ var gMainPane = {
       row.removeAttribute("hidden");
       // Showing attribution only for Bing Translator.
       Components.utils.import("resource:///modules/translation/Translation.jsm");
       if (Translation.translationEngine == "bing") {
         document.getElementById("bingAttribution").removeAttribute("hidden");
       }
     }
 
+    if (AppConstants.E10S_TESTING_ONLY) {
+      setEventListener("e10sAutoStart", "command",
+        gMainPane.enableE10SChange);
+      let e10sCheckbox = document.getElementById("e10sAutoStart");
+
+      let e10sPref = document.getElementById("browser.tabs.remote.autostart");
+      let e10sTempPref = document.getElementById("e10sTempPref");
+      let e10sForceEnable = document.getElementById("e10sForceEnable");
+
+      let preffedOn = e10sPref.value || e10sTempPref.value || e10sForceEnable.value;
+
+      if (preffedOn) {
+        // The checkbox is checked if e10s is preffed on and enabled.
+        e10sCheckbox.checked = Services.appinfo.browserTabsRemoteAutostart;
+
+        // but if it's force disabled, then the checkbox is disabled.
+        e10sCheckbox.disabled = !Services.appinfo.browserTabsRemoteAutostart;
+      }
+    }
+
     if (AppConstants.MOZ_DEV_EDITION) {
       let uAppData = OS.Constants.Path.userApplicationDataDir;
       let ignoreSeparateProfile = OS.Path.join(uAppData, "ignore-dev-edition-profile");
 
       setEventListener("separateProfileMode", "command", gMainPane.separateProfileModeChange);
       let separateProfileModeCheckbox = document.getElementById("separateProfileMode");
       setEventListener("getStarted", "click", gMainPane.onGetStarted);
 
@@ -516,16 +541,64 @@ var gMainPane = {
 
     const link = document.getElementById("browserContainersLearnMore");
     link.href = Services.urlFormatter.formatURLPref("app.support.baseURL") + "containers";
 
     document.getElementById("browserContainersbox").hidden = false;
     this.readBrowserContainersCheckbox();
   },
 
+  isE10SEnabled() {
+    let e10sEnabled;
+    try {
+      let e10sStatus = Components.classes["@mozilla.org/supports-PRUint64;1"]
+        .createInstance(Ci.nsISupportsPRUint64);
+      let appinfo = Services.appinfo.QueryInterface(Ci.nsIObserver);
+      appinfo.observe(e10sStatus, "getE10SBlocked", "");
+      e10sEnabled = e10sStatus.data < 2;
+    } catch (e) {
+      e10sEnabled = false;
+    }
+
+    return e10sEnabled;
+  },
+
+  enableE10SChange() {
+    if (AppConstants.E10S_TESTING_ONLY) {
+      let e10sCheckbox = document.getElementById("e10sAutoStart");
+      let e10sPref = document.getElementById("browser.tabs.remote.autostart");
+      let e10sTempPref = document.getElementById("e10sTempPref");
+
+      let prefsToChange;
+      if (e10sCheckbox.checked) {
+        // Enabling e10s autostart
+        prefsToChange = [e10sPref];
+      } else {
+        // Disabling e10s autostart
+        prefsToChange = [e10sPref];
+        if (e10sTempPref.value) {
+          prefsToChange.push(e10sTempPref);
+        }
+      }
+
+      let buttonIndex = confirmRestartPrompt(e10sCheckbox.checked, 0,
+        true, false);
+      if (buttonIndex == CONFIRM_RESTART_PROMPT_RESTART_NOW) {
+        for (let prefToChange of prefsToChange) {
+          prefToChange.value = e10sCheckbox.checked;
+        }
+
+        Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart);
+      }
+
+      // Revert the checkbox in case we didn't quit
+      e10sCheckbox.checked = e10sPref.value || e10sTempPref.value;
+    }
+  },
+
   separateProfileModeChange() {
     if (AppConstants.MOZ_DEV_EDITION) {
       function quitApp() {
         Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestartNotSameProfile);
       }
       function revertCheckbox(error) {
         separateProfileModeCheckbox.checked = !separateProfileModeCheckbox.checked;
         if (error) {
@@ -1198,17 +1271,17 @@ var gMainPane = {
         processCountPref.value == processCountPref.defaultValue) {
         processCountPref.value = e10sRolloutProcessCountPref.value;
       }
       performanceSettings.hidden = false;
     }
   },
 
   buildContentProcessCountMenuList() {
-    if (Services.appinfo.browserTabsRemoteAutostart) {
+    if (gMainPane.isE10SEnabled()) {
       let processCountPref = document.getElementById("dom.ipc.processCount");
       let e10sRolloutProcessCountPref =
         document.getElementById("dom.ipc.processCount.web");
       let defaultProcessCount =
         e10sRolloutProcessCountPref.value || processCountPref.defaultValue;
       let bundlePreferences = document.getElementById("bundlePreferences");
       let label = bundlePreferences.getFormattedString("defaultContentProcessCount",
         [defaultProcessCount]);
--- a/browser/components/preferences/in-content/main.xul
+++ b/browser/components/preferences/in-content/main.xul
@@ -12,16 +12,29 @@
 #endif
 
 <script type="application/javascript"
         src="chrome://mozapps/content/preferences/fontbuilder.js"/>
 
 <stringbundle id="bundlePreferences" src="chrome://browser/locale/preferences.properties"/>
 
 <preferences id="mainPreferences" hidden="true" data-category="paneGeneral">
+
+#ifdef E10S_TESTING_ONLY
+    <preference id="browser.tabs.remote.autostart"
+                name="browser.tabs.remote.autostart"
+                type="bool"/>
+    <preference id="e10sTempPref"
+                name="browser.tabs.remote.autostart.2"
+                type="bool"/>
+    <preference id="e10sForceEnable"
+                name="browser.tabs.remote.force-enable"
+                type="bool"/>
+#endif
+
     <!-- Startup -->
     <preference id="browser.startup.page"
                 name="browser.startup.page"
                 type="int"/>
     <preference id="browser.startup.homepage"
                 name="browser.startup.homepage"
                 type="wstring"/>
 
@@ -280,16 +293,21 @@
       <deck id="getStarted">
         <label class="text-link">&getStarted.notloggedin.label;</label>
         <label class="text-link">&getStarted.configured.label;</label>
       </deck>
     </hbox>
   </vbox>
 #endif
 
+#ifdef E10S_TESTING_ONLY
+  <checkbox id="e10sAutoStart"
+            label="&e10sEnabled.label;"/>
+#endif
+
 #ifdef HAVE_SHELL_SERVICE
   <vbox id="defaultBrowserBox">
     <checkbox id="alwaysCheckDefault" preference="browser.shell.checkDefaultBrowser"
               label="&alwaysCheckDefault2.label;" accesskey="&alwaysCheckDefault2.accesskey;"/>
     <deck id="setDefaultPane">
       <hbox align="center" class="indent">
         <image class="face-sad"/>
         <label id="isNotDefaultLabel" flex="1">&isNotDefault.label;</label>
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -288,16 +288,17 @@ These should match what Safari and other
 <!ENTITY fileMenu.accesskey       "F">
 <!ENTITY newUserContext.label             "New Container Tab">
 <!ENTITY newUserContext.accesskey         "B">
 <!ENTITY newNavigatorCmd.label        "New Window">
 <!ENTITY newNavigatorCmd.key        "N">
 <!ENTITY newNavigatorCmd.accesskey      "N">
 <!ENTITY newPrivateWindow.label     "New Private Window">
 <!ENTITY newPrivateWindow.accesskey "W">
+<!ENTITY newNonRemoteWindow.label   "New Non-e10s Window">
 
 <!ENTITY editMenu.label         "Edit">
 <!ENTITY editMenu.accesskey       "E">
 <!ENTITY undoCmd.label            "Undo">
 <!ENTITY undoCmd.key            "Z">
 <!ENTITY undoCmd.accesskey          "U">
 <!ENTITY redoCmd.label            "Redo">
 <!ENTITY redoCmd.key            "Y">
--- a/browser/locales/en-US/chrome/browser/customizableui/customizableWidgets.properties
+++ b/browser/locales/en-US/chrome/browser/customizableui/customizableWidgets.properties
@@ -96,11 +96,14 @@ panic-button.label = Forget
 panic-button.tooltiptext = Forget about some browsing history
 
 # LOCALIZATION NOTE(devtools-webide-button.label, devtools-webide-button.tooltiptext):
 # widget is only visible after WebIDE has been started once (Tools > Web Developers > WebIDE)
 # %S is the keyboard shortcut
 devtools-webide-button2.label = WebIDE
 devtools-webide-button2.tooltiptext = Open WebIDE (%S)
 
+e10s-button.label = New Non-e10s Window
+e10s-button.tooltiptext = Open a new Non-e10s Window
+
 toolbarspring.label = Flexible Space
 toolbarseparator.label = Separator
 toolbarspacer.label = Space
--- a/browser/locales/en-US/chrome/browser/preferences/main.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/main.dtd
@@ -39,8 +39,10 @@
 <!ENTITY setAsMyDefaultBrowser3.accesskey "D">
 <!ENTITY isDefault.label                  "&brandShortName; is currently your default browser">
 <!ENTITY isNotDefault.label               "&brandShortName; is not your default browser">
 
 <!ENTITY separateProfileMode.label        "Allow &brandShortName; and Firefox to run at the same time">
 <!ENTITY useFirefoxSync.label             "Tip: This uses separate profiles. Use Sync to share data between them.">
 <!ENTITY getStarted.notloggedin.label     "Sign in to &syncBrand.shortName.label;…">
 <!ENTITY getStarted.configured.label      "Open &syncBrand.shortName.label; preferences">
+
+<!ENTITY e10sEnabled.label                "Enable multi-process &brandShortName;">
--- a/browser/themes/shared/toolbarbutton-icons.inc.css
+++ b/browser/themes/shared/toolbarbutton-icons.inc.css
@@ -224,16 +224,24 @@ toolbar[brighttext] {
 #characterencoding-button {
   list-style-image: url("chrome://browser/skin/characterEncoding.svg");
 }
 
 #new-window-button {
   list-style-image: url("chrome://browser/skin/new-window.svg");
 }
 
+#e10s-button {
+  list-style-image: url("chrome://browser/skin/new-window.svg");
+}
+
+#e10s-button > .toolbarbutton-icon {
+  transform: scaleY(-1);
+}
+
 #new-tab-button {
   list-style-image: url("chrome://browser/skin/new-tab.svg");
 }
 
 #privatebrowsing-button {
   list-style-image: url("chrome://browser/skin/privateBrowsing.svg");
 }
 
--- a/devtools/client/locales/en-US/performance.dtd
+++ b/devtools/client/locales/en-US/performance.dtd
@@ -10,16 +10,21 @@
   - You want to make that choice consistent across the developer tools.
   - A good criteria is the language in which you'd find the best
   - documentation on web development on the web. -->
 
 <!-- LOCALIZATION NOTE (performanceUI.bufferStatusTooltip): This string
   -  is displayed as the tooltip for the buffer capacity during a recording. -->
 <!ENTITY performanceUI.bufferStatusTooltip "The profiler stores samples in a circular buffer, and once the buffer reaches the limit for a recording, newer samples begin to overwrite samples at the beginning of the recording.">
 
+<!-- LOCALIZATION NOTE (performanceUI.disabledRealTime.nonE10SBuild): This string
+  -  is displayed as a message for why the real time overview graph is disabled
+  -  when running on a non-multiprocess build. -->
+<!ENTITY performanceUI.disabledRealTime.nonE10SBuild "Realtime recording data disabled on non-multiprocess Firefox.">
+
 <!-- LOCALIZATION NOTE (performanceUI.disabledRealTime.disabledE10S): This string
   -  is displayed as a message for why the real time overview graph is disabled
   -  when running on a build that can run multiprocess Firefox, but just is not enabled. -->
 <!ENTITY performanceUI.disabledRealTime.disabledE10S "Enable multiprocess Firefox in preferences for rendering recording data in realtime.">
 
 <!-- LOCALIZATION NOTE (performanceUI.bufferStatusFull): This string
   -  is displayed when the profiler's circular buffer has started to overlap. -->
 <!ENTITY performanceUI.bufferStatusFull "The buffer is full. Older samples are now being overwritten.">
--- a/devtools/client/performance/performance-controller.js
+++ b/devtools/client/performance/performance-controller.js
@@ -512,27 +512,28 @@ var PerformanceController = {
   /**
    * Returns an object with `supported` and `enabled` properties indicating
    * whether or not the platform is capable of turning on e10s and whether or not
    * it's already enabled, respectively.
    *
    * @return {object}
    */
   getMultiprocessStatus: function () {
-    // If testing, set enabled to true so we have realtime rendering tests
-    // in non-e10s. This function is overridden wholesale in tests
-    // when we want to test multiprocess support
+    // If testing, set both supported and enabled to true so we
+    // have realtime rendering tests in non-e10s. This function is
+    // overridden wholesale in tests when we want to test multiprocess support
     // specifically.
     if (flags.testing) {
-      return { enabled: true };
+      return { supported: true, enabled: true };
     }
+    let supported = system.constants.E10S_TESTING_ONLY;
     // This is only checked on tool startup -- requires a restart if
     // e10s subsequently enabled.
     let enabled = this._e10s;
-    return { enabled };
+    return { supported, enabled };
   },
 
   /**
    * Takes a PerformanceRecording and a state, and waits for
    * the event to be emitted from the front for that recording.
    *
    * @param {PerformanceRecordingFront} recording
    * @param {string} expectedState
@@ -550,19 +551,22 @@ var PerformanceController = {
   }),
 
   /**
    * Called on init, sets an `e10s` attribute on the main view container with
    * "disabled" if e10s is possible on the platform and just not on, or "unsupported"
    * if e10s is not possible on the platform. If e10s is on, no attribute is set.
    */
   _setMultiprocessAttributes: function () {
-    let { enabled } = this.getMultiprocessStatus();
-    if (!enabled) {
+    let { enabled, supported } = this.getMultiprocessStatus();
+    if (!enabled && supported) {
       $("#performance-view").setAttribute("e10s", "disabled");
+    } else if (!enabled && !supported) {
+      // Could be a chance where the directive goes away yet e10s is still on
+      $("#performance-view").setAttribute("e10s", "unsupported");
     }
   },
 
   /**
    * Pipes an event from some source to the PerformanceController.
    */
   _pipe: function (eventName, ...data) {
     this.emit(eventName, ...data);
--- a/devtools/client/performance/performance.xul
+++ b/devtools/client/performance/performance.xul
@@ -206,16 +206,18 @@
             <vbox id="recording-notice"
                   class="notice-container"
                   align="center"
                   pack="center"
                   flex="1">
               <hbox pack="center">
                 <html:div class='recording-button-mount'/>
               </hbox>
+              <label class="realtime-disabled-message"
+                     value="&performanceUI.disabledRealTime.nonE10SBuild;"/>
               <label class="realtime-disabled-on-e10s-message"
                      value="&performanceUI.disabledRealTime.disabledE10S;"/>
               <label class="buffer-status-message"
                      tooltiptext="&performanceUI.bufferStatusTooltip;"/>
               <label class="buffer-status-message-full"
                      value="&performanceUI.bufferStatusFull;"/>
             </vbox>
 
@@ -230,16 +232,18 @@
                 <label class="console-profile-command" />
                 <label value="&performanceUI.console.recordingNoticeEnd;" />
               </hbox>
               <hbox class="console-profile-stop-notice">
                 <label value="&performanceUI.console.stopCommandStart;" />
                 <label class="console-profile-command" />
                 <label value="&performanceUI.console.stopCommandEnd;" />
               </hbox>
+              <label class="realtime-disabled-message"
+                     value="&performanceUI.disabledRealTime.nonE10SBuild;"/>
               <label class="realtime-disabled-on-e10s-message"
                      value="&performanceUI.disabledRealTime.disabledE10S;"/>
               <label class="buffer-status-message"
                      tooltiptext="&performanceUI.bufferStatusTooltip;"/>
               <label class="buffer-status-message-full"
                      value="&performanceUI.bufferStatusFull;"/>
             </vbox>
 
--- a/devtools/client/performance/test/browser_perf-recording-notices-05.js
+++ b/devtools/client/performance/test/browser_perf-recording-notices-05.js
@@ -15,26 +15,40 @@ add_task(function* () {
     win: window
   });
 
   let { gFront, $, PerformanceController } = panel.panelWin;
 
   // Set a fast profiler-status update interval
   yield gFront.setProfilerStatusInterval(10);
 
+  let supported = false;
   let enabled = false;
 
   PerformanceController.getMultiprocessStatus = () => {
-    return { enabled };
+    return { supported, enabled };
   };
 
   PerformanceController._setMultiprocessAttributes();
-  ok($("#performance-view").getAttribute("e10s"), "disabled",
-    "When e10s is disabled, container has [e10s=disabled].");
+  ok($("#performance-view").getAttribute("e10s"), "unsupported",
+    "When e10s is disabled and no option to turn on, container has [e10s=unsupported].");
 
+  supported = true;
+  enabled = false;
+  PerformanceController._setMultiprocessAttributes();
+  ok($("#performance-view").getAttribute("e10s"), "disabled",
+    "When e10s is disabled and but is supported, container has [e10s=disabled].");
+
+  supported = false;
   enabled = true;
-
   PerformanceController._setMultiprocessAttributes();
   ok($("#performance-view").getAttribute("e10s"), "",
-    "When e10s is enabled, there should be no e10s attribute.");
+    "When e10s is enabled, but not supported, this probably means we no longer have " +
+    "E10S_TESTING_ONLY, and we have no e10s attribute.");
+
+  supported = true;
+  enabled = true;
+  PerformanceController._setMultiprocessAttributes();
+  ok($("#performance-view").getAttribute("e10s"), "",
+    "When e10s is enabled and supported, there should be no e10s attribute.");
 
   yield teardownToolboxAndRemoveTab(panel);
 });
--- a/devtools/client/themes/performance.css
+++ b/devtools/client/themes/performance.css
@@ -242,21 +242,23 @@
   overflow: hidden;
 }
 
 .console-profile-command {
   font-family: monospace;
   margin: 3px 2px;
 }
 
+.realtime-disabled-message,
 .realtime-disabled-on-e10s-message {
   display: none;
 }
 
-#performance-view[e10s="disabled"] .realtime-disabled-on-e10s-message {
+#performance-view[e10s="disabled"] .realtime-disabled-on-e10s-message,
+#performance-view[e10s="unsupported"] .realtime-disabled-message {
   display: initial;
   opacity: 0.5;
 }
 
 .buffer-status-message,
 .buffer-status-message-full {
   display: none;
 }
--- a/moz.configure
+++ b/moz.configure
@@ -9,16 +9,27 @@ include('build/moz.configure/init.config
 # Note:
 # - Gecko-specific options and rules should go in toolkit/moz.configure.
 # - Firefox-specific options and rules should go in browser/moz.configure.
 # - Fennec-specific options and rules should go in
 #   mobile/android/moz.configure.
 # - Spidermonkey-specific options and rules should go in js/moz.configure.
 # - etc.
 
+# Multiprocess Firefox Testing UI - Nightly and Aurora
+# To be removed in Bug 1003313
+@depends(milestone)
+def e10s_testing_only(milestone):
+    if not milestone.is_release_or_beta:
+        return True
+
+set_config('E10S_TESTING_ONLY', e10s_testing_only)
+set_define('E10S_TESTING_ONLY', e10s_testing_only)
+
+
 option('--enable-artifact-builds', env='MOZ_ARTIFACT_BUILDS',
        help='Download and use prebuilt binary artifacts.')
 
 @depends('--enable-artifact-builds')
 def artifact_builds(value):
     if value:
         return True
 
--- a/toolkit/modules/AppConstants.jsm
+++ b/toolkit/modules/AppConstants.jsm
@@ -175,16 +175,23 @@ this.AppConstants = Object.freeze({
 
   MOZ_MAINTENANCE_SERVICE:
 #ifdef MOZ_MAINTENANCE_SERVICE
   true,
 #else
   false,
 #endif
 
+  E10S_TESTING_ONLY:
+#ifdef E10S_TESTING_ONLY
+  true,
+#else
+  false,
+#endif
+
   DEBUG:
 #ifdef DEBUG
   true,
 #else
   false,
 #endif
 
   ASAN: