Merge mozilla-central to mozilla-inboun
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Fri, 04 Mar 2016 13:39:20 +0100
changeset 323120 92ce3f765f055e650df3cf21412ce92f6605ea8e
parent 323119 249cbccd3ad3b52f6b30f5eb471a22f3770cd2f0 (current diff)
parent 323098 33d36bf6ca0c9d9c22cadf6d8223fa6e1418b62c (diff)
child 323121 fa16519da919a07c029abac60d328564ee8e73d3
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone47.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to mozilla-inboun
devtools/client/locales/en-US/tilt.properties
devtools/client/shared/test/browser_telemetry_button_tilt.js
devtools/client/themes/images/command-tilt.png
devtools/client/themes/images/command-tilt@2x.png
devtools/client/tilt/TiltWorkerCrafter.js
devtools/client/tilt/TiltWorkerPicker.js
devtools/client/tilt/moz.build
devtools/client/tilt/test/.eslintrc
devtools/client/tilt/test/browser.ini
devtools/client/tilt/test/browser_tilt_01_lazy_getter.js
devtools/client/tilt/test/browser_tilt_02_notifications-seq.js
devtools/client/tilt/test/browser_tilt_02_notifications-tabs.js
devtools/client/tilt/test/browser_tilt_02_notifications.js
devtools/client/tilt/test/browser_tilt_03_tab_switch.js
devtools/client/tilt/test/browser_tilt_04_initialization.js
devtools/client/tilt/test/browser_tilt_05_destruction-esc.js
devtools/client/tilt/test/browser_tilt_05_destruction-url.js
devtools/client/tilt/test/browser_tilt_05_destruction.js
devtools/client/tilt/test/browser_tilt_arcball-reset-typeahead.js
devtools/client/tilt/test/browser_tilt_arcball-reset.js
devtools/client/tilt/test/browser_tilt_arcball.js
devtools/client/tilt/test/browser_tilt_controller.js
devtools/client/tilt/test/browser_tilt_gl01.js
devtools/client/tilt/test/browser_tilt_gl02.js
devtools/client/tilt/test/browser_tilt_gl03.js
devtools/client/tilt/test/browser_tilt_gl04.js
devtools/client/tilt/test/browser_tilt_gl05.js
devtools/client/tilt/test/browser_tilt_gl06.js
devtools/client/tilt/test/browser_tilt_gl07.js
devtools/client/tilt/test/browser_tilt_gl08.js
devtools/client/tilt/test/browser_tilt_math01.js
devtools/client/tilt/test/browser_tilt_math02.js
devtools/client/tilt/test/browser_tilt_math03.js
devtools/client/tilt/test/browser_tilt_math04.js
devtools/client/tilt/test/browser_tilt_math05.js
devtools/client/tilt/test/browser_tilt_math06.js
devtools/client/tilt/test/browser_tilt_math07.js
devtools/client/tilt/test/browser_tilt_picking.js
devtools/client/tilt/test/browser_tilt_picking_delete.js
devtools/client/tilt/test/browser_tilt_picking_highlight01-offs.js
devtools/client/tilt/test/browser_tilt_picking_highlight01.js
devtools/client/tilt/test/browser_tilt_picking_highlight02.js
devtools/client/tilt/test/browser_tilt_picking_highlight03.js
devtools/client/tilt/test/browser_tilt_picking_inspector.js
devtools/client/tilt/test/browser_tilt_picking_miv.js
devtools/client/tilt/test/browser_tilt_utils01.js
devtools/client/tilt/test/browser_tilt_utils02.js
devtools/client/tilt/test/browser_tilt_utils03.js
devtools/client/tilt/test/browser_tilt_utils04.js
devtools/client/tilt/test/browser_tilt_utils05.js
devtools/client/tilt/test/browser_tilt_utils06.js
devtools/client/tilt/test/browser_tilt_utils07.js
devtools/client/tilt/test/browser_tilt_utils08.js
devtools/client/tilt/test/browser_tilt_visualizer.js
devtools/client/tilt/test/browser_tilt_zoom.js
devtools/client/tilt/test/head.js
devtools/client/tilt/tilt-commands.js
devtools/client/tilt/tilt-gl.js
devtools/client/tilt/tilt-math.js
devtools/client/tilt/tilt-utils.js
devtools/client/tilt/tilt-visualizer-style.js
devtools/client/tilt/tilt-visualizer.js
devtools/client/tilt/tilt.js
dom/media/mediasource/test/mochitest.ini
dom/media/test/mochitest.ini
dom/media/tests/mochitest/identity/mochitest.ini
dom/media/tests/mochitest/ipc/mochitest.ini
dom/media/tests/mochitest/mochitest.ini
dom/media/webaudio/test/mochitest.ini
dom/media/webspeech/recognition/test/mochitest.ini
dom/media/webspeech/synth/test/mochitest.ini
testing/mozharness/configs/android/androidarm.py
testing/mozharness/configs/android/androidarm_4_3.py
testing/mozharness/configs/unittests/linux_unittest.py
testing/mozharness/configs/unittests/mac_unittest.py
testing/mozharness/configs/unittests/win_unittest.py
testing/taskcluster/tasks/branches/base_job_flags.yml
testing/taskcluster/tasks/branches/base_jobs.yml
testing/taskcluster/tasks/branches/try/job_flags.yml
--- a/.eslintignore
+++ b/.eslintignore
@@ -98,17 +98,16 @@ devtools/client/netmonitor/**
 devtools/client/performance/**
 devtools/client/projecteditor/**
 devtools/client/promisedebugger/**
 devtools/client/responsivedesign/**
 devtools/client/scratchpad/**
 devtools/client/shadereditor/**
 devtools/client/shared/**
 devtools/client/sourceeditor/**
-devtools/client/tilt/**
 devtools/client/webaudioeditor/**
 devtools/client/webconsole/**
 devtools/client/webide/**
 devtools/server/**
 devtools/shared/**
 
 # Ignore devtools pre-processed files
 devtools/client/framework/toolbox-process-window.js
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -549,16 +549,19 @@
                             observes="devtoolsMenuBroadcaster_Scratchpad"
                             accesskey="&scratchpad.accesskey;"/>
                   <menuitem id="menu_pageSource"
                             observes="devtoolsMenuBroadcaster_PageSource"
                             accesskey="&pageSourceCmd.accesskey;"/>
                   <menuitem id="javascriptConsole"
                             observes="devtoolsMenuBroadcaster_ErrorConsole"
                             accesskey="&errorConsoleCmd.accesskey;"/>
+                  <menuitem id="menu_devtools_serviceworkers"
+                            observes="devtoolsMenuBroadcaster_ServiceWorkers"
+                            accesskey="&devtoolsServiceWorkers.accesskey;"/>
                   <menuitem id="menu_devtools_connect"
                             observes="devtoolsMenuBroadcaster_connect"/>
                   <menuseparator id="devToolsEndSeparator"/>
                   <menuitem id="getMoreDevtools"
                             observes="devtoolsMenuBroadcaster_GetMoreTools"
                             accesskey="&getMoreDevtoolsCmd.accesskey;"/>
                 </menupopup>
               </menu>
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -102,16 +102,17 @@
     <command id="Tools:BrowserToolbox" oncommand="BrowserToolboxProcess.init();" disabled="true" hidden="true"/>
     <command id="Tools:BrowserContentToolbox" oncommand="gDevToolsBrowser.openContentProcessToolbox();" disabled="true" hidden="true"/>
     <command id="Tools:BrowserConsole" oncommand="HUDService.openBrowserConsoleOrFocus();"/>
     <command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();"/>
     <command id="Tools:ResponsiveUI" oncommand="ResponsiveUI.toggle();"/>
     <command id="Tools:Eyedropper" oncommand="openEyedropper();"/>
     <command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/>
     <command id="Tools:ErrorConsole" oncommand="toJavaScriptConsole()" disabled="true" hidden="true"/>
+    <command id="Tools:ServiceWorkers" oncommand="gDevToolsBrowser.openAboutDebugging(gBrowser, 'workers')"/>
     <command id="Tools:DevToolsConnect" oncommand="gDevToolsBrowser.openConnectScreen(gBrowser)" disabled="true" hidden="true"/>
     <command id="Tools:Sanitize"
      oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/>
     <command id="Tools:PrivateBrowsing"
       oncommand="OpenBrowserWindow({private: true});" reserved="true"/>
 #ifdef E10S_TESTING_ONLY
     <command id="Tools:NonRemoteWindow"
       oncommand="OpenBrowserWindow({remote: false});"/>
@@ -241,16 +242,19 @@
       <observes element="canViewSource" attribute="disabled"/>
     </broadcaster>
     <broadcaster id="devtoolsMenuBroadcaster_ErrorConsole"
                  label="&errorConsoleCmd.label;"
                  command="Tools:ErrorConsole"/>
     <broadcaster id="devtoolsMenuBroadcaster_GetMoreTools"
                  label="&getMoreDevtoolsCmd.label;"
                  oncommand="openUILinkIn('https://addons.mozilla.org/firefox/collections/mozilla/webdeveloper/', 'tab');"/>
+    <broadcaster id="devtoolsMenuBroadcaster_ServiceWorkers"
+                 label="&devtoolsServiceWorkers.label;"
+                 command="Tools:ServiceWorkers"/>
     <broadcaster id="devtoolsMenuBroadcaster_connect"
                  label="&devtoolsConnect.label;"
                  command="Tools:DevToolsConnect"/>
   </broadcasterset>
 
   <keyset id="mainKeyset">
     <key id="key_newNavigator"
          key="&newNavigatorCmd.key;"
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -463,18 +463,18 @@
     <menupopup id="SyncedTabsSidebarContext">
       <menuitem label="&syncedTabs.context.openTab.label;"
                 accesskey="&syncedTabs.context.openTab.accesskey;"
                 id="syncedTabsOpenSelected"/>
       <menuitem label="&syncedTabs.context.bookmarkSingleTab.label;"
                 accesskey="&syncedTabs.context.bookmarkSingleTab.accesskey;"
                 id="syncedTabsBookmarkSelected"/>
       <menuseparator/>
-      <menuitem label="&syncedTabs.context.refreshList.label;"
-                accesskey="&syncedTabs.context.refreshList.accesskey;"
+      <menuitem label="&syncSyncNowItem.label;"
+                accesskey="&syncSyncNowItem.accesskey;"
                 id="syncedTabsRefresh"/>
     </menupopup>
   </popupset>
 
 #ifdef CAN_DRAW_IN_TITLEBAR
 <vbox id="titlebar">
   <hbox id="titlebar-content">
     <spacer id="titlebar-spacer" flex="1"/>
--- a/browser/base/content/tab-content.js
+++ b/browser/base/content/tab-content.js
@@ -144,22 +144,16 @@ var AboutHomeListener = {
     // Set snippetsVersion last, which triggers to show the snippets when it's set.
     docElt.setAttribute("snippetsURL", aData.snippetsURL);
     if (aData.showKnowYourRights)
       docElt.setAttribute("showKnowYourRights", "true");
     docElt.setAttribute("snippetsVersion", aData.snippetsVersion);
   },
 
   onPageLoad: function() {
-    let doc = content.document;
-    if (doc.documentElement.hasAttribute("hasBrowserHandlers")) {
-      return;
-    }
-
-    doc.documentElement.setAttribute("hasBrowserHandlers", "true");
     addMessageListener("AboutHome:Update", this);
     addEventListener("click", this, true);
     addEventListener("pagehide", this, true);
 
     sendAsyncMessage("AboutHome:RequestUpdate");
   },
 
   onClick: function(aEvent) {
@@ -211,19 +205,16 @@ var AboutHomeListener = {
 
   onPageHide: function(aEvent) {
     if (aEvent.target.defaultView.frameElement) {
       return;
     }
     removeMessageListener("AboutHome:Update", this);
     removeEventListener("click", this, true);
     removeEventListener("pagehide", this, true);
-    if (aEvent.target.documentElement) {
-      aEvent.target.documentElement.removeAttribute("hasBrowserHandlers");
-    }
   },
 };
 AboutHomeListener.init(this);
 
 var AboutPrivateBrowsingListener = {
   init(chromeGlobal) {
     chromeGlobal.addEventListener("AboutPrivateBrowsingOpenWindow", this,
                                   false, true);
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -179,23 +179,23 @@ skip-if = e10s # Bug 1236991 - Update or
 [browser_bug423833.js]
 skip-if = true # bug 428712
 [browser_bug424101.js]
 [browser_bug427559.js]
 [browser_bug431826.js]
 [browser_bug432599.js]
 [browser_bug435035.js]
 [browser_bug435325.js]
-skip-if = buildapp == 'mulet' || e10s # Bug 1099156 - test directly manipulates content
+skip-if = buildapp == 'mulet'
 [browser_bug441778.js]
 skip-if = buildapp == 'mulet'
 [browser_bug455852.js]
 [browser_bug460146.js]
 [browser_bug462289.js]
-skip-if = toolkit == "cocoa" || e10s # Bug 1102017 - middle-button mousedown on selected tab2 does not activate tab - Didn't expect [object XULElement], but got it
+skip-if = toolkit == "cocoa"
 [browser_bug462673.js]
 [browser_bug477014.js]
 [browser_bug479408.js]
 skip-if = buildapp == 'mulet'
 [browser_bug481560.js]
 [browser_bug484315.js]
 [browser_bug491431.js]
 skip-if = buildapp == 'mulet'
@@ -280,17 +280,17 @@ tags = mcb
 tags = mcb
 skip-if = buildapp == "mulet" || e10s # Bug 1093642 - test manipulates content and relies on content focus
 [browser_mixedContentFromOnunload.js]
 tags = mcb
 [browser_mixedContentFramesOnHttp.js]
 tags = mcb
 [browser_bug970746.js]
 [browser_bug1015721.js]
-skip-if = os == 'win' || e10s # Bug 1159268 - Need a content-process safe version of synthesizeWheel
+skip-if = os == 'win'
 [browser_bug1064280_changeUrlInPinnedTab.js]
 [browser_bug1070778.js]
 [browser_accesskeys.js]
 [browser_canonizeURL.js]
 [browser_clipboard.js]
 [browser_contentAreaClick.js]
 [browser_contextmenu.js]
 skip-if = toolkit == "gtk2" || toolkit == "gtk3" # disabled on Linux due to bug 513558
@@ -309,17 +309,17 @@ skip-if = e10s # Bug 1071623
 [browser_duplicateIDs.js]
 [browser_drag.js]
 skip-if = true # browser_drag.js is disabled, as it needs to be updated for the new behavior from bug 320638.
 [browser_favicon_change.js]
 [browser_favicon_change_not_in_document.js]
 [browser_findbarClose.js]
 [browser_focusonkeydown.js]
 [browser_fullscreen-window-open.js]
-skip-if = buildapp == 'mulet' || e10s || os == "linux" # Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly. Linux: Intermittent failures - bug 941575.
+skip-if = buildapp == 'mulet' || os == "linux" # Linux: Intermittent failures - bug 941575.
 [browser_fxaccounts.js]
 support-files = fxa_profile_handler.sjs
 [browser_fxa_migrate.js]
 [browser_fxa_oauth.js]
 [browser_fxa_web_channel.js]
 [browser_gestureSupport.js]
 skip-if = e10s # Bug 863514 - no gesture support.
 [browser_getshortcutoruri.js]
--- a/browser/base/content/test/general/browser_action_keyword.js
+++ b/browser/base/content/test/general/browser_action_keyword.js
@@ -63,28 +63,28 @@ add_task(function*() {
   is(span.childNodes[0].data, "something", "Node should contain the query for the keyword");
 
   is_element_hidden(result._url, "URL element should be hidden");
 
   // Click on the result
   info("Normal click on result");
   let tabPromise = promiseTabLoadEvent(tab);
   EventUtils.synthesizeMouseAtCenter(result, {});
-  let loadEvent = yield tabPromise;
-  is(loadEvent.target.location.href, "http://example.com/?q=something", "Tab should have loaded from clicking on result");
+  yield tabPromise;
+  is(tab.linkedBrowser.currentURI.spec, "http://example.com/?q=something", "Tab should have loaded from clicking on result");
 
   // Middle-click on the result
   info("Middle-click on result");
   result = yield promise_first_result("keyword somethingmore");
   isnot(result, null, "Expect a keyword result");
   // We need to make a real URI out of this to ensure it's normalised for
   // comparison.
   uri = NetUtil.newURI(result.getAttribute("url"));
   is(uri.spec, makeActionURI("keyword", {url: "http://example.com/?q=somethingmore", input: "keyword somethingmore"}).spec, "Expect correct url");
 
   tabPromise = promiseWaitForEvent(gBrowser.tabContainer, "TabOpen");
   EventUtils.synthesizeMouseAtCenter(result, {button: 1});
   let tabOpenEvent = yield tabPromise;
   let newTab = tabOpenEvent.target;
   tabs.push(newTab);
-  loadEvent = yield promiseTabLoadEvent(newTab);
-  is(loadEvent.target.location.href, "http://example.com/?q=somethingmore", "Tab should have loaded from middle-clicking on result");
+  yield promiseTabLoadEvent(newTab);
+  is(newTab.linkedBrowser.currentURI.spec, "http://example.com/?q=somethingmore", "Tab should have loaded from middle-clicking on result");
 });
--- a/browser/base/content/test/general/browser_bug1015721.js
+++ b/browser/base/content/test/general/browser_bug1015721.js
@@ -15,33 +15,32 @@ function test() {
     gTab2 = gBrowser.addTab();
 
     yield FullZoomHelper.selectTabAndWaitForLocationChange(gTab1);
     yield FullZoomHelper.load(gTab1, TEST_PAGE);
     yield FullZoomHelper.load(gTab2, TEST_PAGE);
   }).then(zoomTab1, FullZoomHelper.failAndContinue(finish));
 }
 
-function dispatchZoomEventToBrowser(browser) {
-  EventUtils.synthesizeWheel(browser.contentDocument.documentElement, 10, 10, {
-    ctrlKey: true, deltaY: -1, deltaMode: WheelEvent.DOM_DELTA_LINE
-  }, browser.contentWindow);
-}
-
 function zoomTab1() {
   Task.spawn(function () {
     is(gBrowser.selectedTab, gTab1, "Tab 1 is selected");
     FullZoomHelper.zoomTest(gTab1, 1, "Initial zoom of tab 1 should be 1");
     FullZoomHelper.zoomTest(gTab2, 1, "Initial zoom of tab 2 should be 1");
 
     let browser1 = gBrowser.getBrowserForTab(gTab1);
-    dispatchZoomEventToBrowser(browser1);
+    yield BrowserTestUtils.synthesizeMouse(null, 10, 10, {
+      wheel: true, ctrlKey: true, deltaY: -1, deltaMode: WheelEvent.DOM_DELTA_LINE
+    }, browser1);
 
-    gLevel1 = ZoomManager.getZoomForBrowser(browser1);
-    ok(gLevel1 > 1, "New zoom for tab 1 should be greater than 1");
+    info("Waiting for tab 1 to be zoomed");
+    yield promiseWaitForCondition(() => {
+      gLevel1 = ZoomManager.getZoomForBrowser(browser1);
+      return gLevel1 > 1;
+    });
 
     yield FullZoomHelper.selectTabAndWaitForLocationChange(gTab2);
     FullZoomHelper.zoomTest(gTab2, gLevel1, "Tab 2 should have zoomed along with tab 1");
   }).then(finishTest, FullZoomHelper.failAndContinue(finish));
 }
 
 function finishTest() {
   Task.spawn(function () {
--- a/browser/base/content/test/general/browser_bug435325.js
+++ b/browser/base/content/test/general/browser_bug435325.js
@@ -3,71 +3,67 @@
 
 /* Ensure that clicking the button in the Offline mode neterror page makes the browser go online. See bug 435325. */
 
 var proxyPrefValue;
 
 function test() {
   waitForExplicitFinish();
 
-  let tab = gBrowser.selectedTab = gBrowser.addTab();
-
   // Go offline and disable the proxy and cache, then try to load the test URL.
   Services.io.offline = true;
 
   // Tests always connect to localhost, and per bug 87717, localhost is now
   // reachable in offline mode.  To avoid this, disable any proxy.
   proxyPrefValue = Services.prefs.getIntPref("network.proxy.type");
   Services.prefs.setIntPref("network.proxy.type", 0);
 
   Services.prefs.setBoolPref("browser.cache.disk.enable", false);
   Services.prefs.setBoolPref("browser.cache.memory.enable", false);
-  content.location = "http://example.com/";
 
-  window.addEventListener("DOMContentLoaded", function load() {
-    if (content.location == "about:blank") {
-      info("got about:blank, which is expected once, so return");
-      return;
-    }
-    window.removeEventListener("DOMContentLoaded", load, false);
+  gBrowser.selectedTab = gBrowser.addTab("http://example.com/");
 
-    let observer = new MutationObserver(function (mutations) {
-      for (let mutation of mutations) {
-        if (mutation.attributeName == "hasBrowserHandlers") {
-          observer.disconnect();
-          checkPage();
-          return;
-        }
-      }
-    });
-    let docElt = tab.linkedBrowser.contentDocument.documentElement;
-    observer.observe(docElt, { attributes: true });
-  }, false);
+  let contentScript = `
+    let listener = function () {
+      removeEventListener("DOMContentLoaded", listener);
+      sendAsyncMessage("Test:DOMContentLoaded", { uri: content.document.documentURI });
+    };
+    addEventListener("DOMContentLoaded", listener);
+  `;
+
+  function pageloaded({ data }) {
+    mm.removeMessageListener("Test:DOMContentLoaded", pageloaded);
+    checkPage(data);
+  }
+
+  let mm = gBrowser.selectedBrowser.messageManager;
+  mm.addMessageListener("Test:DOMContentLoaded", pageloaded);
+  mm.loadFrameScript("data:," + contentScript, true);
 }
 
-function checkPage() {
+function checkPage(data) {
   ok(Services.io.offline, "Setting Services.io.offline to true.");
-  is(gBrowser.contentDocument.documentURI.substring(0,27),
-    "about:neterror?e=netOffline", "Loading the Offline mode neterror page.");
 
-  // Now press the "Try Again" button
-  ok(gBrowser.contentDocument.getElementById("errorTryAgain"),
-    "The error page has got a #errorTryAgain element");
+  is(data.uri.substring(0, 27),
+     "about:neterror?e=netOffline", "Loading the Offline mode neterror page.");
 
   // Re-enable the proxy so example.com is resolved to localhost, rather than
   // the actual example.com.
   Services.prefs.setIntPref("network.proxy.type", proxyPrefValue);
 
   Services.obs.addObserver(function observer(aSubject, aTopic) {
     ok(!Services.io.offline, "After clicking the Try Again button, we're back " +
                              "online.");
     Services.obs.removeObserver(observer, "network:offline-status-changed", false);
     finish();
   }, "network:offline-status-changed", false);
-  gBrowser.contentDocument.getElementById("errorTryAgain").click();
+
+  ContentTask.spawn(gBrowser.selectedBrowser, null, function* () {
+    content.document.getElementById("errorTryAgain").click();
+  });
 }
 
 registerCleanupFunction(function() {
   Services.prefs.setBoolPref("browser.cache.disk.enable", true);
   Services.prefs.setBoolPref("browser.cache.memory.enable", true);
   Services.io.offline = false;
   gBrowser.removeCurrentTab();
 });
--- a/browser/base/content/test/general/browser_bug462289.js
+++ b/browser/base/content/test/general/browser_bug462289.js
@@ -12,63 +12,66 @@ function focus_in_navbar()
 function test()
 {
   waitForExplicitFinish();
 
   tab1 = gBrowser.addTab("about:blank", {skipAnimation: true});
   tab2 = gBrowser.addTab("about:blank", {skipAnimation: true});
 
   EventUtils.synthesizeMouseAtCenter(tab1, {});
-  setTimeout(step2, 0);
+  executeSoon(step2);
 }
 
 function step2()
 {
   is(gBrowser.selectedTab, tab1, "1st click on tab1 selects tab");
   isnot(document.activeElement, tab1, "1st click on tab1 does not activate tab");
 
   EventUtils.synthesizeMouseAtCenter(tab1, {});
-  setTimeout(step3, 0);
+  executeSoon(step3);
 }
 
 function step3()
 {
   is(gBrowser.selectedTab, tab1, "2nd click on selected tab1 keeps tab selected");
   isnot(document.activeElement, tab1, "2nd click on selected tab1 does not activate tab");
 
   ok(true, "focusing URLBar then sending 1 Shift+Tab.");
   gURLBar.focus();
   EventUtils.synthesizeKey("VK_TAB", {shiftKey: true});
   is(gBrowser.selectedTab, tab1, "tab key to selected tab1 keeps tab selected");
   is(document.activeElement, tab1, "tab key to selected tab1 activates tab");
 
   EventUtils.synthesizeMouseAtCenter(tab1, {});
-  setTimeout(step4, 0);
+  executeSoon(step4);
 }
 
 function step4()
 {
   is(gBrowser.selectedTab, tab1, "3rd click on activated tab1 keeps tab selected");
   is(document.activeElement, tab1, "3rd click on activated tab1 keeps tab activated");
 
+  gBrowser.addEventListener("TabSwitchDone", step5);
   EventUtils.synthesizeMouseAtCenter(tab2, {});
-  setTimeout(step5, 0);
 }
 
 function step5()
 {
+  gBrowser.removeEventListener("TabSwitchDone", step5);
+
   // The tabbox selects a tab within a setTimeout in a bubbling mousedown event
   // listener, and focuses the current tab if another tab previously had focus.
   is(gBrowser.selectedTab, tab2, "click on tab2 while tab1 is activated selects tab");
   is(document.activeElement, tab2, "click on tab2 while tab1 is activated activates tab");
 
-  ok(true, "focusing content then sending middle-button mousedown to tab2.");
+  info("focusing content then sending middle-button mousedown to tab2.");
   gBrowser.selectedBrowser.focus();
+
   EventUtils.synthesizeMouseAtCenter(tab2, {button: 1, type: "mousedown"});
-  setTimeout(step6, 0);
+  executeSoon(step6);
 }
 
 function step6()
 {
   is(gBrowser.selectedTab, tab2, "middle-button mousedown on selected tab2 keeps tab selected");
   isnot(document.activeElement, tab2, "middle-button mousedown on selected tab2 does not activate tab");
 
   gBrowser.removeTab(tab2);
--- a/browser/base/content/test/general/browser_fullscreen-window-open.js
+++ b/browser/base/content/test/general/browser_fullscreen-window-open.js
@@ -11,29 +11,25 @@ const TEST_FILE = "file_fullscreen-windo
 const gHttpTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/",
                                                           "http://127.0.0.1:8888/");
 
 function test () {
   waitForExplicitFinish();
 
   Services.prefs.setBoolPref(PREF_DISABLE_OPEN_NEW_WINDOW, true);
 
-  let newTab = gBrowser.addTab();
+  let newTab = gBrowser.addTab(gHttpTestRoot + TEST_FILE);
   gBrowser.selectedTab = newTab;
 
-  let gTestBrowser = gBrowser.selectedBrowser;
-  gTestBrowser.addEventListener("load", function onLoad(){
-    gTestBrowser.removeEventListener("load", onLoad, true, true);
-
+  whenTabLoaded(newTab, function () {
     // Enter browser fullscreen mode.
     BrowserFullScreen();
 
     runNextTest();
-  }, true, true);
-  gTestBrowser.contentWindow.location.href = gHttpTestRoot + TEST_FILE;
+  });
 }
 
 registerCleanupFunction(function(){
   // Exit browser fullscreen mode.
   BrowserFullScreen();
 
   gBrowser.removeCurrentTab();
 
@@ -197,30 +193,27 @@ function waitForTabOpen(aOptions) {
   }
 
   info("Running test: " + message.title);
 
   let onTabOpen = function onTabOpen(aEvent) {
     gBrowser.tabContainer.removeEventListener("TabOpen", onTabOpen, true);
 
     let tab = aEvent.target;
-    tab.linkedBrowser.addEventListener("load", function onLoad(ev){
-      let browser = ev.currentTarget;
-      browser.removeEventListener("load", onLoad, true, true);
-
-      is(browser.contentWindow.document.title, message.title,
+    whenTabLoaded(tab, function () {
+      is(tab.linkedBrowser.contentTitle, message.title,
          "Opened Tab is expected: " + message.title);
 
       if (aOptions.successFn) {
         aOptions.successFn();
       }
 
       gBrowser.removeTab(tab);
       finalize();
-    }, true, true);
+    });
   }
   gBrowser.tabContainer.addEventListener("TabOpen", onTabOpen, true);
 
   let finalize = function () {
     aOptions.finalizeFn();
     info("Finished: " + message.title);
     runNextTest();
   };
@@ -235,17 +228,17 @@ function waitForTabOpen(aOptions) {
     option: message.param,
   });
 }
 
 
 function waitForWindowOpen(aOptions) {
   let start = Date.now();
   let message = aOptions.message;
-  let url = aOptions.url || getBrowserURL();
+  let url = aOptions.url || "about:blank";
 
   if (!message.title) {
     ok(false, "Can't get message.title");
     aOptions.finalizeFn();
     runNextTest();
     return;
   }
 
@@ -253,43 +246,41 @@ function waitForWindowOpen(aOptions) {
 
   let onFinalize = function () {
     aOptions.finalizeFn();
 
     info("Finished: " + message.title);
     runNextTest();
   };
 
-  let listener = new WindowListener(message.title, url, {
+  let listener = new WindowListener(message.title, getBrowserURL(), {
     onSuccess: aOptions.successFn,
     onFinalize: onFinalize,
   });
   Services.wm.addListener(listener);
 
-  const URI = aOptions.url || "about:blank";
-
   executeWindowOpenInContent({
-    uri: URI,
+    uri: url,
     title: message.title,
     option: message.param,
   });
 }
 
 function executeWindowOpenInContent(aParam) {
-  var testWindow = gBrowser.selectedBrowser.contentWindow;
-  var testElm = testWindow.document.getElementById("test");
-
-  testElm.setAttribute("data-test-param", JSON.stringify(aParam));
-  EventUtils.synthesizeMouseAtCenter(testElm, {}, testWindow);
+  ContentTask.spawn(gBrowser.selectedBrowser, JSON.stringify(aParam), function* (dataTestParam) {
+    let testElm = content.document.getElementById("test");
+    testElm.setAttribute("data-test-param", dataTestParam);
+    testElm.click();
+  });
 }
 
 function waitForWindowOpenFromChrome(aOptions) {
   let start = Date.now();
   let message = aOptions.message;
-  let url = aOptions.url || getBrowserURL();
+  let url = aOptions.url || "about:blank";
 
   if (!message.title) {
     ok(false, "Can't get message.title");
     aOptions.finalizeFn();
     runNextTest();
     return;
   }
 
@@ -297,26 +288,23 @@ function waitForWindowOpenFromChrome(aOp
 
   let onFinalize = function () {
     aOptions.finalizeFn();
 
     info("Finished: " + message.title);
     runNextTest();
   };
 
-  let listener = new WindowListener(message.title, url, {
+  let listener = new WindowListener(message.title, getBrowserURL(), {
     onSuccess: aOptions.successFn,
     onFinalize: onFinalize,
   });
   Services.wm.addListener(listener);
 
-
-  const URI = aOptions.url || "about:blank";
-
-  let testWindow = window.open(URI, message.title, message.option);
+  let testWindow = window.open(url, message.title, message.option);
 }
 
 function WindowListener(aTitle, aUrl, aCallBackObj) {
   this.test_title = aTitle;
   this.test_url = aUrl;
   this.callback_onSuccess = aCallBackObj.onSuccess;
   this.callBack_onFinalize = aCallBackObj.onFinalize;
 }
--- a/browser/components/uitour/UITour.jsm
+++ b/browser/components/uitour/UITour.jsm
@@ -835,25 +835,25 @@ this.UITour = {
           return false;
         }
       }
     } catch (ex) {
       log.warn("_populateCampaignParams: extraURLCampaignParams is not a JSON object");
       return false;
     }
     if (campaignParams) {
-      // The regex that both the name and value of each param must match.
+      // The regex that the name of each param must match - there's no
+      // character restriction on the value - they will be escaped as necessary.
       let reSimpleString = /^[-_a-zA-Z0-9]*$/;
       for (let name in campaignParams) {
         let value = campaignParams[name];
         if (typeof name != "string" || typeof value != "string" ||
             !name.startsWith("utm_") ||
             value.length == 0 ||
-            !reSimpleString.test(name) ||
-            !reSimpleString.test(value)) {
+            !reSimpleString.test(name)) {
           log.warn("_populateCampaignParams: invalid campaign param specified");
           return false;
         }
         urlSearchParams.append(name, value);
       }
     }
     return true;
   },
--- a/browser/components/uitour/test/browser_UITour_sync.js
+++ b/browser/components/uitour/test/browser_UITour_sync.js
@@ -29,16 +29,28 @@ add_UITour_task(function* test_firefoxAc
 });
 
 add_UITour_task(function* test_firefoxAccountsValidParams() {
   yield gContentAPI.showFirefoxAccounts({ utm_foo: "foo", utm_bar: "bar" });
   yield BrowserTestUtils.browserLoaded(gTestTab.linkedBrowser, false,
                                        "about:accounts?action=signup&entrypoint=uitour&utm_foo=foo&utm_bar=bar");
 });
 
+add_UITour_task(function* test_firefoxAccountsNonAlphaValue() {
+  // All characters in the value are allowed, but they must be automatically escaped.
+  // (we throw a unicode character in there too - it's not auto-utf8 encoded,
+  // but that's ok, so long as it is escaped correctly.)
+  let value = "foo& /=?:\\\xa9";
+  // encodeURIComponent encodes spaces to %20 but we want "+"
+  let expected = encodeURIComponent(value).replace(/%20/g, "+");
+  yield gContentAPI.showFirefoxAccounts({ utm_foo: value });
+  yield BrowserTestUtils.browserLoaded(gTestTab.linkedBrowser, false,
+                                       "about:accounts?action=signup&entrypoint=uitour&utm_foo=" + expected);
+});
+
 // A helper to check the request was ignored due to invalid params.
 function* checkAboutAccountsNotLoaded() {
   try {
     yield waitForConditionPromise(() => {
       return gBrowser.selectedBrowser.currentURI.spec.startsWith("about:accounts");
     }, "Check if about:accounts opened");
     ok(false, "No about:accounts tab should have opened");
   } catch (ex) {
@@ -58,14 +70,8 @@ add_UITour_task(function* test_firefoxAc
   yield checkAboutAccountsNotLoaded();
 });
 
 add_UITour_task(function* test_firefoxAccountsNonAlphaName() {
   // Any "utm_" name which includes non-alpha chars should be rejected.
   yield gContentAPI.showFirefoxAccounts({ utm_foo: "foo", "utm_bar=": "bar" });
   yield checkAboutAccountsNotLoaded();
 });
-
-add_UITour_task(function* test_firefoxAccountsNonAlphaValue() {
-  // Any non-alpha value should be rejected.
-  yield gContentAPI.showFirefoxAccounts({ utm_foo: "foo&" });
-  yield checkAboutAccountsNotLoaded();
-});
--- a/browser/extensions/pdfjs/README.mozilla
+++ b/browser/extensions/pdfjs/README.mozilla
@@ -1,3 +1,3 @@
 This is the pdf.js project output, https://github.com/mozilla/pdf.js
 
-Current extension version is: 1.4.95
+Current extension version is: 1.4.121
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -23,18 +23,18 @@ define('pdfjs-dist/build/pdf', ['exports
     factory(exports);
   } else {
 factory((root.pdfjsDistBuildPdf = {}));
   }
 }(this, function (exports) {
   // Use strict in our context only - users might not want it
   'use strict';
 
-var pdfjsVersion = '1.4.95';
-var pdfjsBuild = '2b813c0';
+var pdfjsVersion = '1.4.121';
+var pdfjsBuild = '51f6aba';
 
   var pdfjsFilePath =
     typeof document !== 'undefined' && document.currentScript ?
       document.currentScript.src : null;
 
   var pdfjsLibs = {};
 
   (function pdfjsWrapper() {
@@ -685,16 +685,65 @@ function stringToBytes(str) {
   var length = str.length;
   var bytes = new Uint8Array(length);
   for (var i = 0; i < length; ++i) {
     bytes[i] = str.charCodeAt(i) & 0xFF;
   }
   return bytes;
 }
 
+/**
+ * Gets length of the array (Array, Uint8Array, or string) in bytes.
+ * @param {Array|Uint8Array|string} arr
+ * @returns {number}
+ */
+function arrayByteLength(arr) {
+  if (arr.length !== undefined) {
+    return arr.length;
+  }
+  assert(arr.byteLength !== undefined);
+  return arr.byteLength;
+}
+
+/**
+ * Combines array items (arrays) into single Uint8Array object.
+ * @param {Array} arr - the array of the arrays (Array, Uint8Array, or string).
+ * @returns {Uint8Array}
+ */
+function arraysToBytes(arr) {
+  // Shortcut: if first and only item is Uint8Array, return it.
+  if (arr.length === 1 && (arr[0] instanceof Uint8Array)) {
+    return arr[0];
+  }
+  var resultLength = 0;
+  var i, ii = arr.length;
+  var item, itemLength ;
+  for (i = 0; i < ii; i++) {
+    item = arr[i];
+    itemLength = arrayByteLength(item);
+    resultLength += itemLength;
+  }
+  var pos = 0;
+  var data = new Uint8Array(resultLength);
+  for (i = 0; i < ii; i++) {
+    item = arr[i];
+    if (!(item instanceof Uint8Array)) {
+      if (typeof item === 'string') {
+        item = stringToBytes(item);
+      } else {
+        item = new Uint8Array(item);
+      }
+    }
+    itemLength = item.byteLength;
+    data.set(item, pos);
+    pos += itemLength;
+  }
+  return data;
+}
+
 function string32(value) {
   return String.fromCharCode((value >> 24) & 0xff, (value >> 16) & 0xff,
                              (value >> 8) & 0xff, value & 0xff);
 }
 
 function log2(x) {
   var n = 1, i = 0;
   while (x > n) {
@@ -1537,16 +1586,18 @@ exports.PasswordException = PasswordExce
 exports.PasswordResponses = PasswordResponses;
 exports.StatTimer = StatTimer;
 exports.StreamType = StreamType;
 exports.TextRenderingMode = TextRenderingMode;
 exports.UnexpectedResponseException = UnexpectedResponseException;
 exports.UnknownErrorException = UnknownErrorException;
 exports.Util = Util;
 exports.XRefParseException = XRefParseException;
+exports.arrayByteLength = arrayByteLength;
+exports.arraysToBytes = arraysToBytes;
 exports.assert = assert;
 exports.bytesToString = bytesToString;
 exports.combineUrl = combineUrl;
 exports.createPromiseCapability = createPromiseCapability;
 exports.deprecated = deprecated;
 exports.error = error;
 exports.getFilenameFromUrl = getFilenameFromUrl;
 exports.getLookupTableFactory = getLookupTableFactory;
@@ -5276,25 +5327,29 @@ var CanvasGraphics = (function CanvasGra
             ctx.scale(characterScaleX, 1);
             scaledX /= characterScaleX;
           } else if (width !== measuredWidth) {
             scaledX += (width - measuredWidth) / 2000 *
               fontSize / fontSizeScale;
           }
         }
 
-        if (simpleFillText && !accent) {
-          // common case
-          ctx.fillText(character, scaledX, scaledY);
-        } else {
-          this.paintChar(character, scaledX, scaledY);
-          if (accent) {
-            scaledAccentX = scaledX + accent.offset.x / fontSizeScale;
-            scaledAccentY = scaledY - accent.offset.y / fontSizeScale;
-            this.paintChar(accent.fontChar, scaledAccentX, scaledAccentY);
+        // Only attempt to draw the glyph if it is actually in the embedded font
+        // file or if there isn't a font file so the fallback font is shown.
+        if (glyph.isInFont || font.missingFile) {
+          if (simpleFillText && !accent) {
+            // common case
+            ctx.fillText(character, scaledX, scaledY);
+          } else {
+            this.paintChar(character, scaledX, scaledY);
+            if (accent) {
+              scaledAccentX = scaledX + accent.offset.x / fontSizeScale;
+              scaledAccentY = scaledY - accent.offset.y / fontSizeScale;
+              this.paintChar(accent.fontChar, scaledAccentX, scaledAccentY);
+            }
           }
         }
 
         var charWidth = width * widthAdvanceScale + spacing * fontDirection;
         x += charWidth;
 
         if (restoreNeeded) {
           ctx.restore();
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js
+++ b/browser/extensions/pdfjs/content/build/pdf.worker.js
@@ -23,18 +23,18 @@ define('pdfjs-dist/build/pdf.worker', ['
     factory(exports);
   } else {
 factory((root.pdfjsDistBuildPdfWorker = {}));
   }
 }(this, function (exports) {
   // Use strict in our context only - users might not want it
   'use strict';
 
-var pdfjsVersion = '1.4.95';
-var pdfjsBuild = '2b813c0';
+var pdfjsVersion = '1.4.121';
+var pdfjsBuild = '51f6aba';
 
   var pdfjsFilePath =
     typeof document !== 'undefined' && document.currentScript ?
       document.currentScript.src : null;
 
   var pdfjsLibs = {};
 
   (function pdfjsWrapper() {
@@ -2644,16 +2644,65 @@ function stringToBytes(str) {
   var length = str.length;
   var bytes = new Uint8Array(length);
   for (var i = 0; i < length; ++i) {
     bytes[i] = str.charCodeAt(i) & 0xFF;
   }
   return bytes;
 }
 
+/**
+ * Gets length of the array (Array, Uint8Array, or string) in bytes.
+ * @param {Array|Uint8Array|string} arr
+ * @returns {number}
+ */
+function arrayByteLength(arr) {
+  if (arr.length !== undefined) {
+    return arr.length;
+  }
+  assert(arr.byteLength !== undefined);
+  return arr.byteLength;
+}
+
+/**
+ * Combines array items (arrays) into single Uint8Array object.
+ * @param {Array} arr - the array of the arrays (Array, Uint8Array, or string).
+ * @returns {Uint8Array}
+ */
+function arraysToBytes(arr) {
+  // Shortcut: if first and only item is Uint8Array, return it.
+  if (arr.length === 1 && (arr[0] instanceof Uint8Array)) {
+    return arr[0];
+  }
+  var resultLength = 0;
+  var i, ii = arr.length;
+  var item, itemLength ;
+  for (i = 0; i < ii; i++) {
+    item = arr[i];
+    itemLength = arrayByteLength(item);
+    resultLength += itemLength;
+  }
+  var pos = 0;
+  var data = new Uint8Array(resultLength);
+  for (i = 0; i < ii; i++) {
+    item = arr[i];
+    if (!(item instanceof Uint8Array)) {
+      if (typeof item === 'string') {
+        item = stringToBytes(item);
+      } else {
+        item = new Uint8Array(item);
+      }
+    }
+    itemLength = item.byteLength;
+    data.set(item, pos);
+    pos += itemLength;
+  }
+  return data;
+}
+
 function string32(value) {
   return String.fromCharCode((value >> 24) & 0xff, (value >> 16) & 0xff,
                              (value >> 8) & 0xff, value & 0xff);
 }
 
 function log2(x) {
   var n = 1, i = 0;
   while (x > n) {
@@ -3496,16 +3545,18 @@ exports.PasswordException = PasswordExce
 exports.PasswordResponses = PasswordResponses;
 exports.StatTimer = StatTimer;
 exports.StreamType = StreamType;
 exports.TextRenderingMode = TextRenderingMode;
 exports.UnexpectedResponseException = UnexpectedResponseException;
 exports.UnknownErrorException = UnknownErrorException;
 exports.Util = Util;
 exports.XRefParseException = XRefParseException;
+exports.arrayByteLength = arrayByteLength;
+exports.arraysToBytes = arraysToBytes;
 exports.assert = assert;
 exports.bytesToString = bytesToString;
 exports.combineUrl = combineUrl;
 exports.createPromiseCapability = createPromiseCapability;
 exports.deprecated = deprecated;
 exports.error = error;
 exports.getFilenameFromUrl = getFilenameFromUrl;
 exports.getLookupTableFactory = getLookupTableFactory;
@@ -3539,16 +3590,18 @@ exports.warn = warn;
 
 (function (root, factory) {
   {
     factory((root.pdfjsCoreChunkedStream = {}), root.pdfjsSharedUtil);
   }
 }(this, function (exports, sharedUtil) {
 
 var MissingDataException = sharedUtil.MissingDataException;
+var arrayByteLength = sharedUtil.arrayByteLength;
+var arraysToBytes = sharedUtil.arraysToBytes;
 var assert = sharedUtil.assert;
 var createPromiseCapability = sharedUtil.createPromiseCapability;
 var isInt = sharedUtil.isInt;
 var isEmptyObj = sharedUtil.isEmptyObj;
 
 var ChunkedStream = (function ChunkedStreamClosure() {
   function ChunkedStream(length, chunkSize, manager) {
     this.bytes = new Uint8Array(length);
@@ -3790,67 +3843,81 @@ var ChunkedStream = (function ChunkedStr
     isStream: true
   };
 
   return ChunkedStream;
 })();
 
 var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
 
-  function ChunkedStreamManager(length, chunkSize, url, args) {
+  function ChunkedStreamManager(pdfNetworkStream, args) {
+    var chunkSize = args.rangeChunkSize;
+    var length = args.length;
     this.stream = new ChunkedStream(length, chunkSize, this);
     this.length = length;
     this.chunkSize = chunkSize;
-    this.url = url;
+    this.pdfNetworkStream = pdfNetworkStream;
+    this.url = args.url;
     this.disableAutoFetch = args.disableAutoFetch;
-    var msgHandler = this.msgHandler = args.msgHandler;
-
-    if (args.chunkedViewerLoading) {
-      msgHandler.on('OnDataRange', this.onReceiveData.bind(this));
-      msgHandler.on('OnDataProgress', this.onProgress.bind(this));
-      this.sendRequest = function ChunkedStreamManager_sendRequest(begin, end) {
-        msgHandler.send('RequestDataRange', { begin: begin, end: end });
-      };
-    } else {
-
-      var getXhr = function getXhr() {
-        return new XMLHttpRequest();
-      };
-      this.networkManager = new NetworkManager(this.url, {
-        getXhr: getXhr,
-        httpHeaders: args.httpHeaders,
-        withCredentials: args.withCredentials
-      });
-      this.sendRequest = function ChunkedStreamManager_sendRequest(begin, end) {
-        this.networkManager.requestRange(begin, end, {
-          onDone: this.onReceiveData.bind(this),
-          onProgress: this.onProgress.bind(this)
-        });
-      };
-    }
+    this.msgHandler = args.msgHandler;
 
     this.currRequestId = 0;
 
     this.chunksNeededByRequest = Object.create(null);
     this.requestsByChunk = Object.create(null);
     this.promisesByRequest = Object.create(null);
     this.progressiveDataLength = 0;
+    this.aborted = false;
 
     this._loadedStreamCapability = createPromiseCapability();
-
-    if (args.initialData) {
-      this.onReceiveData({chunk: args.initialData});
-    }
   }
 
   ChunkedStreamManager.prototype = {
     onLoadedStream: function ChunkedStreamManager_getLoadedStream() {
       return this._loadedStreamCapability.promise;
     },
 
+    sendRequest: function ChunkedStreamManager_sendRequest(begin, end) {
+      var rangeReader = this.pdfNetworkStream.getRangeReader(begin, end);
+      if (!rangeReader.isStreamingSupported) {
+        rangeReader.onProgress = this.onProgress.bind(this);
+      }
+      var chunks = [], loaded = 0;
+      var manager = this;
+      var promise = new Promise(function (resolve, reject) {
+        var readChunk = function (chunk) {
+          try {
+            if (!chunk.done) {
+              var data = chunk.value;
+              chunks.push(data);
+              loaded += arrayByteLength(data);
+              if (rangeReader.isStreamingSupported) {
+                manager.onProgress({loaded: loaded});
+              }
+              rangeReader.read().then(readChunk, reject);
+              return;
+            }
+            var chunkData = arraysToBytes(chunks);
+            chunks = null;
+            resolve(chunkData);
+          } catch (e) {
+            reject(e);
+          }
+        };
+        rangeReader.read().then(readChunk, reject);
+      });
+      promise.then(function (data) {
+        if (this.aborted) {
+          return; // ignoring any data after abort
+        }
+        this.onReceiveData({chunk: data, begin: begin});
+      }.bind(this));
+      // TODO check errors
+    },
+
     // Get all the chunks that are not yet loaded and groups them into
     // contiguous ranges to load in as few requests as possible
     requestAllChunks: function ChunkedStreamManager_requestAllChunks() {
       var missingChunks = this.stream.getMissingChunks();
       this._requestChunks(missingChunks);
       return this._loadedStreamCapability.promise;
     },
 
@@ -4060,18 +4127,19 @@ var ChunkedStreamManager = (function Chu
     },
 
     getEndChunk: function ChunkedStreamManager_getEndChunk(end) {
       var chunk = Math.floor((end - 1) / this.chunkSize) + 1;
       return chunk;
     },
 
     abort: function ChunkedStreamManager_abort() {
-      if (this.networkManager) {
-        this.networkManager.abortAllRequests();
+      this.aborted = true;
+      if (this.pdfNetworkStream) {
+        this.pdfNetworkStream.cancelAllRequests('abort');
       }
       for(var requestId in this.promisesByRequest) {
         var capability = this.promisesByRequest[requestId];
         capability.reject(new Error('Request was aborted'));
       }
     }
   };
 
@@ -24933,35 +25001,38 @@ function getFontType(type, subtype) {
       return FontType.TYPE0;
     default:
       return FontType.UNKNOWN;
   }
 }
 
 var Glyph = (function GlyphClosure() {
   function Glyph(fontChar, unicode, accent, width, vmetric, operatorListId,
-                 isSpace) {
+                 isSpace, isInFont) {
     this.fontChar = fontChar;
     this.unicode = unicode;
     this.accent = accent;
     this.width = width;
     this.vmetric = vmetric;
     this.operatorListId = operatorListId;
     this.isSpace = isSpace;
+    this.isInFont = isInFont;
   }
 
   Glyph.prototype.matchesForCache = function(fontChar, unicode, accent, width,
-                                             vmetric, operatorListId, isSpace) {
+                                             vmetric, operatorListId, isSpace,
+                                             isInFont) {
     return this.fontChar === fontChar &&
            this.unicode === unicode &&
            this.accent === accent &&
            this.width === width &&
            this.vmetric === vmetric &&
            this.operatorListId === operatorListId &&
-           this.isSpace === isSpace;
+           this.isSpace === isSpace &&
+           this.isInFont === isInFont;
   };
 
   return Glyph;
 })();
 
 var ToUnicodeMap = (function ToUnicodeMapClosure() {
   function ToUnicodeMap(cmap) {
     // The elements of this._map can be integers or strings, depending on how
@@ -25210,16 +25281,17 @@ var ProblematicCharRanges = new Int32Arr
 var Font = (function FontClosure() {
   function Font(name, file, properties) {
     var charCode, glyphName, fontChar;
 
     this.name = name;
     this.loadedName = properties.loadedName;
     this.isType3Font = properties.isType3Font;
     this.sizes = [];
+    this.missingFile = false;
 
     this.glyphCache = Object.create(null);
 
     var names = name.split('+');
     names = names.length > 1 ? names[1] : names[0];
     names = names.split(/[-,_]/g)[0];
     this.isSerifFont = !!(properties.flags & FontFlags.Serif);
     this.isSymbolicFont = !!(properties.flags & FontFlags.Symbolic);
@@ -26574,16 +26646,19 @@ var Font = (function FontClosure() {
           // using only Macintosh and Windows platform/encoding names
           if ((r.platform === 1 && r.encoding === 0 && r.language === 0) ||
               (r.platform === 3 && r.encoding === 1 && r.language === 0x409)) {
             records.push(r);
           }
         }
         for (i = 0, ii = records.length; i < ii; i++) {
           var record = records[i];
+          if (record.length <= 0) {
+            continue; // Nothing to process, ignoring.
+          }
           var pos = start + stringsStart + record.offset;
           if (pos + record.length > end) {
             continue; // outside of name table, ignoring
           }
           font.pos = pos;
           var nameIndex = record.name;
           if (record.encoding) {
             // unicode
@@ -27021,17 +27096,17 @@ var Font = (function FontClosure() {
       if (properties.type === 'CIDFontType2') {
         var cidToGidMap = properties.cidToGidMap || [];
         var isCidToGidMapEmpty = cidToGidMap.length === 0;
 
         properties.cMap.forEach(function(charCode, cid) {
           assert(cid <= 0xffff, 'Max size of CID is 65,535');
           var glyphId = -1;
           if (isCidToGidMapEmpty) {
-            glyphId = charCode;
+            glyphId = cid;
           } else if (cidToGidMap[cid] !== undefined) {
             glyphId = cidToGidMap[cid];
           }
 
           if (glyphId >= 0 && glyphId < numGlyphs &&
               hasGlyph(glyphId, charCode, cid)) {
             charCodeToGlyphId[charCode] = glyphId;
           }
@@ -27549,46 +27624,48 @@ var Font = (function FontClosure() {
       width = isNum(width) ? width : this.defaultWidth;
       var vmetric = this.vmetrics && this.vmetrics[widthCode];
 
       var unicode = this.toUnicode.get(charcode) || charcode;
       if (typeof unicode === 'number') {
         unicode = String.fromCharCode(unicode);
       }
 
+      var isInFont = charcode in this.toFontChar;
       // First try the toFontChar map, if it's not there then try falling
       // back to the char code.
       fontCharCode = this.toFontChar[charcode] || charcode;
       if (this.missingFile) {
         fontCharCode = mapSpecialUnicodeValues(fontCharCode);
       }
 
       if (this.isType3Font) {
         // Font char code in this case is actually a glyph name.
         operatorListId = fontCharCode;
       }
 
       var accent = null;
       if (this.seacMap && this.seacMap[charcode]) {
+        isInFont = true;
         var seac = this.seacMap[charcode];
         fontCharCode = seac.baseFontCharCode;
         accent = {
           fontChar: String.fromCharCode(seac.accentFontCharCode),
           offset: seac.accentOffset
         };
       }
 
       var fontChar = String.fromCharCode(fontCharCode);
 
       var glyph = this.glyphCache[charcode];
       if (!glyph ||
           !glyph.matchesForCache(fontChar, unicode, accent, width, vmetric,
-                                 operatorListId, isSpace)) {
+                                 operatorListId, isSpace, isInFont)) {
         glyph = new Glyph(fontChar, unicode, accent, width, vmetric,
-                          operatorListId, isSpace);
+                          operatorListId, isSpace, isInFont);
         this.glyphCache[charcode] = glyph;
       }
       return glyph;
     },
 
     charsToGlyphs: function Font_charsToGlyphs(chars) {
       var charsCache = this.charsCache;
       var glyphs, glyph, charcode;
@@ -40357,31 +40434,28 @@ var LocalPdfManager = (function LocalPdf
       return;
     }
   });
 
   return LocalPdfManager;
 })();
 
 var NetworkPdfManager = (function NetworkPdfManagerClosure() {
-  function NetworkPdfManager(docId, args, msgHandler) {
+  function NetworkPdfManager(docId, pdfNetworkStream, args) {
     this._docId = docId;
-    this.msgHandler = msgHandler;
+    this.msgHandler = args.msgHandler;
 
     var params = {
-      msgHandler: msgHandler,
-      httpHeaders: args.httpHeaders,
-      withCredentials: args.withCredentials,
-      chunkedViewerLoading: args.chunkedViewerLoading,
+      msgHandler: args.msgHandler,
+      url: args.url,
+      length: args.length,
       disableAutoFetch: args.disableAutoFetch,
-      initialData: args.initialData
+      rangeChunkSize: args.rangeChunkSize
     };
-    this.streamManager = new ChunkedStreamManager(args.length,
-                                                  args.rangeChunkSize,
-                                                  args.url, params);
+    this.streamManager = new ChunkedStreamManager(pdfNetworkStream, params);
     this.pdfDocument = new PDFDocument(this, this.streamManager.getStream(),
                                        args.password);
   }
 
   Util.inherit(NetworkPdfManager, BasePdfManager, {
     ensure: function NetworkPdfManager_ensure(obj, prop, args) {
       var pdfManager = this;
 
@@ -40453,20 +40527,22 @@ var UNSUPPORTED_FEATURES = sharedUtil.UN
 var InvalidPDFException = sharedUtil.InvalidPDFException;
 var MessageHandler = sharedUtil.MessageHandler;
 var MissingPDFException = sharedUtil.MissingPDFException;
 var UnexpectedResponseException = sharedUtil.UnexpectedResponseException;
 var PasswordException = sharedUtil.PasswordException;
 var PasswordResponses = sharedUtil.PasswordResponses;
 var UnknownErrorException = sharedUtil.UnknownErrorException;
 var XRefParseException = sharedUtil.XRefParseException;
+var arrayByteLength = sharedUtil.arrayByteLength;
+var arraysToBytes = sharedUtil.arraysToBytes;
+var assert = sharedUtil.assert;
 var createPromiseCapability = sharedUtil.createPromiseCapability;
 var error = sharedUtil.error;
 var info = sharedUtil.info;
-var isInt = sharedUtil.isInt;
 var warn = sharedUtil.warn;
 var Ref = corePrimitives.Ref;
 var LocalPdfManager = corePdfManager.LocalPdfManager;
 var NetworkPdfManager = corePdfManager.NetworkPdfManager;
 var globalScope = sharedGlobal.globalScope;
 var PDFJS = sharedGlobal.PDFJS;
 
 var WorkerTask = (function WorkerTaskClosure() {
@@ -40494,16 +40570,231 @@ var WorkerTask = (function WorkerTaskClo
         throw new Error('Worker task was terminated');
       }
     }
   };
 
   return WorkerTask;
 })();
 
+
+/** @implements {IPDFStream} */
+var PDFWorkerStream = (function PDFWorkerStreamClosure() {
+  function PDFWorkerStream(params, msgHandler) {
+    this._queuedChunks = [];
+    var initialData = params.initialData;
+    if (initialData && initialData.length > 0) {
+      this._queuedChunks.push(initialData);
+    }
+    this._msgHandler = msgHandler;
+
+    this._isRangeSupported = !(params.disableRange);
+    this._isStreamingSupported = !(params.disableStream);
+    this._contentLength = params.length;
+
+    this._fullRequestReader = null;
+    this._rangeReaders = [];
+
+    msgHandler.on('OnDataRange', this._onReceiveData.bind(this));
+    msgHandler.on('OnDataProgress', this._onProgress.bind(this));
+  }
+  PDFWorkerStream.prototype = {
+    _onReceiveData: function PDFWorkerStream_onReceiveData(args) {
+       if (args.begin === undefined) {
+         if (this._fullRequestReader) {
+           this._fullRequestReader._enqueue(args.chunk);
+         } else {
+           this._queuedChunks.push(args.chunk);
+         }
+       } else {
+         var found = this._rangeReaders.some(function (rangeReader) {
+           if (rangeReader._begin !== args.begin) {
+             return false;
+           }
+           rangeReader._enqueue(args.chunk);
+           return true;
+         });
+         assert(found);
+       }
+    },
+
+    _onProgress: function PDFWorkerStream_onProgress(evt) {
+       if (this._rangeReaders.length > 0) {
+         // Reporting to first range reader.
+         var firstReader = this._rangeReaders[0];
+         if (firstReader.onProgress) {
+           firstReader.onProgress({loaded: evt.loaded});
+         }
+       }
+    },
+
+    _removeRangeReader: function PDFWorkerStream_removeRangeReader(reader) {
+      var i = this._rangeReaders.indexOf(reader);
+      if (i >= 0) {
+        this._rangeReaders.splice(i, 1);
+      }
+    },
+
+    getFullReader: function PDFWorkerStream_getFullReader() {
+      assert(!this._fullRequestReader);
+      var queuedChunks = this._queuedChunks;
+      this._queuedChunks = null;
+      return new PDFWorkerStreamReader(this, queuedChunks);
+    },
+
+    getRangeReader: function PDFWorkerStream_getRangeReader(begin, end) {
+      var reader = new PDFWorkerStreamRangeReader(this, begin, end);
+      this._msgHandler.send('RequestDataRange', { begin: begin, end: end });
+      this._rangeReaders.push(reader);
+      return reader;
+    },
+
+    cancelAllRequests: function PDFWorkerStream_cancelAllRequests(reason) {
+      if (this._fullRequestReader) {
+        this._fullRequestReader.cancel(reason);
+      }
+      var readers = this._rangeReaders.slice(0);
+      readers.forEach(function (rangeReader) {
+        rangeReader.cancel(reason);
+      });
+    }
+  };
+
+  /** @implements {IPDFStreamReader} */
+  function PDFWorkerStreamReader(stream, queuedChunks) {
+    this._stream = stream;
+    this._done = false;
+    this._queuedChunks = queuedChunks || [];
+    this._requests = [];
+    this._headersReady = Promise.resolve();
+    stream._fullRequestReader = this;
+
+    this.onProgress = null; // not used
+  }
+  PDFWorkerStreamReader.prototype = {
+    _enqueue: function PDFWorkerStreamReader_enqueue(chunk) {
+      if (this._done) {
+        return; // ignore new data
+      }
+      if (this._requests.length > 0) {
+        var requestCapability = this._requests.shift();
+        requestCapability.resolve({value: chunk, done: false});
+        return;
+      }
+      this._queuedChunks.push(chunk);
+    },
+
+    get headersReady() {
+      return this._headersReady;
+    },
+
+    get isRangeSupported() {
+      return this._stream._isRangeSupported;
+    },
+
+    get isStreamingSupported() {
+      return this._stream._isStreamingSupported;
+    },
+
+    get contentLength() {
+      return this._stream._contentLength;
+    },
+
+    read: function PDFWorkerStreamReader_read() {
+      if (this._queuedChunks.length > 0) {
+        var chunk = this._queuedChunks.shift();
+        return Promise.resolve({value: chunk, done: false});
+      }
+      if (this._done) {
+        return Promise.resolve({value: undefined, done: true});
+      }
+      var requestCapability = createPromiseCapability();
+      this._requests.push(requestCapability);
+      return requestCapability.promise;
+    },
+
+    cancel: function PDFWorkerStreamReader_cancel(reason) {
+      this._done = true;
+      this._requests.forEach(function (requestCapability) {
+        requestCapability.resolve({value: undefined, done: true});
+      });
+      this._requests = [];
+    }
+  };
+
+  /** @implements {IPDFStreamRangeReader} */
+  function PDFWorkerStreamRangeReader(stream, begin, end) {
+    this._stream = stream;
+    this._begin = begin;
+    this._end = end;
+    this._queuedChunk = null;
+    this._requests = [];
+    this._done = false;
+
+    this.onProgress = null;
+  }
+  PDFWorkerStreamRangeReader.prototype = {
+    _enqueue: function PDFWorkerStreamRangeReader_enqueue(chunk) {
+      if (this._done) {
+        return; // ignore new data
+      }
+      if (this._requests.length === 0) {
+        this._queuedChunk = chunk;
+      } else {
+        var requestsCapability = this._requests.shift();
+        requestsCapability.resolve({value: chunk, done: false});
+        this._requests.forEach(function (requestCapability) {
+          requestCapability.resolve({value: undefined, done: true});
+        });
+        this._requests = [];
+      }
+      this._done = true;
+      this._stream._removeRangeReader(this);
+    },
+
+    get isStreamingSupported() {
+      return false;
+    },
+
+    read: function PDFWorkerStreamRangeReader_read() {
+      if (this._queuedChunk) {
+        return Promise.resolve({value: this._queuedChunk, done: false});
+      }
+      if (this._done) {
+        return Promise.resolve({value: undefined, done: true});
+      }
+      var requestCapability = createPromiseCapability();
+      this._requests.push(requestCapability);
+      return requestCapability.promise;
+    },
+
+    cancel: function PDFWorkerStreamRangeReader_cancel(reason) {
+      this._done = true;
+      this._requests.forEach(function (requestCapability) {
+        requestCapability.resolve({value: undefined, done: true});
+      });
+      this._requests = [];
+      this._stream._removeRangeReader(this);
+    }
+  };
+
+  return PDFWorkerStream;
+})();
+
+/** @type IPDFStream */
+var PDFNetworkStream;
+
+/**
+ * Sets PDFNetworkStream class to be used as alternative PDF data transport.
+ * @param {IPDFStream} cls - the PDF data transport.
+ */
+function setPDFNetworkStreamClass(cls) {
+  PDFNetworkStream = cls;
+}
+
 var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
   setup: function wphSetup(handler, port) {
     var testMessageProcessed = false;
     handler.on('test', function wphSetupTest(data) {
       if (testMessageProcessed) {
         return; // we already processed 'test' message once
       }
       testMessageProcessed = true;
@@ -40600,162 +40891,131 @@ var WorkerMessageHandler = PDFJS.WorkerM
       return loadDocumentCapability.promise;
     }
 
     function getPdfManager(data) {
       var pdfManagerCapability = createPromiseCapability();
       var pdfManager;
 
       var source = data.source;
-      var disableRange = data.disableRange;
       if (source.data) {
         try {
           pdfManager = new LocalPdfManager(docId, source.data, source.password);
           pdfManagerCapability.resolve(pdfManager);
         } catch (ex) {
           pdfManagerCapability.reject(ex);
         }
         return pdfManagerCapability.promise;
-      } else if (source.chunkedViewerLoading) {
+      }
+
+      var pdfStream;
+      try {
+        if (source.chunkedViewerLoading) {
+          pdfStream = new PDFWorkerStream(source, handler);
+        } else {
+          assert(PDFNetworkStream, 'pdfjs/core/network module is not loaded');
+          pdfStream = new PDFNetworkStream(data);
+        }
+      } catch (ex) {
+        pdfManagerCapability.reject(ex);
+        return pdfManagerCapability.promise;
+      }
+
+      var fullRequest = pdfStream.getFullReader();
+      fullRequest.headersReady.then(function () {
+        if (!fullRequest.isStreamingSupported ||
+            !fullRequest.isRangeSupported) {
+          // If stream or range are disabled, it's our only way to report
+          // loading progress.
+          fullRequest.onProgress = function (evt) {
+            handler.send('DocProgress', {
+              loaded: evt.loaded,
+              total: evt.total
+            });
+          };
+        }
+
+        if (!fullRequest.isRangeSupported) {
+          return;
+        }
+
+        // We don't need auto-fetch when streaming is enabled.
+        var disableAutoFetch = source.disableAutoFetch ||
+                               fullRequest.isStreamingSupported;
+        pdfManager = new NetworkPdfManager(docId, pdfStream, {
+          msgHandler: handler,
+          url: source.url,
+          password: source.password,
+          length: fullRequest.contentLength,
+          disableAutoFetch: disableAutoFetch,
+          rangeChunkSize: source.rangeChunkSize
+        });
+        pdfManagerCapability.resolve(pdfManager);
+        cancelXHRs = null;
+      }).catch(function (reason) {
+        pdfManagerCapability.reject(reason);
+        cancelXHRs = null;
+      });
+
+      var cachedChunks = [], loaded = 0;
+      var flushChunks = function () {
+        var pdfFile = arraysToBytes(cachedChunks);
+        if (source.length && pdfFile.length !== source.length) {
+          warn('reported HTTP length is different from actual');
+        }
+        // the data is array, instantiating directly from it
         try {
-          pdfManager = new NetworkPdfManager(docId, source, handler);
+          pdfManager = new LocalPdfManager(docId, pdfFile, source.password);
           pdfManagerCapability.resolve(pdfManager);
         } catch (ex) {
           pdfManagerCapability.reject(ex);
         }
-        return pdfManagerCapability.promise;
-      }
-
-      var networkManager = new NetworkManager(source.url, {
-        httpHeaders: source.httpHeaders,
-        withCredentials: source.withCredentials
-      });
-      var cachedChunks = [];
-      var fullRequestXhrId = networkManager.requestFull({
-        onHeadersReceived: function onHeadersReceived() {
-          if (disableRange) {
-            return;
-          }
-
-          var fullRequestXhr = networkManager.getRequestXhr(fullRequestXhrId);
-          if (fullRequestXhr.getResponseHeader('Accept-Ranges') !== 'bytes') {
-            return;
-          }
-
-          var contentEncoding =
-            fullRequestXhr.getResponseHeader('Content-Encoding') || 'identity';
-          if (contentEncoding !== 'identity') {
-            return;
-          }
-
-          var length = fullRequestXhr.getResponseHeader('Content-Length');
-          length = parseInt(length, 10);
-          if (!isInt(length)) {
-            return;
-          }
-          source.length = length;
-          if (length <= 2 * source.rangeChunkSize) {
-            // The file size is smaller than the size of two chunks, so it does
-            // not make any sense to abort the request and retry with a range
-            // request.
-            return;
-          }
-
-          if (networkManager.isStreamingRequest(fullRequestXhrId)) {
-            // We can continue fetching when progressive loading is enabled,
-            // and we don't need the autoFetch feature.
-            source.disableAutoFetch = true;
-          } else {
-            // NOTE: by cancelling the full request, and then issuing range
-            // requests, there will be an issue for sites where you can only
-            // request the pdf once. However, if this is the case, then the
-            // server should not be returning that it can support range
-            // requests.
-            networkManager.abortRequest(fullRequestXhrId);
-          }
-
+        cachedChunks = [];
+      };
+      var readPromise = new Promise(function (resolve, reject) {
+        var readChunk = function (chunk) {
           try {
-            pdfManager = new NetworkPdfManager(docId, source, handler);
-            pdfManagerCapability.resolve(pdfManager);
-          } catch (ex) {
-            pdfManagerCapability.reject(ex);
-          }
-          cancelXHRs = null;
-        },
-
-        onProgressiveData: source.disableStream ? null :
-            function onProgressiveData(chunk) {
-          if (!pdfManager) {
-            cachedChunks.push(chunk);
-            return;
-          }
-          pdfManager.sendProgressiveData(chunk);
-        },
-
-        onDone: function onDone(args) {
-          if (pdfManager) {
-            return; // already processed
-          }
-
-          var pdfFile;
-          if (args === null) {
-            // TODO add some streaming manager, e.g. for unknown length files.
-            // The data was returned in the onProgressiveData, combining...
-            var pdfFileLength = 0, pos = 0;
-            cachedChunks.forEach(function (chunk) {
-              pdfFileLength += chunk.byteLength;
-            });
-            if (source.length && pdfFileLength !== source.length) {
-              warn('reported HTTP length is different from actual');
-            }
-            var pdfFileArray = new Uint8Array(pdfFileLength);
-            cachedChunks.forEach(function (chunk) {
-              pdfFileArray.set(new Uint8Array(chunk), pos);
-              pos += chunk.byteLength;
-            });
-            pdfFile = pdfFileArray.buffer;
-          } else {
-            pdfFile = args.chunk;
-          }
-
-          // the data is array, instantiating directly from it
-          try {
-            pdfManager = new LocalPdfManager(docId, pdfFile, source.password);
-            pdfManagerCapability.resolve(pdfManager);
-          } catch (ex) {
-            pdfManagerCapability.reject(ex);
-          }
-          cancelXHRs = null;
-        },
-
-        onError: function onError(status) {
-          var exception;
-          if (status === 404 || status === 0 && /^file:/.test(source.url)) {
-            exception = new MissingPDFException('Missing PDF "' +
-                                                source.url + '".');
-            handler.send('MissingPDF', exception);
-          } else {
-            exception = new UnexpectedResponseException(
-              'Unexpected server response (' + status +
-              ') while retrieving PDF "' + source.url + '".', status);
-            handler.send('UnexpectedResponse', exception);
-          }
-          cancelXHRs = null;
-        },
-
-        onProgress: function onProgress(evt) {
-          handler.send('DocProgress', {
-            loaded: evt.loaded,
-            total: evt.lengthComputable ? evt.total : source.length
-          });
-        }
+            ensureNotTerminated();
+            if (chunk.done) {
+              if (!pdfManager) {
+                flushChunks();
+              }
+              cancelXHRs = null;
+              return;
+            }
+
+            var data = chunk.value;
+            loaded += arrayByteLength(data);
+            if (!fullRequest.isStreamingSupported) {
+              handler.send('DocProgress', {
+                loaded: loaded,
+                total: Math.max(loaded, fullRequest.contentLength || 0)
+              });
+            }
+
+            if (pdfManager) {
+              pdfManager.sendProgressiveData(data);
+            } else {
+              cachedChunks.push(data);
+            }
+
+            fullRequest.read().then(readChunk, reject);
+          } catch (e) {
+            reject(e);
+          }
+        };
+        fullRequest.read().then(readChunk, reject);
+      });
+      readPromise.catch(function (e) {
+        pdfManagerCapability.reject(e);
+        cancelXHRs = null;
       });
 
       cancelXHRs = function () {
-        networkManager.abortRequest(fullRequestXhrId);
+        pdfStream.cancelAllRequests('abort');
       };
 
       return pdfManagerCapability.promise;
     }
 
     var setupDoc = function(data) {
       var onSuccess = function(doc) {
         ensureNotTerminated();
@@ -41048,16 +41308,17 @@ function initializeWorker() {
 }
 
 // Worker thread (and not node.js)?
 if (typeof window === 'undefined' &&
     !(typeof module !== 'undefined' && module.require)) {
   initializeWorker();
 }
 
+exports.setPDFNetworkStreamClass = setPDFNetworkStreamClass;
 exports.WorkerTask = WorkerTask;
 exports.WorkerMessageHandler = WorkerMessageHandler;
 }));
 
 
   }).call(pdfjsLibs);
 
   exports.PDFJS = pdfjsLibs.pdfjsSharedGlobal.PDFJS;
--- a/browser/extensions/pdfjs/content/web/viewer.js
+++ b/browser/extensions/pdfjs/content/web/viewer.js
@@ -10,19 +10,19 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 /* globals PDFJS, PDFBug, FirefoxCom, Stats, ProgressBar, DownloadManager,
            getPDFFileNameFromURL, PDFHistory, Preferences, SidebarView,
            ViewHistory, Stats, PDFThumbnailViewer, URL, noContextMenuHandler,
-           SecondaryToolbar, PasswordPrompt, PDFPresentationMode,
+           SecondaryToolbar, PasswordPrompt, PDFPresentationMode, PDFSidebar,
            PDFDocumentProperties, HandTool, Promise, PDFLinkService,
-           PDFOutlineView, PDFAttachmentView, OverlayManager,
+           PDFOutlineViewer, PDFAttachmentViewer, OverlayManager,
            PDFFindController, PDFFindBar, PDFViewer, PDFRenderingQueue,
            PresentationModeState, parseQueryString, RenderingStates,
            UNKNOWN_SCALE, DEFAULT_SCALE_VALUE,
            IGNORE_CURRENT_POSITION_ON_ZOOM: true */
 
 'use strict';
 
 var DEFAULT_URL = 'compressed.tracemonkey-pldi-09.pdf';
@@ -444,23 +444,16 @@ var DEFAULT_PREFERENCES = {
   disableAutoFetch: false,
   disableFontFace: false,
   disableTextLayer: false,
   useOnlyCssZoom: false,
   externalLinkTarget: 0,
 };
 
 
-var SidebarView = {
-  NONE: 0,
-  THUMBS: 1,
-  OUTLINE: 2,
-  ATTACHMENTS: 3
-};
-
 /**
  * Preferences - Utility for storing persistent settings.
  *   Used for settings that should be applied to all opened documents,
  *   or every time the viewer is loaded.
  */
 var Preferences = {
   prefs: Object.create(DEFAULT_PREFERENCES),
   isInitializedPromiseResolved: false,
@@ -868,16 +861,20 @@ var PDFFindBar = (function PDFFindBarClo
     });
 
     this.caseSensitive.addEventListener('click', function() {
       self.dispatchEvent('casesensitivitychange');
     });
   }
 
   PDFFindBar.prototype = {
+    reset: function PDFFindBar_reset() {
+      this.updateUIState();
+    },
+
     dispatchEvent: function PDFFindBar_dispatchEvent(type, findPrev) {
       var event = document.createEvent('CustomEvent');
       event.initCustomEvent('find' + type, true, true, {
         query: this.findField.value,
         caseSensitive: this.caseSensitive.checked,
         highlightAll: this.highlightAll.checked,
         findPrevious: findPrev
       });
@@ -981,95 +978,94 @@ var FindStates = {
   FIND_NOTFOUND: 1,
   FIND_WRAPPED: 2,
   FIND_PENDING: 3
 };
 
 var FIND_SCROLL_OFFSET_TOP = -50;
 var FIND_SCROLL_OFFSET_LEFT = -400;
 
+var CHARACTERS_TO_NORMALIZE = {
+  '\u2018': '\'', // Left single quotation mark
+  '\u2019': '\'', // Right single quotation mark
+  '\u201A': '\'', // Single low-9 quotation mark
+  '\u201B': '\'', // Single high-reversed-9 quotation mark
+  '\u201C': '"', // Left double quotation mark
+  '\u201D': '"', // Right double quotation mark
+  '\u201E': '"', // Double low-9 quotation mark
+  '\u201F': '"', // Double high-reversed-9 quotation mark
+  '\u00BC': '1/4', // Vulgar fraction one quarter
+  '\u00BD': '1/2', // Vulgar fraction one half
+  '\u00BE': '3/4', // Vulgar fraction three quarters
+};
+
 /**
  * Provides "search" or "find" functionality for the PDF.
  * This object actually performs the search for a given string.
  */
 var PDFFindController = (function PDFFindControllerClosure() {
   function PDFFindController(options) {
-    this.startedTextExtraction = false;
-    this.extractTextPromises = [];
-    this.pendingFindMatches = Object.create(null);
-    this.active = false; // If active, find results will be highlighted.
-    this.pageContents = []; // Stores the text for each page.
-    this.pageMatches = [];
-    this.matchCount = 0;
-    this.selected = { // Currently selected match.
-      pageIdx: -1,
-      matchIdx: -1
-    };
-    this.offset = { // Where the find algorithm currently is in the document.
-      pageIdx: null,
-      matchIdx: null
-    };
-    this.pagesToSearch = null;
-    this.resumePageIdx = null;
-    this.state = null;
-    this.dirtyMatch = false;
-    this.findTimeout = null;
     this.pdfViewer = options.pdfViewer || null;
     this.integratedFind = options.integratedFind || false;
-    this.charactersToNormalize = {
-      '\u2018': '\'', // Left single quotation mark
-      '\u2019': '\'', // Right single quotation mark
-      '\u201A': '\'', // Single low-9 quotation mark
-      '\u201B': '\'', // Single high-reversed-9 quotation mark
-      '\u201C': '"', // Left double quotation mark
-      '\u201D': '"', // Right double quotation mark
-      '\u201E': '"', // Double low-9 quotation mark
-      '\u201F': '"', // Double high-reversed-9 quotation mark
-      '\u00BC': '1/4', // Vulgar fraction one quarter
-      '\u00BD': '1/2', // Vulgar fraction one half
-      '\u00BE': '3/4', // Vulgar fraction three quarters
-    };
     this.findBar = options.findBar || null;
 
-    // Compile the regular expression for text normalization once
-    var replace = Object.keys(this.charactersToNormalize).join('');
+    this.reset();
+
+    // Compile the regular expression for text normalization once.
+    var replace = Object.keys(CHARACTERS_TO_NORMALIZE).join('');
     this.normalizationRegex = new RegExp('[' + replace + ']', 'g');
 
     var events = [
       'find',
       'findagain',
       'findhighlightallchange',
       'findcasesensitivitychange'
     ];
-
-    this.firstPagePromise = new Promise(function (resolve) {
-      this.resolveFirstPage = resolve;
-    }.bind(this));
     this.handleEvent = this.handleEvent.bind(this);
 
     for (var i = 0, len = events.length; i < len; i++) {
       window.addEventListener(events[i], this.handleEvent);
     }
   }
 
   PDFFindController.prototype = {
     setFindBar: function PDFFindController_setFindBar(findBar) {
       this.findBar = findBar;
     },
 
     reset: function PDFFindController_reset() {
       this.startedTextExtraction = false;
       this.extractTextPromises = [];
-      this.active = false;
+      this.pendingFindMatches = Object.create(null);
+      this.active = false; // If active, find results will be highlighted.
+      this.pageContents = []; // Stores the text for each page.
+      this.pageMatches = [];
+      this.matchCount = 0;
+      this.selected = { // Currently selected match.
+        pageIdx: -1,
+        matchIdx: -1
+      };
+      this.offset = { // Where the find algorithm currently is in the document.
+        pageIdx: null,
+        matchIdx: null
+      };
+      this.pagesToSearch = null;
+      this.resumePageIdx = null;
+      this.state = null;
+      this.dirtyMatch = false;
+      this.findTimeout = null;
+
+      this.firstPagePromise = new Promise(function (resolve) {
+        this.resolveFirstPage = resolve;
+      }.bind(this));
     },
 
     normalize: function PDFFindController_normalize(text) {
-      var self = this;
       return text.replace(this.normalizationRegex, function (ch) {
-        return self.charactersToNormalize[ch];
+        return CHARACTERS_TO_NORMALIZE[ch];
       });
     },
 
     calcFindMatch: function PDFFindController_calcFindMatch(pageIndex) {
       var pageContent = this.normalize(this.pageContents[pageIndex]);
       var query = this.normalize(this.state.query);
       var caseSensitive = this.state.caseSensitive;
       var queryLen = query.length;
@@ -2205,35 +2201,32 @@ var DELAY_BEFORE_HIDING_CONTROLS = 3000;
 var ACTIVE_SELECTOR = 'pdfPresentationMode';
 var CONTROLS_SELECTOR = 'pdfPresentationModeControls';
 
 /**
  * @typedef {Object} PDFPresentationModeOptions
  * @property {HTMLDivElement} container - The container for the viewer element.
  * @property {HTMLDivElement} viewer - (optional) The viewer element.
  * @property {PDFViewer} pdfViewer - The document viewer.
- * @property {PDFThumbnailViewer} pdfThumbnailViewer - (optional) The thumbnail
- *   viewer.
  * @property {Array} contextMenuItems - (optional) The menuitems that are added
  *   to the context menu in Presentation Mode.
  */
 
 /**
  * @class
  */
 var PDFPresentationMode = (function PDFPresentationModeClosure() {
   /**
    * @constructs PDFPresentationMode
    * @param {PDFPresentationModeOptions} options
    */
   function PDFPresentationMode(options) {
     this.container = options.container;
     this.viewer = options.viewer || options.container.firstElementChild;
     this.pdfViewer = options.pdfViewer;
-    this.pdfThumbnailViewer = options.pdfThumbnailViewer || null;
     var contextMenuItems = options.contextMenuItems || null;
 
     this.active = false;
     this.args = null;
     this.contextMenuOpen = false;
     this.mouseScrollTimeStamp = 0;
     this.mouseScrollDelta = 0;
 
@@ -2425,20 +2418,16 @@ var PDFPresentationMode = (function PDFP
         this.args = null;
       }.bind(this), 0);
 
       this._removeWindowListeners();
       this._hideControls();
       this._resetMouseScrollState();
       this.container.removeAttribute('contextmenu');
       this.contextMenuOpen = false;
-
-      if (this.pdfThumbnailViewer) {
-        this.pdfThumbnailViewer.ensureThumbnailVisible(page);
-      }
     },
 
     /**
      * @private
      */
     _mouseDown: function PDFPresentationMode_mouseDown(evt) {
       if (this.contextMenuOpen) {
         this.contextMenuOpen = false;
@@ -5670,23 +5659,16 @@ var PDFThumbnailViewer = (function PDFTh
           thumbView.setPdfPage(pdfPage);
           this._pagesRequests[pageNumber] = null;
           return pdfPage;
         }.bind(this));
       this._pagesRequests[pageNumber] = promise;
       return promise;
     },
 
-    ensureThumbnailVisible:
-        function PDFThumbnailViewer_ensureThumbnailVisible(page) {
-      // Ensure that the thumbnail of the current page is visible
-      // when switching from another view.
-      scrollIntoView(document.getElementById('thumbnailContainer' + page));
-    },
-
     forceRendering: function () {
       var visibleThumbs = this._getVisibleThumbs();
       var thumbView = this.renderingQueue.getHighestPriority(visibleThumbs,
                                                              this.thumbnails,
                                                              this.scroll.down);
       if (thumbView) {
         this._ensurePdfPageLoaded(thumbView).then(function () {
           this.renderingQueue.renderView(thumbView);
@@ -5696,81 +5678,422 @@ var PDFThumbnailViewer = (function PDFTh
       return false;
     }
   };
 
   return PDFThumbnailViewer;
 })();
 
 
+var SidebarView = {
+  NONE: 0,
+  THUMBS: 1,
+  OUTLINE: 2,
+  ATTACHMENTS: 3
+};
+
 /**
- * @typedef {Object} PDFOutlineViewOptions
- * @property {HTMLDivElement} container - The viewer element.
- * @property {Array} outline - An array of outline objects.
- * @property {IPDFLinkService} linkService - The navigation/linking service.
+ * @typedef {Object} PDFSidebarOptions
+ * @property {PDFViewer} - The document viewer.
+ * @property {PDFThumbnailViewer} - The thumbnail viewer.
+ * @property {PDFOutlineViewer} - The outline viewer.
+ * @property {HTMLDivElement} mainContainer - The main container
+ *   (in which the viewer element is placed).
+ * @property {HTMLDivElement} outerContainer - The outer container
+ *   (encasing both the viewer and sidebar elements).
+ * @property {HTMLButtonElement} toggleButton - The button used for
+ *   opening/closing the sidebar.
+ * @property {HTMLButtonElement} thumbnailButton - The button used to show
+ *   the thumbnail view.
+ * @property {HTMLButtonElement} outlineButton - The button used to show
+ *   the outline view.
+ * @property {HTMLButtonElement} attachmentsButton - The button used to show
+ *   the attachments view.
+ * @property {HTMLDivElement} thumbnailView - The container in which
+ *   the thumbnails are placed.
+ * @property {HTMLDivElement} outlineView - The container in which
+ *   the outline is placed.
+ * @property {HTMLDivElement} attachmentsView - The container in which
+ *   the attachments are placed.
  */
 
 /**
  * @class
  */
-var PDFOutlineView = (function PDFOutlineViewClosure() {
+var PDFSidebar = (function PDFSidebarClosure() {
   /**
-   * @constructs PDFOutlineView
-   * @param {PDFOutlineViewOptions} options
+   * @constructs PDFSidebar
+   * @param {PDFSidebarOptions} options
    */
-  function PDFOutlineView(options) {
-    this.container = options.container;
-    this.outline = options.outline;
-    this.linkService = options.linkService;
-    this.lastToggleIsShow = true;
+  function PDFSidebar(options) {
+    this.isOpen = false;
+    this.active = SidebarView.THUMBS;
+    this.isInitialViewSet = false;
+
+    /**
+     * Callback used when the sidebar has been opened/closed, to ensure that
+     * the viewers (PDFViewer/PDFThumbnailViewer) are updated correctly.
+     */
+    this.onToggled = null;
+
+    this.pdfViewer = options.pdfViewer;
+    this.pdfThumbnailViewer = options.pdfThumbnailViewer;
+    this.pdfOutlineViewer = options.pdfOutlineViewer;
+
+    this.mainContainer = options.mainContainer;
+    this.outerContainer = options.outerContainer;
+    this.toggleButton = options.toggleButton;
+
+    this.thumbnailButton = options.thumbnailButton;
+    this.outlineButton = options.outlineButton;
+    this.attachmentsButton = options.attachmentsButton;
+
+    this.thumbnailView = options.thumbnailView;
+    this.outlineView = options.outlineView;
+    this.attachmentsView = options.attachmentsView;
+
+    this._addEventListeners();
   }
 
-  PDFOutlineView.prototype = {
-    reset: function PDFOutlineView_reset() {
-      var container = this.container;
-      while (container.firstChild) {
-        container.removeChild(container.firstChild);
-      }
-      this.lastToggleIsShow = true;
+  PDFSidebar.prototype = {
+    reset: function PDFSidebar_reset() {
+      this.isInitialViewSet = false;
+
+      this.close();
+      this.switchView(SidebarView.THUMBS);
+
+      this.outlineButton.disabled = false;
+      this.attachmentsButton.disabled = false;
+    },
+
+    /**
+     * @returns {number} One of the values in {SidebarView}.
+     */
+    get visibleView() {
+      return (this.isOpen ? this.active : SidebarView.NONE);
+    },
+
+    get isThumbnailViewVisible() {
+      return (this.isOpen && this.active === SidebarView.THUMBS);
+    },
+
+    get isOutlineViewVisible() {
+      return (this.isOpen && this.active === SidebarView.OUTLINE);
+    },
+
+    get isAttachmentsViewVisible() {
+      return (this.isOpen && this.active === SidebarView.ATTACHMENTS);
+    },
+
+    /**
+     * @param {number} view - The sidebar view that should become visible,
+     *                        must be one of the values in {SidebarView}.
+     */
+    setInitialView: function PDFSidebar_setInitialView(view) {
+      if (this.isInitialViewSet) {
+        return;
+      }
+      this.isInitialViewSet = true;
+
+      if (this.isOpen && view === SidebarView.NONE) {
+        // If the user has already manually opened the sidebar,
+        // immediately closing it would be bad UX.
+        return;
+      }
+      this.switchView(view, true);
+    },
+
+    /**
+     * @param {number} view - The sidebar view that should be switched to,
+     *                        must be one of the values in {SidebarView}.
+     * @param {boolean} forceOpen - Ensure that the sidebar is opened.
+     *                              The default value is false.
+     */
+    switchView: function PDFSidebar_switchView(view, forceOpen) {
+      if (view === SidebarView.NONE) {
+        this.close();
+        return;
+      }
+      if (forceOpen) {
+        this.open();
+      }
+      var shouldForceRendering = false;
+
+      switch (view) {
+        case SidebarView.THUMBS:
+          this.thumbnailButton.classList.add('toggled');
+          this.outlineButton.classList.remove('toggled');
+          this.attachmentsButton.classList.remove('toggled');
+
+          this.thumbnailView.classList.remove('hidden');
+          this.outlineView.classList.add('hidden');
+          this.attachmentsView.classList.add('hidden');
+
+          if (this.isOpen && view !== this.active) {
+            this._updateThumbnailViewer();
+            shouldForceRendering = true;
+          }
+          break;
+        case SidebarView.OUTLINE:
+          if (this.outlineButton.disabled) {
+            return;
+          }
+          this.thumbnailButton.classList.remove('toggled');
+          this.outlineButton.classList.add('toggled');
+          this.attachmentsButton.classList.remove('toggled');
+
+          this.thumbnailView.classList.add('hidden');
+          this.outlineView.classList.remove('hidden');
+          this.attachmentsView.classList.add('hidden');
+          break;
+        case SidebarView.ATTACHMENTS:
+          if (this.attachmentsButton.disabled) {
+            return;
+          }
+          this.thumbnailButton.classList.remove('toggled');
+          this.outlineButton.classList.remove('toggled');
+          this.attachmentsButton.classList.add('toggled');
+
+          this.thumbnailView.classList.add('hidden');
+          this.outlineView.classList.add('hidden');
+          this.attachmentsView.classList.remove('hidden');
+          break;
+        default:
+          console.error('PDFSidebar_switchView: "' + view +
+                        '" is an unsupported value.');
+          return;
+      }
+      // Update the active view *after* it has been validated above,
+      // in order to prevent setting it to an invalid state.
+      this.active = view | 0;
+
+      if (shouldForceRendering) {
+        this._forceRendering();
+      }
+    },
+
+    open: function PDFSidebar_open() {
+      if (this.isOpen) {
+        return;
+      }
+      this.isOpen = true;
+      this.toggleButton.classList.add('toggled');
+
+      this.outerContainer.classList.add('sidebarMoving');
+      this.outerContainer.classList.add('sidebarOpen');
+
+      if (this.active === SidebarView.THUMBS) {
+        this._updateThumbnailViewer();
+      }
+      this._forceRendering();
+    },
+
+    close: function PDFSidebar_close() {
+      if (!this.isOpen) {
+        return;
+      }
+      this.isOpen = false;
+      this.toggleButton.classList.remove('toggled');
+
+      this.outerContainer.classList.add('sidebarMoving');
+      this.outerContainer.classList.remove('sidebarOpen');
+
+      this._forceRendering();
+    },
+
+    toggle: function PDFSidebar_toggle() {
+      if (this.isOpen) {
+        this.close();
+      } else {
+        this.open();
+      }
     },
 
     /**
      * @private
      */
-    _dispatchEvent: function PDFOutlineView_dispatchEvent(outlineCount) {
+    _forceRendering: function PDFSidebar_forceRendering() {
+      if (this.onToggled) {
+        this.onToggled();
+      } else { // Fallback
+        this.pdfViewer.forceRendering();
+        this.pdfThumbnailViewer.forceRendering();
+      }
+    },
+
+    /**
+     * @private
+     */
+    _updateThumbnailViewer: function PDFSidebar_updateThumbnailViewer() {
+      var pdfViewer = this.pdfViewer;
+      var thumbnailViewer = this.pdfThumbnailViewer;
+
+      // Use the rendered pages to set the corresponding thumbnail images.
+      var pagesCount = pdfViewer.pagesCount;
+      for (var pageIndex = 0; pageIndex < pagesCount; pageIndex++) {
+        var pageView = pdfViewer.getPageView(pageIndex);
+        if (pageView && pageView.renderingState === RenderingStates.FINISHED) {
+          var thumbnailView = thumbnailViewer.getThumbnail(pageIndex);
+          thumbnailView.setImage(pageView);
+        }
+      }
+      thumbnailViewer.scrollThumbnailIntoView(pdfViewer.currentPageNumber);
+    },
+
+    /**
+     * @private
+     */
+    _addEventListeners: function PDFSidebar_addEventListeners() {
+      var self = this;
+
+      self.mainContainer.addEventListener('transitionend', function(evt) {
+        if (evt.target === /* mainContainer */ this) {
+          self.outerContainer.classList.remove('sidebarMoving');
+        }
+      });
+
+      // Buttons for switching views.
+      self.thumbnailButton.addEventListener('click', function() {
+        self.switchView(SidebarView.THUMBS);
+      });
+
+      self.outlineButton.addEventListener('click', function() {
+        self.switchView(SidebarView.OUTLINE);
+      });
+      self.outlineButton.addEventListener('dblclick', function() {
+        self.pdfOutlineViewer.toggleOutlineTree();
+      });
+
+      self.attachmentsButton.addEventListener('click', function() {
+        self.switchView(SidebarView.ATTACHMENTS);
+      });
+
+      // Disable/enable views.
+      self.outlineView.addEventListener('outlineloaded', function(evt) {
+        var outlineCount = evt.detail.outlineCount;
+
+        self.outlineButton.disabled = !outlineCount;
+        if (!outlineCount && self.active === SidebarView.OUTLINE) {
+          self.switchView(SidebarView.THUMBS);
+        }
+      });
+
+      self.attachmentsView.addEventListener('attachmentsloaded', function(evt) {
+        var attachmentsCount = evt.detail.attachmentsCount;
+
+        self.attachmentsButton.disabled = !attachmentsCount;
+        if (!attachmentsCount && self.active === SidebarView.ATTACHMENTS) {
+          self.switchView(SidebarView.THUMBS);
+        }
+      });
+
+      // Update the thumbnailViewer, if visible, when exiting presentation mode.
+      window.addEventListener('presentationmodechanged', function(evt) {
+        if (!evt.detail.active && !evt.detail.switchInProgress &&
+            self.isThumbnailViewVisible) {
+          self._updateThumbnailViewer();
+        }
+      });
+    },
+  };
+
+  return PDFSidebar;
+})();
+
+
+var DEFAULT_TITLE = '\u2013';
+
+/**
+ * @typedef {Object} PDFOutlineViewerOptions
+ * @property {HTMLDivElement} container - The viewer element.
+ * @property {IPDFLinkService} linkService - The navigation/linking service.
+ */
+
+/**
+ * @typedef {Object} PDFOutlineViewerRenderParameters
+ * @property {Array|null} outline - An array of outline objects.
+ */
+
+/**
+ * @class
+ */
+var PDFOutlineViewer = (function PDFOutlineViewerClosure() {
+  /**
+   * @constructs PDFOutlineViewer
+   * @param {PDFOutlineViewerOptions} options
+   */
+  function PDFOutlineViewer(options) {
+    this.outline = null;
+    this.lastToggleIsShow = true;
+    this.container = options.container;
+    this.linkService = options.linkService;
+  }
+
+  PDFOutlineViewer.prototype = {
+    reset: function PDFOutlineViewer_reset() {
+      this.outline = null;
+      this.lastToggleIsShow = true;
+
+      var container = this.container;
+      while (container.firstChild) {
+        container.removeChild(container.firstChild);
+      }
+    },
+
+    /**
+     * @private
+     */
+    _dispatchEvent: function PDFOutlineViewer_dispatchEvent(outlineCount) {
       var event = document.createEvent('CustomEvent');
       event.initCustomEvent('outlineloaded', true, true, {
         outlineCount: outlineCount
       });
       this.container.dispatchEvent(event);
     },
 
     /**
      * @private
      */
-    _bindLink: function PDFOutlineView_bindLink(element, item) {
+    _bindLink: function PDFOutlineViewer_bindLink(element, item) {
       if (item.url) {
         PDFJS.addLinkAttributes(element, { url: item.url });
         return;
       }
       var linkService = this.linkService;
       element.href = linkService.getDestinationHash(item.dest);
       element.onclick = function goToDestination(e) {
         linkService.navigateTo(item.dest);
         return false;
       };
     },
 
     /**
+     * @private
+     */
+    _setStyles: function PDFOutlineViewer_setStyles(element, item) {
+      var styleStr = '';
+      if (item.bold) {
+        styleStr += 'font-weight: bold;';
+      }
+      if (item.italic) {
+        styleStr += 'font-style: italic;';
+      }
+
+      if (styleStr) {
+        element.setAttribute('style', styleStr);
+      }
+    },
+
+    /**
      * Prepend a button before an outline item which allows the user to toggle
      * the visibility of all outline items at that level.
      *
      * @private
      */
-    _addToggleButton: function PDFOutlineView_addToggleButton(div) {
+    _addToggleButton: function PDFOutlineViewer_addToggleButton(div) {
       var toggler = document.createElement('div');
       toggler.className = 'outlineItemToggler';
       toggler.onclick = function(event) {
         event.stopPropagation();
         toggler.classList.toggle('outlineItemsHidden');
 
         if (event.shiftKey) {
           var shouldShowAll = !toggler.classList.contains('outlineItemsHidden');
@@ -5784,54 +6107,69 @@ var PDFOutlineView = (function PDFOutlin
      * Toggle the visibility of the subtree of an outline item.
      *
      * @param {Element} root - the root of the outline (sub)tree.
      * @param {boolean} state - whether to show the outline (sub)tree. If false,
      *   the outline subtree rooted at |root| will be collapsed.
      *
      * @private
      */
-    _toggleOutlineItem: function PDFOutlineView_toggleOutlineItem(root, show) {
+    _toggleOutlineItem:
+        function PDFOutlineViewer_toggleOutlineItem(root, show) {
       this.lastToggleIsShow = show;
       var togglers = root.querySelectorAll('.outlineItemToggler');
       for (var i = 0, ii = togglers.length; i < ii; ++i) {
         togglers[i].classList[show ? 'remove' : 'add']('outlineItemsHidden');
       }
     },
 
     /**
      * Collapse or expand all subtrees of the outline.
      */
-    toggleOutlineTree: function PDFOutlineView_toggleOutlineTree() {
+    toggleOutlineTree: function PDFOutlineViewer_toggleOutlineTree() {
+      if (!this.outline) {
+        return;
+      }
       this._toggleOutlineItem(this.container, !this.lastToggleIsShow);
     },
 
-    render: function PDFOutlineView_render() {
-      var outline = this.outline;
+    /**
+     * @param {PDFOutlineViewerRenderParameters} params
+     */
+    render: function PDFOutlineViewer_render(params) {
+      var outline = (params && params.outline) || null;
       var outlineCount = 0;
 
-      this.reset();
+      if (this.outline) {
+        this.reset();
+      }
+      this.outline = outline;
 
       if (!outline) {
         this._dispatchEvent(outlineCount);
         return;
       }
 
       var fragment = document.createDocumentFragment();
       var queue = [{ parent: fragment, items: this.outline }];
       var hasAnyNesting = false;
       while (queue.length > 0) {
         var levelData = queue.shift();
         for (var i = 0, len = levelData.items.length; i < len; i++) {
           var item = levelData.items[i];
+
           var div = document.createElement('div');
           div.className = 'outlineItem';
+
           var element = document.createElement('a');
           this._bindLink(element, item);
-          element.textContent = PDFJS.removeNullCharacters(item.title);
+          this._setStyles(element, item);
+          element.textContent =
+            PDFJS.removeNullCharacters(item.title) || DEFAULT_TITLE;
+
           div.appendChild(element);
 
           if (item.items.length > 0) {
             hasAnyNesting = true;
             this._addToggleButton(div);
 
             var itemsDiv = document.createElement('div');
             itemsDiv.className = 'outlineItems';
@@ -5848,75 +6186,89 @@ var PDFOutlineView = (function PDFOutlin
       }
 
       this.container.appendChild(fragment);
 
       this._dispatchEvent(outlineCount);
     }
   };
 
-  return PDFOutlineView;
+  return PDFOutlineViewer;
 })();
 
 
 /**
- * @typedef {Object} PDFAttachmentViewOptions
+ * @typedef {Object} PDFAttachmentViewerOptions
  * @property {HTMLDivElement} container - The viewer element.
- * @property {Array} attachments - An array of attachment objects.
  * @property {DownloadManager} downloadManager - The download manager.
  */
 
 /**
+ * @typedef {Object} PDFAttachmentViewerRenderParameters
+ * @property {Array|null} attachments - An array of attachment objects.
+ */
+
+/**
  * @class
  */
-var PDFAttachmentView = (function PDFAttachmentViewClosure() {
+var PDFAttachmentViewer = (function PDFAttachmentViewerClosure() {
   /**
-   * @constructs PDFAttachmentView
-   * @param {PDFAttachmentViewOptions} options
+   * @constructs PDFAttachmentViewer
+   * @param {PDFAttachmentViewerOptions} options
    */
-  function PDFAttachmentView(options) {
+  function PDFAttachmentViewer(options) {
+    this.attachments = null;
     this.container = options.container;
-    this.attachments = options.attachments;
     this.downloadManager = options.downloadManager;
   }
 
-  PDFAttachmentView.prototype = {
-    reset: function PDFAttachmentView_reset() {
+  PDFAttachmentViewer.prototype = {
+    reset: function PDFAttachmentViewer_reset() {
+      this.attachments = null;
+
       var container = this.container;
       while (container.firstChild) {
         container.removeChild(container.firstChild);
       }
     },
 
     /**
      * @private
      */
-    _dispatchEvent: function PDFAttachmentView_dispatchEvent(attachmentsCount) {
+    _dispatchEvent:
+        function PDFAttachmentViewer_dispatchEvent(attachmentsCount) {
       var event = document.createEvent('CustomEvent');
       event.initCustomEvent('attachmentsloaded', true, true, {
         attachmentsCount: attachmentsCount
       });
       this.container.dispatchEvent(event);
     },
 
     /**
      * @private
      */
-    _bindLink: function PDFAttachmentView_bindLink(button, content, filename) {
+    _bindLink:
+        function PDFAttachmentViewer_bindLink(button, content, filename) {
       button.onclick = function downloadFile(e) {
         this.downloadManager.downloadData(content, filename, '');
         return false;
       }.bind(this);
     },
 
-    render: function PDFAttachmentView_render() {
-      var attachments = this.attachments;
+    /**
+     * @param {PDFAttachmentViewerRenderParameters} params
+     */
+    render: function PDFAttachmentViewer_render(params) {
+      var attachments = (params && params.attachments) || null;
       var attachmentsCount = 0;
 
-      this.reset();
+      if (this.attachments) {
+        this.reset();
+      }
+      this.attachments = attachments;
 
       if (!attachments) {
         this._dispatchEvent(attachmentsCount);
         return;
       }
 
       var names = Object.keys(attachments).sort(function(a, b) {
         return a.toLowerCase().localeCompare(b.toLowerCase());
@@ -5934,43 +6286,48 @@ var PDFAttachmentView = (function PDFAtt
         div.appendChild(button);
         this.container.appendChild(div);
       }
 
       this._dispatchEvent(attachmentsCount);
     }
   };
 
-  return PDFAttachmentView;
+  return PDFAttachmentViewer;
 })();
 
 
 var PDFViewerApplication = {
   initialBookmark: document.location.hash.substring(1),
   initialDestination: null,
   initialized: false,
   fellback: false,
   pdfDocument: null,
   pdfLoadingTask: null,
-  sidebarOpen: false,
   printing: false,
   /** @type {PDFViewer} */
   pdfViewer: null,
   /** @type {PDFThumbnailViewer} */
   pdfThumbnailViewer: null,
   /** @type {PDFRenderingQueue} */
   pdfRenderingQueue: null,
   /** @type {PDFPresentationMode} */
   pdfPresentationMode: null,
   /** @type {PDFDocumentProperties} */
   pdfDocumentProperties: null,
   /** @type {PDFLinkService} */
   pdfLinkService: null,
   /** @type {PDFHistory} */
   pdfHistory: null,
+  /** @type {PDFSidebar} */
+  pdfSidebar: null,
+  /** @type {PDFOutlineViewer} */
+  pdfOutlineViewer: null,
+  /** @type {PDFAttachmentViewer} */
+  pdfAttachmentViewer: null,
   pageRotation: 0,
   isInitialViewSet: false,
   animationStartedPromise: null,
   preferenceSidebarViewOnLoad: SidebarView.NONE,
   preferencePdfBugEnabled: false,
   preferenceShowPreviousViewOnLoad: true,
   preferenceDefaultZoomValue: '',
   isViewerEmbedded: (window.parent !== window),
@@ -6075,17 +6432,16 @@ var PDFViewerApplication = {
     });
 
     if (this.supportsFullscreen) {
       var toolbar = SecondaryToolbar;
       this.pdfPresentationMode = new PDFPresentationMode({
         container: container,
         viewer: viewer,
         pdfViewer: this.pdfViewer,
-        pdfThumbnailViewer: this.pdfThumbnailViewer,
         contextMenuItems: [
           { element: document.getElementById('contextFirstPage'),
             handler: toolbar.firstPageClick.bind(toolbar) },
           { element: document.getElementById('contextLastPage'),
             handler: toolbar.lastPageClick.bind(toolbar) },
           { element: document.getElementById('contextPageRotateCw'),
             handler: toolbar.pageRotateCwClick.bind(toolbar) },
           { element: document.getElementById('contextPageRotateCcw'),
@@ -6097,16 +6453,45 @@ var PDFViewerApplication = {
     PasswordPrompt.initialize({
       overlayName: 'passwordOverlay',
       passwordField: document.getElementById('password'),
       passwordText: document.getElementById('passwordText'),
       passwordSubmit: document.getElementById('passwordSubmit'),
       passwordCancel: document.getElementById('passwordCancel')
     });
 
+    this.pdfOutlineViewer = new PDFOutlineViewer({
+      container: document.getElementById('outlineView'),
+      linkService: pdfLinkService,
+    });
+
+    this.pdfAttachmentViewer = new PDFAttachmentViewer({
+      container: document.getElementById('attachmentsView'),
+      downloadManager: new DownloadManager(),
+    });
+
+    this.pdfSidebar = new PDFSidebar({
+      pdfViewer: this.pdfViewer,
+      pdfThumbnailViewer: this.pdfThumbnailViewer,
+      pdfOutlineViewer: this.pdfOutlineViewer,
+      // Divs (and sidebar button)
+      mainContainer: document.getElementById('mainContainer'),
+      outerContainer: document.getElementById('outerContainer'),
+      toggleButton: document.getElementById('sidebarToggle'),
+      // Buttons
+      thumbnailButton: document.getElementById('viewThumbnail'),
+      outlineButton: document.getElementById('viewOutline'),
+      attachmentsButton: document.getElementById('viewAttachments'),
+      // Views
+      thumbnailView: document.getElementById('thumbnailView'),
+      outlineView: document.getElementById('outlineView'),
+      attachmentsView: document.getElementById('attachmentsView'),
+    });
+    this.pdfSidebar.onToggled = this.forceRendering.bind(this);
+
     var self = this;
     var initializedPromise = Promise.all([
       Preferences.get('enableWebGL').then(function resolved(value) {
         PDFJS.disableWebGL = !value;
       }),
       Preferences.get('sidebarViewOnLoad').then(function resolved(value) {
         self.preferenceSidebarViewOnLoad = value;
       }),
@@ -6368,16 +6753,23 @@ var PDFViewerApplication = {
     if (this.pdfDocument) {
       this.pdfDocument = null;
 
       this.pdfThumbnailViewer.setDocument(null);
       this.pdfViewer.setDocument(null);
       this.pdfLinkService.setDocument(null, null);
     }
 
+    this.pdfSidebar.reset();
+    this.pdfOutlineViewer.reset();
+    this.pdfAttachmentViewer.reset();
+
+    this.findController.reset();
+    this.findBar.reset();
+
     if (typeof PDFBug !== 'undefined') {
       PDFBug.cleanup();
     }
     return promise;
   },
 
   /**
    * Opens PDF document specified by URL or array with additional arguments.
@@ -6605,18 +6997,16 @@ var PDFViewerApplication = {
       }
     }
   },
 
   load: function pdfViewLoad(pdfDocument, scale) {
     var self = this;
     scale = scale || UNKNOWN_SCALE;
 
-    this.findController.reset();
-
     this.pdfDocument = pdfDocument;
 
     this.pdfDocumentProperties.setDocumentAndUrl(pdfDocument, this.url);
 
     var downloadedPromise = pdfDocument.getDownloadInfo().then(function() {
       self.downloadComplete = true;
       self.loadingBar.hide();
     });
@@ -6742,59 +7132,23 @@ var PDFViewerApplication = {
         });
       }
     });
 
     // outline depends on pagesRefMap
     var promises = [pagesPromise, this.animationStartedPromise];
     Promise.all(promises).then(function() {
       pdfDocument.getOutline().then(function(outline) {
-        var container = document.getElementById('outlineView');
-        self.outline = new PDFOutlineView({
-          container: container,
-          outline: outline,
-          linkService: self.pdfLinkService
-        });
-        self.outline.render();
-        document.getElementById('viewOutline').disabled = !outline;
-
-        if (!outline && !container.classList.contains('hidden')) {
-          self.switchSidebarView('thumbs');
-        }
-        if (outline &&
-            self.preferenceSidebarViewOnLoad === SidebarView.OUTLINE) {
-          self.switchSidebarView('outline', true);
-        }
+        self.pdfOutlineViewer.render({ outline: outline });
       });
       pdfDocument.getAttachments().then(function(attachments) {
-        var container = document.getElementById('attachmentsView');
-        self.attachments = new PDFAttachmentView({
-          container: container,
-          attachments: attachments,
-          downloadManager: new DownloadManager()
-        });
-        self.attachments.render();
-        document.getElementById('viewAttachments').disabled = !attachments;
-
-        if (!attachments && !container.classList.contains('hidden')) {
-          self.switchSidebarView('thumbs');
-        }
-        if (attachments &&
-            self.preferenceSidebarViewOnLoad === SidebarView.ATTACHMENTS) {
-          self.switchSidebarView('attachments', true);
-        }
+        self.pdfAttachmentViewer.render({ attachments: attachments });
       });
     });
 
-    if (self.preferenceSidebarViewOnLoad === SidebarView.THUMBS) {
-      Promise.all([firstPagePromise, onePageRendered]).then(function () {
-        self.switchSidebarView('thumbs', true);
-      });
-    }
-
     pdfDocument.getMetadata().then(function(data) {
       var info = data.info, metadata = data.metadata;
       self.documentInfo = info;
       self.metadata = metadata;
 
       // Provides some basic debug information
       console.log('PDF ' + pdfDocument.fingerprint + ' [' +
                   info.PDFFormatVersion + ' ' + (info.Producer || '-').trim() +
@@ -6856,16 +7210,18 @@ var PDFViewerApplication = {
   setInitialView: function pdfViewSetInitialView(storedHash, scale) {
     this.isInitialViewSet = true;
 
     // When opening a new file, when one is already loaded in the viewer,
     // ensure that the 'pageNumber' element displays the correct value.
     document.getElementById('pageNumber').value =
       this.pdfViewer.currentPageNumber;
 
+    this.pdfSidebar.setInitialView(this.preferenceSidebarViewOnLoad);
+
     if (this.initialDestination) {
       this.pdfLinkService.navigateTo(this.initialDestination);
       this.initialDestination = null;
     } else if (this.initialBookmark) {
       this.pdfLinkService.setHash(this.initialBookmark);
       this.pdfHistory.push({ hash: this.initialBookmark }, true);
       this.initialBookmark = null;
     } else if (storedHash) {
@@ -6888,93 +7244,21 @@ var PDFViewerApplication = {
     }
     this.pdfViewer.cleanup();
     this.pdfThumbnailViewer.cleanup();
     this.pdfDocument.cleanup();
   },
 
   forceRendering: function pdfViewForceRendering() {
     this.pdfRenderingQueue.printing = this.printing;
-    this.pdfRenderingQueue.isThumbnailViewEnabled = this.sidebarOpen;
+    this.pdfRenderingQueue.isThumbnailViewEnabled =
+      this.pdfSidebar.isThumbnailViewVisible;
     this.pdfRenderingQueue.renderHighestPriority();
   },
 
-  refreshThumbnailViewer: function pdfViewRefreshThumbnailViewer() {
-    var pdfViewer = this.pdfViewer;
-    var thumbnailViewer = this.pdfThumbnailViewer;
-
-    // set thumbnail images of rendered pages
-    var pagesCount = pdfViewer.pagesCount;
-    for (var pageIndex = 0; pageIndex < pagesCount; pageIndex++) {
-      var pageView = pdfViewer.getPageView(pageIndex);
-      if (pageView && pageView.renderingState === RenderingStates.FINISHED) {
-        var thumbnailView = thumbnailViewer.getThumbnail(pageIndex);
-        thumbnailView.setImage(pageView);
-      }
-    }
-
-    thumbnailViewer.scrollThumbnailIntoView(this.page);
-  },
-
-  switchSidebarView: function pdfViewSwitchSidebarView(view, openSidebar) {
-    if (openSidebar && !this.sidebarOpen) {
-      document.getElementById('sidebarToggle').click();
-    }
-    var thumbsView = document.getElementById('thumbnailView');
-    var outlineView = document.getElementById('outlineView');
-    var attachmentsView = document.getElementById('attachmentsView');
-
-    var thumbsButton = document.getElementById('viewThumbnail');
-    var outlineButton = document.getElementById('viewOutline');
-    var attachmentsButton = document.getElementById('viewAttachments');
-
-    switch (view) {
-      case 'thumbs':
-        var wasAnotherViewVisible = thumbsView.classList.contains('hidden');
-
-        thumbsButton.classList.add('toggled');
-        outlineButton.classList.remove('toggled');
-        attachmentsButton.classList.remove('toggled');
-        thumbsView.classList.remove('hidden');
-        outlineView.classList.add('hidden');
-        attachmentsView.classList.add('hidden');
-
-        this.forceRendering();
-
-        if (wasAnotherViewVisible) {
-          this.pdfThumbnailViewer.ensureThumbnailVisible(this.page);
-        }
-        break;
-
-      case 'outline':
-        if (outlineButton.disabled) {
-          return;
-        }
-        thumbsButton.classList.remove('toggled');
-        outlineButton.classList.add('toggled');
-        attachmentsButton.classList.remove('toggled');
-        thumbsView.classList.add('hidden');
-        outlineView.classList.remove('hidden');
-        attachmentsView.classList.add('hidden');
-        break;
-
-      case 'attachments':
-        if (attachmentsButton.disabled) {
-          return;
-        }
-        thumbsButton.classList.remove('toggled');
-        outlineButton.classList.remove('toggled');
-        attachmentsButton.classList.add('toggled');
-        thumbsView.classList.add('hidden');
-        outlineView.classList.add('hidden');
-        attachmentsView.classList.remove('hidden');
-        break;
-    }
-  },
-
   beforePrint: function pdfViewSetupBeforePrint() {
     if (!this.supportsPrinting) {
       var printMessage = mozL10n.get('printing_not_supported', null,
           'Warning: Printing is not fully supported by this browser.');
       this.error(printMessage);
       return;
     }
 
@@ -7188,58 +7472,28 @@ function webViewerInitialized() {
 
   if (PDFViewerApplication.supportsIntegratedFind) {
     document.getElementById('viewFind').classList.add('hidden');
   }
 
   // Suppress context menus for some controls
   document.getElementById('scaleSelect').oncontextmenu = noContextMenuHandler;
 
-  var mainContainer = document.getElementById('mainContainer');
-  var outerContainer = document.getElementById('outerContainer');
-  mainContainer.addEventListener('transitionend', function(e) {
-    if (e.target === mainContainer) {
-      var event = document.createEvent('UIEvents');
-      event.initUIEvent('resize', false, false, window, 0);
-      window.dispatchEvent(event);
-      outerContainer.classList.remove('sidebarMoving');
-    }
-  }, true);
+  document.getElementById('mainContainer').addEventListener('transitionend',
+    function(e) {
+      if (e.target === /* mainContainer */ this) {
+        var event = document.createEvent('UIEvents');
+        event.initUIEvent('resize', false, false, window, 0);
+        window.dispatchEvent(event);
+      }
+    }, true);
 
   document.getElementById('sidebarToggle').addEventListener('click',
     function() {
-      this.classList.toggle('toggled');
-      outerContainer.classList.add('sidebarMoving');
-      outerContainer.classList.toggle('sidebarOpen');
-      PDFViewerApplication.sidebarOpen =
-        outerContainer.classList.contains('sidebarOpen');
-      if (PDFViewerApplication.sidebarOpen) {
-        PDFViewerApplication.refreshThumbnailViewer();
-      }
-      PDFViewerApplication.forceRendering();
-    });
-
-  document.getElementById('viewThumbnail').addEventListener('click',
-    function() {
-      PDFViewerApplication.switchSidebarView('thumbs');
-    });
-
-  document.getElementById('viewOutline').addEventListener('click',
-    function() {
-      PDFViewerApplication.switchSidebarView('outline');
-    });
-
-  document.getElementById('viewOutline').addEventListener('dblclick',
-    function() {
-      PDFViewerApplication.outline.toggleOutlineTree();
-    });
-
-  document.getElementById('viewAttachments').addEventListener('click',
-    function() {
-      PDFViewerApplication.switchSidebarView('attachments');
+      PDFViewerApplication.pdfSidebar.toggle();
     });
 
   document.getElementById('previous').addEventListener('click',
     function() {
       PDFViewerApplication.page--;
     });
 
   document.getElementById('next').addEventListener('click',
@@ -7297,17 +7551,18 @@ function webViewerInitialized() {
 
 document.addEventListener('DOMContentLoaded', webViewerLoad, true);
 
 document.addEventListener('pagerendered', function (e) {
   var pageNumber = e.detail.pageNumber;
   var pageIndex = pageNumber - 1;
   var pageView = PDFViewerApplication.pdfViewer.getPageView(pageIndex);
 
-  if (PDFViewerApplication.sidebarOpen) {
+  // Use the rendered page to set the corresponding thumbnail image.
+  if (PDFViewerApplication.pdfSidebar.isThumbnailViewVisible) {
     var thumbnailView = PDFViewerApplication.pdfThumbnailViewer.
                         getThumbnail(pageIndex);
     thumbnailView.setImage(pageView);
   }
 
   if (PDFJS.pdfBug && Stats.enabled && pageView.stats) {
     Stats.add(pageNumber, pageView.stats);
   }
@@ -7351,33 +7606,36 @@ document.addEventListener('textlayerrend
   }
 }, true);
 
 document.addEventListener('pagemode', function (evt) {
   if (!PDFViewerApplication.initialized) {
     return;
   }
   // Handle the 'pagemode' hash parameter, see also `PDFLinkService_setHash`.
-  var mode = evt.detail.mode;
+  var mode = evt.detail.mode, view;
   switch (mode) {
+    case 'thumbs':
+      view = SidebarView.THUMBS;
+      break;
     case 'bookmarks':
-      // Note: Our code calls this property 'outline', even though the
-      //       Open Parameter specification calls it 'bookmarks'.
-      mode = 'outline';
-      /* falls through */
-    case 'thumbs':
+    case 'outline':
+      view = SidebarView.OUTLINE;
+      break;
     case 'attachments':
-      PDFViewerApplication.switchSidebarView(mode, true);
+      view = SidebarView.ATTACHMENTS;
       break;
     case 'none':
-      if (PDFViewerApplication.sidebarOpen) {
-        document.getElementById('sidebarToggle').click();
-      }
+      view = SidebarView.NONE;
       break;
+    default:
+      console.error('Invalid "pagemode" hash parameter: ' + mode);
+      return;
   }
+  PDFViewerApplication.pdfSidebar.switchView(view, /* forceOpen = */ true);
 }, true);
 
 document.addEventListener('namedaction', function (e) {
   if (!PDFViewerApplication.initialized) {
     return;
   }
   // Processing couple of named actions that might be useful.
   // See also PDFLinkService.executeNamedAction
@@ -7537,17 +7795,18 @@ window.addEventListener('scalechange', f
   }
   PDFViewerApplication.pdfViewer.update();
 }, true);
 
 window.addEventListener('pagechange', function pagechange(evt) {
   var page = evt.pageNumber;
   if (evt.previousPageNumber !== page) {
     document.getElementById('pageNumber').value = page;
-    if (PDFViewerApplication.sidebarOpen) {
+
+    if (PDFViewerApplication.pdfSidebar.isThumbnailViewVisible) {
       PDFViewerApplication.pdfThumbnailViewer.scrollThumbnailIntoView(page);
     }
   }
   var numPages = PDFViewerApplication.pagesCount;
 
   document.getElementById('previous').disabled = (page <= 1);
   document.getElementById('next').disabled = (page >= numPages);
 
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -253,16 +253,19 @@ These should match what Safari and other
 <!ENTITY addons.commandkey            "A">
 
 <!ENTITY webDeveloperMenu.label       "Web Developer">
 <!ENTITY webDeveloperMenu.accesskey   "W">
 
 <!ENTITY devToolsCmd.keycode          "VK_F12">
 <!ENTITY devToolsCmd.keytext          "F12">
 
+<!ENTITY devtoolsServiceWorkers.label      "Service Workers">
+<!ENTITY devtoolsServiceWorkers.accesskey  "k">
+
 <!ENTITY devtoolsConnect.label        "Connect…">
 <!ENTITY devtoolsConnect.accesskey    "e">
 
 <!ENTITY errorConsoleCmd.label        "Error Console">
 <!ENTITY errorConsoleCmd.accesskey    "C">
 
 <!ENTITY remoteWebConsoleCmd.label    "Remote Web Console">
 
@@ -801,18 +804,16 @@ you can use these alternative items. Oth
 <!-- LOCALIZATION NOTE (syncedTabs.sidebar.tabsnotsyncing.label): This is shown
      when Sync is configured but syncing tabs is disabled. -->
 <!ENTITY syncedTabs.sidebar.tabsnotsyncing.label       "Turn on tab syncing to view a list of tabs from your other devices.">
 
 <!ENTITY syncedTabs.context.openTab.label                   "Open This Tab">
 <!ENTITY syncedTabs.context.openTab.accesskey               "O">
 <!ENTITY syncedTabs.context.bookmarkSingleTab.label         "Bookmark This Tab…">
 <!ENTITY syncedTabs.context.bookmarkSingleTab.accesskey     "B">
-<!ENTITY syncedTabs.context.refreshList.label               "Refresh List">
-<!ENTITY syncedTabs.context.refreshList.accesskey           "R">
 
 
 <!ENTITY syncBrand.shortName.label    "Sync">
 
 <!ENTITY syncSignIn.label             "Sign In To &syncBrand.shortName.label;…">
 <!ENTITY syncSignIn.accesskey         "Y">
 <!ENTITY syncSyncNowItem.label        "Sync Now">
 <!ENTITY syncSyncNowItem.accesskey    "S">
--- a/browser/themes/shared/customizableui/panelUIOverlay.inc.css
+++ b/browser/themes/shared/customizableui/panelUIOverlay.inc.css
@@ -193,17 +193,16 @@ panelmultiview[nosubviews=true] > .panel
 
 #PanelUI-popup > arrowscrollbox > autorepeatbutton {
   display: none;
 }
 #PanelUI-popup > arrowscrollbox > scrollbox {
   overflow: visible;
 }
 
-.cui-widget-panel > .panel-arrowcontainer > .panel-arrowcontent,
 #PanelUI-popup > .panel-arrowcontainer > .panel-arrowcontent {
   overflow: hidden;
 }
 
 #PanelUI-popup > .panel-arrowcontainer > .panel-arrowcontent,
 .cui-widget-panel > .panel-arrowcontainer > .panel-arrowcontent > .popup-internal-box {
   padding: 0;
 }
--- a/browser/themes/shared/identity-block/identity-block.inc.css
+++ b/browser/themes/shared/identity-block/identity-block.inc.css
@@ -161,19 +161,23 @@
 
 #urlbar[pageproxystate="valid"] > #identity-box.insecureLoginForms > #connection-icon,
 #urlbar[pageproxystate="valid"] > #identity-box.mixedActiveContent > #connection-icon {
   list-style-image: url(chrome://browser/skin/identity-mixed-active-loaded.svg);
   visibility: visible;
 }
 
 #urlbar[pageproxystate="valid"] > #identity-box.weakCipher > #connection-icon,
-#urlbar[pageproxystate="valid"] > #identity-box.certUserOverridden > #connection-icon,
 #urlbar[pageproxystate="valid"] > #identity-box.mixedDisplayContent > #connection-icon,
 #urlbar[pageproxystate="valid"] > #identity-box.mixedDisplayContentLoadedActiveBlocked > #connection-icon {
   list-style-image: url(chrome://browser/skin/identity-mixed-passive-loaded.svg);
   visibility: visible;
 }
 
 #urlbar[pageproxystate="valid"] > #identity-box.mixedActiveBlocked > #connection-icon {
   list-style-image: url(chrome://browser/skin/identity-mixed-active-blocked.svg);
   visibility: visible;
 }
+
+#urlbar[pageproxystate="valid"] > #identity-box.certUserOverridden > #connection-icon {
+  list-style-image: url(chrome://browser/skin/identity-mixed-passive-loaded.svg);
+  visibility: visible;
+}
--- a/devtools/client/aboutdebugging/aboutdebugging.css
+++ b/devtools/client/aboutdebugging/aboutdebugging.css
@@ -9,16 +9,17 @@ html, body {
 
 h2, h3, h4 {
   margin-bottom: 5px;
 }
 
 button {
   padding-left: 20px;
   padding-right: 20px;
+  min-width: 100px;
 }
 
 /* Category tabs */
 
 .category {
   display: flex;
   flex-direction: row;
   align-content: center;
@@ -81,9 +82,9 @@ button {
 
 .addons-options {
   flex: 1;
 }
 
 .addons-debugging-label {
   display: inline-block;
   margin: 0 5px 5px 0;
-}
\ No newline at end of file
+}
--- a/devtools/client/aboutdebugging/aboutdebugging.xhtml
+++ b/devtools/client/aboutdebugging/aboutdebugging.xhtml
@@ -6,17 +6,17 @@
 <!DOCTYPE html [
 <!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd"> %htmlDTD;
 <!ENTITY % toolboxDTD SYSTEM "chrome://devtools/locale/toolbox.dtd"> %toolboxDTD;
 <!ENTITY % aboutdebuggingDTD SYSTEM "chrome://devtools/locale/aboutdebugging.dtd"> %aboutdebuggingDTD;
 ]>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
   <head>
-    <title>&aboutDebugging.title;</title>
+    <title>&aboutDebugging.fullTitle;</title>
     <link rel="stylesheet" href="chrome://global/skin/global.css" type="text/css"/>
     <link rel="stylesheet" href="chrome://global/skin/in-content/common.css" type="text/css"/>
     <link rel="stylesheet" href="chrome://devtools/content/aboutdebugging/aboutdebugging.css"  type="text/css"/>
     <script type="application/javascript" src="resource://devtools/client/shared/vendor/react.js"></script>
     <script type="application/javascript;version=1.8" src="chrome://devtools/content/aboutdebugging/initializer.js"></script>
   </head>
   <body id="body">
   </body>
--- a/devtools/client/aboutdebugging/components/target.js
+++ b/devtools/client/aboutdebugging/components/target.js
@@ -46,17 +46,20 @@ module.exports = createClass({
         null
       ),
       (isRunning ?
         dom.button({
           className: "debug-button",
           onClick: this.debug,
           disabled: debugDisabled,
         }, Strings.GetStringFromName("debug")) :
-        null
+        dom.button({
+          className: "start-button",
+          onClick: this.start
+        }, Strings.GetStringFromName("start"))
       )
     );
   },
 
   debug() {
     let { target } = this.props;
     switch (target.type) {
       case "extension":
@@ -84,16 +87,26 @@ module.exports = createClass({
     if (target.workerActor) {
       client.request({
         to: target.workerActor,
         type: "push"
       });
     }
   },
 
+  start() {
+    let { client, target } = this.props;
+    if (target.type === "serviceworker" && !target.workerActor) {
+      client.request({
+        to: target.registrationActor,
+        type: "start"
+      });
+    }
+  },
+
   openWorkerToolbox(workerActor) {
     let { client } = this.props;
     client.attachWorker(workerActor, (response, workerClient) => {
       gDevTools.showToolbox(TargetFactory.forWorker(workerClient),
         "jsdebugger", Toolbox.HostType.WINDOW)
         .then(toolbox => {
           toolbox.once("destroy", () => workerClient.detach());
         });
--- a/devtools/client/aboutdebugging/test/browser.ini
+++ b/devtools/client/aboutdebugging/test/browser.ini
@@ -10,9 +10,10 @@ support-files =
   service-workers/push-sw.html
   service-workers/push-sw.js
 
 [browser_addons_debugging_initial_state.js]
 [browser_addons_install.js]
 [browser_addons_toggle_debug.js]
 [browser_service_workers.js]
 [browser_service_workers_push.js]
+[browser_service_workers_start.js]
 [browser_service_workers_timeout.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging/test/browser_service_workers_start.js
@@ -0,0 +1,85 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that clicking on the Start button next to a Service Worker works as
+// intended in about:debugging.
+// It should cause a worker to start running in a child process.
+
+// Service workers can't be loaded from chrome://, but http:// is ok with
+// dom.serviceWorkers.testing.enabled turned on.
+const HTTP_ROOT = CHROME_ROOT.replace(
+  "chrome://mochitests/content/", "http://mochi.test:8888/");
+const SERVICE_WORKER = HTTP_ROOT + "service-workers/empty-sw.js";
+const TAB_URL = HTTP_ROOT + "service-workers/empty-sw.html";
+
+const SW_TIMEOUT = 1000;
+
+add_task(function* () {
+  info("Turn on workers via mochitest http.");
+  yield new Promise(done => {
+    let options = { "set": [
+      // Accept workers from mochitest's http.
+      ["dom.serviceWorkers.testing.enabled", true],
+      // Reduce the timeout to accelerate service worker freezing
+      ["dom.serviceWorkers.idle_timeout", SW_TIMEOUT],
+      ["dom.serviceWorkers.idle_extended_timeout", SW_TIMEOUT],
+    ]};
+    SpecialPowers.pushPrefEnv(options, done);
+  });
+
+  let { tab, document } = yield openAboutDebugging("workers");
+
+  // Listen for mutations in the service-workers list.
+  let serviceWorkersElement = document.getElementById("service-workers");
+  let onMutation = waitForMutation(serviceWorkersElement, { childList: true });
+
+  // Open a tab that registers an empty service worker.
+  let swTab = yield addTab(TAB_URL);
+
+  // Wait for the service-workers list to update.
+  yield onMutation;
+
+  // Check that the service worker appears in the UI.
+  assertHasTarget(true, document, "service-workers", SERVICE_WORKER);
+
+  info("Ensure that the registration resolved before trying to interact with " +
+    "the service worker.");
+  yield waitForServiceWorkerRegistered(swTab);
+  ok(true, "Service worker registration resolved");
+
+  // Retrieve the Target element corresponding to the service worker.
+  let names = [...document.querySelectorAll("#service-workers .target-name")];
+  let name = names.filter(element => element.textContent === SERVICE_WORKER)[0];
+  ok(name, "Found the service worker in the list");
+  let targetElement = name.parentNode.parentNode;
+
+  // Check that there is a Debug button but not a Start button.
+  ok(targetElement.querySelector(".debug-button"), "Found its debug button");
+  ok(!targetElement.querySelector(".start-button"), "No start button");
+
+  // Wait for the service worker to be killed due to inactivity.
+  yield waitForMutation(targetElement, { childList: true });
+
+  // We should now have a Start button but no Debug button.
+  let startBtn = targetElement.querySelector(".start-button");
+  ok(startBtn, "Found its start button");
+  ok(!targetElement.querySelector(".debug-button"), "No debug button");
+
+  // Click on the Start button and wait for the service worker to be back.
+  let onStarted = waitForMutation(targetElement, { childList: true });
+  startBtn.click();
+  yield onStarted;
+
+  // Check that we have a Debug button but not a Start button again.
+  ok(targetElement.querySelector(".debug-button"), "Found its debug button");
+  ok(!targetElement.querySelector(".start-button"), "No start button");
+
+  // Finally, unregister the service worker itself.
+  yield unregisterServiceWorker(swTab);
+  ok(true, "Service worker registration unregistered");
+
+  yield removeTab(swTab);
+  yield closeAboutDebugging(tab);
+});
--- a/devtools/client/canvasdebugger/canvasdebugger.js
+++ b/devtools/client/canvasdebugger/canvasdebugger.js
@@ -13,19 +13,16 @@ Cu.import("resource://gre/modules/Consol
 const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
 const promise = require("promise");
 const Services = require("Services");
 const EventEmitter = require("devtools/shared/event-emitter");
 const { CallWatcherFront } = require("devtools/server/actors/call-watcher");
 const { CanvasFront } = require("devtools/server/actors/canvas");
 const DevToolsUtils = require("devtools/shared/DevToolsUtils");
 
-const Telemetry = require("devtools/client/shared/telemetry");
-const telemetry = new Telemetry();
-
 const CANVAS_ACTOR_RECORDING_ATTEMPT = DevToolsUtils.testing ? 500 : 5000;
 
 XPCOMUtils.defineLazyModuleGetter(this, "Task",
   "resource://gre/modules/Task.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
   "resource://gre/modules/PluralForm.jsm");
 
@@ -127,27 +124,25 @@ function shutdownCanvasDebugger() {
 /**
  * Functions handling target-related lifetime events.
  */
 var EventsHandler = {
   /**
    * Listen for events emitted by the current tab target.
    */
   initialize: function() {
-    telemetry.toolOpened("canvasdebugger");
     this._onTabNavigated = this._onTabNavigated.bind(this);
     gTarget.on("will-navigate", this._onTabNavigated);
     gTarget.on("navigate", this._onTabNavigated);
   },
 
   /**
    * Remove events emitted by the current tab target.
    */
   destroy: function() {
-    telemetry.toolClosed("canvasdebugger");
     gTarget.off("will-navigate", this._onTabNavigated);
     gTarget.off("navigate", this._onTabNavigated);
   },
 
   /**
    * Called for each location change in the debugged tab.
    */
   _onTabNavigated: function(event) {
--- a/devtools/client/canvasdebugger/test/head.js
+++ b/devtools/client/canvasdebugger/test/head.js
@@ -12,19 +12,19 @@ var Services = require("Services");
 var promise = require("promise");
 var { gDevTools } = require("devtools/client/framework/devtools");
 var { DebuggerClient } = require("devtools/shared/client/main");
 var { DebuggerServer } = require("devtools/server/main");
 var { CallWatcherFront } = require("devtools/server/actors/call-watcher");
 var { CanvasFront } = require("devtools/server/actors/canvas");
 var { setTimeout } = require("sdk/timers");
 var DevToolsUtils = require("devtools/shared/DevToolsUtils");
-var TiltGL = require("devtools/client/tilt/tilt-gl");
 var { TargetFactory } = require("devtools/client/framework/target");
 var { Toolbox } = require("devtools/client/framework/toolbox");
+var { isWebGLSupported } = require("devtools/client/shared/webgl-utils");
 var mm = null
 
 const FRAME_SCRIPT_UTILS_URL = "chrome://devtools/content/shared/frame-script-utils.js";
 const EXAMPLE_URL = "http://example.com/browser/devtools/client/canvasdebugger/test/";
 const SET_TIMEOUT_URL = EXAMPLE_URL + "doc_settimeout.html";
 const NO_CANVAS_URL = EXAMPLE_URL + "doc_no-canvas.html";
 const RAF_NO_CANVAS_URL = EXAMPLE_URL + "doc_raf-no-canvas.html";
 const SIMPLE_CANVAS_URL = EXAMPLE_URL + "doc_simple-canvas.html";
@@ -135,20 +135,17 @@ function createCanvas() {
 }
 
 function isTestingSupported() {
   if (!gRequiresWebGL) {
     info("This test does not require WebGL support.");
     return true;
   }
 
-  let supported =
-    !TiltGL.isWebGLForceEnabled() &&
-     TiltGL.isWebGLSupported() &&
-     TiltGL.create3DContext(createCanvas());
+  let supported = isWebGLSupported(document);
 
   info("This test requires WebGL support.");
   info("Apparently, WebGL is" + (supported ? "" : " not") + " supported.");
   return supported;
 }
 
 function once(aTarget, aEventName, aUseCapture = false) {
   info("Waiting for event: '" + aEventName + "' on " + aTarget + ".");
--- a/devtools/client/commandline/test/browser_cmd_pref1.js
+++ b/devtools/client/commandline/test/browser_cmd_pref1.js
@@ -12,18 +12,18 @@ const TEST_URI = "data:text/html;charset
 function test() {
   return Task.spawn(spawnTest).then(finish, helpers.handleError);
 }
 
 function* spawnTest() {
   let options = yield helpers.openTab(TEST_URI);
   yield helpers.openToolbar(options);
 
-  let tiltEnabledOrig = prefBranch.getBoolPref("devtools.tilt.enabled");
-  info("originally: devtools.tilt.enabled = " + tiltEnabledOrig);
+  let netmonEnabledOrig = prefBranch.getBoolPref("devtools.netmonitor.enabled");
+  info("originally: devtools.netmonitor.enabled = " + netmonEnabledOrig);
 
   yield helpers.audit(options, [
     {
       setup: 'pref',
       check: {
         input:  'pref',
         hints:      ' reset',
         markup: 'IIII',
@@ -61,55 +61,55 @@ function* spawnTest() {
       check: {
         input:  'pref show usetexttospeech',
         hints:                           ' -> accessibility.usetexttospeech',
         markup: 'VVVVVVVVVVIIIIIIIIIIIIIII',
         status: 'ERROR'
       },
     },
     {
-      setup: 'pref show devtools.til',
+      setup: 'pref show devtools.netmoni',
       check: {
-        input:  'pref show devtools.til',
-        hints:                        't.enabled',
-        markup: 'VVVVVVVVVVIIIIIIIIIIII',
+        input:  'pref show devtools.netmoni',
+        hints:                        'tor.enabled',
+        markup: 'VVVVVVVVVVIIIIIIIIIIIIIIII',
         status: 'ERROR',
         tooltipState: 'true:importantFieldFlag',
         args: {
           setting: { value: undefined, status: 'INCOMPLETE' },
         }
       },
     },
     {
-      setup: 'pref reset devtools.tilt.enabled',
+      setup: 'pref reset devtools.netmonitor.enabled',
       check: {
-        input:  'pref reset devtools.tilt.enabled',
+        input:  'pref reset devtools.netmonitor.enabled',
         hints:                                  '',
-        markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
+        markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV',
         status: 'VALID'
       },
     },
     {
-      setup: 'pref show devtools.tilt.enabled 4',
+      setup: 'pref show devtools.netmonitor.enabled 4',
       check: {
-        input:  'pref show devtools.tilt.enabled 4',
+        input:  'pref show devtools.netmonitor.enabled 4',
         hints:                                   '',
-        markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVE',
+        markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVE',
         status: 'ERROR'
       },
     },
     {
-      setup: 'pref set devtools.tilt.enabled 4',
+      setup: 'pref set devtools.netmonitor.enabled 4',
       check: {
-        input:  'pref set devtools.tilt.enabled 4',
+        input:  'pref set devtools.netmonitor.enabled 4',
         hints:                                  '',
-        markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVE',
+        markup: 'VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVE',
         status: 'ERROR',
         args: {
-          setting: { arg: ' devtools.tilt.enabled' },
+          setting: { arg: ' devtools.netmonitor.enabled' },
           value: { status: 'ERROR', message: 'Can\'t use \'4\'.' },
         }
       },
     },
     {
       setup: 'pref set devtools.editor.tabsize 4',
       check: {
         input:  'pref set devtools.editor.tabsize 4',
@@ -127,28 +127,28 @@ function* spawnTest() {
       check: {
         input:  'pref list',
         hints:           ' -> pref set',
         markup: 'IIIIVIIII',
         status: 'ERROR'
       },
     },
     {
-      setup: 'pref show devtools.tilt.enabled',
+      setup: 'pref show devtools.netmonitor.enabled',
       check: {
         args: {
           setting: {
-            value: options.requisition.system.settings.get("devtools.tilt.enabled")
+            value: options.requisition.system.settings.get("devtools.netmonitor.enabled")
           }
         },
       },
       exec: {
-        output: "devtools.tilt.enabled: " + tiltEnabledOrig,
+        output: "devtools.netmonitor.enabled: " + netmonEnabledOrig,
       },
       post: function() {
-        prefBranch.setBoolPref("devtools.tilt.enabled", tiltEnabledOrig);
+        prefBranch.setBoolPref("devtools.netmonitor.enabled", netmonEnabledOrig);
       }
     },
   ]);
 
   yield helpers.closeToolbar(options);
   yield helpers.closeTab(options);
 }
--- a/devtools/client/debugger/content/actions/breakpoints.js
+++ b/devtools/client/debugger/content/actions/breakpoints.js
@@ -61,17 +61,19 @@ function addBreakpoint(location, conditi
           condition: bp.condition
         });
         const { isPending, actualLocation } = response;
 
         // Save the client instance
         setBreakpointClient(bpClient.actor, bpClient);
 
         return {
-          text: DebuggerView.editor.getText(bp.location.line - 1).trim(),
+          text: DebuggerView.editor.getText(
+            (actualLocation ? actualLocation.line : bp.location.line) - 1
+          ).trim(),
 
           // If the breakpoint response has an "actualLocation" attached, then
           // the original requested placement for the breakpoint wasn't
           // accepted.
           actualLocation: isPending ? null : actualLocation,
           actor: bpClient.actor
         };
       })
--- a/devtools/client/debugger/content/views/sources-view.js
+++ b/devtools/client/debugger/content/views/sources-view.js
@@ -1142,17 +1142,17 @@ SourcesView.prototype = Heritage.extend(
     }
   },
 
   /**
    * Called when the add breakpoint key sequence was pressed.
    */
   _onCmdAddBreakpoint: function(e) {
     let actor = this.selectedValue;
-    let line = (e && e.sourceEvent.target.tagName == 'menuitem' ?
+    let line = (this.DebuggerView.clickedLine ?
                 this.DebuggerView.clickedLine + 1 :
                 this.DebuggerView.editor.getCursor().line + 1);
     let location = { actor, line };
     let bp = getBreakpoint(this.getState(), location);
 
     // If a breakpoint already existed, remove it now.
     if (bp) {
       this.actions.removeBreakpoint(bp.location);
--- a/devtools/client/debugger/debugger-view.js
+++ b/devtools/client/debugger/debugger-view.js
@@ -332,16 +332,20 @@ var DebuggerView = {
           if (this.editor.hasBreakpoint(line)) {
             this.controller.dispatch(actions.removeBreakpoint(location));
           } else {
             this.controller.dispatch(actions.addBreakpoint(location));
           }
         }
       }
     });
+
+    this.editor.on("cursorActivity", () => {
+      this.clickedLine = null;
+    });
   },
 
   updateEditorBreakpoints: function(source) {
     const breakpoints = queries.getBreakpoints(this.controller.getState());
     const sources = queries.getSources(this.controller.getState());
 
     for (let bp of breakpoints) {
       if (sources[bp.location.actor] && !bp.disabled) {
--- a/devtools/client/framework/devtools-browser.js
+++ b/devtools/client/framework/devtools-browser.js
@@ -188,16 +188,25 @@ var gDevToolsBrowser = exports.gDevTools
 
         toolbox.fireCustomKey(toolId);
         gDevTools.emit("select-tool-command", toolId);
       });
     }
   },
 
   /**
+   * Open a tab on "about:debugging", optionally pre-select a given tab.
+   */
+   // Used by browser-sets.inc, command
+  openAboutDebugging: function(gBrowser, hash) {
+    let url = "about:debugging" + (hash ? "#" + hash : "");
+    gBrowser.selectedTab = gBrowser.addTab(url);
+  },
+
+  /**
    * Open a tab to allow connects to a remote browser
    */
    // Used by browser-sets.inc, command
   openConnectScreen: function(gBrowser) {
     gBrowser.selectedTab = gBrowser.addTab("chrome://devtools/content/framework/connect/connect.xhtml");
   },
 
   /**
--- a/devtools/client/framework/gDevTools.jsm
+++ b/devtools/client/framework/gDevTools.jsm
@@ -116,16 +116,19 @@ gDevToolsMethods.forEach(name => {
 let gDevToolsBrowserMethods = [
   // used by browser-sets.inc, command
   "toggleToolboxCommand",
 
   // Used by browser.js itself, by setting a oncommand string...
   "selectToolCommand",
 
   // Used by browser-sets.inc, command
+  "openAboutDebugging",
+
+  // Used by browser-sets.inc, command
   "openConnectScreen",
 
   // Used by browser-sets.inc, command
   //         itself, webide widget
   "openWebIDE",
 
   // Used by browser-sets.inc, command
   "openContentProcessToolbox",
--- a/devtools/client/framework/test/browser_toolbox_options_disable_buttons.js
+++ b/devtools/client/framework/test/browser_toolbox_options_disable_buttons.js
@@ -76,22 +76,16 @@ function testPreferenceAndUIStateIsConsi
   }
 }
 
 function testToggleToolboxButtons() {
   let checkNodes = [...panelWin.document.querySelectorAll("#enabled-toolbox-buttons-box > checkbox")];
   let toolboxButtonNodes = [...doc.querySelectorAll(".command-button")];
   let toggleableTools = toolbox.toolboxButtons;
 
-  // Tilt is disabled in E10S mode so we skip the tilt button if E10S is
-  // enabled.
-  if (toolbox.target.isMultiProcess) {
-    toolboxButtonNodes = [...doc.querySelectorAll(".command-button:not(#command-button-tilt)")];
-  }
-
   // The noautohide button is only displayed in the browser toolbox
   toggleableTools = toggleableTools.filter(tool => tool.id != "command-button-noautohide");
   toolboxButtonNodes = toolboxButtonNodes.filter(btn => btn.id != "command-button-noautohide");
 
   is (checkNodes.length, toggleableTools.length, "All of the buttons are toggleable." );
   is (checkNodes.length, toolboxButtonNodes.length, "All of the DOM buttons are toggleable." );
 
   for (let tool of toggleableTools) {
--- a/devtools/client/framework/toolbox-options.js
+++ b/devtools/client/framework/toolbox-options.js
@@ -169,19 +169,16 @@ OptionsPanel.prototype = {
       checkbox.setAttribute("id", tool.id);
       checkbox.setAttribute("label", tool.label);
       checkbox.setAttribute("checked", InfallibleGetBoolPref(tool.visibilityswitch));
       checkbox.addEventListener("command", onCheckboxClick.bind(this, checkbox));
       return checkbox;
     };
 
     for (let tool of toggleableButtons) {
-      if (this.toolbox.target.isMultiProcess && tool.id === "command-button-tilt") {
-        continue;
-      }
       if (!tool.isTargetSupported(this.toolbox.target)) {
         continue;
       }
 
       enabledToolbarButtonsBox.appendChild(createCommandCheckbox(tool));
     }
   },
 
--- a/devtools/client/framework/toolbox.js
+++ b/devtools/client/framework/toolbox.js
@@ -84,18 +84,16 @@ const ToolboxButtons = exports.ToolboxBu
     isTargetSupported: target => {
       return target.activeTab && target.activeTab.traits.frames;
     }
   },
   { id: "command-button-splitconsole",
     isTargetSupported: target => !target.isAddon },
   { id: "command-button-responsive" },
   { id: "command-button-paintflashing" },
-  { id: "command-button-tilt",
-    commands: "devtools/client/tilt/tilt-commands" },
   { id: "command-button-scratchpad" },
   { id: "command-button-eyedropper" },
   { id: "command-button-screenshot" },
   { id: "command-button-rulers" },
   { id: "command-button-measure" },
   { id: "command-button-noautohide",
     isTargetSupported: target => target.chrome },
 ];
@@ -1003,22 +1001,16 @@ Toolbox.prototype = {
   get toolboxButtons() {
     return ToolboxButtons.map(options => {
       let button = this.doc.getElementById(options.id);
       // Some buttons may not exist inside of Browser Toolbox
       if (!button) {
         return false;
       }
 
-      // Disable tilt in E10S mode. Removing it from the list of toolbox buttons
-      // allows a bunch of tests to pass without modification.
-      if (this.target.isMultiProcess && options.id === "command-button-tilt") {
-        return false;
-      }
-
       return {
         id: options.id,
         button: button,
         label: button.getAttribute("tooltiptext"),
         visibilityswitch: "devtools." + options.id + ".enabled",
         isTargetSupported: options.isTargetSupported
                            ? options.isTargetSupported
                            : target => target.isLocalTab,
@@ -1045,32 +1037,16 @@ Toolbox.prototype = {
           button.removeAttribute("hidden");
         } else {
           button.setAttribute("hidden", "true");
         }
       }
     });
 
     this._updateNoautohideButton();
-
-    // Tilt is handled separately because it is disabled in E10S mode. Because
-    // we have removed tilt from toolboxButtons we have to deal with it here.
-    let tiltEnabled = !this.target.isMultiProcess &&
-                      Services.prefs.getBoolPref("devtools.command-button-tilt.enabled");
-    let tiltButton = this.doc.getElementById("command-button-tilt");
-    // Remote toolboxes don't add the button to the DOM at all
-    if (!tiltButton) {
-      return;
-    }
-
-    if (tiltEnabled) {
-      tiltButton.removeAttribute("hidden");
-    } else {
-      tiltButton.setAttribute("hidden", "true");
-    }
   },
 
   /**
    * Build a tab for one tool definition and add to the toolbox
    *
    * @param {string} toolDefinition
    *        Tool definition of the tool to build a tab for.
    */
--- a/devtools/client/inspector/inspector.xul
+++ b/devtools/client/inspector/inspector.xul
@@ -188,39 +188,43 @@
              crop="end"
              hidden="true"/>
         <tab id="sidebar-tab-layoutview"
              label="&layoutViewTitle;"
              crop="end"/>
       </tabs>
       <tabpanels flex="1">
         <tabpanel id="sidebar-panel-ruleview" class="devtools-monospace theme-sidebar inspector-tabpanel">
-          <html:div id="ruleview-toolbar" class="devtools-toolbar devtools-sidebar-toolbar">
-            <html:div class="devtools-searchbox">
-              <html:input id="ruleview-searchbox"
-                          class="devtools-searchinput devtools-rule-searchbox"
-                          type="search"
-                          placeholder="&filterStylesPlaceholder;"/>
-              <html:button id="ruleview-searchinput-clear" class="devtools-searchinput-clear"></html:button>
+          <html:div id="ruleview-toolbar-container" class="devtools-toolbar">
+            <html:div id="ruleview-toolbar">
+              <html:div class="devtools-searchbox">
+                <html:input id="ruleview-searchbox"
+                            class="devtools-searchinput devtools-rule-searchbox"
+                            type="search"
+                            placeholder="&filterStylesPlaceholder;"/>
+                <html:button id="ruleview-searchinput-clear" class="devtools-searchinput-clear"></html:button>
+              </html:div>
+              <html:div id="ruleview-command-toolbar">
+                <html:button id="ruleview-add-rule-button" title="&addRuleButtonTooltip;" class="devtools-button"></html:button>
+                <html:button id="pseudo-class-panel-toggle" title="&togglePseudoClassPanel;" class="devtools-button"></html:button>
+              </html:div>
             </html:div>
-            <html:button id="ruleview-add-rule-button" title="&addRuleButtonTooltip;" class="devtools-button"></html:button>
-            <html:button id="pseudo-class-panel-toggle" title="&togglePseudoClassPanel;" class="devtools-button"></html:button>
+            <html:div id="pseudo-class-panel" hidden="true">
+              <html:label><html:input id="pseudo-hover-toggle" type="checkbox" value=":hover" tabindex="-1" />:hover</html:label>
+              <html:label><html:input id="pseudo-active-toggle" type="checkbox" value=":active" tabindex="-1" />:active</html:label>
+              <html:label><html:input id="pseudo-focus-toggle" type="checkbox" value=":focus" tabindex="-1" />:focus</html:label>
           </html:div>
-          <html:div id="pseudo-class-panel" class="devtools-toolbar devtools-sidebar-toolbar" hidden="true" tabindex="-1">
-            <html:label><html:input id="pseudo-hover-toggle" type="checkbox" value=":hover" tabindex="-1" />:hover</html:label>
-            <html:label><html:input id="pseudo-active-toggle" type="checkbox" value=":active" tabindex="-1" />:active</html:label>
-            <html:label><html:input id="pseudo-focus-toggle" type="checkbox" value=":focus" tabindex="-1" />:focus</html:label>
           </html:div>
 
           <html:div id="ruleview-container" class="ruleview">
           </html:div>
         </tabpanel>
 
         <tabpanel id="sidebar-panel-computedview" class="devtools-monospace theme-sidebar inspector-tabpanel">
-          <html:div class="devtools-toolbar devtools-sidebar-toolbar">
+          <html:div class="devtools-toolbar">
             <html:div class="devtools-searchbox">
               <html:input id="computedview-searchbox"
                           class="devtools-searchinput devtools-rule-searchbox"
                           type="search"
                           placeholder="&filterStylesPlaceholder;"/>
               <html:button id="computedview-searchinput-clear" class="devtools-searchinput-clear"></html:button>
             </html:div>
             <checkbox id="browser-style-checkbox"
@@ -233,17 +237,17 @@
           </html:div>
 
           <html:div id="noResults" hidden="">
             &noPropertiesFound;
           </html:div>
         </tabpanel>
 
         <tabpanel id="sidebar-panel-fontinspector" class="devtools-monospace theme-sidebar inspector-tabpanel">
-          <html:div class="devtools-toolbar devtools-sidebar-toolbar">
+          <html:div class="devtools-toolbar">
             <html:div class="devtools-searchbox">
               <html:input id="font-preview-text-input"
                           class="devtools-textinput"
                           type="search"
                           placeholder="&previewHint;"/>
             </html:div>
           </html:div>
 
--- a/devtools/client/inspector/rules/rules.js
+++ b/devtools/client/inspector/rules/rules.js
@@ -1054,75 +1054,74 @@ CssRuleView.prototype = {
    *         The label for the container header
    * @param  {Boolean} isPseudo
    *         Whether or not the container will hold pseudo element rules
    * @return {DOMNode} The container element
    */
   createExpandableContainer: function(label, isPseudo = false) {
     let header = this.styleDocument.createElementNS(HTML_NS, "div");
     header.className = this._getRuleViewHeaderClassName(true);
-    header.classList.add("show-expandable-container");
     header.textContent = label;
 
     let twisty = this.styleDocument.createElementNS(HTML_NS, "span");
     twisty.className = "ruleview-expander theme-twisty";
     twisty.setAttribute("open", "true");
 
     header.insertBefore(twisty, header.firstChild);
     this.element.appendChild(header);
 
     let container = this.styleDocument.createElementNS(HTML_NS, "div");
     container.classList.add("ruleview-expandable-container");
+    container.hidden = false;
     this.element.appendChild(container);
 
     header.addEventListener("dblclick", () => {
-      this._toggleContainerVisibility(twisty, header, isPseudo,
+      this._toggleContainerVisibility(twisty, container, isPseudo,
         !this.showPseudoElements);
     }, false);
 
     twisty.addEventListener("click", () => {
-      this._toggleContainerVisibility(twisty, header, isPseudo,
+      this._toggleContainerVisibility(twisty, container, isPseudo,
         !this.showPseudoElements);
     }, false);
 
     if (isPseudo) {
-      this._toggleContainerVisibility(twisty, header, isPseudo,
+      this._toggleContainerVisibility(twisty, container, isPseudo,
         this.showPseudoElements);
     }
 
     return container;
   },
 
   /**
    * Toggle the visibility of an expandable container
    *
    * @param  {DOMNode}  twisty
-   *         clickable toggle DOM Node
-   * @param  {DOMNode}  header
-   *         expandable container header DOM Node
+   *         Clickable toggle DOM Node
+   * @param  {DOMNode}  container
+   *         Expandable container DOM Node
    * @param  {Boolean}  isPseudo
-   *         whether or not the container will hold pseudo element rules
+   *         Whether or not the container will hold pseudo element rules
    * @param  {Boolean}  showPseudo
-   *         whether or not pseudo element rules should be displayed
+   *         Whether or not pseudo element rules should be displayed
    */
-  _toggleContainerVisibility: function(twisty, header, isPseudo, showPseudo) {
+  _toggleContainerVisibility: function(twisty, container, isPseudo,
+      showPseudo) {
     let isOpen = twisty.getAttribute("open");
 
     if (isPseudo) {
       this._showPseudoElements = !!showPseudo;
 
       Services.prefs.setBoolPref("devtools.inspector.show_pseudo_elements",
         this.showPseudoElements);
 
-      header.classList.toggle("show-expandable-container",
-        this.showPseudoElements);
-
+      container.hidden = !this.showPseudoElements;
       isOpen = !this.showPseudoElements;
     } else {
-      header.classList.toggle("show-expandable-container");
+      container.hidden = !container.hidden;
     }
 
     if (isOpen) {
       twisty.removeAttribute("open");
     } else {
       twisty.setAttribute("open", "true");
     }
   },
--- a/devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js
+++ b/devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js
@@ -35,33 +35,31 @@ function* testTopLeft(inspector, view) {
       selectionRulesNb: 0
     }
   );
 
   let gutters = assertGutters(view);
 
   info("Make sure that clicking on the twisty hides pseudo elements");
   let expander = gutters[0].querySelector(".ruleview-expander");
-  ok(view.element.firstChild.classList.contains("show-expandable-container"),
-     "Pseudo Elements are expanded");
+  ok(!view.element.children[1].hidden, "Pseudo Elements are expanded");
 
   expander.click();
-  ok(!view.element.firstChild.classList.contains("show-expandable-container"),
-     "Pseudo Elements are collapsed by twisty");
+  ok(view.element.children[1].hidden,
+    "Pseudo Elements are collapsed by twisty");
 
   expander.click();
-  ok(view.element.firstChild.classList.contains("show-expandable-container"),
-     "Pseudo Elements are expanded again");
+  ok(!view.element.children[1].hidden, "Pseudo Elements are expanded again");
 
   info("Make sure that dblclicking on the header container also toggles " +
        "the pseudo elements");
   EventUtils.synthesizeMouseAtCenter(gutters[0], {clickCount: 2},
                                      view.styleWindow);
-  ok(!view.element.firstChild.classList.contains("show-expandable-container"),
-     "Pseudo Elements are collapsed by dblclicking");
+  ok(view.element.children[1].hidden,
+    "Pseudo Elements are collapsed by dblclicking");
 
   let elementRuleView = getRuleViewRuleEditor(view, 3);
 
   let elementFirstLineRule = rules.firstLineRules[0];
   let elementFirstLineRuleView =
     [...view.element.children[1].children].filter(e => {
       return e._ruleEditor && e._ruleEditor.rule === elementFirstLineRule;
     })[0]._ruleEditor;
@@ -130,18 +128,18 @@ function* testTopRight(inspector, view) 
   let gutters = assertGutters(view);
 
   let expander = gutters[0].querySelector(".ruleview-expander");
   ok(!view.element.firstChild.classList.contains("show-expandable-container"),
      "Pseudo Elements remain collapsed after switching element");
 
   expander.scrollIntoView();
   expander.click();
-  ok(view.element.firstChild.classList.contains("show-expandable-container"),
-     "Pseudo Elements are shown again after clicking twisty");
+  ok(!view.element.children[1].hidden,
+    "Pseudo Elements are shown again after clicking twisty");
 }
 
 function* testBottomRight(inspector, view) {
   yield assertPseudoElementRulesNumbers("#bottomright", inspector, view, {
     elementRulesNb: 4,
     firstLineRulesNb: 1,
     firstLetterRulesNb: 1,
     selectionRulesNb: 0
--- a/devtools/client/inspector/rules/test/browser_rules_pseudo_lock_options.js
+++ b/devtools/client/inspector/rules/test/browser_rules_pseudo_lock_options.js
@@ -104,32 +104,28 @@ function* assertPseudoRemoved(inspector,
 function* assertPseudoPanelOpened(view) {
   info("Check the opened state of the pseudo class panel");
 
   ok(!view.pseudoClassPanel.hidden, "Pseudo Class Panel Opened");
   ok(!view.hoverCheckbox.disabled, ":hover checkbox is not disabled");
   ok(!view.activeCheckbox.disabled, ":active checkbox is not disabled");
   ok(!view.focusCheckbox.disabled, ":focus checkbox is not disabled");
 
-  is(view.pseudoClassPanel.getAttribute("tabindex"), "-1",
-    "Pseudo Class Panel has a tabindex of -1");
   is(view.hoverCheckbox.getAttribute("tabindex"), "0",
     ":hover checkbox has a tabindex of 0");
   is(view.activeCheckbox.getAttribute("tabindex"), "0",
     ":active checkbox has a tabindex of 0");
   is(view.focusCheckbox.getAttribute("tabindex"), "0",
     ":focus checkbox has a tabindex of 0");
 }
 
 function* assertPseudoPanelClosed(view) {
   info("Check the closed state of the pseudo clas panel");
 
   ok(view.pseudoClassPanel.hidden, "Pseudo Class Panel Hidden");
 
-  is(view.pseudoClassPanel.getAttribute("tabindex"), "-1",
-    "Pseudo Class Panel has a tabindex of -1");
   is(view.hoverCheckbox.getAttribute("tabindex"), "-1",
     ":hover checkbox has a tabindex of -1");
   is(view.activeCheckbox.getAttribute("tabindex"), "-1",
     ":active checkbox has a tabindex of -1");
   is(view.focusCheckbox.getAttribute("tabindex"), "-1",
     ":focus checkbox has a tabindex of -1");
 }
--- a/devtools/client/jar.mn
+++ b/devtools/client/jar.mn
@@ -172,18 +172,16 @@ devtools.jar:
     skin/images/command-paintflashing.png (themes/images/command-paintflashing.png)
     skin/images/command-paintflashing@2x.png (themes/images/command-paintflashing@2x.png)
     skin/images/command-screenshot.png (themes/images/command-screenshot.png)
     skin/images/command-screenshot@2x.png (themes/images/command-screenshot@2x.png)
     skin/images/command-responsivemode.png (themes/images/command-responsivemode.png)
     skin/images/command-responsivemode@2x.png (themes/images/command-responsivemode@2x.png)
     skin/images/command-scratchpad.png (themes/images/command-scratchpad.png)
     skin/images/command-scratchpad@2x.png (themes/images/command-scratchpad@2x.png)
-    skin/images/command-tilt.png (themes/images/command-tilt.png)
-    skin/images/command-tilt@2x.png (themes/images/command-tilt@2x.png)
     skin/images/command-pick.png (themes/images/command-pick.png)
     skin/images/command-pick@2x.png (themes/images/command-pick@2x.png)
     skin/images/command-frames.png (themes/images/command-frames.png)
     skin/images/command-frames@2x.png (themes/images/command-frames@2x.png)
     skin/images/command-console.png (themes/images/command-console.png)
     skin/images/command-console@2x.png (themes/images/command-console@2x.png)
     skin/images/command-eyedropper.png (themes/images/command-eyedropper.png)
     skin/images/command-eyedropper@2x.png (themes/images/command-eyedropper@2x.png)
--- a/devtools/client/locales/en-US/aboutdebugging.dtd
+++ b/devtools/client/locales/en-US/aboutdebugging.dtd
@@ -1,5 +1,5 @@
 <!-- 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/. -->
 
-<!ENTITY aboutDebugging.title                      "about:debugging">
+<!ENTITY aboutDebugging.fullTitle    "Debugging with Firefox Developer Tools">
--- a/devtools/client/locales/en-US/aboutdebugging.properties
+++ b/devtools/client/locales/en-US/aboutdebugging.properties
@@ -1,14 +1,15 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 debug = Debug
 push = Push
+start = Start
 
 addons = Add-ons
 addonDebugging.label = Enable add-on debugging
 addonDebugging.tooltip = Turning this on will allow you to debug add-ons and various other parts of the browser chrome
 addonDebugging.moreInfo = more info
 loadTemporaryAddon = Load Temporary Add-on
 extensions = Extensions
 selectAddonFromFile = Select Add-on Directory or XPI File
deleted file mode 100755
--- a/devtools/client/locales/en-US/tilt.properties
+++ /dev/null
@@ -1,49 +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/.
-
-# LOCALIZATION NOTE These strings are used inside the Tilt Inspector
-# which is available from the Web Developer sub-menu -> 'Tilt'.
-#
-# The correct localization of this file might be to keep it in
-# English, or another language commonly spoken among web developers.
-# You want to make that choice consistent across the developer tools.
-# A good criteria is the language in which you'd find the best
-# documentation on web development on the web.
-
-# LOCALIZATION NOTE (initTilt.error): Tilt requires WebGL capabilities, which
-# are not available on every hardware. This message is displayed as an modal
-# popup window when initialization fails because of unsupported hardware.
-initTilt.error = Could not initialize Tilt, please check the\ntroubleshooting information available at http://get.webgl.org/troubleshooting
-
-# LOCALIZATION NOTE (initWebGL.error): Tilt requires WebGL capabilities, which
-# are not available on every hardware. This message is displayed in the console
-# when initialization fails because of unsupported hardware.
-initWebGL.error = Could not initialize the WebGL context, your hardware or drivers may not support it.
-
-# LOCALIZATION NOTE (linkProgram.error): This error happens when the WebGL
-# context can't link two compiled shader programs together. It is displayed in
-# the Error Console.
-linkProgram.error = Could not initialize shader program: %S
-
-# LOCALIZATION NOTE (compileShader.source.error): This error is caused when the
-# source (uri or path) of a shader is not the expected one. It is displayed in
-# the Error Console.
-compileShader.source.error = Bad shader source type (expected String).
-
-# LOCALIATION NOTE (compileShader.type.error): There are two types of shader
-# programs - vertex and fragment. At a shader initialization, if none of these
-# two types is specified, this compile-time error is shown. It is displayed in
-# the Error Console.
-compileShader.type.error = Wrong shader type specified for: %S
-
-# LOCALIZATION NOTE (compileShader.compile.error): If the shader source and
-# type are correctly specified, there may be syntax errors in the shader code.
-# If this is the case, this compile-time error is shown. It is displayed in
-# the Error Console.
-compileShader.compile.error = Shader compile status:\n%S
-
-# LOCALIZATION NOTE (compileShader.source.error): This error is caused when the
-# source (canvas or image) of a texture is not as expected. It is displayed in
-# the Error Console.
-initTexture.source.error = Bad texture source type (expected Image).
--- a/devtools/client/memory/initializer.js
+++ b/devtools/client/memory/initializer.js
@@ -10,47 +10,43 @@ Cu.import("resource://devtools/client/sh
 const { require } = BrowserLoaderModule.BrowserLoader("resource://devtools/client/memory/", this);
 const { Task } = require("resource://gre/modules/Task.jsm");
 const { createFactory, createElement } = require("devtools/client/shared/vendor/react");
 const ReactDOM = require("devtools/client/shared/vendor/react-dom");
 const { Provider } = require("devtools/client/shared/vendor/react-redux");
 const App = createFactory(require("devtools/client/memory/app"));
 const Store = require("devtools/client/memory/store");
 const { assert } = require("devtools/shared/DevToolsUtils");
-const Telemetry = require("devtools/client/shared/telemetry");
 
 /**
  * The current target, toolbox, MemoryFront, and HeapAnalysesClient, set by this tool's host.
  */
 var gToolbox, gTarget, gFront, gHeapAnalysesClient;
 
 /**
  * Variables set by `initialize()`
  */
 var gStore, gRoot, gApp, gProvider, unsubscribe, isHighlighted, telemetry;
 
 var initialize = Task.async(function*() {
-  telemetry = new Telemetry();
-  telemetry.toolOpened("memory");
   gRoot = document.querySelector("#app");
   gStore = Store();
   gApp = createElement(App, { toolbox: gToolbox, front: gFront, heapWorker: gHeapAnalysesClient });
   gProvider = createElement(Provider, { store: gStore }, gApp);
   ReactDOM.render(gProvider, gRoot);
   unsubscribe = gStore.subscribe(onStateChange);
 });
 
 var destroy = Task.async(function*() {
   const ok = ReactDOM.unmountComponentAtNode(gRoot);
   assert(ok, "Should successfully unmount the memory tool's top level React component");
 
-  telemetry.toolClosed("memory");
   unsubscribe();
 
-  gStore, gRoot, gApp, gProvider, unsubscribe, isHighlighted, telemetry = null;
+  gStore, gRoot, gApp, gProvider, unsubscribe, isHighlighted;
 });
 
 /**
  * Fired on any state change, currently only handles toggling
  * the highlighting of the tool when recording allocations.
  */
 function onStateChange () {
   let isRecording = gStore.getState().allocations.recording;
--- a/devtools/client/moz.build
+++ b/devtools/client/moz.build
@@ -28,17 +28,16 @@ DIRS += [
     'scratchpad',
     'shadereditor',
     'shared',
     'shims',
     'sourceeditor',
     'storage',
     'styleeditor',
     'themes',
-    'tilt',
     'webaudioeditor',
     'webconsole',
     'webide',
 ]
 
 # Shim old theme paths used by DevTools add-ons
 if CONFIG['MOZ_BUILD_APP'] == 'browser':
     DIRS += ['themes/shims']
--- a/devtools/client/preferences/devtools.js
+++ b/devtools/client/preferences/devtools.js
@@ -28,28 +28,27 @@ pref("devtools.toolbar.visible", false);
 pref("devtools.webide.enabled", true);
 
 // Toolbox preferences
 pref("devtools.toolbox.footer.height", 250);
 pref("devtools.toolbox.sidebar.width", 500);
 pref("devtools.toolbox.host", "bottom");
 pref("devtools.toolbox.previousHost", "side");
 pref("devtools.toolbox.selectedTool", "webconsole");
-pref("devtools.toolbox.toolbarSpec", '["splitconsole", "paintflashing toggle","tilt toggle","scratchpad","resize toggle","eyedropper","screenshot --fullpage", "rulers", "measure"]');
+pref("devtools.toolbox.toolbarSpec", '["splitconsole", "paintflashing toggle","scratchpad","resize toggle","eyedropper","screenshot --fullpage", "rulers", "measure"]');
 pref("devtools.toolbox.sideEnabled", true);
 pref("devtools.toolbox.zoomValue", "1");
 pref("devtools.toolbox.splitconsoleEnabled", false);
 pref("devtools.toolbox.splitconsoleHeight", 100);
 
 // Toolbox Button preferences
 pref("devtools.command-button-pick.enabled", true);
 pref("devtools.command-button-frames.enabled", true);
 pref("devtools.command-button-splitconsole.enabled", true);
 pref("devtools.command-button-paintflashing.enabled", false);
-pref("devtools.command-button-tilt.enabled", false);
 pref("devtools.command-button-scratchpad.enabled", false);
 pref("devtools.command-button-responsive.enabled", true);
 pref("devtools.command-button-eyedropper.enabled", false);
 pref("devtools.command-button-screenshot.enabled", false);
 pref("devtools.command-button-rulers.enabled", false);
 pref("devtools.command-button-measure.enabled", false);
 pref("devtools.command-button-noautohide.enabled", false);
 
@@ -167,21 +166,16 @@ pref("devtools.netmonitor.har.defaultFil
 pref("devtools.netmonitor.har.jsonp", false);
 pref("devtools.netmonitor.har.jsonpCallback", "");
 pref("devtools.netmonitor.har.includeResponseBodies", true);
 pref("devtools.netmonitor.har.compress", false);
 pref("devtools.netmonitor.har.forceExport", false);
 pref("devtools.netmonitor.har.pageLoadedTimeout", 1500);
 pref("devtools.netmonitor.har.enableAutoExportToFile", false);
 
-// Enable the Tilt inspector
-pref("devtools.tilt.enabled", true);
-pref("devtools.tilt.intro_transition", true);
-pref("devtools.tilt.outro_transition", true);
-
 // Scratchpad settings
 // - recentFileMax: The maximum number of recently-opened files
 //                  stored. Setting this preference to 0 will not
 //                  clear any recent files, but rather hide the
 //                  'Open Recent'-menu.
 // - lineNumbers: Whether to show line numbers or not.
 // - wrapText: Whether to wrap text or not.
 // - showTrailingSpace: Whether to highlight trailing space or not.
--- a/devtools/client/scratchpad/scratchpad.js
+++ b/devtools/client/scratchpad/scratchpad.js
@@ -40,17 +40,16 @@ const EDITOR_FONT_SIZE = "devtools.scrat
 const ENABLE_AUTOCOMPLETION = "devtools.scratchpad.enableAutocompletion";
 const TAB_SIZE = "devtools.editor.tabsize";
 const FALLBACK_CHARSET_LIST = "intl.fallbackCharsetList.ISO-8859-1";
 
 const VARIABLES_VIEW_URL = "chrome://devtools/content/shared/widgets/VariablesView.xul";
 
 const {require, loader} = Cu.import("resource://devtools/shared/Loader.jsm", {});
 
-const Telemetry = require("devtools/client/shared/telemetry");
 const Editor    = require("devtools/client/sourceeditor/editor");
 const TargetFactory = require("devtools/client/framework/target").TargetFactory;
 const EventEmitter = require("devtools/shared/event-emitter");
 const {DevToolsWorker} = require("devtools/shared/worker/worker");
 const DevToolsUtils = require("devtools/shared/DevToolsUtils");
 const promise = require("promise");
 const Services = require("Services");
 const {gDevTools} = require("devtools/client/framework/devtools");
@@ -87,21 +86,16 @@ XPCOMUtils.defineLazyGetter(this, "REMOT
   Services.prefs.getIntPref("devtools.debugger.remote-timeout"));
 
 XPCOMUtils.defineLazyModuleGetter(this, "ShortcutUtils",
   "resource://gre/modules/ShortcutUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Reflect",
   "resource://gre/modules/reflect.jsm");
 
-// Because we have no constructor / destructor where we can log metrics we need
-// to do so here.
-var telemetry = new Telemetry();
-telemetry.toolOpened("scratchpad");
-
 var WebConsoleUtils = require("devtools/shared/webconsole/utils").Utils;
 
 /**
  * The scratchpad object handles the Scratchpad window functionality.
  */
 var Scratchpad = {
   _instanceId: null,
   _initialWindowTitle: document.title,
@@ -1918,17 +1912,16 @@ var Scratchpad = {
 
     this.promptSave((aShouldClose, aSaved, aStatus) => {
        shouldClose = aShouldClose;
       if (aSaved && !Components.isSuccessCode(aStatus)) {
         shouldClose = false;
       }
 
       if (shouldClose) {
-        telemetry.toolClosed("scratchpad");
         window.close();
       }
 
       if (aCallback) {
         aCallback(shouldClose);
       }
     });
 
--- a/devtools/client/shadereditor/shadereditor.js
+++ b/devtools/client/shadereditor/shadereditor.js
@@ -12,18 +12,16 @@ Cu.import("resource://devtools/client/sh
 Cu.import("resource://gre/modules/Console.jsm");
 
 const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
 const promise = require("promise");
 const Services = require("Services");
 const EventEmitter = require("devtools/shared/event-emitter");
 const {Tooltip} = require("devtools/client/shared/widgets/Tooltip");
 const Editor = require("devtools/client/sourceeditor/editor");
-const Telemetry = require("devtools/client/shared/telemetry");
-const telemetry = new Telemetry();
 
 // The panel's window global is an EventEmitter firing the following events:
 const EVENTS = {
   // When new programs are received from the server.
   NEW_PROGRAM: "ShaderEditor:NewProgram",
   PROGRAMS_ADDED: "ShaderEditor:ProgramsAdded",
 
   // When the vertex and fragment sources were shown in the editor.
@@ -82,34 +80,32 @@ function shutdownShaderEditor() {
 /**
  * Functions handling target-related lifetime events.
  */
 var EventsHandler = {
   /**
    * Listen for events emitted by the current tab target.
    */
   initialize: function() {
-    telemetry.toolOpened("shadereditor");
     this._onHostChanged = this._onHostChanged.bind(this);
     this._onTabNavigated = this._onTabNavigated.bind(this);
     this._onProgramLinked = this._onProgramLinked.bind(this);
     this._onProgramsAdded = this._onProgramsAdded.bind(this);
     gToolbox.on("host-changed", this._onHostChanged);
     gTarget.on("will-navigate", this._onTabNavigated);
     gTarget.on("navigate", this._onTabNavigated);
     gFront.on("program-linked", this._onProgramLinked);
     this.reloadButton = $("#requests-menu-reload-notice-button");
     this.reloadButton.addEventListener("command", this._onReloadCommand);
   },
 
   /**
    * Remove events emitted by the current tab target.
    */
   destroy: function() {
-    telemetry.toolClosed("shadereditor");
     gToolbox.off("host-changed", this._onHostChanged);
     gTarget.off("will-navigate", this._onTabNavigated);
     gTarget.off("navigate", this._onTabNavigated);
     gFront.off("program-linked", this._onProgramLinked);
     this.reloadButton.removeEventListener("command", this._onReloadCommand);
   },
 
   /**
--- a/devtools/client/shadereditor/test/head.js
+++ b/devtools/client/shadereditor/test/head.js
@@ -9,19 +9,19 @@ var { require } = Cu.import("resource://
 
 var Services = require("Services");
 var promise = require("promise");
 var { gDevTools } = require("devtools/client/framework/devtools");
 var { DebuggerClient } = require("devtools/shared/client/main");
 var { DebuggerServer } = require("devtools/server/main");
 var { WebGLFront } = require("devtools/server/actors/webgl");
 var DevToolsUtils = require("devtools/shared/DevToolsUtils");
-var TiltGL = require("devtools/client/tilt/tilt-gl");
-var {TargetFactory} = require("devtools/client/framework/target");
-var {Toolbox} = require("devtools/client/framework/toolbox");
+var { TargetFactory } = require("devtools/client/framework/target");
+var { Toolbox } = require("devtools/client/framework/toolbox");
+var { isWebGLSupported } = require("devtools/client/shared/webgl-utils");
 var mm = null;
 
 const FRAME_SCRIPT_UTILS_URL = "chrome://devtools/content/shared/frame-script-utils.js"
 const EXAMPLE_URL = "http://example.com/browser/devtools/client/shadereditor/test/";
 const SIMPLE_CANVAS_URL = EXAMPLE_URL + "doc_simple-canvas.html";
 const SHADER_ORDER_URL = EXAMPLE_URL + "doc_shader-order.html";
 const MULTIPLE_CONTEXTS_URL = EXAMPLE_URL + "doc_multiple-contexts.html";
 const OVERLAPPING_GEOMETRY_CANVAS_URL = EXAMPLE_URL + "doc_overlapping-geometry.html";
@@ -113,34 +113,24 @@ function ifWebGLSupported() {
 }
 
 function ifWebGLUnsupported() {
   todo(false, "Skipping test because WebGL isn't supported.");
   finish();
 }
 
 function test() {
-  let generator = isWebGLSupported() ? ifWebGLSupported : ifWebGLUnsupported;
+  let generator = isWebGLSupported(document) ? ifWebGLSupported : ifWebGLUnsupported;
   Task.spawn(generator).then(null, handleError);
 }
 
 function createCanvas() {
   return document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
 }
 
-function isWebGLSupported() {
-  let supported =
-    !TiltGL.isWebGLForceEnabled() &&
-     TiltGL.isWebGLSupported() &&
-     TiltGL.create3DContext(createCanvas());
-
-  info("Apparently, WebGL is" + (supported ? "" : " not") + " supported.");
-  return supported;
-}
-
 function once(aTarget, aEventName, aUseCapture = false) {
   info("Waiting for event: '" + aEventName + "' on " + aTarget + ".");
 
   let deferred = promise.defer();
 
   for (let [add, remove] of [
     ["on", "off"], // Use event emitter before DOM events for consistency
     ["addEventListener", "removeEventListener"],
--- a/devtools/client/shared/components/h-split-box.js
+++ b/devtools/client/shared/components/h-split-box.js
@@ -64,21 +64,29 @@ module.exports = createClass({
 
     // A callback fired when the user drags the splitter to resize the relative
     // pane widths. The function is passed the startWidth value that would put
     // the splitter underneath the users mouse.
     onResize: PropTypes.func.isRequired,
   },
 
   _onMouseDown(event) {
+    if (event.button !== 0) {
+      return;
+    }
+
     this.setState({ mouseDown: true });
     event.preventDefault();
   },
 
   _onMouseUp(event) {
+    if (event.button !== 0 || !this.state.mouseDown) {
+      return;
+    }
+
     this.setState({ mouseDown: false });
     event.preventDefault();
   },
 
   _onMouseMove(event) {
     if (!this.state.mouseDown) {
       return;
     }
--- a/devtools/client/shared/components/test/mochitest/test_HSplitBox_01.html
+++ b/devtools/client/shared/components/test/mochitest/test_HSplitBox_01.html
@@ -75,17 +75,17 @@ window.onload = Task.async(function* () 
     is(newSizes.length, 0, "Mouse moves without dragging the splitter should have no effect");
 
     // Send a mouse down on the splitter, and then move the mouse a couple
     // times. Now we should get resizes.
 
     const splitter = document.querySelector(".h-split-box-splitter");
     ok(splitter, "Should get our splitter");
 
-    synthesizeMouseAtCenter(splitter, { button: 1, type: "mousedown" }, window);
+    synthesizeMouseAtCenter(splitter, { button: 0, type: "mousedown" }, window);
 
     function mouseMove(clientX) {
       const event = new MouseEvent("mousemove", { clientX });
       document.defaultView.top.dispatchEvent(event);
     }
 
     mouseMove(middle);
     is(newSizes.length, 1, "Should get 1 resize");
@@ -98,17 +98,17 @@ window.onload = Task.async(function* () 
     mouseMove(oneQuarter);
     is(newSizes.length, 3, "Sould get 3 resizes");
     ok(aboutEq(newSizes[2], .25), "New size should be ~.25");
 
     mouseMove(threeQuarters);
     is(newSizes.length, 4, "Should get 4 resizes");
     ok(aboutEq(newSizes[3], .75), "New size should be ~.75");
 
-    synthesizeMouseAtCenter(splitter, { button: 1, type: "mouseup" }, window);
+    synthesizeMouseAtCenter(splitter, { button: 0, type: "mouseup" }, window);
 
     // Now that we have let go of the splitter, mouse moves should not result in resizes.
 
     synthesizeMouse(container, middle, top, { type: "mousemove" }, window);
     is(newSizes.length, 4, "Should still have 4 resizes");
 
   } catch(e) {
     ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
--- a/devtools/client/shared/moz.build
+++ b/devtools/client/shared/moz.build
@@ -38,9 +38,10 @@ DevToolsModules(
     'poller.js',
     'source-utils.js',
     'SplitView.jsm',
     'telemetry.js',
     'theme-switching.js',
     'theme.js',
     'undo.js',
     'view-source.js',
+    'webgl-utils.js',
 )
--- a/devtools/client/shared/telemetry.js
+++ b/devtools/client/shared/telemetry.js
@@ -155,21 +155,16 @@ Telemetry.prototype = {
       userHistogram: "DEVTOOLS_NETMONITOR_OPENED_PER_USER_FLAG",
       timerHistogram: "DEVTOOLS_NETMONITOR_TIME_ACTIVE_SECONDS"
     },
     storage: {
       histogram: "DEVTOOLS_STORAGE_OPENED_COUNT",
       userHistogram: "DEVTOOLS_STORAGE_OPENED_PER_USER_FLAG",
       timerHistogram: "DEVTOOLS_STORAGE_TIME_ACTIVE_SECONDS"
     },
-    tilt: {
-      histogram: "DEVTOOLS_TILT_OPENED_COUNT",
-      userHistogram: "DEVTOOLS_TILT_OPENED_PER_USER_FLAG",
-      timerHistogram: "DEVTOOLS_TILT_TIME_ACTIVE_SECONDS"
-    },
     paintflashing: {
       histogram: "DEVTOOLS_PAINTFLASHING_OPENED_COUNT",
       userHistogram: "DEVTOOLS_PAINTFLASHING_OPENED_PER_USER_FLAG",
       timerHistogram: "DEVTOOLS_PAINTFLASHING_TIME_ACTIVE_SECONDS"
     },
     scratchpad: {
       histogram: "DEVTOOLS_SCRATCHPAD_OPENED_COUNT",
       userHistogram: "DEVTOOLS_SCRATCHPAD_OPENED_PER_USER_FLAG",
--- a/devtools/client/shared/test/browser.ini
+++ b/devtools/client/shared/test/browser.ini
@@ -131,19 +131,16 @@ skip-if = e10s # Test intermittently fai
 [browser_tableWidget_keyboard_interaction.js]
 [browser_tableWidget_mouse_interaction.js]
 [browser_telemetry_button_eyedropper.js]
 [browser_telemetry_button_paintflashing.js]
 skip-if = e10s # Bug 937167 - e10s paintflashing
 [browser_telemetry_button_responsive.js]
 skip-if = e10s # Bug 1067145 - e10s responsiveview
 [browser_telemetry_button_scratchpad.js]
-[browser_telemetry_button_tilt.js]
-skip-if = e10s # Bug 1086492 - Disable tilt for e10s
-               # Bug 937166 - Make tilt work in E10S mode
 [browser_telemetry_sidebar.js]
 [browser_telemetry_toolbox.js]
 [browser_telemetry_toolboxtabs_canvasdebugger.js]
 [browser_telemetry_toolboxtabs_inspector.js]
 [browser_telemetry_toolboxtabs_jsdebugger.js]
 [browser_telemetry_toolboxtabs_jsprofiler.js]
 [browser_telemetry_toolboxtabs_netmonitor.js]
 [browser_telemetry_toolboxtabs_options.js]
deleted file mode 100644
--- a/devtools/client/shared/test/browser_telemetry_button_tilt.js
+++ /dev/null
@@ -1,110 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-const TEST_URI = "data:text/html;charset=utf-8," +
-  "<p>browser_telemetry_button_tilt.js</p>";
-
-// Because we need to gather stats for the period of time that a tool has been
-// opened we make use of setTimeout() to create tool active times.
-const TOOL_DELAY = 200;
-
-add_task(function*() {
-  yield addTab(TEST_URI);
-  let Telemetry = loadTelemetryAndRecordLogs();
-
-  let target = TargetFactory.forTab(gBrowser.selectedTab);
-  let toolbox = yield gDevTools.showToolbox(target, "inspector");
-
-  // Wait for the inspector to be initialized
-  yield toolbox.getPanel("inspector").once("inspector-updated");
-
-  info("inspector opened");
-
-  info("testing the tilt button");
-  yield testButton(toolbox, Telemetry);
-
-  stopRecordingTelemetryLogs(Telemetry);
-
-  yield gDevTools.closeToolbox(target);
-  gBrowser.removeCurrentTab();
-});
-
-function* testButton(toolbox, Telemetry) {
-  info("Testing command-button-tilt");
-
-  let button = toolbox.doc.querySelector("#command-button-tilt");
-  ok(button, "Captain, we have the button");
-
-  yield delayedClicks(button, 4)
-
-  checkResults("_TILT_", Telemetry);
-}
-
-function delayedClicks(node, clicks) {
-  return new Promise(resolve => {
-    let clicked = 0;
-
-    // See TOOL_DELAY for why we need setTimeout here
-    setTimeout(function delayedClick() {
-      if (clicked >= clicks) {
-        resolve();
-        return;
-      }
-      info("Clicking button " + node.id);
-
-      // Depending on odd/even click we are either opening
-      // or closing tilt
-      let event;
-      if (clicked % 2 == 0) {
-        info("Waiting for opening\n");
-        event = "tilt-initialized";
-      } else {
-        dump("Waiting for closing\n");
-        event = "tilt-destroyed";
-      }
-      let f = function () {
-        Services.obs.removeObserver(f, event, false);
-        setTimeout(delayedClick, 200);
-      };
-      Services.obs.addObserver(f, event, false);
-
-      clicked++;
-      node.click();
-    }, TOOL_DELAY);
-  });
-}
-
-function checkResults(histIdFocus, Telemetry) {
-  let result = Telemetry.prototype.telemetryInfo;
-
-  for (let [histId, value] of Iterator(result)) {
-    if (histId.startsWith("DEVTOOLS_INSPECTOR_") ||
-        !histId.includes(histIdFocus)) {
-      // Inspector stats are tested in
-      // browser_telemetry_toolboxtabs_{toolname}.js so we skip them here
-      // because we only open the inspector once for this test.
-      continue;
-    }
-
-    if (histId.endsWith("OPENED_PER_USER_FLAG")) {
-      ok(value.length === 1 && value[0] === true,
-         "Per user value " + histId + " has a single value of true");
-    } else if (histId.endsWith("OPENED_COUNT")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element === true;
-      });
-
-      ok(okay, "All " + histId + " entries are === true");
-    } else if (histId.endsWith("TIME_ACTIVE_SECONDS")) {
-      ok(value.length > 1, histId + " has more than one entry");
-
-      let okay = value.every(function(element) {
-        return element > 0;
-      });
-
-      ok(okay, "All " + histId + " entries have time > 0");
-    }
-  }
-}
new file mode 100644
--- /dev/null
+++ b/devtools/client/shared/webgl-utils.js
@@ -0,0 +1,58 @@
+/* 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 } = require("chrome");
+const Services = require("Services");
+
+const WEBGL_CONTEXT_NAME = "experimental-webgl";
+
+function isWebGLForceEnabled()
+{
+  return Services.prefs.getBoolPref("webgl.force-enabled");
+}
+
+function isWebGLSupportedByGFX()
+{
+  let supported = false;
+
+  try {
+    let gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
+    let angle = gfxInfo.FEATURE_WEBGL_ANGLE;
+    let opengl = gfxInfo.FEATURE_WEBGL_OPENGL;
+
+    // if either the Angle or OpenGL renderers are available, WebGL should work
+    supported = gfxInfo.getFeatureStatus(angle) === gfxInfo.FEATURE_STATUS_OK ||
+                gfxInfo.getFeatureStatus(opengl) === gfxInfo.FEATURE_STATUS_OK;
+  } catch(e) {
+    return false;
+  }
+  return supported;
+}
+
+function create3DContext(aCanvas)
+{
+  // try to get a valid context from an existing canvas
+  let context = null;
+  try {
+    context = aCanvas.getContext(WEBGL_CONTEXT_NAME, aFlags);
+  } catch(e) {
+    return null;
+  }
+  return context;
+}
+
+function createCanvas(doc) {
+  return doc.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
+}
+
+function isWebGLSupported(doc) {
+  let supported =
+    !isWebGLForceEnabled() &&
+     isWebGLSupportedByGFX() &&
+     create3DContext(createCanvas(doc));
+
+  return supported;
+}
+exports.isWebGLSupported = isWebGLSupported;
--- a/devtools/client/shared/widgets/TableWidget.js
+++ b/devtools/client/shared/widgets/TableWidget.js
@@ -447,21 +447,21 @@ TableWidget.prototype = {
    *
    * @param {String} value: The filter value
    * @param {Array} ignoreProps: Props to ignore while filtering
    */
   filterItems(value, ignoreProps = []) {
     if (this.filteredValue == value) {
       return;
     }
+    this.filteredValue = value;
     if (!value) {
       this.emit(EVENTS.TABLE_FILTERED, []);
       return;
     }
-    this.filteredValue = value;
     // Shouldn't be case-sensitive
     value = value.toLowerCase();
 
     let itemsToHide = [...this.items.keys()];
     // Loop through all items and hide unmatched items
     for (let [id, val] of this.items) {
       for (let prop in val) {
         if (ignoreProps.includes(prop)) {
--- a/devtools/client/storage/storage.xul
+++ b/devtools/client/storage/storage.xul
@@ -25,16 +25,17 @@
   <box flex="1" class="devtools-responsive-container theme-body">
     <vbox id="storage-tree"/>
     <splitter class="devtools-side-splitter"/>
     <vbox flex="1">
       <hbox id="storage-toolbar" class="devtools-toolbar">
         <textbox id="storage-searchbox"
                  class="devtools-searchinput"
                  type="search"
+                 timeout="200"
                  placeholder="&searchBox.placeholder;"/>
       </hbox>
       <vbox id="storage-table" class="theme-sidebar" flex="1"/>
     </vbox>
     <splitter class="devtools-side-splitter"/>
     <vbox id="storage-sidebar" class="devtools-sidebar-tabs" hidden="true">
       <vbox flex="1"/>
     </vbox>
--- a/devtools/client/storage/ui.js
+++ b/devtools/client/storage/ui.js
@@ -12,18 +12,16 @@ loader.lazyRequireGetter(this, "TreeWidg
                          "devtools/client/shared/widgets/TreeWidget", true);
 loader.lazyRequireGetter(this, "TableWidget",
                          "devtools/client/shared/widgets/TableWidget", true);
 loader.lazyImporter(this, "ViewHelpers",
   "resource://devtools/client/shared/widgets/ViewHelpers.jsm");
 loader.lazyImporter(this, "VariablesView",
   "resource://devtools/client/shared/widgets/VariablesView.jsm");
 
-const Telemetry = require("devtools/client/shared/telemetry");
-
 /**
  * Localization convenience methods.
  */
 const STORAGE_STRINGS = "chrome://devtools/locale/storage.properties";
 const L10N = new ViewHelpers.L10N(STORAGE_STRINGS);
 
 const GENERIC_VARIABLES_VIEW_SETTINGS = {
   lazyEmpty: true,
@@ -78,32 +76,29 @@ var StorageUI = this.StorageUI = functio
 
   this.sidebar = this._panelDoc.getElementById("storage-sidebar");
   this.sidebar.setAttribute("width", "300");
   this.view = new VariablesView(this.sidebar.firstChild,
                                 GENERIC_VARIABLES_VIEW_SETTINGS);
 
   this.searchBox = this._panelDoc.getElementById("storage-searchbox");
   this.filterItems = this.filterItems.bind(this);
-  this.searchBox.addEventListener("input", this.filterItems);
+  this.searchBox.addEventListener("command", this.filterItems);
 
   this.front.listStores().then(storageTypes => {
     this.populateStorageTree(storageTypes);
   }).then(null, console.error);
 
   this.onUpdate = this.onUpdate.bind(this);
   this.front.on("stores-update", this.onUpdate);
   this.onCleared = this.onCleared.bind(this);
   this.front.on("stores-cleared", this.onCleared);
 
   this.handleKeypress = this.handleKeypress.bind(this);
   this._panelDoc.addEventListener("keypress", this.handleKeypress);
-
-  this._telemetry = new Telemetry();
-  this._telemetry.toolOpened("storage");
 };
 
 exports.StorageUI = StorageUI;
 
 StorageUI.prototype = {
 
   storageTypes: null,
   shouldResetColumns: true,
@@ -114,17 +109,16 @@ StorageUI.prototype = {
   },
 
   destroy: function() {
     this.front.off("stores-update", this.onUpdate);
     this.front.off("stores-cleared", this.onCleared);
     this._panelDoc.removeEventListener("keypress", this.handleKeypress);
     this.searchBox.removeEventListener("input", this.filterItems);
     this.searchBox = null;
-    this._telemetry.toolClosed("storage");
   },
 
   /**
    * Empties and hides the object viewer sidebar
    */
   hideSidebar: function() {
     this.view.empty();
     this.sidebar.hidden = true;
--- a/devtools/client/themes/computed.css
+++ b/devtools/client/themes/computed.css
@@ -9,16 +9,20 @@
   flex-direction: column;
   width: 100%;
   /* Bug 1243598 - Reduce the container height by the tab height to make room
      for the tabs above. */
   height: calc(100% - 24px);
   position: absolute;
 }
 
+#sidebar-panel-computedview > .devtools-toolbar {
+  display: flex;
+}
+
 #browser-style-checkbox {
   /* Bug 1200073 - extra space before the browser styles checkbox so
      they aren't squished together in a small window. */
   -moz-margin-start: 5px;
 }
 
 #propertyContainer {
   -moz-user-select: text;
@@ -137,21 +141,16 @@
 .onlyuserstyles {
   cursor: pointer;
 }
 
 .legendKey {
   margin: 0 5px;
 }
 
-#root .devtools-toolbar {
-  width: 100%;
-  display: flex;
-}
-
 .link {
   padding: 0 3px;
   cursor: pointer;
   float: right;
 }
 
 /* Take away these two :visited rules to get a core dumper     */
 /* See https://bugzilla.mozilla.org/show_bug.cgi?id=575675#c30 */
--- a/devtools/client/themes/fonts.css
+++ b/devtools/client/themes/fonts.css
@@ -9,16 +9,20 @@
   padding-bottom: 20px;
   width: 100%;
   /* Bug 1243598 - Reduce the container height by the tab height to make room
      for the tabs above. */
   height: calc(100% - 24px);
   position: absolute;
 }
 
+#sidebar-panel-fontinspector > .devtools-toolbar {
+  display: flex;
+}
+
 #font-container {
   overflow: auto;
   flex: auto;
 }
 
 #all-fonts {
   padding: 0;
   margin: 0;
deleted file mode 100644
index 841aac23f5292d3748ccf99b1ce469ca886afaca..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 8a13a9e08bf92f5163f0d190ed6bf8479771e3b0..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/devtools/client/themes/layout.css
+++ b/devtools/client/themes/layout.css
@@ -1,14 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/ */
 
 #sidebar-panel-layoutview {
   display: block;
+  overflow: auto;
 }
 
 #layout-container {
   /* The view will grow bigger as the window gets resized, until 400px */
   max-width: 400px;
   margin: 0px auto;
   padding: 0;
   /* "Contain" the absolutely positioned #layout-main element */
@@ -36,17 +37,17 @@
 #layout-element-size {
   -moz-box-flex: 1;
 }
 
 #layout-element-size:-moz-dir(rtl) {
   -moz-box-pack: end;
 }
 
-@media (max-height: 228px) {
+@media (max-height: 250px) {
   #layout-header {
     padding-top: 0;
     padding-bottom: 0;
     margin-top: 10px;
     margin-bottom: 8px;
   }
 }
 
@@ -86,17 +87,17 @@
 
 #layout-margins {
   /* This opacity applies to all of the regions, since they are nested */
   opacity: .8;
 }
 
 /* Respond to window size change by changing the size of the regions */
 
-@media (max-height: 228px) {
+@media (max-height: 250px) {
   #layout-content {
     height: 18px;
   }
 
   #layout-margins,
   #layout-borders,
   #layout-padding {
     border-width: 18px;
@@ -222,17 +223,17 @@
 
 .layout-rotate.layout-right:not(.layout-editing) {
   transform: rotate(90deg);
 }
 
 /* Coordinates should be different when the window is small, because we make
    the regions smaller then */
 
-@media (max-height: 228px) {
+@media (max-height: 250px) {
   .layout-padding.layout-top {
     top: 37px;
   }
 
   .layout-padding.layout-bottom {
     bottom: 38px;
   }
 
@@ -295,17 +296,17 @@
   margin: 5px 6px;
   z-index: 1;
 }
 
 .layout-legend[data-box="margin"] {
   color: var(--theme-highlight-blue);
 }
 
-@media (max-height: 228px) {
+@media (max-height: 250px) {
   .layout-legend {
     margin: 2px 6px;
   }
 }
 
 /* Editable fields */
 
 .layout-editable {
--- a/devtools/client/themes/memory.css
+++ b/devtools/client/themes/memory.css
@@ -176,23 +176,29 @@ html, body, #app, #memory-tool {
   /**
    * Flex: contains several children, which need to be laid out vertically.
    */
   display: flex;
   flex-direction: column;
   color: var(--theme-body-color);
   border-bottom: 1px solid rgba(128,128,128,0.15);
   padding: 8px;
+  cursor: default;
 }
 
 .snapshot-list-item.selected {
   background-color: var(--theme-selection-background);
   color: var(--theme-selection-color);
 }
 
+.snapshot-list-item.selected ::-moz-selection {
+  background-color: var(--theme-selection-color);
+  color: var(--theme-selection-background);
+}
+
 .snapshot-list-item .snapshot-info {
   display: flex;
   justify-content: space-between;
   font-size: 90%;
 }
 
 .snapshot-list-item .save {
   text-decoration: underline;
@@ -360,16 +366,17 @@ html, body, #app, #memory-tool {
   flex: 1;
   overflow-y: auto;
   background-color: var(--theme-body-background);
 }
 
 .tree-node {
   height: var(--heap-tree-row-height);
   line-height: var(--heap-tree-row-height);
+  cursor: default;
 }
 
 .children-pointer {
   padding-inline-end: 5px;
 }
 
 /**
  * Heap tree view columns
@@ -392,16 +399,21 @@ html, body, #app, #memory-tool {
   background-color: var(--row-hover-background-color);
 }
 
 .heap-tree-item.focused {
   background-color: var(--theme-selection-background);
   color: var(--theme-selection-color);
 }
 
+.heap-tree-item.focused ::-moz-selection {
+  background-color: var(--theme-selection-color);
+  color: var(--theme-selection-background);
+}
+
 .heap-tree-item-bytes,
 .heap-tree-item-count,
 .heap-tree-item-total-bytes,
 .heap-tree-item-total-count {
   /**
    * Flex: contains several subcolumns, which need to be laid out horizontally.
    * These subcolumns may have specific widths or need to flex.
    */
--- a/devtools/client/themes/rules.css
+++ b/devtools/client/themes/rules.css
@@ -8,79 +8,95 @@
   --rule-filter-icon: url(images/magnifying-glass-light.png);
 }
 
 .theme-dark {
   --rule-highlight-background-color: #594724;
   --rule-filter-icon: url(images/magnifying-glass.png);
 }
 
+/* Rule View Tabpanel */
+
 #sidebar-panel-ruleview {
   margin: 0;
   display: flex;
   flex-direction: column;
   width: 100%;
   /* Bug 1243598 - Reduce the container height by the tab height to make room
      for the tabs above. */
   height: calc(100% - 24px);
   position: absolute;
 }
 
+/* Rule View Toolbar */
+
+#ruleview-toolbar-container {
+  display: flex;
+  flex-direction: column;
+  height: auto;
+}
+
+#ruleview-toolbar {
+  display: flex;
+  height: 23px;
+}
+
+#ruleview-toolbar > .devtools-searchbox:first-child {
+  -moz-padding-start: 0px;
+}
+
+#ruleview-command-toolbar {
+  display: flex;
+}
+
+#pseudo-class-panel {
+  display: flex;
+  height: 24px;
+  overflow: hidden;
+  transition: height 150ms ease;
+}
+
+#pseudo-class-panel[hidden] {
+  height: 0px;
+}
+
+#pseudo-class-panel > label {
+  -moz-user-select: none;
+  flex-grow: 1;
+  display: flex;
+  align-items: center;
+}
+
+/* Rule View Container */
+
 #ruleview-container {
   -moz-user-select: text;
   overflow: auto;
   flex: auto;
 }
 
 #ruleview-container.non-interactive {
   pointer-events: none;
   visibility: collapse;
   transition: visibility 0.25s;
 }
 
-.devtools-sidebar-toolbar {
-  display: flex;
-}
-
-#pseudo-class-panel {
-  position: relative;
-  margin-top: -1px;
-  margin-bottom: -1px;
-  overflow-y: hidden;
-  max-height: 24px;
-  outline: 0 !important;
-  transition-property: max-height;
-  transition-duration: 150ms;
-  transition-timing-function: ease;
-}
-
-#pseudo-class-panel[hidden] {
-  max-height: 0px;
-}
-
-#pseudo-class-panel > label {
-  -moz-user-select: none;
-  flex-grow: 1;
-  display: flex;
-  align-items: center;
-}
-
 .ruleview-code {
   direction: ltr;
 }
 
 .ruleview-property:not(:hover) > .ruleview-enableproperty {
   pointer-events: none;
 }
 
-.ruleview-expandable-container {
+.ruleview-expandable-container[hidden] {
   display: none;
 }
 
-.show-expandable-container + .ruleview-expandable-container {
+.ruleview-expandable-container {
   display: block;
 }
 
 .ruleview-namecontainer {
   cursor: text;
 }
 
 .ruleview-propertyvaluecontainer {
@@ -130,16 +146,17 @@
   border-top-style: solid;
   border-bottom-style: solid;
   padding: 1px 4px;
   -moz-user-select: none;
   word-wrap: break-word;
   vertical-align: middle;
   min-height: 1.5em;
   line-height: 1.5em;
+  margin-top: -1px;
 }
 
 :root[platform="win"] .ruleview-header,
 :root[platform="linux"] .ruleview-header {
   margin-top: 4px;
 }
 
 .ruleview-header.ruleview-expandable-header {
--- a/devtools/client/themes/toolbars.css
+++ b/devtools/client/themes/toolbars.css
@@ -737,20 +737,16 @@
 #command-button-screenshot > image {
   background-image: url("chrome://devtools/skin/images/command-screenshot.png");
 }
 
 #command-button-responsive > image {
   background-image: url("chrome://devtools/skin/images/command-responsivemode.png");
 }
 
-#command-button-tilt > image {
-  background-image: url("chrome://devtools/skin/images/command-tilt.png");
-}
-
 #command-button-scratchpad > image {
   background-image: url("chrome://devtools/skin/images/command-scratchpad.png");
 }
 
 #command-button-pick > image {
   background-image: url("chrome://devtools/skin/images/command-pick.png");
 }
 
@@ -786,20 +782,16 @@
   #command-button-screenshot > image {
     background-image: url("chrome://devtools/skin/images/command-screenshot@2x.png");
   }
 
   #command-button-responsive > image {
     background-image: url("chrome://devtools/skin/images/command-responsivemode@2x.png");
   }
 
-  #command-button-tilt > image {
-    background-image: url("chrome://devtools/skin/images/command-tilt@2x.png");
-  }
-
   #command-button-scratchpad > image {
     background-image: url("chrome://devtools/skin/images/command-scratchpad@2x.png");
   }
 
   #command-button-pick > image {
     background-image: url("chrome://devtools/skin/images/command-pick@2x.png");
   }
 
deleted file mode 100644
--- a/devtools/client/tilt/TiltWorkerCrafter.js
+++ /dev/null
@@ -1,281 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-/**
- * Given the initialization data (sizes and information about
- * each DOM node) this worker sends back the arrays representing
- * vertices, texture coords, colors, indices and all the needed data for
- * rendering the DOM visualization mesh.
- *
- * Used in the TiltVisualization.Presenter object.
- */
-self.onmessage = function TWC_onMessage(event)
-{
-  let data = event.data;
-  let maxGroupNodes = parseInt(data.maxGroupNodes);
-  let style = data.style;
-  let texWidth = data.texWidth;
-  let texHeight = data.texHeight;
-  let nodesInfo = data.nodesInfo;
-
-  let mesh = {
-    allVertices: [],
-    groups: [],
-    width: 0,
-    height: 0
-  };
-
-  let vertices;
-  let texCoord;
-  let color;
-  let stacksIndices;
-  let wireframeIndices;
-  let index;
-
-  // seed the random function to get the same values each time
-  // we're doing this to avoid ugly z-fighting with overlapping nodes
-  self.random.seed(0);
-
-  // go through all the dom nodes and compute the verts, texcoord etc.
-  for (let n = 0, len = nodesInfo.length; n < len; n++) {
-
-    // check if we need to start creating a new group
-    if (n % maxGroupNodes === 0) {
-      vertices = []; // recreate the arrays used to construct the 3D mesh data
-      texCoord = [];
-      color = [];
-      stacksIndices = [];
-      wireframeIndices = [];
-      index = 0;
-    }
-
-    let info = nodesInfo[n];
-    let coord = info.coord;
-
-    // calculate the stack x, y, z, width and height coordinates
-    let z = coord.depth + coord.thickness;
-    let y = coord.top;
-    let x = coord.left;
-    let w = coord.width;
-    let h = coord.height;
-
-    // the maximum texture size slices the visualization mesh where needed
-    if (x + w > texWidth) {
-      w = texWidth - x;
-    }
-    if (y + h > texHeight) {
-      h = texHeight - y;
-    }
-
-    x += self.random.next();
-    y += self.random.next();
-    w -= self.random.next() * 0.1;
-    h -= self.random.next() * 0.1;
-
-    let xpw = x + w;
-    let yph = y + h;
-    let zmt = coord.depth;
-
-    let xotw = x / texWidth;
-    let yoth = y / texHeight;
-    let xpwotw = xpw / texWidth;
-    let yphoth = yph / texHeight;
-
-    // calculate the margin fill color
-    let fill = style[info.name] || style.highlight.defaultFill;
-
-    let r = fill[0];
-    let g = fill[1];
-    let b = fill[2];
-    let g10 = r * 1.1;
-    let g11 = g * 1.1;
-    let g12 = b * 1.1;
-    let g20 = r * 0.6;
-    let g21 = g * 0.6;
-    let g22 = b * 0.6;
-
-    // compute the vertices
-    vertices.push(x,   y,   z,                                /* front */ // 0
-                  x,   yph, z,                                            // 1
-                  xpw, yph, z,                                            // 2
-                  xpw, y,   z,                                            // 3
-    // we don't duplicate vertices for the left and right faces, because
-    // they can be reused from the bottom and top faces; we do, however,
-    // duplicate some vertices from front face, because it has custom
-    // texture coordinates which are not shared by the other faces
-                  x,   y,   z,                                /* front */ // 4
-                  x,   yph, z,                                            // 5
-                  xpw, yph, z,                                            // 6
-                  xpw, y,   z,                                            // 7
-                  x,   y,   zmt,                              /* back */  // 8
-                  x,   yph, zmt,                                          // 9
-                  xpw, yph, zmt,                                          // 10
-                  xpw, y,   zmt);                                         // 11
-
-    // compute the texture coordinates
-    texCoord.push(xotw,   yoth,
-                  xotw,   yphoth,
-                  xpwotw, yphoth,
-                  xpwotw, yoth,
-                  -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0);
-
-    // compute the colors for each vertex in the mesh
-    color.push(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-               g10, g11, g12,
-               g10, g11, g12,
-               g10, g11, g12,
-               g10, g11, g12,
-               g20, g21, g22,
-               g20, g21, g22,
-               g20, g21, g22,
-               g20, g21, g22);
-
-    let i = index; // number of vertex points, used to create the indices array
-    let ip1 = i + 1;
-    let ip2 = ip1 + 1;
-    let ip3 = ip2 + 1;
-    let ip4 = ip3 + 1;
-    let ip5 = ip4 + 1;
-    let ip6 = ip5 + 1;
-    let ip7 = ip6 + 1;
-    let ip8 = ip7 + 1;
-    let ip9 = ip8 + 1;
-    let ip10 = ip9 + 1;
-    let ip11 = ip10 + 1;
-
-    // compute the stack indices
-    stacksIndices.unshift(i,    ip1,  ip2,  i,    ip2,  ip3,
-                          ip8,  ip9,  ip5,  ip8,  ip5,  ip4,
-                          ip7,  ip6,  ip10, ip7,  ip10, ip11,
-                          ip8,  ip4,  ip7,  ip8,  ip7,  ip11,
-                          ip5,  ip9,  ip10, ip5,  ip10, ip6);
-
-    // compute the wireframe indices
-    if (coord.thickness !== 0) {
-      wireframeIndices.unshift(i,    ip1, ip1,  ip2,
-                               ip2,  ip3, ip3,  i,
-                               ip8,  i,   ip9,  ip1,
-                               ip11, ip3, ip10, ip2);
-    }
-
-    // there are 12 vertices in a stack representing a node
-    index += 12;
-
-    // set the maximum mesh width and height to calculate the center offset
-    mesh.width = Math.max(w, mesh.width);
-    mesh.height = Math.max(h, mesh.height);
-
-    // check if we need to save the currently active group; this happens after
-    // we filled all the "slots" in a group or there aren't any remaining nodes
-    if (((n + 1) % maxGroupNodes === 0) || (n === len - 1)) {
-      mesh.groups.push({
-        vertices: vertices,
-        texCoord: texCoord,
-        color: color,
-        stacksIndices: stacksIndices,
-        wireframeIndices: wireframeIndices
-      });
-      mesh.allVertices = mesh.allVertices.concat(vertices);
-    }
-  }
-
-  self.postMessage(mesh);
-  close();
-};
-
-/**
- * Utility functions for generating random numbers using the Alea algorithm.
- */
-self.random = {
-
-  /**
-   * The generator function, automatically created with seed 0.
-   */
-  _generator: null,
-
-  /**
-   * Returns a new random number between [0..1)
-   */
-  next: function RNG_next()
-  {
-    return this._generator();
-  },
-
-  /**
-   * From http://baagoe.com/en/RandomMusings/javascript
-   * Johannes Baagoe <baagoe@baagoe.com>, 2010
-   *
-   * Seeds a random generator function with a set of passed arguments.
-   */
-  seed: function RNG_seed()
-  {
-    let s0 = 0;
-    let s1 = 0;
-    let s2 = 0;
-    let c = 1;
-
-    if (arguments.length === 0) {
-      return this.seed(+new Date());
-    } else {
-      s0 = this.mash(" ");
-      s1 = this.mash(" ");
-      s2 = this.mash(" ");
-
-      for (let i = 0, len = arguments.length; i < len; i++) {
-        s0 -= this.mash(arguments[i]);
-        if (s0 < 0) {
-          s0 += 1;
-        }
-        s1 -= this.mash(arguments[i]);
-        if (s1 < 0) {
-          s1 += 1;
-        }
-        s2 -= this.mash(arguments[i]);
-        if (s2 < 0) {
-          s2 += 1;
-        }
-      }
-
-      let random = function() {
-        let t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32
-        s0 = s1;
-        s1 = s2;
-        return (s2 = t - (c = t | 0));
-      };
-      random.uint32 = function() {
-        return random() * 0x100000000; // 2^32
-      };
-      random.fract53 = function() {
-        return random() +
-              (random() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53
-      };
-      return (this._generator = random);
-    }
-  },
-
-  /**
-   * From http://baagoe.com/en/RandomMusings/javascript
-   * Johannes Baagoe <baagoe@baagoe.com>, 2010
-   */
-  mash: function RNG_mash(data)
-  {
-    let h, n = 0xefc8249d;
-
-    data = data.toString();
-    for (let i = 0, len = data.length; i < len; i++) {
-      n += data.charCodeAt(i);
-      h = 0.02519603282416938 * n;
-      n = h >>> 0;
-      h -= n;
-      h *= n;
-      n = h >>> 0;
-      h -= n;
-      n += h * 0x100000000; // 2^32
-    }
-    return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
-  }
-};
deleted file mode 100644
--- a/devtools/client/tilt/TiltWorkerPicker.js
+++ /dev/null
@@ -1,186 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-/**
- * This worker handles picking, given a set of vertices and a ray (calculates
- * the intersection points and offers back information about the closest hit).
- *
- * Used in the TiltVisualization.Presenter object.
- */
-self.onmessage = function TWP_onMessage(event)
-{
-  let data = event.data;
-  let vertices = data.vertices;
-  let ray = data.ray;
-
-  let intersection = null;
-  let hit = [];
-
-  // calculates the squared distance between two points
-  function dsq(p1, p2) {
-    let xd = p2[0] - p1[0];
-    let yd = p2[1] - p1[1];
-    let zd = p2[2] - p1[2];
-
-    return xd * xd + yd * yd + zd * zd;
-  }
-
-  // check each stack face in the visualization mesh for intersections with
-  // the mouse ray (using a ray picking algorithm)
-  for (let i = 0, len = vertices.length; i < len; i += 36) {
-
-    // the front quad
-    let v0f = [vertices[i],      vertices[i + 1],  vertices[i + 2]];
-    let v1f = [vertices[i + 3],  vertices[i + 4],  vertices[i + 5]];
-    let v2f = [vertices[i + 6],  vertices[i + 7],  vertices[i + 8]];
-    let v3f = [vertices[i + 9],  vertices[i + 10], vertices[i + 11]];
-
-    // the back quad
-    let v0b = [vertices[i + 24], vertices[i + 25], vertices[i + 26]];
-    let v1b = [vertices[i + 27], vertices[i + 28], vertices[i + 29]];
-    let v2b = [vertices[i + 30], vertices[i + 31], vertices[i + 32]];
-    let v3b = [vertices[i + 33], vertices[i + 34], vertices[i + 35]];
-
-    // don't do anything with degenerate quads
-    if (!v0f[0] && !v1f[0] && !v2f[0] && !v3f[0]) {
-      continue;
-    }
-
-    // for each triangle in the stack box, check for the intersections
-    if (self.intersect(v0f, v1f, v2f, ray, hit) || // front left
-        self.intersect(v0f, v2f, v3f, ray, hit) || // front right
-        self.intersect(v0b, v1b, v1f, ray, hit) || // left back
-        self.intersect(v0b, v1f, v0f, ray, hit) || // left front
-        self.intersect(v3f, v2b, v3b, ray, hit) || // right back
-        self.intersect(v3f, v2f, v2b, ray, hit) || // right front
-        self.intersect(v0b, v0f, v3f, ray, hit) || // top left
-        self.intersect(v0b, v3f, v3b, ray, hit) || // top right
-        self.intersect(v1f, v1b, v2b, ray, hit) || // bottom left
-        self.intersect(v1f, v2b, v2f, ray, hit)) { // bottom right
-
-      // calculate the distance between the intersection hit point and camera
-      let d = dsq(hit, ray.origin);
-
-      // we're picking the closest stack in the mesh from the camera
-      if (intersection === null || d < intersection.distance) {
-        intersection = {
-          // each mesh stack is composed of 12 vertices, so there's information
-          // about a node once in 12 * 3 = 36 iterations (to avoid duplication)
-          index: i / 36,
-          distance: d
-        };
-      }
-    }
-  }
-
-  self.postMessage(intersection);
-  close();
-};
-
-/**
- * Utility function for finding intersections between a ray and a triangle.
- */
-self.intersect = (function() {
-
-  // creates a new instance of a vector
-  function create() {
-    return new Float32Array(3);
-  }
-
-  // performs a vector addition
-  function add(aVec, aVec2, aDest) {
-    aDest[0] = aVec[0] + aVec2[0];
-    aDest[1] = aVec[1] + aVec2[1];
-    aDest[2] = aVec[2] + aVec2[2];
-    return aDest;
-  }
-
-  // performs a vector subtraction
-  function subtract(aVec, aVec2, aDest) {
-    aDest[0] = aVec[0] - aVec2[0];
-    aDest[1] = aVec[1] - aVec2[1];
-    aDest[2] = aVec[2] - aVec2[2];
-    return aDest;
-  }
-
-  // performs a vector scaling
-  function scale(aVec, aVal, aDest) {
-    aDest[0] = aVec[0] * aVal;
-    aDest[1] = aVec[1] * aVal;
-    aDest[2] = aVec[2] * aVal;
-    return aDest;
-  }
-
-  // generates the cross product of two vectors
-  function cross(aVec, aVec2, aDest) {
-    let x = aVec[0];
-    let y = aVec[1];
-    let z = aVec[2];
-    let x2 = aVec2[0];
-    let y2 = aVec2[1];
-    let z2 = aVec2[2];
-
-    aDest[0] = y * z2 - z * y2;
-    aDest[1] = z * x2 - x * z2;
-    aDest[2] = x * y2 - y * x2;
-    return aDest;
-  }
-
-  // calculates the dot product of two vectors
-  function dot(aVec, aVec2) {
-    return aVec[0] * aVec2[0] + aVec[1] * aVec2[1] + aVec[2] * aVec2[2];
-  }
-
-  let edge1 = create();
-  let edge2 = create();
-  let pvec = create();
-  let tvec = create();
-  let qvec = create();
-  let lvec = create();
-
-  // checks for ray-triangle intersections using the Fast Minimum-Storage
-  // (simplified) algorithm by Tomas Moller and Ben Trumbore
-  return function intersect(aVert0, aVert1, aVert2, aRay, aDest) {
-    let dir = aRay.direction;
-    let orig = aRay.origin;
-
-    // find vectors for two edges sharing vert0
-    subtract(aVert1, aVert0, edge1);
-    subtract(aVert2, aVert0, edge2);
-
-    // begin calculating determinant - also used to calculate the U parameter
-    cross(dir, edge2, pvec);
-
-    // if determinant is near zero, ray lines in plane of triangle
-    let inv_det = 1 / dot(edge1, pvec);
-
-    // calculate distance from vert0 to ray origin
-    subtract(orig, aVert0, tvec);
-
-    // calculate U parameter and test bounds
-    let u = dot(tvec, pvec) * inv_det;
-    if (u < 0 || u > 1) {
-      return false;
-    }
-
-    // prepare to test V parameter
-    cross(tvec, edge1, qvec);
-
-    // calculate V parameter and test bounds
-    let v = dot(dir, qvec) * inv_det;
-    if (v < 0 || u + v > 1) {
-      return false;
-    }
-
-    // calculate T, ray intersects triangle
-    let t = dot(edge2, qvec) * inv_det;
-
-    scale(dir, t, lvec);
-    add(orig, lvec, aDest);
-    return true;
-  };
-}());
deleted file mode 100644
--- a/devtools/client/tilt/moz.build
+++ /dev/null
@@ -1,17 +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/.
-
-DevToolsModules(
-    'tilt-commands.js',
-    'tilt-gl.js',
-    'tilt-math.js',
-    'tilt-utils.js',
-    'tilt-visualizer-style.js',
-    'tilt-visualizer.js',
-    'tilt.js',
-    'TiltWorkerCrafter.js',
-    'TiltWorkerPicker.js'
-)
-
-BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
deleted file mode 100644
--- a/devtools/client/tilt/test/.eslintrc
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-  // Extend from the shared list of defined globals for mochitests.
-  "extends": "../../../.eslintrc.mochitests"
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser.ini
+++ /dev/null
@@ -1,54 +0,0 @@
-[DEFAULT]
-tags = devtools
-skip-if = e10s # Bug 1086492 - Disable tilt for e10s
-               # Bug 937166 - Make tilt work in E10S mode
-subsuite = devtools
-support-files = head.js
-
-[browser_tilt_01_lazy_getter.js]
-[browser_tilt_02_notifications-seq.js]
-[browser_tilt_02_notifications-tabs.js]
-[browser_tilt_02_notifications.js]
-[browser_tilt_03_tab_switch.js]
-skip-if = true # Bug 1093215 - Failed assertion
-[browser_tilt_04_initialization.js]
-[browser_tilt_05_destruction-esc.js]
-[browser_tilt_05_destruction-url.js]
-[browser_tilt_05_destruction.js]
-[browser_tilt_arcball-reset-typeahead.js]
-[browser_tilt_arcball-reset.js]
-[browser_tilt_arcball.js]
-[browser_tilt_controller.js]
-[browser_tilt_gl01.js]
-[browser_tilt_gl02.js]
-[browser_tilt_gl03.js]
-[browser_tilt_gl04.js]
-[browser_tilt_gl05.js]
-[browser_tilt_gl06.js]
-[browser_tilt_gl07.js]
-[browser_tilt_gl08.js]
-[browser_tilt_math01.js]
-[browser_tilt_math02.js]
-[browser_tilt_math03.js]
-[browser_tilt_math04.js]
-[browser_tilt_math05.js]
-[browser_tilt_math06.js]
-[browser_tilt_math07.js]
-[browser_tilt_picking.js]
-[browser_tilt_picking_delete.js]
-[browser_tilt_picking_highlight01-offs.js]
-[browser_tilt_picking_highlight01.js]
-[browser_tilt_picking_highlight02.js]
-[browser_tilt_picking_highlight03.js]
-[browser_tilt_picking_inspector.js]
-[browser_tilt_picking_miv.js]
-[browser_tilt_utils01.js]
-[browser_tilt_utils02.js]
-[browser_tilt_utils03.js]
-[browser_tilt_utils04.js]
-[browser_tilt_utils05.js]
-[browser_tilt_utils06.js]
-[browser_tilt_utils07.js]
-[browser_tilt_utils08.js]
-[browser_tilt_visualizer.js]
-[browser_tilt_zoom.js]
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_01_lazy_getter.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-function test() {
-  ok(Tilt,
-    "The Tilt object wasn't got correctly via defineLazyGetter.");
-  is(Tilt.chromeWindow, window,
-    "The top-level window wasn't saved correctly");
-  ok(Tilt.visualizers,
-    "The holder object for all the instances of the visualizer doesn't exist.")
-  ok(Tilt.NOTIFICATIONS,
-    "The notifications constants weren't referenced correctly.");
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_02_notifications-seq.js
+++ /dev/null
@@ -1,99 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-var tabEvents = "";
-
-function test() {
-  if (!isTiltEnabled()) {
-    aborting();
-    info("Skipping notifications test because Tilt isn't enabled.");
-    return;
-  }
-  if (!isWebGLSupported()) {
-    aborting();
-    info("Skipping notifications test because WebGL isn't supported.");
-    return;
-  }
-
-  requestLongerTimeout(10);
-  waitForExplicitFinish();
-
-  createTab(function() {
-    Services.obs.addObserver(finalize, DESTROYED, false);
-    Services.obs.addObserver(obs_STARTUP, STARTUP, false);
-    Services.obs.addObserver(obs_INITIALIZING, INITIALIZING, false);
-    Services.obs.addObserver(obs_INITIALIZED, INITIALIZED, false);
-    Services.obs.addObserver(obs_DESTROYING, DESTROYING, false);
-    Services.obs.addObserver(obs_BEFORE_DESTROYED, BEFORE_DESTROYED, false);
-    Services.obs.addObserver(obs_DESTROYED, DESTROYED, false);
-
-    info("Starting up the Tilt notifications test.");
-    createTilt({}, false, function suddenDeath()
-    {
-      ok(false, "Tilt could not be initialized properly.");
-      cleanup();
-    });
-  });
-}
-
-function obs_STARTUP(win) {
-  info("Handling the STARTUP notification.");
-  is(win, gBrowser.selectedBrowser.contentWindow, "Saw the correct window");
-  tabEvents += "STARTUP;";
-}
-
-function obs_INITIALIZING(win) {
-  info("Handling the INITIALIZING notification.");
-  is(win, gBrowser.selectedBrowser.contentWindow, "Saw the correct window");
-  tabEvents += "INITIALIZING;";
-}
-
-function obs_INITIALIZED(win) {
-  info("Handling the INITIALIZED notification.");
-  is(win, gBrowser.selectedBrowser.contentWindow, "Saw the correct window");
-  tabEvents += "INITIALIZED;";
-
-  Tilt.destroy(Tilt.currentWindowId, true);
-}
-
-function obs_DESTROYING(win) {
-  info("Handling the DESTROYING( notification.");
-  is(win, gBrowser.selectedBrowser.contentWindow, "Saw the correct window");
-  tabEvents += "DESTROYING;";
-}
-
-function obs_BEFORE_DESTROYED(win) {
-  info("Handling the BEFORE_DESTROYED notification.");
-  is(win, gBrowser.selectedBrowser.contentWindow, "Saw the correct window");
-  tabEvents += "BEFORE_DESTROYED;";
-}
-
-function obs_DESTROYED(win) {
-  info("Handling the DESTROYED notification.");
-  is(win, gBrowser.selectedBrowser.contentWindow, "Saw the correct window");
-  tabEvents += "DESTROYED;";
-}
-
-function finalize(win) {
-  is(win, gBrowser.selectedBrowser.contentWindow, "Saw the correct window");
-  is(tabEvents, "STARTUP;INITIALIZING;INITIALIZED;DESTROYING;BEFORE_DESTROYED;DESTROYED;",
-    "The notifications weren't fired in the correct order.");
-
-  cleanup();
-}
-
-function cleanup() {
-  info("Cleaning up the notifications test.");
-
-  Services.obs.removeObserver(finalize, DESTROYED);
-  Services.obs.removeObserver(obs_INITIALIZING, INITIALIZING);
-  Services.obs.removeObserver(obs_INITIALIZED, INITIALIZED);
-  Services.obs.removeObserver(obs_DESTROYING, DESTROYING);
-  Services.obs.removeObserver(obs_BEFORE_DESTROYED, BEFORE_DESTROYED);
-  Services.obs.removeObserver(obs_DESTROYED, DESTROYED);
-  Services.obs.removeObserver(obs_STARTUP, STARTUP);
-
-  gBrowser.removeCurrentTab();
-  finish();
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_02_notifications-tabs.js
+++ /dev/null
@@ -1,179 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-var tab0, tab1, tab2;
-var testStep = -1;
-
-var expected = [];
-function expect(notification, win) {
-  expected.push({ notification: notification, window: win });
-}
-
-function notification(win, topic) {
-  if (expected.length == 0) {
-    is(topic, null, "Shouldn't see a notification");
-    return;
-  }
-
-  let { notification, window } = expected.shift();
-  if (Cu.isDeadWrapper(window)) {
-    // Sometimes we end up with a nuked window reference here :-(
-    return;
-  }
-  is(topic, notification, "Saw the expected notification");
-  is(win, window, "Saw the expected window");
-}
-
-function after(notification, callback) {
-  function observer() {
-    Services.obs.removeObserver(observer, notification);
-    executeSoon(callback);
-  }
-  Services.obs.addObserver(observer, notification, false);
-}
-
-function test() {
-  if (!isTiltEnabled()) {
-    aborting();
-    info("Skipping tab switch test because Tilt isn't enabled.");
-    return;
-  }
-  if (!isWebGLSupported()) {
-    aborting();
-    info("Skipping tab switch test because WebGL isn't supported.");
-    return;
-  }
-
-  Services.obs.addObserver(notification, STARTUP, false);
-  Services.obs.addObserver(notification, INITIALIZING, false);
-  Services.obs.addObserver(notification, INITIALIZED, false);
-  Services.obs.addObserver(notification, DESTROYING, false);
-  Services.obs.addObserver(notification, BEFORE_DESTROYED, false);
-  Services.obs.addObserver(notification, DESTROYED, false);
-  Services.obs.addObserver(notification, SHOWN, false);
-  Services.obs.addObserver(notification, HIDDEN, false);
-
-  waitForExplicitFinish();
-
-  tab0 = gBrowser.selectedTab;
-  nextStep();
-}
-
-function createTab2() {
-}
-
-var testSteps = [
-  function step0() {
-    tab1 = createTab(function() {
-      expect(STARTUP, tab1.linkedBrowser.contentWindow);
-      expect(INITIALIZING, tab1.linkedBrowser.contentWindow);
-      expect(INITIALIZED, tab1.linkedBrowser.contentWindow);
-      after(INITIALIZED, nextStep);
-
-      createTilt({}, false, function suddenDeath()
-      {
-        ok(false, "Tilt could not be initialized properly.");
-        cleanup();
-      });
-    });
-  },
-  function step1() {
-    expect(HIDDEN, tab1.linkedBrowser.contentWindow);
-
-    tab2 = createTab(function() {
-      expect(STARTUP, tab2.linkedBrowser.contentWindow);
-      expect(INITIALIZING, tab2.linkedBrowser.contentWindow);
-      expect(INITIALIZED, tab2.linkedBrowser.contentWindow);
-      after(INITIALIZED, nextStep);
-
-      createTilt({}, false, function suddenDeath()
-      {
-        ok(false, "Tilt could not be initialized properly.");
-        cleanup();
-      });
-    });
-  },
-  function step2() {
-    expect(HIDDEN, tab2.linkedBrowser.contentWindow);
-    after(HIDDEN, nextStep);
-
-    gBrowser.selectedTab = tab0;
-  },
-  function step3() {
-    expect(SHOWN, tab2.linkedBrowser.contentWindow);
-    after(SHOWN, nextStep);
-
-    gBrowser.selectedTab = tab2;
-  },
-  function step4() {
-    expect(HIDDEN, tab2.linkedBrowser.contentWindow);
-    expect(SHOWN, tab1.linkedBrowser.contentWindow);
-    after(SHOWN, nextStep);
-
-    gBrowser.selectedTab = tab1;
-  },
-  function step5() {
-    expect(HIDDEN, tab1.linkedBrowser.contentWindow);
-    expect(SHOWN, tab2.linkedBrowser.contentWindow);
-    after(SHOWN, nextStep);
-
-    gBrowser.selectedTab = tab2;
-  },
-  function step6() {
-    expect(DESTROYING, tab2.linkedBrowser.contentWindow);
-    expect(BEFORE_DESTROYED, tab2.linkedBrowser.contentWindow);
-    expect(DESTROYED, tab2.linkedBrowser.contentWindow);
-    after(DESTROYED, nextStep);
-
-    Tilt.destroy(Tilt.currentWindowId, true);
-  },
-  function step7() {
-    expect(SHOWN, tab1.linkedBrowser.contentWindow);
-
-    gBrowser.removeCurrentTab();
-    tab2 = null;
-
-    expect(DESTROYING, tab1.linkedBrowser.contentWindow);
-    expect(HIDDEN, tab1.linkedBrowser.contentWindow);
-    expect(BEFORE_DESTROYED, tab1.linkedBrowser.contentWindow);
-    expect(DESTROYED, tab1.linkedBrowser.contentWindow);
-    after(DESTROYED, nextStep);
-
-    gBrowser.removeCurrentTab();
-    tab1 = null;
-  },
-  function step8_cleanup() {
-    is(gBrowser.selectedTab, tab0, "Should be back to the first tab");
-
-    cleanup();
-  }
-];
-
-function cleanup() {
-  if (tab1) {
-    gBrowser.removeTab(tab1);
-    tab1 = null;
-  }
-  if (tab2) {
-    gBrowser.removeTab(tab2);
-    tab2 = null;
-  }
-
-  Services.obs.removeObserver(notification, STARTUP);
-  Services.obs.removeObserver(notification, INITIALIZING);
-  Services.obs.removeObserver(notification, INITIALIZED);
-  Services.obs.removeObserver(notification, DESTROYING);
-  Services.obs.removeObserver(notification, BEFORE_DESTROYED);
-  Services.obs.removeObserver(notification, DESTROYED);
-  Services.obs.removeObserver(notification, SHOWN);
-  Services.obs.removeObserver(notification, HIDDEN);
-
-  finish();
-}
-
-function nextStep() {
-  let step = testSteps.shift();
-  info("Executing " + step.name);
-  step();
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_02_notifications.js
+++ /dev/null
@@ -1,131 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-var tab0, tab1;
-var testStep = -1;
-var tabEvents = "";
-
-function test() {
-  if (!isTiltEnabled()) {
-    aborting();
-    info("Skipping notifications test because Tilt isn't enabled.");
-    return;
-  }
-  if (!isWebGLSupported()) {
-    aborting();
-    info("Skipping notifications test because WebGL isn't supported.");
-    return;
-  }
-
-  requestLongerTimeout(10);
-  waitForExplicitFinish();
-
-  gBrowser.tabContainer.addEventListener("TabSelect", tabSelect, false);
-  createNewTab();
-}
-
-function createNewTab() {
-  tab0 = gBrowser.selectedTab;
-
-  tab1 = createTab(function() {
-    Services.obs.addObserver(finalize, DESTROYED, false);
-    Services.obs.addObserver(tab_STARTUP, STARTUP, false);
-    Services.obs.addObserver(tab_INITIALIZING, INITIALIZING, false);
-    Services.obs.addObserver(tab_DESTROYING, DESTROYING, false);
-    Services.obs.addObserver(tab_SHOWN, SHOWN, false);
-    Services.obs.addObserver(tab_HIDDEN, HIDDEN, false);
-
-    info("Starting up the Tilt notifications test.");
-    createTilt({
-      onTiltOpen: function()
-      {
-        testStep = 0;
-        tabSelect();
-      }
-    }, false, function suddenDeath()
-    {
-      ok(false, "Tilt could not be initialized properly.");
-      cleanup();
-    });
-  });
-}
-
-function tab_STARTUP(win) {
-  info("Handling the STARTUP notification.");
-  is(win, tab1.linkedBrowser.contentWindow, "Saw the correct window");
-  tabEvents += "STARTUP;";
-}
-
-function tab_INITIALIZING(win) {
-  info("Handling the INITIALIZING notification.");
-  is(win, tab1.linkedBrowser.contentWindow, "Saw the correct window");
-  tabEvents += "INITIALIZING;";
-}
-
-function tab_DESTROYING(win) {
-  info("Handling the DESTROYING notification.");
-  is(win, tab1.linkedBrowser.contentWindow, "Saw the correct window");
-  tabEvents += "DESTROYING;";
-}
-
-function tab_SHOWN(win) {
-  info("Handling the SHOWN notification.");
-  is(win, tab1.linkedBrowser.contentWindow, "Saw the correct window");
-  tabEvents += "SHOWN;";
-}
-
-function tab_HIDDEN(win) {
-  info("Handling the HIDDEN notification.");
-  is(win, tab1.linkedBrowser.contentWindow, "Saw the correct window");
-  tabEvents += "HIDDEN;";
-}
-
-var testSteps = [
-  function step0() {
-    info("Selecting tab0.");
-    gBrowser.selectedTab = tab0;
-  },
-  function step1() {
-    info("Selecting tab1.");
-    gBrowser.selectedTab = tab1;
-  },
-  function step2() {
-    info("Killing it.");
-    Tilt.destroy(Tilt.currentWindowId, true);
-  }
-];
-
-function finalize(win) {
-  is(win, tab1.linkedBrowser.contentWindow, "Saw the correct window");
-
-  is(tabEvents, "STARTUP;INITIALIZING;HIDDEN;SHOWN;DESTROYING;",
-    "The notifications weren't fired in the correct order.");
-
-  cleanup();
-}
-
-function cleanup() {
-  info("Cleaning up the notifications test.");
-
-  tab0 = null;
-  tab1 = null;
-
-  Services.obs.removeObserver(finalize, DESTROYED);
-  Services.obs.removeObserver(tab_INITIALIZING, INITIALIZING);
-  Services.obs.removeObserver(tab_DESTROYING, DESTROYING);
-  Services.obs.removeObserver(tab_SHOWN, SHOWN);
-  Services.obs.removeObserver(tab_HIDDEN, HIDDEN);
-  Services.obs.removeObserver(tab_STARTUP, STARTUP);
-
-  gBrowser.tabContainer.removeEventListener("TabSelect", tabSelect);
-  gBrowser.removeCurrentTab();
-  finish();
-}
-
-function tabSelect() {
-  if (testStep !== -1) {
-    executeSoon(testSteps[testStep]);
-    testStep++;
-  }
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_03_tab_switch.js
+++ /dev/null
@@ -1,110 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-var tab0, tab1, tab2;
-var testStep = -1;
-
-function test() {
-  // This test relies on a timeout to indicate pass or fail. All tests need at
-  // least one pass, fail or todo so let's create a dummy pass.
-  ok(true, "Each test requires at least one pass, fail or todo so here is a pass.");
-
-  if (!isTiltEnabled()) {
-    info("Skipping tab switch test because Tilt isn't enabled.");
-    return;
-  }
-  if (!isWebGLSupported()) {
-    info("Skipping tab switch test because WebGL isn't supported.");
-    return;
-  }
-
-  waitForExplicitFinish();
-
-  gBrowser.tabContainer.addEventListener("TabSelect", tabSelect, false);
-  createTab1();
-}
-
-function createTab1() {
-  tab0 = gBrowser.selectedTab;
-
-  tab1 = createTab(function() {
-    createTilt({
-      onTiltOpen: function()
-      {
-        createTab2();
-      }
-    }, false, function suddenDeath()
-    {
-      ok(false, "Tilt could not be initialized properly.");
-      cleanup();
-    });
-  });
-}
-
-function createTab2() {
-  tab2 = createTab(function() {
-
-    createTilt({
-      onTiltOpen: function()
-      {
-        testStep = 0;
-        tabSelect();
-      }
-    }, false, function suddenDeath()
-    {
-      ok(false, "Tilt could not be initialized properly.");
-      cleanup();
-    });
-  });
-}
-
-var testSteps = [
-  function step0() {
-    gBrowser.selectedTab = tab1;
-  },
-  function step1() {
-    gBrowser.selectedTab = tab0;
-  },
-  function step2() {
-    gBrowser.selectedTab = tab1;
-  },
-  function step3() {
-    gBrowser.selectedTab = tab2;
-  },
-  function step4() {
-    Tilt.destroy(Tilt.currentWindowId);
-    gBrowser.removeCurrentTab();
-    tab2 = null;
-  },
-  function step5() {
-    Tilt.destroy(Tilt.currentWindowId);
-    gBrowser.removeCurrentTab();
-    tab1 = null;
-  },
-  function step6_cleanup() {
-    cleanup();
-  }
-];
-
-function cleanup() {
-  gBrowser.tabContainer.removeEventListener("TabSelect", tabSelect, false);
-
-  if (tab1) {
-    gBrowser.removeTab(tab1);
-    tab1 = null;
-  }
-  if (tab2) {
-    gBrowser.removeTab(tab2);
-    tab2 = null;
-  }
-
-  finish();
-}
-
-function tabSelect() {
-  if (testStep !== -1) {
-    executeSoon(testSteps[testStep]);
-    testStep++;
-  }
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_04_initialization.js
+++ /dev/null
@@ -1,59 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-function test() {
-  if (!isTiltEnabled()) {
-    aborting();
-    info("Skipping initialization test because Tilt isn't enabled.");
-    return;
-  }
-  if (!isWebGLSupported()) {
-    aborting();
-    info("Skipping initialization test because WebGL isn't supported.");
-    return;
-  }
-
-  waitForExplicitFinish();
-
-  createTab(function() {
-    let id = TiltUtils.getWindowId(gBrowser.selectedBrowser.contentWindow);
-
-    is(id, Tilt.currentWindowId,
-      "The unique window identifiers should match for the same window.");
-
-    createTilt({
-      onTiltOpen: function(instance)
-      {
-        is(document.activeElement, instance.presenter.canvas,
-          "The visualizer canvas should be focused on initialization.");
-
-        ok(Tilt.visualizers[id] instanceof TiltVisualizer,
-          "A new instance of the visualizer wasn't created properly.");
-        ok(Tilt.visualizers[id].isInitialized(),
-          "The new instance of the visualizer wasn't initialized properly.");
-      },
-      onTiltClose: function()
-      {
-        is(document.activeElement, gBrowser.selectedBrowser,
-          "The focus wasn't correctly given back to the selectedBrowser.");
-
-        is(Tilt.visualizers[id], null,
-          "The current instance of the visualizer wasn't destroyed properly.");
-      },
-      onEnd: function()
-      {
-        cleanup();
-      }
-    }, true, function suddenDeath()
-    {
-      ok(false, "Tilt could not be initialized properly.");
-      cleanup();
-    });
-  });
-}
-
-function cleanup() {
-  gBrowser.removeCurrentTab();
-  finish();
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_05_destruction-esc.js
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-var tiltOpened = false;
-
-function test() {
-  if (!isTiltEnabled()) {
-    aborting();
-    info("Skipping destruction test because Tilt isn't enabled.");
-    return;
-  }
-  if (!isWebGLSupported()) {
-    aborting();
-    info("Skipping destruction test because WebGL isn't supported.");
-    return;
-  }
-
-  waitForExplicitFinish();
-
-  createTab(function() {
-    createTilt({
-      onTiltOpen: function()
-      {
-        tiltOpened = true;
-
-        Services.obs.addObserver(finalize, DESTROYED, false);
-        EventUtils.sendKey("ESCAPE");
-      }
-    }, false, function suddenDeath()
-    {
-      ok(false, "Tilt could not be initialized properly.");
-      cleanup();
-    });
-  });
-}
-
-function finalize() {
-  let id = TiltUtils.getWindowId(gBrowser.selectedBrowser.contentWindow);
-
-  is(Tilt.visualizers[id], null,
-    "The current instance of the visualizer wasn't destroyed properly.");
-
-  cleanup();
-}
-
-function cleanup() {
-  if (tiltOpened) { Services.obs.removeObserver(finalize, DESTROYED); }
-  gBrowser.removeCurrentTab();
-  finish();
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_05_destruction-url.js
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-var tiltOpened = false;
-
-function test() {
-  if (!isTiltEnabled()) {
-    aborting();
-    info("Skipping destruction test because Tilt isn't enabled.");
-    return;
-  }
-  if (!isWebGLSupported()) {
-    aborting();
-    info("Skipping destruction test because WebGL isn't supported.");
-    return;
-  }
-
-  waitForExplicitFinish();
-
-  createTab(function() {
-    createTilt({
-      onTiltOpen: function()
-      {
-        tiltOpened = true;
-
-        Services.obs.addObserver(finalize, DESTROYED, false);
-        window.content.location = "about:mozilla";
-      }
-    }, false, function suddenDeath()
-    {
-      ok(false, "Tilt could not be initialized properly.");
-      cleanup();
-    });
-  });
-}
-
-function finalize() {
-  let id = TiltUtils.getWindowId(gBrowser.selectedBrowser.contentWindow);
-
-  is(Tilt.visualizers[id], null,
-    "The current instance of the visualizer wasn't destroyed properly.");
-
-  cleanup();
-}
-
-function cleanup() {
-  if (tiltOpened) { Services.obs.removeObserver(finalize, DESTROYED); }
-  gBrowser.removeCurrentTab();
-  finish();
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_05_destruction.js
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-var tiltOpened = false;
-
-function test() {
-  if (!isTiltEnabled()) {
-    aborting();
-    info("Skipping destruction test because Tilt isn't enabled.");
-    return;
-  }
-  if (!isWebGLSupported()) {
-    aborting();
-    info("Skipping destruction test because WebGL isn't supported.");
-    return;
-  }
-
-  waitForExplicitFinish();
-
-  createTab(function() {
-    createTilt({
-      onTiltOpen: function()
-      {
-        tiltOpened = true;
-
-        Services.obs.addObserver(finalize, DESTROYED, false);
-        Tilt.destroy(Tilt.currentWindowId);
-      }
-    }, false, function suddenDeath()
-    {
-      ok(false, "Tilt could not be initialized properly.");
-      cleanup();
-    });
-  });
-}
-
-function finalize() {
-  let id = TiltUtils.getWindowId(gBrowser.selectedBrowser.contentWindow);
-
-  is(Tilt.visualizers[id], null,
-    "The current instance of the visualizer wasn't destroyed properly.");
-
-  cleanup();
-}
-
-function cleanup() {
-  if (tiltOpened) { Services.obs.removeObserver(finalize, DESTROYED); }
-  gBrowser.removeCurrentTab();
-  finish();
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_arcball-reset-typeahead.js
+++ /dev/null
@@ -1,132 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-var tiltOpened = false;
-
-function test() {
-  if (!isTiltEnabled()) {
-	  aborting();
-    info("Skipping part of the arcball test because Tilt isn't enabled.");
-    return;
-  }
-  if (!isWebGLSupported()) {
-    aborting();
-    info("Skipping part of the arcball test because WebGL isn't supported.");
-    return;
-  }
-
-  requestLongerTimeout(10);
-  waitForExplicitFinish();
-  Services.prefs.setBoolPref("accessibility.typeaheadfind", true);
-
-  createTab(function() {
-    createTilt({
-      onTiltOpen: function(instance)
-      {
-        tiltOpened = true;
-
-        performTest(instance.presenter.canvas,
-                    instance.controller.arcball, function() {
-
-          info("Killing arcball reset test.");
-
-          Services.prefs.setBoolPref("accessibility.typeaheadfind", false);
-          Services.obs.addObserver(cleanup, DESTROYED, false);
-          Tilt.destroy(Tilt.currentWindowId);
-        });
-      }
-    }, false, function suddenDeath()
-    {
-      ok(false, "Tilt could not be initialized properly.");
-      cleanup();
-    });
-  });
-}
-
-function performTest(canvas, arcball, callback) {
-  is(document.activeElement, canvas,
-    "The visualizer canvas should be focused when performing this test.");
-
-  info("Starting arcball reset test.");
-
-  // start translating and rotating sometime at random
-
-  window.setTimeout(function() {
-    info("Synthesizing key down events.");
-
-    EventUtils.synthesizeKey("VK_S", { type: "keydown" });     // add a little
-    EventUtils.synthesizeKey("VK_RIGHT", { type: "keydown" }); // diversity
-
-    // wait for some arcball translations and rotations to happen
-
-    window.setTimeout(function() {
-      info("Synthesizing key up events.");
-
-      EventUtils.synthesizeKey("VK_S", { type: "keyup" });
-      EventUtils.synthesizeKey("VK_RIGHT", { type: "keyup" });
-
-      // ok, transformations finished, we can now try to reset the model view
-
-      window.setTimeout(function() {
-        info("Synthesizing arcball reset key press.");
-
-        arcball._onResetStart = function() {
-          info("Starting arcball reset animation.");
-        };
-
-        arcball._onResetStep = function() {
-          info("\nlastRot: " + quat4.str(arcball._lastRot) +
-               "\ndeltaRot: " + quat4.str(arcball._deltaRot) +
-               "\ncurrentRot: " + quat4.str(arcball._currentRot) +
-               "\nlastTrans: " + vec3.str(arcball._lastTrans) +
-               "\ndeltaTrans: " + vec3.str(arcball._deltaTrans) +
-               "\ncurrentTrans: " + vec3.str(arcball._currentTrans) +
-               "\nadditionalRot: " + vec3.str(arcball._additionalRot) +
-               "\nadditionalTrans: " + vec3.str(arcball._additionalTrans) +
-               "\nzoomAmount: " + arcball._zoomAmount);
-        };
-
-        arcball._onResetFinish = function() {
-          ok(isApproxVec(arcball._lastRot, [0, 0, 0, 1]),
-            "The arcball _lastRot field wasn't reset correctly.");
-          ok(isApproxVec(arcball._deltaRot, [0, 0, 0, 1]),
-            "The arcball _deltaRot field wasn't reset correctly.");
-          ok(isApproxVec(arcball._currentRot, [0, 0, 0, 1]),
-            "The arcball _currentRot field wasn't reset correctly.");
-
-          ok(isApproxVec(arcball._lastTrans, [0, 0, 0]),
-            "The arcball _lastTrans field wasn't reset correctly.");
-          ok(isApproxVec(arcball._deltaTrans, [0, 0, 0]),
-            "The arcball _deltaTrans field wasn't reset correctly.");
-          ok(isApproxVec(arcball._currentTrans, [0, 0, 0]),
-            "The arcball _currentTrans field wasn't reset correctly.");
-
-          ok(isApproxVec(arcball._additionalRot, [0, 0, 0]),
-            "The arcball _additionalRot field wasn't reset correctly.");
-          ok(isApproxVec(arcball._additionalTrans, [0, 0, 0]),
-            "The arcball _additionalTrans field wasn't reset correctly.");
-
-          ok(isApproxVec([arcball._zoomAmount], [0]),
-            "The arcball _zoomAmount field wasn't reset correctly.");
-
-          executeSoon(function() {
-            info("Finishing arcball reset test.");
-            callback();
-          });
-        };
-
-        EventUtils.synthesizeKey("VK_R", { type: "keydown" });
-
-      }, Math.random() * 1000); // leave enough time for transforms to happen
-    }, Math.random() * 1000);
-  }, Math.random() * 1000);
-}
-
-function cleanup() {
-  info("Cleaning up arcball reset test.");
-
-  if (tiltOpened) { Services.obs.removeObserver(cleanup, DESTROYED); }
-  gBrowser.removeCurrentTab();
-  finish();
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_arcball-reset.js
+++ /dev/null
@@ -1,130 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-var tiltOpened = false;
-
-function test() {
-  if (!isTiltEnabled()) {
-	  aborting();
-    info("Skipping part of the arcball test because Tilt isn't enabled.");
-    return;
-  }
-  if (!isWebGLSupported()) {
-    aborting();
-    info("Skipping part of the arcball test because WebGL isn't supported.");
-    return;
-  }
-
-  requestLongerTimeout(10);
-  waitForExplicitFinish();
-
-  createTab(function() {
-    createTilt({
-      onTiltOpen: function(instance)
-      {
-        tiltOpened = true;
-
-        performTest(instance.presenter.canvas,
-                    instance.controller.arcball, function() {
-
-          info("Killing arcball reset test.");
-
-          Services.obs.addObserver(cleanup, DESTROYED, false);
-          Tilt.destroy(Tilt.currentWindowId);
-        });
-      }
-    }, false, function suddenDeath()
-    {
-      ok(false, "Tilt could not be initialized properly.");
-      cleanup();
-    });
-  });
-}
-
-function performTest(canvas, arcball, callback) {
-  is(document.activeElement, canvas,
-    "The visualizer canvas should be focused when performing this test.");
-
-  info("Starting arcball reset test.");
-
-  // start translating and rotating sometime at random
-
-  window.setTimeout(function() {
-    info("Synthesizing key down events.");
-
-    EventUtils.synthesizeKey("VK_W", { type: "keydown" });
-    EventUtils.synthesizeKey("VK_LEFT", { type: "keydown" });
-
-    // wait for some arcball translations and rotations to happen
-
-    window.setTimeout(function() {
-      info("Synthesizing key up events.");
-
-      EventUtils.synthesizeKey("VK_W", { type: "keyup" });
-      EventUtils.synthesizeKey("VK_LEFT", { type: "keyup" });
-
-      // ok, transformations finished, we can now try to reset the model view
-
-      window.setTimeout(function() {
-        info("Synthesizing arcball reset key press.");
-
-        arcball._onResetStart = function() {
-          info("Starting arcball reset animation.");
-        };
-
-        arcball._onResetStep = function() {
-          info("\nlastRot: " + quat4.str(arcball._lastRot) +
-               "\ndeltaRot: " + quat4.str(arcball._deltaRot) +
-               "\ncurrentRot: " + quat4.str(arcball._currentRot) +
-               "\nlastTrans: " + vec3.str(arcball._lastTrans) +
-               "\ndeltaTrans: " + vec3.str(arcball._deltaTrans) +
-               "\ncurrentTrans: " + vec3.str(arcball._currentTrans) +
-               "\nadditionalRot: " + vec3.str(arcball._additionalRot) +
-               "\nadditionalTrans: " + vec3.str(arcball._additionalTrans) +
-               "\nzoomAmount: " + arcball._zoomAmount);
-        };
-
-        arcball._onResetFinish = function() {
-          ok(isApproxVec(arcball._lastRot, [0, 0, 0, 1]),
-            "The arcball _lastRot field wasn't reset correctly.");
-          ok(isApproxVec(arcball._deltaRot, [0, 0, 0, 1]),
-            "The arcball _deltaRot field wasn't reset correctly.");
-          ok(isApproxVec(arcball._currentRot, [0, 0, 0, 1]),
-            "The arcball _currentRot field wasn't reset correctly.");
-
-          ok(isApproxVec(arcball._lastTrans, [0, 0, 0]),
-            "The arcball _lastTrans field wasn't reset correctly.");
-          ok(isApproxVec(arcball._deltaTrans, [0, 0, 0]),
-            "The arcball _deltaTrans field wasn't reset correctly.");
-          ok(isApproxVec(arcball._currentTrans, [0, 0, 0]),
-            "The arcball _currentTrans field wasn't reset correctly.");
-
-          ok(isApproxVec(arcball._additionalRot, [0, 0, 0]),
-            "The arcball _additionalRot field wasn't reset correctly.");
-          ok(isApproxVec(arcball._additionalTrans, [0, 0, 0]),
-            "The arcball _additionalTrans field wasn't reset correctly.");
-
-          ok(isApproxVec([arcball._zoomAmount], [0]),
-            "The arcball _zoomAmount field wasn't reset correctly.");
-
-          executeSoon(function() {
-            info("Finishing arcball reset test.");
-            callback();
-          });
-        };
-
-        EventUtils.synthesizeKey("VK_R", { type: "keydown" });
-
-      }, Math.random() * 1000); // leave enough time for transforms to happen
-    }, Math.random() * 1000);
-  }, Math.random() * 1000);
-}
-
-function cleanup() {
-  info("Cleaning up arcball reset test.");
-
-  if (tiltOpened) { Services.obs.removeObserver(cleanup, DESTROYED); }
-  gBrowser.removeCurrentTab();
-  finish();
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_arcball.js
+++ /dev/null
@@ -1,496 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-function cloneUpdate(update) {
-  return {
-    rotation: quat4.create(update.rotation),
-    translation: vec3.create(update.translation)
-  };
-}
-
-function isExpectedUpdate(update1, update2) {
-  if (update1.length !== update2.length) {
-    return false;
-  }
-  for (let i = 0, len = update1.length; i < len; i++) {
-    if (!isApproxVec(update1[i].rotation, update2[i].rotation) ||
-        !isApproxVec(update1[i].translation, update2[i].translation)) {
-      info("isExpectedUpdate expected " + JSON.stringify(update1), ", got " +
-                                          JSON.stringify(update2) + " instead.");
-      return false;
-    }
-  }
-  return true;
-}
-
-function test() {
-  let arcball1 = new TiltVisualizer.Arcball(window, 123, 456);
-
-  is(arcball1.width, 123,
-    "The first arcball width wasn't set correctly.");
-  is(arcball1.height, 456,
-    "The first arcball height wasn't set correctly.");
-  is(arcball1.radius, 123,
-    "The first arcball radius wasn't implicitly set correctly.");
-
-
-  let arcball2 = new TiltVisualizer.Arcball(window, 987, 654);
-
-  is(arcball2.width, 987,
-    "The second arcball width wasn't set correctly.");
-  is(arcball2.height, 654,
-    "The second arcball height wasn't set correctly.");
-  is(arcball2.radius, 654,
-    "The second arcball radius wasn't implicitly set correctly.");
-
-
-  let arcball3 = new TiltVisualizer.Arcball(window, 512, 512);
-
-  let sphereVec = vec3.create();
-  arcball3._pointToSphere(123, 456, 256, 512, 512, sphereVec);
-
-  ok(isApproxVec(sphereVec, [-0.009765625, 0.390625, 0.9204980731010437]),
-    "The _pointToSphere() function didn't map the coordinates correctly.");
-
-  let stack1 = [];
-  let expect1 = [
-    { rotation: [
-      -0.08877250552177429, 0.0242881178855896,
-      -0.04222869873046875, -0.9948599338531494],
-      translation: [0, 0, 0] },
-    { rotation: [
-      -0.13086390495300293, 0.03413732722401619,
-      -0.06334304809570312, -0.9887855648994446],
-      translation: [0, 0, 0] },
-    { rotation: [
-      -0.15138940513134003, 0.03854173421859741,
-      -0.07390022277832031, -0.9849540591239929],
-      translation: [0, 0, 0] },
-    { rotation: [
-      -0.1615273654460907, 0.040619146078825,
-      -0.0791788101196289, -0.9828477501869202],
-      translation: [0, 0, 0] },
-    { rotation: [
-      -0.16656573116779327, 0.04162723943591118,
-      -0.0818181037902832, -0.9817478656768799],
-      translation: [0, 0, 0] },
-    { rotation: [
-      -0.16907735168933868, 0.042123712599277496,
-      -0.08313775062561035, -0.9811863303184509],
-      translation: [0, 0, 0] },
-    { rotation: [
-      -0.17033125460147858, 0.042370058596134186,
-      -0.08379757404327393, -0.9809026718139648],
-      translation: [0, 0, 0] },
-    { rotation: [
-      -0.17095772922039032, 0.04249274358153343,
-      -0.08412748575210571, -0.9807600975036621],
-      translation: [0, 0, 0] },
-    { rotation: [
-      -0.17127084732055664, 0.04255397245287895,
-      -0.0842924416065216, -0.9806886315345764],
-      translation: [0, 0, 0] },
-    { rotation: [
-      -0.171427384018898, 0.042584557086229324,
-      -0.08437491953372955, -0.9806528687477112],
-      translation: [0, 0, 0] }];
-
-  arcball3.mouseDown(10, 10, 1);
-  arcball3.mouseMove(10, 100);
-  for (let i1 = 0; i1 < 10; i1++) {
-    stack1.push(cloneUpdate(arcball3.update()));
-  }
-
-  ok(isExpectedUpdate(stack1, expect1),
-    "Mouse down & move events didn't create the expected transform. results.");
-
-  let stack2 = [];
-  let expect2 = [
-    { rotation: [
-      -0.1684110015630722, 0.04199237748980522,
-      -0.0827873945236206, -0.9813361167907715],
-      translation: [0, 0, 0] },
-    { rotation: [
-      -0.16936375200748444, 0.04218007251620293,
-      -0.08328840136528015, -0.9811217188835144],
-      translation: [0, 0, 0] },
-    { rotation: [
-      -0.17003019154071808, 0.04231100529432297,
-      -0.08363909274339676, -0.9809709787368774],
-      translation: [0, 0, 0] },
-    { rotation: [
-      -0.17049652338027954, 0.042402446269989014,
-      -0.0838845893740654, -0.9808651208877563],
-      translation: [0, 0, 0] },
-    { rotation: [
-      -0.17082282900810242, 0.042466338723897934,
-      -0.08405643701553345, -0.9807908535003662],
-      translation: [0, 0, 0] },
-    { rotation: [
-      -0.17105120420455933, 0.04251104220747948,
-      -0.08417671173810959, -0.9807388186454773],
-      translation: [0, 0, 0] },
-    { rotation: [
-      -0.17121103405952454, 0.04254228621721268,
-      -0.08426092565059662, -0.9807023406028748],
-      translation: [0, 0, 0] },
-    { rotation: [
-      -0.17132291197776794, 0.042564138770103455,
-      -0.08431987464427948, -0.9806767106056213],
-      translation: [0, 0, 0] },
-    { rotation: [
-      -0.1714012324810028, 0.04257945716381073,
-      -0.08436112850904465, -0.9806588888168335],
-      translation: [0, 0, 0] },
-    { rotation: [
-      -0.17145603895187378, 0.042590171098709106,
-      -0.08439001441001892, -0.9806463718414307],
-      translation: [0, 0, 0] }];
-
-  arcball3.mouseUp(100, 100);
-  for (let i2 = 0; i2 < 10; i2++) {
-    stack2.push(cloneUpdate(arcball3.update()));
-  }
-
-  ok(isExpectedUpdate(stack2, expect2),
-    "Mouse up events didn't create the expected transformation results.");
-
-  let stack3 = [];
-  let expect3 = [
-    { rotation: [
-      -0.17149439454078674, 0.04259764403104782,
-      -0.08441022783517838, -0.9806375503540039],
-      translation: [0, 0, -1] },
-    { rotation: [
-      -0.17152123153209686, 0.04260288551449776,
-      -0.08442437648773193, -0.980631411075592],
-      translation: [0, 0, -1.899999976158142] },
-    { rotation: [
-      -0.1715400665998459, 0.04260658100247383,
-      -0.08443428575992584, -0.9806271195411682],
-      translation: [0, 0, -2.7100000381469727] },
-    { rotation: [
-      -0.17155319452285767, 0.04260912910103798,
-      -0.08444121479988098, -0.9806240797042847],
-      translation: [0, 0, -3.439000129699707] },
-    { rotation: [
-      -0.17156240344047546, 0.042610932141542435,
-      -0.08444607257843018, -0.9806219935417175],
-      translation: [0, 0, -4.095099925994873] },
-    { rotation: [
-      -0.1715688556432724, 0.042612191289663315,
-      -0.08444946259260178, -0.9806205034255981],
-      translation: [0, 0, -4.685589790344238] },
-    { rotation: [
-      -0.17157337069511414, 0.04261308163404465,
-      -0.0844518393278122, -0.980619490146637],
-      translation: [0, 0, -5.217031002044678] },
-    { rotation: [
-      -0.17157652974128723, 0.0426136814057827,
-      -0.0844535157084465, -0.9806187748908997],
-      translation: [0, 0, -5.6953277587890625] },
-    { rotation: [
-      -0.17157875001430511, 0.04261413961648941,
-      -0.08445467799901962, -0.9806182980537415],
-      translation: [0, 0, -6.125794887542725] },
-    { rotation: [
-      -0.17158031463623047, 0.04261442646384239,
-      -0.08445550501346588, -0.980617880821228],
-      translation: [0, 0, -6.5132155418396] }];
-
-  arcball3.zoom(10);
-  for (let i3 = 0; i3 < 10; i3++) {
-    stack3.push(cloneUpdate(arcball3.update()));
-  }
-
-  ok(isExpectedUpdate(stack3, expect3),
-    "Mouse zoom events didn't create the expected transformation results.");
-
-  let stack4 = [];
-  let expect4 = [
-    { rotation: [
-      -0.17158135771751404, 0.04261462762951851,
-      -0.08445606380701065, -0.9806176424026489],
-      translation: [0, 0, -6.861894130706787] },
-    { rotation: [
-      -0.1715821474790573, 0.04261479899287224,
-      -0.08445646613836288, -0.9806175231933594],
-      translation: [0, 0, -7.1757049560546875] },
-    { rotation: [
-      -0.1715826541185379, 0.0426148846745491,
-      -0.08445674180984497, -0.980617344379425],
-      translation: [0, 0, -7.458134651184082] },
-    { rotation: [
-      -0.17158304154872894, 0.04261497035622597,
-      -0.08445693552494049, -0.9806172847747803],
-      translation: [0, 0, -7.7123212814331055] },
-    { rotation: [
-      -0.17158329486846924, 0.042615000158548355,
-      -0.08445708453655243, -0.9806172251701355],
-      translation: [0, 0, -7.941089153289795] },
-    { rotation: [
-      -0.17158347368240356, 0.04261505603790283,
-      -0.084457166492939, -0.9806172251701355],
-      translation: [0, 0, -8.146980285644531] },
-    { rotation: [
-      -0.1715836226940155, 0.04261508584022522,
-      -0.08445724099874496, -0.9806171655654907],
-      translation: [0, 0, -8.332282066345215] },
-    { rotation: [
-      -0.17158368229866028, 0.04261508584022522,
-      -0.08445728570222855, -0.980617105960846],
-      translation: [0, 0, -8.499053955078125] },
-    { rotation: [
-      -0.17158377170562744, 0.04261511191725731,
-      -0.08445732295513153, -0.980617105960846],
-      translation: [0, 0, -8.649148941040039] },
-    { rotation: [
-      -0.17158380150794983, 0.04261511191725731,
-      -0.08445733785629272, -0.980617105960846],
-      translation: [0, 0, -8.784234046936035] }];
-
-  arcball3.keyDown(arcball3.rotateKeys.left);
-  arcball3.keyDown(arcball3.rotateKeys.right);
-  arcball3.keyDown(arcball3.rotateKeys.up);
-  arcball3.keyDown(arcball3.rotateKeys.down);
-  arcball3.keyDown(arcball3.panKeys.left);
-  arcball3.keyDown(arcball3.panKeys.right);
-  arcball3.keyDown(arcball3.panKeys.up);
-  arcball3.keyDown(arcball3.panKeys.down);
-  for (let i4 = 0; i4 < 10; i4++) {
-    stack4.push(cloneUpdate(arcball3.update()));
-  }
-
-  ok(isExpectedUpdate(stack4, expect4),
-    "Key down events didn't create the expected transformation results.");
-
-  let stack5 = [];
-  let expect5 = [
-    { rotation: [
-      -0.1715838462114334, 0.04261511191725731,
-      -0.08445736765861511, -0.980617105960846],
-      translation: [0, 0, -8.905810356140137] },
-    { rotation: [
-      -0.1715838462114334, 0.04261511191725731,
-      -0.08445736765861511, -0.980617105960846],
-      translation: [0, 0, -9.015229225158691] },
-    { rotation: [
-      -0.1715838462114334, 0.04261511191725731,
-      -0.08445736765861511, -0.980617105960846],
-      translation: [0, 0, -9.113706588745117] },
-    { rotation: [
-      -0.1715838611125946, 0.04261511191725731,
-      -0.0844573825597763, -0.9806170463562012],
-      translation: [0, 0, -9.202336311340332] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, -9.282102584838867] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, -9.35389232635498] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, -9.418502807617188] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, -9.476652145385742] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, -9.528986930847168] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, -9.576087951660156] }];
-
-  arcball3.keyUp(arcball3.rotateKeys.left);
-  arcball3.keyUp(arcball3.rotateKeys.right);
-  arcball3.keyUp(arcball3.rotateKeys.up);
-  arcball3.keyUp(arcball3.rotateKeys.down);
-  arcball3.keyUp(arcball3.panKeys.left);
-  arcball3.keyUp(arcball3.panKeys.right);
-  arcball3.keyUp(arcball3.panKeys.up);
-  arcball3.keyUp(arcball3.panKeys.down);
-  for (let i5 = 0; i5 < 10; i5++) {
-    stack5.push(cloneUpdate(arcball3.update()));
-  }
-
-  ok(isExpectedUpdate(stack5, expect5),
-    "Key up events didn't create the expected transformation results.");
-
-  let stack6 = [];
-  let expect6 = [
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, -9.618478775024414] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, -6.156630992889404] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 0.4590320587158203] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 9.913128852844238] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 21.921815872192383] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 36.22963333129883] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 52.60667037963867] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 70.84600067138672] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 90.76139831542969] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 112.18525695800781] }];
-
-  arcball3.keyDown(arcball3.zoomKeys["in"][0]);
-  arcball3.keyDown(arcball3.zoomKeys["in"][1]);
-  arcball3.keyDown(arcball3.zoomKeys["in"][2]);
-  for (let i6 = 0; i6 < 10; i6++) {
-    stack6.push(cloneUpdate(arcball3.update()));
-  }
-  arcball3.keyUp(arcball3.zoomKeys["in"][0]);
-  arcball3.keyUp(arcball3.zoomKeys["in"][1]);
-  arcball3.keyUp(arcball3.zoomKeys["in"][2]);
-
-  ok(isExpectedUpdate(stack6, expect6),
-    "Key zoom in events didn't create the expected transformation results.");
-
-  let stack7 = [];
-  let expect7 = [
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 134.96673583984375] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 151.97006225585938] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 163.77305603027344] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 170.895751953125] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 173.80618286132812] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 172.92556762695312] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 168.6330108642578] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 161.26971435546875] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 151.1427459716797] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 138.52847290039062] }];
-
-  arcball3.keyDown(arcball3.zoomKeys["out"][0]);
-  arcball3.keyDown(arcball3.zoomKeys["out"][1]);
-  for (let i7 = 0; i7 < 10; i7++) {
-    stack7.push(cloneUpdate(arcball3.update()));
-  }
-  arcball3.keyUp(arcball3.zoomKeys["out"][0]);
-  arcball3.keyUp(arcball3.zoomKeys["out"][1]);
-
-  ok(isExpectedUpdate(stack7, expect7),
-    "Key zoom out events didn't create the expected transformation results.");
-
-  let stack8 = [];
-  let expect8 = [
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 123.67562866210938] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 111.30806732177734] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 100.17726135253906] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 90.15953826904297] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 81.14358520507812] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 73.02922821044922] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 65.72630310058594] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 59.15367126464844] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 53.238304138183594] },
-    { rotation: [
-      -0.17158392071723938, 0.0426151417195797,
-      -0.0844573974609375, -0.980617105960846],
-      translation: [0, 0, 47.91447448730469] }];
-
-  arcball3.keyDown(arcball3.zoomKeys["unzoom"]);
-  for (let i8 = 0; i8 < 10; i8++) {
-    stack8.push(cloneUpdate(arcball3.update()));
-  }
-  arcball3.keyUp(arcball3.zoomKeys["unzoom"]);
-
-  ok(isExpectedUpdate(stack8, expect8),
-    "Key zoom reset events didn't create the expected transformation results.");
-
-
-  arcball3.resize(123, 456);
-  is(arcball3.width, 123,
-    "The third arcball width wasn't updated correctly.");
-  is(arcball3.height, 456,
-    "The third arcball height wasn't updated correctly.");
-  is(arcball3.radius, 123,
-    "The third arcball radius wasn't implicitly updated correctly.");
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_controller.js
+++ /dev/null
@@ -1,138 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-function test() {
-  if (!isTiltEnabled()) {
-    aborting();
-    info("Skipping controller test because Tilt isn't enabled.");
-    return;
-  }
-  if (!isWebGLSupported()) {
-    aborting();
-    info("Skipping controller test because WebGL isn't supported.");
-    return;
-  }
-
-  waitForExplicitFinish();
-
-  createTab(function() {
-    createTilt({
-      onTiltOpen: function(instance)
-      {
-        let canvas = instance.presenter.canvas;
-        let prev_tran = vec3.create([0, 0, 0]);
-        let prev_rot = quat4.create([0, 0, 0, 1]);
-
-        function tran() {
-          return instance.presenter.transforms.translation;
-        }
-
-        function rot() {
-          return instance.presenter.transforms.rotation;
-        }
-
-        function save() {
-          prev_tran = vec3.create(tran());
-          prev_rot = quat4.create(rot());
-        }
-
-        ok(isEqualVec(tran(), prev_tran),
-          "At init, the translation should be zero.");
-        ok(isEqualVec(rot(), prev_rot),
-          "At init, the rotation should be zero.");
-
-        function testEventCancel(cancellingEvent, cancellingDescription) {
-          let description = "testEventCancel, cancellingEvent is " + cancellingDescription + ": ";
-          is(document.activeElement, canvas,
-             description + "The visualizer canvas should be focused when performing this test.");
-
-          EventUtils.synthesizeKey("a", { type: "keydown", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A });
-          instance.controller._update();
-          ok(!isEqualVec(rot(), prev_rot),
-             description + "After a rotation key is pressed, the quaternion should change.");
-          EventUtils.synthesizeKey("a", { type: "keyup", code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A });
-
-          EventUtils.synthesizeKey("ArrowLeft", { type: "keydown", code: "ArrowLeft", keyCode: KeyboardEvent.DOM_VK_LEFT });
-          instance.controller._update();
-          ok(!isEqualVec(tran(), prev_tran),
-             description + "After a translation key is pressed, the vector should change.");
-          EventUtils.synthesizeKey("ArrowLeft", { type: "keyup", code: "ArrowLeft", keyCode: KeyboardEvent.DOM_VK_LEFT });
-
-          save();
-
-
-          cancellingEvent();
-          instance.controller._update();
-
-          ok(!isEqualVec(tran(), prev_tran),
-             description + "Even if the canvas lost focus, the vector has some inertia.");
-          ok(!isEqualVec(rot(), prev_rot),
-             description + "Even if the canvas lost focus, the quaternion has some inertia.");
-
-          save();
-
-
-          while (!isEqualVec(tran(), prev_tran) ||
-                 !isEqualVec(rot(), prev_rot)) {
-            instance.controller._update();
-            save();
-          }
-
-          ok(isEqualVec(tran(), prev_tran) && isEqualVec(rot(), prev_rot),
-            "After focus lost, the transforms inertia eventually stops.");
-        }
-
-        info("Setting typeaheadfind to true.");
-
-        let typeaheadfindEnabled = true;
-        Services.prefs.setBoolPref("accessibility.typeaheadfind", typeaheadfindEnabled);
-        for (var i = 0; i < 2; i++) {
-          testEventCancel(function() {
-            // XXX Don't use a character which is registered as a mnemonic in the menubar.
-            EventUtils.synthesizeKey("A", { altKey: true, code: "KeyA", keyCode: KeyboardEvent.DOM_VK_A });
-          }, "Alt + A");
-          testEventCancel(function() {
-            // XXX Don't use a character which is registered as a shortcut key.
-            EventUtils.synthesizeKey(";", { ctrlKey: true, code: "Semicolon", keyCode: KeyboardEvent.DOM_VK_SEMICONLON });
-          }, "Ctrl + ;");
-          testEventCancel(function() {
-            // XXX Don't use a character which is registered as a shortcut key.
-            EventUtils.synthesizeKey("\\", { metaKey: true, code: "Backslash", keyCode: KeyboardEvent.DOM_VK_BACK_SLASH });
-          }, "Meta + \\");
-          // If typeahead is enabled, Shift + T causes moving focus to the findbar because it inputs "T".
-          if (!typeaheadfindEnabled) {
-            testEventCancel(function() {
-              EventUtils.synthesizeKey("T", { shiftKey: true, code: "KeyT", keyCode: KeyboardEvent.DOM_VK_T });
-            }, "Shift + T");
-          }
-
-          // Retry after disabling typeaheadfind.
-          info("Setting typeaheadfind to false.");
-
-          typeaheadfindEnabled = false;
-          Services.prefs.setBoolPref("accessibility.typeaheadfind", typeaheadfindEnabled);
-        }
-
-        info("Testing if loosing focus halts any stacked arcball animations.");
-
-        testEventCancel(function() {
-          gBrowser.selectedBrowser.contentWindow.focus();
-        }, "setting focus to the content window");
-      },
-      onEnd: function()
-      {
-        cleanup();
-      }
-    }, true, function suddenDeath()
-    {
-      ok(false, "Tilt could not be initialized properly.");
-      cleanup();
-    });
-  });
-}
-
-function cleanup() {
-  gBrowser.removeCurrentTab();
-  finish();
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_gl01.js
+++ /dev/null
@@ -1,157 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-var isWebGLAvailable;
-
-function onWebGLFail() {
-  isWebGLAvailable = false;
-}
-
-function onWebGLSuccess() {
-  isWebGLAvailable = true;
-}
-
-function test() {
-  if (!isWebGLSupported()) {
-    aborting();
-    info("Skipping tilt_gl01 because WebGL isn't supported on this hardware.");
-    return;
-  }
-
-  let canvas = createCanvas();
-
-  let renderer = new TiltGL.Renderer(canvas, onWebGLFail, onWebGLSuccess);
-  let gl = renderer.context;
-
-  if (!isWebGLAvailable) {
-    aborting();
-    return;
-  }
-
-
-  ok(renderer,
-    "The TiltGL.Renderer constructor should have initialized a new object.");
-
-  ok(gl instanceof WebGLRenderingContext,
-    "The renderer context wasn't created correctly from the passed canvas.");
-
-
-  let clearColor = gl.getParameter(gl.COLOR_CLEAR_VALUE),
-      clearDepth = gl.getParameter(gl.DEPTH_CLEAR_VALUE);
-
-  is(clearColor[0], 0,
-    "The default red clear color wasn't set correctly at initialization.");
-  is(clearColor[1], 0,
-    "The default green clear color wasn't set correctly at initialization.");
-  is(clearColor[2], 0,
-    "The default blue clear color wasn't set correctly at initialization.");
-  is(clearColor[3], 0,
-    "The default alpha clear color wasn't set correctly at initialization.");
-  is(clearDepth, 1,
-    "The default clear depth wasn't set correctly at initialization.");
-
-  is(renderer.width, canvas.width,
-    "The renderer width wasn't set correctly from the passed canvas.");
-  is(renderer.height, canvas.height,
-    "The renderer height wasn't set correctly from the passed canvas.");
-
-  ok(renderer.mvMatrix,
-    "The model view matrix wasn't initialized properly.");
-  ok(renderer.projMatrix,
-    "The model view matrix wasn't initialized properly.");
-
-  ok(isApproxVec(renderer._fillColor, [1, 1, 1, 1]),
-    "The default fill color wasn't set correctly.");
-  ok(isApproxVec(renderer._strokeColor, [0, 0, 0, 1]),
-    "The default stroke color wasn't set correctly.");
-  is(renderer._strokeWeightValue, 1,
-    "The default stroke weight wasn't set correctly.");
-
-  ok(renderer._colorShader,
-    "A default color shader should have been created.");
-
-  ok(typeof renderer.Program, "function",
-    "At init, the renderer should have created a Program constructor.");
-  ok(typeof renderer.VertexBuffer, "function",
-    "At init, the renderer should have created a VertexBuffer constructor.");
-  ok(typeof renderer.IndexBuffer, "function",
-    "At init, the renderer should have created a IndexBuffer constructor.");
-  ok(typeof renderer.Texture, "function",
-    "At init, the renderer should have created a Texture constructor.");
-
-  renderer.depthTest(true);
-  is(gl.getParameter(gl.DEPTH_TEST), true,
-    "The depth test wasn't enabled when requested.");
-
-  renderer.depthTest(false);
-  is(gl.getParameter(gl.DEPTH_TEST), false,
-    "The depth test wasn't disabled when requested.");
-
-  renderer.stencilTest(true);
-  is(gl.getParameter(gl.STENCIL_TEST), true,
-    "The stencil test wasn't enabled when requested.");
-
-  renderer.stencilTest(false);
-  is(gl.getParameter(gl.STENCIL_TEST), false,
-    "The stencil test wasn't disabled when requested.");
-
-  renderer.cullFace("front");
-  is(gl.getParameter(gl.CULL_FACE), true,
-    "The cull face wasn't enabled when requested.");
-  is(gl.getParameter(gl.CULL_FACE_MODE), gl.FRONT,
-    "The cull face front mode wasn't set correctly.");
-
-  renderer.cullFace("back");
-  is(gl.getParameter(gl.CULL_FACE), true,
-    "The cull face wasn't enabled when requested.");
-  is(gl.getParameter(gl.CULL_FACE_MODE), gl.BACK,
-    "The cull face back mode wasn't set correctly.");
-
-  renderer.cullFace("both");
-  is(gl.getParameter(gl.CULL_FACE), true,
-    "The cull face wasn't enabled when requested.");
-  is(gl.getParameter(gl.CULL_FACE_MODE), gl.FRONT_AND_BACK,
-    "The cull face back mode wasn't set correctly.");
-
-  renderer.cullFace(false);
-  is(gl.getParameter(gl.CULL_FACE), false,
-    "The cull face wasn't disabled when requested.");
-
-  renderer.frontFace("cw");
-  is(gl.getParameter(gl.FRONT_FACE), gl.CW,
-    "The front face cw mode wasn't set correctly.");
-
-  renderer.frontFace("ccw");
-  is(gl.getParameter(gl.FRONT_FACE), gl.CCW,
-    "The front face ccw mode wasn't set correctly.");
-
-  renderer.blendMode("alpha");
-  is(gl.getParameter(gl.BLEND), true,
-    "The blend mode wasn't enabled when requested.");
-  is(gl.getParameter(gl.BLEND_SRC_ALPHA), gl.SRC_ALPHA,
-    "The source blend func wasn't set correctly.");
-  is(gl.getParameter(gl.BLEND_DST_ALPHA), gl.ONE_MINUS_SRC_ALPHA,
-    "The destination blend func wasn't set correctly.");
-
-  renderer.blendMode("add");
-  is(gl.getParameter(gl.BLEND), true,
-    "The blend mode wasn't enabled when requested.");
-  is(gl.getParameter(gl.BLEND_SRC_ALPHA), gl.SRC_ALPHA,
-    "The source blend func wasn't set correctly.");
-  is(gl.getParameter(gl.BLEND_DST_ALPHA), gl.ONE,
-    "The destination blend func wasn't set correctly.");
-
-  renderer.blendMode(false);
-  is(gl.getParameter(gl.CULL_FACE), false,
-    "The blend mode wasn't disabled when requested.");
-
-
-  is(gl.getParameter(gl.CURRENT_PROGRAM), null,
-    "No program should be initially set in the WebGL context.");
-
-  renderer.useColorShader(new renderer.VertexBuffer([1, 2, 3], 3));
-
-  ok(gl.getParameter(gl.CURRENT_PROGRAM) instanceof WebGLProgram,
-    "The correct program hasn't been set in the WebGL context.");
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_gl02.js
+++ /dev/null
@@ -1,46 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-var isWebGLAvailable;
-
-function onWebGLFail() {
-  isWebGLAvailable = false;
-}
-
-function onWebGLSuccess() {
-  isWebGLAvailable = true;
-}
-
-function test() {
-  if (!isWebGLSupported()) {
-    aborting();
-    info("Skipping tilt_gl02 because WebGL isn't supported on this hardware.");
-    return;
-  }
-
-  let canvas = createCanvas();
-
-  let renderer = new TiltGL.Renderer(canvas, onWebGLFail, onWebGLSuccess);
-  let gl = renderer.context;
-
-  if (!isWebGLAvailable) {
-    aborting();
-    return;
-  }
-
-
-  renderer.fill([1, 0, 0, 1]);
-  ok(isApproxVec(renderer._fillColor, [1, 0, 0, 1]),
-    "The fill color wasn't set correctly.");
-
-  renderer.stroke([0, 1, 0, 1]);
-  ok(isApproxVec(renderer._strokeColor, [0, 1, 0, 1]),
-    "The stroke color wasn't set correctly.");
-
-  renderer.strokeWeight(2);
-  is(renderer._strokeWeightValue, 2,
-    "The stroke weight wasn't set correctly.");
-  is(gl.getParameter(gl.LINE_WIDTH), 2,
-    "The stroke weight wasn't applied correctly.");
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_gl03.js
+++ /dev/null
@@ -1,69 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-var isWebGLAvailable;
-
-function onWebGLFail() {
-  isWebGLAvailable = false;
-}
-
-function onWebGLSuccess() {
-  isWebGLAvailable = true;
-}
-
-function test() {
-  if (!isWebGLSupported()) {
-    aborting();
-    info("Skipping tilt_gl03 because WebGL isn't supported on this hardware.");
-    return;
-  }
-
-  let canvas = createCanvas();
-
-  let renderer = new TiltGL.Renderer(canvas, onWebGLFail, onWebGLSuccess);
-  let gl = renderer.context;
-
-  if (!isWebGLAvailable) {
-    aborting();
-    return;
-  }
-
-
-  renderer.defaults();
-  is(gl.getParameter(gl.DEPTH_TEST), true,
-    "The depth test wasn't set to the correct default value.");
-  is(gl.getParameter(gl.STENCIL_TEST), false,
-    "The stencil test wasn't set to the correct default value.");
-  is(gl.getParameter(gl.CULL_FACE), false,
-    "The cull face wasn't set to the correct default value.");
-  is(gl.getParameter(gl.FRONT_FACE), gl.CCW,
-    "The front face wasn't set to the correct default value.");
-  is(gl.getParameter(gl.BLEND), true,
-    "The blend mode wasn't set to the correct default value.");
-  is(gl.getParameter(gl.BLEND_SRC_ALPHA), gl.SRC_ALPHA,
-    "The source blend func wasn't set to the correct default value.");
-  is(gl.getParameter(gl.BLEND_DST_ALPHA), gl.ONE_MINUS_SRC_ALPHA,
-    "The destination blend func wasn't set to the correct default value.");
-
-
-  ok(isApproxVec(renderer._fillColor, [1, 1, 1, 1]),
-    "The fill color wasn't set to the correct default value.");
-  ok(isApproxVec(renderer._strokeColor, [0, 0, 0, 1]),
-    "The stroke color wasn't set to the correct default value.");
-  is(renderer._strokeWeightValue, 1,
-    "The stroke weight wasn't set to the correct default value.");
-  is(gl.getParameter(gl.LINE_WIDTH), 1,
-    "The stroke weight wasn't applied with the correct default value.");
-
-
-  ok(isApproxVec(renderer.projMatrix, [
-    1.2071068286895752, 0, 0, 0, 0, -2.4142136573791504, 0, 0, 0, 0,
-    -1.0202020406723022, -1, -181.06602478027344, 181.06602478027344,
-    148.14492797851562, 181.06602478027344
-  ]), "The default perspective projection matrix wasn't set correctly.");
-
-  ok(isApproxVec(renderer.mvMatrix, [
-    1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1
-  ]), "The default model view matrix wasn't set correctly.");
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_gl04.js
+++ /dev/null
@@ -1,126 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-var isWebGLAvailable;
-
-function onWebGLFail() {
-  isWebGLAvailable = false;
-}
-
-function onWebGLSuccess() {
-  isWebGLAvailable = true;
-}
-
-function test() {
-  if (!isWebGLSupported()) {
-    aborting();
-    info("Skipping tilt_gl04 because WebGL isn't supported on this hardware.");
-    return;
-  }
-
-  let canvas = createCanvas();
-
-  let renderer = new TiltGL.Renderer(canvas, onWebGLFail, onWebGLSuccess);
-  let gl = renderer.context;
-
-  if (!isWebGLAvailable) {
-    aborting();
-    return;
-  }
-
-
-  renderer.perspective();
-  ok(isApproxVec(renderer.projMatrix, [
-    1.2071068286895752, 0, 0, 0, 0, -2.4142136573791504, 0, 0, 0, 0,
-    -1.0202020406723022, -1, -181.06602478027344, 181.06602478027344,
-    148.14492797851562, 181.06602478027344
-  ]), "The default perspective proj. matrix wasn't calculated correctly.");
-
-  ok(isApproxVec(renderer.mvMatrix, [
-    1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1
-  ]), "Changing the perpective matrix should reset the modelview by default.");
-
-
-  renderer.ortho();
-  ok(isApproxVec(renderer.projMatrix, [
-    0.006666666828095913, 0, 0, 0, 0, -0.013333333656191826, 0, 0, 0, 0, -1,
-    0, -1, 1, 0, 1
-  ]), "The default ortho proj. matrix wasn't calculated correctly.");
-  ok(isApproxVec(renderer.mvMatrix, [
-    1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1
-  ]), "Changing the ortho matrix should reset the modelview by default.");
-
-
-  renderer.projection(mat4.perspective(45, 1, 0.1, 100));
-  ok(isApproxVec(renderer.projMatrix, [
-    2.4142136573791504, 0, 0, 0, 0, 2.4142136573791504, 0, 0, 0, 0,
-    -1.0020020008087158, -1, 0, 0, -0.20020020008087158, 0
-  ]), "A custom proj. matrix couldn't be set correctly.");
-  ok(isApproxVec(renderer.mvMatrix, [
-    1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1
-  ]), "Setting a custom proj. matrix should reset the model view by default.");
-
-
-  renderer.translate(1, 1, 1);
-  ok(isApproxVec(renderer.mvMatrix, [
-    1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1
-  ]), "The translation transformation wasn't applied correctly.");
-
-  renderer.rotate(0.5, 1, 1, 1);
-  ok(isApproxVec(renderer.mvMatrix, [
-    0.9183883666992188, 0.317602276802063, -0.23599065840244293, 0,
-    -0.23599065840244293, 0.9183883666992188, 0.317602276802063, 0,
-    0.317602276802063, -0.23599065840244293, 0.9183883666992188, 0, 1, 1, 1, 1
-  ]), "The rotation transformation wasn't applied correctly.");
-
-  renderer.rotateX(0.5);
-  ok(isApproxVec(renderer.mvMatrix, [
-    0.9183883666992188, 0.317602276802063, -0.23599065840244293, 0,
-    -0.05483464524149895, 0.6928216814994812, 0.7190210819244385, 0,
-    0.391862154006958, -0.6474001407623291, 0.6536949872970581, 0, 1, 1, 1, 1
-  ]), "The X rotation transformation wasn't applied correctly.");
-
-  renderer.rotateY(0.5);
-  ok(isApproxVec(renderer.mvMatrix, [
-    0.6180928945541382, 0.5891023874282837, -0.5204993486404419, 0,
-    -0.05483464524149895, 0.6928216814994812, 0.7190210819244385, 0,
-    0.7841902375221252, -0.4158804416656494, 0.4605313837528229, 0, 1, 1, 1, 1
-  ]), "The Y rotation transformation wasn't applied correctly.");
-
-  renderer.rotateZ(0.5);
-  ok(isApproxVec(renderer.mvMatrix, [
-    0.5161384344100952, 0.8491423726081848, -0.11206408590078354, 0,
-    -0.3444514572620392, 0.3255774974822998, 0.8805410265922546, 0,
-    0.7841902375221252, -0.4158804416656494, 0.4605313837528229, 0, 1, 1, 1, 1
-  ]), "The Z rotation transformation wasn't applied correctly.");
-
-  renderer.scale(2, 2, 2);
-  ok(isApproxVec(renderer.mvMatrix, [
-    1.0322768688201904, 1.6982847452163696, -0.22412817180156708, 0,
-    -0.6889029145240784, 0.6511549949645996, 1.7610820531845093, 0,
-    1.5683804750442505, -0.8317608833312988, 0.9210627675056458, 0, 1, 1, 1, 1
-  ]), "The Z rotation transformation wasn't applied correctly.");
-
-  renderer.transform(mat4.create());
-  ok(isApproxVec(renderer.mvMatrix, [
-    1.0322768688201904, 1.6982847452163696, -0.22412817180156708, 0,
-    -0.6889029145240784, 0.6511549949645996, 1.7610820531845093, 0,
-    1.5683804750442505, -0.8317608833312988, 0.9210627675056458, 0, 1, 1, 1, 1
-  ]), "The identity matrix transformation wasn't applied correctly.");
-
-  renderer.origin(1, 1, 1);
-  ok(isApproxVec(renderer.mvMatrix, [
-    1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1
-  ]), "The origin wasn't reset to identity correctly.");
-
-  renderer.translate(1, 2);
-  ok(isApproxVec(renderer.mvMatrix, [
-    1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 2, 0, 1
-  ]), "The second translation transformation wasn't applied correctly.");
-
-  renderer.scale(3, 4);
-  ok(isApproxVec(renderer.mvMatrix, [
-    3, 0, 0, 0, 0, 4, 0, 0, 0, 0, 1, 0, 1, 2, 0, 1
-  ]), "The second scale transformation wasn't applied correctly.");
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_gl05.js
+++ /dev/null
@@ -1,42 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-var isWebGLAvailable;
-
-function onWebGLFail() {
-  isWebGLAvailable = false;
-}
-
-function onWebGLSuccess() {
-  isWebGLAvailable = true;
-}
-
-function test() {
-  if (!isWebGLSupported()) {
-    aborting();
-    info("Skipping tilt_gl05 because WebGL isn't supported on this hardware.");
-    return;
-  }
-
-  let canvas = createCanvas();
-
-  let renderer = new TiltGL.Renderer(canvas, onWebGLFail, onWebGLSuccess);
-  let gl = renderer.context;
-
-  if (!isWebGLAvailable) {
-    aborting();
-    return;
-  }
-
-
-  let mesh = {
-    vertices: new renderer.VertexBuffer([1, 2, 3], 3),
-    indices: new renderer.IndexBuffer([1]),
-  };
-
-  ok(mesh.vertices instanceof TiltGL.VertexBuffer,
-    "The mesh vertices weren't saved at initialization.");
-  ok(mesh.indices instanceof TiltGL.IndexBuffer,
-    "The mesh indices weren't saved at initialization.");
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_gl06.js
+++ /dev/null
@@ -1,59 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-var isWebGLAvailable;
-
-function onWebGLFail() {
-  isWebGLAvailable = false;
-}
-
-function onWebGLSuccess() {
-  isWebGLAvailable = true;
-}
-
-function test() {
-  if (!isWebGLSupported()) {
-    aborting();
-    info("Skipping tilt_gl06 because WebGL isn't supported on this hardware.");
-    return;
-  }
-
-  let canvas = createCanvas();
-
-  let renderer = new TiltGL.Renderer(canvas, onWebGLFail, onWebGLSuccess);
-  let gl = renderer.context;
-
-  if (!isWebGLAvailable) {
-    aborting();
-    return;
-  }
-
-
-  let vb = new renderer.VertexBuffer([1, 2, 3, 4, 5, 6], 3);
-
-  ok(vb instanceof TiltGL.VertexBuffer,
-    "The vertex buffer object wasn't instantiated correctly.");
-  ok(vb._ref,
-    "The vertex buffer gl element wasn't created at initialization.");
-  ok(vb.components,
-    "The vertex buffer components weren't created at initialization.");
-  is(vb.itemSize, 3,
-    "The vertex buffer item size isn't set correctly.");
-  is(vb.numItems, 2,
-    "The vertex buffer number of items weren't calculated correctly.");
-
-
-  let ib = new renderer.IndexBuffer([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
-
-  ok(ib instanceof TiltGL.IndexBuffer,
-    "The index buffer object wasn't instantiated correctly.");
-  ok(ib._ref,
-    "The index buffer gl element wasn't created at initialization.");
-  ok(ib.components,
-    "The index buffer components weren't created at initialization.");
-  is(ib.itemSize, 1,
-    "The index buffer item size isn't set correctly.");
-  is(ib.numItems, 10,
-    "The index buffer number of items weren't calculated correctly.");
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_gl07.js
+++ /dev/null
@@ -1,60 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-var isWebGLAvailable;
-
-function onWebGLFail() {
-  isWebGLAvailable = false;
-}
-
-function onWebGLSuccess() {
-  isWebGLAvailable = true;
-}
-
-function test() {
-  if (!isWebGLSupported()) {
-    aborting();
-    info("Skipping tilt_gl07 because WebGL isn't supported on this hardware.");
-    return;
-  }
-
-  let canvas = createCanvas();
-
-  let renderer = new TiltGL.Renderer(canvas, onWebGLFail, onWebGLSuccess);
-  let gl = renderer.context;
-
-  if (!isWebGLAvailable) {
-    aborting();
-    return;
-  }
-
-
-  let p = new renderer.Program({
-    vs: TiltGL.ColorShader.vs,
-    fs: TiltGL.ColorShader.fs,
-    attributes: ["vertexPosition"],
-    uniforms: ["mvMatrix", "projMatrix", "fill"]
-  });
-
-  ok(p instanceof TiltGL.Program,
-    "The program object wasn't instantiated correctly.");
-
-  ok(p._ref,
-    "The program WebGL object wasn't created properly.");
-  isnot(p._id, -1,
-    "The program id wasn't set properly.");
-  ok(p._attributes,
-    "The program attributes cache wasn't created properly.");
-  ok(p._uniforms,
-    "The program uniforms cache wasn't created properly.");
-
-  is(typeof p._attributes.vertexPosition, "number",
-    "The vertexPosition attribute wasn't cached as it should.");
-  is(typeof p._uniforms.mvMatrix, "object",
-    "The mvMatrix uniform wasn't cached as it should.");
-  is(typeof p._uniforms.projMatrix, "object",
-    "The projMatrix uniform wasn't cached as it should.");
-  is(typeof p._uniforms.fill, "object",
-    "The fill uniform wasn't cached as it should.");
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_gl08.js
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-var isWebGLAvailable;
-
-function onWebGLFail() {
-  isWebGLAvailable = false;
-}
-
-function onWebGLSuccess() {
-  isWebGLAvailable = true;
-}
-
-function test() {
-  if (!isWebGLSupported()) {
-    aborting();
-    info("Skipping tilt_gl08 because WebGL isn't supported on this hardware.");
-    return;
-  }
-
-  let canvas = createCanvas();
-
-  let renderer = new TiltGL.Renderer(canvas, onWebGLFail, onWebGLSuccess);
-  let gl = renderer.context;
-
-  if (!isWebGLAvailable) {
-    aborting();
-    return;
-  }
-
-
-  let t = new renderer.Texture({
-    source: canvas,
-    format: "RGB"
-  });
-
-  ok(t instanceof TiltGL.Texture,
-    "The texture object wasn't instantiated correctly.");
-
-  ok(t._ref,
-    "The texture WebGL object wasn't created properly.");
-  isnot(t._id, -1,
-    "The texture id wasn't set properly.");
-  isnot(t.width, -1,
-    "The texture width wasn't set properly.");
-  isnot(t.height, -1,
-    "The texture height wasn't set properly.");
-  ok(t.loaded,
-    "The texture loaded flag wasn't set to true as it should.");
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_math01.js
+++ /dev/null
@@ -1,59 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-function test() {
-  ok(isApprox(TiltMath.radians(30), 0.523598775),
-    "The radians() function didn't calculate the value correctly.");
-
-  ok(isApprox(TiltMath.degrees(0.5), 28.64788975),
-    "The degrees() function didn't calculate the value correctly.");
-
-  ok(isApprox(TiltMath.map(0.5, 0, 1, 0, 100), 50),
-    "The map() function didn't calculate the value correctly.");
-
-  is(TiltMath.isPowerOfTwo(32), true,
-    "The isPowerOfTwo() function didn't return the expected value.");
-
-  is(TiltMath.isPowerOfTwo(33), false,
-    "The isPowerOfTwo() function didn't return the expected value.");
-
-  ok(isApprox(TiltMath.nextPowerOfTwo(31), 32),
-    "The nextPowerOfTwo() function didn't calculate the 1st value correctly.");
-
-  ok(isApprox(TiltMath.nextPowerOfTwo(32), 32),
-    "The nextPowerOfTwo() function didn't calculate the 2nd value correctly.");
-
-  ok(isApprox(TiltMath.nextPowerOfTwo(33), 64),
-    "The nextPowerOfTwo() function didn't calculate the 3rd value correctly.");
-
-  ok(isApprox(TiltMath.clamp(5, 1, 3), 3),
-    "The clamp() function didn't calculate the 1st value correctly.");
-
-  ok(isApprox(TiltMath.clamp(5, 3, 1), 3),
-    "The clamp() function didn't calculate the 2nd value correctly.");
-
-  ok(isApprox(TiltMath.saturate(5), 1),
-    "The saturate() function didn't calculate the 1st value correctly.");
-
-  ok(isApprox(TiltMath.saturate(-5), 0),
-    "The saturate() function didn't calculate the 2nd value correctly.");
-
-  ok(isApproxVec(TiltMath.hex2rgba("#f00"), [1, 0, 0, 1]),
-    "The hex2rgba() function didn't calculate the 1st rgba values correctly.");
-
-  ok(isApproxVec(TiltMath.hex2rgba("#f008"), [1, 0, 0, 0.53]),
-    "The hex2rgba() function didn't calculate the 2nd rgba values correctly.");
-
-  ok(isApproxVec(TiltMath.hex2rgba("#ff0000"), [1, 0, 0, 1]),
-    "The hex2rgba() function didn't calculate the 3rd rgba values correctly.");
-
-  ok(isApproxVec(TiltMath.hex2rgba("#ff0000aa"), [1, 0, 0, 0.66]),
-    "The hex2rgba() function didn't calculate the 4th rgba values correctly.");
-
-  ok(isApproxVec(TiltMath.hex2rgba("rgba(255, 0, 0, 0.5)"), [1, 0, 0, 0.5]),
-    "The hex2rgba() function didn't calculate the 5th rgba values correctly.");
-
-  ok(isApproxVec(TiltMath.hex2rgba("rgb(255, 0, 0)"), [1, 0, 0, 1]),
-    "The hex2rgba() function didn't calculate the 6th rgba values correctly.");
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_math02.js
+++ /dev/null
@@ -1,104 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-function test() {
-  let v1 = vec3.create();
-
-  ok(v1, "Should have created a vector with vec3.create().");
-  is(v1.length, 3, "A vec3 should have 3 elements.");
-
-  ok(isApproxVec(v1, [0, 0, 0]),
-    "When created, a vec3 should have the values default to 0.");
-
-  vec3.set([1, 2, 3], v1);
-  ok(isApproxVec(v1, [1, 2, 3]),
-    "The vec3.set() function didn't set the values correctly.");
-
-  vec3.zero(v1);
-  ok(isApproxVec(v1, [0, 0, 0]),
-    "The vec3.zero() function didn't set the values correctly.");
-
-  let v2 = vec3.create([4, 5, 6]);
-  ok(isApproxVec(v2, [4, 5, 6]),
-    "When cloning arrays, a vec3 should have the values copied.");
-
-  let v3 = vec3.create(v2);
-  ok(isApproxVec(v3, [4, 5, 6]),
-    "When cloning vectors, a vec3 should have the values copied.");
-
-  vec3.add(v2, v3);
-  ok(isApproxVec(v2, [8, 10, 12]),
-    "The vec3.add() function didn't set the x value correctly.");
-
-  vec3.subtract(v2, v3);
-  ok(isApproxVec(v2, [4, 5, 6]),
-    "The vec3.subtract() function didn't set the values correctly.");
-
-  vec3.negate(v2);
-  ok(isApproxVec(v2, [-4, -5, -6]),
-    "The vec3.negate() function didn't set the values correctly.");
-
-  vec3.scale(v2, -2);
-  ok(isApproxVec(v2, [8, 10, 12]),
-    "The vec3.scale() function didn't set the values correctly.");
-
-  vec3.normalize(v1);
-  ok(isApproxVec(v1, [0, 0, 0]),
-    "Normalizing a vector with zero length should return [0, 0, 0].");
-
-  vec3.normalize(v2);
-  ok(isApproxVec(v2, [
-    0.4558423161506653, 0.5698028802871704, 0.6837634444236755
-  ]), "The vec3.normalize() function didn't set the values correctly.");
-
-  vec3.cross(v2, v3);
-  ok(isApproxVec(v2, [
-    5.960464477539063e-8, -1.1920928955078125e-7, 5.960464477539063e-8
-  ]), "The vec3.cross() function didn't set the values correctly.");
-
-  vec3.dot(v2, v3);
-  ok(isApproxVec(v2, [
-    5.960464477539063e-8, -1.1920928955078125e-7, 5.960464477539063e-8
-  ]), "The vec3.dot() function didn't set the values correctly.");
-
-  ok(isApproxVec([vec3.length(v2)], [1.4600096599955427e-7]),
-    "The vec3.length() function didn't calculate the value correctly.");
-
-  vec3.direction(v2, v3);
-  ok(isApproxVec(v2, [
-    -0.4558422863483429, -0.5698028802871704, -0.6837634444236755
-  ]), "The vec3.direction() function didn't set the values correctly.");
-
-  vec3.lerp(v2, v3, 0.5);
-  ok(isApproxVec(v2, [
-    1.7720788717269897, 2.2150986194610596, 2.65811824798584
-  ]), "The vec3.lerp() function didn't set the values correctly.");
-
-
-  vec3.project([100, 100, 10], [0, 0, 100, 100],
-    mat4.create(), mat4.perspective(45, 1, 0.1, 100), v1);
-  ok(isApproxVec(v1, [-1157.10693359375, 1257.10693359375, 0]),
-    "The vec3.project() function didn't set the values correctly.");
-
-  vec3.unproject([100, 100, 1], [0, 0, 100, 100],
-    mat4.create(), mat4.perspective(45, 1, 0.1, 100), v1);
-  ok(isApproxVec(v1, [
-    41.420406341552734, -41.420406341552734, -99.99771118164062
-  ]), "The vec3.project() function didn't set the values correctly.");
-
-
-  let ray = vec3.createRay([10, 10, 0], [100, 100, 1], [0, 0, 100, 100],
-    mat4.create(), mat4.perspective(45, 1, 0.1, 100));
-
-  ok(isApproxVec(ray.origin, [
-    -0.03313708305358887, 0.03313708305358887, -0.1000000014901161
-  ]), "The vec3.createRay() function didn't create the position correctly.");
-  ok(isApproxVec(ray.direction, [
-    0.35788586614428364, -0.35788586614428364, -0.862458934459091
-  ]), "The vec3.createRay() function didn't create the direction correctly.");
-
-
-  is(vec3.str([0, 0, 0]), "[0, 0, 0]",
-    "The vec3.str() function didn't work properly.");
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_math03.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-function test() {
-  let m1 = mat3.create();
-
-  ok(m1, "Should have created a matrix with mat3.create().");
-  is(m1.length, 9, "A mat3 should have 9 elements.");
-
-  ok(isApproxVec(m1, [1, 0, 0, 0, 1, 0, 0, 0, 1]),
-    "When created, a mat3 should have the values default to identity.");
-
-  mat3.set([1, 2, 3, 4, 5, 6, 7, 8, 9], m1);
-  ok(isApproxVec(m1, [1, 2, 3, 4, 5, 6, 7, 8, 9]),
-    "The mat3.set() function didn't set the values correctly.");
-
-  mat3.transpose(m1);
-  ok(isApproxVec(m1, [1, 4, 7, 2, 5, 8, 3, 6, 9]),
-    "The mat3.transpose() function didn't set the values correctly.");
-
-  mat3.identity(m1);
-  ok(isApproxVec(m1, [1, 0, 0, 0, 1, 0, 0, 0, 1]),
-    "The mat3.identity() function didn't set the values correctly.");
-
-  let m2 = mat3.toMat4(m1);
-  ok(isApproxVec(m2, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]),
-    "The mat3.toMat4() function didn't set the values correctly.");
-
-
-  is(mat3.str([1, 2, 3, 4, 5, 6, 7, 8, 9]), "[1, 2, 3, 4, 5, 6, 7, 8, 9]",
-    "The mat3.str() function didn't work properly.");
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_math04.js
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-function test() {
-  let m1 = mat4.create();
-
-  ok(m1, "Should have created a matrix with mat4.create().");
-  is(m1.length, 16, "A mat4 should have 16 elements.");
-
-  ok(isApproxVec(m1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]),
-    "When created, a mat4 should have the values default to identity.");
-
-  mat4.set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], m1);
-  ok(isApproxVec(m1, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
-    "The mat4.set() function didn't set the values correctly.");
-
-  mat4.transpose(m1);
-  ok(isApproxVec(m1, [1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16]),
-    "The mat4.transpose() function didn't set the values correctly.");
-
-  mat4.identity(m1);
-  ok(isApproxVec(m1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]),
-    "The mat4.identity() function didn't set the values correctly.");
-
-  ok(isApprox(mat4.determinant(m1), 1),
-    "The mat4.determinant() function didn't calculate the value correctly.");
-
-  let m2 = mat4.inverse([1, 3, 1, 1, 1, 1, 2, 1, 2, 3, 4, 1, 1, 1, 1, 1]);
-  ok(isApproxVec(m2, [
-    -1, -3, 1, 3, 0.5, 0, 0, -0.5, 0, 1, 0, -1, 0.5, 2, -1, -0.5
-  ]), "The mat4.inverse() function didn't calculate the values correctly.");
-
-  let m3 = mat4.toRotationMat([
-    1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16]);
-  ok(isApproxVec(m3, [
-    1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 0, 0, 0, 1
-  ]), "The mat4.toRotationMat() func. didn't calculate the values correctly.");
-
-  let m4 = mat4.toMat3([
-    1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16]);
-  ok(isApproxVec(m4, [1, 5, 9, 2, 6, 10, 3, 7, 11]),
-    "The mat4.toMat3() function didn't set the values correctly.");
-
-  let m5 = mat4.toInverseMat3([
-    1, 3, 1, 1, 1, 1, 2, 1, 2, 3, 4, 1, 1, 1, 1, 1]);
-  ok(isApproxVec(m5, [2, 9, -5, 0, -2, 1, -1, -3, 2]),
-    "The mat4.toInverseMat3() function didn't set the values correctly.");
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_math05.js
+++ /dev/null
@@ -1,101 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-function test() {
-  let m1 = mat4.create([
-    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
-
-  let m2 = mat4.create([
-    0, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16]);
-
-  mat4.multiply(m1, m2);
-  ok(isApproxVec(m1, [
-    275, 302, 329, 356, 304, 336, 368, 400,
-    332, 368, 404, 440, 360, 400, 440, 480
-  ]), "The mat4.multiply() function didn't set the values correctly.");
-
-  let v1 = mat4.multiplyVec3(m1, [1, 2, 3]);
-  ok(isApproxVec(v1, [2239, 2478, 2717]),
-    "The mat4.multiplyVec3() function didn't set the values correctly.");
-
-  let v2 = mat4.multiplyVec4(m1, [1, 2, 3, 0]);
-  ok(isApproxVec(v2, [1879, 2078, 2277, 2476]),
-    "The mat4.multiplyVec4() function didn't set the values correctly.");
-
-  mat4.translate(m1, [1, 2, 3]);
-  ok(isApproxVec(m1, [
-    275, 302, 329, 356, 304, 336, 368, 400,
-    332, 368, 404, 440, 2239, 2478, 2717, 2956
-  ]), "The mat4.translate() function didn't set the values correctly.");
-
-  mat4.scale(m1, [1, 2, 3]);
-  ok(isApproxVec(m1, [
-    275, 302, 329, 356, 608, 672, 736, 800,
-    996, 1104, 1212, 1320, 2239, 2478, 2717, 2956
-  ]), "The mat4.scale() function didn't set the values correctly.");
-
-  mat4.rotate(m1, 0.5, [1, 1, 1]);
-  ok(isApproxVec(m1, [
-    210.6123046875, 230.2483367919922, 249.88438415527344, 269.5204162597656,
-    809.8145751953125, 896.520751953125, 983.2268676757812,
-    1069.9329833984375, 858.5731201171875, 951.23095703125,
-    1043.8887939453125, 1136.5465087890625, 2239, 2478, 2717, 2956
-  ]), "The mat4.rotate() function didn't set the values correctly.");
-
-  mat4.rotateX(m1, 0.5);
-  ok(isApproxVec(m1, [
-    210.6123046875, 230.2483367919922, 249.88438415527344, 269.5204162597656,
-    1122.301025390625, 1242.8154296875, 1363.3297119140625,
-    1483.843994140625, 365.2230224609375, 404.96875, 444.71453857421875,
-    484.460205078125, 2239, 2478, 2717, 2956
-  ]), "The mat4.rotateX() function didn't set the values correctly.");
-
-  mat4.rotateY(m1, 0.5);
-  ok(isApproxVec(m1, [
-    9.732441902160645, 7.909564018249512, 6.086670875549316,
-    4.263822555541992, 1122.301025390625, 1242.8154296875, 1363.3297119140625,
-    1483.843994140625, 421.48626708984375, 465.78045654296875,
-    510.0746765136719, 554.3687744140625, 2239, 2478, 2717, 2956
-  ]), "The mat4.rotateY() function didn't set the values correctly.");
-
-  mat4.rotateZ(m1, 0.5);
-  ok(isApproxVec(m1, [
-    546.6007690429688, 602.7787475585938, 658.9566650390625, 715.1345825195312,
-    980.245849609375, 1086.881103515625, 1193.5162353515625,
-    1300.1514892578125, 421.48626708984375, 465.78045654296875,
-    510.0746765136719, 554.3687744140625, 2239, 2478, 2717, 2956
-  ]), "The mat4.rotateZ() function didn't set the values correctly.");
-
-
-  let m3 = mat4.frustum(0, 100, 200, 0, 0.1, 100);
-  ok(isApproxVec(m3, [
-    0.0020000000949949026, 0, 0, 0, 0, -0.0010000000474974513, 0, 0, 1, -1,
-    -1.0020020008087158, -1, 0, 0, -0.20020020008087158, 0
-  ]), "The mat4.frustum() function didn't compute the values correctly.");
-
-  let m4 = mat4.perspective(45, 1.6, 0.1, 100);
-  ok(isApproxVec(m4, [1.5088834762573242, 0, 0, 0, 0, 2.4142136573791504, 0,
-    0, 0, 0, -1.0020020008087158, -1, 0, 0, -0.20020020008087158, 0
-  ]), "The mat4.frustum() function didn't compute the values correctly.");
-
-  let m5 = mat4.ortho(0, 100, 200, 0, -1, 1);
-  ok(isApproxVec(m5, [
-    0.019999999552965164, 0, 0, 0, 0, -0.009999999776482582, 0, 0,
-    0, 0, -1, 0, -1, 1, 0, 1
-  ]), "The mat4.ortho() function didn't compute the values correctly.");
-
-  let m6 = mat4.lookAt([1, 2, 3], [4, 5, 6], [0, 1, 0]);
-  ok(isApproxVec(m6, [
-    -0.7071067690849304, -0.40824830532073975, -0.5773502588272095, 0, 0,
-    0.8164966106414795, -0.5773502588272095, 0, 0.7071067690849304,
-    -0.40824830532073975, -0.5773502588272095, 0, -1.4142135381698608, 0,
-    3.464101552963257, 1
-  ]), "The mat4.lookAt() function didn't compute the values correctly.");
-
-
-  is(mat4.str([
-    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
-  "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]",
-  "The mat4.str() function didn't work properly.");
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_math06.js
+++ /dev/null
@@ -1,42 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-function test() {
-  let q1 = quat4.create();
-
-  ok(q1, "Should have created a quaternion with quat4.create().");
-  is(q1.length, 4, "A quat4 should have 4 elements.");
-
-  ok(isApproxVec(q1, [0, 0, 0, 1]),
-    "When created, a vec3 should have the values default to identity.");
-
-  quat4.set([1, 2, 3, 4], q1);
-  ok(isApproxVec(q1, [1, 2, 3, 4]),
-    "The quat4.set() function didn't set the values correctly.");
-
-  quat4.identity(q1);
-  ok(isApproxVec(q1, [0, 0, 0, 1]),
-    "The quat4.identity() function didn't set the values correctly.");
-
-  quat4.set([5, 6, 7, 8], q1);
-  ok(isApproxVec(q1, [5, 6, 7, 8]),
-    "The quat4.set() function didn't set the values correctly.");
-
-  quat4.calculateW(q1);
-  ok(isApproxVec(q1, [5, 6, 7, -10.440306663513184]),
-    "The quat4.calculateW() function didn't compute the values correctly.");
-
-  quat4.inverse(q1);
-  ok(isApproxVec(q1, [-5, -6, -7, -10.440306663513184]),
-    "The quat4.inverse() function didn't compute the values correctly.");
-
-  quat4.normalize(q1);
-  ok(isApproxVec(q1, [
-    -0.33786869049072266, -0.40544241666793823,
-    -0.4730161726474762, -0.7054905295372009
-  ]), "The quat4.normalize() function didn't compute the values correctly.");
-
-  ok(isApprox(quat4.length(q1), 1),
-    "The mat4.length() function didn't calculate the value correctly.");
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_math07.js
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-function test() {
-  let q1 = quat4.create([1, 2, 3, 4]);
-  let q2 = quat4.create([5, 6, 7, 8]);
-
-  quat4.multiply(q1, q2);
-  ok(isApproxVec(q1, [24, 48, 48, -6]),
-    "The quat4.multiply() function didn't set the values correctly.");
-
-  let v1 = quat4.multiplyVec3(q1, [9, 9, 9]);
-  ok(isApproxVec(v1, [5508, 54756, 59940]),
-    "The quat4.multiplyVec3() function didn't set the values correctly.");
-
-  let m1 = quat4.toMat3(q1);
-  ok(isApproxVec(m1, [
-    -9215, 2880, 1728, 1728, -5759, 4896, 2880, 4320, -5759
-  ]), "The quat4.toMat3() function didn't set the values correctly.");
-
-  let m2 = quat4.toMat4(q1);
-  ok(isApproxVec(m2, [
-    -9215, 2880, 1728, 0, 1728, -5759, 4896, 0,
-    2880, 4320, -5759, 0, 0, 0, 0, 1
-  ]), "The quat4.toMat4() function didn't set the values correctly.");
-
-  quat4.calculateW(q1);
-  quat4.calculateW(q2);
-  quat4.slerp(q1, q2, 0.5);
-  ok(isApproxVec(q1, [24, 48, 48, -71.99305725097656]),
-    "The quat4.slerp() function didn't set the values correctly.");
-
-  let q3 = quat4.fromAxis([1, 1, 1], 0.5);
-  ok(isApproxVec(q3, [
-    0.24740396440029144, 0.24740396440029144, 0.24740396440029144,
-    0.9689124226570129
-  ]), "The quat4.fromAxis() function didn't compute the values correctly.");
-
-  let q4 = quat4.fromEuler(0.5, 0.75, 1.25);
-  ok(isApproxVec(q4, [
-    0.15310347080230713, 0.39433568716049194,
-    0.4540249705314636, 0.7841683626174927
-  ]), "The quat4.fromEuler() function didn't compute the values correctly.");
-
-
-  is(quat4.str([1, 2, 3, 4]), "[1, 2, 3, 4]",
-    "The quat4.str() function didn't work properly.");
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_picking.js
+++ /dev/null
@@ -1,56 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-var pickDone = false;
-
-function test() {
-  if (!isTiltEnabled()) {
-    aborting();
-    info("Skipping picking test because Tilt isn't enabled.");
-    return;
-  }
-  if (!isWebGLSupported()) {
-    aborting();
-    info("Skipping picking test because WebGL isn't supported.");
-    return;
-  }
-
-  waitForExplicitFinish();
-
-  createTab(function() {
-    createTilt({
-      onTiltOpen: function(instance)
-      {
-        let presenter = instance.presenter;
-        let canvas = presenter.canvas;
-
-        presenter._onSetupMesh = function() {
-          let p = getPickablePoint(presenter);
-
-          presenter.pickNode(p[0], p[1], {
-            onpick: function(data)
-            {
-              ok(data.index > 0,
-                "Simply picking a node didn't work properly.");
-
-              pickDone = true;
-              Services.obs.addObserver(cleanup, DESTROYED, false);
-              Tilt.destroy(Tilt.currentWindowId);
-            }
-          });
-        };
-      }
-    }, false, function suddenDeath()
-    {
-      ok(false, "Tilt could not be initialized properly.");
-      cleanup();
-    });
-  });
-}
-
-function cleanup() {
-  if (pickDone) { Services.obs.removeObserver(cleanup, DESTROYED); }
-  gBrowser.removeCurrentTab();
-  finish();
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_picking_delete.js
+++ /dev/null
@@ -1,78 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-var nodeDeleted = false;
-var presenter;
-
-function test() {
-  if (!isTiltEnabled()) {
-    aborting();
-    info("Skipping picking delete test because Tilt isn't enabled.");
-    return;
-  }
-  if (!isWebGLSupported()) {
-    aborting();
-    info("Skipping picking delete test because WebGL isn't supported.");
-    return;
-  }
-
-  waitForExplicitFinish();
-
-  createTab(function() {
-    createTilt({
-      onTiltOpen: function(instance)
-      {
-        presenter = instance.presenter;
-        Services.obs.addObserver(whenNodeRemoved, NODE_REMOVED, false);
-
-        presenter._onSetupMesh = function() {
-          let p = getPickablePoint(presenter);
-
-          presenter.highlightNodeAt(p[0], p[1], {
-            onpick: function()
-            {
-              ok(presenter._currentSelection > 0,
-                "Highlighting a node didn't work properly.");
-              ok(!presenter._highlight.disabled,
-                "After highlighting a node, it should be highlighted. D'oh.");
-
-              nodeDeleted = true;
-              presenter.deleteNode();
-            }
-          });
-        };
-      }
-    }, false, function suddenDeath()
-    {
-      ok(false, "Tilt could not be initialized properly.");
-      cleanup();
-    });
-  });
-}
-
-function whenNodeRemoved() {
-  ok(presenter._currentSelection > 0,
-    "Deleting a node shouldn't change the current selection.");
-  ok(presenter._highlight.disabled,
-    "After deleting a node, it shouldn't be highlighted.");
-
-  let nodeIndex = presenter._currentSelection;
-  let vertices = presenter._meshStacks[0].vertices.components;
-
-  for (let i = 0, k = 36 * nodeIndex; i < 36; i++) {
-    is(vertices[i + k], 0,
-      "The stack vertices weren't degenerated properly.");
-  }
-
-  executeSoon(function() {
-    Services.obs.addObserver(cleanup, DESTROYED, false);
-    Tilt.destroy(Tilt.currentWindowId);
-  });
-}
-
-function cleanup() {
-  if (nodeDeleted) { Services.obs.removeObserver(cleanup, DESTROYED); }
-  gBrowser.removeCurrentTab();
-  finish();
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_picking_highlight01-offs.js
+++ /dev/null
@@ -1,77 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-var nodeHighlighted = false;
-var presenter;
-
-function test() {
-  if (!isTiltEnabled()) {
-    aborting();
-    info("Skipping highlight test because Tilt isn't enabled.");
-    return;
-  }
-  if (!isWebGLSupported()) {
-    aborting();
-    info("Skipping highlight test because WebGL isn't supported.");
-    return;
-  }
-
-  waitForExplicitFinish();
-
-  createTab(function() {
-    createTilt({
-      onTiltOpen: function(instance)
-      {
-        presenter = instance.presenter;
-        Services.obs.addObserver(whenHighlighting, HIGHLIGHTING, false);
-
-        presenter._onInitializationFinished = function() {
-          let contentDocument = presenter.contentWindow.document;
-          let div = contentDocument.getElementById("far-far-away");
-
-          nodeHighlighted = true;
-          presenter.highlightNode(div, "moveIntoView");
-        };
-      }
-    }, false, function suddenDeath()
-    {
-      ok(false, "Tilt could not be initialized properly.");
-      cleanup();
-    });
-  });
-}
-
-function whenHighlighting() {
-  ok(presenter._currentSelection > 0,
-    "Highlighting a node didn't work properly.");
-  ok(!presenter._highlight.disabled,
-    "After highlighting a node, it should be highlighted. D'oh.");
-  ok(presenter.controller.arcball._resetInProgress,
-    "Highlighting a node that's not already visible should trigger a reset!");
-
-  executeSoon(function() {
-    Services.obs.removeObserver(whenHighlighting, HIGHLIGHTING);
-    Services.obs.addObserver(whenUnhighlighting, UNHIGHLIGHTING, false);
-    presenter.highlightNode(null);
-  });
-}
-
-function whenUnhighlighting() {
-  ok(presenter._currentSelection < 0,
-    "Unhighlighting a should remove the current selection.");
-  ok(presenter._highlight.disabled,
-    "After unhighlighting a node, it shouldn't be highlighted anymore. D'oh.");
-
-  executeSoon(function() {
-    Services.obs.removeObserver(whenUnhighlighting, UNHIGHLIGHTING);
-    Services.obs.addObserver(cleanup, DESTROYED, false);
-    Tilt.destroy(Tilt.currentWindowId);
-  });
-}
-
-function cleanup() {
-  if (nodeHighlighted) { Services.obs.removeObserver(cleanup, DESTROYED); }
-  gBrowser.removeCurrentTab();
-  finish();
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_picking_highlight01.js
+++ /dev/null
@@ -1,77 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-var nodeHighlighted = false;
-var presenter;
-
-function test() {
-  if (!isTiltEnabled()) {
-    aborting();
-    info("Skipping highlight test because Tilt isn't enabled.");
-    return;
-  }
-  if (!isWebGLSupported()) {
-    aborting();
-    info("Skipping highlight test because WebGL isn't supported.");
-    return;
-  }
-
-  waitForExplicitFinish();
-
-  createTab(function() {
-    createTilt({
-      onTiltOpen: function(instance)
-      {
-        presenter = instance.presenter;
-        Services.obs.addObserver(whenHighlighting, HIGHLIGHTING, false);
-
-        presenter._onInitializationFinished = function() {
-          let contentDocument = presenter.contentWindow.document;
-          let div = contentDocument.getElementById("first-law");
-
-          nodeHighlighted = true;
-          presenter.highlightNode(div, "moveIntoView");
-        };
-      }
-    }, false, function suddenDeath()
-    {
-      ok(false, "Tilt could not be initialized properly.");
-      cleanup();
-    });
-  });
-}
-
-function whenHighlighting() {
-  ok(presenter._currentSelection > 0,
-    "Highlighting a node didn't work properly.");
-  ok(!presenter._highlight.disabled,
-    "After highlighting a node, it should be highlighted. D'oh.");
-  ok(!presenter.controller.arcball._resetInProgress,
-    "Highlighting a node that's already visible shouldn't trigger a reset.");
-
-  executeSoon(function() {
-    Services.obs.removeObserver(whenHighlighting, HIGHLIGHTING);
-    Services.obs.addObserver(whenUnhighlighting, UNHIGHLIGHTING, false);
-    presenter.highlightNode(null);
-  });
-}
-
-function whenUnhighlighting() {
-  ok(presenter._currentSelection < 0,
-    "Unhighlighting a should remove the current selection.");
-  ok(presenter._highlight.disabled,
-    "After unhighlighting a node, it shouldn't be highlighted anymore. D'oh.");
-
-  executeSoon(function() {
-    Services.obs.removeObserver(whenUnhighlighting, UNHIGHLIGHTING);
-    Services.obs.addObserver(cleanup, DESTROYED, false);
-    Tilt.destroy(Tilt.currentWindowId);
-  });
-}
-
-function cleanup() {
-  if (nodeHighlighted) { Services.obs.removeObserver(cleanup, DESTROYED); }
-  gBrowser.removeCurrentTab();
-  finish();
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_picking_highlight02.js
+++ /dev/null
@@ -1,72 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-var nodeHighlighted = false;
-var presenter;
-
-function test() {
-  if (!isTiltEnabled()) {
-    aborting();
-    info("Skipping highlight test because Tilt isn't enabled.");
-    return;
-  }
-  if (!isWebGLSupported()) {
-    aborting();
-    info("Skipping highlight test because WebGL isn't supported.");
-    return;
-  }
-
-  waitForExplicitFinish();
-
-  createTab(function() {
-    createTilt({
-      onTiltOpen: function(instance)
-      {
-        presenter = instance.presenter;
-        Services.obs.addObserver(whenHighlighting, HIGHLIGHTING, false);
-
-        presenter._onInitializationFinished = function() {
-          nodeHighlighted = true;
-          presenter.highlightNodeAt.apply(this, getPickablePoint(presenter));
-        };
-      }
-    }, false, function suddenDeath()
-    {
-      ok(false, "Tilt could not be initialized properly.");
-      cleanup();
-    });
-  });
-}
-
-function whenHighlighting() {
-  ok(presenter._currentSelection > 0,
-    "Highlighting a node didn't work properly.");
-  ok(!presenter._highlight.disabled,
-    "After highlighting a node, it should be highlighted. D'oh.");
-
-  executeSoon(function() {
-    Services.obs.removeObserver(whenHighlighting, HIGHLIGHTING);
-    Services.obs.addObserver(whenUnhighlighting, UNHIGHLIGHTING, false);
-    presenter.highlightNode(null);
-  });
-}
-
-function whenUnhighlighting() {
-  ok(presenter._currentSelection < 0,
-    "Unhighlighting a should remove the current selection.");
-  ok(presenter._highlight.disabled,
-    "After unhighlighting a node, it shouldn't be highlighted anymore. D'oh.");
-
-  executeSoon(function() {
-    Services.obs.removeObserver(whenUnhighlighting, UNHIGHLIGHTING);
-    Services.obs.addObserver(cleanup, DESTROYED, false);
-    Tilt.destroy(Tilt.currentWindowId);
-  });
-}
-
-function cleanup() {
-  if (nodeHighlighted) { Services.obs.removeObserver(cleanup, DESTROYED); }
-  gBrowser.removeCurrentTab();
-  finish();
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_picking_highlight03.js
+++ /dev/null
@@ -1,72 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-var nodeHighlighted = false;
-var presenter;
-
-function test() {
-  if (!isTiltEnabled()) {
-    aborting();
-    info("Skipping highlight test because Tilt isn't enabled.");
-    return;
-  }
-  if (!isWebGLSupported()) {
-    aborting();
-    info("Skipping highlight test because WebGL isn't supported.");
-    return;
-  }
-
-  waitForExplicitFinish();
-
-  createTab(function() {
-    createTilt({
-      onTiltOpen: function(instance)
-      {
-        presenter = instance.presenter;
-        Services.obs.addObserver(whenHighlighting, HIGHLIGHTING, false);
-
-        presenter._onInitializationFinished = function() {
-          nodeHighlighted = true;
-          presenter.highlightNodeFor(3); // 1 = html, 2 = body, 3 = first div
-        };
-      }
-    }, false, function suddenDeath()
-    {
-      ok(false, "Tilt could not be initialized properly.");
-      cleanup();
-    });
-  });
-}
-
-function whenHighlighting() {
-  ok(presenter._currentSelection > 0,
-    "Highlighting a node didn't work properly.");
-  ok(!presenter._highlight.disabled,
-    "After highlighting a node, it should be highlighted. D'oh.");
-
-  executeSoon(function() {
-    Services.obs.removeObserver(whenHighlighting, HIGHLIGHTING);
-    Services.obs.addObserver(whenUnhighlighting, UNHIGHLIGHTING, false);
-    presenter.highlightNodeFor(-1);
-  });
-}
-
-function whenUnhighlighting() {
-  ok(presenter._currentSelection < 0,
-    "Unhighlighting a should remove the current selection.");
-  ok(presenter._highlight.disabled,
-    "After unhighlighting a node, it shouldn't be highlighted anymore. D'oh.");
-
-  executeSoon(function() {
-    Services.obs.removeObserver(whenUnhighlighting, UNHIGHLIGHTING);
-    Services.obs.addObserver(cleanup, DESTROYED, false);
-    Tilt.destroy(Tilt.currentWindowId);
-  });
-}
-
-function cleanup() {
-  if (nodeHighlighted) { Services.obs.removeObserver(cleanup, DESTROYED); }
-  gBrowser.removeCurrentTab();
-  finish();
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_picking_inspector.js
+++ /dev/null
@@ -1,76 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-Components.utils.import("resource://gre/modules/Task.jsm");
-var promise = require("promise");
-
-function test() {
-  if (!isTiltEnabled()) {
-    aborting();
-    info("Skipping highlight test because Tilt isn't enabled.");
-    return;
-  }
-  if (!isWebGLSupported()) {
-    aborting();
-    info("Skipping highlight test because WebGL isn't supported.");
-    return;
-  }
-
-  waitForExplicitFinish();
-
-  createTab(function() {
-    let {TargetFactory} = require("devtools/client/framework/target");
-    let target = TargetFactory.forTab(gBrowser.selectedTab);
-
-    gDevTools.showToolbox(target, "inspector")
-             .then(Task.async(onToolbox));
-  });
-}
-
-function* onToolbox(toolbox) {
-  let contentDocument = toolbox.target.tab.linkedBrowser.contentDocument;
-  let div = contentDocument.getElementById("first-law");
-  let inspector = toolbox.getPanel("inspector");
-
-  let onInspectorUpdated = inspector.once("inspector-updated");
-  inspector.selection.setNode(div);
-  yield onInspectorUpdated;
-
-  let deferred = promise.defer();
-  onInspectorUpdated = inspector.once("inspector-updated");
-  createTilt({
-    onTiltOpen: function(instance)
-    {
-      deferred.resolve(instance.presenter);
-    }
-  }, false, function suddenDeath()
-  {
-    ok(false, "Tilt could not be initialized properly.");
-    cleanup();
-  });
-  let presenter = yield deferred.promise;
-  yield onInspectorUpdated;
-
-  whenOpen(presenter);
-}
-
-function whenOpen(presenter) {
-  ok(presenter._currentSelection > 0,
-    "Highlighting a node didn't work properly.");
-  ok(!presenter._highlight.disabled,
-    "After highlighting a node, it should be highlighted. D'oh.");
-  ok(!presenter.controller.arcball._resetInProgress,
-    "Highlighting a node that's already visible shouldn't trigger a reset.");
-
-  executeSoon(function() {
-    Services.obs.addObserver(cleanup, DESTROYED, false);
-    Tilt.destroy(Tilt.currentWindowId);
-  });
-}
-
-function cleanup() {
-  Services.obs.removeObserver(cleanup, DESTROYED);
-  gBrowser.removeCurrentTab();
-  finish();
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_picking_miv.js
+++ /dev/null
@@ -1,78 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-var nodeHighlighted = false;
-var presenter;
-
-function test() {
-  if (!isTiltEnabled()) {
-    aborting();
-    info("Skipping highlight test because Tilt isn't enabled.");
-    return;
-  }
-  if (!isWebGLSupported()) {
-    aborting();
-    info("Skipping highlight test because WebGL isn't supported.");
-    return;
-  }
-
-  waitForExplicitFinish();
-
-  createTab(function() {
-    createTilt({
-      onTiltOpen: function(instance)
-      {
-        presenter = instance.presenter;
-        Services.obs.addObserver(whenHighlighting, HIGHLIGHTING, false);
-
-        presenter._onInitializationFinished = function() {
-          let contentDocument = presenter.contentWindow.document;
-          let div = contentDocument.getElementById("far-far-away");
-
-          nodeHighlighted = true;
-          presenter.highlightNode(div);
-        };
-      }
-    }, false, function suddenDeath()
-    {
-      ok(false, "Tilt could not be initialized properly.");
-      cleanup();
-    });
-  });
-}
-
-function whenHighlighting() {
-  ok(presenter._currentSelection > 0,
-    "Highlighting a node didn't work properly.");
-  ok(!presenter._highlight.disabled,
-    "After highlighting a node, it should be highlighted. D'oh.");
-  ok(!presenter.controller.arcball._resetInProgress,
-    "Highlighting a node that's not already visible shouldn't trigger a reset " +
-    "without this being explicitly requested!");
-
-  EventUtils.sendKey("F");
-  executeSoon(whenBringingIntoView);
-}
-
-function whenBringingIntoView() {
-  ok(presenter._currentSelection > 0,
-    "The node should still be selected.");
-  ok(!presenter._highlight.disabled,
-    "The node should still be highlighted");
-  ok(presenter.controller.arcball._resetInProgress,
-    "Highlighting a node that's not already visible should trigger a reset " +
-    "when this is being explicitly requested!");
-
-  executeSoon(function() {
-    Services.obs.removeObserver(whenHighlighting, HIGHLIGHTING);
-    Services.obs.addObserver(cleanup, DESTROYED, false);
-    Tilt.destroy(Tilt.currentWindowId);
-  });
-}
-
-function cleanup() {
-  if (nodeHighlighted) { Services.obs.removeObserver(cleanup, DESTROYED); }
-  gBrowser.removeCurrentTab();
-  finish();
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_utils01.js
+++ /dev/null
@@ -1,69 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-function test() {
-  let prefs = TiltUtils.Preferences;
-  ok(prefs, "The TiltUtils.Preferences wasn't found.");
-
-  prefs.create("test-pref-bool", "boolean", true);
-  prefs.create("test-pref-int", "integer", 42);
-  prefs.create("test-pref-string", "string", "hello world!");
-
-  is(prefs.get("test-pref-bool", "boolean"), true,
-    "The boolean test preference wasn't initially set correctly.");
-  is(prefs.get("test-pref-int", "integer"), 42,
-    "The integer test preference wasn't initially set correctly.");
-  is(prefs.get("test-pref-string", "string"), "hello world!",
-    "The string test preference wasn't initially set correctly.");
-
-
-  prefs.set("test-pref-bool", "boolean", false);
-  prefs.set("test-pref-int", "integer", 24);
-  prefs.set("test-pref-string", "string", "!dlrow olleh");
-
-  is(prefs.get("test-pref-bool", "boolean"), false,
-    "The boolean test preference wasn't changed correctly.");
-  is(prefs.get("test-pref-int", "integer"), 24,
-    "The integer test preference wasn't changed correctly.");
-  is(prefs.get("test-pref-string", "string"), "!dlrow olleh",
-    "The string test preference wasn't changed correctly.");
-
-
-  is(typeof prefs.get("unknown-pref", "boolean"), "undefined",
-    "Inexisted boolean prefs should be handled as undefined.");
-  is(typeof prefs.get("unknown-pref", "integer"), "undefined",
-    "Inexisted integer prefs should be handled as undefined.");
-  is(typeof prefs.get("unknown-pref", "string"), "undefined",
-    "Inexisted string prefs should be handled as undefined.");
-
-
-  is(prefs.get("test-pref-bool", "integer"), null,
-    "The get() boolean function didn't handle incorrect types as it should.");
-  is(prefs.get("test-pref-bool", "string"), null,
-    "The get() boolean function didn't handle incorrect types as it should.");
-  is(prefs.get("test-pref-int", "boolean"), null,
-    "The get() integer function didn't handle incorrect types as it should.");
-  is(prefs.get("test-pref-int", "string"), null,
-    "The get() integer function didn't handle incorrect types as it should.");
-  is(prefs.get("test-pref-string", "boolean"), null,
-    "The get() string function didn't handle incorrect types as it should.");
-  is(prefs.get("test-pref-string", "integer"), null,
-    "The get() string function didn't handle incorrect types as it should.");
-
-
-  is(typeof prefs.get(), "undefined",
-    "The get() function should not work if not enough params are passed.");
-  is(typeof prefs.set(), "undefined",
-    "The set() function should not work if not enough params are passed.");
-  is(typeof prefs.create(), "undefined",
-    "The create() function should not work if not enough params are passed.");
-
-
-  is(prefs.get("test-pref-wrong-type", "wrong-type", 1), null,
-    "The get() function should expect only correct pref types.");
-  is(prefs.set("test-pref-wrong-type", "wrong-type", 1), false,
-    "The set() function should expect only correct pref types.");
-  is(prefs.create("test-pref-wrong-type", "wrong-type", 1), false,
-    "The create() function should expect only correct pref types.");
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_utils02.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-function test() {
-  let l10 = TiltUtils.L10n;
-  ok(l10, "The TiltUtils.L10n wasn't found.");
-
-
-  ok(l10.stringBundle,
-    "The necessary string bundle wasn't found.");
-  is(l10.get(), null,
-    "The get() function shouldn't work if no params are passed.");
-  is(l10.format(), null,
-    "The format() function shouldn't work if no params are passed.");
-
-  is(typeof l10.get("initWebGL.error"), "string",
-    "No valid string was returned from a correct name in the bundle.");
-  is(typeof l10.format("linkProgram.error", ["error"]), "string",
-    "No valid formatted string was returned from a name in the bundle.");
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_utils03.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-function test() {
-  let dom = TiltUtils.DOM;
-
-  is(dom.parentNode, null,
-    "The parent node should not be initially set.");
-
-  dom.parentNode = {};
-  ok(dom.parentNode,
-    "The parent node should now be set.");
-
-  TiltUtils.clearCache();
-  is(dom.parentNode, null,
-    "The parent node should not be set after clearing the cache.");
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_utils04.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-function test() {
-  let dom = TiltUtils.DOM;
-  ok(dom, "The TiltUtils.DOM wasn't found.");
-
-
-  is(dom.initCanvas(), null,
-    "The initCanvas() function shouldn't work if no parent node is set.");
-
-
-  dom.parentNode = gBrowser.parentNode;
-  ok(dom.parentNode,
-    "The necessary parent node wasn't found.");
-
-
-  let canvas = dom.initCanvas(null, {
-    append: true,
-    focusable: true,
-    width: 123,
-    height: 456,
-    id: "tilt-test-canvas"
-  });
-
-  is(canvas.width, 123,
-    "The test canvas doesn't have the correct width set.");
-  is(canvas.height, 456,
-    "The test canvas doesn't have the correct height set.");
-  is(canvas.getAttribute("tabindex"), 1,
-    "The test canvas tab index wasn't set correctly.");
-  is(canvas.getAttribute("id"), "tilt-test-canvas",
-    "The test canvas doesn't have the correct id set.");
-  ok(dom.parentNode.ownerDocument.getElementById(canvas.id),
-    "A canvas should be appended to the parent node if specified.");
-  canvas.parentNode.removeChild(canvas);
-
-  let canvas2 = dom.initCanvas(null, { id: "tilt-test-canvas2" });
-
-  is(canvas2.width, dom.parentNode.clientWidth,
-    "The second test canvas doesn't have the implicit width set.");
-  is(canvas2.height, dom.parentNode.clientHeight,
-    "The second test canvas doesn't have the implicit height set.");
-  is(canvas2.id, "tilt-test-canvas2",
-    "The second test canvas doesn't have the correct id set.");
-  is(dom.parentNode.ownerDocument.getElementById(canvas2.id), null,
-    "A canvas shouldn't be appended to the parent node if not specified.");
-
-
-  dom.parentNode = null;
-  is(dom.parentNode, null,
-    "The necessary parent node shouldn't be found anymore.");
-}
deleted file mode 100644
--- a/devtools/client/tilt/test/browser_tilt_utils05.js
+++ /dev/null
@@ -1,101 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-"use strict";
-
-const STACK_THICKNESS = 15;
-
-function init(callback) {
-  let iframe = gBrowser.ownerDocument.createElement("iframe");
-
-  iframe.addEventListener("load", function onLoad() {
-    iframe.removeEventListener("load", onLoad, true);
-    callback(iframe);
-
-    gBrowser.parentNode.removeChild(iframe);
-    finish();
-  }, true);
-
-  iframe.setAttribute("src", ["data:text/html,",
-    "<!DOCTYPE html>",
-    "<html>",
-      "<head>",
-        "<style>",
-        "</style>",
-        "<script>",
-        "</script>",
-      "</head>",
-      "<body style='margin: 0;'>",
-        "<div style='margin-top: 98px;" +
-                    "margin-left: 76px;" +
-                    "width: 123px;" +
-                    "height: 456px;' id='test-div'>",
-          "<span></span>",
-        "</div>",
-      "</body>",
-    "</html>"
-  ].join(""));
-
-  gBrowser.parentNode.appendChild(iframe);
-}
-
-function test() {
-  waitForExplicitFinish();
-  ok(TiltUtils, "The TiltUtils object doesn't exist.");
-
-  let dom = TiltUtils.DOM;
-  ok(dom, "The TiltUtils.DOM wasn't found.");
-
-  init(function(iframe) {
-    let cwDimensions = dom.getContentWindowDimensions(iframe.contentWindow);
-
-    is(cwDimensions.width - iframe.contentWindow.scrollMaxX,
-      iframe.contentWindow.innerWidth,
-      "The content window width wasn't calculated correctly.");
-    is(cwDimensions.height - iframe.contentWindow.scrollMaxY,
-      iframe.contentWindow.innerHeight,
-      "The content window height wasn't calculated correctly.");
-
-    let nodeCoordinates = getRect(
-      gBrowser.contentWindow,
-      iframe.contentDocument.getElementById("test-div"), iframe.contentWindow);
-
-    let frameOffset = getIframeContentOffset(iframe);
-    let frameRect = iframe.getBoundingClientRect();
-
-    is(nodeCoordinates.top, frameRect.top + frameOffset[0] + 98,
-      "The node coordinates top value wasn't calculated correctly.");
-    is(nodeCoordinates.left, frameRect.left + frameOffset[1] + 76,
-      "The node coordinates left value wasn't calculated correctly.");
-    is(nodeCo