Merge mozilla-central to b2g-inbound
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 22 Jun 2015 14:59:33 +0200
changeset 280742 006adfdd7855a89e122e3018eb837e24e3accf4d
parent 280741 feaeb705556d1fe4a0c3bc52e69ed6cb4c7fcce0 (current diff)
parent 280729 be81b8d6fae99c89e8b14591b11dd26eec0a416e (diff)
child 280743 8b4b778a7f70d4f83a112d3ccef6b05ca67fa058
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-beta@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone41.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 b2g-inbound
browser/devtools/performance/system.js
browser/devtools/performance/views/jit-optimizations.js
caps/tests/mochitest/moz.build
dom/imptests/failures/webapps/XMLHttpRequest/tests/submissions/Ms2ger/mochitest.ini
dom/imptests/failures/webapps/XMLHttpRequest/tests/submissions/Ms2ger/test_interfaces.html.json
image/test/mochitest/test_bug512435.html
testing/web-platform/meta/IndexedDB/close-in-upgradeneeded.html.ini
testing/web-platform/meta/IndexedDB/idbcursor_delete_index4.htm.ini
testing/web-platform/meta/IndexedDB/idbcursor_delete_objectstore4.htm.ini
testing/web-platform/meta/IndexedDB/idbcursor_update_index4.htm.ini
testing/web-platform/meta/IndexedDB/idbcursor_update_objectstore5.htm.ini
testing/web-platform/meta/IndexedDB/idbindex_get6.htm.ini
testing/web-platform/meta/IndexedDB/idbindex_getKey6.htm.ini
testing/web-platform/meta/IndexedDB/idbindex_openCursor.htm.ini
testing/web-platform/meta/IndexedDB/idbindex_openKeyCursor2.htm.ini
testing/web-platform/meta/IndexedDB/idbobjectstore_add16.htm.ini
testing/web-platform/meta/IndexedDB/idbobjectstore_clear4.htm.ini
testing/web-platform/meta/IndexedDB/idbobjectstore_count4.htm.ini
testing/web-platform/meta/IndexedDB/idbobjectstore_delete7.htm.ini
testing/web-platform/meta/IndexedDB/idbobjectstore_deleted.htm.ini
testing/web-platform/meta/IndexedDB/idbobjectstore_put16.htm.ini
testing/web-platform/meta/workers/WorkerLocation_hash_encoding.htm.ini
--- a/addon-sdk/source/lib/sdk/io/buffer.js
+++ b/addon-sdk/source/lib/sdk/io/buffer.js
@@ -242,21 +242,21 @@ Object.defineProperties(Buffer.prototype
 
       return buffer;
     }
   },
   write: {
     value: function(string, offset, length, encoding = 'utf8') {
       // write(string, encoding);
       if (typeof(offset) === 'string' && Number.isNaN(parseInt(offset))) {
-        ([offset, length, encoding]) = [0, null, offset];
+        [offset, length, encoding] = [0, null, offset];
       }
       // write(string, offset, encoding);
       else if (typeof(length) === 'string')
-        ([length, encoding]) = [null, length];
+        [length, encoding] = [null, length];
 
       if (offset < 0 || offset > this.length)
         throw new RangeError('offset is outside of valid range');
 
       offset = ~~offset;
 
       // Clamp length if it would overflow buffer, or if its
       // undefined
--- a/addon-sdk/source/lib/sdk/panel/utils.js
+++ b/addon-sdk/source/lib/sdk/panel/utils.js
@@ -124,33 +124,33 @@ function display(panel, options, anchor)
 
   if (!anchor) {
     // The XUL Panel doesn't have an arrow, so the margin needs to be reset
     // in order to, be positioned properly
     panel.style.margin = "0";
 
     let viewportRect = document.defaultView.gBrowser.getBoundingClientRect();
 
-    ({x, y, width, height}) = calculateRegion(options, viewportRect);
+    ({x, y, width, height} = calculateRegion(options, viewportRect));
   }
   else {
     // The XUL Panel has an arrow, so the margin needs to be reset
     // to the default value.
     panel.style.margin = "";
     let { CustomizableUI, window } = anchor.ownerDocument.defaultView;
 
     // In Australis, widgets may be positioned in an overflow panel or the
     // menu panel.
     // In such cases clicking this widget will hide the overflow/menu panel,
     // and the widget's panel will show instead.
     // If `CustomizableUI` is not available, it means the anchor is not in a
     // chrome browser window, and therefore there is no need for this check.
     if (CustomizableUI) {
       let node = anchor;
-      ({anchor}) = CustomizableUI.getWidget(anchor.id).forWindow(window);
+      ({anchor} = CustomizableUI.getWidget(anchor.id).forWindow(window));
 
       // if `node` is not the `anchor` itself, it means the widget is
       // positioned in a panel, therefore we have to hide it before show
       // the widget's panel in the same anchor
       if (node !== anchor)
         CustomizableUI.hidePanelForNode(anchor);
     }
 
--- a/addon-sdk/source/lib/sdk/util/sequence.js
+++ b/addon-sdk/source/lib/sdk/util/sequence.js
@@ -240,17 +240,17 @@ const map = (f, ...sequences) => seq(fun
     // Run loop yielding of applying `f` to the set of
     // items at each step until one of the `inputs` is
     // exhausted.
     let done = false;
     while (!done) {
       let index = 0;
       let value = void(0);
       while (index < count && !done) {
-        ({ done, value }) = inputs[index].next();
+        ({ done, value } = inputs[index].next());
 
         // If input is not exhausted yet store value in args.
         if (!done) {
           args[index] = value;
           index = index + 1;
         }
       }
 
@@ -268,20 +268,20 @@ exports.map = map;
 //
 // Implements clojure reductions:
 // http://clojuredocs.org/clojure_core/clojure.core/reductions
 const reductions = (...params) => {
   const count = params.length;
   let hasInitial = false;
   let f, initial, source;
   if (count === 2) {
-    ([f, source]) = params;
+    [f, source] = params;
   }
   else if (count === 3) {
-    ([f, initial, source]) = params;
+    [f, initial, source] = params;
     hasInitial = true;
   }
   else {
     throw Error("Invoked with wrong number of arguments: " + count);
   }
 
   const sequence = seq(source);
 
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -217,16 +217,20 @@ pref("content.sink.perf_parse_time", 500
 pref("dom.use_watchdog", false);
 
 // The slow script dialog can be triggered from inside the JS engine as well,
 // ensure that those calls don't accidentally trigger the dialog.
 pref("dom.max_script_run_time", 0);
 pref("dom.max_chrome_script_run_time", 0);
 pref("dom.max_child_script_run_time", 0);
 
+// Temporarily disable support for offsetX/Y to work around Google Maps bug
+// (bug 1150284)
+pref("dom.mouseEvent.offsetXY.enabled", false);
+
 // plugins
 pref("plugin.disable", true);
 pref("dom.ipc.plugins.enabled", true);
 
 // product URLs
 // The breakpad report server to link to in about:crashes
 pref("breakpad.reportURL", "https://crash-stats.mozilla.com/report/index/");
 pref("app.releaseNotesURL", "http://www.mozilla.com/%LOCALE%/b2g/%VERSION%/releasenotes/");
--- a/browser/app/blocklist.xml
+++ b/browser/app/blocklist.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0"?>
-<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1433264296000">
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1433888926000">
   <emItems>
       <emItem  blockID="i58" id="webmaster@buzzzzvideos.info">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
       <emItem  blockID="i71" id="youtube@2youtube.com">
@@ -156,16 +156,25 @@
       <emItem  blockID="i800" id="{424b0d11-e7fe-4a04-b7df-8f2c77f58aaf}">
                         <versionRange  minVersion="0" maxVersion="*" severity="3">
                     </versionRange>
                     <prefs>
                   <pref>browser.startup.homepage</pref>
                   <pref>browser.search.defaultenginename</pref>
               </prefs>
     </emItem>
+      <emItem  blockID="i926" id="{B1FC07E1-E05B-4567-8891-E63FBE545BA8}">
+                        <versionRange  minVersion="0" maxVersion="1.2.0" severity="1">
+                      <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+                              <versionRange  minVersion="39.0a1" maxVersion="*" />
+                          </targetApplication>
+                    </versionRange>
+                    <prefs>
+              </prefs>
+    </emItem>
       <emItem  blockID="i62" id="jid0-EcdqvFOgWLKHNJPuqAnawlykCGZ@jetpack">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
       <emItem  blockID="i624" id="/^({b95faac1-a3d7-4d69-8943-ddd5a487d966}|{ecce0073-a837-45a2-95b9-600420505f7e}|{2713b394-286f-4d7c-89ea-4174eeab9f5a}|{da7a20cf-bef4-4342-ad78-0240fdf87055})$/">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
@@ -761,16 +770,25 @@
               </prefs>
     </emItem>
       <emItem  blockID="i596" id="{b99c8534-7800-48fa-bd71-519a46cdc7e1}">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
+      <emItem  blockID="i924" id="{DAC3F861-B30D-40dd-9166-F4E75327FAC7}">
+                        <versionRange  minVersion="0" maxVersion="1.3.1" severity="1">
+                      <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+                              <versionRange  minVersion="39.0a1" maxVersion="*" />
+                          </targetApplication>
+                    </versionRange>
+                    <prefs>
+              </prefs>
+    </emItem>
       <emItem  blockID="i740" id="ascsurfingprotection@iobit.com">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
       <emItem  blockID="i360" id="ytd@mybrowserbar.com">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
@@ -971,16 +989,25 @@
               </prefs>
     </emItem>
       <emItem  blockID="i816" id="noOpus@outlook.com">
                         <versionRange  minVersion="0" maxVersion="*" severity="3">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
+      <emItem  blockID="i922" id="{34712C68-7391-4c47-94F3-8F88D49AD632}">
+                        <versionRange  minVersion="0" maxVersion="1.3.0" severity="1">
+                      <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+                              <versionRange  minVersion="39.0a1" maxVersion="*" />
+                          </targetApplication>
+                    </versionRange>
+                    <prefs>
+              </prefs>
+    </emItem>
       <emItem  blockID="i528" id="008abed2-b43a-46c9-9a5b-a771c87b82da@1ad61d53-2bdc-4484-a26b-b888ecae1906.com">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
       <emItem  blockID="i540" id="/^(ffxtlbr@mixidj\.com|{c0c2693d-2ee8-47b4-9df7-b67a0ee31988}|{67097627-fd8e-4f6b-af4b-ecb65e50112e}|{f6f0f973-a4a3-48cf-9a7a-b7a69c30d71a}|{a3d0e35f-f1da-4ccb-ae77-e9d27777e68d}|{1122b43d-30ee-403f-9bfa-3cc99b0caddd})$/">
                         <versionRange  minVersion="0" maxVersion="*" severity="3">
@@ -1690,16 +1717,25 @@
               </prefs>
     </emItem>
       <emItem  blockID="i523" id="/^({7e8a1050-cf67-4575-92df-dcc60e7d952d}|{b3420a9c-a397-4409-b90d-bcf22da1a08a}|{eca6641f-2176-42ba-bdbe-f3e327f8e0af}|{707dca12-3f99-4d94-afea-06dcc0ae0108}|{aea20431-87fc-40be-bc5b-18066fe2819c}|{30ee6676-1ba6-455a-a7e8-298fa863a546})$/">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
+      <emItem  blockID="i920" id="{FCE04E1F-9378-4f39-96F6-5689A9159E45}">
+                        <versionRange  minVersion="0" maxVersion="1.3.2" severity="1">
+                      <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+                              <versionRange  minVersion="39.0a1" maxVersion="*" />
+                          </targetApplication>
+                    </versionRange>
+                    <prefs>
+              </prefs>
+    </emItem>
       <emItem  blockID="i656" id="hdv@vovcacik.addons.mozilla.org">
                         <versionRange  minVersion="102.0" maxVersion="102.0" severity="3">
                     </versionRange>
                     <prefs>
               </prefs>
     </emItem>
       <emItem  blockID="i503" id="{9CE11043-9A15-4207-A565-0C94C42D590D}">
                         <versionRange  minVersion="0" maxVersion="*" severity="3">
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -266,16 +266,17 @@ pref("general.autoScroll", false);
 #else
 pref("general.autoScroll", true);
 #endif
 
 // At startup, check if we're the default browser and prompt user if not.
 pref("browser.shell.checkDefaultBrowser", true);
 pref("browser.shell.shortcutFavicons",true);
 pref("browser.shell.mostRecentDateSetAsDefault", "");
+pref("browser.shell.windows10DefaultBrowserABTest", -1);
 
 // 0 = blank, 1 = home (browser.startup.homepage), 2 = last visited page, 3 = resume previous browser session
 // The behavior of option 3 is detailed at: http://wiki.mozilla.org/Session_Restore
 pref("browser.startup.page",                1);
 pref("browser.startup.homepage",            "chrome://branding/locale/browserconfig.properties");
 
 pref("browser.slowStartup.notificationDisabled", false);
 pref("browser.slowStartup.timeThreshold", 40000);
@@ -291,17 +292,17 @@ pref("browser.casting.enabled", false);
 pref("browser.chrome.site_icons", true);
 pref("browser.chrome.favicons", true);
 // browser.warnOnQuit == false will override all other possible prompts when quitting or restarting
 pref("browser.warnOnQuit", true);
 // browser.showQuitWarning specifically controls the quit warning dialog. We
 // might still show the window closing dialog with showQuitWarning == false.
 pref("browser.showQuitWarning", false);
 pref("browser.fullscreen.autohide", true);
-pref("browser.fullscreen.animateUp", 1);
+pref("browser.fullscreen.animate", true);
 pref("browser.overlink-delay", 80);
 
 #ifdef UNIX_BUT_NOT_MAC
 pref("browser.urlbar.clickSelectsAll", false);
 #else
 pref("browser.urlbar.clickSelectsAll", true);
 #endif
 #ifdef UNIX_BUT_NOT_MAC
@@ -623,17 +624,17 @@ pref("mousewheel.with_meta.action", 1); 
 #endif
 pref("mousewheel.with_control.action",3);
 pref("mousewheel.with_win.action", 1);
 
 pref("browser.xul.error_pages.enabled", true);
 pref("browser.xul.error_pages.expert_bad_cert", false);
 
 // If true, network link events will change the value of navigator.onLine
-pref("network.manage-offline-status", false);
+pref("network.manage-offline-status", true);
 
 // We want to make sure mail URLs are handled externally...
 pref("network.protocol-handler.external.mailto", true); // for mail
 pref("network.protocol-handler.external.news", true);   // for news
 pref("network.protocol-handler.external.snews", true);  // for secure news
 pref("network.protocol-handler.external.nntp", true);   // also news
 #ifdef XP_WIN
 pref("network.protocol-handler.external.ms-windows-store", true);
@@ -1946,9 +1947,10 @@ pref("browser.pocket.oAuthConsumerKey", 
 pref("browser.pocket.useLocaleList", true);
 pref("browser.pocket.enabledLocales", "en-US de es-ES ja ja-JP-mac ru");
 
 pref("view_source.tab", true);
 
 // Enable Service Workers for desktop on non-release builds
 #ifndef RELEASE_BUILD
 pref("dom.serviceWorkers.enabled", true);
+pref("dom.serviceWorkers.interception.enabled", true);
 #endif
--- a/browser/base/content/browser-fullScreen.js
+++ b/browser/base/content/browser-fullScreen.js
@@ -1,16 +1,14 @@
 # -*- indent-tabs-mode: nil; js-indent-level: 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/.
 
 var FullScreen = {
-  _XULNS: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
-
   _MESSAGES: [
     "DOMFullscreen:Request",
     "DOMFullscreen:NewOrigin",
     "DOMFullscreen:Exit",
   ],
 
   init: function() {
     // called when we go into full screen, even if initiated by a web page script
@@ -58,37 +56,34 @@ var FullScreen = {
       this._fullScrToggler = document.getElementById("fullscr-toggler");
       this._fullScrToggler.addEventListener("mouseover", this._expandCallback, false);
       this._fullScrToggler.addEventListener("dragenter", this._expandCallback, false);
     }
 
     if (enterFS) {
       gNavToolbox.setAttribute("inFullscreen", true);
       document.documentElement.setAttribute("inFullscreen", true);
+      if (!document.mozFullScreen && this.useLionFullScreen)
+        document.documentElement.setAttribute("OSXLionFullscreen", true);
     } else {
       gNavToolbox.removeAttribute("inFullscreen");
       document.documentElement.removeAttribute("inFullscreen");
+      document.documentElement.removeAttribute("OSXLionFullscreen");
     }
 
-    // show/hide menubars, toolbars (except the full screen toolbar)
-    // On OS X Lion, we don't want to hide toolbars when entering
-    // fullscreen, unless we're entering DOM fullscreen.
-    if (document.mozFullScreen || !this.useLionFullScreen) {
-      this.showXULChrome("toolbar", !enterFS);
-    }
+    if (!document.mozFullScreen)
+      this._updateToolbars(enterFS);
 
     if (enterFS) {
       document.addEventListener("keypress", this._keyToggleCallback, false);
       document.addEventListener("popupshown", this._setPopupOpen, false);
       document.addEventListener("popuphidden", this._setPopupOpen, false);
-      this._shouldAnimate = true;
-      // We don't animate the toolbar collapse if in DOM full-screen mode,
-      // as the size of the content area would still be changing after the
-      // mozfullscreenchange event fired, which could confuse content script.
-      this.hideNavToolbox(document.mozFullScreen);
+      // In DOM fullscreen mode, we hide toolbars with CSS
+      if (!document.mozFullScreen)
+        this.hideNavToolbox(true);
     }
     else {
       this.showNavToolbox(false);
       // This is needed if they use the context menu to quit fullscreen
       this._isPopupOpen = false;
       this.cleanup();
       // In TabsInTitlebar._update(), we cancel the appearance update on
       // resize event for exiting fullscreen, since that happens before we
@@ -203,20 +198,16 @@ var FullScreen = {
     gBrowser.tabContainer.addEventListener("TabClose", this.exitDomFullScreen);
     gBrowser.tabContainer.addEventListener("TabSelect", this.exitDomFullScreen);
 
     // Add listener to detect when the fullscreen window is re-focused.
     // If a fullscreen window loses focus, we show a warning when the
     // fullscreen window is refocused.
     window.addEventListener("activate", this);
 
-    // Cancel any "hide the toolbar" animation which is in progress, and make
-    // the toolbar hide immediately.
-    this.hideNavToolbox(true);
-    this._fullScrToggler.hidden = true;
     return true;
   },
 
   cleanup: function () {
     if (!window.fullScreen) {
       MousePosTracker.removeListener(this);
       document.removeEventListener("keypress", this._keyToggleCallback, false);
       document.removeEventListener("popupshown", this._setPopupOpen, false);
@@ -227,23 +218,16 @@ var FullScreen = {
   cleanupDomFullscreen: function () {
     this.cancelWarning();
     gBrowser.tabContainer.removeEventListener("TabOpen", this.exitDomFullScreen);
     gBrowser.tabContainer.removeEventListener("TabClose", this.exitDomFullScreen);
     gBrowser.tabContainer.removeEventListener("TabSelect", this.exitDomFullScreen);
     window.removeEventListener("activate", this);
 
     document.documentElement.removeAttribute("inDOMFullscreen");
-    this.showNavToolbox();
-    // If we are still in fullscreen mode, re-hide
-    // the toolbox with animation.
-    if (window.fullScreen) {
-      this._shouldAnimate = true;
-      this.hideNavToolbox();
-    }
 
     window.messageManager
           .broadcastAsyncMessage("DOMFullscreen:CleanUp");
   },
 
   _isRemoteBrowser: function (aBrowser) {
     return gMultiProcessBrowser && aBrowser.getAttribute("remote") == "true";
   },
@@ -267,50 +251,45 @@ var FullScreen = {
   {
     FullScreen.hideNavToolbox();
   },
   _keyToggleCallback: function(aEvent)
   {
     // if we can use the keyboard (eg Ctrl+L or Ctrl+E) to open the toolbars, we
     // should provide a way to collapse them too.
     if (aEvent.keyCode == aEvent.DOM_VK_ESCAPE) {
-      FullScreen.hideNavToolbox(true);
+      FullScreen.hideNavToolbox();
     }
     // F6 is another shortcut to the address bar, but its not covered in OpenLocation()
     else if (aEvent.keyCode == aEvent.DOM_VK_F6)
       FullScreen.showNavToolbox();
   },
 
   // Checks whether we are allowed to collapse the chrome
   _isPopupOpen: false,
   _isChromeCollapsed: false,
-  _safeToCollapse: function(forceHide)
-  {
+  _safeToCollapse: function () {
     if (!gPrefService.getBoolPref("browser.fullscreen.autohide"))
       return false;
 
-    if (!forceHide) {
-      // a popup menu is open in chrome: don't collapse chrome
-      if (this._isPopupOpen)
-        return false;
-      // On OS X Lion we don't want to hide toolbars.
-      if (this.useLionFullScreen)
-        return false;
-    }
+    // a popup menu is open in chrome: don't collapse chrome
+    if (this._isPopupOpen)
+      return false;
+
+    // On OS X Lion we don't want to hide toolbars.
+    if (this.useLionFullScreen)
+      return false;
 
     // a textbox in chrome is focused (location bar anyone?): don't collapse chrome
     if (document.commandDispatcher.focusedElement &&
         document.commandDispatcher.focusedElement.ownerDocument == document &&
         document.commandDispatcher.focusedElement.localName == "input") {
-      if (forceHide)
-        // hidden textboxes that still have focus are bad bad bad
-        document.commandDispatcher.focusedElement.blur();
-      else
-        return false;
+      return false;
     }
+
     return true;
   },
 
   _setPopupOpen: function(aEvent)
   {
     // Popups should only veto chrome collapsing if they were opened when the chrome was not collapsed.
     // Otherwise, they would not affect chrome and the user would expect the chrome to go away.
     // e.g. we wouldn't want the autoscroll icon firing this event, so when the user
@@ -328,19 +307,16 @@ var FullScreen = {
   {
     aItem.setAttribute("checked", gPrefService.getBoolPref("browser.fullscreen.autohide"));
   },
   setAutohide: function()
   {
     gPrefService.setBoolPref("browser.fullscreen.autohide", !gPrefService.getBoolPref("browser.fullscreen.autohide"));
   },
 
-  // Animate the toolbars disappearing
-  _shouldAnimate: true,
-
   cancelWarning: function(event) {
     if (!this.warningBox)
       return;
     this.warningBox.removeEventListener("transitionend", this);
     if (this.warningFadeOutTimeout) {
       clearTimeout(this.warningFadeOutTimeout);
       this.warningFadeOutTimeout = null;
     }
@@ -509,92 +485,60 @@ var FullScreen = {
         bottom: rect.bottom,
         left: rect.left,
         right: rect.right
       };
       MousePosTracker.addListener(this);
     }
   },
 
-  hideNavToolbox: function(forceHide = false) {
-    this._fullScrToggler.hidden = document.mozFullScreen;
-    if (this._isChromeCollapsed) {
-      if (forceHide) {
-        gNavToolbox.removeAttribute("fullscreenShouldAnimate");
-      }
+  hideNavToolbox: function (aAnimate = false) {
+    if (this._isChromeCollapsed || !this._safeToCollapse())
       return;
-    }
-    if (!this._safeToCollapse(forceHide)) {
-      this._fullScrToggler.hidden = true;
-      return;
-    }
 
-    // browser.fullscreen.animateUp
-    // 0 - never animate up
-    // 1 - animate only for first collapse after entering fullscreen (default for perf's sake)
-    // 2 - animate every time it collapses
-    let animateUp = gPrefService.getIntPref("browser.fullscreen.animateUp");
-    if (animateUp == 0) {
-      this._shouldAnimate = false;
-    } else if (animateUp == 2) {
-      this._shouldAnimate = true;
-    }
-    if (this._shouldAnimate && !forceHide) {
+    this._fullScrToggler.hidden = false;
+
+    if (aAnimate && gPrefService.getBoolPref("browser.fullscreen.animate")) {
       gNavToolbox.setAttribute("fullscreenShouldAnimate", true);
-      this._shouldAnimate = false;
       // Hide the fullscreen toggler until the transition ends.
       let listener = () => {
         gNavToolbox.removeEventListener("transitionend", listener, true);
         if (this._isChromeCollapsed)
           this._fullScrToggler.hidden = false;
       };
       gNavToolbox.addEventListener("transitionend", listener, true);
       this._fullScrToggler.hidden = true;
     }
 
     gNavToolbox.style.marginTop =
       -gNavToolbox.getBoundingClientRect().height + "px";
     this._isChromeCollapsed = true;
     MousePosTracker.removeListener(this);
   },
 
-  showXULChrome: function(aTag, aShow)
-  {
-    var els = document.getElementsByTagNameNS(this._XULNS, aTag);
-
-    for (let el of els) {
-      // XXX don't interfere with previously collapsed toolbars
-      if (el.getAttribute("fullscreentoolbar") == "true") {
-        if (!aShow) {
-          // Give the main nav bar and the tab bar the fullscreen context menu,
-          // otherwise remove context menu to prevent breakage
-          el.setAttribute("saved-context", el.getAttribute("context"));
-          if (el.id == "nav-bar" || el.id == "TabsToolbar")
-            el.setAttribute("context", "autohide-context");
-          else
-            el.removeAttribute("context");
+  _updateToolbars: function (aEnterFS) {
+    for (let el of document.querySelectorAll("toolbar[fullscreentoolbar=true]")) {
+      if (aEnterFS) {
+        // Give the main nav bar and the tab bar the fullscreen context menu,
+        // otherwise remove context menu to prevent breakage
+        el.setAttribute("saved-context", el.getAttribute("context"));
+        if (el.id == "nav-bar" || el.id == "TabsToolbar")
+          el.setAttribute("context", "autohide-context");
+        else
+          el.removeAttribute("context");
 
-          // Set the inFullscreen attribute to allow specific styling
-          // in fullscreen mode
-          el.setAttribute("inFullscreen", true);
+        // Set the inFullscreen attribute to allow specific styling
+        // in fullscreen mode
+        el.setAttribute("inFullscreen", true);
+      } else {
+        if (el.hasAttribute("saved-context")) {
+          el.setAttribute("context", el.getAttribute("saved-context"));
+          el.removeAttribute("saved-context");
         }
-        else {
-          if (el.hasAttribute("saved-context")) {
-            el.setAttribute("context", el.getAttribute("saved-context"));
-            el.removeAttribute("saved-context");
-          }
-          el.removeAttribute("inFullscreen");
-        }
-      } else {
-        // use moz-collapsed so it doesn't persist hidden/collapsed,
-        // so that new windows don't have missing toolbars
-        if (aShow)
-          el.removeAttribute("moz-collapsed");
-        else
-          el.setAttribute("moz-collapsed", "true");
+        el.removeAttribute("inFullscreen");
       }
     }
 
     ToolbarIconColor.inferFromText();
 
     // For Lion fullscreen, all fullscreen controls are hidden, don't
     // bother to touch them. If we don't stop here, the following code
     // could cause the native fullscreen button be shown unexpectedly.
@@ -609,17 +553,17 @@ var FullScreen = {
     if (fullscreenctls.parentNode == navbar && ctlsOnTabbar) {
       fullscreenctls.removeAttribute("flex");
       document.getElementById("TabsToolbar").appendChild(fullscreenctls);
     }
     else if (fullscreenctls.parentNode.id == "TabsToolbar" && !ctlsOnTabbar) {
       fullscreenctls.setAttribute("flex", "1");
       navbar.appendChild(fullscreenctls);
     }
-    fullscreenctls.hidden = aShow;
+    fullscreenctls.hidden = !aEnterFS;
   }
 };
 XPCOMUtils.defineLazyGetter(FullScreen, "useLionFullScreen", function() {
   // We'll only use OS X Lion full screen if we're
   // * on OS X
   // * on Lion or higher (Darwin 11+)
   // * have fullscreenbutton="true"
 #ifdef XP_MACOSX
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -285,21 +285,24 @@ toolbar[customizing] > .overflow-button 
 %ifdef XP_WIN
 #main-window[sizemode="maximized"] #titlebar-buttonbox {
   -moz-appearance: -moz-window-button-box-maximized;
 }
 %endif
 
 %endif
 
+#main-window[inDOMFullscreen] #navigator-toolbox,
+#main-window[inDOMFullscreen] #fullscr-toggler,
 #main-window[inDOMFullscreen] #sidebar-box,
 #main-window[inDOMFullscreen] #sidebar-splitter {
   visibility: collapse;
 }
 
+#main-window[inFullscreen]:not([OSXLionFullscreen]) toolbar:not([fullscreentoolbar=true]),
 #main-window[inFullscreen] #global-notificationbox,
 #main-window[inFullscreen] #high-priority-global-notificationbox {
   visibility: collapse;
 }
 
 #navigator-toolbox[fullscreenShouldAnimate] {
   transition: 1.5s margin-top ease-out;
 }
--- a/browser/base/content/pageinfo/permissions.js
+++ b/browser/base/content/pageinfo/permissions.js
@@ -201,16 +201,20 @@ function initIndexedDBRow()
 }
 
 function onIndexedDBClear()
 {
   Components.classes["@mozilla.org/dom/quota/manager;1"]
             .getService(nsIQuotaManager)
             .clearStoragesForURI(gPermURI);
 
+  Components.classes["@mozilla.org/serviceworkers/manager;1"]
+            .getService(Components.interfaces.nsIServiceWorkerManager)
+            .removeAndPropagate(gPermURI.host);
+
   SitePermissions.remove(gPermURI, "indexedDB");
   initIndexedDBRow();
 }
 
 function onIndexedDBUsageCallback(uri, usage, fileUsage)
 {
   if (!uri.equals(gPermURI)) {
     throw new Error("Callback received for bad URI: " + uri);
--- a/browser/components/loop/content/shared/css/conversation.css
+++ b/browser/components/loop/content/shared/css/conversation.css
@@ -1150,18 +1150,19 @@ html[dir="rtl"] .room-context-btn-edit {
      https://code.google.com/p/chromium/issues/detail?id=400829 */
   overflow: hidden;
 }
 
 .media-wrapper > .remote > .remote-video {
   object-fit: cover;
 }
 
-/* Note: we can't use flex for the text-chat-view as this lets it overflow
-   the expected column heights, and we ca't fix its height. */
+/* Note: we can't use "display: flex;" for the text-chat-view itself,
+   as this lets it overflow the expected column heights, and we can't
+   fix its height. */
 .media-wrapper > .text-chat-view {
   flex: 0 0 auto;
   /* Text chat is a fixed 200px width for normal displays. */
   width: 200px;
   height: 100%;
 }
 
 .media-wrapper.showing-local-streams > .text-chat-view {
@@ -1171,21 +1172,28 @@ html[dir="rtl"] .room-context-btn-edit {
 }
 
 .media-wrapper.showing-local-streams.receiving-screen-share > .text-chat-view {
   /* When we're displaying the local streams, then we need to make the text
      chat view a bit shorter to give room. */
   height: calc(100% - 300px);
 }
 
+/* Temporarily slaved from .media-wrapper until we use it in more places
+   to avoid affecting the conversation window on desktop. */
 .media-wrapper > .text-chat-view > .text-chat-entries {
   /* 40px is the height of .text-chat-box. */
   height: calc(100% - 40px);
 }
 
+.media-wrapper > .text-chat-disabled > .text-chat-entries {
+  /* When text chat is disabled, the entries box should be 100% height. */
+  height: 100%;
+}
+
 .media-wrapper > .local {
   flex: 0 1 auto;
   width: 200px;
   height: 150px;
 }
 
 .media-wrapper.receiving-screen-share > .screen {
   order: 1;
@@ -1225,22 +1233,29 @@ html[dir="rtl"] .room-context-btn-edit {
     /* A reasonable height */
     height: 70%;
   }
 
   .media-wrapper.receiving-screen-share > .focus-stream {
     height: 50%;
   }
 
+  /* Temporarily slaved from .media-wrapper until we use it in more places
+     to avoid affecting the conversation window on desktop. */
   .media-wrapper > .text-chat-view > .text-chat-entries {
     /* 40px is the height of .text-chat-box. */
     height: calc(100% - 40px);
     width: 100%;
   }
 
+  .media-wrapper > .text-chat-disabled > .text-chat-entries {
+    /* When text chat is disabled, the entries box should be 100% height. */
+    height: 100%;
+  }
+
   .media-wrapper > .local {
     /* Position over the remote video */
     position: absolute;
     /* Make sure its on top */
     z-index: 1001;
     margin: 3px;
     right: 0;
     /* 29px is (30% of 50px high header) + (height toolbar (38px) +
@@ -1443,17 +1458,17 @@ html[dir="rtl"] .standalone .room-conver
   flex-flow: column nowrap;
 }
 
 .fx-embedded .video-layout-wrapper {
   flex: 1 1 auto;
 }
 
 .text-chat-view {
-  background: #fff;
+  background: white;
 }
 
 .fx-embedded .text-chat-view {
   flex: 1 0 auto;
   display: flex;
   flex-flow: column nowrap;
 }
 
@@ -1467,17 +1482,17 @@ html[dir="rtl"] .standalone .room-conver
 .text-chat-box {
   flex: 0 0 auto;
   max-height: 40px;
   min-height: 40px;
   width: 100%;
 }
 
 .text-chat-entries {
-  overflow: scroll;
+  overflow: auto;
 }
 
 .text-chat-entry {
   text-align: end;
   margin-bottom: 1.5em;
 }
 
 .text-chat-entry > p {
@@ -1485,16 +1500,20 @@ html[dir="rtl"] .standalone .room-conver
   border-style: solid;
   border-color: #0095dd;
   border-radius: 10000px;
   padding: .5em 1em;
   /* Drop the default margins from the 'p' element. */
   margin: 0;
   /* inline-block stops the elements taking 100% of the text-chat-view width */
   display: inline-block;
+  /* Split really long strings with no spaces appropriately, whilst limiting the
+     width to 100%. */
+  max-width: 100%;
+  word-wrap: break-word;
 }
 
 .text-chat-entry.received {
   text-align: start;
 }
 
 .text-chat-entry.received > p {
   border-color: #d8d8d8;
@@ -1517,21 +1536,23 @@ html[dir="rtl"] .standalone .room-conver
   margin: auto;
 }
 
 .text-chat-box > form > input {
   width: 100%;
   height: 40px;
   padding: 0 .5em .5em;
   font-size: 1.1em;
+  border: 0;
+  border-top: 1px solid #999;
 }
 
-.fx-embedded .text-chat-box > form > input {
-  border: 0;
-  border-top: 1px solid #999;
+/* turn the visible border blue as a visual indicator of focus */
+.text-chat-box > form > input:focus {
+  border-top: 1px solid #66c9f2;
 }
 
 @media screen and (max-width:640px) {
   .standalone-context-url {
     /* XXX We haven't got UX for standalone yet, so temporarily not displaying
        on narrow window widths. See bug 1153827. */
     display: none;
   }
--- a/browser/components/loop/content/shared/js/textChatView.js
+++ b/browser/components/loop/content/shared/js/textChatView.js
@@ -76,18 +76,22 @@ loop.shared.views.TextChatView = (functi
       // Scroll only if we're right at the bottom of the display.
       this.shouldScroll = node.scrollHeight === node.scrollTop + node.clientHeight;
     },
 
     componentDidUpdate: function() {
       if (this.shouldScroll) {
         // This ensures the paint is complete.
         window.requestAnimationFrame(function() {
-          var node = this.getDOMNode();
-          node.scrollTop = node.scrollHeight - node.clientHeight;
+          try {
+            var node = this.getDOMNode();
+            node.scrollTop = node.scrollHeight - node.clientHeight;
+          } catch (ex) {
+            console.error("TextChatEntriesView.componentDidUpdate exception", ex);
+          }
         }.bind(this));
       }
     },
 
     render: function() {
       if (!this.props.messageList.length) {
         return null;
       }
@@ -95,25 +99,24 @@ loop.shared.views.TextChatView = (functi
       return (
         React.createElement("div", {className: "text-chat-entries"}, 
           React.createElement("div", {className: "text-chat-scroller"}, 
             
               this.props.messageList.map(function(entry, i) {
                 if (entry.type === CHAT_MESSAGE_TYPES.SPECIAL) {
                   switch (entry.contentType) {
                     case CHAT_CONTENT_TYPES.ROOM_NAME:
-                      return React.createElement(TextChatRoomName, {message: entry.message});
+                      return React.createElement(TextChatRoomName, {key: i, message: entry.message});
                     case CHAT_CONTENT_TYPES.CONTEXT:
                       return (
-                        React.createElement("div", {className: "context-url-view-wrapper"}, 
+                        React.createElement("div", {key: i, className: "context-url-view-wrapper"}, 
                           React.createElement(sharedViews.ContextUrlView, {
                             allowClick: true, 
                             description: entry.message, 
                             dispatcher: this.props.dispatcher, 
-                            key: i, 
                             showContextTitle: true, 
                             thumbnail: entry.extraData.thumbnail, 
                             url: entry.extraData.location, 
                             useDesktopPaths: false})
                         )
                       );
                     default:
                       console.error("Unsupported contentType", entry.contentType);
@@ -256,18 +259,23 @@ loop.shared.views.TextChatView = (functi
         });
         hasNonSpecialMessages = !!messageList.length;
       }
 
       if (!this.props.showAlways && !this.state.textChatEnabled && !messageList.length) {
         return null;
       }
 
+      var textChatViewClasses = React.addons.classSet({
+        "text-chat-view": true,
+        "text-chat-disabled": !this.state.textChatEnabled
+      });
+
       return (
-        React.createElement("div", {className: "text-chat-view"}, 
+        React.createElement("div", {className: textChatViewClasses}, 
           React.createElement(TextChatEntriesView, {
             dispatcher: this.props.dispatcher, 
             messageList: messageList}), 
           React.createElement(TextChatInputView, {
             dispatcher: this.props.dispatcher, 
             showPlaceholder: !hasNonSpecialMessages, 
             textChatEnabled: this.state.textChatEnabled})
         )
--- a/browser/components/loop/content/shared/js/textChatView.jsx
+++ b/browser/components/loop/content/shared/js/textChatView.jsx
@@ -76,18 +76,22 @@ loop.shared.views.TextChatView = (functi
       // Scroll only if we're right at the bottom of the display.
       this.shouldScroll = node.scrollHeight === node.scrollTop + node.clientHeight;
     },
 
     componentDidUpdate: function() {
       if (this.shouldScroll) {
         // This ensures the paint is complete.
         window.requestAnimationFrame(function() {
-          var node = this.getDOMNode();
-          node.scrollTop = node.scrollHeight - node.clientHeight;
+          try {
+            var node = this.getDOMNode();
+            node.scrollTop = node.scrollHeight - node.clientHeight;
+          } catch (ex) {
+            console.error("TextChatEntriesView.componentDidUpdate exception", ex);
+          }
         }.bind(this));
       }
     },
 
     render: function() {
       if (!this.props.messageList.length) {
         return null;
       }
@@ -95,25 +99,24 @@ loop.shared.views.TextChatView = (functi
       return (
         <div className="text-chat-entries">
           <div className="text-chat-scroller">
             {
               this.props.messageList.map(function(entry, i) {
                 if (entry.type === CHAT_MESSAGE_TYPES.SPECIAL) {
                   switch (entry.contentType) {
                     case CHAT_CONTENT_TYPES.ROOM_NAME:
-                      return <TextChatRoomName message={entry.message}/>;
+                      return <TextChatRoomName key={i} message={entry.message}/>;
                     case CHAT_CONTENT_TYPES.CONTEXT:
                       return (
-                        <div className="context-url-view-wrapper">
+                        <div key={i} className="context-url-view-wrapper">
                           <sharedViews.ContextUrlView
                             allowClick={true}
                             description={entry.message}
                             dispatcher={this.props.dispatcher}
-                            key={i}
                             showContextTitle={true}
                             thumbnail={entry.extraData.thumbnail}
                             url={entry.extraData.location}
                             useDesktopPaths={false} />
                         </div>
                       );
                     default:
                       console.error("Unsupported contentType", entry.contentType);
@@ -256,18 +259,23 @@ loop.shared.views.TextChatView = (functi
         });
         hasNonSpecialMessages = !!messageList.length;
       }
 
       if (!this.props.showAlways && !this.state.textChatEnabled && !messageList.length) {
         return null;
       }
 
+      var textChatViewClasses = React.addons.classSet({
+        "text-chat-view": true,
+        "text-chat-disabled": !this.state.textChatEnabled
+      });
+
       return (
-        <div className="text-chat-view">
+        <div className={textChatViewClasses}>
           <TextChatEntriesView
             dispatcher={this.props.dispatcher}
             messageList={messageList} />
           <TextChatInputView
             dispatcher={this.props.dispatcher}
             showPlaceholder={!hasNonSpecialMessages}
             textChatEnabled={this.state.textChatEnabled} />
         </div>
--- a/browser/components/loop/ui/react-frame-component.js
+++ b/browser/components/loop/ui/react-frame-component.js
@@ -64,19 +64,23 @@ window.Frame = React.createClass({
       var iframeHead = childDoc.querySelector("head");
       var parentHeadChildren = document.querySelector("head").children;
 
       [].forEach.call(parentHeadChildren, function(parentHeadNode) {
 
         // if this node is a CSS stylesheet...
         if (isStyleSheet(parentHeadNode)) {
           // and it has a class different from the one that this frame does,
-          // return immediately instead of appending it.
-          if (parentHeadNode.hasAttribute("class") && this.props.cssClass &&
-            parentHeadNode.getAttribute("class") !== this.props.cssClass) {
+          // return immediately instead of appending it.  Note that this
+          // explicitly does not check for cssClass existence, because
+          // non-existence of cssClass will be different from a style
+          // element that does have a class on it, and we want it to return
+          // in that case.
+          if (parentHeadNode.hasAttribute("class") &&
+              parentHeadNode.getAttribute("class") !== this.props.cssClass) {
             return;
           }
         }
 
         iframeHead.appendChild(parentHeadNode.cloneNode(true));
       }.bind(this));
 
       var contents = React.createElement("div",
--- a/browser/components/loop/ui/ui-showcase.js
+++ b/browser/components/loop/ui/ui-showcase.js
@@ -288,33 +288,58 @@
     client: {},
     mozLoop: navigator.mozLoop,
     sdkDriver: mockSDK
   });
   var textChatStore = new loop.store.TextChatStore(dispatcher, {
     sdkDriver: mockSDK
   });
 
-  textChatStore.setStoreState({
-    // XXX Disabled until we start sorting out some of the layouts.
-    textChatEnabled: false
-  });
-
   // Update the text chat store with the room info.
   textChatStore.updateRoomInfo(new sharedActions.UpdateRoomInfo({
     roomName: "A Very Long Conversation Name",
     roomOwner: "fake",
     roomUrl: "http://showcase",
     urls: [{
       description: "A wonderful page!",
       location: "http://wonderful.invalid"
       // use the fallback thumbnail
     }]
   }));
 
+  textChatStore.setStoreState({textChatEnabled: true});
+
+  dispatcher.dispatch(new sharedActions.SendTextChatMessage({
+    contentType: loop.store.CHAT_CONTENT_TYPES.TEXT,
+    message: "Rheet!"
+  }));
+  dispatcher.dispatch(new sharedActions.ReceivedTextChatMessage({
+    contentType: loop.store.CHAT_CONTENT_TYPES.TEXT,
+    message: "Hi there"
+  }));
+  dispatcher.dispatch(new sharedActions.SendTextChatMessage({
+    contentType: loop.store.CHAT_CONTENT_TYPES.TEXT,
+    message: "Check out this menu from DNA Pizza:" +
+    " http://example.com/DNA/pizza/menu/lots-of-different-kinds-of-pizza/" +
+    "%8D%E0%B8%88%E0%B8%A1%E0%B8%A3%E0%8D%E0%B8%88%E0%B8%A1%E0%B8%A3%E0%"
+  }));
+  dispatcher.dispatch(new sharedActions.SendTextChatMessage({
+    contentType: loop.store.CHAT_CONTENT_TYPES.TEXT,
+    message: "Nowforareallylongwordwithoutspacesorpunctuationwhichshouldcause" +
+    "linewrappingissuesifthecssiswrong"
+  }));
+  dispatcher.dispatch(new sharedActions.ReceivedTextChatMessage({
+    contentType: loop.store.CHAT_CONTENT_TYPES.TEXT,
+    message: "That avocado monkey-brains pie sounds tasty!"
+  }));
+  dispatcher.dispatch(new sharedActions.SendTextChatMessage({
+    contentType: loop.store.CHAT_CONTENT_TYPES.TEXT,
+    message: "What time should we meet?"
+  }));
+
   loop.store.StoreMixin.register({
     activeRoomStore: activeRoomStore,
     conversationStore: conversationStore,
     feedbackStore: feedbackStore,
     textChatStore: textChatStore
   });
 
   // Local mocks
@@ -816,28 +841,28 @@
               React.createElement("div", {className: "standalone"}, 
                 React.createElement(UnsupportedDeviceView, {platform: "ios"})
               )
             )
           ), 
 
           React.createElement(Section, {name: "DesktopRoomConversationView"}, 
             React.createElement(FramedExample, {width: 298, height: 254, 
-              summary: "Desktop room conversation (invitation)"}, 
+              summary: "Desktop room conversation (invitation, text-chat inclusion/scrollbars don't happen in real client)"}, 
               React.createElement("div", {className: "fx-embedded"}, 
                 React.createElement(DesktopRoomConversationView, {
                   roomStore: invitationRoomStore, 
                   dispatcher: dispatcher, 
                   mozLoop: navigator.mozLoop, 
                   localPosterUrl: "sample-img/video-screen-local.png", 
                   roomState: ROOM_STATES.INIT})
               )
             ), 
 
-            React.createElement(FramedExample, {width: 298, height: 254, 
+            React.createElement(FramedExample, {width: 298, height: 394, dashed: true, 
               summary: "Desktop room conversation (loading)"}, 
               /* Hide scrollbars here. Rotating loading div overflows and causes
                scrollbars to appear */
               React.createElement("div", {className: "fx-embedded overflow-hidden"}, 
                 React.createElement(DesktopRoomConversationView, {
                   roomStore: desktopRoomStoreLoading, 
                   dispatcher: dispatcher, 
                   mozLoop: navigator.mozLoop, 
@@ -855,28 +880,28 @@
                   dispatcher: dispatcher, 
                   mozLoop: navigator.mozLoop, 
                   localPosterUrl: "sample-img/video-screen-local.png", 
                   remotePosterUrl: "sample-img/video-screen-remote.png", 
                   roomState: ROOM_STATES.HAS_PARTICIPANTS})
               )
             ), 
 
-            React.createElement(FramedExample, {width: 298, height: 254, 
+            React.createElement(FramedExample, {width: 298, height: 394, dashed: true, 
                            summary: "Desktop room conversation local face-mute"}, 
               React.createElement("div", {className: "fx-embedded"}, 
                 React.createElement(DesktopRoomConversationView, {
                   roomStore: desktopLocalFaceMuteRoomStore, 
                   dispatcher: dispatcher, 
                   mozLoop: navigator.mozLoop, 
                   remotePosterUrl: "sample-img/video-screen-remote.png"})
               )
             ), 
 
-            React.createElement(FramedExample, {width: 298, height: 254, 
+            React.createElement(FramedExample, {width: 298, height: 394, dashed: true, 
                            summary: "Desktop room conversation remote face-mute"}, 
               React.createElement("div", {className: "fx-embedded"}, 
                 React.createElement(DesktopRoomConversationView, {
                   roomStore: desktopRemoteFaceMuteRoomStore, 
                   dispatcher: dispatcher, 
                   mozLoop: navigator.mozLoop, 
                   localPosterUrl: "sample-img/video-screen-local.png"})
               )
@@ -1063,16 +1088,17 @@
                   activeRoomStore: failedRoomStore, 
                   isFirefox: false})
               )
             )
           ), 
 
           React.createElement(Section, {name: "StandaloneRoomView (Mobile)"}, 
             React.createElement(FramedExample, {width: 600, height: 480, cssClass: "standalone", 
+                           dashed: true, 
                            onContentsRendered: updatingActiveRoomStore.forcedUpdate, 
                            summary: "Standalone room conversation (has-participants, 600x480)"}, 
                 React.createElement("div", {className: "standalone"}, 
                   React.createElement(StandaloneRoomView, {
                     dispatcher: dispatcher, 
                     activeRoomStore: updatingActiveRoomStore, 
                     roomState: ROOM_STATES.HAS_PARTICIPANTS, 
                     isFirefox: true, 
@@ -1092,24 +1118,36 @@
                     isFirefox: true, 
                     localPosterUrl: "sample-img/video-screen-local.png", 
                     remotePosterUrl: "sample-img/video-screen-remote.png", 
                     screenSharePosterUrl: "sample-img/video-screen-terminal.png"})
                 )
             )
           ), 
 
-          React.createElement(Section, {name: "TextChatView (standalone)"}, 
-            React.createElement(FramedExample, {width: 200, height: 400, cssClass: "standalone", 
-                          summary: "Standalone Text Chat conversation (200 x 400)"}, 
+          React.createElement(Section, {name: "TextChatView"}, 
+            React.createElement(FramedExample, {width: 298, height: 160, dashed: true, 
+                           summary: "TextChatView: desktop embedded"}, 
+              React.createElement("div", {className: "fx-embedded"}, 
+                React.createElement(TextChatView, {dispatcher: dispatcher, 
+                              showAlways: false, 
+                              showRoomName: false})
+              )
+            ), 
+
+            React.createElement(FramedExample, {width: 200, height: 400, dashed: true, 
+                           cssClass: "standalone", 
+                           summary: "Standalone Text Chat conversation (200x400)"}, 
               React.createElement("div", {className: "standalone text-chat-example"}, 
-                React.createElement(TextChatView, {
-                  dispatcher: dispatcher, 
-                  showAlways: true, 
-                  showRoomName: true})
+                React.createElement("div", {className: "media-wrapper"}, 
+                  React.createElement(TextChatView, {
+                    dispatcher: dispatcher, 
+                    showAlways: true, 
+                    showRoomName: true})
+                )
               )
             )
           ), 
 
           React.createElement(Section, {name: "SVG icons preview", className: "svg-icons"}, 
             React.createElement(Example, {summary: "10x10"}, 
               React.createElement(SVGIcons, {size: "10x10"})
             ), 
--- a/browser/components/loop/ui/ui-showcase.jsx
+++ b/browser/components/loop/ui/ui-showcase.jsx
@@ -288,33 +288,58 @@
     client: {},
     mozLoop: navigator.mozLoop,
     sdkDriver: mockSDK
   });
   var textChatStore = new loop.store.TextChatStore(dispatcher, {
     sdkDriver: mockSDK
   });
 
-  textChatStore.setStoreState({
-    // XXX Disabled until we start sorting out some of the layouts.
-    textChatEnabled: false
-  });
-
   // Update the text chat store with the room info.
   textChatStore.updateRoomInfo(new sharedActions.UpdateRoomInfo({
     roomName: "A Very Long Conversation Name",
     roomOwner: "fake",
     roomUrl: "http://showcase",
     urls: [{
       description: "A wonderful page!",
       location: "http://wonderful.invalid"
       // use the fallback thumbnail
     }]
   }));
 
+  textChatStore.setStoreState({textChatEnabled: true});
+
+  dispatcher.dispatch(new sharedActions.SendTextChatMessage({
+    contentType: loop.store.CHAT_CONTENT_TYPES.TEXT,
+    message: "Rheet!"
+  }));
+  dispatcher.dispatch(new sharedActions.ReceivedTextChatMessage({
+    contentType: loop.store.CHAT_CONTENT_TYPES.TEXT,
+    message: "Hi there"
+  }));
+  dispatcher.dispatch(new sharedActions.SendTextChatMessage({
+    contentType: loop.store.CHAT_CONTENT_TYPES.TEXT,
+    message: "Check out this menu from DNA Pizza:" +
+    " http://example.com/DNA/pizza/menu/lots-of-different-kinds-of-pizza/" +
+    "%8D%E0%B8%88%E0%B8%A1%E0%B8%A3%E0%8D%E0%B8%88%E0%B8%A1%E0%B8%A3%E0%"
+  }));
+  dispatcher.dispatch(new sharedActions.SendTextChatMessage({
+    contentType: loop.store.CHAT_CONTENT_TYPES.TEXT,
+    message: "Nowforareallylongwordwithoutspacesorpunctuationwhichshouldcause" +
+    "linewrappingissuesifthecssiswrong"
+  }));
+  dispatcher.dispatch(new sharedActions.ReceivedTextChatMessage({
+    contentType: loop.store.CHAT_CONTENT_TYPES.TEXT,
+    message: "That avocado monkey-brains pie sounds tasty!"
+  }));
+  dispatcher.dispatch(new sharedActions.SendTextChatMessage({
+    contentType: loop.store.CHAT_CONTENT_TYPES.TEXT,
+    message: "What time should we meet?"
+  }));
+
   loop.store.StoreMixin.register({
     activeRoomStore: activeRoomStore,
     conversationStore: conversationStore,
     feedbackStore: feedbackStore,
     textChatStore: textChatStore
   });
 
   // Local mocks
@@ -816,28 +841,28 @@
               <div className="standalone">
                 <UnsupportedDeviceView platform="ios"/>
               </div>
             </Example>
           </Section>
 
           <Section name="DesktopRoomConversationView">
             <FramedExample width={298} height={254}
-              summary="Desktop room conversation (invitation)">
+              summary="Desktop room conversation (invitation, text-chat inclusion/scrollbars don't happen in real client)">
               <div className="fx-embedded">
                 <DesktopRoomConversationView
                   roomStore={invitationRoomStore}
                   dispatcher={dispatcher}
                   mozLoop={navigator.mozLoop}
                   localPosterUrl="sample-img/video-screen-local.png"
                   roomState={ROOM_STATES.INIT} />
               </div>
             </FramedExample>
 
-            <FramedExample width={298} height={254}
+            <FramedExample width={298} height={394} dashed={true}
               summary="Desktop room conversation (loading)">
               {/* Hide scrollbars here. Rotating loading div overflows and causes
                scrollbars to appear */}
               <div className="fx-embedded overflow-hidden">
                 <DesktopRoomConversationView
                   roomStore={desktopRoomStoreLoading}
                   dispatcher={dispatcher}
                   mozLoop={navigator.mozLoop}
@@ -855,28 +880,28 @@
                   dispatcher={dispatcher}
                   mozLoop={navigator.mozLoop}
                   localPosterUrl="sample-img/video-screen-local.png"
                   remotePosterUrl="sample-img/video-screen-remote.png"
                   roomState={ROOM_STATES.HAS_PARTICIPANTS} />
               </div>
             </FramedExample>
 
-            <FramedExample width={298} height={254}
+            <FramedExample width={298} height={394} dashed={true}
                            summary="Desktop room conversation local face-mute">
               <div className="fx-embedded">
                 <DesktopRoomConversationView
                   roomStore={desktopLocalFaceMuteRoomStore}
                   dispatcher={dispatcher}
                   mozLoop={navigator.mozLoop}
                   remotePosterUrl="sample-img/video-screen-remote.png" />
               </div>
             </FramedExample>
 
-            <FramedExample width={298} height={254}
+            <FramedExample width={298} height={394} dashed={true}
                            summary="Desktop room conversation remote face-mute">
               <div className="fx-embedded">
                 <DesktopRoomConversationView
                   roomStore={desktopRemoteFaceMuteRoomStore}
                   dispatcher={dispatcher}
                   mozLoop={navigator.mozLoop}
                   localPosterUrl="sample-img/video-screen-local.png" />
               </div>
@@ -1063,16 +1088,17 @@
                   activeRoomStore={failedRoomStore}
                   isFirefox={false} />
               </div>
             </FramedExample>
           </Section>
 
           <Section name="StandaloneRoomView (Mobile)">
             <FramedExample width={600} height={480} cssClass="standalone"
+                           dashed={true}
                            onContentsRendered={updatingActiveRoomStore.forcedUpdate}
                            summary="Standalone room conversation (has-participants, 600x480)">
                 <div className="standalone">
                   <StandaloneRoomView
                     dispatcher={dispatcher}
                     activeRoomStore={updatingActiveRoomStore}
                     roomState={ROOM_STATES.HAS_PARTICIPANTS}
                     isFirefox={true}
@@ -1092,24 +1118,36 @@
                     isFirefox={true}
                     localPosterUrl="sample-img/video-screen-local.png"
                     remotePosterUrl="sample-img/video-screen-remote.png"
                     screenSharePosterUrl="sample-img/video-screen-terminal.png" />
                 </div>
             </FramedExample>
           </Section>
 
-          <Section name="TextChatView (standalone)">
-            <FramedExample width={200} height={400} cssClass="standalone"
-                          summary="Standalone Text Chat conversation (200 x 400)">
+          <Section name="TextChatView">
+            <FramedExample width={298} height={160} dashed={true}
+                           summary="TextChatView: desktop embedded">
+              <div className="fx-embedded">
+                <TextChatView dispatcher={dispatcher}
+                              showAlways={false}
+                              showRoomName={false} />
+              </div>
+            </FramedExample>
+
+            <FramedExample width={200} height={400} dashed={true}
+                           cssClass="standalone"
+                           summary="Standalone Text Chat conversation (200x400)">
               <div className="standalone text-chat-example">
-                <TextChatView
-                  dispatcher={dispatcher}
-                  showAlways={true}
-                  showRoomName={true} />
+                <div className="media-wrapper">
+                  <TextChatView
+                    dispatcher={dispatcher}
+                    showAlways={true}
+                    showRoomName={true} />
+                </div>
               </div>
             </FramedExample>
           </Section>
 
           <Section name="SVG icons preview" className="svg-icons">
             <Example summary="10x10">
               <SVGIcons size="10x10"/>
             </Example>
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -161,16 +161,19 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource:///modules/ReaderParent.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AddonWatcher",
                                   "resource://gre/modules/AddonWatcher.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
                                   "resource://gre/modules/LightweightThemeManager.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
+                                  "resource://gre/modules/AppConstants.jsm");
+
 const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser";
 const PREF_PLUGINS_UPDATEURL  = "plugins.update.url";
 
 // Seconds of idle before trying to create a bookmarks backup.
 const BOOKMARKS_BACKUP_IDLE_TIME_SEC = 8 * 60;
 // Minimum interval between backups.  We try to not create more than one backup
 // per interval.
 const BOOKMARKS_BACKUP_MIN_INTERVAL_DAYS = 1;
@@ -1120,16 +1123,27 @@ BrowserGlue.prototype = {
       }
       catch (ex) { /* Don't break the default prompt if telemetry is broken. */ }
 
       if (isDefault) {
         let now = Date.now().toString().slice(0, -3);
         Services.prefs.setCharPref("browser.shell.mostRecentDateSetAsDefault", now);
       }
 
+      if (Services.prefs.getIntPref("browser.shell.windows10DefaultBrowserABTest") == -1) {
+        let abTest = Math.round(Math.random());
+        Services.prefs.setIntPref("browser.shell.windows10DefaultBrowserABTest", abTest);
+      }
+
+      if (AppConstants.isPlatformAndVersionAtLeast("win", "10")) {
+        let abTest = Services.prefs.getIntPref("browser.shell.windows10DefaultBrowserABTest");
+        let result = abTest * 2 + Number(isDefault);
+        Services.telemetry.getHistogramById("WIN_10_DEFAULT_BROWSER_AB_TEST").add(result);
+      }
+
       if (shouldCheck && !isDefault && !willRecoverSession) {
         Services.tm.mainThread.dispatch(function() {
           DefaultBrowserCheck.prompt(RecentWindow.getMostRecentBrowserWindow());
         }.bind(this), Ci.nsIThread.DISPATCH_NORMAL);
       }
     }
 
 #ifdef E10S_TESTING_ONLY
--- a/browser/components/shell/nsWindowsShellService.cpp
+++ b/browser/components/shell/nsWindowsShellService.cpp
@@ -739,16 +739,17 @@ nsWindowsShellService::SetDefaultBrowser
 
   if (aForAllUsers) {
     appHelperPath.AppendLiteral(" /SetAsDefaultAppGlobal");
   } else {
     appHelperPath.AppendLiteral(" /SetAsDefaultAppUser");
   }
 
   nsresult rv = LaunchHelper(appHelperPath);
+  nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
   if (NS_SUCCEEDED(rv) && IsWin8OrLater()) {
     if (aClaimAllTypes) {
       if (IsWin10OrLater()) {
         rv = LaunchModernSettingsDialogDefaultApps();
       } else {
         rv = LaunchControlPanelDefaultPrograms();
       }
       // The above call should never really fail, but just in case
@@ -756,38 +757,44 @@ nsWindowsShellService::SetDefaultBrowser
       if (NS_FAILED(rv)) {
         if (IsWin10OrLater()) {
           rv = InvokeHTTPOpenAsVerb();
         } else {
           rv = LaunchHTTPHandlerPane();
         }
       }
     } else {
-      // Windows 10 blocks attempts to load the HTTP Handler
-      // association dialog, so the modern Settings dialog
-      // is opened with the Default Apps view loaded.
+      // Windows 10 blocks attempts to load the
+      // HTTP Handler association dialog.
       if (IsWin10OrLater()) {
-        rv = InvokeHTTPOpenAsVerb();
+        if (prefs) {
+          int32_t abTest;
+          rv = prefs->GetIntPref("browser.shell.windows10DefaultBrowserABTest", &abTest);
+          if (NS_SUCCEEDED(rv) && abTest == 0) {
+            rv = InvokeHTTPOpenAsVerb();
+          } else {
+            rv = LaunchModernSettingsDialogDefaultApps();
+          }
+        }
       } else {
         rv = LaunchHTTPHandlerPane();
       }
 
       // The above call should never really fail, but just in case
       // fall back to showing control panel for all defaults
       if (NS_FAILED(rv)) {
         if (IsWin10OrLater()) {
           rv = LaunchModernSettingsDialogDefaultApps();
         } else {
           rv = LaunchControlPanelDefaultPrograms();
         }
       }
     }
   }
 
-  nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
   if (prefs) {
     (void) prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, true);
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
--- a/browser/devtools/framework/test/browser_toolbox_tool_ready.js
+++ b/browser/devtools/framework/test/browser_toolbox_tool_ready.js
@@ -13,16 +13,21 @@ function performChecks(target) {
     let toolIds = gDevTools.getToolDefinitionArray()
                            .filter(def => def.isTargetSupported(target))
                            .map(def => def.id);
 
     let toolbox;
     for (let index = 0; index < toolIds.length; index++) {
       let toolId = toolIds[index];
 
+      // FIXME Bug 1175850 - Enable storage inspector tests after upgrading for E10S
+      if (toolId === "storage") {
+        continue;
+      }
+
       info("About to open " + index + "/" + toolId);
       toolbox = yield gDevTools.showToolbox(target, toolId);
       ok(toolbox, "toolbox exists for " + toolId);
       is(toolbox.currentToolId, toolId, "currentToolId should be " + toolId);
 
       let panel = toolbox.getCurrentPanel();
       ok(panel.isReady, toolId + " panel should be ready");
     }
--- a/browser/devtools/framework/test/browser_toolbox_tool_remote_reopen.js
+++ b/browser/devtools/framework/test/browser_toolbox_tool_remote_reopen.js
@@ -44,16 +44,21 @@ function runTools(target) {
     let toolIds = gDevTools.getToolDefinitionArray()
                            .filter(def => def.isTargetSupported(target))
                            .map(def => def.id);
 
     let toolbox;
     for (let index = 0; index < toolIds.length; index++) {
       let toolId = toolIds[index];
 
+      // FIXME Bug 1175850 - Enable storage inspector tests after upgrading for E10S
+      if (toolId === "storage") {
+        continue;
+      }
+
       info("About to open " + index + "/" + toolId);
       toolbox = yield gDevTools.showToolbox(target, toolId, "window");
       ok(toolbox, "toolbox exists for " + toolId);
       is(toolbox.currentToolId, toolId, "currentToolId should be " + toolId);
 
       let panel = toolbox.getCurrentPanel();
       ok(panel.isReady, toolId + " panel should be ready");
     }
--- a/browser/devtools/framework/test/browser_toolbox_window_shortcuts.js
+++ b/browser/devtools/framework/test/browser_toolbox_window_shortcuts.js
@@ -38,16 +38,22 @@ function testShortcuts(aToolbox, aIndex)
   } else if (aIndex == toolIDs.length) {
     tidyUp();
     return;
   }
 
   toolbox = aToolbox;
   info("Toolbox fired a `ready` event");
 
+  // FIXME Bug 1175850 - Enable storage inspector tests after upgrading for E10S
+  if (toolIDs[aIndex] === "storage") {
+    testShortcuts(toolbox, aIndex + 1);
+    return;
+  }
+
   toolbox.once("select", selectCB);
 
   let key = gDevTools._tools.get(toolIDs[aIndex]).key;
   let toolModifiers = gDevTools._tools.get(toolIDs[aIndex]).modifiers;
   let modifiers = {
     accelKey: toolModifiers.includes("accel"),
     altKey: toolModifiers.includes("alt"),
     shiftKey: toolModifiers.includes("shift"),
--- a/browser/devtools/framework/toolbox.js
+++ b/browser/devtools/framework/toolbox.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/. */
 /* globals gDevTools, DOMHelpers, toolboxStrings, InspectorFront, Selection,
-   CommandUtils, DevToolsUtils, screenManager, oscpu, Hosts, is64Bit,
-   osString, showDoorhanger, getHighlighterUtils, getPerformanceFront */
+   CommandUtils, DevToolsUtils, Hosts, osString, showDoorhanger,
+   getHighlighterUtils, getPerformanceFront */
 
 "use strict";
 
 const MAX_ORDINAL = 99;
 const ZOOM_PREF = "devtools.toolbox.zoomValue";
 const SPLITCONSOLE_ENABLED_PREF = "devtools.toolbox.splitconsoleEnabled";
 const SPLITCONSOLE_HEIGHT_PREF = "devtools.toolbox.splitconsoleHeight";
 const MIN_ZOOM = 0.5;
@@ -56,29 +56,21 @@ loader.lazyRequireGetter(this, "Selectio
 loader.lazyRequireGetter(this, "InspectorFront",
   "devtools/server/actors/inspector", true);
 loader.lazyRequireGetter(this, "DevToolsUtils",
   "devtools/toolkit/DevToolsUtils");
 loader.lazyRequireGetter(this, "showDoorhanger",
   "devtools/shared/doorhanger", true);
 loader.lazyRequireGetter(this, "getPerformanceFront",
   "devtools/performance/front", true);
+loader.lazyRequireGetter(this, "system",
+  "devtools/toolkit/shared/system");
 loader.lazyGetter(this, "osString", () => {
   return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
 });
-loader.lazyGetter(this, "screenManager", () => {
-  return Cc["@mozilla.org/gfx/screenmanager;1"].getService(Ci.nsIScreenManager);
-});
-loader.lazyGetter(this, "oscpu", () => {
-  return Cc["@mozilla.org/network/protocol;1?name=http"]
-           .getService(Ci.nsIHttpProtocolHandler).oscpu;
-});
-loader.lazyGetter(this, "is64Bit", () => {
-  return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).is64Bit;
-});
 loader.lazyGetter(this, "registerHarOverlay", () => {
   return require("devtools/netmonitor/har/toolbox-overlay.js").register;
 });
 
 // White-list buttons that can be toggled to prevent adding prefs for
 // addons that have manually inserted toolbarbuttons into DOM.
 // (By default, supported target is only local tab)
 const ToolboxButtons = exports.ToolboxButtons = [
@@ -432,21 +424,19 @@ Toolbox.prototype = {
 
       this.emit("ready");
     }.bind(this)).then(null, console.error.bind(console));
   },
 
   _pingTelemetry: function() {
     this._telemetry.toolOpened("toolbox");
 
-    this._telemetry.logOncePerBrowserVersion(OS_HISTOGRAM,
-                                             this._getOsCpu());
-    this._telemetry.logOncePerBrowserVersion(OS_IS_64_BITS, is64Bit ? 1 : 0);
-    this._telemetry.logOncePerBrowserVersion(SCREENSIZE_HISTOGRAM,
-                                             this._getScreenDimensions());
+    this._telemetry.logOncePerBrowserVersion(OS_HISTOGRAM, system.getOSCPU());
+    this._telemetry.logOncePerBrowserVersion(OS_IS_64_BITS, system.is64Bit ? 1 : 0);
+    this._telemetry.logOncePerBrowserVersion(SCREENSIZE_HISTOGRAM, system.getScreenDimensions());
   },
 
   /**
    * Because our panels are lazy loaded this is a good place to watch for
    * "pref-changed" events.
    * @param  {String} event
    *         The event type, "pref-changed".
    * @param  {Object} data
@@ -1796,91 +1786,16 @@ Toolbox.prototype = {
    * Get the toolbox's notification box
    *
    * @return The notification box element.
    */
   getNotificationBox: function() {
     return this.doc.getElementById("toolbox-notificationbox");
   },
 
-  _getScreenDimensions: function() {
-    let width = {};
-    let height = {};
-
-    screenManager.primaryScreen.GetRect({}, {}, width, height);
-    let dims = width.value + "x" + height.value;
-
-    if (width.value < 800 || height.value < 600) {
-      return 0;
-    }
-    if (dims === "800x600") {
-      return 1;
-    }
-    if (dims === "1024x768") {
-      return 2;
-    }
-    if (dims === "1280x800") {
-      return 3;
-    }
-    if (dims === "1280x1024") {
-      return 4;
-    }
-    if (dims === "1366x768") {
-      return 5;
-    }
-    if (dims === "1440x900") {
-      return 6;
-    }
-    if (dims === "1920x1080") {
-      return 7;
-    }
-    if (dims === "2560×1440") {
-      return 8;
-    }
-    if (dims === "2560×1600") {
-      return 9;
-    }
-    if (dims === "2880x1800") {
-      return 10;
-    }
-    if (width.value > 2880 || height.value > 1800) {
-      return 12;
-    }
-
-    // Other dimension such as a VM.
-    return 11;
-  },
-
-  _getOsCpu: function() {
-    if (oscpu.includes("NT 5.1") || oscpu.includes("NT 5.2")) {
-      return 0;
-    }
-    if (oscpu.includes("NT 6.0")) {
-      return 1;
-    }
-    if (oscpu.includes("NT 6.1")) {
-      return 2;
-    }
-    if (oscpu.includes("NT 6.2")) {
-      return 3;
-    }
-    if (oscpu.includes("NT 6.3")) {
-      return 4;
-    }
-    if (oscpu.includes("OS X")) {
-      return 5;
-    }
-    if (oscpu.includes("Linux")) {
-      return 6;
-    }
-
-    // Other OS.
-    return 12;
-  },
-
   /**
    * Destroy the current host, and remove event listeners from its frame.
    *
    * @return {promise} to be resolved when the host is destroyed.
    */
   destroyHost: function() {
     // The host iframe's contentDocument may already be gone.
     if (this.doc) {
--- a/browser/devtools/jar.mn
+++ b/browser/devtools/jar.mn
@@ -94,30 +94,31 @@ browser.jar:
     content/browser/devtools/webaudioeditor/models.js                  (webaudioeditor/models.js)
     content/browser/devtools/webaudioeditor/controller.js              (webaudioeditor/controller.js)
     content/browser/devtools/webaudioeditor/views/utils.js             (webaudioeditor/views/utils.js)
     content/browser/devtools/webaudioeditor/views/context.js           (webaudioeditor/views/context.js)
     content/browser/devtools/webaudioeditor/views/inspector.js         (webaudioeditor/views/inspector.js)
     content/browser/devtools/webaudioeditor/views/properties.js        (webaudioeditor/views/properties.js)
     content/browser/devtools/webaudioeditor/views/automation.js        (webaudioeditor/views/automation.js)
     content/browser/devtools/performance.xul                           (performance/performance.xul)
-*   content/browser/devtools/performance/system.js                     (performance/system.js)
     content/browser/devtools/performance/performance-controller.js     (performance/performance-controller.js)
     content/browser/devtools/performance/performance-view.js           (performance/performance-view.js)
     content/browser/devtools/performance/views/overview.js             (performance/views/overview.js)
     content/browser/devtools/performance/views/toolbar.js              (performance/views/toolbar.js)
     content/browser/devtools/performance/views/details.js              (performance/views/details.js)
     content/browser/devtools/performance/views/details-subview.js      (performance/views/details-abstract-subview.js)
     content/browser/devtools/performance/views/details-waterfall.js    (performance/views/details-waterfall.js)
     content/browser/devtools/performance/views/details-js-call-tree.js      (performance/views/details-js-call-tree.js)
     content/browser/devtools/performance/views/details-js-flamegraph.js     (performance/views/details-js-flamegraph.js)
     content/browser/devtools/performance/views/details-memory-call-tree.js  (performance/views/details-memory-call-tree.js)
     content/browser/devtools/performance/views/details-memory-flamegraph.js (performance/views/details-memory-flamegraph.js)
+    content/browser/devtools/performance/views/details-optimizations.js     (performance/views/details-optimizations.js)
+    content/browser/devtools/performance/views/optimizations-list.js        (performance/views/optimizations-list.js)
+    content/browser/devtools/performance/views/frames-list.js               (performance/views/frames-list.js)
     content/browser/devtools/performance/views/recordings.js           (performance/views/recordings.js)
-    content/browser/devtools/performance/views/jit-optimizations.js    (performance/views/jit-optimizations.js)
     content/browser/devtools/commandline.css                           (commandline/commandline.css)
     content/browser/devtools/commandlineoutput.xhtml                   (commandline/commandlineoutput.xhtml)
     content/browser/devtools/commandlinetooltip.xhtml                  (commandline/commandlinetooltip.xhtml)
 *   content/browser/devtools/framework/toolbox-window.xul              (framework/toolbox-window.xul)
     content/browser/devtools/framework/toolbox-options.xul             (framework/toolbox-options.xul)
     content/browser/devtools/framework/toolbox-options.js              (framework/toolbox-options.js)
     content/browser/devtools/framework/toolbox.xul                     (framework/toolbox.xul)
     content/browser/devtools/framework/options-panel.css               (framework/options-panel.css)
--- a/browser/devtools/performance/modules/logic/recording-model.js
+++ b/browser/devtools/performance/modules/logic/recording-model.js
@@ -180,18 +180,17 @@ RecordingModel.prototype = {
       return Date.now() - this._localStartTime;
     } else {
       return this._duration;
     }
   },
 
   /**
    * Returns configuration object of specifying whether the recording
-   * was started withTicks, withMemory and withAllocations and other
-   * recording options.
+   * was started withTicks, withMemory and withAllocations, and other configurations.
    * @return object
    */
   getConfiguration: function () {
     return this._configuration;
   },
 
   /**
    * Gets the accumulated markers in the current recording.
--- a/browser/devtools/performance/modules/logic/tree-model.js
+++ b/browser/devtools/performance/modules/logic/tree-model.js
@@ -454,27 +454,28 @@ FrameNode.prototype = {
    */
   _computeInfo: function() {
     let categoryData = CATEGORY_MAPPINGS[this.category] || {};
     let parsedData = FrameUtils.parseLocation(this.location, this.line, this.column);
     parsedData.nodeType = "Frame";
     parsedData.categoryData = categoryData;
     parsedData.isContent = this.isContent;
     parsedData.isMetaCategory = this.isMetaCategory;
+    parsedData.hasOptimizations = this.hasOptimizations();
 
     return this._data = parsedData;
   },
 
   /**
    * Returns whether or not the frame node has an JITOptimizations model.
    *
    * @return {Boolean}
    */
   hasOptimizations: function () {
-    return !!this._optimizations;
+    return !this.isMetaCategory && !!this._optimizations;
   },
 
   /**
    * Returns the underlying JITOptimizations model representing
    * the optimization attempts occuring in this frame.
    *
    * @return {JITOptimizations|null}
    */
--- a/browser/devtools/performance/modules/widgets/graphs.js
+++ b/browser/devtools/performance/modules/widgets/graphs.js
@@ -5,18 +5,18 @@
 
 /**
  * This file contains the base line graph that all Performance line graphs use.
  */
 
 const { Cc, Ci, Cu, Cr } = require("chrome");
 const { Task } = require("resource://gre/modules/Task.jsm");
 const { Heritage } = require("resource:///modules/devtools/ViewHelpers.jsm");
-const { LineGraphWidget } = require("devtools/shared/widgets/Graphs");
-const { BarGraphWidget } = require("devtools/shared/widgets/Graphs");
+const LineGraphWidget = require("devtools/shared/widgets/LineGraphWidget");
+const BarGraphWidget = require("devtools/shared/widgets/BarGraphWidget");
 const { CanvasGraphUtils } = require("devtools/shared/widgets/Graphs");
 
 loader.lazyRequireGetter(this, "promise");
 loader.lazyRequireGetter(this, "EventEmitter",
   "devtools/toolkit/event-emitter");
 
 loader.lazyRequireGetter(this, "colorUtils",
   "devtools/css-color", true);
--- a/browser/devtools/performance/modules/widgets/tree-view.js
+++ b/browser/devtools/performance/modules/widgets/tree-view.js
@@ -11,16 +11,18 @@
 const { Cc, Ci, Cu, Cr } = require("chrome");
 const { L10N } = require("devtools/performance/global");
 const { Heritage } = require("resource:///modules/devtools/ViewHelpers.jsm");
 const { AbstractTreeItem } = require("resource:///modules/devtools/AbstractTreeItem.jsm");
 
 const MILLISECOND_UNITS = L10N.getStr("table.ms");
 const PERCENTAGE_UNITS = L10N.getStr("table.percentage");
 const URL_LABEL_TOOLTIP = L10N.getStr("table.url.tooltiptext");
+const VIEW_OPTIMIZATIONS_TOOLTIP = L10N.getStr("table.view-optimizations.tooltiptext");
+
 const CALL_TREE_INDENTATION = 16; // px
 
 const DEFAULT_SORTING_PREDICATE = (frameA, frameB) => {
   let dataA = frameA.getDisplayedData();
   let dataB = frameB.getDisplayedData();
   if (this.inverted) {
     // Invert trees, sort by selfPercentage, and then totalPercentage
     if (dataA.selfPercentage === dataB.selfPercentage) {
@@ -80,20 +82,24 @@ const sum = vals => vals.reduce((a, b) =
  * @param number autoExpandDepth [optional]
  *        The depth to which the tree should automatically expand. Defualts to
  *        the caller's `autoExpandDepth` if a caller exists, otherwise defaults
  *        to DEFAULT_AUTO_EXPAND_DEPTH.
  * @param object visibleCells
  *        An object specifying which cells are visible in the tree. Defaults to
  *        the caller's `visibleCells` if a caller exists, otherwise defaults
  *        to DEFAULT_VISIBLE_CELLS.
+ * @param boolean showOptimizationHint [optional]
+ *        Whether or not to show an icon indicating if the frame has optimization
+ *        data.
  */
 function CallView({
   caller, frame, level, hidden, inverted,
-  sortingPredicate, autoExpandDepth, visibleCells
+  sortingPredicate, autoExpandDepth, visibleCells,
+  showOptimizationHint
 }) {
   AbstractTreeItem.call(this, {
     parent: caller,
     level: level|0 - (hidden ? 1 : 0)
   });
 
   this.sortingPredicate = sortingPredicate != null
     ? sortingPredicate
@@ -109,16 +115,17 @@ function CallView({
     ? visibleCells
     : caller ? caller.visibleCells
              : Object.create(DEFAULT_VISIBLE_CELLS);
 
   this.caller = caller;
   this.frame = frame;
   this.hidden = hidden;
   this.inverted = inverted;
+  this.showOptimizationHint = showOptimizationHint;
 
   this._onUrlClick = this._onUrlClick.bind(this);
 };
 
 CallView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
   /**
    * Creates the view for this tree node.
    * @param nsIDOMNode document
@@ -251,16 +258,26 @@ CallView.prototype = Heritage.extend(Abs
   },
   _createFunctionCell: function(doc, arrowNode, frameName, frameInfo, frameLevel) {
     let cell = doc.createElement("hbox");
     cell.className = "call-tree-cell";
     cell.style.MozMarginStart = (frameLevel * CALL_TREE_INDENTATION) + "px";
     cell.setAttribute("type", "function");
     cell.appendChild(arrowNode);
 
+    // Render optimization link to JIT view if the frame
+    // has optimizations
+    if (this.root.showOptimizationHint && frameInfo.hasOptimizations && !frameInfo.isMetaCategory) {
+      let icon = doc.createElement("description");
+      icon.setAttribute("tooltiptext", VIEW_OPTIMIZATIONS_TOOLTIP);
+      icon.setAttribute("type", "linkable");
+      icon.className = "opt-icon";
+      cell.appendChild(icon);
+    }
+
     // Don't render a name label node if there's no function name. A different
     // location label node will be rendered instead.
     if (frameName) {
       let nameNode = doc.createElement("description");
       nameNode.className = "plain call-tree-name";
       nameNode.setAttribute("flex", "1");
       nameNode.setAttribute("crop", "end");
       nameNode.setAttribute("value", frameName);
@@ -275,16 +292,17 @@ CallView.prototype = Heritage.extend(Abs
     // Don't render an expando-arrow for leaf nodes.
     let hasDescendants = Object.keys(this.frame.calls).length > 0;
     if (!hasDescendants) {
       arrowNode.setAttribute("invisible", "");
     }
 
     return cell;
   },
+
   _appendFunctionDetailsCells: function(doc, cell, frameInfo) {
     if (frameInfo.fileName) {
       let urlNode = doc.createElement("description");
       urlNode.className = "plain call-tree-url";
       urlNode.setAttribute("flex", "1");
       urlNode.setAttribute("crop", "end");
       urlNode.setAttribute("value", frameInfo.fileName);
       urlNode.setAttribute("tooltiptext", URL_LABEL_TOOLTIP + " → " + frameInfo.url);
--- a/browser/devtools/performance/performance-controller.js
+++ b/browser/devtools/performance/performance-controller.js
@@ -1,22 +1,28 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
+const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
+const { devtools: loader } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
+const require = loader.require;
+
 const { Task } = require("resource://gre/modules/Task.jsm");
 const { Heritage, ViewHelpers, WidgetMethods } = require("resource:///modules/devtools/ViewHelpers.jsm");
 
 loader.lazyRequireGetter(this, "Services");
 loader.lazyRequireGetter(this, "promise");
 loader.lazyRequireGetter(this, "EventEmitter",
   "devtools/toolkit/event-emitter");
 loader.lazyRequireGetter(this, "DevToolsUtils",
   "devtools/toolkit/DevToolsUtils");
+loader.lazyRequireGetter(this, "system",
+  "devtools/toolkit/shared/system");
 
 // Logic modules
 
 loader.lazyRequireGetter(this, "L10N",
   "devtools/performance/global", true);
 loader.lazyRequireGetter(this, "TIMELINE_BLUEPRINT",
   "devtools/performance/markers", true);
 loader.lazyRequireGetter(this, "RecordingUtils",
@@ -524,17 +530,17 @@ let PerformanceController = {
   getMultiprocessStatus: function () {
     // 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 (gDevTools.testing) {
       return { supported: true, enabled: true };
     }
-    let supported = SYSTEM.MULTIPROCESS_SUPPORTED;
+    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 { supported, enabled };
   },
 
   /**
    * Called on init, sets an `e10s` attribute on the main view container with
--- a/browser/devtools/performance/performance.xul
+++ b/browser/devtools/performance/performance.xul
@@ -9,30 +9,31 @@
 <?xml-stylesheet href="chrome://browser/skin/devtools/performance.css" type="text/css"?>
 <!DOCTYPE window [
   <!ENTITY % profilerDTD SYSTEM "chrome://browser/locale/devtools/profiler.dtd">
   %profilerDTD;
 ]>
 
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <script src="chrome://browser/content/devtools/theme-switching.js"/>
-  <script type="application/javascript" src="performance/system.js"/>
   <script type="application/javascript" src="performance/performance-controller.js"/>
   <script type="application/javascript" src="performance/performance-view.js"/>
   <script type="application/javascript" src="performance/views/overview.js"/>
   <script type="application/javascript" src="performance/views/toolbar.js"/>
   <script type="application/javascript" src="performance/views/details-subview.js"/>
   <script type="application/javascript" src="performance/views/details-waterfall.js"/>
   <script type="application/javascript" src="performance/views/details-js-call-tree.js"/>
   <script type="application/javascript" src="performance/views/details-js-flamegraph.js"/>
   <script type="application/javascript" src="performance/views/details-memory-call-tree.js"/>
   <script type="application/javascript" src="performance/views/details-memory-flamegraph.js"/>
+  <script type="application/javascript" src="performance/views/details-optimizations.js"/>
   <script type="application/javascript" src="performance/views/details.js"/>
   <script type="application/javascript" src="performance/views/recordings.js"/>
-  <script type="application/javascript" src="performance/views/jit-optimizations.js"/>
+  <script type="application/javascript" src="performance/views/optimizations-list.js"/>
+  <script type="application/javascript" src="performance/views/frames-list.js"/>
 
   <popupset id="performance-options-popupset">
     <menupopup id="performance-filter-menupopup"/>
     <menupopup id="performance-options-menupopup">
       <menuitem id="option-show-platform-data"
                 type="checkbox"
                 data-pref="show-platform-data"
                 label="&profilerUI.showPlatformData;"
@@ -135,16 +136,21 @@
                          label="Allocations Tree"
                          hidden="true"
                          data-view="memory-calltree" />
           <toolbarbutton id="select-memory-flamegraph-view"
                          class="devtools-toolbarbutton devtools-button"
                          label="Allocations Chart"
                          hidden="true"
                          data-view="memory-flamegraph" />
+          <toolbarbutton id="select-optimizations-view"
+                         class="devtools-toolbarbutton devtools-button"
+                         label="Optimizations"
+                         hidden="true"
+                         data-view="optimizations" />
         </hbox>
         <spacer flex="1"></spacer>
         <hbox id="performance-toolbar-controls-options"
               class="devtools-toolbarbutton-group">
           <toolbarbutton id="performance-options-button"
                          class="devtools-toolbarbutton devtools-option-toolbarbutton"
                          popup="performance-options-menupopup"
                          tooltiptext="&profilerUI.options.gear.tooltiptext;"/>
@@ -288,30 +294,16 @@
                     <label class="plain call-tree-header"
                            type="function"
                            crop="end"
                            value="&profilerUI.table.function;"
                            tooltiptext="&profilerUI.table.function.tooltip;"/>
                   </hbox>
                   <vbox class="call-tree-cells-container" flex="1"/>
                 </vbox>
-
-                <splitter id="js-call-tree-splitter" class="devtools-side-splitter"/>
-
-                <vbox id="jit-optimizations-view" hidden="true">
-                  <toolbar id="jit-optimizations-toolbar" class="devtools-toolbar">
-                    <hbox id="jit-optimizations-header">
-                      <span class="jit-optimizations-title">&profilerUI.JITOptimizationsTitle;</span>
-                      <span class="header-function-name" />
-                      <span class="header-file opt-url debugger-link" />
-                      <span class="header-line opt-line" />
-                    </hbox>
-                  </toolbar>
-                  <vbox id="jit-optimizations-raw-view"></vbox>
-                </vbox>
               </hbox>
 
               <!-- JS FlameChart -->
               <hbox id="js-flamegraph-view" flex="1">
               </hbox>
 
               <!-- Memory Tree -->
               <vbox id="memory-calltree-view" flex="1">
@@ -333,15 +325,55 @@
                 </hbox>
                 <vbox class="call-tree-cells-container" flex="1"/>
               </vbox>
 
               <!-- Memory FlameChart -->
               <hbox id="memory-flamegraph-view" flex="1">
               </hbox>
 
+              <!-- JIT View -->
+              <hbox id="optimizations-view" flex="1">
+                <hbox id="graph-placeholder" flex="1">
+                </hbox>
+                <splitter id="optimizations-splitter" class="devtools-side-splitter"/>
+                <tabbox id="optimizations-tabs"
+                        class="devtools-sidebar-tabs"
+                        handleCtrlTab="false">
+                  <tabs>
+                    <tab id="optimizations-optimizations-tab"
+                         label="Optimizations" />
+                    <tab id="optimizations-frames-tab"
+                         label="Frames" />
+                  </tabs>
+                  <tabpanels flex="1">
+
+                    <!-- Optimizations Panel -->
+                    <tabpanel id="optimizations-tabpanel"
+                              class="tabpanel-content">
+                      <vbox id="jit-optimizations-view">
+                        <toolbar id="jit-optimizations-toolbar" class="devtools-toolbar">
+                          <hbox id="jit-optimizations-header">
+                            <span class="jit-optimizations-title">&profilerUI.JITOptimizationsTitle;</span>
+                            <span class="header-function-name" />
+                            <span class="header-file opt-url debugger-link" />
+                            <span class="header-line opt-line" />
+                          </hbox>
+                        </toolbar>
+                        <vbox id="jit-optimizations-raw-view"></vbox>
+                      </vbox>
+                    </tabpanel>
+
+                    <!-- Frames Panel -->
+                    <tabpanel id="frames-tabpanel"
+                              class="tabpanel-content">
+                    </tabpanel>
+                  </tabpanels>
+                </tabbox>
+              </hbox>
+              <!-- /JIT View -->
             </deck>
           </deck>
         </vbox>
       </deck>
     </vbox>
   </hbox>
 </window>
deleted file mode 100644
--- a/browser/devtools/performance/system.js
+++ /dev/null
@@ -1,20 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-/**
- * A dump file to attach preprocessing directives consumable to the controller
- * without littering our code with directives.
- */
-
-const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
-const { devtools: loader } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
-const require = loader.require;
-
-const SYSTEM = {};
-
-// If e10s is possible on the platform.
-#ifdef E10S_TESTING_ONLY
-SYSTEM.MULTIPROCESS_SUPPORTED = true;
-#endif
--- a/browser/devtools/performance/test/browser.ini
+++ b/browser/devtools/performance/test/browser.ini
@@ -61,18 +61,18 @@ support-files =
 [browser_perf-front-profiler-02.js]
 [browser_perf-front-profiler-03.js]
 [browser_perf-front-profiler-04.js]
 #[browser_perf-front-profiler-05.js] bug 1077464
 #[browser_perf-front-profiler-06.js]
 [browser_perf-front-01.js]
 [browser_perf-front-02.js]
 [browser_perf-highlighted.js]
-[browser_perf-jit-view-01.js]
-[browser_perf-jit-view-02.js]
+#[browser_perf-jit-view-01.js] bug 1176056
+#[browser_perf-jit-view-02.js] bug 1176056
 [browser_perf-loading-01.js]
 [browser_perf-loading-02.js]
 [browser_perf-marker-details-01.js]
 skip-if = os == 'linux' # Bug 1172120
 [browser_perf-options-01.js]
 [browser_perf-options-02.js]
 [browser_perf-options-03.js]
 [browser_perf-options-invert-call-tree-01.js]
@@ -132,15 +132,16 @@ skip-if = os == 'linux' # Bug 1172120
 [browser_profiler_tree-view-03.js]
 [browser_profiler_tree-view-04.js]
 [browser_profiler_tree-view-05.js]
 [browser_profiler_tree-view-06.js]
 [browser_profiler_tree-view-07.js]
 [browser_profiler_tree-view-08.js]
 [browser_profiler_tree-view-09.js]
 [browser_profiler_tree-view-10.js]
+[browser_profiler_tree-view-11.js]
 [browser_timeline-filters-01.js]
 [browser_timeline-filters-02.js]
 [browser_timeline-waterfall-background.js]
 [browser_timeline-waterfall-generic.js]
 [browser_timeline-waterfall-rerender.js]
 [browser_timeline-waterfall-sidebar.js]
 skip-if = os == 'linux' # Bug 1161817
--- a/browser/devtools/performance/test/browser_perf-marker-details-01.js
+++ b/browser/devtools/performance/test/browser_perf-marker-details-01.js
@@ -18,69 +18,77 @@ function* spawnTest() {
     return { submarkers: markers };
   };
 
   const MARKER_TYPES = [
     "Styles", "Reflow", "Paint", "ConsoleTime", "TimeStamp"
   ];
 
   yield startRecording(panel);
+  ok(true, "Recording has started.");
+
   yield waitUntil(() => {
-    // Wait until we get 3 different markers.
+    // Wait until we get all the different markers.
     let markers = PerformanceController.getCurrentRecording().getMarkers();
     return MARKER_TYPES.every(type => markers.some(m => m.name === type));
   });
-  yield stopRecording(panel);
 
-  // Select everything
-  let timeline = OverviewView.graphs.get("timeline");
-  let rerendered = WaterfallView.once(EVENTS.WATERFALL_RENDERED);
-  timeline.setSelection({ start: 0, end: timeline.width });
-  yield rerendered;
+  yield stopRecording(panel);
+  ok(true, "Recording has ended.");
+
+  info("No need to select everything in the timeline.");
+  info("All the markers should be displayed by default.");
 
   let bars = $$(".waterfall-marker-bar");
   let markers = PerformanceController.getCurrentRecording().getMarkers();
 
+  info(`Got ${bars.length} bars and ${markers.length} markers.`);
+  info("Markers types from datasrc: " + Array.map(markers, e => e.name));
+  info("Markers names from sidebar: " + Array.map(bars, e => e.parentNode.parentNode.querySelector(".waterfall-marker-name").getAttribute("value")));
+
   ok(bars.length >= MARKER_TYPES.length, `Got at least ${MARKER_TYPES.length} markers (1)`);
   ok(markers.length >= MARKER_TYPES.length, `Got at least ${MARKER_TYPES.length} markers (2)`);
 
   const tests = {
     ConsoleTime: function (marker) {
+      info("Got `ConsoleTime` marker with data: " + JSON.stringify(marker));
       shouldHaveStack($, "startStack", marker);
       shouldHaveStack($, "endStack", marker);
       shouldHaveLabel($, "Timer Name:", "!!!", marker);
       return true;
     },
     TimeStamp: function (marker) {
+      info("Got `TimeStamp` marker with data: " + JSON.stringify(marker));
       shouldHaveLabel($, "Label:", "go", marker);
       shouldHaveStack($, "stack", marker);
       return true;
     },
     Styles: function (marker) {
+      info("Got `Styles` marker with data: " + JSON.stringify(marker));
       if (marker.restyleHint) {
         shouldHaveLabel($, "Restyle Hint:", marker.restyleHint.replace(/eRestyle_/g, ""), marker);
       }
       if (marker.stack) {
         shouldHaveStack($, "stack", marker);
         return true;
       }
     },
     Reflow: function (marker) {
+      info("Got `Reflow` marker with data: " + JSON.stringify(marker));
       if (marker.stack) {
         shouldHaveStack($, "stack", marker);
         return true;
       }
     }
   };
 
   // Keep track of all marker tests that are finished so we only
   // run through each marker test once, so we don't spam 500 redundant
   // tests.
   let testsDone = [];
-  let TOTAL_TESTS = 4;
 
   for (let i = 0; i < bars.length; i++) {
     let bar = bars[i];
     let m = markers[i];
     EventUtils.sendMouseEvent({ type: "mousedown" }, bar);
 
     if (tests[m.name]) {
       if (testsDone.indexOf(m.name) === -1) {
@@ -88,17 +96,17 @@ function* spawnTest() {
         if (fullTestComplete) {
           testsDone.push(m.name);
         }
       }
     } else {
       info(`TODO: Need to add marker details tests for ${m.name}`);
     }
 
-    if (testsDone.length === TOTAL_TESTS) {
+    if (testsDone.length === Object.keys(tests).length) {
       break;
     }
   }
 
   yield teardown(panel);
   finish();
 }
 
--- a/browser/devtools/performance/test/browser_perf-options-enable-optimizations.js
+++ b/browser/devtools/performance/test/browser_perf-options-enable-optimizations.js
@@ -1,44 +1,45 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Tests that `enable-jit-optimizations` sets the recording to subsequently
- * display optimizations info.
+ * enable the Optimizations View.
  */
 function* spawnTest() {
   let { panel } = yield initPerformance(SIMPLE_URL);
-  let { EVENTS, PerformanceController, $, DetailsView, JsCallTreeView } = panel.panelWin;
+  let { EVENTS, PerformanceController, $, DetailsView, WaterfallView, OptimizationsView } = panel.panelWin;
   Services.prefs.setBoolPref(JIT_PREF, true);
 
 
   yield startRecording(panel);
-  let rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
+  let rendered = once(OptimizationsView, EVENTS.OPTIMIZATIONS_RENDERED);
   yield stopRecording(panel);
 
-  yield DetailsView.selectView("js-calltree");
-  ok(DetailsView.isViewSelected(JsCallTreeView), "The call tree is now selected.");
+  yield DetailsView.selectView("optimizations");
+  ok(DetailsView.isViewSelected(OptimizationsView), "The Optimizations View is now selected.");
   yield rendered;
 
   let recording = PerformanceController.getCurrentRecording();
   is(recording.getConfiguration().withJITOptimizations, true, "recording model has withJITOptimizations as true");
 
   // Set back to false, should not affect display of first recording
   info("Disabling enable-jit-optimizations");
   Services.prefs.setBoolPref(JIT_PREF, false);
-  is($("#jit-optimizations-view").hidden, false, "JIT Optimizations panel is displayed when feature enabled.");
+  is($("#select-optimizations-view").hidden, false,
+    "JIT Optimizations selector still available since the recording has it enabled.");
 
   yield startRecording(panel);
-  rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
+  rendered = once(WaterfallView, EVENTS.WATERFALL_RENDERED);
   yield stopRecording(panel);
 
-  yield DetailsView.selectView("js-calltree");
-  ok(DetailsView.isViewSelected(JsCallTreeView), "The call tree is now selected.");
+  ok(DetailsView.isViewSelected(WaterfallView), "The waterfall view is now selected.");
   yield rendered;
 
   recording = PerformanceController.getCurrentRecording();
   is(recording.getConfiguration().withJITOptimizations, false, "recording model has withJITOptimizations as false");
-  is($("#jit-optimizations-view").hidden, true, "JIT Optimizations panel is hidden when feature disabled");
+  is($("#select-optimizations-view").hidden, true,
+    "JIT Optimizations selector is hidden if recording did not enable optimizations.");
 
   yield teardown(panel);
   finish();
 }
--- a/browser/devtools/performance/test/browser_perf-recording-model-02.js
+++ b/browser/devtools/performance/test/browser_perf-recording-model-02.js
@@ -8,19 +8,19 @@
 let BUFFER_SIZE = 20000;
 
 function* spawnTest() {
   let { target, front } = yield initBackend(SIMPLE_URL, { TEST_MOCK_PROFILER_CHECK_TIMER: 10 });
   let config = { bufferSize: BUFFER_SIZE };
 
   let model = yield front.startRecording(config);
   let [_, stats] = yield onceSpread(front, "profiler-status");
-  is(stats.totalSize, BUFFER_SIZE, `profiler-status event has correct totalSize: ${stats.totalSize}`);
-  ok(stats.position < BUFFER_SIZE, `profiler-status event has correct position: ${stats.position}`);
-  is(stats.generation, 0, `profiler-status event has correct generation: ${stats.generation}`);
+  is(stats.totalSize, BUFFER_SIZE, `profiler-status event has totalSize: ${stats.totalSize}`);
+  ok(stats.position < BUFFER_SIZE, `profiler-status event has position: ${stats.position}`);
+  ok(stats.generation >= 0, `profiler-status event has generation: ${stats.generation}`);
   ok(stats.isActive, `profiler-status event is isActive`);
   is(typeof stats.currentTime, "number", `profiler-status event has currentTime`);
 
   // Halt once more for a buffer status to ensure we're beyond 0
   yield once(front, "profiler-status");
 
   let lastBufferStatus = 0;
   let checkCount = 0;
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/test/browser_profiler_tree-view-11.js
@@ -0,0 +1,153 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests that if a recording set `withJITOptimizations` on, then an
+ * icon is next to the frame with optimizations
+ */
+
+const RecordingUtils = devtools.require("devtools/performance/recording-utils");
+const { CATEGORY_MASK } = devtools.require("devtools/performance/global");
+
+function* spawnTest() {
+  let { panel } = yield initPerformance(SIMPLE_URL);
+  let { EVENTS, $, $$, window, PerformanceController } = panel.panelWin;
+  let { OverviewView, DetailsView, JITOptimizationsView, JsCallTreeView, RecordingsView } = panel.panelWin;
+
+  let profilerData = { threads: [gThread] };
+
+  Services.prefs.setBoolPref(JIT_PREF, true);
+  Services.prefs.setBoolPref(PLATFORM_DATA_PREF, false);
+  Services.prefs.setBoolPref(INVERT_PREF, false);
+
+  // Make two recordings, so we have one to switch to later, as the
+  // second one will have fake sample data
+  yield startRecording(panel);
+  yield stopRecording(panel);
+
+  yield DetailsView.selectView("js-calltree");
+
+  yield injectAndRenderProfilerData();
+
+  let rows = $$("#js-calltree-view .call-tree-item");
+  is(rows.length, 4, "4 call tree rows exist");
+  for (let row of rows) {
+    let name = $(".call-tree-name", row).value;
+    switch (name) {
+      case "A":
+        ok($(".opt-icon", row), "found an opt icon on a leaf node with opt data");
+        break;
+      case "C":
+        ok(!$(".opt-icon", row), "frames without opt data do not have an icon");
+        break;
+      case "Gecko":
+        ok(!$(".opt-icon", row), "meta category frames with opt data do not have an icon");
+        break;
+      case "(root)":
+        ok(!$(".opt-icon", row), "root frame certainly does not have opt data");
+        break;
+      default:
+        ok(false, `Unidentified frame: ${name}`);
+        break;
+    }
+  }
+
+  yield teardown(panel);
+  finish();
+
+  function *injectAndRenderProfilerData() {
+    // Get current recording and inject our mock data
+    info("Injecting mock profile data");
+    let recording = PerformanceController.getCurrentRecording();
+    recording._profile = profilerData;
+
+    // Force a rerender
+    let rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
+    JsCallTreeView.render(OverviewView.getTimeInterval());
+    yield rendered;
+  }
+}
+
+let gUniqueStacks = new RecordingUtils.UniqueStacks();
+
+function uniqStr(s) {
+  return gUniqueStacks.getOrAddStringIndex(s);
+}
+
+// Since deflateThread doesn't handle deflating optimization info, use
+// placeholder names A_O1, B_O2, and B_O3, which will be used to manually
+// splice deduped opts into the profile.
+let gThread = RecordingUtils.deflateThread({
+  samples: [{
+    time: 0,
+    frames: [
+      { location: "(root)" }
+    ]
+  }, {
+    time: 5,
+    frames: [
+      { location: "(root)" },
+      { location: "A (http://foo:1)" },
+    ]
+  }, {
+    time: 5 + 1,
+    frames: [
+      { location: "(root)" },
+      { location: "C (http://foo/bar/baz:56)" }
+    ]
+  }, {
+    time: 5 + 1 + 2,
+    frames: [
+      { location: "(root)" },
+      { category: CATEGORY_MASK("other"),  location: "PlatformCode" }
+    ]
+  }],
+  markers: []
+}, gUniqueStacks);
+
+// 3 RawOptimizationSites
+let gRawSite1 = {
+  _testFrameInfo: { name: "A", line: "12", file: "@baz" },
+  line: 12,
+  column: 2,
+  types: [{
+    mirType: uniqStr("Object"),
+    site: uniqStr("A (http://foo/bar/bar:12)"),
+    typeset: [{
+        keyedBy: uniqStr("constructor"),
+        name: uniqStr("Foo"),
+        location: uniqStr("A (http://foo/bar/baz:12)")
+    }, {
+        keyedBy: uniqStr("primitive"),
+        location: uniqStr("self-hosted")
+    }]
+  }],
+  attempts: {
+    schema: {
+      outcome: 0,
+      strategy: 1
+    },
+    data: [
+      [uniqStr("Failure1"), uniqStr("SomeGetter1")],
+      [uniqStr("Failure2"), uniqStr("SomeGetter2")],
+      [uniqStr("Failure3"), uniqStr("SomeGetter3")]
+    ]
+  }
+};
+
+gThread.frameTable.data.forEach((frame) => {
+  const LOCATION_SLOT = gThread.frameTable.schema.location;
+  const OPTIMIZATIONS_SLOT = gThread.frameTable.schema.optimizations;
+
+  let l = gThread.stringTable[frame[LOCATION_SLOT]];
+  switch (l) {
+  case "A (http://foo:1)":
+    frame[LOCATION_SLOT] = uniqStr("A (http://foo:1)");
+    frame[OPTIMIZATIONS_SLOT] = gRawSite1;
+    break;
+  case "PlatformCode":
+    frame[LOCATION_SLOT] = uniqStr("PlatformCode");
+    frame[OPTIMIZATIONS_SLOT] = gRawSite1;
+    break;
+  }
+});
--- a/browser/devtools/performance/test/browser_timeline-filters-01.js
+++ b/browser/devtools/performance/test/browser_timeline-filters-01.js
@@ -20,16 +20,17 @@ function* spawnTest() {
     // Wait until we get 3 different markers.
     let markers = PerformanceController.getCurrentRecording().getMarkers();
     return markers.some(m => m.name == "Styles") &&
            markers.some(m => m.name == "Reflow") &&
            markers.some(m => m.name == "Paint");
   });
 
   yield stopRecording(panel);
+  ok(true, "Recording has ended.");
 
   // Push some fake markers of a type we do not have a blueprint for
   let markers = PerformanceController.getCurrentRecording().getMarkers();
   let endTime = markers[markers.length - 1].end;
   markers.push({ name: "CustomMarker", start: endTime + EPSILON, end: endTime + (EPSILON * 2) });
   markers.push({ name: "CustomMarker", start: endTime + (EPSILON * 3), end: endTime + (EPSILON * 4) });
 
   // Invalidate marker cache
--- a/browser/devtools/performance/test/browser_timeline-waterfall-sidebar.js
+++ b/browser/devtools/performance/test/browser_timeline-waterfall-sidebar.js
@@ -28,19 +28,26 @@ function* spawnTest() {
     return markers.some(m => m.name == "Styles") &&
            markers.some(m => m.name == "Reflow") &&
            markers.some(m => m.name == "Paint");
   });
 
   yield stopRecording(panel);
   ok(true, "Recording has ended.");
 
+  info("No need to select everything in the timeline.");
+  info("All the markers should be displayed by default.");
+
   let bars = $$(".waterfall-marker-bar");
   let markers = PerformanceController.getCurrentRecording().getMarkers();
 
+  info(`Got ${bars.length} bars and ${markers.length} markers.`);
+  info("Markers types from datasrc: " + Array.map(markers, e => e.name));
+  info("Markers names from sidebar: " + Array.map(bars, e => e.parentNode.parentNode.querySelector(".waterfall-marker-name").getAttribute("value")));
+
   ok(bars.length > 2, "Got at least 3 markers (1)");
   ok(markers.length > 2, "Got at least 3 markers (2)");
 
   let toMs = ms => L10N.getFormatStrWithNumbers("timeline.tick", ms);
 
   for (let i = 0; i < bars.length; i++) {
     let bar = bars[i];
     let mkr = markers[i];
--- a/browser/devtools/performance/views/details-js-call-tree.js
+++ b/browser/devtools/performance/views/details-js-call-tree.js
@@ -6,60 +6,57 @@
 /**
  * CallTree view containing profiler call tree, controlled by DetailsView.
  */
 let JsCallTreeView = Heritage.extend(DetailsSubview, {
 
   rerenderPrefs: [
     "invert-call-tree",
     "show-platform-data",
-    "flatten-tree-recursion"
+    "flatten-tree-recursion",
   ],
 
   rangeChangeDebounceTime: 75, // ms
 
   /**
    * Sets up the view with event binding.
    */
   initialize: function () {
     DetailsSubview.initialize.call(this);
 
-    this._onPrefChanged = this._onPrefChanged.bind(this);
     this._onLink = this._onLink.bind(this);
 
     this.container = $("#js-calltree-view .call-tree-cells-container");
-    JITOptimizationsView.initialize();
   },
 
   /**
    * Unbinds events.
    */
   destroy: function () {
     this.container = null;
-    JITOptimizationsView.destroy();
     DetailsSubview.destroy.call(this);
   },
 
   /**
    * Method for handling all the set up for rendering a new call tree.
    *
    * @param object interval [optional]
    *        The { startTime, endTime }, in milliseconds.
    */
   render: function (interval={}) {
+    let recording = PerformanceController.getCurrentRecording();
+    let profile = recording.getProfile();
     let options = {
       contentOnly: !PerformanceController.getOption("show-platform-data"),
       invertTree: PerformanceController.getOption("invert-call-tree"),
-      flattenRecursion: PerformanceController.getOption("flatten-tree-recursion")
+      flattenRecursion: PerformanceController.getOption("flatten-tree-recursion"),
+      showOptimizationHint: recording.getConfiguration().withJITOptimizations,
     };
-    let recording = PerformanceController.getCurrentRecording();
-    let profile = recording.getProfile();
     let threadNode = this._prepareCallTree(profile, interval, options);
     this._populateCallTree(threadNode, options);
-    this._toggleJITOptimizationsView(recording);
     this.emit(EVENTS.JS_CALL_TREE_RENDERED);
   },
 
   /**
    * Fired on the "link" event for the call tree in this container.
    */
   _onLink: function (_, treeItem) {
     let { url, line } = treeItem.frame.getInfo();
@@ -103,49 +100,37 @@ let JsCallTreeView = Heritage.extend(Det
 
     let root = new CallView({
       frame: frameNode,
       inverted: inverted,
       // The synthesized root node is hidden in inverted call trees.
       hidden: inverted,
       // Call trees should only auto-expand when not inverted. Passing undefined
       // will default to the CALL_TREE_AUTO_EXPAND depth.
-      autoExpandDepth: inverted ? 0 : undefined
+      autoExpandDepth: inverted ? 0 : undefined,
+      showOptimizationHint: options.showOptimizationHint
     });
 
     // Bind events.
     root.on("link", this._onLink);
 
-    // Pipe "focus" events to the view, used by
-    // tests and JITOptimizationsView.
-    root.on("focus", (_, node) => this.emit("focus", node));
+    // Pipe "focus" events to the view, mostly for tests
+    root.on("focus", () => this.emit("focus"));
+    // TODO tests for optimization event and rendering
+    // optimization bubbles in call tree
+    root.on("optimization", (_, node) => this.emit("optimization", node));
 
     // Clear out other call trees.
     this.container.innerHTML = "";
     root.attachTo(this.container);
 
     // When platform data isn't shown, hide the cateogry labels, since they're
     // only available for C++ frames. Pass *false* to make them invisible.
     root.toggleCategories(!options.contentOnly);
 
     // Return the CallView for tests
     return root;
   },
 
-  /**
-   * Displays or hides the optimizations view based on the recordings
-   * optimizations feature.
-   *
-   * @param {RecordingModel} recording
-   */
-  _toggleJITOptimizationsView: function (recording) {
-    if (recording && recording.getConfiguration().withJITOptimizations) {
-      JITOptimizationsView.show();
-      JITOptimizationsView.render();
-    } else {
-      JITOptimizationsView.hide();
-    }
-  },
-
   toString: () => "[object JsCallTreeView]"
 });
 
 EventEmitter.decorate(JsCallTreeView);
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/views/details-optimizations.js
@@ -0,0 +1,174 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+let OptimizationsView = Heritage.extend(DetailsSubview, {
+
+  rerenderPrefs: [
+    "show-platform-data",
+    "flatten-tree-recursion",
+  ],
+
+  rangeChangeDebounceTime: 75, // ms
+
+  /**
+   * Sets up the view with event binding.
+   */
+  initialize: function () {
+    DetailsSubview.initialize.call(this);
+    this.reset = this.reset.bind(this);
+    this.tabs = $("#optimizations-tabs");
+    this._onFramesListSelect = this._onFramesListSelect.bind(this);
+
+    OptimizationsListView.initialize();
+    FramesListView.initialize({ container: $("#frames-tabpanel") });
+    FramesListView.on("select", this._onFramesListSelect);
+  },
+
+  /**
+   * Unbinds events.
+   */
+  destroy: function () {
+    DetailsSubview.destroy.call(this);
+    this.tabs = this._threadNode = this._frameNode = null;
+
+    FramesListView.off("select", this._onFramesListSelect);
+    FramesListView.destroy();
+    OptimizationsListView.destroy();
+  },
+
+  /**
+   * Selects a tab by name.
+   *
+   * @param {string} name
+   *                 Can be "frames" or "optimizations"
+   */
+  selectTabByName: function (name="frames") {
+    switch(name) {
+    case "optimizations":
+      this.tabs.selectedIndex = 0;
+      break;
+    case "frames":
+      this.tabs.selectedIndex = 1;
+      break;
+    }
+  },
+
+  /**
+   * Method for handling all the set up for rendering a new call tree.
+   *
+   * @param object interval [optional]
+   *        The { startTime, endTime }, in milliseconds.
+   */
+  render: function (interval={}) {
+    let options = {
+      contentOnly: !PerformanceController.getOption("show-platform-data"),
+      flattenRecursion: PerformanceController.getOption("flatten-tree-recursion"),
+      // Always invert the tree for the optimizations view so we can quickly
+      // get leaves
+      invertTree: true,
+    };
+    let recording = PerformanceController.getCurrentRecording();
+    let profile = recording.getProfile();
+
+    this.reset();
+    // TODO bug 1175662
+    // Share thread nodes between details view
+    this.threadNode = this._prepareThreadNode(profile, interval, options);
+    this.emit(EVENTS.OPTIMIZATIONS_RENDERED);
+  },
+
+  /**
+   * The main thread node used in this recording that contains
+   * all potential frame nodes to select.
+   */
+  set threadNode(threadNode) {
+    if (threadNode === this._threadNode) {
+      return;
+    }
+    this._threadNode = threadNode;
+    // Also clear out the current frame node as its no
+    // longer relevent
+    this.frameNode = null;
+    this._setAndRenderFramesList();
+  },
+  get threadNode() {
+    return this._threadNode;
+  },
+
+  /**
+   * frameNode is the frame node selected currently to inspect
+   * the optimization tiers over time and strategies.
+   */
+  set frameNode(frameNode) {
+    if (frameNode === this._frameNode) {
+      return;
+    }
+    this._frameNode = frameNode;
+
+    // If no frame selected, jump to the frame list view. If just selected
+    // a frame, jump to optimizations view.
+    // TODO test for this bug 1176056
+    this.selectTabByName(frameNode ? "optimizations" : "frames");
+    this._setAndRenderTierGraph();
+    this._setAndRenderOptimizationsList();
+  },
+
+  get frameNode() {
+    return this._frameNode;
+  },
+
+  /**
+   * Clears the frameNode so that tier and opts list
+   * views are cleared.
+   */
+  reset: function () {
+    this.threadNode = this.frameNode = null;
+  },
+
+  /**
+   * Called when the recording is stopped and prepares data to
+   * populate the graph.
+   */
+  _prepareThreadNode: function (profile, { startTime, endTime }, options) {
+    let thread = profile.threads[0];
+    let { contentOnly, invertTree, flattenRecursion } = options;
+    let threadNode = new ThreadNode(thread, { startTime, endTime, contentOnly, invertTree, flattenRecursion });
+    return threadNode;
+  },
+
+  /**
+   * Renders the tier graph.
+   */
+  _setAndRenderTierGraph: function () {
+    // TODO bug 1150299
+  },
+
+  /**
+   * Renders the frames list.
+   */
+  _setAndRenderFramesList: function () {
+    FramesListView.setCurrentThread(this.threadNode);
+    FramesListView.render();
+  },
+
+  /**
+   * Renders the optimizations list.
+   */
+  _setAndRenderOptimizationsList: function () {
+    OptimizationsListView.setCurrentFrame(this.frameNode);
+    OptimizationsListView.render();
+  },
+
+  /**
+   * Called when a frame is selected via the FramesListView
+   */
+  _onFramesListSelect: function (_, frameNode) {
+    this.frameNode = frameNode;
+  },
+
+  toString: () => "[object OptimizationsView]"
+});
+
+EventEmitter.decorate(OptimizationsView);
--- a/browser/devtools/performance/views/details.js
+++ b/browser/devtools/performance/views/details.js
@@ -34,16 +34,21 @@ let DetailsView = {
       actors: ["memory"],
       features: ["withAllocations"]
     },
     "memory-flamegraph": {
       id: "memory-flamegraph-view",
       view: MemoryFlameGraphView,
       actors: ["memory", "timeline"],
       features: ["withAllocations"]
+    },
+    "optimizations": {
+      id: "optimizations-view",
+      view: OptimizationsView,
+      features: ["withJITOptimizations"],
     }
   },
 
   /**
    * Sets up the view with event binding, initializes subviews.
    */
   initialize: Task.async(function *() {
     this.el = $("#details-pane");
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/views/frames-list.js
@@ -0,0 +1,114 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+const HTML_NS = "http://www.w3.org/1999/xhtml";
+const PERCENTAGE_UNITS = L10N.getStr("table.percentage");
+
+/**
+ * View for rendering a list of all youngest-frames in a profiler recording.
+ */
+
+let FramesListView = {
+
+  // Current `<li>` element selected.
+  _selectedItem: null,
+
+  /**
+   * Initialization function called when the tool starts up.
+   */
+  initialize: function ({ container }) {
+    this._onFrameListClick = this._onFrameListClick.bind(this);
+
+    this.container = container;
+    this.list = document.createElementNS(HTML_NS, "ul");
+    this.list.setAttribute("class", "frames-list");
+    this.list.addEventListener("click", this._onFrameListClick, false);
+
+    this.container.appendChild(this.list);
+  },
+
+  /**
+   * Destruction function called when the tool cleans up.
+   */
+  destroy: function () {
+    this.list.removeEventListener("click", this._onFrameListClick, false);
+    this.container.innerHTML = "";
+    this.container = this.list = null;
+  },
+
+  /**
+   * Sets the thread node used for subsequent rendering.
+   *
+   * @param {ThreadNode} threadNode
+   */
+  setCurrentThread: function (threadNode) {
+    this.threadNode = threadNode;
+  },
+
+  /**
+   * Renders a list of leaf frames with optimizations in
+   * order of hotness from the current ThreadNode.
+   */
+  render: function () {
+    this.list.innerHTML = "";
+
+    if (!this.threadNode) {
+      return;
+    }
+
+    let totalSamples = this.threadNode.samples;
+    let sortedFrames = this.threadNode.calls.sort((a, b) => a.youngestFrameSamples < b.youngestFrameSamples ? 1 : -1);
+    for (let frame of sortedFrames) {
+      if (!frame.hasOptimizations()) {
+        continue;
+      }
+      let info = frame.getInfo();
+      let el = document.createElementNS(HTML_NS, "li");
+      let percentage = frame.youngestFrameSamples / totalSamples * 100;
+      let percentageText = L10N.numberWithDecimals(percentage, 2) + PERCENTAGE_UNITS;
+      let label = `(${percentageText}) ${info.functionName}`;
+      el.textContent = label;
+      el.setAttribute("tooltip", label);
+      el.setAttribute("data-location", frame.location);
+      this.list.appendChild(el);
+    }
+  },
+
+  /**
+   * Fired when a frame in the list is clicked.
+   */
+  _onFrameListClick: function (e) {
+    // If no threadNode (no renders), abort;
+    // also only allow left click to trigger this event
+    if (!this.threadNode || e.button !== 0) {
+      return;
+    }
+
+    let target = e.target;
+    let location = target.getAttribute("data-location");
+    if (!location) {
+      return;
+    }
+
+    for (let frame of this.threadNode.calls) {
+      if (frame.location === location) {
+        // If found, set the selected class on element, remove it
+        // from previous element, and emit event "select"
+        if (this._selectedItem) {
+          this._selectedItem.classList.remove("selected");
+        }
+        this._selectedItem = target;
+        target.classList.add("selected");
+        console.log("Emitting select on", this, frame);
+        this.emit("select", frame);
+        break;
+      }
+    }
+  },
+
+  toString: () => "[object FramesListView]"
+};
+
+EventEmitter.decorate(FramesListView);
rename from browser/devtools/performance/views/jit-optimizations.js
rename to browser/devtools/performance/views/optimizations-list.js
--- a/browser/devtools/performance/views/jit-optimizations.js
+++ b/browser/devtools/performance/views/optimizations-list.js
@@ -5,57 +5,51 @@
 
 const URL_LABEL_TOOLTIP = L10N.getStr("table.url.tooltiptext");
 const OPTIMIZATION_FAILURE = L10N.getStr("jit.optimizationFailure");
 const JIT_SAMPLES = L10N.getStr("jit.samples2");
 const JIT_EMPTY_TEXT = L10N.getStr("jit.empty");
 const PROPNAME_MAX_LENGTH = 4;
 
 /**
- * View for rendering JIT Optimization data. The terminology and types
- * used here can be referenced:
+ * View for rendering a list of all optmizations found in a frame.
+ * The terminology and types used here can be referenced:
  * @see browser/devtools/performance/modules/logic/jit.js
  */
 
-let JITOptimizationsView = {
+let OptimizationsListView = {
 
   _currentFrame: null,
 
   /**
    * Initialization function called when the tool starts up.
    */
   initialize: function () {
     this.reset = this.reset.bind(this);
-    this._onFocusFrame = this._onFocusFrame.bind(this);
 
     this.el = $("#jit-optimizations-view");
     this.$headerName = $("#jit-optimizations-header .header-function-name");
     this.$headerFile = $("#jit-optimizations-header .header-file");
     this.$headerLine = $("#jit-optimizations-header .header-line");
 
     this.tree = new TreeWidget($("#jit-optimizations-raw-view"), {
       sorted: false,
       emptyText: JIT_EMPTY_TEXT
     });
 
     // Start the tree by resetting.
     this.reset();
-
-    PerformanceController.on(EVENTS.RECORDING_SELECTED, this.reset);
-    JsCallTreeView.on("focus", this._onFocusFrame);
   },
 
   /**
    * Destruction function called when the tool cleans up.
    */
   destroy: function () {
     this.tree = null;
     this.$headerName = this.$headerFile = this.$headerLine = this.el = null;
-    PerformanceController.off(EVENTS.RECORDING_SELECTED, this.reset);
-    JsCallTreeView.off("focus", this._onFocusFrame);
   },
 
   /**
    * Takes a FrameNode, with corresponding optimization data to be displayed
    * in the view.
    *
    * @param {FrameNode} frameNode
    */
@@ -88,42 +82,22 @@ let JITOptimizationsView = {
 
   /**
    * Clears out data in the tree.
    */
   clear: function () {
     this.tree.clear();
   },
 
-  show: function () {
-    this.el.hidden = false;
-  },
-
-  hide: function () {
-    this.el.hidden = true;
-  },
-
-  /**
-   * Helper to determine whether or not this view should be enabled.
-   */
-  isEnabled: function () {
-    let recording = PerformanceController.getCurrentRecording();
-    return !!(recording && recording.getConfiguration().withJITOptimizations);
-  },
-
   /**
    * Takes a JITOptimizations object and builds a view containing all attempted
    * optimizations for this frame. This view is very verbose and meant for those
    * who understand JIT compilers.
    */
   render: function () {
-    if (!this.isEnabled()) {
-      return;
-    }
-
     let frameNode = this.getCurrentFrame();
 
     if (!frameNode) {
       this.reset();
       return;
     }
 
     let view = this.tree;
@@ -380,36 +354,13 @@ let JITOptimizationsView = {
 
   _isLinkableURL: function (url) {
     return url && url.indexOf &&
        (url.indexOf("http") === 0 ||
         url.indexOf("resource://") === 0 ||
         url.indexOf("file://") === 0);
   },
 
-  /**
-   * Called when the JSCallTreeView focuses on a frame.
-   */
-
-  _onFocusFrame: function (_, view) {
-    if (!view.frame) {
-      return;
-    }
-
-    // Only attempt to rerender if this is new -- focus is called even
-    // when the window removes focus and comes back, so this prevents
-    // repeating rendering of the same frame
-    let shouldRender = this.getCurrentFrame() !== view.frame;
-
-    // Save the frame even if the view is disabled, so we can
-    // render it if it becomes enabled
-    this.setCurrentFrame(view.frame);
-
-    if (shouldRender) {
-      this.render();
-    }
-  },
-
-  toString: () => "[object JITOptimizationsView]"
+  toString: () => "[object OptimizationsListView]"
 
 };
 
-EventEmitter.decorate(JITOptimizationsView);
+EventEmitter.decorate(OptimizationsListView);
--- a/browser/devtools/shared/moz.build
+++ b/browser/devtools/shared/moz.build
@@ -43,20 +43,23 @@ EXTRA_JS_MODULES.devtools.shared += [
     'source-utils.js',
     'telemetry.js',
     'theme-switching.js',
     'theme.js',
     'undo.js'
 ]
 
 EXTRA_JS_MODULES.devtools.shared.widgets += [
+    'widgets/BarGraphWidget.js',
     'widgets/CubicBezierPresets.js',
     'widgets/CubicBezierWidget.js',
     'widgets/FastListWidget.js',
     'widgets/FilterWidget.js',
     'widgets/FlameGraph.js',
     'widgets/Graphs.js',
+    'widgets/LineGraphWidget.js',
     'widgets/MdnDocsWidget.js',
+    'widgets/MountainGraphWidget.js',
     'widgets/Spectrum.js',
     'widgets/TableWidget.js',
     'widgets/Tooltip.js',
     'widgets/TreeWidget.js',
 ]
--- a/browser/devtools/shared/test/browser.ini
+++ b/browser/devtools/shared/test/browser.ini
@@ -68,19 +68,20 @@ support-files =
 [browser_graphs-10a.js]
 [browser_graphs-10b.js]
 [browser_graphs-10c.js]
 [browser_graphs-11a.js]
 [browser_graphs-11b.js]
 [browser_graphs-12.js]
 [browser_graphs-13.js]
 [browser_graphs-14.js]
+[browser_graphs-15.js]
+[browser_graphs-16.js]
 [browser_inplace-editor-01.js]
 [browser_inplace-editor-02.js]
-[browser_graphs-15.js]
 [browser_layoutHelpers.js]
 skip-if = e10s # Layouthelpers test should not run in a content page.
 [browser_layoutHelpers-getBoxQuads.js]
 skip-if = e10s # Layouthelpers test should not run in a content page.
 [browser_mdn-docs-01.js]
 [browser_mdn-docs-02.js]
 [browser_num-l10n.js]
 [browser_observableobject.js]
--- a/browser/devtools/shared/test/browser_graphs-01.js
+++ b/browser/devtools/shared/test/browser_graphs-01.js
@@ -1,14 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that graph widgets works properly.
 
-let {LineGraphWidget} = devtools.require("devtools/shared/widgets/Graphs");
+let LineGraphWidget = devtools.require("devtools/shared/widgets/LineGraphWidget");
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
 add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
   finish();
 });
--- a/browser/devtools/shared/test/browser_graphs-02.js
+++ b/browser/devtools/shared/test/browser_graphs-02.js
@@ -1,16 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that graph widgets can properly add data, regions and highlights.
 
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
 const TEST_REGIONS = [{ start: 320, end: 460 }, { start: 780, end: 860 }];
-let {LineGraphWidget} = devtools.require("devtools/shared/widgets/Graphs");
+let LineGraphWidget = devtools.require("devtools/shared/widgets/LineGraphWidget");
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
 add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
 });
 
--- a/browser/devtools/shared/test/browser_graphs-03.js
+++ b/browser/devtools/shared/test/browser_graphs-03.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that graph widgets can handle clients getting/setting the
 // selection or cursor.
 
-let {LineGraphWidget} = devtools.require("devtools/shared/widgets/Graphs");
+let LineGraphWidget = devtools.require("devtools/shared/widgets/LineGraphWidget");
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
 add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
 });
 
--- a/browser/devtools/shared/test/browser_graphs-04.js
+++ b/browser/devtools/shared/test/browser_graphs-04.js
@@ -1,14 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that graph widgets can correctly compare selections and cursors.
 
-let {LineGraphWidget} = devtools.require("devtools/shared/widgets/Graphs");
+let LineGraphWidget = devtools.require("devtools/shared/widgets/LineGraphWidget");
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
 add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
 });
 
--- a/browser/devtools/shared/test/browser_graphs-05.js
+++ b/browser/devtools/shared/test/browser_graphs-05.js
@@ -1,16 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that graph widgets can correctly determine which regions are hovered.
 
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
 const TEST_REGIONS = [{ start: 320, end: 460 }, { start: 780, end: 860 }];
-let {LineGraphWidget} = devtools.require("devtools/shared/widgets/Graphs");
+let LineGraphWidget = devtools.require("devtools/shared/widgets/LineGraphWidget");
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
 add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
 });
 
--- a/browser/devtools/shared/test/browser_graphs-06.js
+++ b/browser/devtools/shared/test/browser_graphs-06.js
@@ -1,16 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests if clicking on regions adds a selection spanning that region.
 
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
 const TEST_REGIONS = [{ start: 320, end: 460 }, { start: 780, end: 860 }];
-let {LineGraphWidget} = devtools.require("devtools/shared/widgets/Graphs");
+let LineGraphWidget = devtools.require("devtools/shared/widgets/LineGraphWidget");
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
 add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
 });
 
--- a/browser/devtools/shared/test/browser_graphs-07a.js
+++ b/browser/devtools/shared/test/browser_graphs-07a.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests if selecting, resizing, moving selections and zooming in/out works.
 
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
-let {LineGraphWidget} = devtools.require("devtools/shared/widgets/Graphs");
+let LineGraphWidget = devtools.require("devtools/shared/widgets/LineGraphWidget");
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
 add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
 });
 
--- a/browser/devtools/shared/test/browser_graphs-07b.js
+++ b/browser/devtools/shared/test/browser_graphs-07b.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests if selections can't be added via clicking, while not allowed.
 
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
-let {LineGraphWidget} = devtools.require("devtools/shared/widgets/Graphs");
+let LineGraphWidget = devtools.require("devtools/shared/widgets/LineGraphWidget");
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
 add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
 });
 
--- a/browser/devtools/shared/test/browser_graphs-07c.js
+++ b/browser/devtools/shared/test/browser_graphs-07c.js
@@ -1,17 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests if movement via event dispatching using screenX / screenY
 // works.  All of the other tests directly use the graph's mouse event
 // callbacks with textX / testY for convenience.
 
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
-let {LineGraphWidget} = devtools.require("devtools/shared/widgets/Graphs");
+let LineGraphWidget = devtools.require("devtools/shared/widgets/LineGraphWidget");
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
 add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
 });
 
--- a/browser/devtools/shared/test/browser_graphs-07d.js
+++ b/browser/devtools/shared/test/browser_graphs-07d.js
@@ -1,16 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that selections are drawn onto the canvas.
 
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
 const TEST_REGIONS = [{ start: 320, end: 460 }, { start: 780, end: 860 }];
-let {LineGraphWidget} = devtools.require("devtools/shared/widgets/Graphs");
+let LineGraphWidget = devtools.require("devtools/shared/widgets/LineGraphWidget");
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
 add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
 });
 
--- a/browser/devtools/shared/test/browser_graphs-07e.js
+++ b/browser/devtools/shared/test/browser_graphs-07e.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that selections are drawn onto the canvas.
 
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
-let {LineGraphWidget} = devtools.require("devtools/shared/widgets/Graphs");
+let LineGraphWidget = devtools.require("devtools/shared/widgets/LineGraphWidget");
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 let CURRENT_ZOOM = 1;
 
 add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
 });
--- a/browser/devtools/shared/test/browser_graphs-08.js
+++ b/browser/devtools/shared/test/browser_graphs-08.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests if a selection is dropped when clicking outside of it.
 
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
-let {LineGraphWidget} = devtools.require("devtools/shared/widgets/Graphs");
+let LineGraphWidget = devtools.require("devtools/shared/widgets/LineGraphWidget");
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
 add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
 });
 
--- a/browser/devtools/shared/test/browser_graphs-09a.js
+++ b/browser/devtools/shared/test/browser_graphs-09a.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that line graphs properly create the gutter and tooltips.
 
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
-let {LineGraphWidget} = devtools.require("devtools/shared/widgets/Graphs");
+let LineGraphWidget = devtools.require("devtools/shared/widgets/LineGraphWidget");
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
 add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
 });
 
--- a/browser/devtools/shared/test/browser_graphs-09b.js
+++ b/browser/devtools/shared/test/browser_graphs-09b.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that line graphs properly use the tooltips configuration properties.
 
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
-let {LineGraphWidget} = devtools.require("devtools/shared/widgets/Graphs");
+let LineGraphWidget = devtools.require("devtools/shared/widgets/LineGraphWidget");
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
 add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
 });
 
--- a/browser/devtools/shared/test/browser_graphs-09c.js
+++ b/browser/devtools/shared/test/browser_graphs-09c.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that line graphs hide the tooltips when there's no data available.
 
 const TEST_DATA = [];
-let {LineGraphWidget} = devtools.require("devtools/shared/widgets/Graphs");
+let LineGraphWidget = devtools.require("devtools/shared/widgets/LineGraphWidget");
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
 add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
 });
 
--- a/browser/devtools/shared/test/browser_graphs-09d.js
+++ b/browser/devtools/shared/test/browser_graphs-09d.js
@@ -1,16 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that line graphs hide the 'max' tooltip when the distance between
 // the 'min' and 'max' tooltip is too small.
 
 const TEST_DATA = [{ delta: 100, value: 60 }, { delta: 200, value: 59.9 }];
-let {LineGraphWidget} = devtools.require("devtools/shared/widgets/Graphs");
+let LineGraphWidget = devtools.require("devtools/shared/widgets/LineGraphWidget");
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
 add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
 });
 
--- a/browser/devtools/shared/test/browser_graphs-09e.js
+++ b/browser/devtools/shared/test/browser_graphs-09e.js
@@ -2,17 +2,17 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that line graphs hide the gutter and tooltips when there's no data,
 // but show them when there is.
 
 const NO_DATA = [];
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
 
-let {LineGraphWidget} = devtools.require("devtools/shared/widgets/Graphs");
+let LineGraphWidget = devtools.require("devtools/shared/widgets/LineGraphWidget");
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
 add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
 });
 
--- a/browser/devtools/shared/test/browser_graphs-09f.js
+++ b/browser/devtools/shared/test/browser_graphs-09f.js
@@ -1,16 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests the constructor options for `min`, `max` and `avg` on displaying the
 // gutter/tooltips and lines.
 
 const TEST_DATA = [{ delta: 100, value: 60 }, { delta: 200, value: 1 }];
-let {LineGraphWidget} = devtools.require("devtools/shared/widgets/Graphs");
+let LineGraphWidget = devtools.require("devtools/shared/widgets/LineGraphWidget");
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
 add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
 });
 
--- a/browser/devtools/shared/test/browser_graphs-10a.js
+++ b/browser/devtools/shared/test/browser_graphs-10a.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that graphs properly handle resizing.
 
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
-let {LineGraphWidget} = devtools.require("devtools/shared/widgets/Graphs");
+let LineGraphWidget = devtools.require("devtools/shared/widgets/LineGraphWidget");
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
 add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
 });
 
--- a/browser/devtools/shared/test/browser_graphs-10b.js
+++ b/browser/devtools/shared/test/browser_graphs-10b.js
@@ -1,16 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that graphs aren't refreshed when the owner window resizes but
 // the graph dimensions stay the same.
 
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
-let {LineGraphWidget} = devtools.require("devtools/shared/widgets/Graphs");
+let LineGraphWidget = devtools.require("devtools/shared/widgets/LineGraphWidget");
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
 add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
 });
 
--- a/browser/devtools/shared/test/browser_graphs-10c.js
+++ b/browser/devtools/shared/test/browser_graphs-10c.js
@@ -1,13 +1,13 @@
 
 // Tests that graphs properly handle resizing.
 
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
-let {LineGraphWidget} = devtools.require("devtools/shared/widgets/Graphs");
+let LineGraphWidget = devtools.require("devtools/shared/widgets/LineGraphWidget");
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
 add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
 });
 
--- a/browser/devtools/shared/test/browser_graphs-11a.js
+++ b/browser/devtools/shared/test/browser_graphs-11a.js
@@ -1,14 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that bar graph create a legend as expected.
 
-let {BarGraphWidget} = devtools.require("devtools/shared/widgets/Graphs");
+let BarGraphWidget = devtools.require("devtools/shared/widgets/BarGraphWidget");
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
 const CATEGORIES = [
   { color: "#46afe3", label: "Foo" },
   { color: "#eb5368", label: "Bar" },
   { color: "#70bf53", label: "Baz" }
 ];
 
--- a/browser/devtools/shared/test/browser_graphs-11b.js
+++ b/browser/devtools/shared/test/browser_graphs-11b.js
@@ -1,14 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that bar graph's legend items handle mouseover/mouseout.
 
-let {BarGraphWidget} = devtools.require("devtools/shared/widgets/Graphs");
+let BarGraphWidget = devtools.require("devtools/shared/widgets/BarGraphWidget");
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
 const CATEGORIES = [
   { color: "#46afe3", label: "Foo" },
   { color: "#eb5368", label: "Bar" },
   { color: "#70bf53", label: "Baz" }
 ];
 
--- a/browser/devtools/shared/test/browser_graphs-12.js
+++ b/browser/devtools/shared/test/browser_graphs-12.js
@@ -1,14 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that canvas graphs can have their selection linked.
 
-let {LineGraphWidget,BarGraphWidget,CanvasGraphUtils} = devtools.require("devtools/shared/widgets/Graphs");
+let LineGraphWidget = devtools.require("devtools/shared/widgets/LineGraphWidget");
+let BarGraphWidget = devtools.require("devtools/shared/widgets/BarGraphWidget");
+let {CanvasGraphUtils} = devtools.require("devtools/shared/widgets/Graphs");
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
 add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
 });
 
--- a/browser/devtools/shared/test/browser_graphs-13.js
+++ b/browser/devtools/shared/test/browser_graphs-13.js
@@ -1,14 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that graph widgets may have a fixed width or height.
 
-let {LineGraphWidget} = devtools.require("devtools/shared/widgets/Graphs");
+let LineGraphWidget = devtools.require("devtools/shared/widgets/LineGraphWidget");
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
 add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
 });
 
--- a/browser/devtools/shared/test/browser_graphs-14.js
+++ b/browser/devtools/shared/test/browser_graphs-14.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that graph widgets correctly emit mouse input events.
 
 const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
-let {LineGraphWidget} = devtools.require("devtools/shared/widgets/Graphs");
+let LineGraphWidget = devtools.require("devtools/shared/widgets/LineGraphWidget");
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
 add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
 });
 
--- a/browser/devtools/shared/test/browser_graphs-15.js
+++ b/browser/devtools/shared/test/browser_graphs-15.js
@@ -1,30 +1,31 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that graph widgets correctly emit mouse input events.
 
 const FAST_FPS = 60;
 const SLOW_FPS = 10;
+
 // Each element represents a second
 const FRAMES= [FAST_FPS, FAST_FPS, FAST_FPS, SLOW_FPS, FAST_FPS];
 const TEST_DATA = [];
 const INTERVAL = 100;
 const DURATION = 5000; // 5s
 let t = 0;
 for (let frameRate of FRAMES) {
   for (let i = 0; i < frameRate; i++) {
     let delta = Math.floor(1000 / frameRate); // Duration between frames at this rate
     t += delta;
     TEST_DATA.push(t);
   }
 }
 
-let {LineGraphWidget} = devtools.require("devtools/shared/widgets/Graphs");
+let LineGraphWidget = devtools.require("devtools/shared/widgets/LineGraphWidget");
 let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
 
 add_task(function*() {
   yield promiseTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
 });
 
new file mode 100644
--- /dev/null
+++ b/browser/devtools/shared/test/browser_graphs-16.js
@@ -0,0 +1,44 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that mounta graphs work as expected.
+
+let MountainGraphWidget = devtools.require("devtools/shared/widgets/MountainGraphWidget");
+let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
+
+const TEST_DATA = [
+  { delta: 0, values: [0.1, 0.5, 0.3] },
+  { delta: 1, values: [0.25, 0, 0.5] },
+  { delta: 2, values: [0.5, 0.25, 0.1] },
+  { delta: 3, values: [0, 0.75, 0] },
+  { delta: 4, values: [0.75, 0, 0.25] }
+];
+
+const SECTIONS = [
+  { color: "red" },
+  { color: "green" },
+  { color: "blue" }
+];
+
+add_task(function*() {
+  yield promiseTab("about:blank");
+  yield performTest();
+  gBrowser.removeCurrentTab();
+});
+
+function* performTest() {
+  let [host, win, doc] = yield createHost();
+  let graph = new MountainGraphWidget(doc.body);
+  yield graph.once("ready");
+
+  testGraph(graph);
+
+  yield graph.destroy();
+  host.destroy();
+}
+
+function testGraph(graph) {
+  graph.format = SECTIONS;
+  graph.setData(TEST_DATA);
+  ok(true, "The graph didn't throw any erorrs.");
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/shared/widgets/BarGraphWidget.js
@@ -0,0 +1,476 @@
+"use strict";
+
+const { Cc, Ci, Cu, Cr } = require("chrome");
+
+const { Heritage, setNamedTimeout, clearNamedTimeout } = require("resource:///modules/devtools/ViewHelpers.jsm");
+const { AbstractCanvasGraph, CanvasGraphUtils } = require("devtools/shared/widgets/Graphs");
+
+const HTML_NS = "http://www.w3.org/1999/xhtml";
+
+// Bar graph constants.
+
+const GRAPH_DAMPEN_VALUES_FACTOR = 0.75;
+const GRAPH_BARS_MARGIN_TOP = 1; // px
+const GRAPH_BARS_MARGIN_END = 1; // px
+const GRAPH_MIN_BARS_WIDTH = 5; // px
+const GRAPH_MIN_BLOCKS_HEIGHT = 1; // px
+
+const GRAPH_BACKGROUND_GRADIENT_START = "rgba(0,136,204,0.0)";
+const GRAPH_BACKGROUND_GRADIENT_END = "rgba(255,255,255,0.25)";
+
+const GRAPH_CLIPHEAD_LINE_COLOR = "#666";
+const GRAPH_SELECTION_LINE_COLOR = "#555";
+const GRAPH_SELECTION_BACKGROUND_COLOR = "rgba(0,136,204,0.25)";
+const GRAPH_SELECTION_STRIPES_COLOR = "rgba(255,255,255,0.1)";
+const GRAPH_REGION_BACKGROUND_COLOR = "transparent";
+const GRAPH_REGION_STRIPES_COLOR = "rgba(237,38,85,0.2)";
+
+const GRAPH_HIGHLIGHTS_MASK_BACKGROUND = "rgba(255,255,255,0.75)";
+const GRAPH_HIGHLIGHTS_MASK_STRIPES = "rgba(255,255,255,0.5)";
+
+const GRAPH_LEGEND_MOUSEOVER_DEBOUNCE = 50; // ms
+
+/**
+ * A bar graph, plotting tuples of values as rectangles.
+ *
+ * @see AbstractCanvasGraph for emitted events and other options.
+ *
+ * Example usage:
+ *   let graph = new BarGraphWidget(node);
+ *   graph.format = ...;
+ *   graph.once("ready", () => {
+ *     graph.setData(src);
+ *   });
+ *
+ * The `graph.format` traits are mandatory and will determine how the values
+ * are styled as "blocks" in every "bar":
+ *   [
+ *     { color: "#f00", label: "Foo" },
+ *     { color: "#0f0", label: "Bar" },
+ *     ...
+ *     { color: "#00f", label: "Baz" }
+ *   ]
+ *
+ * Data source format:
+ *   [
+ *     { delta: x1, values: [y11, y12, ... y1n] },
+ *     { delta: x2, values: [y21, y22, ... y2n] },
+ *     ...
+ *     { delta: xm, values: [ym1, ym2, ... ymn] }
+ *   ]
+ * where each item in the array represents a "bar", for which every value
+ * represents a "block" inside that "bar", plotted at the "delta" position.
+ *
+ * @param nsIDOMNode parent
+ *        The parent node holding the graph.
+ */
+this.BarGraphWidget = function(parent, ...args) {
+  AbstractCanvasGraph.apply(this, [parent, "bar-graph", ...args]);
+
+  this.once("ready", () => {
+    this._onLegendMouseOver = this._onLegendMouseOver.bind(this);
+    this._onLegendMouseOut = this._onLegendMouseOut.bind(this);
+    this._onLegendMouseDown = this._onLegendMouseDown.bind(this);
+    this._onLegendMouseUp = this._onLegendMouseUp.bind(this);
+    this._createLegend();
+  });
+};
+
+BarGraphWidget.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
+  clipheadLineColor: GRAPH_CLIPHEAD_LINE_COLOR,
+  selectionLineColor: GRAPH_SELECTION_LINE_COLOR,
+  selectionBackgroundColor: GRAPH_SELECTION_BACKGROUND_COLOR,
+  selectionStripesColor: GRAPH_SELECTION_STRIPES_COLOR,
+  regionBackgroundColor: GRAPH_REGION_BACKGROUND_COLOR,
+  regionStripesColor: GRAPH_REGION_STRIPES_COLOR,
+
+  /**
+   * List of colors used to fill each block inside every bar, also
+   * corresponding to labels displayed in this graph's legend.
+   * @see constructor
+   */
+  format: null,
+
+  /**
+   * Optionally offsets the `delta` in the data source by this scalar.
+   */
+  dataOffsetX: 0,
+
+  /**
+   * Optionally uses this value instead of the last tick in the data source
+   * to compute the horizontal scaling.
+   */
+  dataDuration: 0,
+
+  /**
+   * The scalar used to multiply the graph values to leave some headroom
+   * on the top.
+   */
+  dampenValuesFactor: GRAPH_DAMPEN_VALUES_FACTOR,
+
+  /**
+   * Bars that are too close too each other in the graph will be combined.
+   * This scalar specifies the required minimum width of each bar.
+   */
+  minBarsWidth: GRAPH_MIN_BARS_WIDTH,
+
+  /**
+   * Blocks in a bar that are too thin inside the bar will not be rendered.
+   * This scalar specifies the required minimum height of each block.
+   */
+  minBlocksHeight: GRAPH_MIN_BLOCKS_HEIGHT,
+
+  /**
+   * Renders the graph's background.
+   * @see AbstractCanvasGraph.prototype.buildBackgroundImage
+   */
+  buildBackgroundImage: function() {
+    let { canvas, ctx } = this._getNamedCanvas("bar-graph-background");
+    let width = this._width;
+    let height = this._height;
+
+    let gradient = ctx.createLinearGradient(0, 0, 0, height);
+    gradient.addColorStop(0, GRAPH_BACKGROUND_GRADIENT_START);
+    gradient.addColorStop(1, GRAPH_BACKGROUND_GRADIENT_END);
+    ctx.fillStyle = gradient;
+    ctx.fillRect(0, 0, width, height);
+
+    return canvas;
+  },
+
+  /**
+   * Renders the graph's data source.
+   * @see AbstractCanvasGraph.prototype.buildGraphImage
+   */
+  buildGraphImage: function() {
+    if (!this.format || !this.format.length) {
+      throw "The graph format traits are mandatory to style the data source.";
+    }
+    let { canvas, ctx } = this._getNamedCanvas("bar-graph-data");
+    let width = this._width;
+    let height = this._height;
+
+    let totalTypes = this.format.length;
+    let totalTicks = this._data.length;
+    let lastTick = this._data[totalTicks - 1].delta;
+
+    let minBarsWidth = this.minBarsWidth * this._pixelRatio;
+    let minBlocksHeight = this.minBlocksHeight * this._pixelRatio;
+
+    let duration = this.dataDuration || lastTick;
+    let dataScaleX = this.dataScaleX = width / (duration - this.dataOffsetX);
+    let dataScaleY = this.dataScaleY = height / this._calcMaxHeight({
+      data: this._data,
+      dataScaleX: dataScaleX,
+      minBarsWidth: minBarsWidth
+    }) * this.dampenValuesFactor;
+
+    // Draw the graph.
+
+    // Iterate over the blocks, then the bars, to draw all rectangles of
+    // the same color in a single pass. See the @constructor for more
+    // information about the data source, and how a "bar" contains "blocks".
+
+    this._blocksBoundingRects = [];
+    let prevHeight = [];
+    let scaledMarginEnd = GRAPH_BARS_MARGIN_END * this._pixelRatio;
+    let scaledMarginTop = GRAPH_BARS_MARGIN_TOP * this._pixelRatio;
+
+    for (let type = 0; type < totalTypes; type++) {
+      ctx.fillStyle = this.format[type].color || "#000";
+      ctx.beginPath();
+
+      let prevRight = 0;
+      let skippedCount = 0;
+      let skippedHeight = 0;
+
+      for (let tick = 0; tick < totalTicks; tick++) {
+        let delta = this._data[tick].delta;
+        let value = this._data[tick].values[type] || 0;
+        let blockRight = (delta - this.dataOffsetX) * dataScaleX;
+        let blockHeight = value * dataScaleY;
+
+        let blockWidth = blockRight - prevRight;
+        if (blockWidth < minBarsWidth) {
+          skippedCount++;
+          skippedHeight += blockHeight;
+          continue;
+        }
+
+        let averageHeight = (blockHeight + skippedHeight) / (skippedCount + 1);
+        if (averageHeight >= minBlocksHeight) {
+          let bottom = height - ~~prevHeight[tick];
+          ctx.moveTo(prevRight, bottom);
+          ctx.lineTo(prevRight, bottom - averageHeight);
+          ctx.lineTo(blockRight, bottom - averageHeight);
+          ctx.lineTo(blockRight, bottom);
+
+          // Remember this block's type and location.
+          this._blocksBoundingRects.push({
+            type: type,
+            start: prevRight,
+            end: blockRight,
+            top: bottom - averageHeight,
+            bottom: bottom
+          });
+
+          if (prevHeight[tick] === undefined) {
+            prevHeight[tick] = averageHeight + scaledMarginTop;
+          } else {
+            prevHeight[tick] += averageHeight + scaledMarginTop;
+          }
+        }
+
+        prevRight += blockWidth + scaledMarginEnd;
+        skippedHeight = 0;
+        skippedCount = 0;
+      }
+
+      ctx.fill();
+    }
+
+    // The blocks bounding rects isn't guaranteed to be sorted ascending by
+    // block location on the X axis. This should be the case, for better
+    // cache cohesion and a faster `buildMaskImage`.
+    this._blocksBoundingRects.sort((a, b) => a.start > b.start ? 1 : -1);
+
+    // Update the legend.
+
+    while (this._legendNode.hasChildNodes()) {
+      this._legendNode.firstChild.remove();
+    }
+    for (let { color, label } of this.format) {
+      this._createLegendItem(color, label);
+    }
+
+    return canvas;
+  },
+
+  /**
+   * Renders the graph's mask.
+   * Fades in only the parts of the graph that are inside the specified areas.
+   *
+   * @param array highlights
+   *        A list of { start, end } values. Optionally, each object
+   *        in the list may also specify { top, bottom } pixel values if the
+   *        highlighting shouldn't span across the full height of the graph.
+   * @param boolean inPixels
+   *        Set this to true if the { start, end } values in the highlights
+   *        list are pixel values, and not values from the data source.
+   * @param function unpack [optional]
+   *        @see AbstractCanvasGraph.prototype.getMappedSelection
+   */
+  buildMaskImage: function(highlights, inPixels = false, unpack = e => e.delta) {
+    // A null `highlights` array is used to clear the mask. An empty array
+    // will mask the entire graph.
+    if (!highlights) {
+      return null;
+    }
+
+    // Get a render target for the highlights. It will be overlaid on top of
+    // the existing graph, masking the areas that aren't highlighted.
+
+    let { canvas, ctx } = this._getNamedCanvas("graph-highlights");
+    let width = this._width;
+    let height = this._height;
+
+    // Draw the background mask.
+
+    let pattern = AbstractCanvasGraph.getStripePattern({
+      ownerDocument: this._document,
+      backgroundColor: GRAPH_HIGHLIGHTS_MASK_BACKGROUND,
+      stripesColor: GRAPH_HIGHLIGHTS_MASK_STRIPES
+    });
+    ctx.fillStyle = pattern;
+    ctx.fillRect(0, 0, width, height);
+
+    // Clear highlighted areas.
+
+    let totalTicks = this._data.length;
+    let firstTick = unpack(this._data[0]);
+    let lastTick = unpack(this._data[totalTicks - 1]);
+
+    for (let { start, end, top, bottom } of highlights) {
+      if (!inPixels) {
+        start = CanvasGraphUtils.map(start, firstTick, lastTick, 0, width);
+        end = CanvasGraphUtils.map(end, firstTick, lastTick, 0, width);
+      }
+      let firstSnap = findFirst(this._blocksBoundingRects, e => e.start >= start);
+      let lastSnap = findLast(this._blocksBoundingRects, e => e.start >= start && e.end <= end);
+
+      let x1 = firstSnap ? firstSnap.start : start;
+      let x2 = lastSnap ? lastSnap.end : firstSnap ? firstSnap.end : end;
+      let y1 = top || 0;
+      let y2 = bottom || height;
+      ctx.clearRect(x1, y1, x2 - x1, y2 - y1);
+    }
+
+    return canvas;
+  },
+
+  /**
+   * A list storing the bounding rectangle for each drawn block in the graph.
+   * Created whenever `buildGraphImage` is invoked.
+   */
+  _blocksBoundingRects: null,
+
+  /**
+   * Calculates the height of the tallest bar that would eventially be rendered
+   * in this graph.
+   *
+   * Bars that are too close too each other in the graph will be combined.
+   * @see `minBarsWidth`
+   *
+   * @return number
+   *         The tallest bar height in this graph.
+   */
+  _calcMaxHeight: function({ data, dataScaleX, minBarsWidth }) {
+    let maxHeight = 0;
+    let prevRight = 0;
+    let skippedCount = 0;
+    let skippedHeight = 0;
+    let scaledMarginEnd = GRAPH_BARS_MARGIN_END * this._pixelRatio;
+
+    for (let { delta, values } of data) {
+      let barRight = (delta - this.dataOffsetX) * dataScaleX;
+      let barHeight = values.reduce((a, b) => a + b, 0);
+
+      let barWidth = barRight - prevRight;
+      if (barWidth < minBarsWidth) {
+        skippedCount++;
+        skippedHeight += barHeight;
+        continue;
+      }
+
+      let averageHeight = (barHeight + skippedHeight) / (skippedCount + 1);
+      maxHeight = Math.max(averageHeight, maxHeight);
+
+      prevRight += barWidth + scaledMarginEnd;
+      skippedHeight = 0;
+      skippedCount = 0;
+    }
+
+    return maxHeight;
+  },
+
+  /**
+   * Creates the legend container when constructing this graph.
+   */
+  _createLegend: function() {
+    let legendNode = this._legendNode = this._document.createElementNS(HTML_NS, "div");
+    legendNode.className = "bar-graph-widget-legend";
+    this._container.appendChild(legendNode);
+  },
+
+  /**
+   * Creates a legend item when constructing this graph.
+   */
+  _createLegendItem: function(color, label) {
+    let itemNode = this._document.createElementNS(HTML_NS, "div");
+    itemNode.className = "bar-graph-widget-legend-item";
+
+    let colorNode = this._document.createElementNS(HTML_NS, "span");
+    colorNode.setAttribute("view", "color");
+    colorNode.setAttribute("data-index", this._legendNode.childNodes.length);
+    colorNode.style.backgroundColor = color;
+    colorNode.addEventListener("mouseover", this._onLegendMouseOver);
+    colorNode.addEventListener("mouseout", this._onLegendMouseOut);
+    colorNode.addEventListener("mousedown", this._onLegendMouseDown);
+    colorNode.addEventListener("mouseup", this._onLegendMouseUp);
+
+    let labelNode = this._document.createElementNS(HTML_NS, "span");
+    labelNode.setAttribute("view", "label");
+    labelNode.textContent = label;
+
+    itemNode.appendChild(colorNode);
+    itemNode.appendChild(labelNode);
+    this._legendNode.appendChild(itemNode);
+  },
+
+  /**
+   * Invoked whenever a color node in the legend is hovered.
+   */
+  _onLegendMouseOver: function(e) {
+    setNamedTimeout("bar-graph-debounce", GRAPH_LEGEND_MOUSEOVER_DEBOUNCE, () => {
+      let type = e.target.dataset.index;
+      let rects = this._blocksBoundingRects.filter(e => e.type == type);
+
+      this._originalHighlights = this._mask;
+      this._hasCustomHighlights = true;
+      this.setMask(rects, true);
+
+      this.emit("legend-hover", [type, rects]);
+    });
+  },
+
+  /**
+   * Invoked whenever a color node in the legend is unhovered.
+   */
+  _onLegendMouseOut: function() {
+    clearNamedTimeout("bar-graph-debounce");
+
+    if (this._hasCustomHighlights) {
+      this.setMask(this._originalHighlights);
+      this._hasCustomHighlights = false;
+      this._originalHighlights = null;
+    }
+
+    this.emit("legend-unhover");
+  },
+
+  /**
+   * Invoked whenever a color node in the legend is pressed.
+   */
+  _onLegendMouseDown: function(e) {
+    e.preventDefault();
+    e.stopPropagation();
+
+    let type = e.target.dataset.index;
+    let rects = this._blocksBoundingRects.filter(e => e.type == type);
+    let leftmost = rects[0];
+    let rightmost = rects[rects.length - 1];
+    if (!leftmost || !rightmost) {
+      this.dropSelection();
+    } else {
+      this.setSelection({ start: leftmost.start, end: rightmost.end });
+    }
+
+    this.emit("legend-selection", [leftmost, rightmost]);
+  },
+
+  /**
+   * Invoked whenever a color node in the legend is released.
+   */
+  _onLegendMouseUp: function(e) {
+    e.preventDefault();
+    e.stopPropagation();
+  }
+});
+
+/**
+ * Finds the first element in an array that validates a predicate.
+ * @param array
+ * @param function predicate
+ * @return number
+ */
+function findFirst(array, predicate) {
+  for (let i = 0, len = array.length; i < len; i++) {
+    let element = array[i];
+    if (predicate(element)) return element;
+  }
+}
+
+/**
+ * Finds the last element in an array that validates a predicate.
+ * @param array
+ * @param function predicate
+ * @return number
+ */
+function findLast(array, predicate) {
+  for (let i = array.length - 1; i >= 0; i--) {
+    let element = array[i];
+    if (predicate(element)) return element;
+  }
+}
+
+module.exports = BarGraphWidget;
--- a/browser/devtools/shared/widgets/Graphs.js
+++ b/browser/devtools/shared/widgets/Graphs.js
@@ -1,34 +1,31 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const { Cc, Ci, Cu, Cr } = require("chrome");
 
 const { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
-const { ViewHelpers } = require("resource:///modules/devtools/ViewHelpers.jsm");
 const { Heritage, setNamedTimeout, clearNamedTimeout } = require("resource:///modules/devtools/ViewHelpers.jsm");
 
 loader.lazyRequireGetter(this, "promise");
 loader.lazyRequireGetter(this, "EventEmitter",
   "devtools/toolkit/event-emitter");
 
 loader.lazyImporter(this, "DevToolsWorker",
   "resource://gre/modules/devtools/shared/worker.js");
 loader.lazyImporter(this, "LayoutHelpers",
   "resource://gre/modules/devtools/LayoutHelpers.jsm");
 
 const HTML_NS = "http://www.w3.org/1999/xhtml";
 const GRAPH_SRC = "chrome://browser/content/devtools/graphs-frame.xhtml";
 const WORKER_URL = "resource:///modules/devtools/GraphsWorker.js";
 
-const L10N = new ViewHelpers.L10N();
-
 // Generic constants.
 
 const GRAPH_RESIZE_EVENTS_DRAIN = 100; // ms
 const GRAPH_WHEEL_ZOOM_SENSITIVITY = 0.00075;
 const GRAPH_WHEEL_SCROLL_SENSITIVITY = 0.1;
 const GRAPH_WHEEL_MIN_SELECTION_WIDTH = 10; // px
 
 const GRAPH_SELECTION_BOUNDARY_HOVER_LINE_WIDTH = 4; // px
@@ -39,63 +36,16 @@ const GRAPH_MAX_SELECTION_RIGHT_PADDING 
 const GRAPH_REGION_LINE_WIDTH = 1; // px
 const GRAPH_REGION_LINE_COLOR = "rgba(237,38,85,0.8)";
 
 const GRAPH_STRIPE_PATTERN_WIDTH = 16; // px
 const GRAPH_STRIPE_PATTERN_HEIGHT = 16; // px
 const GRAPH_STRIPE_PATTERN_LINE_WIDTH = 2; // px
 const GRAPH_STRIPE_PATTERN_LINE_SPACING = 4; // px
 
-// Line graph constants.
-
-const LINE_GRAPH_DAMPEN_VALUES = 0.85;
-const LINE_GRAPH_TOOLTIP_SAFE_BOUNDS = 8; // px
-const LINE_GRAPH_MIN_MAX_TOOLTIP_DISTANCE = 14; // px
-
-const LINE_GRAPH_BACKGROUND_COLOR = "#0088cc";
-const LINE_GRAPH_STROKE_WIDTH = 1; // px
-const LINE_GRAPH_STROKE_COLOR = "rgba(255,255,255,0.9)";
-const LINE_GRAPH_HELPER_LINES_DASH = [5]; // px
-const LINE_GRAPH_HELPER_LINES_WIDTH = 1; // px
-const LINE_GRAPH_MAXIMUM_LINE_COLOR = "rgba(255,255,255,0.4)";
-const LINE_GRAPH_AVERAGE_LINE_COLOR = "rgba(255,255,255,0.7)";
-const LINE_GRAPH_MINIMUM_LINE_COLOR = "rgba(255,255,255,0.9)";
-const LINE_GRAPH_BACKGROUND_GRADIENT_START = "rgba(255,255,255,0.25)";
-const LINE_GRAPH_BACKGROUND_GRADIENT_END = "rgba(255,255,255,0.0)";
-
-const LINE_GRAPH_CLIPHEAD_LINE_COLOR = "#fff";
-const LINE_GRAPH_SELECTION_LINE_COLOR = "#fff";
-const LINE_GRAPH_SELECTION_BACKGROUND_COLOR = "rgba(44,187,15,0.25)";
-const LINE_GRAPH_SELECTION_STRIPES_COLOR = "rgba(255,255,255,0.1)";
-const LINE_GRAPH_REGION_BACKGROUND_COLOR = "transparent";
-const LINE_GRAPH_REGION_STRIPES_COLOR = "rgba(237,38,85,0.2)";
-
-// Bar graph constants.
-
-const BAR_GRAPH_DAMPEN_VALUES = 0.75;
-const BAR_GRAPH_BARS_MARGIN_TOP = 1; // px
-const BAR_GRAPH_BARS_MARGIN_END = 1; // px
-const BAR_GRAPH_MIN_BARS_WIDTH = 5; // px
-const BAR_GRAPH_MIN_BLOCKS_HEIGHT = 1; // px
-
-const BAR_GRAPH_BACKGROUND_GRADIENT_START = "rgba(0,136,204,0.0)";
-const BAR_GRAPH_BACKGROUND_GRADIENT_END = "rgba(255,255,255,0.25)";
-
-const BAR_GRAPH_CLIPHEAD_LINE_COLOR = "#666";
-const BAR_GRAPH_SELECTION_LINE_COLOR = "#555";
-const BAR_GRAPH_SELECTION_BACKGROUND_COLOR = "rgba(0,136,204,0.25)";
-const BAR_GRAPH_SELECTION_STRIPES_COLOR = "rgba(255,255,255,0.1)";
-const BAR_GRAPH_REGION_BACKGROUND_COLOR = "transparent";
-const BAR_GRAPH_REGION_STRIPES_COLOR = "rgba(237,38,85,0.2)";
-
-const BAR_GRAPH_HIGHLIGHTS_MASK_BACKGROUND = "rgba(255,255,255,0.75)";
-const BAR_GRAPH_HIGHLIGHTS_MASK_STRIPES = "rgba(255,255,255,0.5)";
-
-const BAR_GRAPH_LEGEND_MOUSEOVER_DEBOUNCE = 50; // ms
-
 /**
  * Small data primitives for all graphs.
  */
 this.GraphCursor = function() {
   this.x = null;
   this.y = null;
 };
 
@@ -1235,792 +1185,16 @@ AbstractCanvasGraph.prototype = {
    */
   _onResize: function() {
     if (this.hasData()) {
       setNamedTimeout(this._uid, GRAPH_RESIZE_EVENTS_DRAIN, this.refresh);
     }
   }
 };
 
-/**
- * A basic line graph, plotting values on a curve and adding helper lines
- * and tooltips for maximum, average and minimum values.
- *
- * @see AbstractCanvasGraph for emitted events and other options.
- *
- * Example usage:
- *   let graph = new LineGraphWidget(node, "units");
- *   graph.once("ready", () => {
- *     graph.setData(src);
- *   });
- *
- * Data source format:
- *   [
- *     { delta: x1, value: y1 },
- *     { delta: x2, value: y2 },
- *     ...
- *     { delta: xn, value: yn }
- *   ]
- * where each item in the array represents a point in the graph.
- *
- * @param nsIDOMNode parent
- *        The parent node holding the graph.
- * @param object options [optional]
- *        `metric`: The metric displayed in the graph, e.g. "fps" or "bananas".
- *        `min`: Boolean whether to show the min tooltip/gutter/line (default: true)
- *        `max`: Boolean whether to show the max tooltip/gutter/line (default: true)
- *        `avg`: Boolean whether to show the avg tooltip/gutter/line (default: true)
- */
-this.LineGraphWidget = function(parent, options, ...args) {
-  options = options || {};
-  let metric = options.metric;
-
-  this._showMin = options.min !== false;
-  this._showMax = options.max !== false;
-  this._showAvg = options.avg !== false;
-  AbstractCanvasGraph.apply(this, [parent, "line-graph", ...args]);
-
-  this.once("ready", () => {
-    // Create all gutters and tooltips incase the showing of min/max/avg
-    // are changed later
-    this._gutter = this._createGutter();
-
-    this._maxGutterLine = this._createGutterLine("maximum");
-    this._maxTooltip = this._createTooltip("maximum", "start", "max", metric);
-    this._minGutterLine = this._createGutterLine("minimum");
-    this._minTooltip = this._createTooltip("minimum", "start", "min", metric);
-    this._avgGutterLine = this._createGutterLine("average");
-    this._avgTooltip = this._createTooltip("average", "end", "avg", metric);
-  });
-};
-
-LineGraphWidget.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
-  backgroundColor: LINE_GRAPH_BACKGROUND_COLOR,
-  backgroundGradientStart: LINE_GRAPH_BACKGROUND_GRADIENT_START,
-  backgroundGradientEnd: LINE_GRAPH_BACKGROUND_GRADIENT_END,
-  strokeColor: LINE_GRAPH_STROKE_COLOR,
-  strokeWidth: LINE_GRAPH_STROKE_WIDTH,
-  maximumLineColor: LINE_GRAPH_MAXIMUM_LINE_COLOR,
-  averageLineColor: LINE_GRAPH_AVERAGE_LINE_COLOR,
-  minimumLineColor: LINE_GRAPH_MINIMUM_LINE_COLOR,
-  clipheadLineColor: LINE_GRAPH_CLIPHEAD_LINE_COLOR,
-  selectionLineColor: LINE_GRAPH_SELECTION_LINE_COLOR,
-  selectionBackgroundColor: LINE_GRAPH_SELECTION_BACKGROUND_COLOR,
-  selectionStripesColor: LINE_GRAPH_SELECTION_STRIPES_COLOR,
-  regionBackgroundColor: LINE_GRAPH_REGION_BACKGROUND_COLOR,
-  regionStripesColor: LINE_GRAPH_REGION_STRIPES_COLOR,
-
-  /**
-   * Optionally offsets the `delta` in the data source by this scalar.
-   */
-  dataOffsetX: 0,
-
-  /**
-   * Optionally uses this value instead of the last tick in the data source
-   * to compute the horizontal scaling.
-   */
-  dataDuration: 0,
-
-  /**
-   * The scalar used to multiply the graph values to leave some headroom.
-   */
-  dampenValuesFactor: LINE_GRAPH_DAMPEN_VALUES,
-
-  /**
-   * Specifies if min/max/avg tooltips have arrow handlers on their sides.
-   */
-  withTooltipArrows: true,
-
-  /**
-   * Specifies if min/max/avg tooltips are positioned based on the actual
-   * values, or just placed next to the graph corners.
-   */
-  withFixedTooltipPositions: false,
-
-  /**
-   * Takes a list of numbers and plots them on a line graph representing
-   * the rate of occurences in a specified interval. Useful for drawing
-   * framerate, for example, from a sequence of timestamps.
-   *
-   * @param array timestamps
-   *        A list of numbers representing time, ordered ascending. For example,
-   *        this can be the raw data received from the framerate actor, which
-   *        represents the elapsed time on each refresh driver tick.
-   * @param number interval
-   *        The maximum amount of time to wait between calculations.
-   * @param number duration
-   *        The duration of the recording in milliseconds.
-   */
-  setDataFromTimestamps: Task.async(function*(timestamps, interval, duration) {
-    let {
-      plottedData,
-      plottedMinMaxSum
-    } = yield CanvasGraphUtils._performTaskInWorker("plotTimestampsGraph", {
-      timestamps, interval, duration
-    });
-
-    this._tempMinMaxSum = plottedMinMaxSum;
-    this.setData(plottedData);
-  }),
-
-  /**
-   * Renders the graph's data source.
-   * @see AbstractCanvasGraph.prototype.buildGraphImage
-   */
-  buildGraphImage: function() {
-    let { canvas, ctx } = this._getNamedCanvas("line-graph-data");
-    let width = this._width;
-    let height = this._height;
-
-    let totalTicks = this._data.length;
-    let firstTick = totalTicks ? this._data[0].delta : 0;
-    let lastTick = totalTicks ? this._data[totalTicks - 1].delta : 0;
-    let maxValue = Number.MIN_SAFE_INTEGER;
-    let minValue = Number.MAX_SAFE_INTEGER;
-    let avgValue = 0;
-
-    if (this._tempMinMaxSum) {
-      maxValue = this._tempMinMaxSum.maxValue;
-      minValue = this._tempMinMaxSum.minValue;
-      avgValue = this._tempMinMaxSum.avgValue;
-    } else {
-      let sumValues = 0;
-      for (let { delta, value } of this._data) {
-        maxValue = Math.max(value, maxValue);
-        minValue = Math.min(value, minValue);
-        sumValues += value;
-      }
-      avgValue = sumValues / totalTicks;
-    }
-
-    let duration = this.dataDuration || lastTick;
-    let dataScaleX = this.dataScaleX = width / (duration - this.dataOffsetX);
-    let dataScaleY = this.dataScaleY = height / maxValue * this.dampenValuesFactor;
-
-    // Draw the background.
-
-    ctx.fillStyle = this.backgroundColor;
-    ctx.fillRect(0, 0, width, height);
-
-    // Draw the graph.
-
-    let gradient = ctx.createLinearGradient(0, height / 2, 0, height);
-    gradient.addColorStop(0, this.backgroundGradientStart);
-    gradient.addColorStop(1, this.backgroundGradientEnd);
-    ctx.fillStyle = gradient;
-    ctx.strokeStyle = this.strokeColor;
-    ctx.lineWidth = this.strokeWidth * this._pixelRatio;
-    ctx.beginPath();
-
-    for (let { delta, value } of this._data) {
-      let currX = (delta - this.dataOffsetX) * dataScaleX;
-      let currY = height - value * dataScaleY;
-
-      if (delta == firstTick) {
-        ctx.moveTo(-LINE_GRAPH_STROKE_WIDTH, height);
-        ctx.lineTo(-LINE_GRAPH_STROKE_WIDTH, currY);
-      }
-
-      ctx.lineTo(currX, currY);
-
-      if (delta == lastTick) {
-        ctx.lineTo(width + LINE_GRAPH_STROKE_WIDTH, currY);
-        ctx.lineTo(width + LINE_GRAPH_STROKE_WIDTH, height);
-      }
-    }
-
-    ctx.fill();
-    ctx.stroke();
-
-    this._drawOverlays(ctx, minValue, maxValue, avgValue, dataScaleY);
-
-    return canvas;
-  },
-
-  /**
-   * Draws the min, max and average horizontal lines, along with their
-   * repsective tooltips.
-   *
-   * @param CanvasRenderingContext2D ctx
-   * @param number minValue
-   * @param number maxValue
-   * @param number avgValue
-   * @param number dataScaleY
-   */
-  _drawOverlays: function(ctx, minValue, maxValue, avgValue, dataScaleY) {
-    let width = this._width;
-    let height = this._height;
-    let totalTicks = this._data.length;
-
-    // Draw the maximum value horizontal line.
-    if (this._showMax) {
-      ctx.strokeStyle = this.maximumLineColor;
-      ctx.lineWidth = LINE_GRAPH_HELPER_LINES_WIDTH;
-      ctx.setLineDash(LINE_GRAPH_HELPER_LINES_DASH);
-      ctx.beginPath();
-      let maximumY = height - maxValue * dataScaleY;
-      ctx.moveTo(0, maximumY);
-      ctx.lineTo(width, maximumY);
-      ctx.stroke();
-    }
-
-    // Draw the average value horizontal line.
-    if (this._showAvg) {
-      ctx.strokeStyle = this.averageLineColor;
-      ctx.lineWidth = LINE_GRAPH_HELPER_LINES_WIDTH;
-      ctx.setLineDash(LINE_GRAPH_HELPER_LINES_DASH);
-      ctx.beginPath();
-      let averageY = height - avgValue * dataScaleY;
-      ctx.moveTo(0, averageY);
-      ctx.lineTo(width, averageY);
-      ctx.stroke();
-    }
-
-    // Draw the minimum value horizontal line.
-    if (this._showMin) {
-      ctx.strokeStyle = this.minimumLineColor;
-      ctx.lineWidth = LINE_GRAPH_HELPER_LINES_WIDTH;
-      ctx.setLineDash(LINE_GRAPH_HELPER_LINES_DASH);
-      ctx.beginPath();
-      let minimumY = height - minValue * dataScaleY;
-      ctx.moveTo(0, minimumY);
-      ctx.lineTo(width, minimumY);
-      ctx.stroke();
-    }
-
-    // Update the tooltips text and gutter lines.
-
-    this._maxTooltip.querySelector("[text=value]").textContent =
-      L10N.numberWithDecimals(maxValue, 2);
-    this._avgTooltip.querySelector("[text=value]").textContent =
-      L10N.numberWithDecimals(avgValue, 2);
-    this._minTooltip.querySelector("[text=value]").textContent =
-      L10N.numberWithDecimals(minValue, 2);
-
-    let bottom = height / this._pixelRatio;
-    let maxPosY = map(maxValue * this.dampenValuesFactor, 0, maxValue, bottom, 0);
-    let avgPosY = map(avgValue * this.dampenValuesFactor, 0, maxValue, bottom, 0);
-    let minPosY = map(minValue * this.dampenValuesFactor, 0, maxValue, bottom, 0);
-
-    let safeTop = LINE_GRAPH_TOOLTIP_SAFE_BOUNDS;
-    let safeBottom = bottom - LINE_GRAPH_TOOLTIP_SAFE_BOUNDS;
-
-    let maxTooltipTop = (this.withFixedTooltipPositions
-      ? safeTop : clamp(maxPosY, safeTop, safeBottom));
-    let avgTooltipTop = (this.withFixedTooltipPositions
-      ? safeTop : clamp(avgPosY, safeTop, safeBottom));
-    let minTooltipTop = (this.withFixedTooltipPositions
-      ? safeBottom : clamp(minPosY, safeTop, safeBottom));
-
-    this._maxTooltip.style.top = maxTooltipTop + "px";
-    this._avgTooltip.style.top = avgTooltipTop + "px";
-    this._minTooltip.style.top = minTooltipTop + "px";
-
-    this._maxGutterLine.style.top = maxPosY + "px";
-    this._avgGutterLine.style.top = avgPosY + "px";
-    this._minGutterLine.style.top = minPosY + "px";
-
-    this._maxTooltip.setAttribute("with-arrows", this.withTooltipArrows);
-    this._avgTooltip.setAttribute("with-arrows", this.withTooltipArrows);
-    this._minTooltip.setAttribute("with-arrows", this.withTooltipArrows);
-
-    let distanceMinMax = Math.abs(maxTooltipTop - minTooltipTop);
-    this._maxTooltip.hidden = this._showMax === false || !totalTicks || distanceMinMax < LINE_GRAPH_MIN_MAX_TOOLTIP_DISTANCE;
-    this._avgTooltip.hidden = this._showAvg === false || !totalTicks;
-    this._minTooltip.hidden = this._showMin === false || !totalTicks;
-    this._gutter.hidden = (this._showMin === false && this._showAvg === false && this._showMax === false) || !totalTicks;
-
-    this._maxGutterLine.hidden = this._showMax === false;
-    this._avgGutterLine.hidden = this._showAvg === false;
-    this._minGutterLine.hidden = this._showMin === false;
-  },
-
-  /**
-   * Creates the gutter node when constructing this graph.
-   * @return nsIDOMNode
-   */
-  _createGutter: function() {
-    let gutter = this._document.createElementNS(HTML_NS, "div");
-    gutter.className = "line-graph-widget-gutter";
-    gutter.setAttribute("hidden", true);
-    this._container.appendChild(gutter);
-
-    return gutter;
-  },
-
-  /**
-   * Creates the gutter line nodes when constructing this graph.
-   * @return nsIDOMNode
-   */
-  _createGutterLine: function(type) {
-    let line = this._document.createElementNS(HTML_NS, "div");
-    line.className = "line-graph-widget-gutter-line";
-    line.setAttribute("type", type);
-    this._gutter.appendChild(line);
-
-    return line;
-  },
-
-  /**
-   * Creates the tooltip nodes when constructing this graph.
-   * @return nsIDOMNode
-   */
-  _createTooltip: function(type, arrow, info, metric) {
-    let tooltip = this._document.createElementNS(HTML_NS, "div");
-    tooltip.className = "line-graph-widget-tooltip";
-    tooltip.setAttribute("type", type);
-    tooltip.setAttribute("arrow", arrow);
-    tooltip.setAttribute("hidden", true);
-
-    let infoNode = this._document.createElementNS(HTML_NS, "span");
-    infoNode.textContent = info;
-    infoNode.setAttribute("text", "info");
-
-    let valueNode = this._document.createElementNS(HTML_NS, "span");
-    valueNode.textContent = 0;
-    valueNode.setAttribute("text", "value");
-
-    let metricNode = this._document.createElementNS(HTML_NS, "span");
-    metricNode.textContent = metric;
-    metricNode.setAttribute("text", "metric");
-
-    tooltip.appendChild(infoNode);
-    tooltip.appendChild(valueNode);
-    tooltip.appendChild(metricNode);
-    this._container.appendChild(tooltip);
-
-    return tooltip;
-  }
-});
-
-/**
- * A bar graph, plotting tuples of values as rectangles.
- *
- * @see AbstractCanvasGraph for emitted events and other options.
- *
- * Example usage:
- *   let graph = new BarGraphWidget(node);
- *   graph.format = ...;
- *   graph.once("ready", () => {
- *     graph.setData(src);
- *   });
- *
- * The `graph.format` traits are mandatory and will determine how the values
- * are styled as "blocks" in every "bar":
- *   [
- *     { color: "#f00", label: "Foo" },
- *     { color: "#0f0", label: "Bar" },
- *     ...
- *     { color: "#00f", label: "Baz" }
- *   ]
- *
- * Data source format:
- *   [
- *     { delta: x1, values: [y11, y12, ... y1n] },
- *     { delta: x2, values: [y21, y22, ... y2n] },
- *     ...
- *     { delta: xm, values: [ym1, ym2, ... ymn] }
- *   ]
- * where each item in the array represents a "bar", for which every value
- * represents a "block" inside that "bar", plotted at the "delta" position.
- *
- * @param nsIDOMNode parent
- *        The parent node holding the graph.
- */
-this.BarGraphWidget = function(parent, ...args) {
-  AbstractCanvasGraph.apply(this, [parent, "bar-graph", ...args]);
-
-  // Populated with [node, event, listener] entries which need to be removed
-  // when this graph is being destroyed.
-  this.outstandingEventListeners = [];
-
-  this.once("ready", () => {
-    this._onLegendMouseOver = this._onLegendMouseOver.bind(this);
-    this._onLegendMouseOut = this._onLegendMouseOut.bind(this);
-    this._onLegendMouseDown = this._onLegendMouseDown.bind(this);
-    this._onLegendMouseUp = this._onLegendMouseUp.bind(this);
-    this._createLegend();
-  });
-
-  this.once("destroyed", () => {
-    for (let [node, event, listener] of this.outstandingEventListeners) {
-      node.removeEventListener(event, listener);
-    }
-    this.outstandingEventListeners = null;
-  });
-};
-
-BarGraphWidget.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
-  clipheadLineColor: BAR_GRAPH_CLIPHEAD_LINE_COLOR,
-  selectionLineColor: BAR_GRAPH_SELECTION_LINE_COLOR,
-  selectionBackgroundColor: BAR_GRAPH_SELECTION_BACKGROUND_COLOR,
-  selectionStripesColor: BAR_GRAPH_SELECTION_STRIPES_COLOR,
-  regionBackgroundColor: BAR_GRAPH_REGION_BACKGROUND_COLOR,
-  regionStripesColor: BAR_GRAPH_REGION_STRIPES_COLOR,
-
-  /**
-   * List of colors used to fill each block inside every bar, also
-   * corresponding to labels displayed in this graph's legend.
-   */
-  format: null,
-
-  /**
-   * Optionally offsets the `delta` in the data source by this scalar.
-   */
-  dataOffsetX: 0,
-
-  /**
-   * The scalar used to multiply the graph values to leave some headroom
-   * on the top.
-   */
-  dampenValuesFactor: BAR_GRAPH_DAMPEN_VALUES,
-
-  /**
-   * Bars that are too close too each other in the graph will be combined.
-   * This scalar specifies the required minimum width of each bar.
-   */
-  minBarsWidth: BAR_GRAPH_MIN_BARS_WIDTH,
-
-  /**
-   * Blocks in a bar that are too thin inside the bar will not be rendered.
-   * This scalar specifies the required minimum height of each block.
-   */
-  minBlocksHeight: BAR_GRAPH_MIN_BLOCKS_HEIGHT,
-
-  /**
-   * Renders the graph's background.
-   * @see AbstractCanvasGraph.prototype.buildBackgroundImage
-   */
-  buildBackgroundImage: function() {
-    let { canvas, ctx } = this._getNamedCanvas("bar-graph-background");
-    let width = this._width;
-    let height = this._height;
-
-    let gradient = ctx.createLinearGradient(0, 0, 0, height);
-    gradient.addColorStop(0, BAR_GRAPH_BACKGROUND_GRADIENT_START);
-    gradient.addColorStop(1, BAR_GRAPH_BACKGROUND_GRADIENT_END);
-    ctx.fillStyle = gradient;
-    ctx.fillRect(0, 0, width, height);
-
-    return canvas;
-  },
-
-  /**
-   * Renders the graph's data source.
-   * @see AbstractCanvasGraph.prototype.buildGraphImage
-   */
-  buildGraphImage: function() {
-    if (!this.format || !this.format.length) {
-      throw "The graph format traits are mandatory to style the data source.";
-    }
-    let { canvas, ctx } = this._getNamedCanvas("bar-graph-data");
-    let width = this._width;
-    let height = this._height;
-
-    let totalTypes = this.format.length;
-    let totalTicks = this._data.length;
-    let lastTick = this._data[totalTicks - 1].delta;
-
-    let minBarsWidth = this.minBarsWidth * this._pixelRatio;
-    let minBlocksHeight = this.minBlocksHeight * this._pixelRatio;
-
-    let dataScaleX = this.dataScaleX = width / (lastTick - this.dataOffsetX);
-    let dataScaleY = this.dataScaleY = height / this._calcMaxHeight({
-      data: this._data,
-      dataScaleX: dataScaleX,
-      minBarsWidth: minBarsWidth
-    }) * this.dampenValuesFactor;
-
-    // Draw the graph.
-
-    // Iterate over the blocks, then the bars, to draw all rectangles of
-    // the same color in a single pass. See the @constructor for more
-    // information about the data source, and how a "bar" contains "blocks".
-
-    this._blocksBoundingRects = [];
-    let prevHeight = [];
-    let scaledMarginEnd = BAR_GRAPH_BARS_MARGIN_END * this._pixelRatio;
-    let unscaledMarginTop = BAR_GRAPH_BARS_MARGIN_TOP;
-
-    for (let type = 0; type < totalTypes; type++) {
-      ctx.fillStyle = this.format[type].color || "#000";
-      ctx.beginPath();
-
-      let prevRight = 0;
-      let skippedCount = 0;
-      let skippedHeight = 0;
-
-      for (let tick = 0; tick < totalTicks; tick++) {
-        let delta = this._data[tick].delta;
-        let value = this._data[tick].values[type] || 0;
-        let blockRight = (delta - this.dataOffsetX) * dataScaleX;
-        let blockHeight = value * dataScaleY;
-
-        let blockWidth = blockRight - prevRight;
-        if (blockWidth < minBarsWidth) {
-          skippedCount++;
-          skippedHeight += blockHeight;
-          continue;
-        }
-
-        let averageHeight = (blockHeight + skippedHeight) / (skippedCount + 1);
-        if (averageHeight >= minBlocksHeight) {
-          let bottom = height - ~~prevHeight[tick];
-          ctx.moveTo(prevRight, bottom);
-          ctx.lineTo(prevRight, bottom - averageHeight);
-          ctx.lineTo(blockRight, bottom - averageHeight);
-          ctx.lineTo(blockRight, bottom);
-
-          // Remember this block's type and location.
-          this._blocksBoundingRects.push({
-            type: type,
-            start: prevRight,
-            end: blockRight,
-            top: bottom - averageHeight,
-            bottom: bottom
-          });
-
-          if (prevHeight[tick] === undefined) {
-            prevHeight[tick] = averageHeight + unscaledMarginTop;
-          } else {
-            prevHeight[tick] += averageHeight + unscaledMarginTop;
-          }
-        }
-
-        prevRight += blockWidth + scaledMarginEnd;
-        skippedHeight = 0;
-        skippedCount = 0;
-      }
-
-      ctx.fill();
-    }
-
-    // The blocks bounding rects isn't guaranteed to be sorted ascending by
-    // block location on the X axis. This should be the case, for better
-    // cache cohesion and a faster `buildMaskImage`.
-    this._blocksBoundingRects.sort((a, b) => a.start > b.start ? 1 : -1);
-
-    // Update the legend.
-
-    while (this._legendNode.hasChildNodes()) {
-      this._legendNode.firstChild.remove();
-    }
-    for (let { color, label } of this.format) {
-      this._createLegendItem(color, label);
-    }
-
-    return canvas;
-  },
-
-  /**
-   * Renders the graph's mask.
-   * Fades in only the parts of the graph that are inside the specified areas.
-   *
-   * @param array highlights
-   *        A list of { start, end } values. Optionally, each object
-   *        in the list may also specify { top, bottom } pixel values if the
-   *        highlighting shouldn't span across the full height of the graph.
-   * @param boolean inPixels
-   *        Set this to true if the { start, end } values in the highlights
-   *        list are pixel values, and not values from the data source.
-   * @param function unpack [optional]
-   *        @see AbstractCanvasGraph.prototype.getMappedSelection
-   */
-  buildMaskImage: function(highlights, inPixels = false, unpack = e => e.delta) {
-    // A null `highlights` array is used to clear the mask. An empty array
-    // will mask the entire graph.
-    if (!highlights) {
-      return null;
-    }
-
-    // Get a render target for the highlights. It will be overlaid on top of
-    // the existing graph, masking the areas that aren't highlighted.
-
-    let { canvas, ctx } = this._getNamedCanvas("graph-highlights");
-    let width = this._width;
-    let height = this._height;
-
-    // Draw the background mask.
-
-    let pattern = AbstractCanvasGraph.getStripePattern({
-      ownerDocument: this._document,
-      backgroundColor: BAR_GRAPH_HIGHLIGHTS_MASK_BACKGROUND,
-      stripesColor: BAR_GRAPH_HIGHLIGHTS_MASK_STRIPES
-    });
-    ctx.fillStyle = pattern;
-    ctx.fillRect(0, 0, width, height);
-
-    // Clear highlighted areas.
-
-    let totalTicks = this._data.length;
-    let firstTick = unpack(this._data[0]);
-    let lastTick = unpack(this._data[totalTicks - 1]);
-
-    for (let { start, end, top, bottom } of highlights) {
-      if (!inPixels) {
-        start = map(start, firstTick, lastTick, 0, width);
-        end = map(end, firstTick, lastTick, 0, width);
-      }
-      let firstSnap = findFirst(this._blocksBoundingRects, e => e.start >= start);
-      let lastSnap = findLast(this._blocksBoundingRects, e => e.start >= start && e.end <= end);
-
-      let x1 = firstSnap ? firstSnap.start : start;
-      let x2 = lastSnap ? lastSnap.end : firstSnap ? firstSnap.end : end;
-      let y1 = top || 0;
-      let y2 = bottom || height;
-      ctx.clearRect(x1, y1, x2 - x1, y2 - y1);
-    }
-
-    return canvas;
-  },
-
-  /**
-   * A list storing the bounding rectangle for each drawn block in the graph.
-   * Created whenever `buildGraphImage` is invoked.
-   */
-  _blocksBoundingRects: null,
-
-  /**
-   * Calculates the height of the tallest bar that would eventially be rendered
-   * in this graph.
-   *
-   * Bars that are too close too each other in the graph will be combined.
-   * @see `minBarsWidth`
-   *
-   * @return number
-   *         The tallest bar height in this graph.
-   */
-  _calcMaxHeight: function({ data, dataScaleX, minBarsWidth }) {
-    let maxHeight = 0;
-    let prevRight = 0;
-    let skippedCount = 0;
-    let skippedHeight = 0;
-    let scaledMarginEnd = BAR_GRAPH_BARS_MARGIN_END * this._pixelRatio;
-
-    for (let { delta, values } of data) {
-      let barRight = (delta - this.dataOffsetX) * dataScaleX;
-      let barHeight = values.reduce((a, b) => a + b, 0);
-
-      let barWidth = barRight - prevRight;
-      if (barWidth < minBarsWidth) {
-        skippedCount++;
-        skippedHeight += barHeight;
-        continue;
-      }
-
-      let averageHeight = (barHeight + skippedHeight) / (skippedCount + 1);
-      maxHeight = Math.max(averageHeight, maxHeight);
-
-      prevRight += barWidth + scaledMarginEnd;
-      skippedHeight = 0;
-      skippedCount = 0;
-    }
-
-    return maxHeight;
-  },
-
-  /**
-   * Creates the legend container when constructing this graph.
-   */
-  _createLegend: function() {
-    let legendNode = this._legendNode = this._document.createElementNS(HTML_NS, "div");
-    legendNode.className = "bar-graph-widget-legend";
-    this._container.appendChild(legendNode);
-  },
-
-  /**
-   * Creates a legend item when constructing this graph.
-   */
-  _createLegendItem: function(color, label) {
-    let itemNode = this._document.createElementNS(HTML_NS, "div");
-    itemNode.className = "bar-graph-widget-legend-item";
-
-    let colorNode = this._document.createElementNS(HTML_NS, "span");
-    colorNode.setAttribute("view", "color");
-    colorNode.setAttribute("data-index", this._legendNode.childNodes.length);
-    colorNode.style.backgroundColor = color;
-    colorNode.addEventListener("mouseover", this._onLegendMouseOver);
-    colorNode.addEventListener("mouseout", this._onLegendMouseOut);
-    colorNode.addEventListener("mousedown", this._onLegendMouseDown);
-    colorNode.addEventListener("mouseup", this._onLegendMouseUp);
-
-    this.outstandingEventListeners.push([colorNode, "mouseover", this._onLegendMouseOver]);
-    this.outstandingEventListeners.push([colorNode, "mouseout", this._onLegendMouseOut]);
-    this.outstandingEventListeners.push([colorNode, "mousedown", this._onLegendMouseDown]);
-    this.outstandingEventListeners.push([colorNode, "mouseup", this._onLegendMouseUp]);
-
-    let labelNode = this._document.createElementNS(HTML_NS, "span");
-    labelNode.setAttribute("view", "label");
-    labelNode.textContent = label;
-
-    itemNode.appendChild(colorNode);
-    itemNode.appendChild(labelNode);
-    this._legendNode.appendChild(itemNode);
-  },
-
-  /**
-   * Invoked whenever a color node in the legend is hovered.
-   */
-  _onLegendMouseOver: function(e) {
-    setNamedTimeout("bar-graph-debounce", BAR_GRAPH_LEGEND_MOUSEOVER_DEBOUNCE, () => {
-      let type = e.target.dataset.index;
-      let rects = this._blocksBoundingRects.filter(e => e.type == type);
-
-      this._originalHighlights = this._mask;
-      this._hasCustomHighlights = true;
-      this.setMask(rects, true);
-
-      this.emit("legend-hover", [type, rects]);
-    });
-  },
-
-  /**
-   * Invoked whenever a color node in the legend is unhovered.
-   */
-  _onLegendMouseOut: function() {
-    clearNamedTimeout("bar-graph-debounce");
-
-    if (this._hasCustomHighlights) {
-      this.setMask(this._originalHighlights);
-      this._hasCustomHighlights = false;
-      this._originalHighlights = null;
-    }
-
-    this.emit("legend-unhover");
-  },
-
-  /**
-   * Invoked whenever a color node in the legend is pressed.
-   */
-  _onLegendMouseDown: function(e) {
-    e.preventDefault();
-    e.stopPropagation();
-
-    let type = e.target.dataset.index;
-    let rects = this._blocksBoundingRects.filter(e => e.type == type);
-    let leftmost = rects[0];
-    let rightmost = rects[rects.length - 1];
-    if (!leftmost || !rightmost) {
-      this.dropSelection();
-    } else {
-      this.setSelection({ start: leftmost.start, end: rightmost.end });
-    }
-
-    this.emit("legend-selection", [leftmost, rightmost]);
-  },
-
-  /**
-   * Invoked whenever a color node in the legend is released.
-   */
-  _onLegendMouseUp: function(e) {
-    e.preventDefault();
-    e.stopPropagation();
-  }
-});
-
 // Helper functions.
 
 /**
  * Creates an iframe element with the provided source URL, appends it to
  * the specified node and invokes the callback once the content is loaded.
  *
  * @param string url
  *        The desired source URL for the iframe.
@@ -2194,51 +1368,16 @@ function map(value, istart, istop, ostar
  * @return number
  */
 function clamp(value, min, max) {
   if (value < min) return min;
   if (value > max) return max;
   return value;
 }
 
-/**
- * Calculates the squared distance between two 2D points.
- */
-function distSquared(x0, y0, x1, y1) {
-  let xs = x1 - x0;
-  let ys = y1 - y0;
-  return xs * xs + ys * ys;
-}
-
-/**
- * Finds the first element in an array that validates a predicate.
- * @param array
- * @param function predicate
- * @return number
- */
-function findFirst(array, predicate) {
-  for (let i = 0, len = array.length; i < len; i++) {
-    let element = array[i];
-    if (predicate(element)) return element;
-  }
-}
-
 exports.GraphCursor = GraphCursor;
 exports.GraphArea = GraphArea;
 exports.GraphAreaDragger = GraphAreaDragger;
 exports.GraphAreaResizer = GraphAreaResizer;
 exports.AbstractCanvasGraph = AbstractCanvasGraph;
-exports.LineGraphWidget = LineGraphWidget;
-exports.BarGraphWidget = BarGraphWidget;
 exports.CanvasGraphUtils = CanvasGraphUtils;
-
-/**
- * Finds the last element in an array that validates a predicate.
- * @param array
- * @param function predicate
- * @return number
- */
-function findLast(array, predicate) {
-  for (let i = array.length - 1; i >= 0; i--) {
-    let element = array[i];
-    if (predicate(element)) return element;
-  }
-}
+exports.CanvasGraphUtils.map = map;
+exports.CanvasGraphUtils.clamp = clamp;
new file mode 100644
--- /dev/null
+++ b/browser/devtools/shared/widgets/LineGraphWidget.js
@@ -0,0 +1,386 @@
+"use strict";
+
+const { Cc, Ci, Cu, Cr } = require("chrome");
+
+const { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
+const { ViewHelpers, Heritage } = require("resource:///modules/devtools/ViewHelpers.jsm");
+const { AbstractCanvasGraph, CanvasGraphUtils } = require("devtools/shared/widgets/Graphs");
+
+const HTML_NS = "http://www.w3.org/1999/xhtml";
+const L10N = new ViewHelpers.L10N();
+
+// Line graph constants.
+
+const GRAPH_DAMPEN_VALUES_FACTOR = 0.85;
+const GRAPH_TOOLTIP_SAFE_BOUNDS = 8; // px
+const GRAPH_MIN_MAX_TOOLTIP_DISTANCE = 14; // px
+
+const GRAPH_BACKGROUND_COLOR = "#0088cc";
+const GRAPH_STROKE_WIDTH = 1; // px
+const GRAPH_STROKE_COLOR = "rgba(255,255,255,0.9)";
+const GRAPH_HELPER_LINES_DASH = [5]; // px
+const GRAPH_HELPER_LINES_WIDTH = 1; // px
+const GRAPH_MAXIMUM_LINE_COLOR = "rgba(255,255,255,0.4)";
+const GRAPH_AVERAGE_LINE_COLOR = "rgba(255,255,255,0.7)";
+const GRAPH_MINIMUM_LINE_COLOR = "rgba(255,255,255,0.9)";
+const GRAPH_BACKGROUND_GRADIENT_START = "rgba(255,255,255,0.25)";
+const GRAPH_BACKGROUND_GRADIENT_END = "rgba(255,255,255,0.0)";
+
+const GRAPH_CLIPHEAD_LINE_COLOR = "#fff";
+const GRAPH_SELECTION_LINE_COLOR = "#fff";
+const GRAPH_SELECTION_BACKGROUND_COLOR = "rgba(44,187,15,0.25)";
+const GRAPH_SELECTION_STRIPES_COLOR = "rgba(255,255,255,0.1)";
+const GRAPH_REGION_BACKGROUND_COLOR = "transparent";
+const GRAPH_REGION_STRIPES_COLOR = "rgba(237,38,85,0.2)";
+
+/**
+ * A basic line graph, plotting values on a curve and adding helper lines
+ * and tooltips for maximum, average and minimum values.
+ *
+ * @see AbstractCanvasGraph for emitted events and other options.
+ *
+ * Example usage:
+ *   let graph = new LineGraphWidget(node, "units");
+ *   graph.once("ready", () => {
+ *     graph.setData(src);
+ *   });
+ *
+ * Data source format:
+ *   [
+ *     { delta: x1, value: y1 },
+ *     { delta: x2, value: y2 },
+ *     ...
+ *     { delta: xn, value: yn }
+ *   ]
+ * where each item in the array represents a point in the graph.
+ *
+ * @param nsIDOMNode parent
+ *        The parent node holding the graph.
+ * @param object options [optional]
+ *        `metric`: The metric displayed in the graph, e.g. "fps" or "bananas".
+ *        `min`: Boolean whether to show the min tooltip/gutter/line (default: true)
+ *        `max`: Boolean whether to show the max tooltip/gutter/line (default: true)
+ *        `avg`: Boolean whether to show the avg tooltip/gutter/line (default: true)
+ */
+this.LineGraphWidget = function(parent, options = {}, ...args) {
+  let { metric, min, max, avg } = options;
+
+  this._showMin = min !== false;
+  this._showMax = max !== false;
+  this._showAvg = avg !== false;
+
+  AbstractCanvasGraph.apply(this, [parent, "line-graph", ...args]);
+
+  this.once("ready", () => {
+    // Create all gutters and tooltips incase the showing of min/max/avg
+    // are changed later
+    this._gutter = this._createGutter();
+    this._maxGutterLine = this._createGutterLine("maximum");
+    this._maxTooltip = this._createTooltip("maximum", "start", "max", metric);
+    this._minGutterLine = this._createGutterLine("minimum");
+    this._minTooltip = this._createTooltip("minimum", "start", "min", metric);
+    this._avgGutterLine = this._createGutterLine("average");
+    this._avgTooltip = this._createTooltip("average", "end", "avg", metric);
+  });
+};
+
+LineGraphWidget.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
+  backgroundColor: GRAPH_BACKGROUND_COLOR,
+  backgroundGradientStart: GRAPH_BACKGROUND_GRADIENT_START,
+  backgroundGradientEnd: GRAPH_BACKGROUND_GRADIENT_END,
+  strokeColor: GRAPH_STROKE_COLOR,
+  strokeWidth: GRAPH_STROKE_WIDTH,
+  maximumLineColor: GRAPH_MAXIMUM_LINE_COLOR,
+  averageLineColor: GRAPH_AVERAGE_LINE_COLOR,
+  minimumLineColor: GRAPH_MINIMUM_LINE_COLOR,
+  clipheadLineColor: GRAPH_CLIPHEAD_LINE_COLOR,
+  selectionLineColor: GRAPH_SELECTION_LINE_COLOR,
+  selectionBackgroundColor: GRAPH_SELECTION_BACKGROUND_COLOR,
+  selectionStripesColor: GRAPH_SELECTION_STRIPES_COLOR,
+  regionBackgroundColor: GRAPH_REGION_BACKGROUND_COLOR,
+  regionStripesColor: GRAPH_REGION_STRIPES_COLOR,
+
+  /**
+   * Optionally offsets the `delta` in the data source by this scalar.
+   */
+  dataOffsetX: 0,
+
+  /**
+   * Optionally uses this value instead of the last tick in the data source
+   * to compute the horizontal scaling.
+   */
+  dataDuration: 0,
+
+  /**
+   * The scalar used to multiply the graph values to leave some headroom.
+   */
+  dampenValuesFactor: GRAPH_DAMPEN_VALUES_FACTOR,
+
+  /**
+   * Specifies if min/max/avg tooltips have arrow handlers on their sides.
+   */
+  withTooltipArrows: true,
+
+  /**
+   * Specifies if min/max/avg tooltips are positioned based on the actual
+   * values, or just placed next to the graph corners.
+   */
+  withFixedTooltipPositions: false,
+
+  /**
+   * Takes a list of numbers and plots them on a line graph representing
+   * the rate of occurences in a specified interval. Useful for drawing
+   * framerate, for example, from a sequence of timestamps.
+   *
+   * @param array timestamps
+   *        A list of numbers representing time, ordered ascending. For example,
+   *        this can be the raw data received from the framerate actor, which
+   *        represents the elapsed time on each refresh driver tick.
+   * @param number interval
+   *        The maximum amount of time to wait between calculations.
+   * @param number duration
+   *        The duration of the recording in milliseconds.
+   */
+  setDataFromTimestamps: Task.async(function*(timestamps, interval, duration) {
+    let {
+      plottedData,
+      plottedMinMaxSum
+    } = yield CanvasGraphUtils._performTaskInWorker("plotTimestampsGraph", {
+      timestamps, interval, duration
+    });
+
+    this._tempMinMaxSum = plottedMinMaxSum;
+    this.setData(plottedData);
+  }),
+
+  /**
+   * Renders the graph's data source.
+   * @see AbstractCanvasGraph.prototype.buildGraphImage
+   */
+  buildGraphImage: function() {
+    let { canvas, ctx } = this._getNamedCanvas("line-graph-data");
+    let width = this._width;
+    let height = this._height;
+
+    let totalTicks = this._data.length;
+    let firstTick = totalTicks ? this._data[0].delta : 0;
+    let lastTick = totalTicks ? this._data[totalTicks - 1].delta : 0;
+    let maxValue = Number.MIN_SAFE_INTEGER;
+    let minValue = Number.MAX_SAFE_INTEGER;
+    let avgValue = 0;
+
+    if (this._tempMinMaxSum) {
+      maxValue = this._tempMinMaxSum.maxValue;
+      minValue = this._tempMinMaxSum.minValue;
+      avgValue = this._tempMinMaxSum.avgValue;
+    } else {
+      let sumValues = 0;
+      for (let { delta, value } of this._data) {
+        maxValue = Math.max(value, maxValue);
+        minValue = Math.min(value, minValue);
+        sumValues += value;
+      }
+      avgValue = sumValues / totalTicks;
+    }
+
+    let duration = this.dataDuration || lastTick;
+    let dataScaleX = this.dataScaleX = width / (duration - this.dataOffsetX);
+    let dataScaleY = this.dataScaleY = height / maxValue * this.dampenValuesFactor;
+
+    // Draw the background.
+
+    ctx.fillStyle = this.backgroundColor;
+    ctx.fillRect(0, 0, width, height);
+
+    // Draw the graph.
+
+    let gradient = ctx.createLinearGradient(0, height / 2, 0, height);
+    gradient.addColorStop(0, this.backgroundGradientStart);
+    gradient.addColorStop(1, this.backgroundGradientEnd);
+    ctx.fillStyle = gradient;
+    ctx.strokeStyle = this.strokeColor;
+    ctx.lineWidth = this.strokeWidth * this._pixelRatio;
+    ctx.beginPath();
+
+    for (let { delta, value } of this._data) {
+      let currX = (delta - this.dataOffsetX) * dataScaleX;
+      let currY = height - value * dataScaleY;
+
+      if (delta == firstTick) {
+        ctx.moveTo(-GRAPH_STROKE_WIDTH, height);
+        ctx.lineTo(-GRAPH_STROKE_WIDTH, currY);
+      }
+
+      ctx.lineTo(currX, currY);
+
+      if (delta == lastTick) {
+        ctx.lineTo(width + GRAPH_STROKE_WIDTH, currY);
+        ctx.lineTo(width + GRAPH_STROKE_WIDTH, height);
+      }
+    }
+
+    ctx.fill();
+    ctx.stroke();
+
+    this._drawOverlays(ctx, minValue, maxValue, avgValue, dataScaleY);
+
+    return canvas;
+  },
+
+  /**
+   * Draws the min, max and average horizontal lines, along with their
+   * repsective tooltips.
+   *
+   * @param CanvasRenderingContext2D ctx
+   * @param number minValue
+   * @param number maxValue
+   * @param number avgValue
+   * @param number dataScaleY
+   */
+  _drawOverlays: function(ctx, minValue, maxValue, avgValue, dataScaleY) {
+    let width = this._width;
+    let height = this._height;
+    let totalTicks = this._data.length;
+
+    // Draw the maximum value horizontal line.
+    if (this._showMax) {
+      ctx.strokeStyle = this.maximumLineColor;
+      ctx.lineWidth = GRAPH_HELPER_LINES_WIDTH;
+      ctx.setLineDash(GRAPH_HELPER_LINES_DASH);
+      ctx.beginPath();
+      let maximumY = height - maxValue * dataScaleY;
+      ctx.moveTo(0, maximumY);
+      ctx.lineTo(width, maximumY);
+      ctx.stroke();
+    }
+
+    // Draw the average value horizontal line.
+    if (this._showAvg) {
+      ctx.strokeStyle = this.averageLineColor;
+      ctx.lineWidth = GRAPH_HELPER_LINES_WIDTH;
+      ctx.setLineDash(GRAPH_HELPER_LINES_DASH);
+      ctx.beginPath();
+      let averageY = height - avgValue * dataScaleY;
+      ctx.moveTo(0, averageY);
+      ctx.lineTo(width, averageY);
+      ctx.stroke();
+    }
+
+    // Draw the minimum value horizontal line.
+    if (this._showMin) {
+      ctx.strokeStyle = this.minimumLineColor;
+      ctx.lineWidth = GRAPH_HELPER_LINES_WIDTH;
+      ctx.setLineDash(GRAPH_HELPER_LINES_DASH);
+      ctx.beginPath();
+      let minimumY = height - minValue * dataScaleY;
+      ctx.moveTo(0, minimumY);
+      ctx.lineTo(width, minimumY);
+      ctx.stroke();
+    }
+
+    // Update the tooltips text and gutter lines.
+
+    this._maxTooltip.querySelector("[text=value]").textContent =
+      L10N.numberWithDecimals(maxValue, 2);
+    this._avgTooltip.querySelector("[text=value]").textContent =
+      L10N.numberWithDecimals(avgValue, 2);
+    this._minTooltip.querySelector("[text=value]").textContent =
+      L10N.numberWithDecimals(minValue, 2);
+
+    let bottom = height / this._pixelRatio;
+    let maxPosY = CanvasGraphUtils.map(maxValue * this.dampenValuesFactor, 0, maxValue, bottom, 0);
+    let avgPosY = CanvasGraphUtils.map(avgValue * this.dampenValuesFactor, 0, maxValue, bottom, 0);
+    let minPosY = CanvasGraphUtils.map(minValue * this.dampenValuesFactor, 0, maxValue, bottom, 0);
+
+    let safeTop = GRAPH_TOOLTIP_SAFE_BOUNDS;
+    let safeBottom = bottom - GRAPH_TOOLTIP_SAFE_BOUNDS;
+
+    let maxTooltipTop = (this.withFixedTooltipPositions
+      ? safeTop : CanvasGraphUtils.clamp(maxPosY, safeTop, safeBottom));
+    let avgTooltipTop = (this.withFixedTooltipPositions
+      ? safeTop : CanvasGraphUtils.clamp(avgPosY, safeTop, safeBottom));
+    let minTooltipTop = (this.withFixedTooltipPositions
+      ? safeBottom : CanvasGraphUtils.clamp(minPosY, safeTop, safeBottom));
+
+    this._maxTooltip.style.top = maxTooltipTop + "px";
+    this._avgTooltip.style.top = avgTooltipTop + "px";
+    this._minTooltip.style.top = minTooltipTop + "px";
+
+    this._maxGutterLine.style.top = maxPosY + "px";
+    this._avgGutterLine.style.top = avgPosY + "px";
+    this._minGutterLine.style.top = minPosY + "px";
+
+    this._maxTooltip.setAttribute("with-arrows", this.withTooltipArrows);
+    this._avgTooltip.setAttribute("with-arrows", this.withTooltipArrows);
+    this._minTooltip.setAttribute("with-arrows", this.withTooltipArrows);
+
+    let distanceMinMax = Math.abs(maxTooltipTop - minTooltipTop);
+    this._maxTooltip.hidden = this._showMax === false || !totalTicks || distanceMinMax < GRAPH_MIN_MAX_TOOLTIP_DISTANCE;
+    this._avgTooltip.hidden = this._showAvg === false || !totalTicks;
+    this._minTooltip.hidden = this._showMin === false || !totalTicks;
+    this._gutter.hidden = (this._showMin === false && this._showAvg === false && this._showMax === false) || !totalTicks;
+
+    this._maxGutterLine.hidden = this._showMax === false;
+    this._avgGutterLine.hidden = this._showAvg === false;
+    this._minGutterLine.hidden = this._showMin === false;
+  },
+
+  /**
+   * Creates the gutter node when constructing this graph.
+   * @return nsIDOMNode
+   */
+  _createGutter: function() {
+    let gutter = this._document.createElementNS(HTML_NS, "div");
+    gutter.className = "line-graph-widget-gutter";
+    gutter.setAttribute("hidden", true);
+    this._container.appendChild(gutter);
+
+    return gutter;
+  },
+
+  /**
+   * Creates the gutter line nodes when constructing this graph.
+   * @return nsIDOMNode
+   */
+  _createGutterLine: function(type) {
+    let line = this._document.createElementNS(HTML_NS, "div");
+    line.className = "line-graph-widget-gutter-line";
+    line.setAttribute("type", type);
+    this._gutter.appendChild(line);
+
+    return line;
+  },
+
+  /**
+   * Creates the tooltip nodes when constructing this graph.
+   * @return nsIDOMNode
+   */
+  _createTooltip: function(type, arrow, info, metric) {
+    let tooltip = this._document.createElementNS(HTML_NS, "div");
+    tooltip.className = "line-graph-widget-tooltip";
+    tooltip.setAttribute("type", type);
+    tooltip.setAttribute("arrow", arrow);
+    tooltip.setAttribute("hidden", true);
+
+    let infoNode = this._document.createElementNS(HTML_NS, "span");
+    infoNode.textContent = info;
+    infoNode.setAttribute("text", "info");
+
+    let valueNode = this._document.createElementNS(HTML_NS, "span");
+    valueNode.textContent = 0;
+    valueNode.setAttribute("text", "value");
+
+    let metricNode = this._document.createElementNS(HTML_NS, "span");
+    metricNode.textContent = metric;
+    metricNode.setAttribute("text", "metric");
+
+    tooltip.appendChild(infoNode);
+    tooltip.appendChild(valueNode);
+    tooltip.appendChild(metricNode);
+    this._container.appendChild(tooltip);
+
+    return tooltip;
+  }
+});
+
+module.exports = LineGraphWidget;
new file mode 100644
--- /dev/null
+++ b/browser/devtools/shared/widgets/MountainGraphWidget.js
@@ -0,0 +1,196 @@
+"use strict";
+
+const { Cc, Ci, Cu, Cr } = require("chrome");
+
+const { Heritage } = require("resource:///modules/devtools/ViewHelpers.jsm");
+const { AbstractCanvasGraph, CanvasGraphUtils } = require("devtools/shared/widgets/Graphs");
+
+const HTML_NS = "http://www.w3.org/1999/xhtml";
+
+// Bar graph constants.
+
+const GRAPH_DAMPEN_VALUES_FACTOR = 0.9;
+
+const GRAPH_BACKGROUND_COLOR = "#ddd";
+const GRAPH_STROKE_WIDTH = 2; // px
+const GRAPH_STROKE_COLOR = "rgba(255,255,255,0.9)";
+const GRAPH_HELPER_LINES_DASH = [5]; // px
+const GRAPH_HELPER_LINES_WIDTH = 1; // px
+
+const GRAPH_CLIPHEAD_LINE_COLOR = "#fff";
+const GRAPH_SELECTION_LINE_COLOR = "#fff";
+const GRAPH_SELECTION_BACKGROUND_COLOR = "rgba(44,187,15,0.25)";
+const GRAPH_SELECTION_STRIPES_COLOR = "rgba(255,255,255,0.1)";
+const GRAPH_REGION_BACKGROUND_COLOR = "transparent";
+const GRAPH_REGION_STRIPES_COLOR = "rgba(237,38,85,0.2)";
+
+/**
+ * A mountain graph, plotting sets of values as line graphs.
+ *
+ * @see AbstractCanvasGraph for emitted events and other options.
+ *
+ * Example usage:
+ *   let graph = new MountainGraphWidget(node);
+ *   graph.format = ...;
+ *   graph.once("ready", () => {
+ *     graph.setData(src);
+ *   });
+ *
+ * The `graph.format` traits are mandatory and will determine how each
+ * section of the moutain will be styled:
+ *   [
+ *     { color: "#f00", ... },
+ *     { color: "#0f0", ... },
+ *     ...
+ *     { color: "#00f", ... }
+ *   ]
+ *
+ * Data source format:
+ *   [
+ *     { delta: x1, values: [y11, y12, ... y1n] },
+ *     { delta: x2, values: [y21, y22, ... y2n] },
+ *     ...
+ *     { delta: xm, values: [ym1, ym2, ... ymn] }
+ *   ]
+ * where the [ymn] values is assumed to aready be normalized from [0..1].
+ *
+ * @param nsIDOMNode parent
+ *        The parent node holding the graph.
+ */
+this.MountainGraphWidget = function(parent, ...args) {
+  AbstractCanvasGraph.apply(this, [parent, "mountain-graph", ...args]);
+};
+
+MountainGraphWidget.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
+  backgroundColor: GRAPH_BACKGROUND_COLOR,
+  strokeColor: GRAPH_STROKE_COLOR,
+  strokeWidth: GRAPH_STROKE_WIDTH,
+  clipheadLineColor: GRAPH_CLIPHEAD_LINE_COLOR,
+  selectionLineColor: GRAPH_SELECTION_LINE_COLOR,
+  selectionBackgroundColor: GRAPH_SELECTION_BACKGROUND_COLOR,
+  selectionStripesColor: GRAPH_SELECTION_STRIPES_COLOR,
+  regionBackgroundColor: GRAPH_REGION_BACKGROUND_COLOR,
+  regionStripesColor: GRAPH_REGION_STRIPES_COLOR,
+
+  /**
+   * List of rules used to style each section of the mountain.
+   * @see constructor
+   * @type array
+   */
+  format: null,
+
+  /**
+   * Optionally offsets the `delta` in the data source by this scalar.
+   */
+  dataOffsetX: 0,
+
+  /**
+   * Optionally uses this value instead of the last tick in the data source
+   * to compute the horizontal scaling.
+   */
+  dataDuration: 0,
+
+  /**
+   * The scalar used to multiply the graph values to leave some headroom
+   * on the top.
+   */
+  dampenValuesFactor: GRAPH_DAMPEN_VALUES_FACTOR,
+
+  /**
+   * Renders the graph's background.
+   * @see AbstractCanvasGraph.prototype.buildBackgroundImage
+   */
+  buildBackgroundImage: function() {
+    let { canvas, ctx } = this._getNamedCanvas("mountain-graph-background");
+    let width = this._width;
+    let height = this._height;
+
+    ctx.fillStyle = this.backgroundColor;
+    ctx.fillRect(0, 0, width, height);
+
+    return canvas;
+  },
+
+  /**
+   * Renders the graph's data source.
+   * @see AbstractCanvasGraph.prototype.buildGraphImage
+   */
+  buildGraphImage: function() {
+    if (!this.format || !this.format.length) {
+      throw "The graph format traits are mandatory to style the data source.";
+    }
+    let { canvas, ctx } = this._getNamedCanvas("mountain-graph-data");
+    let width = this._width;
+    let height = this._height;
+
+    let totalSections = this.format.length;
+    let totalTicks = this._data.length;
+    let firstTick = this._data[0].delta;
+    let lastTick = this._data[totalTicks - 1].delta;
+
+    let duration = this.dataDuration || lastTick;
+    let dataScaleX = this.dataScaleX = width / (duration - this.dataOffsetX);
+    let dataScaleY = this.dataScaleY = height * this.dampenValuesFactor;
+
+    // Draw the graph.
+
+    let prevHeights = Array.from({ length: totalTicks }).fill(0);
+
+    ctx.globalCompositeOperation = "destination-over";
+    ctx.strokeStyle = this.strokeColor;
+    ctx.lineWidth = this.strokeWidth * this._pixelRatio;
+
+    for (let section = 0; section < totalSections; section++) {
+      ctx.fillStyle = this.format[section].color || "#000";
+      ctx.beginPath();
+
+      for (let tick = 0; tick < totalTicks; tick++) {
+        let { delta, values } = this._data[tick];
+        let currX = (delta - this.dataOffsetX) * dataScaleX;
+        let currY = values[section] * dataScaleY;
+        let prevY = prevHeights[tick];
+
+        if (delta == firstTick) {
+          ctx.moveTo(-GRAPH_STROKE_WIDTH, height);
+          ctx.lineTo(-GRAPH_STROKE_WIDTH, height - currY - prevY);
+        }
+
+        ctx.lineTo(currX, height - currY - prevY);
+
+        if (delta == lastTick) {
+          ctx.lineTo(width + GRAPH_STROKE_WIDTH, height - currY - prevY);
+          ctx.lineTo(width + GRAPH_STROKE_WIDTH, height);
+        }
+
+        prevHeights[tick] += currY;
+      }
+
+      ctx.fill();
+      ctx.stroke();
+    }
+
+    ctx.globalCompositeOperation = "source-over";
+    ctx.lineWidth = GRAPH_HELPER_LINES_WIDTH;
+    ctx.setLineDash(GRAPH_HELPER_LINES_DASH);
+
+    // Draw the maximum value horizontal line.
+
+    ctx.beginPath();
+    let maximumY = height * this.dampenValuesFactor;
+    ctx.moveTo(0, maximumY);
+    ctx.lineTo(width, maximumY);
+    ctx.stroke();
+
+    // Draw the average value horizontal line.
+
+    ctx.beginPath();
+    let averageY = height / 2 * this.dampenValuesFactor;
+    ctx.moveTo(0, averageY);
+    ctx.lineTo(width, averageY);
+    ctx.stroke();
+
+    return canvas;
+  }
+});
+
+module.exports = MountainGraphWidget;
--- a/browser/devtools/storage/test/storage-complex-values.html
+++ b/browser/devtools/storage/test/storage-complex-values.html
@@ -1,9 +1,9 @@
-<!DOCTYPE HTML>
+<!DOCTYPE HTML>
 <html>
 <!--
 Bug 970517 - Storage inspector front end - tests
 -->
 <head>
   <meta charset="utf-8">
   <title>Storage inspector test for correct values in the sidebar</title>
 </head>
@@ -36,16 +36,17 @@ console.log("added cookies and stuff fro
 
 function success(event) {
   setupIDB.next(event);
 }
 
 window.idbGenerator = function*(callback) {
   let request = indexedDB.open("idb1", 1);
   request.onupgradeneeded = success;
+  request.onsuccess = success;
   request.onerror = function(e) {
     throw new Error("error opening db connection");
   };
   let event = yield undefined;
   let db = event.target.result;
   let store1 = db.createObjectStore("obj1", { keyPath: "id" });
   store1.createIndex("name", "name", { unique: false });
   store1.createIndex("email", "email", { unique: true });
@@ -55,28 +56,28 @@ window.idbGenerator = function*(callback
   yield undefined;
   store1.add({id: 2, name: "foo2", email: "foo2@bar.com"}).onsuccess = success;
   yield undefined;
   store1.add({id: 3, name: "foo2", email: "foo3@bar.com"}).onsuccess = success;
   yield undefined;
   store2.add({id2: 1, name: "foo", email: "foo@bar.com", extra: "baz"}).onsuccess = success;
   yield undefined;
 
-  store1.transaction.oncomplete = success;
   yield undefined;
   db.close();
 
   request = indexedDB.open("idb2", 1);
   request.onupgradeneeded = success;
+  request.onsuccess = success;
   event = yield undefined;
 
   let db2 = event.target.result;
   let store3 = db2.createObjectStore("obj3", { keyPath: "id3" });
   store3.createIndex("name2", "name2", { unique: true });
-  store3.transaction.oncomplete = success;
+
   yield undefined;
   db2.close();
   console.log("added cookies and stuff from main page");
   callback();
 }
 
 function successClear(event) {
   clearIterator.next(event);
--- a/browser/devtools/storage/test/storage-listings.html
+++ b/browser/devtools/storage/test/storage-listings.html
@@ -1,9 +1,9 @@
-<!DOCTYPE HTML>
+<!DOCTYPE HTML>
 <html>
 <!--
 Bug 970517 - Storage inspector front end - tests
 -->
 <head>
   <meta charset="utf-8">
   <title>Storage inspector test for listing hosts and storages</title>
 </head>
@@ -30,16 +30,17 @@ console.log("added cookies and stuff fro
 
 function success(event) {
   setupIDB.next(event);
 }
 
 window.idbGenerator = function*(callback) {
   let request = indexedDB.open("idb1", 1);
   request.onupgradeneeded = success;
+  request.onsuccess = success;
   request.onerror = function(e) {
     throw new Error("error opening db connection");
   };
   let event = yield undefined;
   let db = event.target.result;
   let store1 = db.createObjectStore("obj1", { keyPath: "id" });
   store1.createIndex("name", "name", { unique: false });
   store1.createIndex("email", "email", { unique: true });
@@ -49,28 +50,28 @@ window.idbGenerator = function*(callback
   yield undefined;
   store1.add({id: 2, name: "foo2", email: "foo2@bar.com"}).onsuccess = success;
   yield undefined;
   store1.add({id: 3, name: "foo2", email: "foo3@bar.com"}).onsuccess = success;
   yield undefined;
   store2.add({id2: 1, name: "foo", email: "foo@bar.com", extra: "baz"}).onsuccess = success;
   yield undefined;
 
-  store1.transaction.oncomplete = success;
   yield undefined;
   db.close();
 
   request = indexedDB.open("idb2", 1);
   request.onupgradeneeded = success;
+  request.onsuccess = success;
   event = yield undefined;
 
   let db2 = event.target.result;
   let store3 = db2.createObjectStore("obj3", { keyPath: "id3" });
   store3.createIndex("name2", "name2", { unique: true });
-  store3.transaction.oncomplete = success;
+
   yield undefined;
   db2.close();
   console.log("added cookies and stuff from main page");
   callback();
 }
 
 function successClear(event) {
   clearIterator.next(event);
--- a/browser/devtools/storage/test/storage-secured-iframe.html
+++ b/browser/devtools/storage/test/storage-secured-iframe.html
@@ -1,9 +1,9 @@
-<!DOCTYPE HTML>
+<!DOCTYPE HTML>
 <html>
 <!--
 Iframe for testing multiple host detetion in storage actor
 -->
 <head>
   <meta charset="utf-8">
 </head>
 <body>
@@ -15,41 +15,43 @@ sessionStorage.setItem("iframe-s-ss1", "
 
 function success(event) {
   setupIDB.next(event);
 }
 
 window.idbGenerator = function*(callback) {
   let request = indexedDB.open("idb-s1", 1);
   request.onupgradeneeded = success;
+  request.onsuccess = success;
   request.onerror = function(e) {
     throw new Error("error opening db connection");
   };
   let event = yield undefined;
   let db = event.target.result;
   let store1 = db.createObjectStore("obj-s1", { keyPath: "id" });
 
   store1.add({id: 6, name: "foo", email: "foo@bar.com"}).onsuccess = success;
   yield undefined;
   store1.add({id: 7, name: "foo2", email: "foo2@bar.com"}).onsuccess = success;
   yield undefined;
-  store1.transaction.oncomplete = success;
+
   yield undefined;
   db.close();
 
   request = indexedDB.open("idb-s2", 1);
   request.onupgradeneeded = success;
+  request.onsuccess = success;
   event = yield undefined;
 
   let db2 = event.target.result;
   let store3 = db2.createObjectStore("obj-s2", { keyPath: "id3", autoIncrement: true });
   store3.createIndex("name2", "name2", { unique: true });
   store3.add({id3: 16, name2: "foo", email: "foo@bar.com"}).onsuccess = success;
   yield undefined;
-  store3.transaction.oncomplete = success;
+
   yield undefined;
   db2.close();
   console.log("added cookies and stuff from secured iframe");
   callback();
 }
 
 function successClear(event) {
   clearIterator.next(event);
--- a/browser/devtools/webaudioeditor/includes.js
+++ b/browser/devtools/webaudioeditor/includes.js
@@ -20,17 +20,17 @@ const { Task } = Cu.import("resource://g
 const { Class } = require("sdk/core/heritage");
 const EventEmitter = require("devtools/toolkit/event-emitter");
 const STRINGS_URI = "chrome://browser/locale/devtools/webaudioeditor.properties"
 const L10N = new ViewHelpers.L10N(STRINGS_URI);
 const Telemetry = require("devtools/shared/telemetry");
 const telemetry = new Telemetry();
 
 devtools.lazyRequireGetter(this, "LineGraphWidget",
-  "devtools/shared/widgets/Graphs", true);
+  "devtools/shared/widgets/LineGraphWidget");
 
 // `AUDIO_NODE_DEFINITION` defined in the controller's initialization,
 // which describes all the properties of an AudioNode
 let AUDIO_NODE_DEFINITION;
 
 // Override DOM promises with Promise.jsm helpers
 const { defer, all } = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
 
--- a/browser/locales/en-US/chrome/browser/devtools/profiler.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/profiler.properties
@@ -106,16 +106,22 @@ table.idle=(idle)
 # labels which, when clicked, jump to the debugger.
 table.url.tooltiptext=View source in Debugger
 
 # LOCALIZATION NOTE (table.zoom.tooltiptext):
 # This string is displayed in the call tree as the tooltip text for the 'zoom'
 # buttons (small magnifying glass icons) which spawn a new tab.
 table.zoom.tooltiptext=Inspect frame in new tab
 
+# LOCALIZATION NOTE (table.view-optimizations.tooltiptext):
+# This string is displayed in the icon displayed next to frames that
+# have optimization data
+table.view-optimizations.tooltiptext=View optimizations in JIT View
+
+
 # LOCALIZATION NOTE (recordingsList.saveDialogTitle):
 # This string is displayed as a title for saving a recording to disk.
 recordingsList.saveDialogTitle=Save profile…
 
 # LOCALIZATION NOTE (recordingsList.saveDialogJSONFilter):
 # This string is displayed as a filter for saving a recording to disk.
 recordingsList.saveDialogJSONFilter=JSON Files
 
--- a/browser/modules/BrowserUITelemetry.jsm
+++ b/browser/modules/BrowserUITelemetry.jsm
@@ -436,16 +436,22 @@ this.BrowserUITelemetry = {
       this._countMouseUpEvent("click-bookmarks-menu-button", action,
                               aEvent.button);
     }
   },
 
   _checkForBuiltinItem: function(aEvent) {
     let item = aEvent.originalTarget;
 
+    // We don't want to count clicks on the private browsing
+    // button for privacy reasons. See bug 1176391.
+    if (item.id == "privatebrowsing-button") {
+      return;
+    }
+
     // We special-case the bookmarks-menu-button, since we want to
     // monitor more than just clicks on it.
     if (item.id == "bookmarks-menu-button" ||
         getIDBasedOnFirstIDedAncestor(item) == "bookmarks-menu-button") {
       this._bookmarksMenuButtonMouseUp(aEvent);
       return;
     }
 
@@ -646,17 +652,19 @@ this.BrowserUITelemetry = {
   _contextMenuItemWhitelist: new Set([
     "close-without-interaction", // for closing the menu without clicking it.
     "custom-page-item", // The ID we use for page-provided items
     "unknown", // The bucket for stuff with no id.
     // Everything we know of so far (which will exclude add-on items):
     "navigation", "back", "forward", "reload", "stop", "bookmarkpage",
     "spell-no-suggestions", "spell-add-to-dictionary",
     "spell-undo-add-to-dictionary", "openlinkincurrent", "openlinkintab",
-    "openlink", "openlinkprivate", "bookmarklink", "sharelink", "savelink",
+    "openlink",
+    // "openlinkprivate" intentionally omitted for privacy reasons. See bug 1176391.
+    "bookmarklink", "sharelink", "savelink",
     "marklinkMenu", "copyemail", "copylink", "media-play", "media-pause",
     "media-mute", "media-unmute", "media-playbackrate",
     "media-playbackrate-050x", "media-playbackrate-100x",
     "media-playbackrate-150x", "media-playbackrate-200x",
     "media-showcontrols", "media-hidecontrols", "video-showstats",
     "video-hidestats", "video-fullscreen", "leave-dom-fullscreen",
     "reloadimage", "viewimage", "viewvideo", "copyimage-contents", "copyimage",
     "copyvideourl", "copyaudiourl", "saveimage", "shareimage", "sendimage",
@@ -674,16 +682,23 @@ this.BrowserUITelemetry = {
     "bidi-text-direction-toggle", "bidi-page-direction-toggle", "inspect",
     "media-eme-learn-more"
   ]),
 
   _contextMenuInteractions: {},
 
   registerContextMenuInteraction: function(keys, itemID) {
     if (itemID) {
+      if (itemID == "openlinkprivate") {
+        // Don't record anything, not even an other-item count
+        // if the user chose to open in a private window. See
+        // bug 1176391.
+        return;
+      }
+
       if (!this._contextMenuItemWhitelist.has(itemID)) {
         itemID = "other-item";
       }
       keys.push(itemID);
     }
 
     this._countEvent(keys, this._contextMenuInteractions);
   },
--- a/browser/themes/shared/devtools/performance.inc.css
+++ b/browser/themes/shared/devtools/performance.inc.css
@@ -64,16 +64,20 @@
   list-style-image: url(performance-icons.svg#details-call-tree);
 }
 
 #select-js-flamegraph-view,
 #select-memory-flamegraph-view {
   list-style-image: url(performance-icons.svg#details-flamegraph);
 }
 
+#select-optimizations-view {
+  list-style-image: url(profiler-stopwatch.svg);
+}
+
 /* Recording buttons */
 
 #main-record-button {
   list-style-image: url(profiler-stopwatch.svg);
 }
 
 #main-record-button[checked] {
   list-style-image: url(profiler-stopwatch-checked.svg);
@@ -632,36 +636,63 @@ menuitem.marker-color-graphs-blue:before
 }
 .opt-url:hover {
   text-decoration: underline;
 }
 .opt-url.debugger-link {
   cursor: pointer;
 }
 
-#jit-optimizations-view .opt-icon::before {
+.opt-icon::before {
   content: "";
   background-image: url(chrome://browser/skin/devtools/webconsole.svg);
   background-repeat: no-repeat;
   background-size: 72px 60px;
+  /* show grey "i" bubble by default */
+  background-position: -36px -36px;
   width: 12px;
   height: 12px;
   display: inline-block;
 
-  margin: 5px 6px 0 0;
   max-height: 12px;
 }
-.theme-light #jit-optimizations-view .opt-icon::before {
+
+#jit-optimizations-view .opt-icon::before {
+  margin: 5px 6px 0 0;
+}
+description.opt-icon {
+  margin: 0px 0px 0px 0px;
+}
+description.opt-icon::before {
+  margin: 1px 4px 0px 0px;
+}
+.theme-light .opt-icon::before {
   background-image: url(chrome://browser/skin/devtools/webconsole.svg#light-icons);
 }
-
-#jit-optimizations-view .opt-icon[severity=warning]::before {
+.opt-icon[severity=warning]::before {
   background-position: -24px -24px;
 }
+.opt-icon[type=linkable]::before {
+  cursor: pointer;
+}
 
+ul.frames-list {
+  list-style-type: none;
+  padding: 0px;
+  margin: 0px;
+}
+
+ul.frames-list li {
+  cursor: pointer;
+}
+
+ul.frames-list li.selected {
+  background-color: var(--theme-selection-background);
+  color: var(--theme-selection-color);
+}
 
 /**
  * Configurable Options
  *
  * Elements can be tagged with a class and visibility is controlled via a
  * preference being applied or removed.
  */
 
--- a/browser/themes/shared/devtools/widgets.inc.css
+++ b/browser/themes/shared/devtools/widgets.inc.css
@@ -1020,20 +1020,16 @@
 }
 
 .line-graph-widget-tooltip[type=average] > [text=value] {
   color: var(--theme-highlight-orange);
 }
 
 /* Bar graph widget */
 
-.bar-graph-widget-canvas {
-  background: #f7f7f7;
-}
-
 .bar-graph-widget-legend {
   position: absolute;
   top: 4px;
   left: 8px;
   color: #292e33;
   font-size: 80%;
   pointer-events: none;
 }
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -1460,22 +1460,23 @@ richlistitem[selected="true"][current="t
 .ac-result-type-keyword,
 .autocomplete-treebody::-moz-tree-image(keyword, treecolAutoCompleteImage),
 richlistitem[type~="action"][actiontype="searchengine"] > .ac-title-box > .ac-site-icon {
   list-style-image: url(chrome://global/skin/icons/autocomplete-search.svg#search-icon);
   width: 16px;
   height: 16px;
 }
 
-@media (-moz-os-version: windows-xp),
-       not all and (-moz-windows-default-theme) {
-  .ac-result-type-keyword[selected="true"],
-  .autocomplete-treebody::-moz-tree-image(keyword, treecolAutoCompleteImage, selected),
-  richlistitem[type~="action"][actiontype="searchengine"][selected="true"] > .ac-title-box > .ac-site-icon {
-    list-style-image: url(chrome://global/skin/icons/autocomplete-search.svg#search-icon-inverted);
+@media not all and (-moz-os-version: windows-vista) and (-moz-windows-default-theme) {
+  @media not all and (-moz-os-version: windows-win7) and (-moz-windows-default-theme) {
+    .ac-result-type-keyword[selected="true"],
+    .autocomplete-treebody::-moz-tree-image(keyword, treecolAutoCompleteImage, selected),
+    richlistitem[type~="action"][actiontype="searchengine"][selected="true"] > .ac-title-box > .ac-site-icon {
+      list-style-image: url(chrome://global/skin/icons/autocomplete-search.svg#search-icon-inverted);
+    }
   }
 }
 
 .ac-result-type-tag,
 .autocomplete-treebody::-moz-tree-image(tag, treecolAutoCompleteImage) {
   list-style-image: url("chrome://browser/skin/places/tag.png");
   width: 16px;
   height: 16px;
index bfdec23e33bd261c9b63925a04c01f5cdd58335d..c310dac494d79c6c1478449bc00175400ac69025
GIT binary patch
literal 93724
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%0DjC*
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
index eb790b766e85d2e0e93f24e77aafbfa03ef62899..d1d52568bcafa3125a44008846847017dedd6a8b
GIT binary patch
literal 47300
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
D=)GyS
--- a/build/mobile/remoteautomation.py
+++ b/build/mobile/remoteautomation.py
@@ -7,17 +7,17 @@ import time
 import re
 import os
 import tempfile
 import shutil
 import subprocess
 import sys
 
 from automation import Automation
-from devicemanager import DMError
+from devicemanager import DMError, DeviceManager
 from mozlog.structured import get_default_logger
 import mozcrash
 
 # signatures for logcat messages that we don't care about much
 fennecLogcatFilters = [ "The character encoding of the HTML document was not declared",
                         "Use of Mutation Events is deprecated. Use MutationObserver instead.",
                         "Unexpected value from nativeGetEnabledTags: 0" ]
 
@@ -119,18 +119,20 @@ class RemoteAutomation(Automation):
 
         return status
 
     def deleteANRs(self):
         # empty ANR traces.txt file; usually need root permissions
         # we make it empty and writable so we can test the ANR reporter later
         traces = "/data/anr/traces.txt"
         try:
-            self._devicemanager.shellCheckOutput(['echo', '', '>', traces], root=True)
-            self._devicemanager.shellCheckOutput(['chmod', '666', traces], root=True)
+            self._devicemanager.shellCheckOutput(['echo', '', '>', traces], root=True,
+                                                 timeout=DeviceManager.short_timeout)
+            self._devicemanager.shellCheckOutput(['chmod', '666', traces], root=True,
+                                                 timeout=DeviceManager.short_timeout)
         except DMError:
             print "Error deleting %s" % traces
             pass
 
     def checkForANRs(self):
         traces = "/data/anr/traces.txt"
         if self._devicemanager.fileExists(traces):
             try:
@@ -145,33 +147,36 @@ class RemoteAutomation(Automation):
                 print "Error pulling %s" % traces
         else:
             print "%s not found" % traces
 
     def deleteTombstones(self):
         # delete any existing tombstone files from device
         remoteDir = "/data/tombstones"
         try:
-            self._devicemanager.shellCheckOutput(['rm', '-r', remoteDir], root=True)
+            self._devicemanager.shellCheckOutput(['rm', '-r', remoteDir], root=True,
+                                                 timeout=DeviceManager.short_timeout)
         except DMError:
             # This may just indicate that the tombstone directory is missing
             pass
 
     def checkForTombstones(self):
         # pull any tombstones from device and move to MOZ_UPLOAD_DIR
         remoteDir = "/data/tombstones"
         blobberUploadDir = os.environ.get('MOZ_UPLOAD_DIR', None)
         if blobberUploadDir:
             if not os.path.exists(blobberUploadDir):
                 os.mkdir(blobberUploadDir)
             if self._devicemanager.dirExists(remoteDir):
                 # copy tombstone files from device to local blobber upload directory
                 try:
-                    self._devicemanager.shellCheckOutput(['chmod', '777', remoteDir], root=True)
-                    self._devicemanager.shellCheckOutput(['chmod', '666', os.path.join(remoteDir, '*')], root=True)
+                    self._devicemanager.shellCheckOutput(['chmod', '777', remoteDir], root=True,
+                                                 timeout=DeviceManager.short_timeout)
+                    self._devicemanager.shellCheckOutput(['chmod', '666', os.path.join(remoteDir, '*')], root=True,
+                                                 timeout=DeviceManager.short_timeout)
                     self._devicemanager.getDirectory(remoteDir, blobberUploadDir, False)
                 except DMError:
                     # This may just indicate that no tombstone files are present
                     pass
                 self.deleteTombstones()
                 # add a .txt file extension to each tombstone file name, so
                 # that blobber will upload it
                 for f in glob.glob(os.path.join(blobberUploadDir, "tombstone_??")):
@@ -187,22 +192,17 @@ class RemoteAutomation(Automation):
                 print "%s does not exist; tombstone check skipped" % remoteDir
         else:
             print "MOZ_UPLOAD_DIR not defined; tombstone check skipped"
 
     def checkForCrashes(self, directory, symbolsPath):
         self.checkForANRs()
         self.checkForTombstones()
 
-        try:
-            logcat = self._devicemanager.getLogcat(filterOutRegexps=fennecLogcatFilters)
-        except DMError:
-            print "getLogcat threw DMError; re-trying just once..."
-            time.sleep(1)
-            logcat = self._devicemanager.getLogcat(filterOutRegexps=fennecLogcatFilters)
+        logcat = self._devicemanager.getLogcat(filterOutRegexps=fennecLogcatFilters)
 
         javaException = mozcrash.check_for_java_exception(logcat)
         if javaException:
             return True
 
         # If crash reporting is disabled (MOZ_CRASHREPORTER!=1), we can't say
         # anything.
         if not self.CRASHREPORTER:
--- a/build/mobile/robocop/Actions.java
+++ b/build/mobile/robocop/Actions.java
@@ -4,17 +4,27 @@
 
 package org.mozilla.gecko;
 import android.database.Cursor;
 
 public interface Actions {
 
     /** Special keys supported by sendSpecialKey() */
     public enum SpecialKey {
-        DOWN, UP, LEFT, RIGHT, ENTER, MENU, BACK
+        DOWN,
+        UP,
+        LEFT,
+        RIGHT,
+        ENTER,
+        MENU,
+        /**
+         * @deprecated Use Solo.goBack() in Robocop instead.
+         */
+        @Deprecated
+        BACK
     }
 
     public interface EventExpecter {
         /** Blocks until the event has been received. Subsequent calls will return immediately. */
         public void blockForEvent();
         public void blockForEvent(long millis, boolean failOnTimeout);
 
         /** Blocks until the event has been received and returns data associated with the event. */
@@ -35,17 +45,17 @@ public interface Actions {
 
     public interface RepeatedEventExpecter extends EventExpecter {
         /** Blocks until at least one event has been received, and no events have been received in the last <code>millis</code> milliseconds. */
         public void blockUntilClear(long millis);
     }
 
     /**
      * Sends an event to Gecko.
-     * 
+     *
      * @param geckoEvent The geckoEvent JSONObject's type
      */
     void sendGeckoEvent(String geckoEvent, String data);
 
     /**
      * Sends a preferences get event to Gecko.
      *
      * @param requestId The id of this request.
@@ -67,32 +77,32 @@ public interface Actions {
      * @param requestId The id of this request.
      */
     void sendPreferencesRemoveObserversEvent(int requestid);
 
     /**
      * Listens for a gecko event to be sent from the Gecko instance.
      * The returned object can be used to test if the event has been
      * received. Note that only one event is listened for.
-     * 
+     *
      * @param geckoEvent The geckoEvent JSONObject's type
      */
     RepeatedEventExpecter expectGeckoEvent(String geckoEvent);
 
     /**
      * Listens for a paint event. Note that calling expectPaint() will
      * invalidate the event expecters returned from any previous calls
      * to expectPaint(); calling any methods on those invalidated objects
      * will result in undefined behaviour.
      */
     RepeatedEventExpecter expectPaint();
 
-    /** 
-     * Send a string to the application 
-     * 
+    /**
+     * Send a string to the application
+     *
      * @param keysToSend The string to send
      */
     void sendKeys(String keysToSend);
 
     /**
      * Send a special keycode to the element
      *
      * @param key The special key to send
--- a/caps/moz.build
+++ b/caps/moz.build
@@ -1,16 +1,16 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-TEST_DIRS += ['tests/mochitest']
-
+MOCHITEST_MANIFESTS += ['tests/mochitest/mochitest.ini']
+MOCHITEST_CHROME_MANIFESTS += ['tests/mochitest/chrome.ini']
 XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
 
 XPIDL_SOURCES += [
     'nsIDomainPolicy.idl',
     'nsIPrincipal.idl',
     'nsIScriptSecurityManager.idl',
 ]
 
deleted file mode 100644
--- a/caps/tests/mochitest/moz.build
+++ /dev/null
@@ -1,9 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-MOCHITEST_MANIFESTS += ['mochitest.ini']
-MOCHITEST_CHROME_MANIFESTS += ['chrome.ini']
-
--- a/db/sqlite3/src/sqlite.def
+++ b/db/sqlite3/src/sqlite.def
@@ -102,16 +102,17 @@ EXPORTS
         sqlite3_realloc
         sqlite3_release_memory
         sqlite3_reset
         sqlite3_reset_auto_extension
         sqlite3_result_blob
         sqlite3_result_double
         sqlite3_result_error
         sqlite3_result_error16
+        sqlite3_result_error_code
         sqlite3_result_error_nomem
         sqlite3_result_int
         sqlite3_result_int64
         sqlite3_result_null
         sqlite3_result_text
         sqlite3_result_text16
         sqlite3_result_text16be
         sqlite3_result_text16le
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -219,20 +219,22 @@ static NS_DEFINE_CID(kAppShellCID, NS_AP
 #else
 #include <unistd.h> // for getpid()
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using mozilla::dom::workers::ServiceWorkerManager;
 
-// True means sUseErrorPages has been added to preferences var cache.
+// True means sUseErrorPages and sInterceptionEnabled has been added to
+// preferences var cache.
 static bool gAddedPreferencesVarCache = false;
 
 bool nsDocShell::sUseErrorPages = false;
+bool nsDocShell::sInterceptionEnabled = false;
 
 // Number of documents currently loading
 static int32_t gNumberOfDocumentsLoading = 0;
 
 // Global count of existing docshells.
 static int32_t gDocShellCount = 0;
 
 // Global count of docshells with the private attribute set
@@ -5736,16 +5738,19 @@ nsDocShell::Create()
   // Should we use XUL error pages instead of alerts if possible?
   mUseErrorPages =
     Preferences::GetBool("browser.xul.error_pages.enabled", mUseErrorPages);
 
   if (!gAddedPreferencesVarCache) {
     Preferences::AddBoolVarCache(&sUseErrorPages,
                                  "browser.xul.error_pages.enabled",
                                  mUseErrorPages);
+    Preferences::AddBoolVarCache(&sInterceptionEnabled,
+                                 "dom.serviceWorkers.interception.enabled",
+                                 false);
     gAddedPreferencesVarCache = true;
   }
 
   mDeviceSizeIsPageSize =
     Preferences::GetBool("docshell.device_size_is_page_size",
                          mDeviceSizeIsPageSize);
 
   nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
@@ -14042,16 +14047,21 @@ nsDocShell::MaybeNotifyKeywordSearchLoad
 #endif
 }
 
 NS_IMETHODIMP
 nsDocShell::ShouldPrepareForIntercept(nsIURI* aURI, bool aIsNavigate,
                                       bool* aShouldIntercept)
 {
   *aShouldIntercept = false;
+  // Preffed off.
+  if (!sInterceptionEnabled) {
+    return NS_OK;
+  }
+
   if (mSandboxFlags) {
     // If we're sandboxed, don't intercept.
     return NS_OK;
   }
 
   nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
   if (!swm) {
     return NS_OK;
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -898,16 +898,19 @@ protected:
     PARENT_ALLOWS,
     PARENT_PROHIBITS
   };
   FullscreenAllowedState mFullscreenAllowed;
 
   // Cached value of the "browser.xul.error_pages.enabled" preference.
   static bool sUseErrorPages;
 
+  // Cached value of the "dom.serviceWorkers.interception.enabled" preference.
+  static bool sInterceptionEnabled;
+
   bool mCreated;
   bool mAllowSubframes;
   bool mAllowPlugins;
   bool mAllowJavascript;
   bool mAllowMetaRedirects;
   bool mAllowImages;
   bool mAllowMedia;
   bool mAllowDNSPrefetch;
--- a/dom/base/Link.cpp
+++ b/dom/base/Link.cpp
@@ -439,17 +439,17 @@ Link::GetHash(nsAString &_hash, ErrorRes
     // string.
     return;
   }
 
   nsAutoCString ref;
   nsresult rv = uri->GetRef(ref);
   if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
     _hash.Assign(char16_t('#'));
-    if (nsContentUtils::EncodeDecodeURLHash()) {
+    if (nsContentUtils::GettersDecodeURLHash()) {
       NS_UnescapeURL(ref); // XXX may result in random non-ASCII bytes!
     }
     AppendUTF8toUTF16(ref, _hash);
   }
 }
 
 void
 Link::ResetLinkState(bool aNotify, bool aHasHref)
--- a/dom/base/URL.cpp
+++ b/dom/base/URL.cpp
@@ -520,17 +520,17 @@ void
 URL::GetHash(nsAString& aHash, ErrorResult& aRv) const
 {
   aHash.Truncate();
 
   nsAutoCString ref;
   nsresult rv = mURI->GetRef(ref);
   if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
     aHash.Assign(char16_t('#'));
-    if (nsContentUtils::EncodeDecodeURLHash()) {
+    if (nsContentUtils::GettersDecodeURLHash()) {
       NS_UnescapeURL(ref); // XXX may result in random non-ASCII bytes!
     }
     AppendUTF8toUTF16(ref, aHash);
   }
 }
 
 void
 URL::SetHash(const nsAString& aHash, ErrorResult& aRv)
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -251,16 +251,17 @@ bool nsContentUtils::sInitialized = fals
 bool nsContentUtils::sIsFullScreenApiEnabled = false;
 bool nsContentUtils::sTrustedFullScreenOnly = true;
 bool nsContentUtils::sIsCutCopyAllowed = true;
 bool nsContentUtils::sIsPerformanceTimingEnabled = false;
 bool nsContentUtils::sIsResourceTimingEnabled = false;
 bool nsContentUtils::sIsUserTimingLoggingEnabled = false;
 bool nsContentUtils::sIsExperimentalAutocompleteEnabled = false;
 bool nsContentUtils::sEncodeDecodeURLHash = false;
+bool nsContentUtils::sGettersDecodeURLHash = false;
 bool nsContentUtils::sPrivacyResistFingerprinting = false;
 
 uint32_t nsContentUtils::sHandlingInputTimeout = 1000;
 
 nsHtml5StringParser* nsContentUtils::sHTMLFragmentParser = nullptr;
 nsIParser* nsContentUtils::sXMLFragmentParser = nullptr;
 nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nullptr;
 bool nsContentUtils::sFragmentParsingActive = false;
@@ -533,16 +534,19 @@ nsContentUtils::Init()
                                "dom.performance.enable_user_timing_logging", false);
 
   Preferences::AddBoolVarCache(&sIsExperimentalAutocompleteEnabled,
                                "dom.forms.autocomplete.experimental", false);
 
   Preferences::AddBoolVarCache(&sEncodeDecodeURLHash,
                                "dom.url.encode_decode_hash", false);
 
+  Preferences::AddBoolVarCache(&sGettersDecodeURLHash,
+                               "dom.url.getters_decode_hash", false);
+
   Preferences::AddBoolVarCache(&sPrivacyResistFingerprinting,
                                "privacy.resistFingerprinting", false);
 
   Preferences::AddUintVarCache(&sHandlingInputTimeout,
                                "dom.event.handling-user-input-time-limit",
                                1000);
 
 #if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
@@ -6308,20 +6312,17 @@ nsContentUtils::FlushLayoutForTree(nsIDO
     nsCOMPtr<nsPIDOMWindow> piWin = do_QueryInterface(aWindow);
     if (!piWin)
         return;
 
     // Note that because FlushPendingNotifications flushes parents, this
     // is O(N^2) in docshell tree depth.  However, the docshell tree is
     // usually pretty shallow.
 
-    nsCOMPtr<nsIDOMDocument> domDoc;
-    aWindow->GetDocument(getter_AddRefs(domDoc));
-    nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
-    if (doc) {
+    if (nsCOMPtr<nsIDocument> doc = piWin->GetDoc()) {
         doc->FlushPendingNotifications(Flush_Layout);
     }
 
     nsCOMPtr<nsIDocShell> docShell = piWin->GetDocShell();
     if (docShell) {
         int32_t i = 0, i_end;
         docShell->GetChildCount(&i_end);
         for (; i < i_end; ++i) {
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -1944,16 +1944,24 @@ public:
    * and getters should return the percent decoded value of the segment
    */
   static bool EncodeDecodeURLHash()
   {
     return sEncodeDecodeURLHash;
   }
 
   /*
+   * Returns true if URL getters should percent decode the value of the segment
+   */
+  static bool GettersDecodeURLHash()
+  {
+    return sGettersDecodeURLHash && sEncodeDecodeURLHash;
+  }
+
+  /*
    * Returns true if the browser should attempt to prevent content scripts
    * from collecting distinctive information about the browser that could
    * be used to "fingerprint" and track the user across websites.
    */
   static bool ResistFingerprinting()
   {
     return sPrivacyResistFingerprinting;
   }
@@ -2494,16 +2502,17 @@ private:
   static bool sTrustedFullScreenOnly;
   static bool sIsCutCopyAllowed;
   static uint32_t sHandlingInputTimeout;
   static bool sIsPerformanceTimingEnabled;
   static bool sIsResourceTimingEnabled;
   static bool sIsUserTimingLoggingEnabled;
   static bool sIsExperimentalAutocompleteEnabled;
   static bool sEncodeDecodeURLHash;
+  static bool sGettersDecodeURLHash;
   static bool sPrivacyResistFingerprinting;
 
   static nsHtml5StringParser* sHTMLFragmentParser;
   static nsIParser* sXMLFragmentParser;
   static nsIFragmentContentSink* sXMLFragmentSink;
 
   /**
    * True if there's a fragment parser activation on the stack.
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -1780,18 +1780,17 @@ nsMessageManagerScriptExecutor::TryCache
     JS::Rooted<JSScript*> script(cx);
 
     if (aRunInGlobalScope) {
       if (!JS::Compile(cx, options, srcBuf, &script)) {
         return;
       }
     } else {
       // We're going to run these against some non-global scope.
-      options.setHasPollutedScope(true);
-      if (!JS::Compile(cx, options, srcBuf, &script)) {
+      if (!JS::CompileForNonSyntacticScope(cx, options, srcBuf, &script)) {
         return;
       }
     }
 
     aScriptp.set(script);
 
     nsAutoCString scheme;
     uri->GetScheme(scheme);
--- a/dom/base/nsImageLoadingContent.cpp
+++ b/dom/base/nsImageLoadingContent.cpp
@@ -82,17 +82,16 @@ nsImageLoadingContent::nsImageLoadingCon
     mImageBlockingStatus(nsIContentPolicy::ACCEPT),
     mLoadingEnabled(true),
     mIsImageStateForced(false),
     mLoading(false),
     // mBroken starts out true, since an image without a URI is broken....
     mBroken(true),
     mUserDisabled(false),
     mSuppressed(false),
-    mFireEventsOnDecode(false),
     mNewRequestsWillNeedAnimationReset(false),
     mStateChangerDepth(0),
     mCurrentRequestRegistered(false),
     mPendingRequestRegistered(false),
     mFrameCreateCalled(false),
     mVisibleCount(0)
 {
   if (!nsContentUtils::GetImgLoaderForChannel(nullptr, nullptr)) {
@@ -181,28 +180,16 @@ nsImageLoadingContent::Notify(imgIReques
       }
     }
     nsresult status =
         reqStatus & imgIRequest::STATUS_ERROR ? NS_ERROR_FAILURE : NS_OK;
     return OnLoadComplete(aRequest, status);
   }
 
   if (aType == imgINotificationObserver::DECODE_COMPLETE) {
-    if (mFireEventsOnDecode) {
-      mFireEventsOnDecode = false;
-
-      uint32_t reqStatus;
-      aRequest->GetImageStatus(&reqStatus);
-      if (reqStatus & imgIRequest::STATUS_ERROR) {
-        FireEvent(NS_LITERAL_STRING("error"));
-      } else {
-        FireEvent(NS_LITERAL_STRING("load"));
-      }
-    }
-
     UpdateImageState(true);
   }
 
   return NS_OK;
 }
 
 nsresult
 nsImageLoadingContent::OnLoadComplete(imgIRequest* aRequest, nsresult aStatus)
@@ -272,33 +259,21 @@ nsImageLoadingContent::OnLoadComplete(im
       // visible.
       if (!mFrameCreateCalled || (f->GetStateBits() & NS_FRAME_FIRST_REFLOW) ||
           mVisibleCount > 0 || shell->AssumeAllImagesVisible()) {
         mCurrentRequest->StartDecoding();
       }
     }
   }
 
-  // We want to give the decoder a chance to find errors. If we haven't found
-  // an error yet and we've started decoding, either from the above
-  // StartDecoding or from some other place, we must only fire these events
-  // after we finish decoding.
-  uint32_t reqStatus;
-  aRequest->GetImageStatus(&reqStatus);
-  if (NS_SUCCEEDED(aStatus) && !(reqStatus & imgIRequest::STATUS_ERROR) &&
-      (reqStatus & imgIRequest::STATUS_DECODE_STARTED) &&
-      !(reqStatus & imgIRequest::STATUS_DECODE_COMPLETE)) {
-    mFireEventsOnDecode = true;
+  // Fire the appropriate DOM event.
+  if (NS_SUCCEEDED(aStatus)) {
+    FireEvent(NS_LITERAL_STRING("load"));
   } else {
-    // Fire the appropriate DOM event.
-    if (NS_SUCCEEDED(aStatus)) {
-      FireEvent(NS_LITERAL_STRING("load"));
-    } else {
-      FireEvent(NS_LITERAL_STRING("error"));
-    }
+    FireEvent(NS_LITERAL_STRING("error"));
   }
 
   nsCOMPtr<nsINode> thisNode = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
   nsSVGEffects::InvalidateDirectRenderingObservers(thisNode->AsElement());
 
   return NS_OK;
 }
 
--- a/dom/base/nsImageLoadingContent.h
+++ b/dom/base/nsImageLoadingContent.h
@@ -405,17 +405,16 @@ private:
   /**
    * The state we had the last time we checked whether we needed to notify the
    * document of a state change.  These are maintained by UpdateImageState.
    */
   bool mLoading : 1;
   bool mBroken : 1;
   bool mUserDisabled : 1;
   bool mSuppressed : 1;
-  bool mFireEventsOnDecode : 1;
 
 protected:
   /**
    * A hack to get animations to reset, see bug 594771. On requests
    * that originate from setting .src, we mark them for needing their animation
    * reset when they are ready. mNewRequestsWillNeedAnimationReset is set to
    * true while preparing such requests (as a hack around needing to change an
    * interface), and the other two booleans store which of the current
--- a/dom/base/nsLocation.cpp
+++ b/dom/base/nsLocation.cpp
@@ -294,17 +294,17 @@ nsLocation::GetHash(nsAString& aHash)
     return rv;
   }
 
   nsAutoCString ref;
   nsAutoString unicodeRef;
 
   rv = uri->GetRef(ref);
 
-  if (nsContentUtils::EncodeDecodeURLHash()) {
+  if (nsContentUtils::GettersDecodeURLHash()) {
     if (NS_SUCCEEDED(rv)) {
       nsCOMPtr<nsITextToSubURI> textToSubURI(
           do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv));
 
       if (NS_SUCCEEDED(rv)) {
         nsAutoCString charset;
         uri->GetOriginCharset(charset);
 
--- a/dom/base/test/test_url.html
+++ b/dom/base/test/test_url.html
@@ -111,17 +111,17 @@
       port: '',
       pathname: '/',
       search: '?test',
       hash: ''
     },
     { url: 'http://example.com/carrot#question%3f',
       base: undefined,
       error: false,
-      hash: '#question?'
+      hash: '#question%3f'
     },
     { url: 'https://example.com:4443?',
       base: undefined,
       error: false,
       protocol: 'https:',
       port: '4443',
       pathname: '/',
       hash: '',
--- a/dom/events/test/mochitest.ini
+++ b/dom/events/test/mochitest.ini
@@ -184,11 +184,12 @@ support-files =
 support-files =
   bug989198_embedded.html
   bug989198_helper.js
 skip-if = buildapp == 'b2g' || e10s
 [test_bug1096146.html]
 support-files =
   bug1096146_embedded.html
 [test_offsetxy.html]
+skip-if = toolkit == 'android' || buildapp == 'b2g' || buildapp == 'mulet'
 [test_eventhandler_scoping.html]
 [test_bug1013412.html]
 skip-if = buildapp == 'b2g' # no wheel events on b2g
--- a/dom/imptests/WebIDLParser.js
+++ b/dom/imptests/WebIDLParser.js
@@ -915,10 +915,10 @@
             parse:  function (str, opt) {
                 if (!opt) opt = {};
                 var tokens = tokenise(str);
                 return parse(tokens, opt);
             }
     };
 
     if (inNode) module.exports = obj;
-    else        window.WebIDL2 = obj;
+    else        self.WebIDL2 = obj;
 }());
--- a/dom/imptests/failures/html/dom/test_interfaces.html.json
+++ b/dom/imptests/failures/html/dom/test_interfaces.html.json
@@ -1,42 +1,35 @@
 {
   "DOMException exception: existence and properties of exception interface prototype object's \"name\" property": true,
-  "CustomEvent interface: existence and properties of interface object": true,
   "EventListener interface: existence and properties of interface prototype object": true,
   "EventListener interface: existence and properties of interface prototype object's \"constructor\" property": true,
   "EventListener interface: operation handleEvent(Event)": true,
   "MutationObserver interface: operation observe(Node,MutationObserverInit)": true,
-  "Node interface: existence and properties of interface object": true,
-  "Document interface: existence and properties of interface object": true,
   "Document interface: operation prepend([object Object],[object Object])": true,
   "Document interface: operation append([object Object],[object Object])": true,
-  "XMLDocument interface: existence and properties of interface object": true,
   "Document interface: xmlDoc must inherit property \"prepend\" with the proper type (28)": true,
   "Document interface: calling prepend([object Object],[object Object]) on xmlDoc with too few arguments must throw TypeError": true,
   "Document interface: xmlDoc must inherit property \"append\" with the proper type (29)": true,
   "Document interface: calling append([object Object],[object Object]) on xmlDoc with too few arguments must throw TypeError": true,
-  "DocumentFragment interface: existence and properties of interface object": true,
   "DocumentFragment interface: operation prepend([object Object],[object Object])": true,
   "DocumentFragment interface: operation append([object Object],[object Object])": true,
   "DocumentFragment interface: document.createDocumentFragment() must inherit property \"prepend\" with the proper type (4)": true,
   "DocumentFragment interface: calling prepend([object Object],[object Object]) on document.createDocumentFragment() with too few arguments must throw TypeError": true,
   "DocumentFragment interface: document.createDocumentFragment() must inherit property \"append\" with the proper type (5)": true,
   "DocumentFragment interface: calling append([object Object],[object Object]) on document.createDocumentFragment() with too few arguments must throw TypeError": true,
-  "DocumentType interface: existence and properties of interface object": true,
   "DocumentType interface: operation before([object Object],[object Object])": true,
   "DocumentType interface: operation after([object Object],[object Object])": true,
   "DocumentType interface: operation replace([object Object],[object Object])": true,
   "DocumentType interface: document.doctype must inherit property \"before\" with the proper type (3)": true,
   "DocumentType interface: calling before([object Object],[object Object]) on document.doctype with too few arguments must throw TypeError": true,
   "DocumentType interface: document.doctype must inherit property \"after\" with the proper type (4)": true,
   "DocumentType interface: calling after([object Object],[object Object]) on document.doctype with too few arguments must throw TypeError": true,
   "DocumentType interface: document.doctype must inherit property \"replace\" with the proper type (5)": true,
   "DocumentType interface: calling replace([object Object],[object Object]) on document.doctype with too few arguments must throw TypeError": true,
-  "Element interface: existence and properties of interface object": true,
   "Element interface: attribute namespaceURI": true,
   "Element interface: attribute prefix": true,
   "Element interface: attribute localName": true,
   "Element interface: operation prepend([object Object],[object Object])": true,
   "Element interface: operation append([object Object],[object Object])": true,
   "Element interface: operation before([object Object],[object Object])": true,
   "Element interface: operation after([object Object],[object Object])": true,
   "Element interface: operation replace([object Object],[object Object])": true,
@@ -47,41 +40,53 @@
   "Element interface: element must inherit property \"before\" with the proper type (25)": true,
   "Element interface: calling before([object Object],[object Object]) on element with too few arguments must throw TypeError": true,
   "Element interface: element must inherit property \"after\" with the proper type (26)": true,
   "Element interface: calling after([object Object],[object Object]) on element with too few arguments must throw TypeError": true,
   "Element interface: element must inherit property \"replace\" with the proper type (27)": true,
   "Element interface: calling replace([object Object],[object Object]) on element with too few arguments must throw TypeError": true,
   "Attr interface: existence and properties of interface object": true,
   "Attr interface: existence and properties of interface prototype object": true,
-  "CharacterData interface: existence and properties of interface object": true,
   "CharacterData interface: operation before([object Object],[object Object])": true,
   "CharacterData interface: operation after([object Object],[object Object])": true,
   "CharacterData interface: operation replace([object Object],[object Object])": true,
-  "Text interface: existence and properties of interface object": true,
   "CharacterData interface: document.createTextNode(\"abc\") must inherit property \"before\" with the proper type (7)": true,
   "CharacterData interface: calling before([object Object],[object Object]) on document.createTextNode(\"abc\") with too few arguments must throw TypeError": true,
   "CharacterData interface: document.createTextNode(\"abc\") must inherit property \"after\" with the proper type (8)": true,
   "CharacterData interface: calling after([object Object],[object Object]) on document.createTextNode(\"abc\") with too few arguments must throw TypeError": true,
   "CharacterData interface: document.createTextNode(\"abc\") must inherit property \"replace\" with the proper type (9)": true,
   "CharacterData interface: calling replace([object Object],[object Object]) on document.createTextNode(\"abc\") with too few arguments must throw TypeError": true,
-  "ProcessingInstruction interface: existence and properties of interface object": true,
   "CharacterData interface: xmlDoc.createProcessingInstruction(\"abc\", \"def\") must inherit property \"before\" with the proper type (7)": true,
   "CharacterData interface: calling before([object Object],[object Object]) on xmlDoc.createProcessingInstruction(\"abc\", \"def\") with too few arguments must throw TypeError": true,
   "CharacterData interface: xmlDoc.createProcessingInstruction(\"abc\", \"def\") must inherit property \"after\" with the proper type (8)": true,
   "CharacterData interface: calling after([object Object],[object Object]) on xmlDoc.createProcessingInstruction(\"abc\", \"def\") with too few arguments must throw TypeError": true,
   "CharacterData interface: xmlDoc.createProcessingInstruction(\"abc\", \"def\") must inherit property \"replace\" with the proper type (9)": true,
   "CharacterData interface: calling replace([object Object],[object Object]) on xmlDoc.createProcessingInstruction(\"abc\", \"def\") with too few arguments must throw TypeError": true,
-  "Comment interface: existence and properties of interface object": true,
   "CharacterData interface: document.createComment(\"abc\") must inherit property \"before\" with the proper type (7)": true,
   "CharacterData interface: calling before([object Object],[object Object]) on document.createComment(\"abc\") with too few arguments must throw TypeError": true,
   "CharacterData interface: document.createComment(\"abc\") must inherit property \"after\" with the proper type (8)": true,
   "CharacterData interface: calling after([object Object],[object Object]) on document.createComment(\"abc\") with too few arguments must throw TypeError": true,
   "CharacterData interface: document.createComment(\"abc\") must inherit property \"replace\" with the proper type (9)": true,
   "CharacterData interface: calling replace([object Object],[object Object]) on document.createComment(\"abc\") with too few arguments must throw TypeError": true,
-  "NodeFilter interface: existence and properties of interface object": true,
-  "NodeList interface: existence and properties of interface prototype object": true,
-  "DOMTokenList interface: operation add(DOMString)": true,
-  "DOMTokenList interface: operation remove(DOMString)": true,
-  "DOMTokenList interface: calling add(DOMString) on document.body.classList with too few arguments must throw TypeError": true,
-  "DOMTokenList interface: calling remove(DOMString) on document.body.classList with too few arguments must throw TypeError": true,
-  "DOMSettableTokenList interface: existence and properties of interface object": true
+  "NodeFilter interface: existence and properties of interface prototype object": true,
+  "NodeFilter interface: existence and properties of interface prototype object": true,
+  "NodeFilter interface: existence and properties of interface prototype object's \"constructor\" property": true,
+  "EventListener interface: existence and properties of interface object": true,
+  "EventListener interface object length": true,
+  "NodeFilter interface: constant FILTER_ACCEPT on interface prototype object": true,
+  "NodeFilter interface: constant FILTER_REJECT on interface prototype object": true,
+  "NodeFilter interface: constant FILTER_SKIP on interface prototype object": true,
+  "NodeFilter interface: constant SHOW_ALL on interface prototype object": true,
+  "NodeFilter interface: constant SHOW_ELEMENT on interface prototype object": true,
+  "NodeFilter interface: constant SHOW_ATTRIBUTE on interface prototype object": true,
+  "NodeFilter interface: constant SHOW_TEXT on interface prototype object": true,
+  "NodeFilter interface: constant SHOW_CDATA_SECTION on interface prototype object": true,
+  "NodeFilter interface: constant SHOW_ENTITY_REFERENCE on interface prototype object": true,
+  "NodeFilter interface: constant SHOW_ENTITY on interface prototype object": true,
+  "NodeFilter interface: constant SHOW_PROCESSING_INSTRUCTION on interface prototype object": true,
+  "NodeFilter interface: constant SHOW_COMMENT on interface prototype object": true,
+  "NodeFilter interface: constant SHOW_DOCUMENT on interface prototype object": true,
+  "NodeFilter interface: constant SHOW_DOCUMENT_TYPE on interface prototype object": true,
+  "NodeFilter interface: constant SHOW_DOCUMENT_FRAGMENT on interface prototype object": true,
+  "NodeFilter interface: constant SHOW_NOTATION on interface prototype object": true,
+  "NodeFilter interface: operation acceptNode(Node)": true,
+  "NodeList interface: existence and properties of interface prototype object": true
 }
deleted file mode 100644
--- a/dom/imptests/failures/webapps/XMLHttpRequest/tests/submissions/Ms2ger/mochitest.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-# THIS FILE IS AUTOGENERATED BY parseFailures.py - DO NOT EDIT
-[DEFAULT]
-support-files =
-
-
-[test_interfaces.html.json]
deleted file mode 100644
--- a/dom/imptests/failures/webapps/XMLHttpRequest/tests/submissions/Ms2ger/test_interfaces.html.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-  "XMLHttpRequestUpload interface: existence and properties of interface object": true,
-  "XMLHttpRequest interface: existence and properties of interface object": true
-}
--- a/dom/imptests/html/dom/test_interfaces.html
+++ b/dom/imptests/html/dom/test_interfaces.html
@@ -5,45 +5,16 @@
 <script src=/resources/testharnessreport.js></script>
 <script src=/resources/WebIDLParser.js></script>
 <script src=/resources/idlharness.js></script>
 
 <h1>DOM IDL tests</h1>
 <div id=log></div>
 
 <script type=text/plain>
-exception DOMException {
-  const unsigned short INDEX_SIZE_ERR = 1;
-  const unsigned short DOMSTRING_SIZE_ERR = 2; // historical
-  const unsigned short HIERARCHY_REQUEST_ERR = 3;
-  const unsigned short WRONG_DOCUMENT_ERR = 4;
-  const unsigned short INVALID_CHARACTER_ERR = 5;
-  const unsigned short NO_DATA_ALLOWED_ERR = 6; // historical
-  const unsigned short NO_MODIFICATION_ALLOWED_ERR = 7;
-  const unsigned short NOT_FOUND_ERR = 8;
-  const unsigned short NOT_SUPPORTED_ERR = 9;
-  const unsigned short INUSE_ATTRIBUTE_ERR = 10; // historical
-  const unsigned short INVALID_STATE_ERR = 11;
-  const unsigned short SYNTAX_ERR = 12;
-  const unsigned short INVALID_MODIFICATION_ERR = 13;
-  const unsigned short NAMESPACE_ERR = 14;
-  const unsigned short INVALID_ACCESS_ERR = 15;
-  const unsigned short VALIDATION_ERR = 16; // historical
-  const unsigned short TYPE_MISMATCH_ERR = 17; // historical; use TypeError instead
-  const unsigned short SECURITY_ERR = 18;
-  const unsigned short NETWORK_ERR = 19;
-  const unsigned short ABORT_ERR = 20;
-  const unsigned short URL_MISMATCH_ERR = 21;
-  const unsigned short QUOTA_EXCEEDED_ERR = 22;
-  const unsigned short TIMEOUT_ERR = 23;
-  const unsigned short INVALID_NODE_TYPE_ERR = 24;
-  const unsigned short DATA_CLONE_ERR = 25;
-  unsigned short code;
-};
-
 [Constructor(DOMString name)]
 interface DOMError {
   readonly attribute DOMString name;
 };
 
 [Constructor(DOMString type, optional EventInit eventInitDict)]
 interface Event {
   readonly attribute DOMString type;
@@ -446,30 +417,28 @@ interface DOMTokenList {
 };
 
 interface DOMSettableTokenList : DOMTokenList {
             attribute DOMString value;
 };
 </script>
 <script>
 "use strict";
-var xmlDoc, domException, detachedRange, element;
+var xmlDoc, detachedRange, element;
 var idlArray;
 setup(function() {
 	xmlDoc = document.implementation.createDocument(null, "", null);
-	try { document.appendChild(document); } catch(e) { domException = e; }
 	detachedRange = document.createRange();
 	detachedRange.detach();
 	element = xmlDoc.createElementNS(null, "test");
 	element.setAttribute("bar", "baz");
 
 	idlArray = new IdlArray();
 	idlArray.add_idls(document.querySelector("script[type=text\\/plain]").textContent);
 	idlArray.add_objects({
-		DOMException: ['domException'],
 		Event: ['document.createEvent("Event")', 'new Event("foo")'],
 		CustomEvent: ['new CustomEvent("foo")'],
 		XMLDocument: ['xmlDoc'],
 		DOMImplementation: ['document.implementation'],
 		DocumentFragment: ['document.createDocumentFragment()'],
 		DocumentType: ['document.doctype'],
 		Element: ['element'],
 		Attr: ['document.querySelector("[id]").attributes[0]'],
--- a/dom/imptests/idlharness.js
+++ b/dom/imptests/idlharness.js
@@ -51,19 +51,32 @@ policies and contribution forms [3].
 /// Helpers ///
 function constValue (cnt) {
     if (cnt.type === "null") return null;
     if (cnt.type === "NaN") return NaN;
     if (cnt.type === "Infinity") return cnt.negative ? -Infinity : Infinity;
     return cnt.value;
 }
 
+function minOverloadLength(overloads) {
+    if (!overloads.length) {
+        return 0;
+    }
+
+    return overloads.map(function(attr) {
+        return attr.arguments ? attr.arguments.filter(function(arg) {
+            return !arg.optional && !arg.variadic;
+        }).length : 0;
+    })
+    .reduce(function(m, n) { return Math.min(m, n); });
+}
+
 /// IdlArray ///
 // Entry point
-window.IdlArray = function()
+self.IdlArray = function()
 //@{
 {
     /**
      * A map from strings to the corresponding named IdlObject, such as
      * IdlInterface or IdlException.  These are the things that test() will run
      * tests on.
      */
     this.members = {};
@@ -161,21 +174,18 @@ IdlArray.prototype.internal_add_idls = f
         parsed_idl.array = this;
         if (parsed_idl.name in this.members)
         {
             throw "Duplicate identifier " + parsed_idl.name;
         }
         switch(parsed_idl.type)
         {
         case "interface":
-            this.members[parsed_idl.name] = new IdlInterface(parsed_idl);
-            break;
-
-        case "exception":
-            this.members[parsed_idl.name] = new IdlException(parsed_idl);
+            this.members[parsed_idl.name] =
+                new IdlInterface(parsed_idl, /* is_callback = */ false);
             break;
 
         case "dictionary":
             // Nothing to test, but we need the dictionary info around for type
             // checks
             this.members[parsed_idl.name] = new IdlDictionary(parsed_idl);
             break;
 
@@ -188,18 +198,18 @@ IdlArray.prototype.internal_add_idls = f
             console.log("callback not yet supported");
             break;
 
         case "enum":
             this.members[parsed_idl.name] = new IdlEnum(parsed_idl);
             break;
 
         case "callback interface":
-            // TODO
-            console.log("callback interface not yet supported");
+            this.members[parsed_idl.name] =
+                new IdlInterface(parsed_idl, /* is_callback = */ true);
             break;
 
         default:
             throw parsed_idl.name + ": " + parsed_idl.type + " not yet supported";
         }
     }.bind(this));
 };
 
@@ -408,22 +418,24 @@ IdlArray.prototype.assert_type_is = func
             assert_true(0 <= value && value <= 4294967295, "unsigned long " + value + " not in range [0, 4294967295]");
             return;
 
         case "long long":
             assert_equals(typeof value, "number");
             return;
 
         case "unsigned long long":
+        case "DOMTimeStamp":
             assert_equals(typeof value, "number");
             assert_true(0 <= value, "unsigned long long is negative");
             return;
 
         case "float":
         case "double":
+        case "DOMHighResTimeStamp":
         case "unrestricted float":
         case "unrestricted double":
             // TODO: distinguish these cases
             assert_equals(typeof value, "number");
             return;
 
         case "DOMString":
         case "ByteString":
@@ -443,23 +455,23 @@ IdlArray.prototype.assert_type_is = func
     }
 
     if (this.members[type] instanceof IdlInterface)
     {
         // We don't want to run the full
         // IdlInterface.prototype.test_instance_of, because that could result
         // in an infinite loop.  TODO: This means we don't have tests for
         // NoInterfaceObject interfaces, and we also can't test objects that
-        // come from another window.
+        // come from another self.
         assert_true(typeof value == "object" || typeof value == "function", "wrong type: not object or function");
         if (value instanceof Object
         && !this.members[type].has_extended_attribute("NoInterfaceObject")
-        && type in window)
+        && type in self)
         {
-            assert_true(value instanceof window[type], "not instanceof " + type);
+            assert_true(value instanceof self[type], "not instanceof " + type);
         }
     }
     else if (this.members[type] instanceof IdlEnum)
     {
         assert_equals(typeof value, "string");
     }
     else if (this.members[type] instanceof IdlDictionary)
     {
@@ -524,21 +536,18 @@ function IdlDictionary(obj)
      * if there is none.
      */
     this.base = obj.inheritance;
 }
 
 //@}
 IdlDictionary.prototype = Object.create(IdlObject.prototype);
 
-/// IdlExceptionOrInterface ///
-// Code sharing!
-function IdlExceptionOrInterface(obj)
-//@{
-{
+/// IdlInterface ///
+function IdlInterface(obj, is_callback) {
     /**
      * obj is an object produced by the WebIDLParser.js "exception" or
      * "interface" production, as appropriate.
      */
 
     /** Self-explanatory. */
     this.name = obj.name;
 
@@ -552,27 +561,58 @@ function IdlExceptionOrInterface(obj)
      */
     this.untested = obj.untested;
 
     /** An array of objects produced by the "ExtAttr" production. */
     this.extAttrs = obj.extAttrs;
 
     /** An array of IdlInterfaceMembers. */
     this.members = obj.members.map(function(m){return new IdlInterfaceMember(m); });
+    if (this.has_extended_attribute("Unforgeable")) {
+        this.members
+            .filter(function(m) { return !m["static"] && (m.type == "attribute" || m.type == "operation"); })
+            .forEach(function(m) { return m.isUnforgeable = true; });
+    }
 
     /**
      * The name (as a string) of the type we inherit from, or null if there is
      * none.
      */
     this.base = obj.inheritance;
+
+    this._is_callback = is_callback;
 }
- 
+IdlInterface.prototype = Object.create(IdlObject.prototype);
+IdlInterface.prototype.is_callback = function()
+//@{
+{
+    return this._is_callback;
+};
 //@}
-IdlExceptionOrInterface.prototype = Object.create(IdlObject.prototype);
-IdlExceptionOrInterface.prototype.test = function()
+
+IdlInterface.prototype.has_constants = function()
+//@{
+{
+    return this.members.some(function(member) {
+        return member.type === "const";
+    });
+};
+//@}
+
+IdlInterface.prototype.is_global = function()
+//@{
+{
+    return this.extAttrs.some(function(attribute) {
+        return attribute.name === "Global" ||
+               attribute.name === "PrimaryGlobal";
+    });
+};
+//@}
+
+IdlInterface.prototype.test = function()
 //@{
 {
     if (this.has_extended_attribute("NoInterfaceObject"))
     {
         // No tests to do without an instance.  TODO: We should still be able
         // to run tests on the prototype object, if we obtain one through some
         // other means.
         return;
@@ -588,853 +628,604 @@ IdlExceptionOrInterface.prototype.test =
     // operations, . . .).  These are run even if .untested is true, because
     // members might themselves be marked as .untested.  This might happen to
     // interfaces if the interface itself is untested but a partial interface
     // that extends it is tested -- then the interface itself and its initial
     // members will be marked as untested, but the members added by the partial
     // interface are still tested.
     this.test_members();
 };
-
-//@}
-
-/// IdlException ///
-function IdlException(obj) { IdlExceptionOrInterface.call(this, obj); }
-IdlException.prototype = Object.create(IdlExceptionOrInterface.prototype);
-IdlException.prototype.test_self = function()
-//@{
-{
-    test(function()
-    {
-        // "For every exception that is not declared with the
-        // [NoInterfaceObject] extended attribute, a corresponding property
-        // must exist on the exception’s relevant namespace object. The name of
-        // the property is the identifier of the exception, and its value is an
-        // object called the exception interface object, which provides access
-        // to any constants that have been associated with the exception. The
-        // property has the attributes { [[Writable]]: true, [[Enumerable]]:
-        // false, [[Configurable]]: true }."
-        assert_own_property(window, this.name,
-                            "window does not have own property " + format_value(this.name));
-        var desc = Object.getOwnPropertyDescriptor(window, this.name);
-        assert_false("get" in desc, "window's property " + format_value(this.name) + " has getter");
-        assert_false("set" in desc, "window's property " + format_value(this.name) + " has setter");
-        assert_true(desc.writable, "window's property " + format_value(this.name) + " is not writable");
-        assert_false(desc.enumerable, "window's property " + format_value(this.name) + " is enumerable");
-        assert_true(desc.configurable, "window's property " + format_value(this.name) + " is not configurable");
-
-        // "The exception interface object for a given exception must be a
-        // function object."
-        // "If an object is defined to be a function object, then it has
-        // characteristics as follows:"
-        // "Its [[Prototype]] internal property is the Function prototype
-        // object."
-        // Note: This doesn't match browsers as of December 2011, see
-        // http://www.w3.org/Bugs/Public/show_bug.cgi?id=14813
-        assert_equals(Object.getPrototypeOf(window[this.name]), Function.prototype,
-                      "prototype of window's property " + format_value(this.name) + " is not Function.prototype");
-        // "Its [[Get]] internal property is set as described in ECMA-262
-        // section 15.3.5.4."
-        // Not much to test for this.
-        // "Its [[Construct]] internal property is set as described in ECMA-262
-        // section 13.2.2."
-        // Tested below.
-        // "Its [[HasInstance]] internal property is set as described in
-        // ECMA-262 section 15.3.5.3, unless otherwise specified."
-        // TODO
-        // "Its [[Class]] internal property is “Function”."
-        // String() returns something implementation-dependent, because it
-        // calls Function#toString.
-        assert_class_string(window[this.name], "Function",
-                            "class string of " + this.name);
-
-        // TODO: Test 4.9.1.1. Exception interface object [[Call]] method
-        // (which does not match browsers:
-        // http://www.w3.org/Bugs/Public/show_bug.cgi?id=14885)
-    }.bind(this), this.name + " exception: existence and properties of exception interface object");
-
-    test(function()
-    {
-        assert_own_property(window, this.name,
-                            "window does not have own property " + format_value(this.name));
-
-        // "The exception interface object must also have a property named
-        // “prototype” with attributes { [[Writable]]: false, [[Enumerable]]:
-        // false, [[Configurable]]: false } whose value is an object called the
-        // exception interface prototype object. This object also provides
-        // access to the constants that are declared on the exception."
-        assert_own_property(window[this.name], "prototype",
-                            'exception "' + this.name + '" does not have own property "prototype"');
-        var desc = Object.getOwnPropertyDescriptor(window[this.name], "prototype");
-        assert_false("get" in desc, this.name + ".prototype has getter");
-        assert_false("set" in desc, this.name + ".prototype has setter");
-        assert_false(desc.writable, this.name + ".prototype is writable");
-        assert_false(desc.enumerable, this.name + ".prototype is enumerable");
-        assert_false(desc.configurable, this.name + ".prototype is configurable");
-
-        // "The exception interface prototype object for a given exception must
-        // have an internal [[Prototype]] property whose value is as follows:
-        //
-        // "If the exception is declared to inherit from another exception,
-        // then the value of the internal [[Prototype]] property is the
-        // exception interface prototype object for the inherited exception.
-        // "Otherwise, the exception is not declared to inherit from another
-        // exception. The value of the internal [[Prototype]] property is the
-        // Error prototype object ([ECMA-262], section 15.11.3.1)."
-        //
-        // Note: This doesn't match browsers as of December 2011, see
-        // https://www.w3.org/Bugs/Public/show_bug.cgi?id=14887.
-        var inherit_exception = this.base ? this.base : "Error";
-        assert_own_property(window, inherit_exception,
-                            'should inherit from ' + inherit_exception + ', but window has no such property');
-        assert_own_property(window[inherit_exception], "prototype",
-                            'should inherit from ' + inherit_exception + ', but that object has no "prototype" property');
-        assert_equals(Object.getPrototypeOf(window[this.name].prototype),
-                      window[inherit_exception].prototype,
-                      'prototype of ' + this.name + '.prototype is not ' + inherit_exception + '.prototype');
-
-        // "The class string of an exception interface prototype object is the
-        // concatenation of the exception’s identifier and the string
-        // “Prototype”."
-        assert_class_string(window[this.name].prototype, this.name + "Prototype",
-                            "class string of " + this.name + ".prototype");
-        // TODO: Test String(), based on ES definition of
-        // Error.prototype.toString?
-    }.bind(this), this.name + " exception: existence and properties of exception interface prototype object");
-
-    test(function()
-    {
-        assert_own_property(window, this.name,
-                            "window does not have own property " + format_value(this.name));
-        assert_own_property(window[this.name], "prototype",
-                            'interface "' + this.name + '" does not have own property "prototype"');
-
-        // "There must be a property named “name” on the exception interface
-        // prototype object with attributes { [[Writable]]: true,
-        // [[Enumerable]]: false, [[Configurable]]: true } and whose value is
-        // the identifier of the exception."
-        assert_own_property(window[this.name].prototype, "name",
-                'prototype object does not have own property "name"');
-        var desc = Object.getOwnPropertyDescriptor(window[this.name].prototype, "name");
-        assert_false("get" in desc, this.name + ".prototype.name has getter");
-        assert_false("set" in desc, this.name + ".prototype.name has setter");
-        assert_true(desc.writable, this.name + ".prototype.name is not writable");
-        assert_false(desc.enumerable, this.name + ".prototype.name is enumerable");
-        assert_true(desc.configurable, this.name + ".prototype.name is not configurable");
-        assert_equals(desc.value, this.name, this.name + ".prototype.name has incorrect value");
-    }.bind(this), this.name + " exception: existence and properties of exception interface prototype object's \"name\" property");
-
-    test(function()
-    {
-        assert_own_property(window, this.name,
-                            "window does not have own property " + format_value(this.name));
-        assert_own_property(window[this.name], "prototype",
-                            'interface "' + this.name + '" does not have own property "prototype"');
-
-        // "If the [NoInterfaceObject] extended attribute was not specified on
-        // the exception, then there must also be a property named
-        // “constructor” on the exception interface prototype object with
-        // attributes { [[Writable]]: true, [[Enumerable]]: false,
-        // [[Configurable]]: true } and whose value is a reference to the
-        // exception interface object for the exception."
-        assert_own_property(window[this.name].prototype, "constructor",
-                            this.name + '.prototype does not have own property "constructor"');
-        var desc = Object.getOwnPropertyDescriptor(window[this.name].prototype, "constructor");
-        assert_false("get" in desc, this.name + ".prototype.constructor has getter");
-        assert_false("set" in desc, this.name + ".prototype.constructor has setter");
-        assert_true(desc.writable, this.name + ".prototype.constructor is not writable");
-        assert_false(desc.enumerable, this.name + ".prototype.constructor is enumerable");
-        assert_true(desc.configurable, this.name + ".prototype.constructor in not configurable");
-        assert_equals(window[this.name].prototype.constructor, window[this.name],
-                      this.name + '.prototype.constructor is not the same object as ' + this.name);
-    }.bind(this), this.name + " exception: existence and properties of exception interface prototype object's \"constructor\" property");
-};
-
-//@}
-IdlException.prototype.test_members = function()
-//@{
-{
-    for (var i = 0; i < this.members.length; i++)
-    {
-        var member = this.members[i];
-        if (member.untested)
-        {
-            continue;
-        }
-        if (member.type == "const" && member.name != "prototype")
-        {
-            test(function()
-            {
-                assert_own_property(window, this.name,
-                                    "window does not have own property " + format_value(this.name));
-
-                // "For each constant defined on the exception, there must be a
-                // corresponding property on the exception interface object, if
-                // it exists, if the identifier of the constant is not
-                // “prototype”."
-                assert_own_property(window[this.name], member.name);
-                // "The value of the property is the ECMAScript value that is
-                // equivalent to the constant’s IDL value, according to the
-                // rules in section 4.2 above."
-                assert_equals(window[this.name][member.name], constValue(member.value),
-                              "property has wrong value");
-                // "The property has attributes { [[Writable]]: false,
-                // [[Enumerable]]: true, [[Configurable]]: false }."
-                var desc = Object.getOwnPropertyDescriptor(window[this.name], member.name);
-                assert_false("get" in desc, "property has getter");
-                assert_false("set" in desc, "property has setter");
-                assert_false(desc.writable, "property is writable");
-                assert_true(desc.enumerable, "property is not enumerable");
-                assert_false(desc.configurable, "property is configurable");
-            }.bind(this), this.name + " exception: constant " + member.name + " on exception interface object");
-            // "In addition, a property with the same characteristics must
-            // exist on the exception interface prototype object."
-            test(function()
-            {
-                assert_own_property(window, this.name,
-                                    "window does not have own property " + format_value(this.name));
-                assert_own_property(window[this.name], "prototype",
-                                    'exception "' + this.name + '" does not have own property "prototype"');
-
-                assert_own_property(window[this.name].prototype, member.name);
-                assert_equals(window[this.name].prototype[member.name], constValue(member.value),
-                              "property has wrong value");
-                var desc = Object.getOwnPropertyDescriptor(window[this.name].prototype, member.name);
-                assert_false("get" in desc, "property has getter");
-                assert_false("set" in desc, "property has setter");
-                assert_false(desc.writable, "property is writable");
-                assert_true(desc.enumerable, "property is not enumerable");
-                assert_false(desc.configurable, "property is configurable");
-            }.bind(this), this.name + " exception: constant " + member.name + " on exception interface prototype object");
-        }
-        else if (member.type == "field")
-        {
-            test(function()
-            {
-                assert_own_property(window, this.name,
-                                    "window does not have own property " + format_value(this.name));
-                assert_own_property(window[this.name], "prototype",
-                                    'exception "' + this.name + '" does not have own property "prototype"');
-
-                // "For each exception field, there must be a corresponding
-                // property on the exception interface prototype object, whose
-                // characteristics are as follows:
-                // "The name of the property is the identifier of the exception
-                // field."
-                assert_own_property(window[this.name].prototype, member.name);
-                // "The property has attributes { [[Get]]: G, [[Enumerable]]:
-                // true, [[Configurable]]: true }, where G is the exception
-                // field getter, defined below."
-                var desc = Object.getOwnPropertyDescriptor(window[this.name].prototype, member.name);
-                assert_false("value" in desc, "property descriptor has value but is supposed to be accessor");
-                assert_false("writable" in desc, 'property descriptor has "writable" field but is supposed to be accessor');
-                // TODO: ES5 doesn't seem to say whether desc should have a
-                // .set property.
-                assert_true(desc.enumerable, "property is not enumerable");
-                assert_true(desc.configurable, "property is not configurable");
-                // "The exception field getter is a Function object whose
-                // behavior when invoked is as follows:"
-                assert_equals(typeof desc.get, "function", "typeof getter");
-                // "The value of the Function object’s “length” property is the
-                // Number value 0."
-                // This test is before the TypeError tests so that it's easiest
-                // to see that Firefox 11a1 only fails one assert in this test.
-                assert_equals(desc.get.length, 0, "getter length");
-                // "Let O be the result of calling ToObject on the this value.
-                // "If O is not a platform object representing an exception for
-                // the exception on which the exception field was declared,
-                // then throw a TypeError."
-                // TODO: Test on a platform object representing an exception.
-                assert_throws(new TypeError(), function()
-                {
-                    window[this.name].prototype[member.name];
-                }.bind(this), "getting property on prototype object must throw TypeError");
-                assert_throws(new TypeError(), function()
-                {
-                    desc.get.call({});
-                }.bind(this), "calling getter on wrong object type must throw TypeError");
-            }.bind(this), this.name + " exception: field " + member.name + " on exception interface prototype object");
-        }
-    }
-};
-
-//@}
-IdlException.prototype.test_object = function(desc)
-//@{
-{
-    var obj, exception = null;
-    try
-    {
-        obj = eval(desc);
-    }
-    catch(e)
-    {
-        exception = e;
-    }
-
-    test(function()
-    {
-        assert_equals(exception, null, "Unexpected exception when evaluating object");
-        assert_equals(typeof obj, "object", "wrong typeof object");
-
-        // We can't easily test that its prototype is correct if there's no
-        // interface object, or the object is from a different global
-        // environment (not instanceof Object).  TODO: test in this case that
-        // its prototype at least looks correct, even if we can't test that
-        // it's actually correct.
-        if (!this.has_extended_attribute("NoInterfaceObject")
-        && (typeof obj != "object" || obj instanceof Object))
-        {
-            assert_own_property(window, this.name,
-                                "window does not have own property " + format_value(this.name));
-            assert_own_property(window[this.name], "prototype",
-                                'exception "' + this.name + '" does not have own property "prototype"');
-
-            // "The value of the internal [[Prototype]] property of the
-            // exception object must be the exception interface prototype
-            // object from the global environment the exception object is
-            // associated with."
-            assert_equals(Object.getPrototypeOf(obj),
-                          window[this.name].prototype,
-                          desc + "'s prototype is not " + this.name + ".prototype");
-        }
-
-        // "The class string of the exception object must be the identifier of
-        // the exception."
-        assert_class_string(obj, this.name, "class string of " + desc);
-        // Stringifier is not defined for DOMExceptions, because message isn't
-        // defined.
-    }.bind(this), this.name + " must be represented by " + desc);
-
-    for (var i = 0; i < this.members.length; i++)
-    {
-        var member = this.members[i];
-        test(function()
-        {
-            assert_equals(exception, null, "Unexpected exception when evaluating object");
-            assert_equals(typeof obj, "object", "wrong typeof object");
-            assert_inherits(obj, member.name);
-            if (member.type == "const")
-            {
-                assert_equals(obj[member.name], constValue(member.value));
-            }
-            if (member.type == "field")
-            {
-                this.array.assert_type_is(obj[member.name], member.idlType);
-            }
-        }.bind(this), this.name + " exception: " + desc + ' must inherit property "' + member.name + '" with the proper type');
-    }
-};
-//@}
-
-/// IdlInterface ///
-function IdlInterface(obj) { IdlExceptionOrInterface.call(this, obj); }
-IdlInterface.prototype = Object.create(IdlExceptionOrInterface.prototype);
-IdlInterface.prototype.is_callback = function()
-//@{
-{
-    return this.has_extended_attribute("Callback");
-};
-//@}
-
-IdlInterface.prototype.has_constants = function()
-//@{
-{
-    return this.members.some(function(member) {
-        return member.type === "const";
-    });
-};
 //@}
 
 IdlInterface.prototype.test_self = function()
 //@{
 {
     test(function()
     {
-        // This function tests WebIDL as of 2012-11-28.
+        // This function tests WebIDL as of 2015-01-13.
+        // TODO: Consider [Exposed].
 
-        // "For every interface that:
+        // "For every interface that is exposed in a given ECMAScript global
+        // environment and:
         // * is a callback interface that has constants declared on it, or
         // * is a non-callback interface that is not declared with the
         //   [NoInterfaceObject] extended attribute,
         // a corresponding property MUST exist on the ECMAScript global object.
         // The name of the property is the identifier of the interface, and its
         // value is an object called the interface object.
         // The property has the attributes { [[Writable]]: true,
         // [[Enumerable]]: false, [[Configurable]]: true }."
         if (this.is_callback() && !this.has_constants()) {
             return;
         }
 
         // TODO: Should we test here that the property is actually writable
         // etc., or trust getOwnPropertyDescriptor?
-        assert_own_property(window, this.name,
-                            "window does not have own property " + format_value(this.name));
-        var desc = Object.getOwnPropertyDescriptor(window, this.name);
-        assert_false("get" in desc, "window's property " + format_value(this.name) + " has getter");
-        assert_false("set" in desc, "window's property " + format_value(this.name) + " has setter");
-        assert_true(desc.writable, "window's property " + format_value(this.name) + " is not writable");
-        assert_false(desc.enumerable, "window's property " + format_value(this.name) + " is enumerable");
-        assert_true(desc.configurable, "window's property " + format_value(this.name) + " is not configurable");
+        assert_own_property(self, this.name,
+                            "self does not have own property " + format_value(this.name));
+        var desc = Object.getOwnPropertyDescriptor(self, this.name);
+        assert_false("get" in desc, "