Merge m-c to b2g-inbound. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 15 Jun 2015 15:58:10 -0400
changeset 267007 9d4200cadeaf0cd4c65808cdd68b11ae534086d5
parent 267006 f4d2f27b10d29d7c2cbabb82ec598f6836f603af (current diff)
parent 266991 cd0d976e5f5c6389512cad8f2cae03526b0fb0f3 (diff)
child 267008 139a0155fd44b7abe7527afa7fbd207e7b0a652c
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-esr52@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone41.0a1
Merge m-c to b2g-inbound. a=merge
browser/devtools/animationinspector/test/browser_animation_timeline_animates.js
browser/devtools/animationinspector/test/browser_animation_timeline_is_enabled.js
browser/devtools/animationinspector/test/browser_animation_timeline_waits_for_delay.js
browser/devtools/performance/test/browser_marker-utils.js
browser/devtools/performance/test/browser_timeline-blueprint.js
build/pgo/certs/bug483440-attack2b.ca
build/pgo/certs/bug483440-attack7.ca
build/pgo/certs/bug483440-pk10oflo.ca
dom/inputmethod/mochitest/file_test_contenteditable.html
layout/mathml/MathJaxFonts.html
layout/mathml/mathfontMathJax_Main.properties
layout/mathml/mathfontStandardSymbolsL.properties
netwerk/test/TestSTSParser.cpp
security/manager/ssl/tests/mochitest/bugs/test_bug483440.html
--- a/accessible/atk/nsMaiInterfaceText.cpp
+++ b/accessible/atk/nsMaiInterfaceText.cpp
@@ -27,23 +27,25 @@ ConvertTextAttributeToAtkAttribute(const
                                    const nsAString& aValue,
                                    AtkAttributeSet** aAttributeSet)
 {
   // Handle attributes where atk has its own name.
   const char* atkName = nullptr;
   nsAutoString atkValue;
   if (aName.EqualsLiteral("color")) {
     // The format of the atk attribute is r,g,b and the gecko one is
-    // rgb(r,g,b).
-    atkValue = Substring(aValue, 5, aValue.Length() - 1);
+    // rgb(r, g, b).
+    atkValue = Substring(aValue, 4, aValue.Length() - 5);
+    atkValue.StripWhitespace();
     atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_FG_COLOR];
   } else if (aName.EqualsLiteral("background-color")) {
     // The format of the atk attribute is r,g,b and the gecko one is
-    // rgb(r,g,b).
-    atkValue = Substring(aValue, 5, aValue.Length() - 1);
+    // rgb(r, g, b).
+    atkValue = Substring(aValue, 4, aValue.Length() - 5);
+    atkValue.StripWhitespace();
     atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_BG_COLOR];
   } else if (aName.EqualsLiteral("font-family")) {
     atkValue = aValue;
     atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_FAMILY_NAME];
   } else if (aName.EqualsLiteral("font-size")) {
     // ATK wants the number of pixels without px at the end.
     atkValue = StringHead(aValue, aValue.Length() - 2);
     atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_SIZE];
--- a/browser/base/content/tab-content.js
+++ b/browser/base/content/tab-content.js
@@ -332,38 +332,69 @@ let AboutReaderListener = {
           // Update the toolbar icon to show the "reader active" icon.
           sendAsyncMessage("Reader:UpdateReaderButton");
           new AboutReader(global, content, this._articlePromise);
           this._articlePromise = null;
         }
         break;
 
       case "pagehide":
+        this.cancelPotentialPendingReadabilityCheck();
         sendAsyncMessage("Reader:UpdateReaderButton", { isArticle: false });
         break;
 
       case "pageshow":
         // If a page is loaded from the bfcache, we won't get a "DOMContentLoaded"
         // event, so we need to rely on "pageshow" in this case.
         if (aEvent.persisted) {
           this.updateReaderButton();
         }
         break;
       case "DOMContentLoaded":
         this.updateReaderButton();
         break;
 
     }
   },
+
+  /**
+   * NB: this function will update the state of the reader button asynchronously
+   * after the next mozAfterPaint call (assuming reader mode is enabled and 
+   * this is a suitable document). Calling it on things which won't be
+   * painted is not going to work.
+   */
   updateReaderButton: function(forceNonArticle) {
     if (!ReaderMode.isEnabledForParseOnLoad || this.isAboutReader ||
         !(content.document instanceof content.HTMLDocument) ||
         content.document.mozSyntheticDocument) {
       return;
     }
+
+    this.scheduleReadabilityCheckPostPaint(forceNonArticle);
+  },
+
+  cancelPotentialPendingReadabilityCheck: function() {
+    if (this._pendingReadabilityCheck) {
+      removeEventListener("MozAfterPaint", this._pendingReadabilityCheck);
+      delete this._pendingReadabilityCheck;
+    }
+  },
+
+  scheduleReadabilityCheckPostPaint: function(forceNonArticle) {
+    if (this._pendingReadabilityCheck) {
+      // We need to stop this check before we re-add one because we don't know
+      // if forceNonArticle was true or false last time.
+      this.cancelPotentialPendingReadabilityCheck();
+    }
+    this._pendingReadabilityCheck = this.onPaintWhenWaitedFor.bind(this, forceNonArticle);
+    addEventListener("MozAfterPaint", this._pendingReadabilityCheck);
+  },
+
+  onPaintWhenWaitedFor: function(forceNonArticle) {
+    this.cancelPotentialPendingReadabilityCheck();
     // Only send updates when there are articles; there's no point updating with
     // |false| all the time.
     if (ReaderMode.isProbablyReaderable(content.document)) {
       sendAsyncMessage("Reader:UpdateReaderButton", { isArticle: true });
     } else if (forceNonArticle) {
       sendAsyncMessage("Reader:UpdateReaderButton", { isArticle: false });
     }
   },
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -473,12 +473,15 @@ skip-if = e10s # Bug 1100687 - test dire
 skip-if = e10s # bug 1100687 - test directly manipulates content (content.document.getElementById)
 [browser_mcb_redirect.js]
 [browser_windowactivation.js]
 [browser_contextmenu_childprocess.js]
 [browser_bug963945.js]
 [browser_readerMode.js]
 support-files =
   readerModeArticle.html
+[browser_readerMode_hidden_nodes.js]
+support-files =
+  readerModeArticleHiddenNodes.html
 [browser_bug1124271_readerModePinnedTab.js]
 support-files =
   readerModeArticle.html
 [browser_domFullscreen_fullscreenMode.js]
copy from browser/base/content/test/general/browser_readerMode.js
copy to browser/base/content/test/general/browser_readerMode_hidden_nodes.js
--- a/browser/base/content/test/general/browser_readerMode.js
+++ b/browser/base/content/test/general/browser_readerMode_hidden_nodes.js
@@ -4,18 +4,17 @@
 
 /**
  * Test that the reader mode button appears and works properly on
  * reader-able content, and that ReadingList button can open and close
  * its Sidebar UI.
  */
 const TEST_PREFS = [
   ["reader.parse-on-load.enabled", true],
-  ["browser.readinglist.enabled", true],
-  ["browser.readinglist.introShown", false],
+  ["browser.reader.detectedFirstArticle", false],
 ];
 
 const TEST_PATH = "http://example.com/browser/browser/base/content/test/general/";
 
 let readerButton = document.getElementById("reader-mode-button");
 
 add_task(function* test_reader_button() {
   registerCleanupFunction(function() {
@@ -27,89 +26,20 @@ add_task(function* test_reader_button() 
       gBrowser.removeCurrentTab();
     }
   });
 
   // Set required test prefs.
   TEST_PREFS.forEach(([name, value]) => {
     Services.prefs.setBoolPref(name, value);
   });
-  Services.prefs.setBoolPref("browser.reader.detectedFirstArticle", false);
 
   let tab = gBrowser.selectedTab = gBrowser.addTab();
   is_element_hidden(readerButton, "Reader mode button is not present on a new tab");
-  ok(!UITour.isInfoOnTarget(window, "readerMode-urlBar"),
-     "Info panel shouldn't appear without the reader mode button");
-  ok(!Services.prefs.getBoolPref("browser.reader.detectedFirstArticle"),
-     "Shouldn't have detected the first article");
-
-  // Point tab to a test page that is reader-able.
-  let url = TEST_PATH + "readerModeArticle.html";
+  // Point tab to a test page that is not reader-able due to hidden nodes.
+  let url = TEST_PATH + "readerModeArticleHiddenNodes.html";
   yield promiseTabLoadEvent(tab, url);
-  yield promiseWaitForCondition(() => !readerButton.hidden);
-  is_element_visible(readerButton, "Reader mode button is present on a reader-able page");
-  ok(UITour.isInfoOnTarget(window, "readerMode-urlBar"),
-     "Info panel should be anchored at the reader mode button");
-  ok(Services.prefs.getBoolPref("browser.reader.detectedFirstArticle"),
-     "Should have detected the first article");
-
-  // Switch page into reader mode.
-  readerButton.click();
-  yield promiseTabLoadEvent(tab);
-  ok(!UITour.isInfoOnTarget(window, "readerMode-urlBar"), "Info panel should have closed");
-
-  let readerUrl = gBrowser.selectedBrowser.currentURI.spec;
-  ok(readerUrl.startsWith("about:reader"), "about:reader loaded after clicking reader mode button");
-  is_element_visible(readerButton, "Reader mode button is present on about:reader");
-
-  is(gURLBar.value, readerUrl, "gURLBar value is about:reader URL");
-  is(gURLBar.textValue, url.substring("http://".length), "gURLBar is displaying original article URL");
-
-  // Readinglist button should be present, and status should be "openned", as the
-  // first time in readerMode opens the Sidebar ReadingList as a feature introduction.
-  let listButton;
-  yield promiseWaitForCondition(() =>
-    listButton = gBrowser.contentDocument.getElementById("list-button"));
-  is_element_visible(listButton, "List button is present on a reader-able page");
-  yield promiseWaitForCondition(() => listButton.classList.contains("on"));
-  ok(listButton.classList.contains("on"),
-    "List button should indicate SideBar-ReadingList open.");
-  ok(ReadingListUI.isSidebarOpen,
-    "The ReadingListUI should indicate SideBar-ReadingList open.");
+  yield ContentTask.spawn(tab.linkedBrowser, "", function() {
+    return ContentTaskUtils.waitForEvent(content, "MozAfterPaint");
+  });
 
-  // Now close the Sidebar ReadingList.
-  listButton.click();
-  yield promiseWaitForCondition(() => !listButton.classList.contains("on"));
-  ok(!listButton.classList.contains("on"),
-    "List button should now indicate SideBar-ReadingList closed.");
-  ok(!ReadingListUI.isSidebarOpen,
-    "The ReadingListUI should now indicate SideBar-ReadingList closed.");
-
-  // Switch page back out of reader mode.
-  readerButton.click();
-  yield promiseTabLoadEvent(tab);
-  is(gBrowser.selectedBrowser.currentURI.spec, url,
-    "Original page loaded after clicking active reader mode button");
-
-  // Load a new tab that is NOT reader-able.
-  let newTab = gBrowser.selectedTab = gBrowser.addTab();
-  yield promiseTabLoadEvent(newTab, "about:robots");
-  yield promiseWaitForCondition(() => readerButton.hidden);
-  is_element_hidden(readerButton, "Reader mode button is not present on a non-reader-able page");
-
-  // Switch back to the original tab to make sure reader mode button is still visible.
-  gBrowser.removeCurrentTab();
-  yield promiseWaitForCondition(() => !readerButton.hidden);
-  is_element_visible(readerButton, "Reader mode button is present on a reader-able page");
+  is_element_hidden(readerButton, "Reader mode button is still not present on tab with unreadable content.");
 });
-
-add_task(function* test_getOriginalUrl() {
-  let { ReaderMode } = Cu.import("resource://gre/modules/ReaderMode.jsm", {});
-  let url = "http://foo.com/article.html";
-
-  is(ReaderMode.getOriginalUrl("about:reader?url=" + encodeURIComponent(url)), url, "Found original URL from encoded URL");
-  is(ReaderMode.getOriginalUrl("about:reader?foobar"), null, "Did not find original URL from malformed reader URL");
-  is(ReaderMode.getOriginalUrl(url), null, "Did not find original URL from non-reader URL");
-
-  let badUrl = "http://foo.com/?;$%^^";
-  is(ReaderMode.getOriginalUrl("about:reader?url=" + encodeURIComponent(badUrl)), badUrl, "Found original URL from encoded malformed URL");
-  is(ReaderMode.getOriginalUrl("about:reader?url=" + badUrl), badUrl, "Found original URL from non-encoded malformed URL");
-});
copy from browser/base/content/test/general/readerModeArticle.html
copy to browser/base/content/test/general/readerModeArticleHiddenNodes.html
--- a/browser/base/content/test/general/readerModeArticle.html
+++ b/browser/base/content/test/general/readerModeArticleHiddenNodes.html
@@ -1,15 +1,18 @@
 <!DOCTYPE html>
 <html>
 <head>
 <title>Article title</title>
 <meta name="description" content="This is the article description." />
 </head>
 <body>
+<style>
+p { display: none }
+</style>
 <header>Site header</header>
 <div>
 <h1>Article title</h1>
 <h2 class="author">by Jane Doe</h2>
 <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.</p>
 <p>Vivamus fermentum semper porta. Nunc diam velit, adipiscing ut tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper ultricies. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, id fringilla sem nunc vel mi. Nam dictum, odio nec pretium volutpat, arcu ante placerat erat, non tristique elit urna et turpis. Quisque mi metus, ornare sit amet fermentum et, tincidunt et orci. Fusce eget orci a orci congue vestibulum. Ut dolor diam, elementum et vestibulum eu, porttitor vel elit. Curabitur venenatis pulvinar tellus gravida ornare. Sed et erat faucibus nunc euismod ultricies ut id justo. Nullam cursus suscipit nisi, et ultrices justo sodales nec. Fusce venenatis facilisis lectus ac semper. Aliquam at massa ipsum. Quisque bibendum purus convallis nulla ultrices ultricies. Nullam aliquam, mi eu aliquam tincidunt, purus velit laoreet tortor, viverra pretium nisi quam vitae mi. Fusce vel volutpat elit. Nam sagittis nisi dui.</p>
 <p>Vivamus fermentum semper porta. Nunc diam velit, adipiscing ut tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper ultricies. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, id fringilla sem nunc vel mi. Nam dictum, odio nec pretium volutpat, arcu ante placerat erat, non tristique elit urna et turpis. Quisque mi metus, ornare sit amet fermentum et, tincidunt et orci. Fusce eget orci a orci congue vestibulum. Ut dolor diam, elementum et vestibulum eu, porttitor vel elit. Curabitur venenatis pulvinar tellus gravida ornare. Sed et erat faucibus nunc euismod ultricies ut id justo. Nullam cursus suscipit nisi, et ultrices justo sodales nec. Fusce venenatis facilisis lectus ac semper. Aliquam at massa ipsum. Quisque bibendum purus convallis nulla ultrices ultricies. Nullam aliquam, mi eu aliquam tincidunt, purus velit laoreet tortor, viverra pretium nisi quam vitae mi. Fusce vel volutpat elit. Nam sagittis nisi dui.</p>
 <p>Vivamus fermentum semper porta. Nunc diam velit, adipiscing ut tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper ultricies. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, id fringilla sem nunc vel mi. Nam dictum, odio nec pretium volutpat, arcu ante placerat erat, non tristique elit urna et turpis. Quisque mi metus, ornare sit amet fermentum et, tincidunt et orci. Fusce eget orci a orci congue vestibulum. Ut dolor diam, elementum et vestibulum eu, porttitor vel elit. Curabitur venenatis pulvinar tellus gravida ornare. Sed et erat faucibus nunc euismod ultricies ut id justo. Nullam cursus suscipit nisi, et ultrices justo sodales nec. Fusce venenatis facilisis lectus ac semper. Aliquam at massa ipsum. Quisque bibendum purus convallis nulla ultrices ultricies. Nullam aliquam, mi eu aliquam tincidunt, purus velit laoreet tortor, viverra pretium nisi quam vitae mi. Fusce vel volutpat elit. Nam sagittis nisi dui.</p>
--- a/browser/components/privatebrowsing/test/browser/browser.ini
+++ b/browser/components/privatebrowsing/test/browser/browser.ini
@@ -11,16 +11,17 @@ support-files =
   browser_privatebrowsing_placesTitleNoUpdate.html
   browser_privatebrowsing_protocolhandler_page.html
   browser_privatebrowsing_windowtitle_page.html
   head.js
   popup.html
   title.sjs
 
 [browser_privatebrowsing_DownloadLastDirWithCPS.js]
+skip-if = (os == "win" && os_version == "6.2") # bug 1173801
 [browser_privatebrowsing_aboutHomeButtonAfterWindowClose.js]
 [browser_privatebrowsing_aboutSessionRestore.js]
 [browser_privatebrowsing_cache.js]
 [browser_privatebrowsing_certexceptionsui.js]
 [browser_privatebrowsing_concurrent.js]
 [browser_privatebrowsing_cookieacceptdialog.js]
 skip-if = e10s # Bug 1139953 - Accept cookie dialog shown in private window when e10s enabled
 [browser_privatebrowsing_crh.js]
--- a/browser/devtools/animationinspector/animation-controller.js
+++ b/browser/devtools/animationinspector/animation-controller.js
@@ -109,16 +109,17 @@ let AnimationsController = {
     this.hasSetCurrentTime = yield target.actorHasMethod("animationplayer",
                                                          "setCurrentTime");
     this.hasMutationEvents = yield target.actorHasMethod("animations",
                                                          "stopAnimationPlayerUpdates");
     this.hasSetPlaybackRate = yield target.actorHasMethod("animationplayer",
                                                           "setPlaybackRate");
     this.hasTargetNode = yield target.actorHasMethod("domwalker",
                                                      "getNodeFromActor");
+    this.isNewUI = Services.prefs.getBoolPref("devtools.inspector.animationInspectorV3");
 
     if (this.destroyed) {
       console.warn("Could not fully initialize the AnimationsController");
       return;
     }
 
     this.startListeners();
     yield this.onNewNodeFront();
@@ -235,38 +236,50 @@ let AnimationsController = {
   }),
 
   onAnimationMutations: Task.async(function*(changes) {
     // Insert new players into this.animationPlayers when new animations are
     // added.
     for (let {type, player} of changes) {
       if (type === "added") {
         this.animationPlayers.push(player);
-        player.startAutoRefresh();
+        if (!this.isNewUI) {
+          player.startAutoRefresh();
+        }
       }
 
       if (type === "removed") {
-        player.stopAutoRefresh();
+        if (!this.isNewUI) {
+          player.stopAutoRefresh();
+        }
         yield player.release();
         let index = this.animationPlayers.indexOf(player);
         this.animationPlayers.splice(index, 1);
       }
     }
 
     // Let the UI know the list has been updated.
     this.emit(this.PLAYERS_UPDATED_EVENT, this.animationPlayers);
   }),
 
   startAllAutoRefresh: function() {
+    if (this.isNewUI) {
+      return;
+    }
+
     for (let front of this.animationPlayers) {
       front.startAutoRefresh();
     }
   },
 
   stopAllAutoRefresh: function() {
+    if (this.isNewUI) {
+      return;
+    }
+
     for (let front of this.animationPlayers) {
       front.stopAutoRefresh();
     }
   },
 
   destroyAnimationPlayers: Task.async(function*() {
     // Let the server know that we're not interested in receiving updates about
     // players for the current node. We're either being destroyed or a new node
--- a/browser/devtools/animationinspector/animation-panel.js
+++ b/browser/devtools/animationinspector/animation-panel.js
@@ -1,33 +1,37 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript 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/. */
+/* globals AnimationsController, document, performance, promise,
+   gToolbox, gInspector, requestAnimationFrame, cancelAnimationFrame, L10N */
 
 "use strict";
 
+const {createNode} = require("devtools/animationinspector/utils");
 const {
   PlayerMetaDataHeader,
   PlaybackRateSelector,
   AnimationTargetNode,
-  createNode
+  AnimationsTimeline
 } = require("devtools/animationinspector/components");
 
 /**
  * The main animations panel UI.
  */
 let AnimationsPanel = {
   UI_UPDATED_EVENT: "ui-updated",
   PANEL_INITIALIZED: "panel-initialized",
 
   initialize: Task.async(function*() {
     if (AnimationsController.destroyed) {
-      console.warn("Could not initialize the animation-panel, controller was destroyed");
+      console.warn("Could not initialize the animation-panel, controller " +
+                   "was destroyed");
       return;
     }
     if (this.initialized) {
       return this.initialized.promise;
     }
     this.initialized = promise.defer();
 
     this.playersEl = document.querySelector("#players");
@@ -40,23 +44,28 @@ let AnimationsPanel = {
     if (!AnimationsController.hasToggleAll) {
       document.querySelector("#toolbar").style.display = "none";
     }
 
     let hUtils = gToolbox.highlighterUtils;
     this.togglePicker = hUtils.togglePicker.bind(hUtils);
     this.onPickerStarted = this.onPickerStarted.bind(this);
     this.onPickerStopped = this.onPickerStopped.bind(this);
-    this.createPlayerWidgets = this.createPlayerWidgets.bind(this);
+    this.refreshAnimations = this.refreshAnimations.bind(this);
     this.toggleAll = this.toggleAll.bind(this);
     this.onTabNavigated = this.onTabNavigated.bind(this);
 
     this.startListeners();
 
-    yield this.createPlayerWidgets();
+    if (AnimationsController.isNewUI) {
+      this.animationsTimelineComponent = new AnimationsTimeline(gInspector);
+      this.animationsTimelineComponent.init(this.playersEl);
+    }
+
+    yield this.refreshAnimations();
 
     this.initialized.resolve();
 
     this.emit(this.PANEL_INITIALIZED);
   }),
 
   destroy: Task.async(function*() {
     if (!this.initialized) {
@@ -64,39 +73,44 @@ let AnimationsPanel = {
     }
 
     if (this.destroyed) {
       return this.destroyed.promise;
     }
     this.destroyed = promise.defer();
 
     this.stopListeners();
+
+    if (this.animationsTimelineComponent) {
+      this.animationsTimelineComponent.destroy();
+      this.animationsTimelineComponent = null;
+    }
     yield this.destroyPlayerWidgets();
 
     this.playersEl = this.errorMessageEl = null;
     this.toggleAllButtonEl = this.pickerButtonEl = null;
 
     this.destroyed.resolve();
   }),
 
   startListeners: function() {
     AnimationsController.on(AnimationsController.PLAYERS_UPDATED_EVENT,
-      this.createPlayerWidgets);
+      this.refreshAnimations);
 
     this.pickerButtonEl.addEventListener("click", this.togglePicker, false);
     gToolbox.on("picker-started", this.onPickerStarted);
     gToolbox.on("picker-stopped", this.onPickerStopped);
 
     this.toggleAllButtonEl.addEventListener("click", this.toggleAll, false);
     gToolbox.target.on("navigate", this.onTabNavigated);
   },
 
   stopListeners: function() {
     AnimationsController.off(AnimationsController.PLAYERS_UPDATED_EVENT,
-      this.createPlayerWidgets);
+      this.refreshAnimations);
 
     this.pickerButtonEl.removeEventListener("click", this.togglePicker, false);
     gToolbox.off("picker-started", this.onPickerStarted);
     gToolbox.off("picker-stopped", this.onPickerStopped);
 
     this.toggleAllButtonEl.removeEventListener("click", this.toggleAll, false);
     gToolbox.target.off("navigate", this.onTabNavigated);
   },
@@ -117,62 +131,75 @@ let AnimationsPanel = {
 
   onPickerStopped: function() {
     this.pickerButtonEl.removeAttribute("checked");
   },
 
   toggleAll: Task.async(function*() {
     let btnClass = this.toggleAllButtonEl.classList;
 
-    // Toggling all animations is async and it may be some time before each of
-    // the current players get their states updated, so toggle locally too, to
-    // avoid the timelines from jumping back and forth.
-    if (this.playerWidgets) {
-      let currentWidgetStateChange = [];
-      for (let widget of this.playerWidgets) {
-        currentWidgetStateChange.push(btnClass.contains("paused")
-          ? widget.play() : widget.pause());
+    if (!AnimationsController.isNewUI) {
+      // Toggling all animations is async and it may be some time before each of
+      // the current players get their states updated, so toggle locally too, to
+      // avoid the timelines from jumping back and forth.
+      if (this.playerWidgets) {
+        let currentWidgetStateChange = [];
+        for (let widget of this.playerWidgets) {
+          currentWidgetStateChange.push(btnClass.contains("paused")
+            ? widget.play() : widget.pause());
+        }
+        yield promise.all(currentWidgetStateChange).catch(Cu.reportError);
       }
-      yield promise.all(currentWidgetStateChange).catch(Cu.reportError);
     }
 
     btnClass.toggle("paused");
     yield AnimationsController.toggleAll();
   }),
 
   onTabNavigated: function() {
     this.toggleAllButtonEl.classList.remove("paused");
   },
 
-  createPlayerWidgets: Task.async(function*() {
+  refreshAnimations: Task.async(function*() {
     let done = gInspector.updating("animationspanel");
 
     // Empty the whole panel first.
     this.hideErrorMessage();
     yield this.destroyPlayerWidgets();
 
-    // If there are no players to show, show the error message instead and return.
+    // Re-render the timeline component.
+    if (this.animationsTimelineComponent) {
+      this.animationsTimelineComponent.render(
+        AnimationsController.animationPlayers);
+    }
+
+    // If there are no players to show, show the error message instead and
+    // return.
     if (!AnimationsController.animationPlayers.length) {
       this.displayErrorMessage();
       this.emit(this.UI_UPDATED_EVENT);
       done();
       return;
     }
 
-    // Otherwise, create player widgets.
-    this.playerWidgets = [];
-    let initPromises = [];
+    // Otherwise, create player widgets (only when isNewUI is false, the
+    // timeline has already been re-rendered).
+    if (!AnimationsController.isNewUI) {
+      this.playerWidgets = [];
+      let initPromises = [];
 
-    for (let player of AnimationsController.animationPlayers) {
-      let widget = new PlayerWidget(player, this.playersEl);
-      initPromises.push(widget.initialize());
-      this.playerWidgets.push(widget);
+      for (let player of AnimationsController.animationPlayers) {
+        let widget = new PlayerWidget(player, this.playersEl);
+        initPromises.push(widget.initialize());
+        this.playerWidgets.push(widget);
+      }
+
+      yield initPromises;
     }
 
-    yield initPromises;
     this.emit(this.UI_UPDATED_EVENT);
     done();
   }),
 
   destroyPlayerWidgets: Task.async(function*() {
     if (!this.playerWidgets) {
       return;
     }
@@ -387,31 +414,30 @@ PlayerWidget.prototype = {
    * Note that tests may want to call this callback directly rather than
    * simulating a click on the button since it returns the promise returned by
    * play and paused.
    * @return {Promise}
    */
   onPlayPauseBtnClick: function() {
     if (this.player.state.playState === "running") {
       return this.pause();
-    } else {
-      return this.play();
     }
+    return this.play();
   },
 
   onRewindBtnClick: function() {
     this.setCurrentTime(0, true);
   },
 
   onFastForwardBtnClick: function() {
     let state = this.player.state;
 
     let time = state.duration;
     if (state.iterationCount) {
-     time = state.iterationCount * state.duration;
+      time = state.iterationCount * state.duration;
     }
     this.setCurrentTime(time, true);
   },
 
   /**
    * Executed when the current-time range input is changed.
    */
   onCurrentTimeChanged: function(e) {
@@ -461,17 +487,18 @@ PlayerWidget.prototype = {
   /**
    * Set the current time of the animation.
    * @param {Number} time.
    * @param {Boolean} shouldPause Should the player be paused too.
    * @return {Promise} Resolves when the current time has been set.
    */
   setCurrentTime: Task.async(function*(time, shouldPause) {
     if (!AnimationsController.hasSetCurrentTime) {
-      throw new Error("This server version doesn't support setting animations' currentTime");
+      throw new Error("This server version doesn't support setting " +
+                      "animations' currentTime");
     }
 
     if (shouldPause) {
       this.stopTimelineAnimation();
       yield this.pause();
     }
 
     if (this.player.state.delay) {
@@ -487,17 +514,18 @@ PlayerWidget.prototype = {
 
   /**
    * Set the playback rate of the animation.
    * @param {Number} rate.
    * @return {Promise} Resolves when the rate has been set.
    */
   setPlaybackRate: function(rate) {
     if (!AnimationsController.hasSetPlaybackRate) {
-      throw new Error("This server version doesn't support setting animations' playbackRate");
+      throw new Error("This server version doesn't support setting " +
+                      "animations' playbackRate");
     }
 
     return this.player.setPlaybackRate(rate);
   },
 
   /**
    * Pause the animation player via this widget.
    * @return {Promise} Resolves when the player is paused, the button is
--- a/browser/devtools/animationinspector/components.js
+++ b/browser/devtools/animationinspector/components.js
@@ -1,34 +1,44 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript 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/. */
+/* globals ViewHelpers */
 
 "use strict";
 
 // Set of reusable UI components for the animation-inspector UI.
 // All components in this module share a common API:
 // 1. construct the component:
 //    let c = new ComponentName();
 // 2. initialize the markup of the component in a given parent node:
 //    c.init(containerElement);
 // 3. render the component, passing in some sort of state:
 //    This may be called over and over again when the state changes, to update
 //    the component output.
 //    c.render(state);
 // 4. destroy the component:
 //    c.destroy();
 
-const {Cu} = require('chrome');
+const {Cu} = require("chrome");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
+const {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
+const {
+  createNode,
+  drawGraphElementBackground,
+  findOptimalTimeInterval
+} = require("devtools/animationinspector/utils");
 
 const STRINGS_URI = "chrome://browser/locale/devtools/animationinspector.properties";
 const L10N = new ViewHelpers.L10N(STRINGS_URI);
+const MILLIS_TIME_FORMAT_MAX_DURATION = 4000;
+// The minimum spacing between 2 time graduation headers in the timeline (ms).
+const TIME_GRADUATION_MIN_SPACING = 40;
 
 /**
  * UI component responsible for displaying and updating the player meta-data:
  * name, duration, iterations, delay.
  * The parent UI component for this should drive its updates by calling
  * render(state) whenever it wants the component to update.
  */
 function PlayerMetaDataHeader() {
@@ -70,50 +80,50 @@ PlayerMetaDataHeader.prototype = {
       attributes: {
         "class": "meta-data"
       }
     });
 
     // Animation duration.
     this.durationLabel = createNode({
       parent: metaData,
-      nodeType: "span"
+      nodeType: "span",
+      textContent: L10N.getStr("player.animationDurationLabel")
     });
-    this.durationLabel.textContent = L10N.getStr("player.animationDurationLabel");
 
     this.durationValue = createNode({
       parent: metaData,
       nodeType: "strong"
     });
 
     // Animation delay (hidden by default since there may not be a delay).
     this.delayLabel = createNode({
       parent: metaData,
       nodeType: "span",
       attributes: {
         "style": "display:none;"
-      }
+      },
+      textContent: L10N.getStr("player.animationDelayLabel")
     });
-    this.delayLabel.textContent = L10N.getStr("player.animationDelayLabel");
 
     this.delayValue = createNode({
       parent: metaData,
       nodeType: "strong"
     });
 
     // Animation iteration count (also hidden by default since we don't display
     // single iterations).
     this.iterationLabel = createNode({
       parent: metaData,
       nodeType: "span",
       attributes: {
         "style": "display:none;"
-      }
+      },
+      textContent: L10N.getStr("player.animationIterationCountLabel")
     });
-    this.iterationLabel.textContent = L10N.getStr("player.animationIterationCountLabel");
 
     this.iterationValue = createNode({
       parent: metaData,
       nodeType: "strong",
       attributes: {
         "style": "display:none;"
       }
     });
@@ -219,17 +229,17 @@ PlaybackRateSelector.prototype = {
     }
   },
 
   /**
    * Get the ordered list of presets, including the current playbackRate if
    * different from the existing presets.
    */
   getCurrentPresets: function({playbackRate}) {
-    return [...new Set([...this.PRESETS, playbackRate])].sort((a,b) => a > b);
+    return [...new Set([...this.PRESETS, playbackRate])].sort((a, b) => a > b);
   },
 
   render: function(state) {
     if (state.playbackRate === this.currentRate) {
       return;
     }
 
     this.removeSelect();
@@ -243,43 +253,47 @@ PlaybackRateSelector.prototype = {
     });
 
     for (let preset of this.getCurrentPresets(state)) {
       let option = createNode({
         parent: this.el,
         nodeType: "option",
         attributes: {
           value: preset,
-        }
+        },
+        textContent: L10N.getFormatStr("player.playbackRateLabel", preset)
       });
-      option.textContent = L10N.getFormatStr("player.playbackRateLabel", preset);
       if (preset === state.playbackRate) {
         option.setAttribute("selected", "");
       }
     }
 
     this.el.addEventListener("change", this.onSelectionChanged);
 
     this.currentRate = state.playbackRate;
   },
 
-  onSelectionChanged: function(e) {
+  onSelectionChanged: function() {
     this.emit("rate-changed", parseFloat(this.el.value));
   }
 };
 
 /**
  * UI component responsible for displaying a preview of the target dom node of
  * a given animation.
  * @param {InspectorPanel} inspector Requires a reference to the inspector-panel
  * to highlight and select the node, as well as refresh it when there are
  * mutations.
+ * @param {Object} options Supported properties are:
+ * - compact {Boolean} Defaults to false. If true, nodes will be previewed like
+ *   tag#id.class instead of <tag id="id" class="class">
  */
-function AnimationTargetNode(inspector) {
+function AnimationTargetNode(inspector, options={}) {
   this.inspector = inspector;
+  this.options = options;
 
   this.onPreviewMouseOver = this.onPreviewMouseOver.bind(this);
   this.onPreviewMouseOut = this.onPreviewMouseOut.bind(this);
   this.onSelectNodeClick = this.onSelectNodeClick.bind(this);
   this.onMarkupMutations = this.onMarkupMutations.bind(this);
 
   EventEmitter.decorate(this);
 }
@@ -308,80 +322,107 @@ AnimationTargetNode.prototype = {
     });
 
     // Wrapper used for mouseover/out event handling.
     this.previewEl = createNode({
       parent: this.el,
       nodeType: "span"
     });
 
-    this.previewEl.appendChild(document.createTextNode("<"));
+    if (!this.options.compact) {
+      this.previewEl.appendChild(document.createTextNode("<"));
+    }
 
     // Tag name.
     this.tagNameEl = createNode({
       parent: this.previewEl,
       nodeType: "span",
       attributes: {
         "class": "tag-name theme-fg-color3"
       }
     });
 
     // Id attribute container.
     this.idEl = createNode({
       parent: this.previewEl,
       nodeType: "span"
     });
 
-    createNode({
-      parent: this.idEl,
-      nodeType: "span",
-      attributes: {
-        "class": "attribute-name theme-fg-color2"
-      }
-    }).textContent = "id";
-
-    this.idEl.appendChild(document.createTextNode("=\""));
+    if (!this.options.compact) {
+      createNode({
+        parent: this.idEl,
+        nodeType: "span",
+        attributes: {
+          "class": "attribute-name theme-fg-color2"
+        },
+        textContent: "id"
+      });
+      this.idEl.appendChild(document.createTextNode("=\""));
+    } else {
+      createNode({
+        parent: this.idEl,
+        nodeType: "span",
+        attributes: {
+          "class": "theme-fg-color2"
+        },
+        textContent: "#"
+      });
+    }
 
     createNode({
       parent: this.idEl,
       nodeType: "span",
       attributes: {
         "class": "attribute-value theme-fg-color6"
       }
     });
 
-    this.idEl.appendChild(document.createTextNode("\""));
+    if (!this.options.compact) {
+      this.idEl.appendChild(document.createTextNode("\""));
+    }
 
     // Class attribute container.
     this.classEl = createNode({
       parent: this.previewEl,
       nodeType: "span"
     });
 
-    createNode({
-      parent: this.classEl,
-      nodeType: "span",
-      attributes: {
-        "class": "attribute-name theme-fg-color2"
-      }
-    }).textContent = "class";
-
-    this.classEl.appendChild(document.createTextNode("=\""));
+    if (!this.options.compact) {
+      createNode({
+        parent: this.classEl,
+        nodeType: "span",
+        attributes: {
+          "class": "attribute-name theme-fg-color2"
+        },
+        textContent: "class"
+      });
+      this.classEl.appendChild(document.createTextNode("=\""));
+    } else {
+      createNode({
+        parent: this.classEl,
+        nodeType: "span",
+        attributes: {
+          "class": "theme-fg-color6"
+        },
+        textContent: "."
+      });
+    }
 
     createNode({
       parent: this.classEl,
       nodeType: "span",
       attributes: {
         "class": "attribute-value theme-fg-color6"
       }
     });
 
-    this.classEl.appendChild(document.createTextNode("\""));
-
-    this.previewEl.appendChild(document.createTextNode(">"));
+    if (!this.options.compact) {
+      this.classEl.appendChild(document.createTextNode("\""));
+      this.previewEl.appendChild(document.createTextNode(">"));
+    }
 
     // Init events for highlighting and selecting the node.
     this.previewEl.addEventListener("mouseover", this.onPreviewMouseOver);
     this.previewEl.addEventListener("mouseout", this.onPreviewMouseOut);
     this.selectNodeEl.addEventListener("click", this.onSelectNodeClick);
 
     // Start to listen for markupmutation events.
     this.inspector.on("markupmutation", this.onMarkupMutations);
@@ -425,78 +466,364 @@ AnimationTargetNode.prototype = {
       if (target === this.nodeFront) {
         // Re-render with the same nodeFront to update the output.
         this.render(this.playerFront);
         break;
       }
     }
   },
 
-  render: function(playerFront) {
+  render: Task.async(function*(playerFront) {
     this.playerFront = playerFront;
-    this.inspector.walker.getNodeFromActor(playerFront.actorID, ["node"]).then(nodeFront => {
-      // We might have been destroyed in the meantime, or the node might not be found.
-      if (!this.el || !nodeFront) {
-        return;
+    this.nodeFront = undefined;
+
+    try {
+      this.nodeFront = yield this.inspector.walker.getNodeFromActor(
+                             playerFront.actorID, ["node"]);
+    } catch (e) {
+      // We might have been destroyed in the meantime, or the node might not be
+      // found.
+      if (!this.el) {
+        console.warn("Cound't retrieve the animation target node, widget " +
+                     "destroyed");
+      }
+      console.error(e);
+      return;
+    }
+
+    if (!this.nodeFront || !this.el) {
+      return;
+    }
+
+    let {tagName, attributes} = this.nodeFront;
+
+    this.tagNameEl.textContent = tagName.toLowerCase();
+
+    let idIndex = attributes.findIndex(({name}) => name === "id");
+    if (idIndex > -1 && attributes[idIndex].value) {
+      this.idEl.querySelector(".attribute-value").textContent =
+        attributes[idIndex].value;
+      this.idEl.style.display = "inline";
+    } else {
+      this.idEl.style.display = "none";
+    }
+
+    let classIndex = attributes.findIndex(({name}) => name === "class");
+    if (classIndex > -1 && attributes[classIndex].value) {
+      let value = attributes[classIndex].value;
+      if (this.options.compact) {
+        value = value.split(" ").join(".");
       }
 
-      this.nodeFront = nodeFront;
-      let {tagName, attributes} = nodeFront;
+      this.classEl.querySelector(".attribute-value").textContent = value;
+      this.classEl.style.display = "inline";
+    } else {
+      this.classEl.style.display = "none";
+    }
 
-      this.tagNameEl.textContent = tagName.toLowerCase();
+    this.emit("target-retrieved");
+  })
+};
 
-      let idIndex = attributes.findIndex(({name}) => name === "id");
-      if (idIndex > -1 && attributes[idIndex].value) {
-        this.idEl.querySelector(".attribute-value").textContent =
-          attributes[idIndex].value;
-        this.idEl.style.display = "inline";
-      } else {
-        this.idEl.style.display = "none";
-      }
+/**
+ * The TimeScale helper object is used to know which size should something be
+ * displayed with in the animation panel, depending on the animations that are
+ * currently displayed.
+ * If there are 5 animations displayed, and the first one starts at 10000ms and
+ * the last one ends at 20000ms, then this helper can be used to convert any
+ * time in this range to a distance in pixels.
+ *
+ * For the helper to know how to convert, it needs to know all the animations.
+ * Whenever a new animation is added to the panel, addAnimation(state) should be
+ * called. reset() can be called to start over.
+ */
+let TimeScale = {
+  minStartTime: Infinity,
+  maxEndTime: 0,
+
+  /**
+   * Add a new animation to time scale.
+   * @param {Object} state A PlayerFront.state object.
+   */
+  addAnimation: function({startTime, delay, duration, iterationCount}) {
+    this.minStartTime = Math.min(this.minStartTime, startTime);
+    let length = delay + (duration * (!iterationCount ? 1 : iterationCount));
+    this.maxEndTime = Math.max(this.maxEndTime, startTime + length);
+  },
+
+  /**
+   * Reset the current time scale.
+   */
+  reset: function() {
+    this.minStartTime = Infinity;
+    this.maxEndTime = 0;
+  },
 
-      let classIndex = attributes.findIndex(({name}) => name === "class");
-      if (classIndex > -1 && attributes[classIndex].value) {
-        this.classEl.querySelector(".attribute-value").textContent =
-          attributes[classIndex].value;
-        this.classEl.style.display = "inline";
-      } else {
-        this.classEl.style.display = "none";
-      }
+  /**
+   * Convert a startTime to a distance in pixels, in the current time scale.
+   * @param {Number} time
+   * @param {Number} containerWidth The width of the container element.
+   * @return {Number}
+   */
+  startTimeToDistance: function(time, containerWidth) {
+    time -= this.minStartTime;
+    return this.durationToDistance(time, containerWidth);
+  },
+
+  /**
+   * Convert a duration to a distance in pixels, in the current time scale.
+   * @param {Number} time
+   * @param {Number} containerWidth The width of the container element.
+   * @return {Number}
+   */
+  durationToDistance: function(duration, containerWidth) {
+    return containerWidth * duration / (this.maxEndTime - this.minStartTime);
+  },
 
-      this.emit("target-retrieved");
-    }, e => {
-      this.nodeFront = null;
-      if (!this.el) {
-        console.warn("Cound't retrieve the animation target node, widget destroyed");
-      } else {
-        console.error(e);
-      }
-    });
+  /**
+   * Convert a distance in pixels to a time, in the current time scale.
+   * @param {Number} distance
+   * @param {Number} containerWidth The width of the container element.
+   * @return {Number}
+   */
+  distanceToTime: function(distance, containerWidth) {
+    return this.minStartTime +
+      ((this.maxEndTime - this.minStartTime) * distance / containerWidth);
+  },
+
+  /**
+   * Convert a distance in pixels to a time, in the current time scale.
+   * The time will be relative to the current minimum start time.
+   * @param {Number} distance
+   * @param {Number} containerWidth The width of the container element.
+   * @return {Number}
+   */
+  distanceToRelativeTime: function(distance, containerWidth) {
+    let time = this.distanceToTime(distance, containerWidth);
+    return time - this.minStartTime;
+  },
+
+  /**
+   * Depending on the time scale, format the given time as milliseconds or
+   * seconds.
+   * @param {Number} time
+   * @return {String} The formatted time string.
+   */
+  formatTime: function(time) {
+    let duration = this.maxEndTime - this.minStartTime;
+
+    // Format in milliseconds if the total duration is short enough.
+    if (duration <= MILLIS_TIME_FORMAT_MAX_DURATION) {
+      return L10N.getFormatStr("timeline.timeGraduationLabel", time.toFixed(0));
+    }
+
+    // Otherwise format in seconds.
+    return L10N.getFormatStr("player.timeLabel", (time / 1000).toFixed(1));
   }
 };
 
+exports.TimeScale = TimeScale;
+
 /**
- * DOM node creation helper function.
- * @param {Object} Options to customize the node to be created.
- * - nodeType {String} Optional, defaults to "div",
- * - attributes {Object} Optional attributes object like
- *   {attrName1:value1, attrName2: value2, ...}
- * - parent {DOMNode} Mandatory node to append the newly created node to.
- * @return {DOMNode} The newly created node.
+ * UI component responsible for displaying a timeline for animations.
+ * The timeline is essentially a graph with time along the x axis and animations
+ * along the y axis.
+ * The time is represented with a graduation header at the top and a current
+ * time play head.
+ * Animations are organized by lines, with a left margin containing the preview
+ * of the target DOM element the animation applies to.
  */
-function createNode(options) {
-  if (!options.parent) {
-    throw new Error("Missing parent DOMNode to create new node");
-  }
-
-  let type = options.nodeType || "div";
-  let node = options.parent.ownerDocument.createElement(type);
+function AnimationsTimeline(inspector) {
+  this.animations = [];
+  this.targetNodes = [];
+  this.inspector = inspector;
 
-  for (let name in options.attributes || {}) {
-    let value = options.attributes[name];
-    node.setAttribute(name, value);
-  }
-
-  options.parent.appendChild(node);
-  return node;
+  this.onAnimationStateChanged = this.onAnimationStateChanged.bind(this);
 }
 
-exports.createNode = createNode;
+exports.AnimationsTimeline = AnimationsTimeline;
+
+AnimationsTimeline.prototype = {
+  init: function(containerEl) {
+    this.win = containerEl.ownerDocument.defaultView;
+
+    this.rootWrapperEl = createNode({
+      parent: containerEl,
+      attributes: {
+        "class": "animation-timeline"
+      }
+    });
+
+    this.timeHeaderEl = createNode({
+      parent: this.rootWrapperEl,
+      attributes: {
+        "class": "time-header"
+      }
+    });
+
+    this.animationsEl = createNode({
+      parent: this.rootWrapperEl,
+      nodeType: "ul",
+      attributes: {
+        "class": "animations"
+      }
+    });
+  },
+
+  destroy: function() {
+    this.unrender();
+
+    this.rootWrapperEl.remove();
+    this.animations = [];
+
+    this.rootWrapperEl = null;
+    this.timeHeaderEl = null;
+    this.animationsEl = null;
+    this.win = null;
+    this.inspector = null;
+  },
+
+  destroyTargetNodes: function() {
+    for (let targetNode of this.targetNodes) {
+      targetNode.destroy();
+    }
+    this.targetNodes = [];
+  },
+
+  unrender: function() {
+    for (let animation of this.animations) {
+      animation.off("changed", this.onAnimationStateChanged);
+    }
+
+    TimeScale.reset();
+    this.destroyTargetNodes();
+    this.animationsEl.innerHTML = "";
+  },
+
+  render: function(animations) {
+    this.unrender();
+
+    this.animations = animations;
+    if (!this.animations.length) {
+      return;
+    }
+
+    // Loop first to set the time scale for all current animations.
+    for (let {state} of animations) {
+      TimeScale.addAnimation(state);
+    }
+
+    this.drawHeaderAndBackground();
+
+    for (let animation of this.animations) {
+      animation.on("changed", this.onAnimationStateChanged);
+
+      // Each line contains the target animated node and the animation time
+      // block.
+      let animationEl = createNode({
+        parent: this.animationsEl,
+        nodeType: "li",
+        attributes: {
+          "class": "animation"
+        }
+      });
+
+      // Left sidebar for the animated node.
+      let animatedNodeEl = createNode({
+        parent: animationEl,
+        attributes: {
+          "class": "target"
+        }
+      });
+
+      let timeBlockEl = createNode({
+        parent: animationEl,
+        attributes: {
+          "class": "time-block"
+        }
+      });
+
+      this.drawTimeBlock(animation, timeBlockEl);
+
+      // Draw the animated node target.
+      let targetNode = new AnimationTargetNode(this.inspector, {compact: true});
+      targetNode.init(animatedNodeEl);
+      targetNode.render(animation);
+
+      // Save the targetNode so it can be destroyed later.
+      this.targetNodes.push(targetNode);
+    }
+  },
+
+  onAnimationStateChanged: function() {
+    // For now, simply re-render the component. The animation front's state has
+    // already been updated.
+    this.render(this.animations);
+  },
+
+  drawHeaderAndBackground: function() {
+    let width = this.timeHeaderEl.offsetWidth;
+    let scale = width / (TimeScale.maxEndTime - TimeScale.minStartTime);
+    drawGraphElementBackground(this.win.document, "time-graduations", width, scale);
+
+    // And the time graduation header.
+    this.timeHeaderEl.innerHTML = "";
+    let interval = findOptimalTimeInterval(scale, TIME_GRADUATION_MIN_SPACING);
+    for (let i = 0; i < width; i += interval) {
+      createNode({
+        parent: this.timeHeaderEl,
+        nodeType: "span",
+        attributes: {
+          "class": "time-tick",
+          "style": `left:${i}px`
+        },
+        textContent: TimeScale.formatTime(
+          TimeScale.distanceToRelativeTime(i, width))
+      });
+    }
+  },
+
+  drawTimeBlock: function({state}, el) {
+    let width = el.offsetWidth;
+
+    // Container for all iterations and delay. Positioned at the right start
+    // time.
+    let x = TimeScale.startTimeToDistance(state.startTime + (state.delay || 0),
+                                          width);
+    // With the right width (duration*duration).
+    let count = state.iterationCount || 1;
+    let w = TimeScale.durationToDistance(state.duration, width);
+
+    let iterations = createNode({
+      parent: el,
+      attributes: {
+        "class": "iterations" + (state.iterationCount ? "" : " infinite"),
+        // Individual iterations are represented by setting the size of the
+        // repeating linear-gradient.
+        "style": `left:${x}px;
+                  width:${w * count}px;
+                  background-size:${Math.max(w, 2)}px 100%;`
+      }
+    });
+
+    // The animation name is displayed over the iterations.
+    createNode({
+      parent: iterations,
+      attributes: {
+        "class": "name"
+      },
+      textContent: state.name
+    });
+
+    // Delay.
+    if (state.delay) {
+      let delay = TimeScale.durationToDistance(state.delay, width);
+      createNode({
+        parent: iterations,
+        attributes: {
+          "class": "delay",
+          "style": `left:-${delay}px;
+                    width:${delay}px;`
+        }
+      });
+    }
+  }
+};
--- a/browser/devtools/animationinspector/moz.build
+++ b/browser/devtools/animationinspector/moz.build
@@ -1,11 +1,13 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
+XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
 
 EXTRA_JS_MODULES.devtools.animationinspector += [
     'components.js',
+    'utils.js',
 ]
--- a/browser/devtools/animationinspector/test/browser.ini
+++ b/browser/devtools/animationinspector/test/browser.ini
@@ -14,30 +14,35 @@ support-files =
 [browser_animation_play_pause_button.js]
 [browser_animation_playerFronts_are_refreshed.js]
 [browser_animation_playerWidgets_appear_on_panel_init.js]
 [browser_animation_playerWidgets_destroy.js]
 [browser_animation_playerWidgets_disables_on_finished.js]
 [browser_animation_playerWidgets_dont_show_time_after_duration.js]
 [browser_animation_playerWidgets_have_control_buttons.js]
 [browser_animation_playerWidgets_meta_data.js]
+[browser_animation_playerWidgets_scrubber_delayed.js]
+[browser_animation_playerWidgets_scrubber_enabled.js]
+[browser_animation_playerWidgets_scrubber_moves.js]
 [browser_animation_playerWidgets_state_after_pause.js]
 [browser_animation_playerWidgets_target_nodes.js]
 [browser_animation_rate_select_shows_presets.js]
 [browser_animation_refresh_on_added_animation.js]
 [browser_animation_refresh_on_removed_animation.js]
 [browser_animation_refresh_when_active.js]
 [browser_animation_same_nb_of_playerWidgets_and_playerFronts.js]
 [browser_animation_setting_currentTime_works_and_pauses.js]
 [browser_animation_setting_playbackRate_works.js]
 [browser_animation_shows_player_on_valid_node.js]
 [browser_animation_target_highlight_select.js]
-[browser_animation_timeline_animates.js]
-[browser_animation_timeline_is_enabled.js]
-[browser_animation_timeline_waits_for_delay.js]
+[browser_animation_timeline_displays_with_pref.js]
+[browser_animation_timeline_header.js]
+[browser_animation_timeline_shows_delay.js]
+[browser_animation_timeline_shows_iterations.js]
+[browser_animation_timeline_ui.js]
 [browser_animation_toggle_button_resets_on_navigate.js]
 [browser_animation_toggle_button_toggles_animations.js]
 [browser_animation_toggle_button_updates_playerWidgets.js]
 [browser_animation_toolbar_exists.js]
 [browser_animation_ui_updates_when_animation_changes.js]
 [browser_animation_ui_updates_when_animation_data_changes.js]
 [browser_animation_ui_updates_when_animation_rate_changes.js]
 [browser_animation_ui_updates_when_animation_time_changes.js]
--- a/browser/devtools/animationinspector/test/browser_animation_empty_on_invalid_nodes.js
+++ b/browser/devtools/animationinspector/test/browser_animation_empty_on_invalid_nodes.js
@@ -3,22 +3,49 @@
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Test that the panel shows no animation data for invalid or not animated nodes
 
 add_task(function*() {
   yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+
   let {inspector, panel} = yield openAnimationInspector();
+  yield testEmptyPanel(inspector, panel);
 
+  ({inspector, panel}) = yield closeAnimationInspectorAndRestartWithNewUI();
+  yield testEmptyPanel(inspector, panel, true);
+});
+
+function* testEmptyPanel(inspector, panel, isNewUI=false) {
   info("Select node .still and check that the panel is empty");
   let stillNode = yield getNodeFront(".still", inspector);
+  let onUpdated = panel.once(panel.UI_UPDATED_EVENT);
   yield selectNode(stillNode, inspector);
-  ok(!panel.playerWidgets || !panel.playerWidgets.length,
-    "No player widgets displayed for a still node");
+  yield onUpdated;
+
+  if (isNewUI) {
+    is(panel.animationsTimelineComponent.animations.length, 0,
+       "No animation players stored in the timeline component for a still node");
+    is(panel.animationsTimelineComponent.animationsEl.childNodes.length, 0,
+       "No animation displayed in the timeline component for a still node");
+  } else {
+    ok(!panel.playerWidgets || !panel.playerWidgets.length,
+       "No player widgets displayed for a still node");
+  }
 
   info("Select the comment text node and check that the panel is empty");
   let commentNode = yield inspector.walker.previousSibling(stillNode);
+  onUpdated = panel.once(panel.UI_UPDATED_EVENT);
   yield selectNode(commentNode, inspector);
-  ok(!panel.playerWidgets || !panel.playerWidgets.length,
-    "No player widgets displayed for a text node");
-});
+  yield onUpdated;
+
+  if (isNewUI) {
+    is(panel.animationsTimelineComponent.animations.length, 0,
+       "No animation players stored in the timeline component for a text node");
+    is(panel.animationsTimelineComponent.animationsEl.childNodes.length, 0,
+       "No animation displayed in the timeline component for a text node");
+  } else {
+    ok(!panel.playerWidgets || !panel.playerWidgets.length,
+       "No player widgets displayed for a text node");
+  }
+}
--- a/browser/devtools/animationinspector/test/browser_animation_panel_exists.js
+++ b/browser/devtools/animationinspector/test/browser_animation_panel_exists.js
@@ -10,9 +10,18 @@ add_task(function*() {
   yield addTab("data:text/html;charset=utf-8,welcome to the animation panel");
   let {panel, controller} = yield openAnimationInspector();
 
   ok(controller, "The animation controller exists");
   ok(controller.animationsFront, "The animation controller has been initialized");
 
   ok(panel, "The animation panel exists");
   ok(panel.playersEl, "The animation panel has been initialized");
+
+  ({panel, controller}) = yield closeAnimationInspectorAndRestartWithNewUI();
+
+  ok(controller, "The animation controller exists");
+  ok(controller.animationsFront, "The animation controller has been initialized");
+
+  ok(panel, "The animation panel exists");
+  ok(panel.playersEl, "The animation panel has been initialized");
+  ok(panel.animationsTimelineComponent, "The animation panel has been initialized");
 });
--- a/browser/devtools/animationinspector/test/browser_animation_participate_in_inspector_update.js
+++ b/browser/devtools/animationinspector/test/browser_animation_participate_in_inspector_update.js
@@ -5,35 +5,42 @@
 "use strict";
 
 // Test that the update of the animation panel participate in the
 // inspector-updated event. This means that the test verifies that the
 // inspector-updated event is emitted *after* the animation panel is ready.
 
 add_task(function*() {
   yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
-  let {inspector, panel, controller} = yield openAnimationInspector();
+
+  let ui = yield openAnimationInspector();
+  yield testEventsOrder(ui);
 
+  ui = yield closeAnimationInspectorAndRestartWithNewUI();
+  yield testEventsOrder(ui);
+});
+
+function* testEventsOrder({inspector, panel, controller}) {
   info("Listen for the players-updated, ui-updated and inspector-updated events");
   let receivedEvents = [];
   controller.once(controller.PLAYERS_UPDATED_EVENT, () => {
     receivedEvents.push(controller.PLAYERS_UPDATED_EVENT);
   });
   panel.once(panel.UI_UPDATED_EVENT, () => {
     receivedEvents.push(panel.UI_UPDATED_EVENT);
-  })
+  });
   inspector.once("inspector-updated", () => {
     receivedEvents.push("inspector-updated");
   });
 
   info("Selecting an animated node");
   let node = yield getNodeFront(".animated", inspector);
   yield selectNode(node, inspector);
 
   info("Check that all events were received, and in the right order");
   is(receivedEvents.length, 3, "3 events were received");
   is(receivedEvents[0], controller.PLAYERS_UPDATED_EVENT,
     "The first event received was the players-updated event");
   is(receivedEvents[1], panel.UI_UPDATED_EVENT,
     "The second event received was the ui-updated event");
   is(receivedEvents[2], "inspector-updated",
     "The third event received was the inspector-updated event");
-});
+}
--- a/browser/devtools/animationinspector/test/browser_animation_playerWidgets_appear_on_panel_init.js
+++ b/browser/devtools/animationinspector/test/browser_animation_playerWidgets_appear_on_panel_init.js
@@ -4,12 +4,19 @@
 
 "use strict";
 
 // Test that player widgets are displayed right when the animation panel is
 // initialized, if the selected node (<body> by default) is animated.
 
 add_task(function*() {
   yield addTab(TEST_URL_ROOT + "doc_body_animation.html");
+
   let {panel} = yield openAnimationInspector();
+  is(panel.playerWidgets.length, 1,
+    "One animation player is displayed after init");
 
-  is(panel.playerWidgets.length, 1, "One animation player is displayed after init");
+  ({panel}) = yield closeAnimationInspectorAndRestartWithNewUI();
+  is(panel.animationsTimelineComponent.animations.length, 1,
+    "One animation is handled by the timeline after init");
+  is(panel.animationsTimelineComponent.animationsEl.childNodes.length, 1,
+    "One animation is displayed after init");
 });
rename from browser/devtools/animationinspector/test/browser_animation_timeline_waits_for_delay.js
rename to browser/devtools/animationinspector/test/browser_animation_playerWidgets_scrubber_delayed.js
rename from browser/devtools/animationinspector/test/browser_animation_timeline_is_enabled.js
rename to browser/devtools/animationinspector/test/browser_animation_playerWidgets_scrubber_enabled.js
rename from browser/devtools/animationinspector/test/browser_animation_timeline_animates.js
rename to browser/devtools/animationinspector/test/browser_animation_playerWidgets_scrubber_moves.js
--- a/browser/devtools/animationinspector/test/browser_animation_playerWidgets_target_nodes.js
+++ b/browser/devtools/animationinspector/test/browser_animation_playerWidgets_target_nodes.js
@@ -22,10 +22,31 @@ add_task(function*() {
   }
 
   let targetEl = widget.el.querySelector(".animation-target");
   ok(targetEl, "The player widget has a target element");
   is(targetEl.textContent, "<divid=\"\"class=\"ball animated\">",
     "The target element's content is correct");
 
   let selectorEl = targetEl.querySelector(".node-selector");
-  ok(selectorEl, "The icon to select the target element in the inspector exists");
+  ok(selectorEl,
+    "The icon to select the target element in the inspector exists");
+
+  info("Test again with the new timeline UI");
+  ({inspector, panel}) = yield closeAnimationInspectorAndRestartWithNewUI();
+
+  info("Select the simple animated node");
+  yield selectNode(".animated", inspector);
+
+  let targetNodeComponent = panel.animationsTimelineComponent.targetNodes[0];
+  // Make sure to wait for the target-retrieved event if the nodeFront hasn't
+  // yet been retrieved by the TargetNodeComponent.
+  if (!targetNodeComponent.nodeFront) {
+    yield targetNodeComponent.once("target-retrieved");
+  }
+
+  is(targetNodeComponent.el.textContent, "div#.ball.animated",
+    "The target element's content is correct");
+
+  selectorEl = targetNodeComponent.el.querySelector(".node-selector");
+  ok(selectorEl,
+    "The icon to select the target element in the inspector exists");
 });
--- a/browser/devtools/animationinspector/test/browser_animation_refresh_on_added_animation.js
+++ b/browser/devtools/animationinspector/test/browser_animation_refresh_on_added_animation.js
@@ -3,32 +3,46 @@
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Test that the panel content refreshes when new animations are added.
 
 add_task(function*() {
   yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
-  let {toolbox, inspector, panel} = yield openAnimationInspector();
+
+  let {inspector, panel} = yield openAnimationInspector();
+  yield testRefreshOnNewAnimation(inspector, panel);
 
+  ({inspector, panel}) = yield closeAnimationInspectorAndRestartWithNewUI();
+  yield testRefreshOnNewAnimation(inspector, panel);
+});
+
+function* testRefreshOnNewAnimation(inspector, panel) {
   info("Select a non animated node");
   yield selectNode(".still", inspector);
 
-  is(panel.playersEl.querySelectorAll(".player-widget").length, 0,
-    "There are no player widgets in the panel");
+  assertAnimationsDisplayed(panel, 0);
 
   info("Listen to the next UI update event");
   let onPanelUpdated = panel.once(panel.UI_UPDATED_EVENT);
 
   info("Start an animation on the node");
   yield executeInContent("devtools:test:setAttribute", {
     selector: ".still",
     attributeName: "class",
     attributeValue: "ball animated"
   });
 
   yield onPanelUpdated;
   ok(true, "The panel update event was fired");
 
-  is(panel.playersEl.querySelectorAll(".player-widget").length, 1,
-    "There is one player widget in the panel");
-});
+  assertAnimationsDisplayed(panel, 1);
+
+  info("Remove the animation class on the node");
+  onPanelUpdated = panel.once(panel.UI_UPDATED_EVENT);
+  yield executeInContent("devtools:test:setAttribute", {
+    selector: ".ball.animated",
+    attributeName: "class",
+    attributeValue: "ball still"
+  });
+  yield onPanelUpdated;
+}
--- a/browser/devtools/animationinspector/test/browser_animation_refresh_on_removed_animation.js
+++ b/browser/devtools/animationinspector/test/browser_animation_refresh_on_removed_animation.js
@@ -3,60 +3,69 @@
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Test that the panel content refreshes when animations are removed.
 
 add_task(function*() {
   yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
-  let {toolbox, inspector, panel} = yield openAnimationInspector();
+
+  let {inspector, panel} = yield openAnimationInspector();
+  yield testRefreshOnRemove(inspector, panel);
+  yield testAddedAnimationWorks(inspector, panel);
 
+  info("Reload and test again with the new UI");
+  ({inspector, panel}) = yield closeAnimationInspectorAndRestartWithNewUI(true);
+  yield testRefreshOnRemove(inspector, panel, true);
+});
+
+function* testRefreshOnRemove(inspector, panel) {
   info("Select a animated node");
   yield selectNode(".animated", inspector);
 
-  is(panel.playersEl.querySelectorAll(".player-widget").length, 1,
-    "There is one player widget in the panel");
+  assertAnimationsDisplayed(panel, 1);
 
   info("Listen to the next UI update event");
   let onPanelUpdated = panel.once(panel.UI_UPDATED_EVENT);
 
   info("Remove the animation on the node by removing the class");
   yield executeInContent("devtools:test:setAttribute", {
     selector: ".animated",
     attributeName: "class",
     attributeValue: "ball still test-node"
   });
 
   yield onPanelUpdated;
   ok(true, "The panel update event was fired");
 
-  is(panel.playersEl.querySelectorAll(".player-widget").length, 0,
-    "There are no player widgets in the panel anymore");
+  assertAnimationsDisplayed(panel, 0);
 
   info("Add an finite animation on the node again, and wait for it to appear");
   onPanelUpdated = panel.once(panel.UI_UPDATED_EVENT);
   yield executeInContent("devtools:test:setAttribute", {
     selector: ".test-node",
     attributeName: "class",
-    attributeValue: "ball short"
+    attributeValue: "ball short test-node"
   });
   yield onPanelUpdated;
-  is(panel.playersEl.querySelectorAll(".player-widget").length, 1,
-    "There is one player widget in the panel again");
 
+  assertAnimationsDisplayed(panel, 1);
+}
+
+function* testAddedAnimationWorks(inspector, panel) {
   info("Now wait until the animation finishes");
   let widget = panel.playerWidgets[0];
-  yield waitForPlayState(widget.player, "finished")
+  yield waitForPlayState(widget.player, "finished");
 
   is(panel.playersEl.querySelectorAll(".player-widget").length, 1,
     "There is still a player widget in the panel after the animation finished");
 
   info("Checking that the animation's currentTime can still be set");
   info("Click at the center of the slider input");
 
   let onPaused = waitForPlayState(widget.player, "paused");
   let input = widget.currentTimeEl;
   let win = input.ownerDocument.defaultView;
   EventUtils.synthesizeMouseAtCenter(input, {type: "mousedown"}, win);
   yield onPaused;
   ok(widget.el.classList.contains("paused"), "The widget is in paused mode");
-});
+}
--- a/browser/devtools/animationinspector/test/browser_animation_refresh_when_active.js
+++ b/browser/devtools/animationinspector/test/browser_animation_refresh_when_active.js
@@ -3,45 +3,52 @@
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Test that the panel only refreshes when it is visible in the sidebar.
 
 add_task(function*() {
   yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
-  let {toolbox, inspector, panel} = yield openAnimationInspector();
+
+  let {inspector, panel} = yield openAnimationInspector();
+  yield testRefresh(inspector, panel);
 
+  ({inspector, panel}) = yield closeAnimationInspectorAndRestartWithNewUI();
+  yield testRefresh(inspector, panel);
+});
+
+function* testRefresh(inspector, panel) {
   info("Select a non animated node");
   yield selectNode(".still", inspector);
 
   info("Switch to the rule-view panel");
   inspector.sidebar.select("ruleview");
 
   info("Select the animated node now");
   yield selectNode(".animated", inspector);
 
-  ok(!panel.playerWidgets || !panel.playerWidgets.length,
+  assertAnimationsDisplayed(panel, 0,
     "The panel doesn't show the animation data while inactive");
 
   info("Switch to the animation panel");
   inspector.sidebar.select("animationinspector");
   yield panel.once(panel.UI_UPDATED_EVENT);
 
-  is(panel.playerWidgets.length, 1,
+  assertAnimationsDisplayed(panel, 1,
     "The panel shows the animation data after selecting it");
 
   info("Switch again to the rule-view");
   inspector.sidebar.select("ruleview");
 
   info("Select the non animated node again");
   yield selectNode(".still", inspector);
 
-  is(panel.playerWidgets.length, 1,
+  assertAnimationsDisplayed(panel, 1,
     "The panel still shows the previous animation data since it is inactive");
 
   info("Switch to the animation panel again");
   inspector.sidebar.select("animationinspector");
   yield panel.once(panel.UI_UPDATED_EVENT);
 
-  ok(!panel.playerWidgets || !panel.playerWidgets.length,
+  assertAnimationsDisplayed(panel, 0,
     "The panel is now empty after refreshing");
-});
+}
--- a/browser/devtools/animationinspector/test/browser_animation_same_nb_of_playerWidgets_and_playerFronts.js
+++ b/browser/devtools/animationinspector/test/browser_animation_same_nb_of_playerWidgets_and_playerFronts.js
@@ -17,9 +17,21 @@ add_task(function*() {
   is(controller.animationPlayers.length, panel.playerWidgets.length,
     "As many playerWidgets were created as there are playerFronts");
 
   for (let widget of panel.playerWidgets) {
     ok(widget.initialized, "The player widget is initialized");
     is(widget.el.parentNode, panel.playersEl,
       "The player widget has been appended to the panel");
   }
+
+  info("Test again with the new UI, making sure the same number of " +
+       "animation timelines is created");
+  ({inspector, panel, controller}) = yield closeAnimationInspectorAndRestartWithNewUI();
+  let timeline = panel.animationsTimelineComponent;
+
+  info("Selecting the test animated node again");
+  yield selectNode(".multi", inspector);
+
+  is(controller.animationPlayers.length,
+    timeline.animationsEl.querySelectorAll(".animation").length,
+    "As many timeline elements were created as there are playerFronts");
 });
--- a/browser/devtools/animationinspector/test/browser_animation_shows_player_on_valid_node.js
+++ b/browser/devtools/animationinspector/test/browser_animation_shows_player_on_valid_node.js
@@ -4,17 +4,23 @@
 
 "use strict";
 
 // Test that the panel shows an animation player when an animated node is
 // selected.
 
 add_task(function*() {
   yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+
   let {inspector, panel} = yield openAnimationInspector();
+  yield testShowsAnimations(inspector, panel);
 
+  ({inspector, panel}) = yield closeAnimationInspectorAndRestartWithNewUI();
+  yield testShowsAnimations(inspector, panel);
+});
+
+function* testShowsAnimations(inspector, panel) {
   info("Select node .animated and check that the panel is not empty");
   let node = yield getNodeFront(".animated", inspector);
   yield selectNode(node, inspector);
 
-  is(panel.playerWidgets.length, 1,
-    "Exactly 1 player widget is shown for animated node");
-});
+  assertAnimationsDisplayed(panel, 1);
+}
--- a/browser/devtools/animationinspector/test/browser_animation_target_highlight_select.js
+++ b/browser/devtools/animationinspector/test/browser_animation_target_highlight_select.js
@@ -4,59 +4,79 @@
 
 "use strict";
 
 // Test that the DOM element targets displayed in animation player widgets can
 // be used to highlight elements in the DOM and select them in the inspector.
 
 add_task(function*() {
   yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
-  let {toolbox, inspector, panel} = yield openAnimationInspector();
+
+  let ui = yield openAnimationInspector();
+  yield testTargetNode(ui);
 
+  ui = yield closeAnimationInspectorAndRestartWithNewUI();
+  yield testTargetNode(ui, true);
+});
+
+function* testTargetNode({toolbox, inspector, panel}, isNewUI) {
   info("Select the simple animated node");
   yield selectNode(".animated", inspector);
 
   // Make sure to wait for the target-retrieved event if the nodeFront hasn't
   // yet been retrieved by the TargetNodeComponent.
-  let targetNodeComponent = panel.playerWidgets[0].targetNodeComponent;
+  let targetNodeComponent;
+  if (isNewUI) {
+    targetNodeComponent = panel.animationsTimelineComponent.targetNodes[0];
+  } else {
+    targetNodeComponent = panel.playerWidgets[0].targetNodeComponent;
+  }
   if (!targetNodeComponent.nodeFront) {
     yield targetNodeComponent.once("target-retrieved");
   }
 
   info("Retrieve the part of the widget that highlights the node on hover");
   let highlightingEl = targetNodeComponent.previewEl;
 
   info("Listen to node-highlight event and mouse over the widget");
   let onHighlight = toolbox.once("node-highlight");
   EventUtils.synthesizeMouse(highlightingEl, 10, 5, {type: "mouseover"},
                              highlightingEl.ownerDocument.defaultView);
   let nodeFront = yield onHighlight;
 
   ok(true, "The node-highlight event was fired");
   is(targetNodeComponent.nodeFront, nodeFront,
     "The highlighted node is the one stored on the animation widget");
-  is(nodeFront.tagName, "DIV", "The highlighted node has the correct tagName");
-  is(nodeFront.attributes[0].name, "class", "The highlighted node has the correct attributes");
-  is(nodeFront.attributes[0].value, "ball animated", "The highlighted node has the correct class");
+  is(nodeFront.tagName, "DIV",
+    "The highlighted node has the correct tagName");
+  is(nodeFront.attributes[0].name, "class",
+    "The highlighted node has the correct attributes");
+  is(nodeFront.attributes[0].value, "ball animated",
+    "The highlighted node has the correct class");
 
   info("Select the body node in order to have the list of all animations");
   yield selectNode("body", inspector);
 
   // Make sure to wait for the target-retrieved event if the nodeFront hasn't
   // yet been retrieved by the TargetNodeComponent.
-  targetNodeComponent = panel.playerWidgets[0].targetNodeComponent;
+  if (isNewUI) {
+    targetNodeComponent = panel.animationsTimelineComponent.targetNodes[0];
+  } else {
+    targetNodeComponent = panel.playerWidgets[0].targetNodeComponent;
+  }
   if (!targetNodeComponent.nodeFront) {
     yield targetNodeComponent.once("target-retrieved");
   }
 
-  info("Click on the first animation widget's selector icon and wait for the selection to change");
+  info("Click on the first animation widget's selector icon and wait for the " +
+    "selection to change");
   let onSelection = inspector.selection.once("new-node-front");
   let onPanelUpdated = panel.once(panel.UI_UPDATED_EVENT);
   let selectIconEl = targetNodeComponent.selectNodeEl;
   EventUtils.sendMouseEvent({type: "click"}, selectIconEl,
                             selectIconEl.ownerDocument.defaultView);
   yield onSelection;
 
   is(inspector.selection.nodeFront, targetNodeComponent.nodeFront,
     "The selected node is the one stored on the animation widget");
 
   yield onPanelUpdated;
-});
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/animationinspector/test/browser_animation_timeline_displays_with_pref.js
@@ -0,0 +1,24 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Check that the timeline-based UI is displayed instead of the playerwidget-
+// based UI when the "devtools.inspector.animationInspectorV3" is set.
+
+add_task(function*() {
+  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  let {inspector, panel} = yield openAnimationInspectorNewUI();
+
+  info("Selecting the test node");
+  yield selectNode(".animated", inspector);
+
+  let timeline = panel.animationsTimelineComponent;
+
+  ok(timeline, "The timeline components was created");
+  is(timeline.rootWrapperEl.parentNode, panel.playersEl,
+    "The timeline component was appended in the DOM");
+  is(panel.playersEl.querySelectorAll(".player-widget").length, 0,
+    "There are no playerWidgets in the DOM");
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/animationinspector/test/browser_animation_timeline_header.js
@@ -0,0 +1,47 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Check that the timeline-based UI shows correct time graduations in the
+// header.
+
+const {findOptimalTimeInterval} = require("devtools/animationinspector/utils");
+const {TimeScale} = require("devtools/animationinspector/components");
+// Should be kept in sync with TIME_GRADUATION_MIN_SPACING in components.js
+const TIME_GRADUATION_MIN_SPACING = 40;
+
+add_task(function*() {
+  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  let {panel} = yield openAnimationInspectorNewUI();
+
+  let timeline = panel.animationsTimelineComponent;
+  let headerEl = timeline.timeHeaderEl;
+
+  info("Find out how many time graduations should there be");
+  let width = headerEl.offsetWidth;
+  let scale = width / (TimeScale.maxEndTime - TimeScale.minStartTime);
+  // Note that findOptimalTimeInterval is tested separately in xpcshell test
+  // test_findOptimalTimeInterval.js, so we assume that it works here.
+  let interval = findOptimalTimeInterval(scale, TIME_GRADUATION_MIN_SPACING);
+  let nb = Math.ceil(width / interval);
+
+  is(headerEl.querySelectorAll(".time-tick").length, nb,
+     "The expected number of time ticks were found");
+
+  info("Make sure graduations are evenly distributed and show the right times");
+  [...headerEl.querySelectorAll(".time-tick")].forEach((tick, i) => {
+    let left = parseFloat(tick.style.left);
+    is(Math.round(left), Math.round(i * interval),
+      "Graduation " + i + " is positioned correctly");
+
+    // Note that the distancetoRelativeTime and formatTime functions are tested
+    // separately in xpcshell test test_timeScale.js, so we assume that they
+    // work here.
+    let formattedTime = TimeScale.formatTime(
+      TimeScale.distanceToRelativeTime(i * interval, width));
+    is(tick.textContent, formattedTime,
+      "Graduation " + i + " has the right text content");
+  });
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/animationinspector/test/browser_animation_timeline_shows_delay.js
@@ -0,0 +1,30 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Check that animation delay is visualized in the timeline-based UI when the
+// animation is delayed.
+
+add_task(function*() {
+  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  let {inspector, panel} = yield openAnimationInspectorNewUI();
+
+  info("Selecting a delayed animated node");
+  yield selectNode(".delayed", inspector);
+
+  info("Getting the animation and delay elements from the panel");
+  let timelineEl = panel.animationsTimelineComponent.rootWrapperEl;
+  let delay = timelineEl.querySelector(".delay");
+
+  ok(delay, "The animation timeline contains the delay element");
+
+  info("Selecting a no-delay animated node");
+  yield selectNode(".animated", inspector);
+
+  info("Getting the animation and delay elements from the panel again");
+  delay = timelineEl.querySelector(".delay");
+
+  ok(!delay, "The animation timeline contains no delay element");
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/animationinspector/test/browser_animation_timeline_shows_iterations.js
@@ -0,0 +1,51 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Check that the timeline-based UI is displays as many iteration elements as
+// there are iterations in an animation.
+
+add_task(function*() {
+  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  let {inspector, panel} = yield openAnimationInspectorNewUI();
+
+  info("Selecting the test node");
+  yield selectNode(".delayed", inspector);
+
+  info("Getting the animation element from the panel");
+  let timelineEl = panel.animationsTimelineComponent.rootWrapperEl;
+  let animation = timelineEl.querySelector(".time-block");
+  let iterations = animation.querySelector(".iterations");
+
+  // Iterations are rendered with a repeating linear-gradient, so we need to
+  // calculate how many iterations are represented by looking at the background
+  // size.
+  let iterationCount = getIterationCountFromBackground(iterations);
+
+  is(iterationCount, 10,
+     "The animation timeline contains the right number of iterations");
+  ok(!iterations.classList.contains("infinite"),
+     "The iteration element doesn't have the infinite class");
+
+  info("Selecting another test node with an infinite animation");
+  yield selectNode(".animated", inspector);
+
+  info("Getting the animation element from the panel again");
+  animation = timelineEl.querySelector(".time-block");
+  iterations = animation.querySelector(".iterations");
+
+  iterationCount = getIterationCountFromBackground(iterations);
+
+  is(iterationCount, 1,
+     "The animation timeline contains just one iteration");
+  ok(iterations.classList.contains("infinite"),
+     "The iteration element has the infinite class");
+});
+
+function getIterationCountFromBackground(el) {
+  let backgroundSize = parseFloat(el.style.backgroundSize.split(" ")[0]);
+  let width = el.offsetWidth;
+  return Math.round(width / backgroundSize);
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/animationinspector/test/browser_animation_timeline_ui.js
@@ -0,0 +1,41 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Check that the timeline-based UI contains the right elements.
+
+add_task(function*() {
+  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  let {panel} = yield openAnimationInspectorNewUI();
+
+  let timeline = panel.animationsTimelineComponent;
+  let el = timeline.rootWrapperEl;
+
+  ok(el.querySelector(".time-header"),
+     "The header element is in the DOM of the timeline");
+  ok(el.querySelectorAll(".time-header .time-tick").length,
+     "The header has some time graduations");
+
+  ok(el.querySelector(".animations"),
+     "The animations container is in the DOM of the timeline");
+  is(el.querySelectorAll(".animations .animation").length,
+     timeline.animations.length,
+     "The number of animations displayed matches the number of animations");
+
+  for (let i = 0; i < timeline.animations.length; i++) {
+    let animation = timeline.animations[i];
+    let animationEl = el.querySelectorAll(".animations .animation")[i];
+
+    ok(animationEl.querySelector(".target"),
+       "The animated node target element is in the DOM");
+    ok(animationEl.querySelector(".time-block"),
+       "The timeline element is in the DOM");
+    is(animationEl.querySelector(".name").textContent,
+       animation.state.name,
+       "The name on the timeline is correct");
+    ok(animationEl.querySelector(".iterations"),
+       "The timeline has iterations displayed");
+  }
+});
--- a/browser/devtools/animationinspector/test/browser_animation_toggle_button_toggles_animations.js
+++ b/browser/devtools/animationinspector/test/browser_animation_toggle_button_toggles_animations.js
@@ -6,17 +6,17 @@
 
 // Test that the main toggle button actually toggles animations.
 // This test doesn't need to be extra careful about checking that *all*
 // animations have been paused (including inside iframes) because there's an
 // actor test in /toolkit/devtools/server/tests/browser/ that does this.
 
 add_task(function*() {
   yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
-  let {inspector, panel} = yield openAnimationInspector();
+  let {panel} = yield openAnimationInspector();
 
   info("Click the toggle button");
   yield panel.toggleAll();
   yield checkState("paused");
 
   info("Click again the toggle button");
   yield panel.toggleAll();
   yield checkState("running");
--- a/browser/devtools/animationinspector/test/browser_animation_toolbar_exists.js
+++ b/browser/devtools/animationinspector/test/browser_animation_toolbar_exists.js
@@ -4,17 +4,17 @@
 
 "use strict";
 
 // Test that the animation panel has a top toolbar that contains the play/pause
 // button and that is displayed at all times.
 
 add_task(function*() {
   yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
-  let {inspector, panel, window} = yield openAnimationInspector();
+  let {inspector, window} = yield openAnimationInspector();
   let doc = window.document;
 
   let toolbar = doc.querySelector("#toolbar");
   ok(toolbar, "The panel contains the toolbar element");
   ok(toolbar.querySelector("#toggle-all"), "The toolbar contains the toggle button");
   ok(isNodeVisible(toolbar), "The toolbar is visible");
 
   info("Select an animated node");
--- a/browser/devtools/animationinspector/test/browser_animation_ui_updates_when_animation_data_changes.js
+++ b/browser/devtools/animationinspector/test/browser_animation_ui_updates_when_animation_data_changes.js
@@ -4,41 +4,69 @@
 
 "use strict";
 
 // Verify that if the animation's duration, iterations or delay change in
 // content, then the widget reflects the changes.
 
 add_task(function*() {
   yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
-  let {panel, inspector} = yield openAnimationInspector();
+
+  let ui = yield openAnimationInspector();
+  yield testDataUpdates(ui);
 
+  info("Close the toolbox, reload the tab, and try again with the new UI");
+  ui = yield closeAnimationInspectorAndRestartWithNewUI(true);
+  yield testDataUpdates(ui, true);
+});
+
+function* testDataUpdates({panel, controller, inspector}, isNewUI=false) {
   info("Select the test node");
   yield selectNode(".animated", inspector);
 
-  info("Get the player widget");
-  let widget = panel.playerWidgets[0];
+  let animation = controller.animationPlayers[0];
+  yield setStyle(animation, "animationDuration", "5.5s", isNewUI);
+  yield setStyle(animation, "animationIterationCount", "300", isNewUI);
+  yield setStyle(animation, "animationDelay", "45s", isNewUI);
 
-  yield setStyle(widget, "animationDuration", "5.5s");
-  is(widget.metaDataComponent.durationValue.textContent, "5.50s",
-    "The widget shows the new duration");
+  if (isNewUI) {
+    let animationsEl = panel.animationsTimelineComponent.animationsEl;
+    let timeBlockEl = animationsEl.querySelector(".time-block");
+
+    // 45s delay + (300 * 5.5)s duration
+    let expectedTotalDuration = 1695 * 1000;
+    let timeRatio = expectedTotalDuration / timeBlockEl.offsetWidth;
 
-  yield setStyle(widget, "animationIterationCount", "300");
-  is(widget.metaDataComponent.iterationValue.textContent, "300",
-    "The widget shows the new iteration count");
+    // XXX: the nb and size of each iteration cannot be tested easily (displayed
+    // using a linear-gradient background and capped at 2px wide). They should
+    // be tested in bug 1173761.
+    let delayWidth = parseFloat(timeBlockEl.querySelector(".delay").style.width);
+    is(Math.round(delayWidth * timeRatio), 45 * 1000,
+      "The timeline has the right delay");
+  } else {
+    let widget = panel.playerWidgets[0];
+    is(widget.metaDataComponent.durationValue.textContent, "5.50s",
+      "The widget shows the new duration");
+    is(widget.metaDataComponent.iterationValue.textContent, "300",
+      "The widget shows the new iteration count");
+    is(widget.metaDataComponent.delayValue.textContent, "45s",
+      "The widget shows the new delay");
+  }
+}
 
-  yield setStyle(widget, "animationDelay", "45s");
-  is(widget.metaDataComponent.delayValue.textContent, "45s",
-    "The widget shows the new delay");
-});
-
-function* setStyle(widget, name, value) {
+function* setStyle(animation, name, value, isNewUI=false) {
   info("Change the animation style via the content DOM. Setting " +
     name + " to " + value);
+
+  let onAnimationChanged = once(animation, "changed");
   yield executeInContent("devtools:test:setStyle", {
     selector: ".animated",
     propertyName: name,
     propertyValue: value
   });
+  yield onAnimationChanged;
 
-  info("Wait for the next state update");
-  yield onceNextPlayerRefresh(widget.player);
+  // If this is the playerWidget-based UI, wait for the auto-refresh event too
+  // to make sure the UI has updated.
+  if (!isNewUI) {
+    yield once(animation, animation.AUTO_REFRESH_EVENT);
+  }
 }
--- a/browser/devtools/animationinspector/test/head.js
+++ b/browser/devtools/animationinspector/test/head.js
@@ -2,54 +2,59 @@
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 const Cu = Components.utils;
 const {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
 const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
+const {require} = devtools;
 const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
 const TargetFactory = devtools.TargetFactory;
-const {console} = Components.utils.import("resource://gre/modules/devtools/Console.jsm", {});
+const {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
 const {ViewHelpers} = Cu.import("resource:///modules/devtools/ViewHelpers.jsm", {});
 
 // All tests are asynchronous
 waitForExplicitFinish();
 
 const TEST_URL_ROOT = "http://example.com/browser/browser/devtools/animationinspector/test/";
 const ROOT_TEST_DIR = getRootDirectory(gTestPath);
 const FRAME_SCRIPT_URL = ROOT_TEST_DIR + "doc_frame_script.js";
 const COMMON_FRAME_SCRIPT_URL = "chrome://browser/content/devtools/frame-script-utils.js";
+const NEW_UI_PREF = "devtools.inspector.animationInspectorV3";
 
 // Auto clean-up when a test ends
 registerCleanupFunction(function*() {
-  let target = TargetFactory.forTab(gBrowser.selectedTab);
-  yield gDevTools.closeToolbox(target);
+  yield closeAnimationInspector();
 
   while (gBrowser.tabs.length > 1) {
     gBrowser.removeCurrentTab();
   }
 });
 
+// Make sure the new UI is off by default.
+Services.prefs.setBoolPref(NEW_UI_PREF, false);
+
 // Uncomment this pref to dump all devtools emitted events to the console.
 // Services.prefs.setBoolPref("devtools.dump.emit", true);
 
 // Uncomment this pref to dump all devtools protocol traffic
 // Services.prefs.setBoolPref("devtools.debugger.log", true);
 
 // Set the testing flag on gDevTools and reset it when the test ends
 gDevTools.testing = true;
 registerCleanupFunction(() => gDevTools.testing = false);
 
 // Clean-up all prefs that might have been changed during a test run
 // (safer here because if the test fails, then the pref is never reverted)
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("devtools.dump.emit");
   Services.prefs.clearUserPref("devtools.debugger.log");
+  Services.prefs.clearUserPref(NEW_UI_PREF);
 });
 
 /**
  * Add a new test tab in the browser and load the given url.
  * @param {String} url The url to be loaded in the new tab
  * @return a promise that resolves to the tab object when the url is loaded
  */
 function addTab(url) {
@@ -73,16 +78,23 @@ function addTab(url) {
 
     def.resolve(tab);
   }, true);
 
   return def.promise;
 }
 
 /**
+ * Switch ON the new UI pref.
+ */
+function enableNewUI() {
+  Services.prefs.setBoolPref(NEW_UI_PREF, true);
+}
+
+/**
  * Reload the current tab location.
  */
 function reloadTab() {
   return executeInContent("devtools:test:reload", {}, {}, false);
 }
 
 /**
  * Get the NodeFront for a given css selector, via the protocol
@@ -115,42 +127,60 @@ let selectNode = Task.async(function*(da
     nodeFront = yield getNodeFront(data, inspector);
   }
   let updated = inspector.once("inspector-updated");
   inspector.selection.setNodeFront(nodeFront, reason);
   yield updated;
 });
 
 /**
+ * Check if there are the expected number of animations being displayed in the
+ * panel right now.
+ * @param {AnimationsPanel} panel
+ * @param {Number} nbAnimations The expected number of animations.
+ * @param {String} msg An optional string to be used as the assertion message.
+ */
+function assertAnimationsDisplayed(panel, nbAnimations, msg="") {
+  let isNewUI = Services.prefs.getBoolPref(NEW_UI_PREF);
+  msg = msg || `There are ${nbAnimations} animations in the panel`;
+  if (isNewUI) {
+    is(panel.animationsTimelineComponent.animationsEl.childNodes.length,
+       nbAnimations, msg);
+  } else {
+    is(panel.playersEl.querySelectorAll(".player-widget").length,
+       nbAnimations, msg);
+  }
+}
+
+/**
  * Takes an Inspector panel that was just created, and waits
  * for a "inspector-updated" event as well as the animation inspector
  * sidebar to be ready. Returns a promise once these are completed.
  *
  * @param {InspectorPanel} inspector
  * @return {Promise}
  */
 let waitForAnimationInspectorReady = Task.async(function*(inspector) {
   let win = inspector.sidebar.getWindowForTab("animationinspector");
   let updated = inspector.once("inspector-updated");
 
-  // In e10s, if we wait for underlying toolbox actors to
-  // load (by setting gDevTools.testing to true), we miss the "animationinspector-ready"
-  // event on the sidebar, so check to see if the iframe
-  // is already loaded.
+  // In e10s, if we wait for underlying toolbox actors to load (by setting
+  // gDevTools.testing to true), we miss the "animationinspector-ready" event on
+  // the sidebar, so check to see if the iframe is already loaded.
   let tabReady = win.document.readyState === "complete" ?
                  promise.resolve() :
                  inspector.sidebar.once("animationinspector-ready");
 
   return promise.all([updated, tabReady]);
 });
 
 /**
  * Open the toolbox, with the inspector tool visible and the animationinspector
  * sidebar selected.
- * @return a promise that resolves when the inspector is ready
+ * @return a promise that resolves when the inspector is ready.
  */
 let openAnimationInspector = Task.async(function*() {
   let target = TargetFactory.forTab(gBrowser.selectedTab);
 
   info("Opening the toolbox with the inspector selected");
   let toolbox = yield gDevTools.showToolbox(target, "inspector");
 
   info("Switching to the animationinspector");
@@ -181,16 +211,55 @@ let openAnimationInspector = Task.async(
     inspector: inspector,
     controller: AnimationsController,
     panel: AnimationsPanel,
     window: win
   };
 });
 
 /**
+ * Turn on the new timeline-based UI pref ON, and then open the toolbox, with
+ * the inspector tool visible and the animationinspector sidebar selected.
+ * @return a promise that resolves when the inspector is ready.
+ */
+function openAnimationInspectorNewUI() {
+  enableNewUI();
+  return openAnimationInspector();
+}
+
+/**
+ * Close the toolbox.
+ * @return a promise that resolves when the toolbox has closed.
+ */
+let closeAnimationInspector = Task.async(function*() {
+  let target = TargetFactory.forTab(gBrowser.selectedTab);
+  yield gDevTools.closeToolbox(target);
+});
+
+/**
+ * During the time period we migrate from the playerWidgets-based UI to the new
+ * AnimationTimeline UI, we'll want to run certain tests against both UI.
+ * This closes the toolbox, switch the new UI pref ON, and opens the toolbox
+ * again, with the animation inspector panel selected.
+ * @param {Boolean} reload Optionally reload the page after the toolbox was
+ * closed and before it is opened again.
+ * @return a promise that resolves when the animation inspector is ready.
+ */
+let closeAnimationInspectorAndRestartWithNewUI = Task.async(function*(reload) {
+  info("Close the toolbox and test again with the new UI");
+  yield closeAnimationInspector();
+  if (reload) {
+    yield reloadTab();
+  }
+  enableNewUI();
+  return yield openAnimationInspector();
+});
+
+
+/**
  * Wait for the toolbox frame to receive focus after it loads
  * @param {Toolbox} toolbox
  * @return a promise that resolves when focus has been received
  */
 function waitForToolboxFrameFocus(toolbox) {
   info("Making sure that the toolbox's frame is focused");
   let def = promise.defer();
   let win = toolbox.frame.contentWindow;
@@ -209,17 +278,17 @@ function hasSideBarTab(inspector, id) {
   return !!inspector.sidebar.getWindowForTab(id);
 }
 
 /**
  * Wait for eventName on target.
  * @param {Object} target An observable object that either supports on/off or
  * addEventListener/removeEventListener
  * @param {String} eventName
- * @param {Boolean} useCapture Optional, for addEventListener/removeEventListener
+ * @param {Boolean} useCapture Optional, for add/removeEventListener
  * @return A promise that resolves when the event has been handled
  */
 function once(target, eventName, useCapture=false) {
   info("Waiting for event: '" + eventName + "' on " + target + ".");
 
   let deferred = promise.defer();
 
   for (let [add, remove] of [
@@ -273,32 +342,34 @@ function waitForContentMessage(name) {
  */
 function executeInContent(name, data={}, objects={}, expectResponse=true) {
   info("Sending message " + name + " to content");
   let mm = gBrowser.selectedBrowser.messageManager;
 
   mm.sendAsyncMessage(name, data, objects);
   if (expectResponse) {
     return waitForContentMessage(name);
-  } else {
-    return promise.resolve();
   }
+
+  return promise.resolve();
 }
 
 function onceNextPlayerRefresh(player) {
   let onRefresh = promise.defer();
   player.once(player.AUTO_REFRESH_EVENT, onRefresh.resolve);
   return onRefresh.promise;
 }
 
 /**
  * Simulate a click on the playPause button of a playerWidget.
  */
 let togglePlayPauseButton = Task.async(function*(widget) {
-  let nextState = widget.player.state.playState === "running" ? "paused" : "running";
+  let nextState = widget.player.state.playState === "running"
+                  ? "paused"
+                  : "running";
 
   // Note that instead of simulating a real event here, the callback is just
   // called. This is better because the callback returns a promise, so we know
   // when the player is paused, and we don't really care to test that simulating
   // a DOM event actually works.
   let onClicked = widget.onPlayPauseBtnClick();
 
   // Verify that the button's state is changed immediately, even if it will be
@@ -339,17 +410,18 @@ let waitForStateCondition = Task.async(f
   return def.promise;
 });
 
 /**
  * Wait for a player's auto-refresh events and stop when the playState is the
  * provided string.
  * @param {AnimationPlayerFront} player
  * @param {String} playState The playState to expect.
- * @return {Promise} Resolves when the playState has changed to the expected value.
+ * @return {Promise} Resolves when the playState has changed to the expected
+ * value.
  */
 function waitForPlayState(player, playState) {
   return waitForStateCondition(player, state => {
     return state.playState === playState;
   }, "Waiting for animation to be " + playState);
 }
 
 /**
new file mode 100644
--- /dev/null
+++ b/browser/devtools/animationinspector/test/unit/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the common devtools xpcshell eslintrc config.
+  "extends": "../../../.eslintrc.xpcshell"
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/devtools/animationinspector/test/unit/test_findOptimalTimeInterval.js
@@ -0,0 +1,85 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+/* eslint no-eval:0 */
+
+"use strict";
+
+const Cu = Components.utils;
+const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
+const {require} = devtools;
+
+const {findOptimalTimeInterval} = require("devtools/animationinspector/utils");
+
+// This test array contains objects that are used to test the
+// findOptimalTimeInterval function. Each object should have the following
+// properties:
+// - desc: an optional string that will be printed out
+// - timeScale: a number that represents how many pixels is 1ms
+// - minSpacing: an optional number that represents the minim space between 2
+//   time graduations
+// - expectedInterval: a number that you expect the findOptimalTimeInterval
+//   function to return as a result.
+//   Optionally you can pass a string where `interval` is the calculated
+//   interval, this string will be eval'd and tested to be truthy.
+const TEST_DATA = [{
+  desc: "With 1px being 1ms and no minSpacing, expect the interval to be the " +
+        "default min spacing",
+  timeScale: 1,
+  minSpacing: undefined,
+  expectedInterval: 10
+}, {
+  desc: "With 1px being 1ms and a custom minSpacing being a multiple of 10 " +
+        "expect the interval to be the custom min spacing",
+  timeScale: 1,
+  minSpacing: 40,
+  expectedInterval: 40
+}, {
+  desc: "With 1px being 1ms and a custom minSpacing not being multiple of 10 " +
+        "expect the interval to be the next multiple of 10",
+  timeScale: 1,
+  minSpacing: 13,
+  expectedInterval: 20
+}, {
+  desc: "If 1ms corresponds to a distance that is greater than the min " +
+        "spacing then, expect the interval to be this distance",
+  timeScale: 20,
+  minSpacing: undefined,
+  expectedInterval: 20
+}, {
+  desc: "If 1ms corresponds to a distance that is greater than the min " +
+        "spacing then, expect the interval to be this distance, even if it " +
+        "isn't a multiple of 10",
+  timeScale: 33,
+  minSpacing: undefined,
+  expectedInterval: 33
+}, {
+  desc: "If 1ms is a very small distance, then expect this distance to be " +
+        "multiplied by 10, 20, 40, 80, etc... until it goes over the min " +
+        "spacing",
+  timeScale: 0.001,
+  minSpacing: undefined,
+  expectedInterval: 10.24
+}, {
+  desc: "If the time scale is such that we need to iterate more than the " +
+        "maximum allowed number of iterations, then expect an interval lower " +
+        "than the minimum one",
+  timeScale: 1e-31,
+  minSpacing: undefined,
+  expectedInterval: "interval < 10"
+}];
+
+function run_test() {
+  for (let {timeScale, desc, minSpacing, expectedInterval} of TEST_DATA) {
+    do_print("Testing timeScale: " + timeScale + " and minSpacing: " +
+              minSpacing + ". Expecting " + expectedInterval + ".");
+
+    let interval = findOptimalTimeInterval(timeScale, minSpacing);
+    if (typeof expectedInterval == "string") {
+      ok(eval(expectedInterval), desc);
+    } else {
+      equal(interval, expectedInterval, desc);
+    }
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/animationinspector/test/unit/test_timeScale.js
@@ -0,0 +1,191 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const Cu = Components.utils;
+const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
+const {require} = devtools;
+
+const {TimeScale} = require("devtools/animationinspector/components");
+
+const TEST_ANIMATIONS = [{
+  startTime: 500,
+  delay: 0,
+  duration: 1000,
+  iterationCount: 1
+}, {
+  startTime: 400,
+  delay: 100,
+  duration: 10,
+  iterationCount: 100
+}, {
+  startTime: 50,
+  delay: 1000,
+  duration: 100,
+  iterationCount: 20
+}];
+const EXPECTED_MIN_START = 50;
+const EXPECTED_MAX_END = 3050;
+
+const TEST_STARTTIME_TO_DISTANCE = [{
+  time: 50,
+  width: 100,
+  expectedDistance: 0
+}, {
+  time: 50,
+  width: 0,
+  expectedDistance: 0
+}, {
+  time: 3050,
+  width: 200,
+  expectedDistance: 200
+}, {
+  time: 1550,
+  width: 200,
+  expectedDistance: 100
+}];
+
+const TEST_DURATION_TO_DISTANCE = [{
+  time: 3000,
+  width: 100,
+  expectedDistance: 100
+}, {
+  time: 0,
+  width: 100,
+  expectedDistance: 0
+}];
+
+const TEST_DISTANCE_TO_TIME = [{
+  distance: 100,
+  width: 100,
+  expectedTime: 3050
+}, {
+  distance: 0,
+  width: 100,
+  expectedTime: 50
+}, {
+  distance: 25,
+  width: 200,
+  expectedTime: 425
+}];
+
+const TEST_DISTANCE_TO_RELATIVE_TIME = [{
+  distance: 100,
+  width: 100,
+  expectedTime: 3000
+}, {
+  distance: 0,
+  width: 100,
+  expectedTime: 0
+}, {
+  distance: 25,
+  width: 200,
+  expectedTime: 375
+}];
+
+const TEST_FORMAT_TIME_MS = [{
+  time: 0,
+  expectedFormattedTime: "0ms"
+}, {
+  time: 3540.341,
+  expectedFormattedTime: "3540ms"
+}, {
+  time: 1.99,
+  expectedFormattedTime: "2ms"
+}, {
+  time: 4000,
+  expectedFormattedTime: "4000ms"
+}];
+
+const TEST_FORMAT_TIME_S = [{
+  time: 0,
+  expectedFormattedTime: "0.0s"
+}, {
+  time: 3540.341,
+  expectedFormattedTime: "3.5s"
+}, {
+  time: 1.99,
+  expectedFormattedTime: "0.0s"
+}, {
+  time: 4000,
+  expectedFormattedTime: "4.0s"
+}, {
+  time: 102540,
+  expectedFormattedTime: "102.5s"
+}, {
+  time: 102940,
+  expectedFormattedTime: "102.9s"
+}];
+
+function run_test() {
+  do_print("Check the default min/max range values");
+  equal(TimeScale.minStartTime, Infinity);
+  equal(TimeScale.maxEndTime, 0);
+
+  do_print("Test adding a few animations");
+  for (let {startTime, delay, duration, iterationCount} of TEST_ANIMATIONS) {
+    TimeScale.addAnimation({startTime, delay, duration, iterationCount});
+  }
+  equal(TimeScale.minStartTime, EXPECTED_MIN_START);
+  equal(TimeScale.maxEndTime, EXPECTED_MAX_END);
+
+  do_print("Test reseting the animations");
+  TimeScale.reset();
+  equal(TimeScale.minStartTime, Infinity);
+  equal(TimeScale.maxEndTime, 0);
+
+  do_print("Test adding the animations again");
+  for (let {startTime, delay, duration, iterationCount} of TEST_ANIMATIONS) {
+    TimeScale.addAnimation({startTime, delay, duration, iterationCount});
+  }
+  equal(TimeScale.minStartTime, EXPECTED_MIN_START);
+  equal(TimeScale.maxEndTime, EXPECTED_MAX_END);
+
+  do_print("Test converting start times to distances");
+  for (let {time, width, expectedDistance} of TEST_STARTTIME_TO_DISTANCE) {
+    let distance = TimeScale.startTimeToDistance(time, width);
+    equal(distance, expectedDistance);
+  }
+
+  do_print("Test converting durations to distances");
+  for (let {time, width, expectedDistance} of TEST_DURATION_TO_DISTANCE) {
+    let distance = TimeScale.durationToDistance(time, width);
+    equal(distance, expectedDistance);
+  }
+
+  do_print("Test converting distances to times");
+  for (let {distance, width, expectedTime} of TEST_DISTANCE_TO_TIME) {
+    let time = TimeScale.distanceToTime(distance, width);
+    equal(time, expectedTime);
+  }
+
+  do_print("Test converting distances to relative times");
+  for (let {distance, width, expectedTime} of TEST_DISTANCE_TO_RELATIVE_TIME) {
+    let time = TimeScale.distanceToRelativeTime(distance, width);
+    equal(time, expectedTime);
+  }
+
+  do_print("Test formatting times (millis)");
+  for (let {time, expectedFormattedTime} of TEST_FORMAT_TIME_MS) {
+    let formattedTime = TimeScale.formatTime(time);
+    equal(formattedTime, expectedFormattedTime);
+  }
+
+  // Add 1 more animation to increase the range and test more time formatting
+  // cases.
+  TimeScale.addAnimation({
+    startTime: 3000,
+    duration: 5000,
+    delay: 0,
+    iterationCount: 1
+  });
+
+  do_print("Test formatting times (seconds)");
+  for (let {time, expectedFormattedTime} of TEST_FORMAT_TIME_S) {
+    let formattedTime = TimeScale.formatTime(time);
+    equal(formattedTime, expectedFormattedTime);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/animationinspector/test/unit/xpcshell.ini
@@ -0,0 +1,9 @@
+[DEFAULT]
+tags = devtools
+head =
+tail =
+firefox-appdir = browser
+skip-if = toolkit == 'android' || toolkit == 'gonk'
+
+[test_findOptimalTimeInterval.js]
+[test_timeScale.js]
new file mode 100644
--- /dev/null
+++ b/browser/devtools/animationinspector/utils.js
@@ -0,0 +1,134 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ft=javascript 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";
+
+// How many times, maximum, can we loop before we find the optimal time
+// interval in the timeline graph.
+const OPTIMAL_TIME_INTERVAL_MAX_ITERS = 100;
+// Background time graduations should be multiple of this number of millis.
+const TIME_INTERVAL_MULTIPLE = 10;
+const TIME_INTERVAL_SCALES = 3;
+// The default minimum spacing between time graduations in px.
+const TIME_GRADUATION_MIN_SPACING = 10;
+// RGB color for the time interval background.
+const TIME_INTERVAL_COLOR = [128, 136, 144];
+const TIME_INTERVAL_OPACITY_MIN = 32; // byte
+const TIME_INTERVAL_OPACITY_ADD = 32; // byte
+
+/**
+ * DOM node creation helper function.
+ * @param {Object} Options to customize the node to be created.
+ * - nodeType {String} Optional, defaults to "div",
+ * - attributes {Object} Optional attributes object like
+ *   {attrName1:value1, attrName2: value2, ...}
+ * - parent {DOMNode} Mandatory node to append the newly created node to.
+ * - textContent {String} Optional text for the node.
+ * @return {DOMNode} The newly created node.
+ */
+function createNode(options) {
+  if (!options.parent) {
+    throw new Error("Missing parent DOMNode to create new node");
+  }
+
+  let type = options.nodeType || "div";
+  let node = options.parent.ownerDocument.createElement(type);
+
+  for (let name in options.attributes || {}) {
+    let value = options.attributes[name];
+    node.setAttribute(name, value);
+  }
+
+  if (options.textContent) {
+    node.textContent = options.textContent;
+  }
+
+  options.parent.appendChild(node);
+  return node;
+}
+
+exports.createNode = createNode;
+
+/**
+ * Given a data-scale, draw the background for a graph (vertical lines) into a
+ * canvas and set that canvas as an image-element with an ID that can be used
+ * from CSS.
+ * @param {Document} document The document where the image-element should be set.
+ * @param {String} id The ID for the image-element.
+ * @param {Number} graphWidth The width of the graph.
+ * @param {Number} timeScale How many px is 1ms in the graph.
+ */
+function drawGraphElementBackground(document, id, graphWidth, timeScale) {
+  let canvas = document.createElement("canvas");
+  let ctx = canvas.getContext("2d");
+
+  // Set the canvas width (as requested) and height (1px, repeated along the Y
+  // axis).
+  canvas.width = graphWidth;
+  canvas.height = 1;
+
+  // Create the image data array which will receive the pixels.
+  let imageData = ctx.createImageData(canvas.width, canvas.height);
+  let pixelArray = imageData.data;
+
+  let buf = new ArrayBuffer(pixelArray.length);
+  let view8bit = new Uint8ClampedArray(buf);
+  let view32bit = new Uint32Array(buf);
+
+  // Build new millisecond tick lines...
+  let [r, g, b] = TIME_INTERVAL_COLOR;
+  let alphaComponent = TIME_INTERVAL_OPACITY_MIN;
+  let interval = findOptimalTimeInterval(timeScale);
+
+  // Insert one pixel for each division on each scale.
+  for (let i = 1; i <= TIME_INTERVAL_SCALES; i++) {
+    let increment = interval * Math.pow(2, i);
+    for (let x = 0; x < canvas.width; x += increment) {
+      let position = x | 0;
+      view32bit[position] = (alphaComponent << 24) | (b << 16) | (g << 8) | r;
+    }
+    alphaComponent += TIME_INTERVAL_OPACITY_ADD;
+  }
+
+  // Flush the image data and cache the waterfall background.
+  pixelArray.set(view8bit);
+  ctx.putImageData(imageData, 0, 0);
+  document.mozSetImageElement(id, canvas);
+}
+
+exports.drawGraphElementBackground = drawGraphElementBackground;
+
+/**
+ * Find the optimal interval between time graduations in the animation timeline
+ * graph based on a time scale and a minimum spacing.
+ * @param {Number} timeScale How many px is 1ms in the graph.
+ * @param {Number} minSpacing The minimum spacing between 2 graduations,
+ * defaults to TIME_GRADUATION_MIN_SPACING.
+ * @return {Number} The optimal interval, in pixels.
+ */
+function findOptimalTimeInterval(timeScale,
+                                 minSpacing=TIME_GRADUATION_MIN_SPACING) {
+  let timingStep = TIME_INTERVAL_MULTIPLE;
+  let numIters = 0;
+
+  if (timeScale > minSpacing) {
+    return timeScale;
+  }
+
+  while (true) {
+    let scaledStep = timeScale * timingStep;
+    if (++numIters > OPTIMAL_TIME_INTERVAL_MAX_ITERS) {
+      return scaledStep;
+    }
+    if (scaledStep < minSpacing) {
+      timingStep *= 2;
+      continue;
+    }
+    return scaledStep;
+  }
+}
+
+exports.findOptimalTimeInterval = findOptimalTimeInterval;
--- a/browser/devtools/framework/toolbox-hosts.js
+++ b/browser/devtools/framework/toolbox-hosts.js
@@ -101,44 +101,42 @@ BottomHost.prototype = {
    * means that the toolbox won't be visible at all once minimized.
    */
   minimize: function(height=0) {
     if (this.isMinimized) {
       return;
     }
     this.isMinimized = true;
 
-    this.frame.style.marginBottom = -this.frame.height + height + "px";
-    this._splitter.classList.add("disabled");
-
     let onTransitionEnd = () => {
       this.frame.removeEventListener("transitionend", onTransitionEnd);
       this.emit("minimized");
     };
     this.frame.addEventListener("transitionend", onTransitionEnd);
+    this.frame.style.marginBottom = -this.frame.height + height + "px";
+    this._splitter.classList.add("disabled");
   },
 
   /**
    * If the host was minimized before, maximize it again (the host will be
    * maximized to the height it previously had).
    */
   maximize: function() {
     if (!this.isMinimized) {
       return;
     }
     this.isMinimized = false;
 
-    this.frame.style.marginBottom = "0";
-    this._splitter.classList.remove("disabled");
-
     let onTransitionEnd = () => {
       this.frame.removeEventListener("transitionend", onTransitionEnd);
       this.emit("maximized");
     };
     this.frame.addEventListener("transitionend", onTransitionEnd);
+    this.frame.style.marginBottom = "0";
+    this._splitter.classList.remove("disabled");
   },
 
   /**
    * Toggle the minimize mode.
    * @param {Number} minHeight The height to minimize to.
    */
   toggleMinimizeMode: function(minHeight) {
     this.isMinimized ? this.maximize() : this.minimize(minHeight);
--- a/browser/devtools/performance/modules/logic/marker-utils.js
+++ b/browser/devtools/performance/modules/logic/marker-utils.js
@@ -3,53 +3,65 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 /**
  * This file contains utilities for creating elements for markers to be displayed,
  * and parsing out the blueprint to generate correct values for markers.
  */
 
-const { Ci } = require("chrome");
+const { Cu, Ci } = require("chrome");
 
 loader.lazyRequireGetter(this, "L10N",
   "devtools/performance/global", true);
 loader.lazyRequireGetter(this, "PREFS",
   "devtools/performance/global", true);
 loader.lazyRequireGetter(this, "TIMELINE_BLUEPRINT",
   "devtools/performance/markers", true);
 loader.lazyRequireGetter(this, "WebConsoleUtils",
   "devtools/toolkit/webconsole/utils");
 
 // String used to fill in platform data when it should be hidden.
 const GECKO_SYMBOL = "(Gecko)";
 
 /**
+ * Takes a marker, blueprint, and filter list and
+ * determines if this marker should be filtered or not.
+ */
+function isMarkerValid (marker, filter) {
+  let isUnknown = !(marker.name in TIMELINE_BLUEPRINT);
+  if (isUnknown) {
+    return filter.indexOf("UNKNOWN") === -1;
+  }
+  return filter.indexOf(marker.name) === -1;
+}
+
+/**
  * Returns the correct label to display for passed in marker, based
  * off of the blueprints.
  *
  * @param {ProfileTimelineMarker} marker
  * @return {string}
  */
 function getMarkerLabel (marker) {
-  let blueprint = TIMELINE_BLUEPRINT[marker.name];
+  let blueprint = getBlueprintFor(marker);
   // Either use the label function in the blueprint, or use it directly
   // as a string.
   return typeof blueprint.label === "function" ? blueprint.label(marker) : blueprint.label;
 }
 
 /**
  * Returns the correct generic name for a marker class, like "Function Call"
  * being the general class for JS markers, rather than "setTimeout", etc.
  *
  * @param {string} type
  * @return {string}
  */
 function getMarkerClassName (type) {
-  let blueprint = TIMELINE_BLUEPRINT[type];
+  let blueprint = getBlueprintFor({ name: type });
   // Either use the label function in the blueprint, or use it directly
   // as a string.
   let className = typeof blueprint.label === "function" ? blueprint.label() : blueprint.label;
 
   // If no class name found, attempt to throw a descriptive error how the marker
   // implementor can fix this.
   if (!className) {
     let message = `Could not find marker class name for "${type}".`;
@@ -67,17 +79,17 @@ function getMarkerClassName (type) {
 /**
  * Returns an array of objects with key/value pairs of what should be rendered
  * in the marker details view.
  *
  * @param {ProfileTimelineMarker} marker
  * @return {Array<object>}
  */
 function getMarkerFields (marker) {
-  let blueprint = TIMELINE_BLUEPRINT[marker.name];
+  let blueprint = getBlueprintFor(marker);
 
   // If blueprint.fields is a function, use that
   if (typeof blueprint.fields === "function") {
     let fields = blueprint.fields(marker);
     // Add a ":" to the label since the localization files contain the ":"
     // if not present. This should be changed, ugh.
     return Object.keys(fields || []).map(label => {
       // TODO revisit localization strings for markers bug 1163763
@@ -106,31 +118,31 @@ const DOM = {
    * Builds all the fields possible for the given marker. Returns an
    * array of elements to be appended to a parent element.
    *
    * @param {Document} doc
    * @param {ProfileTimelineMarker} marker
    * @return {Array<Element>}
    */
   buildFields: function (doc, marker) {
-    let blueprint = TIMELINE_BLUEPRINT[marker.name];
+    let blueprint = getBlueprintFor(marker);
     let fields = getMarkerFields(marker);
 
     return fields.map(({ label, value }) => DOM.buildNameValueLabel(doc, label, value));
   },
 
   /**
    * Builds the label representing marker's type.
    *
    * @param {Document} doc
    * @param {ProfileTimelineMarker}
    * @return {Element}
    */
   buildTitle: function (doc, marker) {
-    let blueprint = TIMELINE_BLUEPRINT[marker.name];
+    let blueprint = getBlueprintFor(marker);
 
     let hbox = doc.createElement("hbox");
     hbox.setAttribute("align", "center");
 
     let bullet = doc.createElement("hbox");
     bullet.className = `marker-details-bullet marker-color-${blueprint.colorName}`;
 
     let title = getMarkerLabel(marker);
@@ -372,16 +384,24 @@ const JS_MARKER_MAP = {
   "EventHandlerNonNull":       "Event Handler",
   "EventListener.handleEvent": "Event Handler",
 };
 
 /**
  * A series of formatters used by the blueprint.
  */
 const Formatters = {
+  /**
+   * Uses the marker name as the label for markers that do not have
+   * a blueprint entry. Uses "Other" in the marker filter menu.
+   */
+  UnknownLabel: function (marker={}) {
+    return marker.name || L10N.getStr("timeline.label.unknown");
+  },
+
   GCLabel: function (marker={}) {
     let label = L10N.getStr("timeline.label.garbageCollection");
     // Only if a `nonincrementalReason` exists, do we want to label
     // this as a non incremental GC event.
     if ("nonincrementalReason" in marker) {
       label = `${label} (Non-incremental)`;
     }
     return label;
@@ -439,14 +459,27 @@ const Formatters = {
   CycleCollectionFields: function (marker) {
     let Type = PREFS["show-platform-data"]
         ? marker.name
         : marker.name.replace(/nsCycleCollector::/g, "");
     return { Type };
   },
 };
 
+/**
+ * Takes a marker and returns the definition for that marker type,
+ * falling back to the UNKNOWN definition if undefined.
+ *
+ * @param {Marker} marker
+ * @return {object}
+ */
+function getBlueprintFor (marker) {
+  return TIMELINE_BLUEPRINT[marker.name] || TIMELINE_BLUEPRINT.UNKNOWN;
+}
+
+exports.isMarkerValid = isMarkerValid;
 exports.getMarkerLabel = getMarkerLabel;
 exports.getMarkerClassName = getMarkerClassName;
 exports.getMarkerFields = getMarkerFields;
 exports.DOM = DOM;
 exports.CollapseFunctions = CollapseFunctions;
 exports.Formatters = Formatters;
+exports.getBlueprintFor = getBlueprintFor;
--- a/browser/devtools/performance/modules/logic/recording-utils.js
+++ b/browser/devtools/performance/modules/logic/recording-utils.js
@@ -192,65 +192,16 @@ function getProfileThreadFromAllocations
     allocationsTable: counts
   };
 
   gProfileThreadFromAllocationCache.set(allocations, thread);
   return thread;
 }
 
 /**
- * Gets the current timeline blueprint without the hidden markers.
- *
- * @param blueprint
- *        The default timeline blueprint.
- * @param array hiddenMarkers
- *        A list of hidden markers' names.
- * @return object
- *         The filtered timeline blueprint.
- */
-function getFilteredBlueprint({ blueprint, hiddenMarkers }) {
-  // Clone functions here just to prevent an error, as the blueprint
-  // contains functions (even though we do not use them).
-  let filteredBlueprint = Cu.cloneInto(blueprint, {}, { cloneFunctions: true });
-  let maybeRemovedGroups = new Set();
-  let removedGroups = new Set();
-
-  // 1. Remove hidden markers from the blueprint.
-
-  for (let hiddenMarkerName of hiddenMarkers) {
-    maybeRemovedGroups.add(filteredBlueprint[hiddenMarkerName].group);
-    delete filteredBlueprint[hiddenMarkerName];
-  }
-
-  // 2. Get a list of all the groups that will be removed.
-
-  for (let maybeRemovedGroup of maybeRemovedGroups) {
-    let markerNames = Object.keys(filteredBlueprint);
-    let isGroupRemoved = markerNames.every(e => filteredBlueprint[e].group != maybeRemovedGroup);
-    if (isGroupRemoved) {
-      removedGroups.add(maybeRemovedGroup);
-    }
-  }
-
-  // 3. Offset groups so that their indices are consecutive.
-
-  for (let removedGroup of removedGroups) {
-    let markerNames = Object.keys(filteredBlueprint);
-    for (let markerName of markerNames) {
-      let markerDetails = filteredBlueprint[markerName];
-      if (markerDetails.group > removedGroup) {
-        markerDetails.group--;
-      }
-    }
-  }
-
-  return filteredBlueprint;
-};
-
-/**
  * Deduplicates a profile by deduplicating stacks, frames, and strings.
  *
  * This is used to adapt version 2 profiles from the backend to version 3, for
  * use with older Geckos (like B2G).
  *
  * Note that the schemas used by this must be kept in sync with schemas used
  * by the C++ UniqueStacks class in tools/profiler/ProfileEntry.cpp.
  *
@@ -566,13 +517,12 @@ UniqueStacks.prototype.getOrAddStringInd
   return this._uniqueStrings.getOrAddStringIndex(s);
 };
 
 exports.filterSamples = filterSamples;
 exports.offsetSampleTimes = offsetSampleTimes;
 exports.offsetMarkerTimes = offsetMarkerTimes;
 exports.offsetAndScaleTimestamps = offsetAndScaleTimestamps;
 exports.getProfileThreadFromAllocations = getProfileThreadFromAllocations;
-exports.getFilteredBlueprint = getFilteredBlueprint;
 exports.deflateProfile = deflateProfile;
 exports.deflateThread = deflateThread;
 exports.UniqueStrings = UniqueStrings;
 exports.UniqueStacks = UniqueStacks;
--- a/browser/devtools/performance/modules/logic/waterfall-utils.js
+++ b/browser/devtools/performance/modules/logic/waterfall-utils.js
@@ -2,37 +2,35 @@
  * 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";
 
 /**
  * Utility functions for collapsing markers into a waterfall.
  */
 
-loader.lazyRequireGetter(this, "TIMELINE_BLUEPRINT",
-  "devtools/performance/markers", true);
+loader.lazyRequireGetter(this, "getBlueprintFor",
+  "devtools/performance/marker-utils", true);
 
 /**
  * Collapses markers into a tree-like structure.
  * @param object markerNode
  * @param array markersList
- * @param ?object blueprint
  */
-function collapseMarkersIntoNode({ markerNode, markersList, blueprint }) {
+function collapseMarkersIntoNode({ markerNode, markersList }) {
   let { getCurrentParentNode, collapseMarker, addParentNode, popParentNode } = createParentNodeFactory(markerNode);
-  blueprint = blueprint || TIMELINE_BLUEPRINT;
 
   for (let i = 0, len = markersList.length; i < len; i++) {
     let curr = markersList[i];
 
     let parentNode = getCurrentParentNode();
-    let def = blueprint[curr.name];
-    let collapse = def.collapseFunc || (() => null);
+    let blueprint = getBlueprintFor(curr);
+
+    let collapse = blueprint.collapseFunc || (() => null);
     let peek = distance => markersList[i + distance];
-    let foundParent = false;
 
     let collapseInfo = collapse(parentNode, curr, peek);
     if (collapseInfo) {
       let { collapse, toParent, finalize } = collapseInfo;
 
       // If `toParent` is an object, use it as the next parent marker
       if (typeof toParent === "object") {
         addParentNode(toParent);
--- a/browser/devtools/performance/modules/markers.js
+++ b/browser/devtools/performance/modules/markers.js
@@ -50,16 +50,26 @@ const { Formatters, CollapseFunctions: c
  *                        displayed value.
  *            Can also be a function that returns an object. Each key in the object
  *            will be rendered as a field, with its value rendering as the value.
  *
  * Whenever this is changed, browser_timeline_waterfall-styles.js *must* be
  * updated as well.
  */
 const TIMELINE_BLUEPRINT = {
+  /* Default definition used for markers that occur but
+   * are not defined here. Should ultimately be defined, but this gives
+   * us room to work on the front end separately from the platform. */
+  "UNKNOWN": {
+    group: 2,
+    colorName: "graphs-grey",
+    collapseFunc: collapse.child,
+    label: Formatters.UnknownLabel
+  },
+
   /* Group 0 - Reflow and Rendering pipeline */
   "Styles": {
     group: 0,
     colorName: "graphs-purple",
     collapseFunc: collapse.child,
     label: L10N.getStr("timeline.label.styles2"),
     fields: Formatters.StylesFields,
   },
@@ -126,17 +136,17 @@ const TIMELINE_BLUEPRINT = {
     collapseFunc: either(collapse.parent, collapse.child),
     label: "Cycle Collection",
     fields: Formatters.CycleCollectionFields,
   },
 
   /* Group 2 - User Controlled */
   "ConsoleTime": {
     group: 2,
-    colorName: "graphs-grey",
+    colorName: "graphs-blue",
     label: sublabelForProperty(L10N.getStr("timeline.label.consoleTime"), "causeName"),
     fields: [{
       property: "causeName",
       label: L10N.getStr("timeline.markerDetail.consoleTimerName")
     }],
   },
   "TimeStamp": {
     group: 2,
--- a/browser/devtools/performance/modules/widgets/graphs.js
+++ b/browser/devtools/performance/modules/widgets/graphs.js
@@ -130,18 +130,18 @@ function MemoryGraph(parent) {
 MemoryGraph.prototype = Heritage.extend(PerformanceGraph.prototype, {
   mainColor: MEMORY_GRAPH_COLOR_NAME,
   setPerformanceData: function ({ duration, memory }) {
     this.dataDuration = duration;
     return this.setData(memory);
   }
 });
 
-function TimelineGraph(parent, blueprint) {
-  MarkersOverview.call(this, parent, blueprint);
+function TimelineGraph(parent, filter) {
+  MarkersOverview.call(this, parent, filter);
 }
 
 TimelineGraph.prototype = Heritage.extend(MarkersOverview.prototype, {
   headerHeight: MARKERS_GRAPH_HEADER_HEIGHT,
   rowHeight: MARKERS_GRAPH_ROW_HEIGHT,
   groupPadding: MARKERS_GROUP_VERTICAL_PADDING,
   setPerformanceData: MarkersOverview.prototype.setData
 });
@@ -158,36 +158,35 @@ const GRAPH_DEFINITIONS = {
   },
   framerate: {
     constructor: FramerateGraph,
     selector: "#time-framerate",
   },
   timeline: {
     constructor: TimelineGraph,
     selector: "#markers-overview",
-    needsBlueprints: true,
     primaryLink: true
   }
 };
 
 /**
  * A controller for orchestrating the performance's tool overview graphs. Constructs,
  * syncs, toggles displays and defines the memory, framerate and timeline view.
  *
  * @param {object} definition
  * @param {DOMElement} root
- * @param {function} getBlueprint
+ * @param {function} getFilter
  * @param {function} getTheme
  */
-function GraphsController ({ definition, root, getBlueprint, getTheme }) {
+function GraphsController ({ definition, root, getFilter, getTheme }) {
   this._graphs = {};
   this._enabled = new Set();
   this._definition = definition || GRAPH_DEFINITIONS;
   this._root = root;
-  this._getBlueprint = getBlueprint;
+  this._getFilter = getFilter;
   this._getTheme = getTheme;
   this._primaryLink = Object.keys(this._definition).filter(name => this._definition[name].primaryLink)[0];
   this.$ = root.ownerDocument.querySelector.bind(root.ownerDocument);
 
   EventEmitter.decorate(this);
   this._onSelecting = this._onSelecting.bind(this);
 }
 
@@ -364,18 +363,18 @@ GraphsController.prototype = {
   }),
 
   /**
    * Creates the graph `graphName` and initializes it.
    */
   _construct: Task.async(function *(graphName) {
     let def = this._definition[graphName];
     let el = this.$(def.selector);
-    let blueprint = def.needsBlueprints ? this._getBlueprint() : void 0;
-    let graph = this._graphs[graphName] = new def.constructor(el, blueprint);
+    let filter = this._getFilter();
+    let graph = this._graphs[graphName] = new def.constructor(el, filter);
     graph.graphName = graphName;
 
     yield graph.ready();
 
     // Sync the graphs' animations and selections together
     if (def.primaryLink) {
       graph.on("selecting", this._onSelecting);
     } else {
--- a/browser/devtools/performance/modules/widgets/marker-details.js
+++ b/browser/devtools/performance/modules/widgets/marker-details.js
@@ -8,18 +8,16 @@
  */
 
 const { Cc, Ci, Cu, Cr } = require("chrome");
 
 loader.lazyRequireGetter(this, "EventEmitter",
   "devtools/toolkit/event-emitter");
 loader.lazyRequireGetter(this, "L10N",
   "devtools/performance/global", true);
-loader.lazyRequireGetter(this, "TIMELINE_BLUEPRINT",
-  "devtools/performance/markers", true);
 loader.lazyRequireGetter(this, "MarkerUtils",
   "devtools/performance/marker-utils");
 
 /**
  * A detailed view for one single marker.
  *
  * @param nsIDOMNode parent
  *        The parent node holding the view.
--- a/browser/devtools/performance/modules/widgets/marker-view.js
+++ b/browser/devtools/performance/modules/widgets/marker-view.js
@@ -6,21 +6,20 @@
 /**
  * This file contains the "marker" view, essentially a detailed list
  * of all the markers in the timeline data.
  */
 
 const { Cc, Ci, Cu, Cr } = require("chrome");
 const { Heritage } = require("resource:///modules/devtools/ViewHelpers.jsm");
 const { AbstractTreeItem } = require("resource:///modules/devtools/AbstractTreeItem.jsm");
-const { TIMELINE_BLUEPRINT: ORIGINAL_BP } = require("devtools/performance/markers");
-
 loader.lazyRequireGetter(this, "MarkerUtils",
   "devtools/performance/marker-utils");
 
+
 const HTML_NS = "http://www.w3.org/1999/xhtml";
 
 const LEVEL_INDENT = 10; // px
 const ARROW_NODE_OFFSET = -15; // px
 const WATERFALL_MARKER_SIDEBAR_WIDTH = 175; // px
 const WATERFALL_MARKER_TIMEBAR_WIDTH_MIN = 5; // px
 
 /**
@@ -55,25 +54,24 @@ MarkerView.prototype = Heritage.extend(A
    * Calculates and stores the available width for the waterfall.
    * This should be invoked every time the container node is resized.
    */
   recalculateBounds: function() {
     this.root._waterfallWidth = this.bounds.width - WATERFALL_MARKER_SIDEBAR_WIDTH;
   },
 
   /**
-   * Sets a list of names and colors used to paint markers.
-   * @see TIMELINE_BLUEPRINT in timeline/widgets/global.js
-   * @param object blueprint
+   * Sets a list of marker types to be filtered out of this view.
+   * @param Array<String> filter
    */
-  set blueprint(blueprint) {
-    this.root._blueprint = blueprint;
+  set filter(filter) {
+    this.root._filter = filter;
   },
-  get blueprint() {
-    return this.root._blueprint;
+  get filter() {
+    return this.root._filter;
   },
 
   /**
    * Sets the { startTime, endTime }, in milliseconds.
    * @param object interval
    */
   set interval(interval) {
     this.root._interval = interval;
@@ -134,35 +132,32 @@ MarkerView.prototype = Heritage.extend(A
    * Populates this node in the waterfall tree with the corresponding "markers".
    * @param array:AbstractTreeItem children
    */
   _populateSelf: function(children) {
     let submarkers = this.marker.submarkers;
     if (!submarkers || !submarkers.length) {
       return;
     }
-    let blueprint = this.root._blueprint;
     let startTime = this.root._interval.startTime;
     let endTime = this.root._interval.endTime;
     let newLevel = this.level + 1;
 
     for (let i = 0, len = submarkers.length; i < len; i++) {
       let marker = submarkers[i];
 
-      // If this marker isn't in the global timeline blueprint, don't display
-      // it, but dump a warning message to the console.
-      if (!(marker.name in blueprint)) {
-        if (!(marker.name in ORIGINAL_BP)) {
-          console.warn(`Marker not found in timeline blueprint: ${marker.name}.`);
-        }
+      // Skip filtered markers
+      if (!MarkerUtils.isMarkerValid(marker, this.filter)) {
         continue;
       }
+
       if (!isMarkerInRange(marker, startTime|0, endTime|0)) {
         continue;
       }
+
       children.push(new MarkerView({
         owner: this,
         marker: marker,
         level: newLevel,
         inverted: this.inverted
       }));
     }
   },
@@ -170,25 +165,22 @@ MarkerView.prototype = Heritage.extend(A
   /**
    * Builds all the nodes representing a marker in the waterfall.
    * @param nsIDOMNode document
    * @param nsIDOMNode targetNode
    * @param nsIDOMNode arrowNode
    */
   _buildMarkerCells: function(doc, targetNode, arrowNode) {
     let marker = this.marker;
-    let style = this.root._blueprint[marker.name];
+    let blueprint = MarkerUtils.getBlueprintFor(marker);
     let startTime = this.root._interval.startTime;
     let endTime = this.root._interval.endTime;
 
-    let sidebarCell = this._buildMarkerSidebar(
-      doc, style, marker);
-
-    let timebarCell = this._buildMarkerTimebar(
-      doc, style, marker, startTime, endTime, arrowNode);
+    let sidebarCell = this._buildMarkerSidebar(doc, blueprint, marker);
+    let timebarCell = this._buildMarkerTimebar(doc, blueprint, marker, startTime, endTime, arrowNode);
 
     targetNode.appendChild(sidebarCell);
     targetNode.appendChild(timebarCell);
 
     // Don't render an expando-arrow for leaf nodes.
     let submarkers = this.marker.submarkers;
     let hasDescendants = submarkers && submarkers.length > 0;
     if (hasDescendants) {
--- a/browser/devtools/performance/modules/widgets/markers-overview.js
+++ b/browser/devtools/performance/modules/widgets/markers-overview.js
@@ -16,74 +16,91 @@ const { Heritage } = require("resource:/
 loader.lazyRequireGetter(this, "colorUtils",
   "devtools/css-color", true);
 loader.lazyRequireGetter(this, "getColor",
   "devtools/shared/theme", true);
 loader.lazyRequireGetter(this, "L10N",
   "devtools/performance/global", true);
 loader.lazyRequireGetter(this, "TickUtils",
   "devtools/performance/waterfall-ticks", true);
+loader.lazyRequireGetter(this, "MarkerUtils",
+  "devtools/performance/marker-utils");
+loader.lazyRequireGetter(this, "TIMELINE_BLUEPRINT",
+  "devtools/performance/markers", true);
 
 const OVERVIEW_HEADER_HEIGHT = 14; // px
 const OVERVIEW_ROW_HEIGHT = 11; // px
 
 const OVERVIEW_SELECTION_LINE_COLOR = "#666";
 const OVERVIEW_CLIPHEAD_LINE_COLOR = "#555";
 
-const FIND_OPTIMAL_TICK_INTERVAL_MAX_ITERS = 100;
 const OVERVIEW_HEADER_TICKS_MULTIPLE = 100; // ms
 const OVERVIEW_HEADER_TICKS_SPACING_MIN = 75; // px
 const OVERVIEW_HEADER_TEXT_FONT_SIZE = 9; // px
 const OVERVIEW_HEADER_TEXT_FONT_FAMILY = "sans-serif";
 const OVERVIEW_HEADER_TEXT_PADDING_LEFT = 6; // px
 const OVERVIEW_HEADER_TEXT_PADDING_TOP = 1; // px
-const OVERVIEW_MARKERS_COLOR_STOPS = [0, 0.1, 0.75, 1];
 const OVERVIEW_MARKER_WIDTH_MIN = 4; // px
 const OVERVIEW_GROUP_VERTICAL_PADDING = 5; // px
 
 /**
  * An overview for the markers data.
  *
  * @param nsIDOMNode parent
  *        The parent node holding the overview.
- * @param Object blueprint
- *        List of names and colors defining markers.
+ * @param Array<String> filter
+ *        List of names of marker types that should not be shown.
  */
-function MarkersOverview(parent, blueprint, ...args) {
+function MarkersOverview(parent, filter=[], ...args) {
   AbstractCanvasGraph.apply(this, [parent, "markers-overview", ...args]);
   this.setTheme();
-  this.setBlueprint(blueprint);
+  this.setFilter(filter);
 }
 
 MarkersOverview.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
   clipheadLineColor: OVERVIEW_CLIPHEAD_LINE_COLOR,
   selectionLineColor: OVERVIEW_SELECTION_LINE_COLOR,
   headerHeight: OVERVIEW_HEADER_HEIGHT,
   rowHeight: OVERVIEW_ROW_HEIGHT,
   groupPadding: OVERVIEW_GROUP_VERTICAL_PADDING,
 
   /**
    * Compute the height of the overview.
    */
   get fixedHeight() {
-    return this.headerHeight + this.rowHeight * (this._lastGroup + 1);
+    return this.headerHeight + this.rowHeight * this._numberOfGroups;
   },
 
   /**
-   * List of names and colors used to paint this overview.
-   * @see TIMELINE_BLUEPRINT in timeline/widgets/global.js
+   * List of marker types that should not be shown in the graph.
    */
-  setBlueprint: function(blueprint) {
+  setFilter: function (filter) {
     this._paintBatches = new Map();
-    this._lastGroup = 0;
+    this._filter = filter;
+    this._groupMap = Object.create(null);
+
+    let observedGroups = new Set();
 
-    for (let type in blueprint) {
-      this._paintBatches.set(type, { style: blueprint[type], batch: [] });
-      this._lastGroup = Math.max(this._lastGroup, blueprint[type].group || 0);
+    for (let type in TIMELINE_BLUEPRINT) {
+      if (filter.indexOf(type) !== -1) {
+        continue;
+      }
+      this._paintBatches.set(type, { definition: TIMELINE_BLUEPRINT[type], batch: [] });
+      observedGroups.add(TIMELINE_BLUEPRINT[type].group);
     }
+
+    // Take our set of observed groups and order them and map
+    // the group numbers to fill in the holes via `_groupMap`.
+    // This normalizes our rows by removing rows that aren't used
+    // if filters are enabled.
+    let actualPosition = 0;
+    for (let groupNumber of Array.from(observedGroups).sort()) {
+      this._groupMap[groupNumber] = actualPosition++;
+    }
+    this._numberOfGroups = Object.keys(this._groupMap).length;
   },
 
   /**
    * Disables selection and empties this graph.
    */
   clearView: function() {
     this.selectionEnabled = false;
     this.dropSelection();
@@ -98,27 +115,29 @@ MarkersOverview.prototype = Heritage.ext
     let { markers, duration } = this._data;
 
     let { canvas, ctx } = this._getNamedCanvas("markers-overview-data");
     let canvasWidth = this._width;
     let canvasHeight = this._height;
 
     // Group markers into separate paint batches. This is necessary to
     // draw all markers sharing the same style at once.
+    for (let marker of markers) {
+      // Again skip over markers that we're filtering -- we don't want them
+      // to be labeled as "Unknown"
+      if (!MarkerUtils.isMarkerValid(marker, this._filter)) {
+        continue;
+      }
 
-    for (let marker of markers) {
-      let markerType = this._paintBatches.get(marker.name);
-      if (markerType) {
-        markerType.batch.push(marker);
-      }
+      let markerType = this._paintBatches.get(marker.name) || this._paintBatches.get("UNKNOWN");
+      markerType.batch.push(marker);
     }
 
     // Calculate each row's height, and the time-based scaling.
 
-    let totalGroups = this._lastGroup + 1;
     let groupHeight = this.rowHeight * this._pixelRatio;
     let groupPadding = this.groupPadding * this._pixelRatio;
     let headerHeight = this.headerHeight * this._pixelRatio;
     let dataScale = this.dataScaleX = canvasWidth / duration;
 
     // Draw the header and overview background.
 
     ctx.fillStyle = this.headerBackgroundColor;
@@ -127,17 +146,17 @@ MarkersOverview.prototype = Heritage.ext
     ctx.fillStyle = this.backgroundColor;
     ctx.fillRect(0, headerHeight, canvasWidth, canvasHeight);
 
     // Draw the alternating odd/even group backgrounds.
 
     ctx.fillStyle = this.alternatingBackgroundColor;
     ctx.beginPath();
 
-    for (let i = 0; i < totalGroups; i += 2) {
+    for (let i = 0; i < this._numberOfGroups; i += 2) {
       let top = headerHeight + i * groupHeight;
       ctx.rect(0, top, canvasWidth, groupHeight);
     }
 
     ctx.fill();
 
     // Draw the timeline header ticks.
 
@@ -167,21 +186,22 @@ MarkersOverview.prototype = Heritage.ext
       ctx.moveTo(lineLeft, 0);
       ctx.lineTo(lineLeft, canvasHeight);
     }
 
     ctx.stroke();
 
     // Draw the timeline markers.
 
-    for (let [, { style, batch }] of this._paintBatches) {
-      let top = headerHeight + style.group * groupHeight + groupPadding / 2;
+    for (let [, { definition, batch }] of this._paintBatches) {
+      let group = this._groupMap[definition.group];
+      let top = headerHeight + group * groupHeight + groupPadding / 2;
       let height = groupHeight - groupPadding;
 
-      let color = getColor(style.colorName, this.theme);
+      let color = getColor(definition.colorName, this.theme);
       ctx.fillStyle = color;
       ctx.beginPath();
 
       for (let { start, end } of batch) {
         let left = start * dataScale;
         let width = Math.max((end - start) * dataScale, OVERVIEW_MARKER_WIDTH_MIN);
         ctx.rect(left, top, width, height);
       }
--- a/browser/devtools/performance/performance-controller.js
+++ b/browser/devtools/performance/performance-controller.js
@@ -394,26 +394,16 @@ let PerformanceController = {
       if (!model.isConsole() && !model.isImported()) {
         return this._recordings[i];
       }
     }
     return null;
   },
 
   /**
-   * Gets the current timeline blueprint without the hidden markers.
-   * @return object
-   */
-  getTimelineBlueprint: function() {
-    let blueprint = TIMELINE_BLUEPRINT;
-    let hiddenMarkers = this.getPref("hidden-markers");
-    return RecordingUtils.getFilteredBlueprint({ blueprint, hiddenMarkers });
-  },
-
-  /**
    * Fired from RecordingsView, we listen on the PerformanceController so we can
    * set it here and re-emit on the controller, where all views can listen.
    */
   _onRecordingSelectFromView: function (_, recording) {
     this.setCurrentRecording(recording);
   },
 
   /**
--- a/browser/devtools/performance/test/browser.ini
+++ b/browser/devtools/performance/test/browser.ini
@@ -8,17 +8,16 @@ support-files =
   doc_markers.html
   doc_simple-test.html
   head.js
 
 # Commented out tests are profiler tests
 # that need to be moved over to performance tool
 
 [browser_aaa-run-first-leaktest.js]
-[browser_marker-utils.js]
 [browser_markers-cycle-collection.js]
 [browser_markers-gc.js]
 [browser_markers-parse-html.js]
 [browser_markers-styles.js]
 [browser_markers-timestamp.js]
 [browser_perf-allocations-to-samples.js]
 [browser_perf-categories-js-calltree.js]
 [browser_perf-compatibility-01.js]
@@ -132,15 +131,14 @@ support-files =
 [browser_profiler_tree-view-03.js]
 [browser_profiler_tree-view-04.js]
 [browser_profiler_tree-view-05.js]
 [browser_profiler_tree-view-06.js]
 [browser_profiler_tree-view-07.js]
 [browser_profiler_tree-view-08.js]
 [browser_profiler_tree-view-09.js]
 [browser_profiler_tree-view-10.js]
-[browser_timeline-blueprint.js]
 [browser_timeline-filters.js]
 [browser_timeline-waterfall-background.js]
 [browser_timeline-waterfall-generic.js]
 [browser_timeline-waterfall-rerender.js]
 [browser_timeline-waterfall-sidebar.js]
 skip-if = os == 'linux' # Bug 1161817
deleted file mode 100644
--- a/browser/devtools/performance/test/browser_marker-utils.js
+++ /dev/null
@@ -1,70 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Tests the marker utils methods.
- */
-
-function* spawnTest() {
-  let { TIMELINE_BLUEPRINT } = devtools.require("devtools/performance/markers");
-  let Utils = devtools.require("devtools/performance/marker-utils");
-
-  Services.prefs.setBoolPref(PLATFORM_DATA_PREF, false);
-
-  is(Utils.getMarkerLabel({ name: "DOMEvent" }), "DOM Event",
-    "getMarkerLabel() returns a simple label");
-  is(Utils.getMarkerLabel({ name: "Javascript", causeName: "setTimeout handler" }), "setTimeout",
-    "getMarkerLabel() returns a label defined via function");
-
-  ok(Utils.getMarkerFields({ name: "Paint" }).length === 0,
-    "getMarkerFields() returns an empty array when no fields defined");
-
-  let fields = Utils.getMarkerFields({ name: "ConsoleTime", causeName: "snowstorm" });
-  is(fields[0].label, "Timer Name:", "getMarkerFields() returns an array with proper label");
-  is(fields[0].value, "snowstorm", "getMarkerFields() returns an array with proper value");
-
-  fields = Utils.getMarkerFields({ name: "DOMEvent", type: "mouseclick" });
-  is(fields.length, 1, "getMarkerFields() ignores fields that are not found on marker");
-  is(fields[0].label, "Event Type:", "getMarkerFields() returns an array with proper label");
-  is(fields[0].value, "mouseclick", "getMarkerFields() returns an array with proper value");
-
-  fields = Utils.getMarkerFields({ name: "DOMEvent", eventPhase: Ci.nsIDOMEvent.AT_TARGET, type: "mouseclick" });
-  is(fields.length, 2, "getMarkerFields() returns multiple fields when using a fields function");
-  is(fields[0].label, "Event Type:", "getMarkerFields() correctly returns fields via function (1)");
-  is(fields[0].value, "mouseclick", "getMarkerFields() correctly returns fields via function (2)");
-  is(fields[1].label, "Phase:", "getMarkerFields() correctly returns fields via function (3)");
-  is(fields[1].value, "Target", "getMarkerFields() correctly returns fields via function (4)");
-
-  is(Utils.getMarkerFields({ name: "Javascript", causeName: "Some Platform Field" })[0].value, "(Gecko)",
-    "Correctly obfuscates JS markers when platform data is off.");
-  Services.prefs.setBoolPref(PLATFORM_DATA_PREF, true);
-  is(Utils.getMarkerFields({ name: "Javascript", causeName: "Some Platform Field" })[0].value, "Some Platform Field",
-    "Correctly deobfuscates JS markers when platform data is on.");
-
-  is(Utils.getMarkerClassName("Javascript"), "Function Call",
-    "getMarkerClassName() returns correct string when defined via function");
-  is(Utils.getMarkerClassName("GarbageCollection"), "GC Event",
-    "getMarkerClassName() returns correct string when defined via function");
-  is(Utils.getMarkerClassName("Reflow"), "Layout",
-    "getMarkerClassName() returns correct string when defined via string");
-
-  TIMELINE_BLUEPRINT["fakemarker"] = { group: 0 };
-  try {
-    Utils.getMarkerClassName("fakemarker");
-    ok(false, "getMarkerClassName() should throw when no label on blueprint.");
-  } catch (e) {
-    ok(true, "getMarkerClassName() should throw when no label on blueprint.");
-  }
-
-  TIMELINE_BLUEPRINT["fakemarker"] = { group: 0, label: () => void 0};
-  try {
-    Utils.getMarkerClassName("fakemarker");
-    ok(false, "getMarkerClassName() should throw when label function returnd undefined.");
-  } catch (e) {
-    ok(true, "getMarkerClassName() should throw when label function returnd undefined.");
-  }
-
-  delete TIMELINE_BLUEPRINT["fakemarker"];
-
-  finish();
-}
deleted file mode 100644
--- a/browser/devtools/performance/test/browser_timeline-blueprint.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Tests if the timeline blueprint has a correct structure.
- */
-
-function* spawnTest() {
-  let { TIMELINE_BLUEPRINT } = devtools.require("devtools/performance/markers");
-
-  ok(TIMELINE_BLUEPRINT,
-    "A timeline blueprint should be available.");
-
-  ok(Object.keys(TIMELINE_BLUEPRINT).length,
-    "The timeline blueprint has at least one entry.");
-
-  for (let [key, value] of Iterator(TIMELINE_BLUEPRINT)) {
-    if (key.startsWith("meta::")) {
-      ok(!("group" in value),
-        "No meta entry in the timeline blueprint can contain a `group` key.");
-      ok("colorName" in value,
-        "Each meta entry in the timeline blueprint contains a `colorName` key.");
-      ok("label" in value,
-        "Each meta entry in the timeline blueprint contains a `label` key.");
-    } else {
-      ok("group" in value,
-        "Each entry in the timeline blueprint contains a `group` key.");
-      ok("colorName" in value,
-        "Each entry in the timeline blueprint contains a `colorName` key.");
-      ok("label" in value,
-        "Each entry in the timeline blueprint contains a `label` key.");
-    }
-  }
-}
--- a/browser/devtools/performance/test/browser_timeline-filters.js
+++ b/browser/devtools/performance/test/browser_timeline-filters.js
@@ -1,15 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Tests markers filtering mechanism.
  */
 
+const EPSILON = 0.00000001;
+
 function* spawnTest() {
   let { panel } = yield initPerformance(SIMPLE_URL);
   let { $, $$, EVENTS, PerformanceController, OverviewView, WaterfallView } = panel.panelWin;
   let { TimelineGraph } = devtools.require("devtools/performance/graphs");
   let { rowHeight: MARKERS_GRAPH_ROW_HEIGHT } = TimelineGraph.prototype;
 
   yield startRecording(panel);
   ok(true, "Recording has started.");
@@ -19,66 +21,92 @@ function* spawnTest() {
     let markers = PerformanceController.getCurrentRecording().getMarkers();
     return markers.some(m => m.name == "Styles") &&
            markers.some(m => m.name == "Reflow") &&
            markers.some(m => m.name == "Paint");
   });
 
   yield stopRecording(panel);
 
+  // Push some fake markers of a type we do not have a blueprint for
+  let markers = PerformanceController.getCurrentRecording().getMarkers();
+  let endTime = markers[markers.length - 1].end;
+  markers.push({ name: "CustomMarker", start: endTime + EPSILON, end: endTime + (EPSILON * 2) });
+  markers.push({ name: "CustomMarker", start: endTime + (EPSILON * 3), end: endTime + (EPSILON * 4) });
+
+  // Invalidate marker cache
+  WaterfallView._cache.delete(markers);
+
   // Select everything
-  OverviewView.setTimeInterval({ startTime: 0, endTime: Number.MAX_VALUE })
+  let waterfallRendered = WaterfallView.once(EVENTS.WATERFALL_RENDERED);
+  OverviewView.setTimeInterval({ startTime: 0, endTime: Number.MAX_VALUE });
 
   $("#filter-button").click();
   let menuItem1 = $("menuitem[marker-type=Styles]");
   let menuItem2 = $("menuitem[marker-type=Reflow]");
   let menuItem3 = $("menuitem[marker-type=Paint]");
+  let menuItem4 = $("menuitem[marker-type=UNKNOWN]");
 
   let overview = OverviewView.graphs.get("timeline");
   let originalHeight = overview.fixedHeight;
 
+  yield waterfallRendered;
+
   ok($(".waterfall-marker-bar[type=Styles]"), "Found at least one 'Styles' marker (1)");
   ok($(".waterfall-marker-bar[type=Reflow]"), "Found at least one 'Reflow' marker (1)");
   ok($(".waterfall-marker-bar[type=Paint]"), "Found at least one 'Paint' marker (1)");
+  ok($(".waterfall-marker-bar[type=CustomMarker]"), "Found at least one 'Unknown' marker (1)");
 
   let heightBefore = overview.fixedHeight;
   EventUtils.synthesizeMouseAtCenter(menuItem1, {type: "mouseup"}, panel.panelWin);
   yield waitForOverviewAndCommand(overview, menuItem1);
 
   is(overview.fixedHeight, heightBefore, "Overview height hasn't changed");
   ok(!$(".waterfall-marker-bar[type=Styles]"), "No 'Styles' marker (2)");
   ok($(".waterfall-marker-bar[type=Reflow]"), "Found at least one 'Reflow' marker (2)");
   ok($(".waterfall-marker-bar[type=Paint]"), "Found at least one 'Paint' marker (2)");
+  ok($(".waterfall-marker-bar[type=CustomMarker]"), "Found at least one 'Unknown' marker (2)");
 
   heightBefore = overview.fixedHeight;
   EventUtils.synthesizeMouseAtCenter(menuItem2, {type: "mouseup"}, panel.panelWin);
   yield waitForOverviewAndCommand(overview, menuItem2);
 
   is(overview.fixedHeight, heightBefore, "Overview height hasn't changed");
   ok(!$(".waterfall-marker-bar[type=Styles]"), "No 'Styles' marker (3)");
   ok(!$(".waterfall-marker-bar[type=Reflow]"), "No 'Reflow' marker (3)");
   ok($(".waterfall-marker-bar[type=Paint]"), "Found at least one 'Paint' marker (3)");
+  ok($(".waterfall-marker-bar[type=CustomMarker]"), "Found at least one 'Unknown' marker (3)");
 
   heightBefore = overview.fixedHeight;
   EventUtils.synthesizeMouseAtCenter(menuItem3, {type: "mouseup"}, panel.panelWin);
   yield waitForOverviewAndCommand(overview, menuItem3);
 
   is(overview.fixedHeight, heightBefore - MARKERS_GRAPH_ROW_HEIGHT, "Overview is smaller");
   ok(!$(".waterfall-marker-bar[type=Styles]"), "No 'Styles' marker (4)");
   ok(!$(".waterfall-marker-bar[type=Reflow]"), "No 'Reflow' marker (4)");
   ok(!$(".waterfall-marker-bar[type=Paint]"), "No 'Paint' marker (4)");
+  ok($(".waterfall-marker-bar[type=CustomMarker]"), "Found at least one 'Unknown' marker (4)");
+
+  EventUtils.synthesizeMouseAtCenter(menuItem4, {type: "mouseup"}, panel.panelWin);
+  yield waitForOverviewAndCommand(overview, menuItem4);
+
+  ok(!$(".waterfall-marker-bar[type=Styles]"), "No 'Styles' marker (5)");
+  ok(!$(".waterfall-marker-bar[type=Reflow]"), "No 'Reflow' marker (5)");
+  ok(!$(".waterfall-marker-bar[type=Paint]"), "No 'Paint' marker (5)");
+  ok(!$(".waterfall-marker-bar[type=CustomMarker]"), "No 'Unknown' marker (5)");
 
   for (let item of [menuItem1, menuItem2, menuItem3]) {
     EventUtils.synthesizeMouseAtCenter(item, {type: "mouseup"}, panel.panelWin);
     yield waitForOverviewAndCommand(overview, item);
   }
 
-  ok($(".waterfall-marker-bar[type=Styles]"), "Found at least one 'Styles' marker (5)");
-  ok($(".waterfall-marker-bar[type=Reflow]"), "Found at least one 'Reflow' marker (5)");
-  ok($(".waterfall-marker-bar[type=Paint]"), "Found at least one 'Paint' marker (5)");
+  ok($(".waterfall-marker-bar[type=Styles]"), "Found at least one 'Styles' marker (6)");
+  ok($(".waterfall-marker-bar[type=Reflow]"), "Found at least one 'Reflow' marker (6)");
+  ok($(".waterfall-marker-bar[type=Paint]"), "Found at least one 'Paint' marker (6)");
+  ok(!$(".waterfall-marker-bar[type=CustomMarker]"), "No 'Unknown' marker (6)");
 
   is(overview.fixedHeight, originalHeight, "Overview restored");
 
   yield teardown(panel);
   finish();
 }
 
 function waitForOverviewAndCommand(overview, item) {
--- a/browser/devtools/performance/test/head.js
+++ b/browser/devtools/performance/test/head.js
@@ -56,16 +56,17 @@ let DEFAULT_PREFS = [
   "devtools.performance.ui.enable-allocations",
   "devtools.performance.ui.enable-framerate",
   "devtools.performance.ui.show-jit-optimizations",
   "devtools.performance.memory.sample-probability",
   "devtools.performance.memory.max-log-length",
   "devtools.performance.profiler.buffer-size",
   "devtools.performance.profiler.sample-frequency-khz",
   "devtools.performance.ui.experimental",
+  "devtools.performance.timeline.hidden-markers",
 ].reduce((prefs, pref) => {
   prefs[pref] = Preferences.get(pref);
   return prefs;
 }, {});
 
 // Enable the new performance panel for all tests.
 Services.prefs.setBoolPref("devtools.performance.enabled", true);
 // Enable logging for all the tests. Both the debugger server and frontend will
--- a/browser/devtools/performance/test/unit/head.js
+++ b/browser/devtools/performance/test/unit/head.js
@@ -1,17 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 "use strict";
 
 const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
 
 let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
+let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
 const RecordingUtils = devtools.require("devtools/performance/recording-utils");
 
+const PLATFORM_DATA_PREF = "devtools.performance.ui.show-platform-data";
+
 /**
  * Get a path in a FrameNode call tree.
  */
 function getFrameNodePath(root, path) {
   let calls = root.calls;
   let node;
   for (let key of path.split(" > ")) {
     node = calls.find((node) => node.key == key);
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/test/unit/test_marker-blueprint.js
@@ -0,0 +1,29 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if the timeline blueprint has a correct structure.
+ */
+
+function run_test() {
+  run_next_test();
+}
+
+add_task(function () {
+  let { TIMELINE_BLUEPRINT } = devtools.require("devtools/performance/markers");
+
+  ok(TIMELINE_BLUEPRINT,
+    "A timeline blueprint should be available.");
+
+  ok(Object.keys(TIMELINE_BLUEPRINT).length,
+    "The timeline blueprint has at least one entry.");
+
+  for (let [key, value] of Iterator(TIMELINE_BLUEPRINT)) {
+    ok("group" in value,
+      "Each entry in the timeline blueprint contains a `group` key.");
+    ok("colorName" in value,
+      "Each entry in the timeline blueprint contains a `colorName` key.");
+    ok("label" in value,
+      "Each entry in the timeline blueprint contains a `label` key.");
+  }
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/test/unit/test_marker-utils.js
@@ -0,0 +1,88 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests the marker utils methods.
+ */
+
+function run_test() {
+  run_next_test();
+}
+
+add_task(function () {
+  let { TIMELINE_BLUEPRINT } = devtools.require("devtools/performance/markers");
+  let Utils = devtools.require("devtools/performance/marker-utils");
+
+  Services.prefs.setBoolPref(PLATFORM_DATA_PREF, false);
+
+  equal(Utils.getMarkerLabel({ name: "DOMEvent" }), "DOM Event",
+    "getMarkerLabel() returns a simple label");
+  equal(Utils.getMarkerLabel({ name: "Javascript", causeName: "setTimeout handler" }), "setTimeout",
+    "getMarkerLabel() returns a label defined via function");
+
+  ok(Utils.getMarkerFields({ name: "Paint" }).length === 0,
+    "getMarkerFields() returns an empty array when no fields defined");
+
+  let fields = Utils.getMarkerFields({ name: "ConsoleTime", causeName: "snowstorm" });
+  equal(fields[0].label, "Timer Name:", "getMarkerFields() returns an array with proper label");
+  equal(fields[0].value, "snowstorm", "getMarkerFields() returns an array with proper value");
+
+  fields = Utils.getMarkerFields({ name: "DOMEvent", type: "mouseclick" });
+  equal(fields.length, 1, "getMarkerFields() ignores fields that are not found on marker");
+  equal(fields[0].label, "Event Type:", "getMarkerFields() returns an array with proper label");
+  equal(fields[0].value, "mouseclick", "getMarkerFields() returns an array with proper value");
+
+  fields = Utils.getMarkerFields({ name: "DOMEvent", eventPhase: Ci.nsIDOMEvent.AT_TARGET, type: "mouseclick" });
+  equal(fields.length, 2, "getMarkerFields() returns multiple fields when using a fields function");
+  equal(fields[0].label, "Event Type:", "getMarkerFields() correctly returns fields via function (1)");
+  equal(fields[0].value, "mouseclick", "getMarkerFields() correctly returns fields via function (2)");
+  equal(fields[1].label, "Phase:", "getMarkerFields() correctly returns fields via function (3)");
+  equal(fields[1].value, "Target", "getMarkerFields() correctly returns fields via function (4)");
+
+  equal(Utils.getMarkerFields({ name: "Javascript", causeName: "Some Platform Field" })[0].value, "(Gecko)",
+    "Correctly obfuscates JS markers when platform data is off.");
+  Services.prefs.setBoolPref(PLATFORM_DATA_PREF, true);
+  equal(Utils.getMarkerFields({ name: "Javascript", causeName: "Some Platform Field" })[0].value, "Some Platform Field",
+    "Correctly deobfuscates JS markers when platform data is on.");
+
+  equal(Utils.getMarkerClassName("Javascript"), "Function Call",
+    "getMarkerClassName() returns correct string when defined via function");
+  equal(Utils.getMarkerClassName("GarbageCollection"), "GC Event",
+    "getMarkerClassName() returns correct string when defined via function");
+  equal(Utils.getMarkerClassName("Reflow"), "Layout",
+    "getMarkerClassName() returns correct string when defined via string");
+
+  TIMELINE_BLUEPRINT["fakemarker"] = { group: 0 };
+  try {
+    Utils.getMarkerClassName("fakemarker");
+    ok(false, "getMarkerClassName() should throw when no label on blueprint.");
+  } catch (e) {
+    ok(true, "getMarkerClassName() should throw when no label on blueprint.");
+  }
+
+  TIMELINE_BLUEPRINT["fakemarker"] = { group: 0, label: () => void 0};
+  try {
+    Utils.getMarkerClassName("fakemarker");
+    ok(false, "getMarkerClassName() should throw when label function returnd undefined.");
+  } catch (e) {
+    ok(true, "getMarkerClassName() should throw when label function returnd undefined.");
+  }
+
+  delete TIMELINE_BLUEPRINT["fakemarker"];
+
+  let customBlueprint = {
+    UNKNOWN: {
+      group: 1,
+      label: "MyDefault"
+    },
+    custom: {
+      group: 0,
+      label: "MyCustom"
+    }
+  };
+
+  equal(Utils.getBlueprintFor({ name: "Reflow" }).label, "Layout",
+    "Utils.getBlueprintFor() should return marker def for passed in marker.");
+  equal(Utils.getBlueprintFor({ name: "Not sure!" }).label(), "Unknown",
+    "Utils.getBlueprintFor() should return a default marker def if the marker is undefined.");
+});
--- a/browser/devtools/performance/test/unit/xpcshell.ini
+++ b/browser/devtools/performance/test/unit/xpcshell.ini
@@ -1,18 +1,20 @@
 [DEFAULT]
 tags = devtools
 head = head.js
 tail =
 firefox-appdir = browser
 skip-if = toolkit == 'android' || toolkit == 'gonk'
 
-[test_profiler-categories.js]
 [test_frame-utils-01.js]
 [test_frame-utils-02.js]
+[test_marker-blueprint.js]
+[test_marker-utils.js]
+[test_profiler-categories.js]
 [test_tree-model-01.js]
 [test_tree-model-02.js]
 [test_tree-model-03.js]
 [test_tree-model-04.js]
 [test_tree-model-05.js]
 [test_tree-model-06.js]
 [test_tree-model-07.js]
 [test_tree-model-08.js]
--- a/browser/devtools/performance/views/details-waterfall.js
+++ b/browser/devtools/performance/views/details-waterfall.js
@@ -27,16 +27,17 @@ let WaterfallView = Heritage.extend(Deta
   initialize: function () {
     DetailsSubview.initialize.call(this);
 
     this._cache = new WeakMap();
 
     this._onMarkerSelected = this._onMarkerSelected.bind(this);
     this._onResize = this._onResize.bind(this);
     this._onViewSource = this._onViewSource.bind(this);
+    this._hiddenMarkers = PerformanceController.getPref("hidden-markers");
 
     this.headerContainer = $("#waterfall-header");
     this.breakdownContainer = $("#waterfall-breakdown");
     this.detailsContainer = $("#waterfall-details");
     this.detailsSplitter = $("#waterfall-view > splitter");
 
     this.details = new MarkerDetails($("#waterfall-details"), $("#waterfall-view > splitter"));
     this.details.hidden = true;
@@ -106,18 +107,17 @@ let WaterfallView = Heritage.extend(Deta
       this.render(OverviewView.getTimeInterval());
     });
   },
 
   /**
    * Called whenever an observed pref is changed.
    */
   _onObservedPrefChange: function(_, prefName) {
-    let blueprint = PerformanceController.getTimelineBlueprint();
-    this._markersRoot.blueprint = blueprint;
+    this._hiddenMarkers = PerformanceController.getPref("hidden-markers");
   },
 
   /**
    * Called when MarkerDetails view emits an event to view source.
    */
   _onViewSource: function (_, file, line) {
     gToolbox.viewSourceInDebugger(file, line);
   },
@@ -131,17 +131,17 @@ let WaterfallView = Heritage.extend(Deta
     if (cached) {
       return cached;
     }
 
     let rootMarkerNode = WaterfallUtils.makeParentMarkerNode({ name: "(root)" });
 
     WaterfallUtils.collapseMarkersIntoNode({
       markerNode: rootMarkerNode,
-      markersList: markers
+      markersList: markers,
     });
 
     this._cache.set(markers, rootMarkerNode);
     return rootMarkerNode;
   },
 
   /**
    * Renders the waterfall tree.
@@ -155,18 +155,17 @@ let WaterfallView = Heritage.extend(Deta
       autoExpandDepth: 0
     });
 
     let header = new WaterfallHeader(root);
 
     this._markersRoot = root;
     this._waterfallHeader = header;
 
-    let blueprint = PerformanceController.getTimelineBlueprint();
-    root.blueprint = blueprint;
+    root.filter = this._hiddenMarkers;
     root.interval = interval;
     root.on("selected", this._onMarkerSelected);
     root.on("unselected", this._onMarkerSelected);
 
     this.breakdownContainer.innerHTML = "";
     root.attachTo(this.breakdownContainer);
 
     this.headerContainer.innerHTML = "";
--- a/browser/devtools/performance/views/overview.js
+++ b/browser/devtools/performance/views/overview.js
@@ -37,17 +37,17 @@ let OverviewView = {
   OVERVIEW_UPDATE_INTERVAL: OVERVIEW_UPDATE_INTERVAL,
 
   /**
    * Sets up the view with event binding.
    */
   initialize: function () {
     this.graphs = new GraphsController({
       root: $("#overview-pane"),
-      getBlueprint: () => PerformanceController.getTimelineBlueprint(),
+      getFilter: () => PerformanceController.getPref("hidden-markers"),
       getTheme: () => PerformanceController.getTheme(),
     });
 
     // If no timeline support, shut it all down.
     if (!gFront.getActorSupport().timeline) {
       this.disable();
       return;
     }
@@ -326,18 +326,18 @@ let OverviewView = {
    * because those will set values on a recording model, and
    * the graphs will render based on the existence.
    */
   _onPrefChanged: Task.async(function* (_, prefName, prefValue) {
     switch (prefName) {
       case "hidden-markers": {
         let graph;
         if (graph = yield this.graphs.isAvailable("timeline")) {
-          let blueprint = PerformanceController.getTimelineBlueprint();
-          graph.setBlueprint(blueprint);
+          let filter = PerformanceController.getPref("hidden-markers");
+          graph.setFilter(filter);
           graph.refresh({ force: true });
         }
         break;
       }
     }
   }),
 
   _setGraphVisibilityFromRecordingFeatures: function (recording) {
--- a/browser/locales/en-US/chrome/browser/devtools/animationinspector.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/animationinspector.properties
@@ -47,8 +47,14 @@ player.infiniteIterationCount=&#8734;
 # time (in seconds too);
 player.timeLabel=%Ss
 
 # LOCALIZATION NOTE (player.playbackRateLabel):
 # This string is displayed in each animation player widget, as the label of
 # drop-down list items that can be used to change the rate at which the
 # animation runs (1x being the default, 2x being twice as fast).
 player.playbackRateLabel=%Sx
+
+# LOCALIZATION NOTE (timeline.timeGraduationLabel):
+# This string is displayed at the top of the animation panel, next to each time
+# graduation, to indicate what duration (in milliseconds) this graduation
+# corresponds to.
+timeline.timeGraduationLabel=%Sms
--- a/browser/locales/en-US/chrome/browser/devtools/timeline.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/timeline.properties
@@ -41,16 +41,17 @@ timeline.label.reflow2=Layout
 timeline.label.paint=Paint
 timeline.label.javascript2=Function Call
 timeline.label.parseHTML=Parse HTML
 timeline.label.parseXML=Parse XML
 timeline.label.domevent=DOM Event
 timeline.label.consoleTime=Console
 timeline.label.garbageCollection=GC Event
 timeline.label.timestamp=Timestamp
+timeline.label.unknown=Unknown
 
 # LOCALIZATION NOTE (graphs.memory):
 # This string is displayed in the memory graph of the Performance tool,
 # as the unit used to memory consumption. This label should be kept
 # AS SHORT AS POSSIBLE so it doesn't obstruct important parts of the graph.
 graphs.memory=MB
 
 # LOCALIZATION NOTE (timeline.markerDetailFormat):
--- a/browser/themes/shared/devtools/animationinspector.css
+++ b/browser/themes/shared/devtools/animationinspector.css
@@ -1,8 +1,22 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Animation-inspector specific theme variables */
+
+.theme-dark {
+  --even-animation-timeline-background-color: rgba(255,255,255,0.03);
+}
+
+.theme-light {
+  --even-animation-timeline-background-color: rgba(128,128,128,0.03);
+}
+
 html {
   height: 100%;
 }
 
 body {
   margin: 0;
   padding: 0;
   display : flex;
@@ -27,34 +41,35 @@ body {
   padding: 1px 4px;
 }
 
 #toggle-all {
   border-width: 0 0 0 1px;
   min-height: 20px;
 }
 
+/* The main animations container */
+
+#players {
+  height: calc(100% - 20px);
+  overflow: auto;
+}
+
 /* The error message, shown when an invalid/unanimated element is selected */
 
 #error-message {
   padding-top: 10%;
   text-align: center;
   flex: 1;
   overflow: auto;
 
   /* The error message is hidden by default */
   display: none;
 }
 
-/* The animation players container */
-
-#players {
-  flex: 1;
-  overflow: auto;
-}
 
 /* Element picker and toggle-all buttons */
 
 #element-picker,
 #toggle-all {
   position: relative;
 }
 
@@ -94,16 +109,166 @@ body {
     background-image: url("debugger-pause@2x.png");
   }
 
   #toggle-all.paused::before {
     background-image: url("debugger-play@2x.png");
   }
 }
 
+/* Animation timeline component */
+
+.animation-timeline {
+  height: 100%;
+  overflow: hidden;
+  /* The timeline gets its background-image from a canvas element created in
+     /browser/devtools/animationinspector/utils.js drawGraphElementBackground
+     thanks to document.mozSetImageElement("time-graduations", canvas)
+     This is done so that the background can be built dynamically from script */
+  background-image: -moz-element(#time-graduations);
+  background-repeat: repeat-y;
+  /* The animations are drawn 150px from the left edge so that animated nodes
+     can be displayed in a sidebar */
+  background-position: 150px 0;
+  display: flex;
+  flex-direction: column;
+}
+
+.animation-timeline .time-header {
+  margin-left: 150px;
+  height: 20px;
+  overflow: hidden;
+  position: relative;
+  border-bottom: 1px solid var(--theme-splitter-color);
+}
+
+.animation-timeline .time-header .time-tick {
+  position: absolute;
+  top: 3px;
+}
+
+.animation-timeline .animations {
+  width: 100%;
+  overflow-y: auto;
+  overflow-x: hidden;
+  margin: 0;
+  padding: 0;
+  list-style-type: none;
+}
+
+/* Animation block widgets */
+
+.animation-timeline .animation {
+  margin: 4px 0;
+  height: 20px;
+  position: relative;
+}
+
+.animation-timeline .animation:nth-child(2n) {
+  background-color: var(--even-animation-timeline-background-color);
+}
+
+.animation-timeline .animation .target {
+  width: 150px;
+  overflow: hidden;
+  height: 100%;
+}
+
+.animation-timeline .animation-target {
+  background-color: transparent;
+}
+
+.animation-timeline .animation .time-block {
+  position: absolute;
+  top: 0;
+  left: 150px;
+  right: 0;
+  height: 100%;
+}
+
+/* Animation iterations */
+
+.animation-timeline .animation .iterations {
+  position: relative;
+  height: 100%;
+  border: 1px solid var(--theme-highlight-lightorange);
+  box-sizing: border-box;
+  background: var(--theme-contrast-background);
+  /* Iterations are displayed with a repeating linear-gradient which size is
+     dynamically changed from JS */
+  background-image:
+    linear-gradient(to right,
+                    var(--theme-highlight-lightorange) 0,
+                    var(--theme-highlight-lightorange) 1px,
+                    transparent 1px,
+                    transparent 2px);
+  background-repeat: repeat-x;
+  background-position: -1px 0;
+}
+
+.animation-timeline .animation .iterations.infinite {
+  border-right-width: 0;
+}
+
+.animation-timeline .animation .iterations.infinite::before,
+.animation-timeline .animation .iterations.infinite::after {
+  content: "";
+  position: absolute;
+  top: 0;
+  right: 0;
+  width: 0;
+  height: 0;
+  border-right: 4px solid var(--theme-body-background);
+  border-top: 4px solid transparent;
+  border-bottom: 4px solid transparent;
+}
+
+.animation-timeline .animation .iterations.infinite::after {
+  bottom: 0;
+  top: unset;
+}
+
+.animation-timeline .animation .animation-title {
+  height: 1.5em;
+  width: 100%;
+  box-sizing: border-box;
+  overflow: hidden;
+}
+
+.animation-timeline .animation .delay {
+  position: absolute;
+  top: 0;
+  height: 100%;
+  background-image: linear-gradient(to bottom,
+                                    transparent,
+                                    transparent 9px,
+                                    var(--theme-highlight-lightorange) 9px,
+                                    var(--theme-highlight-lightorange) 11px,
+                                    transparent 11px,
+                                    transparent);
+}
+
+.animation-timeline .animation .delay::before {
+  position: absolute;
+  content: "";
+  left: 0;
+  width: 2px;
+  height: 8px;
+  top: 50%;
+  margin-top: -4px;
+  background: var(--theme-highlight-lightorange);
+}
+
+.animation-timeline .animation .name {
+  position: absolute;
+  z-index: 1;
+  padding: 2px;
+  white-space: nowrap;
+}
+
 /* Animation target node gutter, contains a preview of the dom node */
 
 .animation-target {
   background-color: var(--theme-toolbar-background);
   padding: 1px 4px;
   box-sizing: border-box;
   overflow: hidden;
   text-overflow: ellipsis;
@@ -248,9 +413,9 @@ body {
 
 .timeline .time-display {
   display: flex;
   align-items: center;
   justify-content: center;
   width: 50px;
   border-left: 1px solid var(--theme-splitter-color);
   background: var(--theme-toolbar-background);
-}
+}
\ No newline at end of file
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -1497,16 +1497,23 @@ richlistitem[type~="action"][actiontype=
 
 @media (-moz-os-version: windows-xp) and (-moz-windows-default-theme) {
   .ac-url-text:not([selected="true"]),
   .ac-action-text:not([selected="true"]) {
     color: #008800;
   }
 }
 
+@media (-moz-os-version: windows-win10) and (-moz-windows-default-theme) {
+  .ac-url-text:not([selected="true"]),
+  .ac-action-text:not([selected="true"]) {
+    color: Highlight;
+  }
+}
+
 richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon {
   list-style-image: url("chrome://browser/skin/actionicon-tab.png");
   -moz-image-region: rect(0, 16px, 11px, 0);
   padding: 0 3px;
 }
 
 @media not all and (-moz-os-version: windows-vista),
        not all and (-moz-windows-default-theme) {
--- a/dom/base/nsCCUncollectableMarker.cpp
+++ b/dom/base/nsCCUncollectableMarker.cpp
@@ -427,17 +427,17 @@ nsCCUncollectableMarker::Observe(nsISupp
     sFSState = eInitial;
     return NS_OK;
   } else {
     ++sFSState;
   }
 
   switch(sFSState) {
     case eUnmarkJSEventListeners: {
-      nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments(sGeneration);
+      nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments();
       break;
     }
     case eUnmarkMessageManagers: {
       MarkMessageManagers();
       break;
     }
     case eUnmarkStrongObservers: {
       nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -3980,39 +3980,32 @@ nsContentUtils::MaybeFireNodeRemoved(nsI
     InternalMutationEvent mutation(true, NS_MUTATION_NODEREMOVED);
     mutation.mRelatedNode = do_QueryInterface(aParent);
 
     mozAutoSubtreeModified subtree(aOwnerDoc, aParent);
     EventDispatcher::Dispatch(aChild, nullptr, &mutation);
   }
 }
 
-PLDHashOperator
-ListenerEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aEntry,
-                   uint32_t aNumber, void* aArg)
-{
-  EventListenerManagerMapEntry* entry =
-    static_cast<EventListenerManagerMapEntry*>(aEntry);
-  if (entry) {
+void
+nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments()
+{
+  if (!sEventListenerManagersHash) {
+    return;
+  }
+
+  PLDHashTable::Iterator iter(sEventListenerManagersHash);
+  while (iter.HasMoreEntries()) {
+    auto entry = static_cast<EventListenerManagerMapEntry*>(iter.NextEntry());
     nsINode* n = static_cast<nsINode*>(entry->mListenerManager->GetTarget());
     if (n && n->IsInDoc() &&
         nsCCUncollectableMarker::InGeneration(n->OwnerDoc()->GetMarkedCCGeneration())) {
       entry->mListenerManager->MarkForCC();
     }
   }
-  return PL_DHASH_NEXT;
-}
-
-void
-nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments(uint32_t aGeneration)
-{
-  if (sEventListenerManagersHash) {
-    PL_DHashTableEnumerate(sEventListenerManagersHash, ListenerEnumerator,
-                           &aGeneration);
-  }
 }
 
 /* static */
 void
 nsContentUtils::TraverseListenerManager(nsINode *aNode,
                                         nsCycleCollectionTraversalCallback &cb)
 {
   if (!sEventListenerManagersHash) {
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -1119,17 +1119,17 @@ public:
    * Get the eventlistener manager for aNode, returning null if it does not
    * already exist.
    *
    * @param aNode The node for which to get the eventlistener manager.
    */
   static mozilla::EventListenerManager*
     GetExistingListenerManagerForNode(const nsINode* aNode);
 
-  static void UnmarkGrayJSListenersInCCGenerationDocuments(uint32_t aGeneration);
+  static void UnmarkGrayJSListenersInCCGenerationDocuments();
 
   /**
    * Remove the eventlistener manager for aNode.
    *
    * @param aNode The node for which to remove the eventlistener manager.
    */
   static void RemoveListenerManager(nsINode *aNode);
 
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -529,17 +529,17 @@ AllocateProtoAndIfaceCache(JSObject* obj
 struct VerifyTraceProtoAndIfaceCacheCalledTracer : public JS::CallbackTracer
 {
   bool ok;
 
   explicit VerifyTraceProtoAndIfaceCacheCalledTracer(JSRuntime *rt)
     : JS::CallbackTracer(rt), ok(false)
   {}
 
-  void trace(void** thingp, JS::TraceKind kind) override {
+  void onChild(const JS::GCCellPtr&) override {
     // We don't do anything here, we only want to verify that
     // TraceProtoAndIfaceCache was called.
   }
 
   TracerKind getTracerKind() const override { return TracerKind::VerifyTraceProtoAndIface; }
 };
 #endif
 
--- a/dom/bindings/TypedArray.h
+++ b/dom/bindings/TypedArray.h
@@ -218,16 +218,49 @@ typedef TypedArray<double, js::UnwrapFlo
                    js::GetFloat64ArrayLengthAndData, JS_NewFloat64Array>
         Float64Array;
 typedef TypedArray_base<uint8_t, js::UnwrapArrayBufferView, js::GetArrayBufferViewLengthAndData>
         ArrayBufferView;
 typedef TypedArray<uint8_t, js::UnwrapArrayBuffer, JS_GetArrayBufferData,
                    js::GetArrayBufferLengthAndData, JS_NewArrayBuffer>
         ArrayBuffer;
 
+typedef TypedArray<int8_t, js::UnwrapSharedInt8Array, JS_GetSharedInt8ArrayData,
+                   js::GetSharedInt8ArrayLengthAndData, JS_NewSharedInt8Array>
+        SharedInt8Array;
+typedef TypedArray<uint8_t, js::UnwrapSharedUint8Array, JS_GetSharedUint8ArrayData,
+                   js::GetSharedUint8ArrayLengthAndData, JS_NewSharedUint8Array>
+        SharedUint8Array;
+typedef TypedArray<uint8_t, js::UnwrapSharedUint8ClampedArray, JS_GetSharedUint8ClampedArrayData,
+                   js::GetSharedUint8ClampedArrayLengthAndData, JS_NewSharedUint8ClampedArray>
+        SharedUint8ClampedArray;
+typedef TypedArray<int16_t, js::UnwrapSharedInt16Array, JS_GetSharedInt16ArrayData,
+                   js::GetSharedInt16ArrayLengthAndData, JS_NewSharedInt16Array>
+        SharedInt16Array;
+typedef TypedArray<uint16_t, js::UnwrapSharedUint16Array, JS_GetSharedUint16ArrayData,
+                   js::GetSharedUint16ArrayLengthAndData, JS_NewSharedUint16Array>
+        SharedUint16Array;
+typedef TypedArray<int32_t, js::UnwrapSharedInt32Array, JS_GetSharedInt32ArrayData,
+                   js::GetSharedInt32ArrayLengthAndData, JS_NewSharedInt32Array>
+        SharedInt32Array;
+typedef TypedArray<uint32_t, js::UnwrapSharedUint32Array, JS_GetSharedUint32ArrayData,
+                   js::GetSharedUint32ArrayLengthAndData, JS_NewSharedUint32Array>
+        SharedUint32Array;
+typedef TypedArray<float, js::UnwrapSharedFloat32Array, JS_GetSharedFloat32ArrayData,
+                   js::GetSharedFloat32ArrayLengthAndData, JS_NewSharedFloat32Array>
+        SharedFloat32Array;
+typedef TypedArray<double, js::UnwrapSharedFloat64Array, JS_GetSharedFloat64ArrayData,
+                   js::GetSharedFloat64ArrayLengthAndData, JS_NewSharedFloat64Array>
+        SharedFloat64Array;
+typedef TypedArray_base<uint8_t, js::UnwrapSharedArrayBufferView, js::GetSharedArrayBufferViewLengthAndData>
+        SharedArrayBufferView;
+typedef TypedArray<uint8_t, js::UnwrapSharedArrayBuffer, JS_GetSharedArrayBufferData,
+                   js::GetSharedArrayBufferLengthAndData, JS_NewSharedArrayBuffer>
+        SharedArrayBuffer;
+
 // A class for converting an nsTArray to a TypedArray
 // Note: A TypedArrayCreator must not outlive the nsTArray it was created from.
 //       So this is best used to pass from things that understand nsTArray to
 //       things that understand TypedArray, as with Promise::ArgumentToJSValue.
 template<typename TypedArrayType>
 class TypedArrayCreator
 {
   typedef nsTArray<typename TypedArrayType::element_type> ArrayType;
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -1724,19 +1724,28 @@ class IDLType(IDLObject):
         return False
 
     def isArrayBuffer(self):
         return False
 
     def isArrayBufferView(self):
         return False
 
+    def isSharedArrayBuffer(self):
+        return False
+
+    def isSharedArrayBufferView(self):
+        return False
+
     def isTypedArray(self):
         return False
 
+    def isSharedTypedArray(self):
+        return False
+
     def isCallbackInterface(self):
         return False
 
     def isNonCallbackInterface(self):
         return False
 
     def isGeckoInterface(self):
         """ Returns a boolean indicating whether this type is an 'interface'
@@ -1746,17 +1755,20 @@ class IDLType(IDLObject):
         return self.isInterface() and not self.isSpiderMonkeyInterface()
 
     def isSpiderMonkeyInterface(self):
         """ Returns a boolean indicating whether this type is an 'interface'
             type that is implemented in Spidermonkey.  At the moment, this
             only returns true for the types from the TypedArray spec. """
         return self.isInterface() and (self.isArrayBuffer() or \
                                        self.isArrayBufferView() or \
-                                       self.isTypedArray())
+                                       self.isSharedArrayBuffer() or \
+                                       self.isSharedArrayBufferView() or \
+                                       self.isTypedArray() or \
+                                       self.isSharedTypedArray())
 
     def isDictionary(self):
         return False
 
     def isInterface(self):
         return False
 
     def isAny(self):
@@ -1928,19 +1940,28 @@ class IDLNullableType(IDLType):
         return self.inner.isArray()
 
     def isArrayBuffer(self):
         return self.inner.isArrayBuffer()
 
     def isArrayBufferView(self):
         return self.inner.isArrayBufferView()
 
+    def isSharedArrayBuffer(self):
+        return self.inner.isSharedArrayBuffer()
+
+    def isSharedArrayBufferView(self):
+        return self.inner.isSharedArrayBufferView()
+
     def isTypedArray(self):
         return self.inner.isTypedArray()
 
+    def isSharedTypedArray(self):
+        return self.inner.isSharedTypedArray()
+
     def isDictionary(self):
         return self.inner.isDictionary()
 
     def isInterface(self):
         return self.inner.isInterface()
 
     def isCallbackInterface(self):
         return self.inner.isCallbackInterface()
@@ -2419,19 +2440,28 @@ class IDLTypedefType(IDLType):
         return self.inner.isDictionary()
 
     def isArrayBuffer(self):
         return self.inner.isArrayBuffer()
 
     def isArrayBufferView(self):
         return self.inner.isArrayBufferView()
 
+    def isSharedArrayBuffer(self):
+        return self.inner.isSharedArrayBuffer()
+
+    def isSharedArrayBufferView(self):
+        return self.inner.isSharedArrayBufferView()
+
     def isTypedArray(self):
         return self.inner.isTypedArray()
 
+    def isSharedTypedArray(self):
+        return self.inner.isSharedTypedArray()
+
     def isInterface(self):
         return self.inner.isInterface()
 
     def isCallbackInterface(self):
         return self.inner.isCallbackInterface()
 
     def isNonCallbackInterface(self):
         return self.inner.isNonCallbackInterface()
@@ -2679,25 +2709,36 @@ class IDLBuiltinType(IDLType):
         'bytestring',
         'usvstring',
         'object',
         'date',
         'void',
         # Funny stuff
         'ArrayBuffer',
         'ArrayBufferView',
+        'SharedArrayBuffer',
+        'SharedArrayBufferView',
         'Int8Array',
         'Uint8Array',
         'Uint8ClampedArray',
         'Int16Array',
         'Uint16Array',
         'Int32Array',
         'Uint32Array',
         'Float32Array',
-        'Float64Array'
+        'Float64Array',
+        'SharedInt8Array',
+        'SharedUint8Array',
+        'SharedUint8ClampedArray',
+        'SharedInt16Array',
+        'SharedUint16Array',
+        'SharedInt32Array',
+        'SharedUint32Array',
+        'SharedFloat32Array',
+        'SharedFloat64Array'
         )
 
     TagLookup = {
             Types.byte: IDLType.Tags.int8,
             Types.octet: IDLType.Tags.uint8,
             Types.short: IDLType.Tags.int16,
             Types.unsigned_short: IDLType.Tags.uint16,
             Types.long: IDLType.Tags.int32,
@@ -2713,25 +2754,36 @@ class IDLBuiltinType(IDLType):
             Types.domstring: IDLType.Tags.domstring,
             Types.bytestring: IDLType.Tags.bytestring,
             Types.usvstring: IDLType.Tags.usvstring,
             Types.object: IDLType.Tags.object,
             Types.date: IDLType.Tags.date,
             Types.void: IDLType.Tags.void,
             Types.ArrayBuffer: IDLType.Tags.interface,
             Types.ArrayBufferView: IDLType.Tags.interface,
+            Types.SharedArrayBuffer: IDLType.Tags.interface,
+            Types.SharedArrayBufferView: IDLType.Tags.interface,
             Types.Int8Array: IDLType.Tags.interface,
             Types.Uint8Array: IDLType.Tags.interface,
             Types.Uint8ClampedArray: IDLType.Tags.interface,
             Types.Int16Array: IDLType.Tags.interface,
             Types.Uint16Array: IDLType.Tags.interface,
             Types.Int32Array: IDLType.Tags.interface,
             Types.Uint32Array: IDLType.Tags.interface,
             Types.Float32Array: IDLType.Tags.interface,
-            Types.Float64Array: IDLType.Tags.interface
+            Types.Float64Array: IDLType.Tags.interface,
+            Types.SharedInt8Array: IDLType.Tags.interface,
+            Types.SharedUint8Array: IDLType.Tags.interface,
+            Types.SharedUint8ClampedArray: IDLType.Tags.interface,
+            Types.SharedInt16Array: IDLType.Tags.interface,
+            Types.SharedUint16Array: IDLType.Tags.interface,
+            Types.SharedInt32Array: IDLType.Tags.interface,
+            Types.SharedUint32Array: IDLType.Tags.interface,
+            Types.SharedFloat32Array: IDLType.Tags.interface,
+            Types.SharedFloat64Array: IDLType.Tags.interface
         }
 
     def __init__(self, location, name, type):
         IDLType.__init__(self, location, name)
         self.builtin = True
         self._typeTag = type
 
     def isPrimitive(self):
@@ -2761,27 +2813,40 @@ class IDLBuiltinType(IDLType):
         return self._typeTag <= IDLBuiltinType.Types.unsigned_long_long
 
     def isArrayBuffer(self):
         return self._typeTag == IDLBuiltinType.Types.ArrayBuffer
 
     def isArrayBufferView(self):
         return self._typeTag == IDLBuiltinType.Types.ArrayBufferView
 
+    def isSharedArrayBuffer(self):
+        return self._typeTag == IDLBuiltinType.Types.SharedArrayBuffer
+
+    def isSharedArrayBufferView(self):
+        return self._typeTag == IDLBuiltinType.Types.SharedArrayBufferView
+
     def isTypedArray(self):
         return self._typeTag >= IDLBuiltinType.Types.Int8Array and \
                self._typeTag <= IDLBuiltinType.Types.Float64Array
 
+    def isSharedTypedArray(self):
+        return self._typeTag >= IDLBuiltinType.Types.SharedInt8Array and \
+               self._typeTag <= IDLBuiltinType.Types.SharedFloat64Array
+
     def isInterface(self):
         # TypedArray things are interface types per the TypedArray spec,
         # but we handle them as builtins because SpiderMonkey implements
         # all of it internally.
         return self.isArrayBuffer() or \
                self.isArrayBufferView() or \
-               self.isTypedArray()
+               self.isSharedArrayBuffer() or \
+               self.isSharedArrayBufferView() or \
+               self.isTypedArray() or \
+               self.isSharedTypedArray()
 
     def isNonCallbackInterface(self):
         # All the interfaces we can be are non-callback
         return self.isInterface()
 
     def isFloat(self):
         return self._typeTag == IDLBuiltinType.Types.float or \
                self._typeTag == IDLBuiltinType.Types.double or \
@@ -2842,25 +2907,30 @@ class IDLBuiltinType(IDLType):
         return (other.isPrimitive() or other.isString() or other.isEnum() or
                 other.isCallback() or other.isDictionary() or
                 other.isSequence() or other.isMozMap() or other.isArray() or
                 other.isDate() or
                 (other.isInterface() and (
                  # ArrayBuffer is distinguishable from everything
                  # that's not an ArrayBuffer or a callback interface
                  (self.isArrayBuffer() and not other.isArrayBuffer()) or
+                 (self.isSharedArrayBuffer() and not other.isSharedArrayBuffer()) or
                  # ArrayBufferView is distinguishable from everything
                  # that's not an ArrayBufferView or typed array.
                  (self.isArrayBufferView() and not other.isArrayBufferView() and
                   not other.isTypedArray()) or
+                 (self.isSharedArrayBufferView() and not other.isSharedArrayBufferView() and
+                  not other.isSharedTypedArray()) or
                  # Typed arrays are distinguishable from everything
                  # except ArrayBufferView and the same type of typed
                  # array
                  (self.isTypedArray() and not other.isArrayBufferView() and not
-                  (other.isTypedArray() and other.name == self.name)))))
+                  (other.isTypedArray() and other.name == self.name)) or
+                 (self.isSharedTypedArray() and not other.isSharedArrayBufferView() and not
+                  (other.isSharedTypedArray() and other.name == self.name)))))
 
     def _getDependentObjects(self):
         return set()
 
 BuiltinTypes = {
       IDLBuiltinType.Types.byte:
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "Byte",
                          IDLBuiltinType.Types.byte),
@@ -2922,16 +2992,22 @@ BuiltinTypes = {
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "Void",
                          IDLBuiltinType.Types.void),
       IDLBuiltinType.Types.ArrayBuffer:
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "ArrayBuffer",
                          IDLBuiltinType.Types.ArrayBuffer),
       IDLBuiltinType.Types.ArrayBufferView:
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "ArrayBufferView",
                          IDLBuiltinType.Types.ArrayBufferView),
+      IDLBuiltinType.Types.SharedArrayBuffer:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedArrayBuffer",
+                         IDLBuiltinType.Types.SharedArrayBuffer),
+      IDLBuiltinType.Types.SharedArrayBufferView:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedArrayBufferView",
+                         IDLBuiltinType.Types.SharedArrayBufferView),
       IDLBuiltinType.Types.Int8Array:
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "Int8Array",
                          IDLBuiltinType.Types.Int8Array),
       IDLBuiltinType.Types.Uint8Array:
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "Uint8Array",
                          IDLBuiltinType.Types.Uint8Array),
       IDLBuiltinType.Types.Uint8ClampedArray:
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "Uint8ClampedArray",
@@ -2948,17 +3024,44 @@ BuiltinTypes = {
       IDLBuiltinType.Types.Uint32Array:
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "Uint32Array",
                          IDLBuiltinType.Types.Uint32Array),
       IDLBuiltinType.Types.Float32Array:
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "Float32Array",
                          IDLBuiltinType.Types.Float32Array),
       IDLBuiltinType.Types.Float64Array:
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "Float64Array",
-                         IDLBuiltinType.Types.Float64Array)
+                         IDLBuiltinType.Types.Float64Array),
+      IDLBuiltinType.Types.SharedInt8Array:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedInt8Array",
+                         IDLBuiltinType.Types.SharedInt8Array),
+      IDLBuiltinType.Types.SharedUint8Array:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedUint8Array",
+                         IDLBuiltinType.Types.SharedUint8Array),
+      IDLBuiltinType.Types.SharedUint8ClampedArray:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedUint8ClampedArray",
+                         IDLBuiltinType.Types.SharedUint8ClampedArray),
+      IDLBuiltinType.Types.SharedInt16Array:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedInt16Array",
+                         IDLBuiltinType.Types.SharedInt16Array),
+      IDLBuiltinType.Types.SharedUint16Array:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedUint16Array",
+                         IDLBuiltinType.Types.SharedUint16Array),
+      IDLBuiltinType.Types.SharedInt32Array:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedInt32Array",
+                         IDLBuiltinType.Types.SharedInt32Array),
+      IDLBuiltinType.Types.SharedUint32Array:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedUint32Array",
+                         IDLBuiltinType.Types.SharedUint32Array),
+      IDLBuiltinType.Types.SharedFloat32Array:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedFloat32Array",
+                         IDLBuiltinType.Types.SharedFloat32Array),
+      IDLBuiltinType.Types.SharedFloat64Array:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "SharedFloat64Array",
+                         IDLBuiltinType.Types.SharedFloat64Array)
     }
 
 
 integerTypeSizes = {
         IDLBuiltinType.Types.byte: (-128, 127),
         IDLBuiltinType.Types.octet:  (0, 255),
         IDLBuiltinType.Types.short: (-32768, 32767),
         IDLBuiltinType.Types.unsigned_short: (0, 65535),
@@ -4408,16 +4511,17 @@ class Tokenizer(object):
         "[": "LBRACKET",
         "]": "RBRACKET",
         "?": "QUESTIONMARK",
         ",": "COMMA",
         "=": "EQUALS",
         "<": "LT",
         ">": "GT",
         "ArrayBuffer": "ARRAYBUFFER",
+        "SharedArrayBuffer": "SHAREDARRAYBUFFER",
         "or": "OR"
         }
 
     tokens.extend(keywords.values())
 
     def t_error(self, t):
         raise WebIDLError("Unrecognized Input",
                [Location(lexer=self.lexer,
@@ -5455,22 +5559,25 @@ class Parser(Tokenizer):
             UnionMemberTypes :
         """
         p[0] = []
 
     def p_NonAnyType(self, p):
         """
             NonAnyType : PrimitiveOrStringType TypeSuffix
                        | ARRAYBUFFER TypeSuffix
+                       | SHAREDARRAYBUFFER TypeSuffix
                        | OBJECT TypeSuffix
         """
         if p[1] == "object":
             type = BuiltinTypes[IDLBuiltinType.Types.object]
         elif p[1] == "ArrayBuffer":
             type = BuiltinTypes[IDLBuiltinType.Types.ArrayBuffer]
+        elif p[1] == "SharedArrayBuffer":
+            type = BuiltinTypes[IDLBuiltinType.Types.SharedArrayBuffer]
         else:
             type = BuiltinTypes[p[1]]
 
         p[0] = self.handleModifiers(type, p[2])
 
     def p_NonAnyTypeSequenceType(self, p):
         """
             NonAnyType : SEQUENCE LT Type GT Null
@@ -5854,17 +5961,17 @@ class Parser(Tokenizer):
         self._filename = None
 
         self.parser.parse(lexer=self.lexer,tracking=True)
 
     def _installBuiltins(self, scope):
         assert isinstance(scope, IDLScope)
 
         # xrange omits the last value.
-        for x in xrange(IDLBuiltinType.Types.ArrayBuffer, IDLBuiltinType.Types.Float64Array + 1):
+        for x in xrange(IDLBuiltinType.Types.ArrayBuffer, IDLBuiltinType.Types.SharedFloat64Array + 1):
             builtin = BuiltinTypes[x]
             name = builtin.name
             typedef = IDLTypedef(BuiltinLocation("<builtin type>"), scope, builtin, name)
 
     @ staticmethod
     def handleModifiers(type, modifiers):
         for (modifier, modifierLocation) in modifiers:
             assert modifier == IDLMethod.TypeSuffixModifier.QMark or \
@@ -5915,16 +6022,17 @@ class Parser(Tokenizer):
 
     def reset(self):
         return Parser(lexer=self.lexer)
 
     # Builtin IDL defined by WebIDL
     _builtins = """
         typedef unsigned long long DOMTimeStamp;
         typedef (ArrayBufferView or ArrayBuffer) BufferSource;
+        typedef (SharedArrayBufferView or SharedArrayBuffer) SharedBufferSource;
     """
 
 def main():
     # Parse arguments.
     from optparse import OptionParser
     usageString = "usage: %prog [options] files"
     o = OptionParser(usage=usageString)
     o.add_option("--cachedir", dest='cachedir', default=None,
--- a/dom/bindings/parser/tests/test_distinguishability.py
+++ b/dom/bindings/parser/tests/test_distinguishability.py
@@ -155,43 +155,46 @@ def WebIDLTest(parser, harness):
                  "Interface", "Interface?",
                  "AncestorInterface", "UnrelatedInterface",
                  "ImplementedInterface", "CallbackInterface",
                  "CallbackInterface?", "CallbackInterface2",
                  "object", "Callback", "Callback2", "optional Dict",
                  "optional Dict2", "sequence<long>", "sequence<short>",
                  "MozMap<object>", "MozMap<Dict>", "MozMap<long>",
                  "long[]", "short[]", "Date", "Date?", "any",
-                 "USVString" ]
+                 "USVString", "ArrayBuffer", "ArrayBufferView", "SharedArrayBuffer", "SharedArrayBufferView",
+                 "Uint8Array", "SharedUint8Array", "Uint16Array", "SharedUint16Array" ]
     # When we can parse Date and RegExp, we need to add them here.
 
     # Try to categorize things a bit to keep list lengths down
     def allBut(list1, list2):
         return [a for a in list1 if a not in list2 and a != "any"]
     numerics = [ "long", "short", "long?", "short?" ]
     booleans = [ "boolean", "boolean?" ]
     primitives = numerics + booleans
     nonNumerics = allBut(argTypes, numerics)
     nonBooleans = allBut(argTypes, booleans)
     strings = [ "DOMString", "ByteString", "Enum", "Enum2", "USVString" ]
     nonStrings = allBut(argTypes, strings)
     nonObjects = primitives + strings
     objects = allBut(argTypes, nonObjects )
+    bufferSourceTypes = ["ArrayBuffer", "ArrayBufferView", "Uint8Array", "Uint16Array"]
+    sharedBufferSourceTypes = ["SharedArrayBuffer", "SharedArrayBufferView", "SharedUint8Array", "SharedUint16Array"]
     interfaces = [ "Interface", "Interface?", "AncestorInterface",
-                   "UnrelatedInterface", "ImplementedInterface" ]
+                   "UnrelatedInterface", "ImplementedInterface" ] + bufferSourceTypes + sharedBufferSourceTypes
     nullables = ["long?", "short?", "boolean?", "Interface?",
                  "CallbackInterface?", "optional Dict", "optional Dict2",
                  "Date?", "any"]
     dates = [ "Date", "Date?" ]
     sequences = [ "sequence<long>", "sequence<short>" ]
     arrays = [ "long[]", "short[]" ]
     nonUserObjects = nonObjects + interfaces + dates + sequences
     otherObjects = allBut(argTypes, nonUserObjects + ["object"])
     notRelatedInterfaces = (nonObjects + ["UnrelatedInterface"] +
-                            otherObjects + dates + sequences)
+                            otherObjects + dates + sequences + bufferSourceTypes + sharedBufferSourceTypes)
     mozMaps = [ "MozMap<object>", "MozMap<Dict>", "MozMap<long>" ]
 
     # Build a representation of the distinguishability table as a dict
     # of dicts, holding True values where needed, holes elsewhere.
     data = dict();
     for type in argTypes:
         data[type] = dict()
     def setDistinguishable(type, types):
@@ -230,16 +233,24 @@ def WebIDLTest(parser, harness):
     setDistinguishable("MozMap<object>", nonUserObjects)
     setDistinguishable("MozMap<Dict>", nonUserObjects)
     setDistinguishable("MozMap<long>", nonUserObjects)
     setDistinguishable("long[]", allBut(nonUserObjects, sequences))
     setDistinguishable("short[]", allBut(nonUserObjects, sequences))
     setDistinguishable("Date", allBut(argTypes, dates + ["object"]))
     setDistinguishable("Date?", allBut(argTypes, dates + nullables + ["object"]))
     setDistinguishable("any", [])
+    setDistinguishable("ArrayBuffer", allBut(argTypes, ["ArrayBuffer", "object"]))
+    setDistinguishable("ArrayBufferView", allBut(argTypes, ["ArrayBufferView", "Uint8Array", "Uint16Array", "object"]))
+    setDistinguishable("Uint8Array", allBut(argTypes, ["ArrayBufferView", "Uint8Array", "object"]))
+    setDistinguishable("Uint16Array", allBut(argTypes, ["ArrayBufferView", "Uint16Array", "object"]))
+    setDistinguishable("SharedArrayBuffer", allBut(argTypes, ["SharedArrayBuffer", "object"]))
+    setDistinguishable("SharedArrayBufferView", allBut(argTypes, ["SharedArrayBufferView", "SharedUint8Array", "SharedUint16Array", "object"]))
+    setDistinguishable("SharedUint8Array", allBut(argTypes, ["SharedArrayBufferView", "SharedUint8Array", "object"]))
+    setDistinguishable("SharedUint16Array", allBut(argTypes, ["SharedArrayBufferView", "SharedUint16Array", "object"]))
 
     def areDistinguishable(type1, type2):
         return data[type1].get(type2, False)
 
     def checkDistinguishability(parser, type1, type2):
         idlTemplate = """
           enum Enum { "a", "b" };
           enum Enum2 { "c", "d" };
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/reftest/capturestream.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<meta charset='UTF-8'>
+<!--
+Clear the canvas to green and capture it to a stream to test that we can get
+the stream to screen in a local video element.
+-->
+<html class="reftest-wait">
+
+<head>
+  <script type='text/javascript'>
+function finished() {
+  document.documentElement.removeAttribute("class");
+}
+
+function runTest() {
+  var canvas = document.getElementById('canvas');
+  var context = canvas.getContext('2d');
+  context.fillStyle = "rgba(0, 255, 0, 1)";
+  context.fillRect(0, 0, canvas.width, canvas.height);
+
+  var video = document.getElementById('video');
+  video.mozSrcObject = canvas.captureStream(0);
+  video.play();
+  video.onloadeddata = finished;
+  video.onerror = finished;
+}
+  </script>
+</head>
+
+<body onload='runTest();'>
+  <video id='video' width='256' height='256'></video>
+  <canvas id='canvas' width='256' height='256' style="display:none"></canvas>
+</body>
+
+</html>
--- a/dom/canvas/test/reftest/reftest.list
+++ b/dom/canvas/test/reftest/reftest.list
@@ -14,16 +14,19 @@ pref(webgl.force-layers-readback,true)  
 # Make sure that our choice of attribs doesn't break rendering.
 == webgl-clear-test.html?depth wrapper.html?green.png
 == webgl-clear-test.html?stencil wrapper.html?green.png
 == webgl-clear-test.html?depth&stencil wrapper.html?green.png
 
 # Check that resize works:
 == webgl-resize-test.html  wrapper.html?green.png
 
+# Check that captureStream() displays in a local video element
+pref(canvas.capturestream.enabled,true) skip-if(winWidget&&layersGPUAccelerated&&d2d) == webgl-capturestream-test.html?preserve wrapper.html?green.png
+
 # Some of the failure conditions are a little crazy. I'm (jgilbert) setting these based on
 # failures encountered when running on Try, and then targetting the Try config by
 # differences in the `sandbox` contents. That is, I'm labeling based on symptoms rather
 # than cause.
 # Lin-R-e10s: gtkWidget && browserIsRemote
 # WinXP-R: winWidget && layersGPUAccelerated && !d2d
 # Win7+-R: winWidget && layersGPUAccelerated && d2d
 # Win7+-Ru: winWidget && !layersGPUAccelerated
@@ -147,8 +150,11 @@ skip-if(!winWidget) pref(webgl.disable-a
 != clip-multiple-paths.html clip-multiple-paths-badref.html
 
 # Bug 815648
 == stroketext-shadow.html stroketext-shadow-ref.html
 
 # focus rings
 pref(canvas.focusring.enabled,true) skip-if(B2G) skip-if(Android&&AndroidVersion<15,8,500) skip-if(winWidget) needs-focus == drawFocusIfNeeded.html drawFocusIfNeeded-ref.html
 pref(canvas.customfocusring.enabled,true) skip-if(B2G) skip-if(Android&&AndroidVersion<15,8,500) skip-if(winWidget) needs-focus == drawCustomFocusRing.html drawCustomFocusRing-ref.html
+
+# Check that captureStream() displays in a local video element
+pref(canvas.capturestream.enabled,true) fails-if(B2G) skip-if(winWidget&&layersGPUAccelerated&&d2d) == capturestream.html wrapper.html?green.png
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/reftest/webgl-capturestream-test.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<meta charset='UTF-8'>
+<!--
+Clear the canvas to green and capture it to a stream to test that we can get
+the stream to screen in a local video element.
+-->
+<html class="reftest-wait">
+
+<head>
+  <script type='text/javascript' src='webgl-utils.js'></script>
+  <script type='text/javascript'>
+'use strict';
+
+function setStatus(text) {
+  var elem = document.getElementById('status');
+  elem.innerHTML = text;
+}
+
+function finished() {
+  document.documentElement.removeAttribute("class");
+}
+
+function runTest() {
+  var canvas = document.getElementById('canvas');
+
+  var gl = initGL(canvas);
+  if (!gl) {
+    setStatus('WebGL context creation failed.');
+    return;
+  }
+
+  gl.clearColor(0.0, 1.0, 0.0, 1.0);
+  gl.clear(gl.COLOR_BUFFER_BIT);
+
+  var video = document.getElementById('video');
+  video.mozSrcObject = canvas.captureStream(0);
+  video.play();
+  video.onloadeddata = finished;
+  video.onerror = finished;
+}
+  </script>
+</head>
+
+<body onload='runTest();'>
+  <video id='video' width='256' height='256'></video>
+  <canvas id='canvas' width='256' height='256' style="display:none"></canvas>
+  <div id='status'></div>
+</body>
+
+</html>
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -3703,18 +3703,28 @@ public:
 /*static*/ bool
 EventStateManager::IsHandlingUserInput()
 {
   if (sUserInputEventDepth <= 0) {
     return false;
   }
 
   TimeDuration timeout = nsContentUtils::HandlingUserInputTimeout();
-  return timeout <= TimeDuration(0) ||
-         (TimeStamp::Now() - sHandlingInputStart) <= timeout;
+  TimeDuration elapsed = TimeStamp::Now() - sHandlingInputStart;
+  bool inTime = timeout <= TimeDuration(0) || elapsed <= timeout;
+
+  if (!inTime) {
+#ifdef DEBUG
+    printf("EventStateManager::IsHandlingUserInput() has timed out "
+           "(timeout: %f, elapsed: %f)\n",
+           timeout.ToMilliseconds(), elapsed.ToMilliseconds());
+#endif
+    return false;
+  }
+  return true;
 }
 
 static void
 CreateMouseOrPointerWidgetEvent(WidgetMouseEvent* aMouseEvent,
                                 uint32_t aMessage,
                                 nsIContent* aRelatedContent,
                                 nsAutoPtr<WidgetMouseEvent>& aNewEvent)
 {
--- a/dom/inputmethod/forms.js
+++ b/dom/inputmethod/forms.js
@@ -13,20 +13,16 @@ let Cc = Components.classes;
 let Cu = Components.utils;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 XPCOMUtils.defineLazyServiceGetter(Services, "fm",
                                    "@mozilla.org/focus-manager;1",
                                    "nsIFocusManager");
 
-XPCOMUtils.defineLazyServiceGetter(Services, "threadManager",
-                                   "@mozilla.org/thread-manager;1",
-                                   "nsIThreadManager");
-
 XPCOMUtils.defineLazyGetter(this, "domWindowUtils", function () {
   return content.QueryInterface(Ci.nsIInterfaceRequestor)
                 .getInterface(Ci.nsIDOMWindowUtils);
 });
 
 const RESIZE_SCROLL_DELAY = 20;
 // In content editable node, when there are hidden elements such as <br>, it
 // may need more than one (usually less than 3 times) move/extend operations
@@ -456,23 +452,16 @@ let FormAssistant = {
           break;
         }
 
         CompositionManager.onCompositionEnd();
         break;
     }
   },
 
-  waitForNextTick: function(callback) {
-    var tm = Services.threadManager;
-    tm.mainThread.dispatch({
-      run: callback,
-    }, Components.interfaces.nsIThread.DISPATCH_NORMAL);
-  },
-
   receiveMessage: function fa_receiveMessage(msg) {
     let target = this.focusedElement;
     let json = msg.json;
 
     // To not break mozKeyboard contextId is optional
     if ('contextId' in json &&
         json.contextId !== this._focusCounter &&
         json.requestId) {
@@ -677,45 +666,23 @@ let FormAssistant = {
   handleFocus: function fa_handleFocus(target) {
     if (this.focusedElement === target)
       return;
 
     if (target instanceof HTMLOptionElement)
       target = target.parentNode;
 
     this.setFocusedElement(target);
-
-    let count = this._focusCounter;
-    this.waitForNextTick(function fa_handleFocusSync() {
-      if (count !== this._focusCounter) {
-        return;
-      }
-
-      let isHandlingFocus = this.sendInputState(target);
-      this.isHandlingFocus = isHandlingFocus;
-    }.bind(this));
+    this.isHandlingFocus = this.sendInputState(target);
   },
 
   unhandleFocus: function fa_unhandleFocus() {
     this.setFocusedElement(null);
-
-    let count = this._focusCounter;
-
-    // Wait for the next tick before unset the focused element and etc.
-    // If the user move from one input from another,
-    // the remote process should get one Forms:Input message instead of two.
-    this.waitForNextTick(function fa_unhandleFocusSync() {
-      if (count !== this._focusCounter ||
-          !this.isHandlingFocus) {
-        return;
-      }
-
-      this.isHandlingFocus = false;
-      sendAsyncMessage("Forms:Input", { "type": "blur" });
-    }.bind(this));
+    this.isHandlingFocus = false;
+    sendAsyncMessage("Forms:Input", { "type": "blur" });
   },
 
   isFocusableElement: function fa_isFocusableElement(element) {
     if (element instanceof HTMLSelectElement ||
         element instanceof HTMLTextAreaElement)
       return true;
 
     if (element instanceof HTMLOptionElement &&
deleted file mode 100644
--- a/dom/inputmethod/mochitest/file_test_contenteditable.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body>
-<div id="text" contenteditable>Jan Jongboom</div>
-<script type="application/javascript;version=1.7">
-  var t = document.querySelector('#text');
-
-  t.focus();
-  var range = document.createRange();
-  range.selectNodeContents(t);
-  range.collapse(false);
-  var selection = window.getSelection();
-  selection.removeAllRanges();
-  selection.addRange(range);
-</script>
-</body>
-</html>
--- a/dom/inputmethod/mochitest/mochitest.ini
+++ b/dom/inputmethod/mochitest/mochitest.ini
@@ -1,17 +1,16 @@
 [DEFAULT]
 # Not supported on Android, bug 983015 for B2G emulator
 skip-if = (toolkit == 'android' || toolkit == 'gonk') || e10s
 support-files =
   inputmethod_common.js
   file_inputmethod.html
   file_inputmethod_1043828.html
   file_test_app.html
-  file_test_contenteditable.html
   file_test_sendkey_cancel.html
   file_test_sms_app.html
   file_test_sms_app_1066515.html
 
 [test_basic.html]
 [test_bug944397.html]
 [test_bug949059.html]
 [test_bug953044.html]
--- a/dom/inputmethod/mochitest/test_bug1059163.html
+++ b/dom/inputmethod/mochitest/test_bug1059163.html
@@ -15,63 +15,69 @@ https://bugzilla.mozilla.org/show_bug.cg
 <pre id="test">
 <script class="testbody" type="application/javascript;version=1.7">
 inputmethod_setup(function() {
   runTest();
 });
 
 // The frame script running in the file
 function appFrameScript() {
+  let document = content.document;
+  let window = content.document.defaultView;
+
+  let t = document.getElementById('text');
+  t.focus();
+
+  let range = document.createRange();
+  range.selectNodeContents(t);
+  range.collapse(false);
+  let selection = window.getSelection();
+  selection.removeAllRanges();
+  selection.addRange(range);
+
   addMessageListener('test:InputMethod:clear', function() {
-    var t = content.document.getElementById('text');
     t.innerHTML = '';
   });
 }
 
 function runTest() {
   let im = navigator.mozInputMethod;
 
   // Set current page as an input method.
   SpecialPowers.wrap(im).setActive(true);
 
   // Create an app frame to recieve keyboard inputs.
   let app = document.createElement('iframe');
-  app.src = 'file_test_contenteditable.html';
+  app.src = 'data:text/html,<html><body><div id="text" contenteditable>Jan Jongboom</div></html>';
   app.setAttribute('mozbrowser', true);
   document.body.appendChild(app);
   app.addEventListener('mozbrowserloadend', function() {
     let mm = SpecialPowers.getBrowserFrameMessageManager(app);
+    mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
+
+    im.oninputcontextchange = function() {
+      if (im.inputcontext) {
+        im.oninputcontextchange = null;
+        register();
+      }
+    };
 
     function register() {
       im.inputcontext.onselectionchange = function() {
         im.inputcontext.onselectionchange = null;
 
         is(im.inputcontext.textBeforeCursor, '', 'textBeforeCursor');
-        is(im.inputcontext.textBeforeCursor, '', 'textAfterCursor');
+        is(im.inputcontext.textAfterCursor, '', 'textAfterCursor');
         is(im.inputcontext.selectionStart, 0, 'selectionStart');
         is(im.inputcontext.selectionEnd, 0, 'selectionEnd');
 
         inputmethod_cleanup();
       };
 
       mm.sendAsyncMessage('test:InputMethod:clear');
     }
-
-    if (im.inputcontext) {
-       register();
-    }
-    else {
-      im.oninputcontextchange = function() {
-        if (im.inputcontext) {
-          im.oninputcontextchange = null;
-          register();
-        }
-      };
-    }
-
-    mm.loadFrameScript('data:,(' + appFrameScript.toString() + ')();', false);
   });
 }
 </script>
 </pre>
 </body>
 </html>
 
--- a/dom/inputmethod/mochitest/test_sync_edit.html
+++ b/dom/inputmethod/mochitest/test_sync_edit.html
@@ -20,44 +20,60 @@ inputmethod_setup(function() {
 });
 
 let appFrameScript = function appFrameScript() {
   let input = content.document.body.firstElementChild;
 
   input.focus();
   input.value = 'First1';
   input.blur();
-
-  content.setTimeout(function() {
-    sendAsyncMessage('test:next', {});
-  });
 };
 
 function runTest() {
   let im = navigator.mozInputMethod;
 
   let i = 0;
   im.oninputcontextchange = function() {
-    ok(false, 'Should not receive any inputcontextchange events.');
+    let inputcontext = im.inputcontext;
+    i++;
+    switch (i) {
+      case 1:
+        ok(!!inputcontext, 'Should receive inputcontext from focus().');
+        is(inputcontext.textAfterCursor, 'First');
+
+        break;
+
+      case 2:
+        ok(!!inputcontext, 'Should receive inputcontext from value change.');
+        is(inputcontext.textBeforeCursor, 'First1');
+
+        break;
+
+      case 3:
+        ok(!inputcontext, 'Should lost inputcontext from blur().');
+
+        inputmethod_cleanup();
+        break;
+
+      default:
+        ok(false, 'Unknown event count.');
+
+        inputmethod_cleanup();
+    }
   };
 
   // Set current page as an input method.
   SpecialPowers.wrap(im).setActive(true);
 
   let iframe = document.createElement('iframe');
   iframe.src = 'data:text/html,<html><body><input value="First"></body></html>';
   iframe.setAttribute('mozbrowser', true);
   document.body.appendChild(iframe);
 
   let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
-  mm.addMessageListener('test:next', function() {
-    ok(true, '\\o/');
-    inputmethod_cleanup();
-  });
-
   iframe.addEventListener('mozbrowserloadend', function() {
     mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
   });
 }
 
 </script>
 </pre>
 </body>
--- a/dom/inputmethod/mochitest/test_two_inputs.html
+++ b/dom/inputmethod/mochitest/test_two_inputs.html
@@ -29,49 +29,47 @@ let appFrameScript = function appFrameSc
 
   input1.focus();
 
   addMessageListener('test:next', function() {
     i++;
     switch (i) {
       case 2:
         input2.focus();
-
-        break;
-
-      case 3:
-        input2.blur();
-        input2.focus();
+        i++; // keep the same count with the parent frame.
 
         break;
 
       case 4:
         input2.blur();
 
         break;
 
       case 5:
         input2.focus();
-        input2.blur();
-
-        input1.focus();
 
         break;
 
       case 6:
+        input1.focus();
+        i++; // keep the same count with the parent frame.
+
+        break;
+
+      case 8:
         content.document.body.removeChild(input1);
 
         break;
 
-      case 7:
+      case 9:
         input2.focus();
 
         break;
 
-      case 8:
+      case 10:
         content.document.body.removeChild(input2);
 
         break;
     }
   });
 };
 
 function runTest() {
@@ -80,75 +78,83 @@ function runTest() {
   let i = 0;
   im.oninputcontextchange = function(evt) {
     var inputcontext = navigator.mozInputMethod.inputcontext;
 
     i++;
     switch (i) {
       // focus on the first input receives the first input context.
       case 1:
-        ok(!!inputcontext, 'Receving the first input context');
+        ok(!!inputcontext, '1) Receving the first input context');
         is(inputcontext.textAfterCursor, 'First');
 
         mm.sendAsyncMessage('test:next');
         break;
 
-      // focus on the second input (implicitly blur the first input)
-      // results the second input context.
+      // focus on the second input should implicitly blur the first input
       case 2:
-        ok(!!inputcontext, 'Receving the second input context');
-        is(inputcontext.textAfterCursor, 'Second');
+        is(inputcontext, null, '2) Receving null inputcontext');
 
-
-        mm.sendAsyncMessage('test:next');
         break;
 
-      // blur and re-focus on the second input results updated
-      // input context for the second input.
+      // ... and results the second input context.
       case 3:
-        ok(!!inputcontext, 'Receving the second input context');
+        ok(!!inputcontext, '3) Receving the second input context');
         is(inputcontext.textAfterCursor, 'Second');
 
         mm.sendAsyncMessage('test:next');
         break;
 
       // blur on the second input results null input context
       case 4:
-        is(inputcontext, null, 'Receving null inputcontext');
+        is(inputcontext, null, '4) Receving null inputcontext');
 
         mm.sendAsyncMessage('test:next');
         break;
 
-      // focus and blur on the second input sends no message;
-      // focus on the first input receives the first input context.
+      // focus on the second input receives the second input context.
       case 5:
-        ok(!!inputcontext, 'Receving the first input context');
+        ok(!!inputcontext, '5) Receving the second input context');
+        is(inputcontext.textAfterCursor, 'Second');
+
+        mm.sendAsyncMessage('test:next');
+        break;
+
+      // focus on the second input should implicitly blur the first input
+      case 6:
+        is(inputcontext, null, '6) Receving null inputcontext');
+
+        break;
+
+      // ... and results the second input context.
+      case 7:
+        ok(!!inputcontext, '7) Receving the first input context');
         is(inputcontext.textAfterCursor, 'First');
 
         mm.sendAsyncMessage('test:next');
         break;
 
       // remove on the first focused input results null input context
-      case 6:
-        is(inputcontext, null, 'Receving null inputcontext');
+      case 8:
+        is(inputcontext, null, '8) Receving null inputcontext');
 
         mm.sendAsyncMessage('test:next');
         break;
 
       // input context for the second input.
-      case 7:
-        ok(!!inputcontext, 'Receving the second input context');
+      case 9:
+        ok(!!inputcontext, '9) Receving the second input context');
         is(inputcontext.textAfterCursor, 'Second');
 
         mm.sendAsyncMessage('test:next');
         break;
 
       // remove on the second focused input results null input context
-      case 8:
-        is(inputcontext, null, 'Receving null inputcontext');
+      case 10:
+        is(inputcontext, null, '10) Receving null inputcontext');
 
         inputmethod_cleanup();
         break;
 
       default:
         ok(false, 'Receving extra inputcontextchange calls');
         inputmethod_cleanup();
 
--- a/dom/inputmethod/mochitest/test_two_selects.html
+++ b/dom/inputmethod/mochitest/test_two_selects.html
@@ -27,40 +27,48 @@ let appFrameScript = function appFrameSc
 
   select1.focus();
 
   addMessageListener('test:next', function() {
     i++;
     switch (i) {
       case 2:
         select2.focus();
-
-        break;
-
-      case 3:
-        select2.blur();
-        select2.focus();
+        i++; // keep the same count with the parent frame.
 
         break;
 
       case 4:
         select2.blur();
 
         break;
 
       case 5:
         select2.focus();
-        select2.blur();
-
-        select1.focus();
 
         break;
 
       case 6:
-        select1.blur();
+        select1.focus();
+        i++; // keep the same count with the parent frame.
+
+        break;
+
+      case 8:
+        content.document.body.removeChild(select1);
+
+        break;
+
+      case 9:
+        select2.focus();
+
+        break;
+
+      case 10:
+        content.document.body.removeChild(select2);
 
         break;
     }
   });
 };
 
 function runTest() {
   let im = navigator.mozInputMethod;
@@ -68,60 +76,83 @@ function runTest() {
   let i = 0;
   im.oninputcontextchange = function(evt) {
     var inputcontext = navigator.mozInputMethod.inputcontext;
 
     i++;
     switch (i) {
       // focus on the first input receives the first input context.
       case 1:
-        ok(!!inputcontext, 'Receving the first input context');
+        ok(!!inputcontext, '1) Receving the first input context');
         is(inputcontext.textAfterCursor, 'First');
 
         mm.sendAsyncMessage('test:next');
         break;
 
-      // focus on the second input (implicitly blur the first input)
-      // results the second input context.
+      // focus on the second input should implicitly blur the first input
       case 2:
-        ok(!!inputcontext, 'Receving the second input context');
-        is(inputcontext.textAfterCursor, 'Second');
+        is(inputcontext, null, '2) Receving null inputcontext');
 
-
-        mm.sendAsyncMessage('test:next');
         break;
 
-      // blur and re-focus on the second input results updated
-      // input context for the second input.
+      // ... and results the second input context.
       case 3:
-        ok(!!inputcontext, 'Receving the second input context');
+        ok(!!inputcontext, '3) Receving the second input context');
         is(inputcontext.textAfterCursor, 'Second');
 
         mm.sendAsyncMessage('test:next');
         break;
 
       // blur on the second input results null input context
       case 4:
-        is(inputcontext, null, 'Receving null inputcontext');
+        is(inputcontext, null, '4) Receving null inputcontext');
 
         mm.sendAsyncMessage('test:next');
         break;
 
-      // focus and blur on the second input sends no message;
-      // focus on the first input receives the first input context.
+      // focus on the second input receives the second input context.
       case 5:
-        ok(!!inputcontext, 'Receving the first input context');
+        ok(!!inputcontext, '5) Receving the second input context');
+        is(inputcontext.textAfterCursor, 'Second');
+
+        mm.sendAsyncMessage('test:next');
+        break;
+
+      // focus on the second input should implicitly blur the first input
+      case 6:
+        is(inputcontext, null, '6) Receving null inputcontext');
+
+        break;
+
+      // ... and results the second input context.
+      case 7:
+        ok(!!inputcontext, '7) Receving the first input context');
         is(inputcontext.textAfterCursor, 'First');
 
         mm.sendAsyncMessage('test:next');
         break;
 
-      // blur on the first input results null input context
-      case 6:
-        is(inputcontext, null, 'Receving null inputcontext');
+      // remove on the first focused input results null input context
+      case 8:
+        is(inputcontext, null, '8) Receving null inputcontext');
+
+        mm.sendAsyncMessage('test:next');
+        break;
+
+      // input context for the second input.
+      case 9:
+        ok(!!inputcontext, '9) Receving the second input context');
+        is(inputcontext.textAfterCursor, 'Second');
+
+        mm.sendAsyncMessage('test:next');
+        break;
+
+      // remove on the second focused input results null input context
+      case 10:
+        is(inputcontext, null, '10) Receving null inputcontext');
 
         inputmethod_cleanup();
         break;
 
       default:
         ok(false, 'Receving extra inputcontextchange calls');
         inputmethod_cleanup();
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -74,17 +74,19 @@
 #include "mozilla/layers/ImageBridgeParent.h"
 #include "mozilla/layers/SharedBufferManagerParent.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/net/NeckoParent.h"
 #include "mozilla/plugins/PluginBridge.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ProcessHangMonitor.h"
 #include "mozilla/ProcessHangMonitorIPC.h"
+#ifdef MOZ_ENABLE_PROFILER_SPS
 #include "mozilla/ProfileGatherer.h"
+#endif
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/unused.h"
 #include "nsAnonymousTemporaryFile.h"
 #include "nsAppRunner.h"
 #include "nsAutoPtr.h"
 #include "nsCDefaultURIFixup.h"
@@ -234,17 +236,19 @@ using namespace mozilla::system;
 #ifdef MOZ_GAMEPAD
 #include "mozilla/dom/GamepadMonitoring.h"
 #endif
 
 static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
 
 using base::ChildPrivileges;
 using base::KillProcess;
+#ifdef MOZ_ENABLE_PROFILER_SPS
 using mozilla::ProfileGatherer;
+#endif
 
 #ifdef MOZ_CRASHREPORTER
 using namespace CrashReporter;
 #endif
 using namespace mozilla::dom::bluetooth;
 using namespace mozilla::dom::cellbroadcast;
 using namespace mozilla::dom::devicestorage;
 using namespace mozilla::dom::icc;
@@ -5101,22 +5105,24 @@ ContentParent::RecvGamepadListenerRemove
     MaybeStopGamepadMonitoring();
 #endif
     return true;
 }
 
 bool
 ContentParent::RecvProfile(const nsCString& aProfile)
 {
+#ifdef MOZ_ENABLE_PROFILER_SPS
     if (NS_WARN_IF(!mGatherer)) {
         return true;
     }
     mProfile = aProfile;
     mGatherer->GatheredOOPProfile();
     mGatherer = nullptr;
+#endif
     return true;
 }
 
 } // namespace dom
 } // namespace mozilla
 
 NS_IMPL_ISUPPORTS(ParentIdleListener, nsIObserver)
 
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -32,17 +32,19 @@ class nsConsoleService;
 class nsICycleCollectorLogSink;
 class nsIDumpGCAndCCLogsCallback;
 class nsITimer;
 class ParentIdleListener;
 class nsIWidget;
 
 namespace mozilla {
 class PRemoteSpellcheckEngineParent;
+#ifdef MOZ_ENABLE_PROFILER_SPS
 class ProfileGatherer;
+#endif
 
 namespace ipc {
 class OptionalURIParams;
 class PFileDescriptorSetParent;
 class URIParams;
 class TestShellParent;
 } // namespace ipc
 
@@ -928,17 +930,19 @@ private:
 #endif
 
 #ifdef MOZ_NUWA_PROCESS
     static int32_t sNuwaPid;
     static bool sNuwaReady;
 #endif
 
     PProcessHangMonitorParent* mHangMonitorActor;
+#ifdef MOZ_ENABLE_PROFILER_SPS
     nsRefPtr<mozilla::ProfileGatherer> mGatherer;
+#endif
     nsCString mProfile;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 class ParentIdleListener : public nsIObserver {
   friend class mozilla::dom::ContentParent;
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -305,17 +305,17 @@ parent:
     sync IsParentWindowMainWidgetVisible() returns (bool visible);
 
     /**
      * Returns the offset of this tab from the top level window
      * origin in device pixels.
      *
      * aPoint offset values in device pixels.
      */
-    sync GetTabOffset() returns (LayoutDeviceIntPoint aPoint);
+    prio(high) sync GetTabOffset() returns (LayoutDeviceIntPoint aPoint);
 
     /**
      * Gets the DPI of the screen corresponding to this browser.
      */
     sync GetDPI() returns (float value);
 
     /**
      * Gets the default scaling factor of the screen corresponding to this browser.
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -2697,16 +2697,23 @@ TabParent::ApzAwareEventRoutingToChild(S
     }
     if (aOutApzResponse) {
       *aOutApzResponse = InputAPZContext::GetApzResponse();
     }
 
     // Let the widget know that the event will be sent to the child process,
     // which will (hopefully) send a confirmation notice back to APZ.
     InputAPZContext::SetRoutedToChildProcess();
+  } else {
+    if (aOutInputBlockId) {
+      *aOutInputBlockId = 0;
+    }
+    if (aOutApzResponse) {
+      *aOutApzResponse = nsEventStatus_eIgnore;
+    }
   }
 }
 
 bool
 TabParent::RecvBrowserFrameOpenWindow(PBrowserParent* aOpener,
                                       const nsString& aURL,
                                       const nsString& aName,
                                       const nsString& aFeatures,
--- a/dom/media/MediaData.cpp
+++ b/dom/media/MediaData.cpp
@@ -485,27 +485,28 @@ VideoData::Create(const VideoInfo& aInfo
 
 #define RAW_DATA_DEFAULT_SIZE 4096
 
 MediaRawData::MediaRawData()
   : MediaData(RAW_DATA)
   , mData(nullptr)
   , mSize(0)
   , mCrypto(mCryptoInternal)
-  , mBuffer(new MediaLargeByteBuffer(RAW_DATA_DEFAULT_SIZE))
+  , mBuffer(new MediaByteBuffer())
   , mPadding(0)
 {
+  unused << mBuffer->SetCapacity(RAW_DATA_DEFAULT_SIZE, fallible);
 }
 
 MediaRawData::MediaRawData(const uint8_t* aData, size_t aSize)
   : MediaData(RAW_DATA)
   , mData(nullptr)
   , mSize(0)
   , mCrypto(mCryptoInternal)
-  , mBuffer(new MediaLargeByteBuffer(RAW_DATA_DEFAULT_SIZE))
+  , mBuffer(new MediaByteBuffer())
   , mPadding(0)
 {
   if (!EnsureCapacity(aSize)) {
     return;
   }
 
   // We ensure sufficient capacity above so this shouldn't fail.
   MOZ_ALWAYS_TRUE(mBuffer->AppendElements(aData, aSize, fallible));
--- a/dom/media/MediaData.h
+++ b/dom/media/MediaData.h
@@ -17,17 +17,16 @@
 
 namespace mozilla {
 
 namespace layers {
 class Image;
 class ImageContainer;
 }
 
-class MediaLargeByteBuffer;
 class MediaByteBuffer;
 
 // Container that holds media samples.
 class MediaData {
 public:
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaData)
 
@@ -364,17 +363,17 @@ public:
   // Clear the memory buffer. Will set mData and mSize to 0.
   void Clear();
 
 private:
   friend class MediaRawData;
   explicit MediaRawDataWriter(MediaRawData* aMediaRawData);
   bool EnsureSize(size_t aSize);
   MediaRawData* mTarget;
-  nsRefPtr<MediaLargeByteBuffer> mBuffer;
+  nsRefPtr<MediaByteBuffer> mBuffer;
 };
 
 class MediaRawData : public MediaData {
 public:
   MediaRawData();
   MediaRawData(const uint8_t* aData, size_t mSize);
 
   // Pointer to data or null if not-yet allocated
@@ -398,33 +397,22 @@ protected:
 private:
   friend class MediaRawDataWriter;
   // Ensure that the backend buffer can hold aSize data. Will update mData.
   // Will enforce that the start of allocated data is always 32 bytes
   // aligned and that it has sufficient end padding to allow for 32 bytes block
   // read as required by some data decoders.
   // Returns false if memory couldn't be allocated.
   bool EnsureCapacity(size_t aSize);
-  nsRefPtr<MediaLargeByteBuffer> mBuffer;
+  nsRefPtr<MediaByteBuffer> mBuffer;
   CryptoSample mCryptoInternal;
   uint32_t mPadding;
   MediaRawData(const MediaRawData&); // Not implemented
 };
 
-  // MediaLargeByteBuffer is a ref counted fallible TArray.
-  // It is designed to share potentially big byte arrays.
-class MediaLargeByteBuffer : public FallibleTArray<uint8_t> {
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaLargeByteBuffer);
-  MediaLargeByteBuffer() = default;
-  explicit MediaLargeByteBuffer(size_t aCapacity) : FallibleTArray<uint8_t>(aCapacity) {}
-
-private:
-  ~MediaLargeByteBuffer() {}
-};
-
   // MediaByteBuffer is a ref counted infallible TArray.
 class MediaByteBuffer : public nsTArray<uint8_t> {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaByteBuffer);
 
 private:
   ~MediaByteBuffer() {}
 };
 
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -2965,21 +2965,17 @@ void MediaDecoderStateMachine::AdvanceFr
   // the monitor and get a staled value from GetCurrentTimeUs() which hits the
   // assertion in GetClock().
 
   if (currentFrame) {
     // Decode one frame and display it.
     int64_t delta = currentFrame->mTime - clock_time;
     TimeStamp presTime = nowTime + TimeDuration::FromMicroseconds(delta / mPlaybackRate);
     NS_ASSERTION(currentFrame->mTime >= mStartTime, "Should have positive frame time");
-    // Filter out invalid frames by checking the frame time. FrameTime could be
-    // zero if it's a initial frame.
-    int64_t frameTime = currentFrame->mTime - mStartTime;
-    if (frameTime > 0  || (frameTime == 0 && mPlayDuration == 0) ||
-        IsRealTime()) {
+    {
       ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
       // If we have video, we want to increment the clock in steps of the frame
       // duration.
       RenderVideoFrame(currentFrame, presTime);
     }
     MOZ_ASSERT(IsPlaying());
     MediaDecoder::FrameStatistics& frameStats = mDecoder->GetFrameStatistics();
     frameStats.NotifyPresentedFrame();
--- a/dom/media/fmp4/MP4Demuxer.cpp
+++ b/dom/media/fmp4/MP4Demuxer.cpp
@@ -15,17 +15,17 @@
 #include "mp4_demuxer/ResourceStream.h"
 #include "mp4_demuxer/BufferStream.h"
 
 namespace mozilla {
 
 MP4Demuxer::MP4Demuxer(MediaResource* aResource)
   : mResource(aResource)
   , mStream(new mp4_demuxer::ResourceStream(aResource))
-  , mInitData(new MediaLargeByteBuffer)
+  , mInitData(new MediaByteBuffer)
 {
 }
 
 nsRefPtr<MP4Demuxer::InitPromise>
 MP4Demuxer::Init()
 {
   AutoPinned<mp4_demuxer::ResourceStream> stream(mStream);
 
--- a/dom/media/fmp4/MP4Demuxer.h
+++ b/dom/media/fmp4/MP4Demuxer.h
@@ -46,17 +46,17 @@ public:
   virtual void NotifyDataArrived(uint32_t aLength, int64_t aOffset) override;
 
   virtual void NotifyDataRemoved() override;
 
 private:
   friend class MP4TrackDemuxer;
   nsRefPtr<MediaResource> mResource;
   nsRefPtr<mp4_demuxer::ResourceStream> mStream;
-  nsRefPtr<MediaLargeByteBuffer> mInitData;
+  nsRefPtr<MediaByteBuffer> mInitData;
   UniquePtr<mp4_demuxer::MP4Metadata> mMetadata;
   nsTArray<nsRefPtr<MP4TrackDemuxer>> mDemuxers;
 };
 
 class MP4TrackDemuxer : public MediaTrackDemuxer
 {
 public:
   MP4TrackDemuxer(MP4Demuxer* aParent,
--- a/dom/media/mediasource/ContainerParser.cpp
+++ b/dom/media/mediasource/ContainerParser.cpp
@@ -32,41 +32,41 @@ namespace mozilla {
 
 ContainerParser::ContainerParser(const nsACString& aType)
   : mHasInitData(false)
   , mType(aType)
 {
 }
 
 bool
-ContainerParser::IsInitSegmentPresent(MediaLargeByteBuffer* aData)
+ContainerParser::IsInitSegmentPresent(MediaByteBuffer* aData)
 {
 MSE_DEBUG(ContainerParser, "aLength=%u [%x%x%x%x]",
             aData->Length(),
             aData->Length() > 0 ? (*aData)[0] : 0,
             aData->Length() > 1 ? (*aData)[1] : 0,
             aData->Length() > 2 ? (*aData)[2] : 0,
             aData->Length() > 3 ? (*aData)[3] : 0);
 return false;
 }
 
 bool
-ContainerParser::IsMediaSegmentPresent(MediaLargeByteBuffer* aData)
+ContainerParser::IsMediaSegmentPresent(MediaByteBuffer* aData)
 {
   MSE_DEBUG(ContainerParser, "aLength=%u [%x%x%x%x]",
             aData->Length(),
             aData->Length() > 0 ? (*aData)[0] : 0,
             aData->Length() > 1 ? (*aData)[1] : 0,
             aData->Length() > 2 ? (*aData)[2] : 0,
             aData->Length() > 3 ? (*aData)[3] : 0);
   return false;
 }
 
 bool
-ContainerParser::ParseStartAndEndTimestamps(MediaLargeByteBuffer* aData,
+ContainerParser::ParseStartAndEndTimestamps(MediaByteBuffer* aData,
                                             int64_t& aStart, int64_t& aEnd)
 {
   return false;
 }
 
 bool
 ContainerParser::TimestampsFuzzyEqual(int64_t aLhs, int64_t aRhs)
 {
@@ -81,17 +81,17 @@ ContainerParser::GetRoundingError()
 }
 
 bool
 ContainerParser::HasCompleteInitData()
 {
   return mHasInitData && !!mInitData->Length();
 }
 
-MediaLargeByteBuffer*
+MediaByteBuffer*
 ContainerParser::InitData()
 {
   return mInitData;
 }
 
 MediaByteRange
 ContainerParser::InitSegmentRange()
 {
@@ -116,17 +116,17 @@ public:
     : ContainerParser(aType)
     , mParser(0)
     , mOffset(0)
   {}
 
   static const unsigned NS_PER_USEC = 1000;
   static const unsigned USEC_PER_SEC = 1000000;
 
-  bool IsInitSegmentPresent(MediaLargeByteBuffer* aData) override
+  bool IsInitSegmentPresent(MediaByteBuffer* aData) override
   {
     ContainerParser::IsInitSegmentPresent(aData);
     // XXX: This is overly primitive, needs to collect data as it's appended
     // to the SB and handle, rather than assuming everything is present in a
     // single aData segment.
     // 0x1a45dfa3 // EBML
     // ...
     // DocType == "webm"
@@ -139,17 +139,17 @@ public:
     if (aData->Length() >= 4 &&
         (*aData)[0] == 0x1a && (*aData)[1] == 0x45 && (*aData)[2] == 0xdf &&
         (*aData)[3] == 0xa3) {
       return true;
     }
     return false;
   }
 
-  bool IsMediaSegmentPresent(MediaLargeByteBuffer* aData) override
+  bool IsMediaSegmentPresent(MediaByteBuffer* aData) override
   {
     ContainerParser::IsMediaSegmentPresent(aData);
     // XXX: This is overly primitive, needs to collect data as it's appended
     // to the SB and handle, rather than assuming everything is present in a
     // single aData segment.
     // 0x1a45dfa3 // EBML
     // ...
     // DocType == "webm"
@@ -160,25 +160,25 @@ public:
     if (aData->Length() >= 4 &&
         (*aData)[0] == 0x1f && (*aData)[1] == 0x43 && (*aData)[2] == 0xb6 &&
         (*aData)[3] == 0x75) {
       return true;
     }
     return false;
   }
 
-  bool ParseStartAndEndTimestamps(MediaLargeByteBuffer* aData,
+  bool ParseStartAndEndTimestamps(MediaByteBuffer* aData,
                                   int64_t& aStart, int64_t& aEnd) override
   {
     bool initSegment = IsInitSegmentPresent(aData);
     if (initSegment) {
       mOffset = 0;
       mParser = WebMBufferedParser(0);
       mOverlappedMapping.Clear();
-      mInitData = new MediaLargeByteBuffer();
+      mInitData = new MediaByteBuffer();
       mResource = new SourceBufferResource(NS_LITERAL_CSTRING("video/webm"));
     }
 
     // XXX if it only adds new mappings, overlapped but not available
     // (e.g. overlap < 0) frames are "lost" from the reported mappings here.
     nsTArray<WebMTimeDataOffset> mapping;
     mapping.AppendElements(mOverlappedMapping);
     mOverlappedMapping.Clear();
@@ -253,17 +253,17 @@ private:
 #ifdef MOZ_FMP4
 class MP4ContainerParser : public ContainerParser {
 public:
   explicit MP4ContainerParser(const nsACString& aType)
     : ContainerParser(aType)
     , mMonitor("MP4ContainerParser Index Monitor")
   {}
 
-  bool IsInitSegmentPresent(MediaLargeByteBuffer* aData) override
+  bool IsInitSegmentPresent(MediaByteBuffer* aData) override
   {
     ContainerParser::IsInitSegmentPresent(aData);
     // Each MP4 atom has a chunk size and chunk type. The root chunk in an MP4
     // file is the 'ftyp' atom followed by a file type. We just check for a
     // vaguely valid 'ftyp' atom.
 
     if (aData->Length() < 8) {
       return false;
@@ -273,17 +273,17 @@ public:
     if (chunk_size < 8) {
       return false;
     }
 
     return (*aData)[4] == 'f' && (*aData)[5] == 't' && (*aData)[6] == 'y' &&
            (*aData)[7] == 'p';
   }
 
-  bool IsMediaSegmentPresent(MediaLargeByteBuffer* aData) override
+  bool IsMediaSegmentPresent(MediaByteBuffer* aData) override
   {
     ContainerParser::IsMediaSegmentPresent(aData);
     if (aData->Length() < 8) {
       return false;
     }
 
     uint32_t chunk_size = BigEndian::readUint32(aData->Elements());
     if (chunk_size < 8) {
@@ -293,31 +293,31 @@ public:
     return ((*aData)[4] == 'm' && (*aData)[5] == 'o' && (*aData)[6] == 'o' &&
             (*aData)[7] == 'f') ||
            ((*aData)[4] == 's' && (*aData)[5] == 't' && (*aData)[6] == 'y' &&
             (*aData)[7] == 'p') ||
            ((*aData)[4] == 's' && (*aData)[5] == 'i' && (*aData)[6] == 'd' &&
             (*aData)[7] == 'x');
   }
 
-  bool ParseStartAndEndTimestamps(MediaLargeByteBuffer* aData,
+  bool ParseStartAndEndTimestamps(MediaByteBuffer* aData,
                                   int64_t& aStart, int64_t& aEnd) override
   {
     MonitorAutoLock mon(mMonitor); // We're not actually racing against anything,
                                    // but mParser requires us to hold a monitor.
     bool initSegment = IsInitSegmentPresent(aData);
     if (initSegment) {
       mResource = new SourceBufferResource(NS_LITERAL_CSTRING("video/mp4"));
       mStream = new MP4Stream(mResource);
       // We use a timestampOffset of 0 for ContainerParser, and require
       // consumers of ParseStartAndEndTimestamps to add their timestamp offset
       // manually. This allows the ContainerParser to be shared across different
       // timestampOffsets.
       mParser = new mp4_demuxer::MoofParser(mStream, 0, /* aIsAudio = */ false, &mMonitor);
-      mInitData = new MediaLargeByteBuffer();
+      mInitData = new MediaByteBuffer();
     } else if (!mStream || !mParser) {
       return false;
     }
 
     mResource->AppendData(aData);
     nsTArray<MediaByteRange> byteRanges;
     MediaByteRange mbr =
       MediaByteRange(mParser->mOffset, mResource->GetLength());
--- a/dom/media/mediasource/ContainerParser.h
+++ b/dom/media/mediasource/ContainerParser.h
@@ -8,48 +8,48 @@
 #define MOZILLA_CONTAINERPARSER_H_
 
 #include "nsRefPtr.h"
 #include "nsString.h"
 #include "MediaResource.h"
 
 namespace mozilla {
 
-class MediaLargeByteBuffer;
+class MediaByteBuffer;
 class SourceBufferResource;
 
 class ContainerParser {
 public:
   explicit ContainerParser(const nsACString& aType);
   virtual ~ContainerParser() {}
 
   // Return true if aData starts with an initialization segment.
   // The base implementation exists only for debug logging and is expected
   // to be called first from the overriding implementation.
-  virtual bool IsInitSegmentPresent(MediaLargeByteBuffer* aData);
+  virtual bool IsInitSegmentPresent(MediaByteBuffer* aData);
 
   // Return true if aData starts with a media segment.
   // The base implementation exists only for debug logging and is expected
   // to be called first from the overriding implementation.
-  virtual bool IsMediaSegmentPresent(MediaLargeByteBuffer* aData);
+  virtual bool IsMediaSegmentPresent(MediaByteBuffer* aData);
 
   // Parse aData to extract the start and end frame times from the media
   // segment.  aData may not start on a parser sync boundary.  Return true
   // if aStart and aEnd have been updated.
-  virtual bool ParseStartAndEndTimestamps(MediaLargeByteBuffer* aData,
+  virtual bool ParseStartAndEndTimestamps(MediaByteBuffer* aData,
                                           int64_t& aStart, int64_t& aEnd);
 
   // Compare aLhs and rHs, considering any error that may exist in the
   // timestamps from the format's base representation.  Return true if aLhs
   // == aRhs within the error epsilon.
   bool TimestampsFuzzyEqual(int64_t aLhs, int64_t aRhs);
 
   virtual int64_t GetRoundingError();
 
-  MediaLargeByteBuffer* InitData();
+  MediaByteBuffer* InitData();
 
   bool HasInitData()
   {
     return mHasInitData;
   }
 
   bool HasCompleteInitData();
   // Returns the byte range of the first complete init segment, or an empty
@@ -60,17 +60,17 @@ public:
   MediaByteRange MediaHeaderRange();
   // Returns the byte range of the first complete media segment or an empty
   // range if not complete.
   MediaByteRange MediaSegmentRange();
 
   static ContainerParser* CreateForMIMEType(const nsACString& aType);
 
 protected:
-  nsRefPtr<MediaLargeByteBuffer> mInitData;
+  nsRefPtr<MediaByteBuffer> mInitData;
   nsRefPtr<SourceBufferResource> mResource;
   bool mHasInitData;
   MediaByteRange mCompleteInitSegmentRange;
   MediaByteRange mCompleteMediaHeaderRange;
   MediaByteRange mCompleteMediaSegmentRange;
   const nsCString mType;
 };
 
--- a/dom/media/mediasource/ResourceQueue.cpp
+++ b/dom/media/mediasource/ResourceQueue.cpp
@@ -15,17 +15,17 @@ extern PRLogModuleInfo* GetSourceBufferR
 #define __func__ __FUNCTION__
 #endif
 
 #define SBR_DEBUG(arg, ...) MOZ_LOG(GetSourceBufferResourceLog(), mozilla::LogLevel::Debug, ("ResourceQueue(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
 #define SBR_DEBUGV(arg, ...) MOZ_LOG(GetSourceBufferResourceLog(), mozilla::LogLevel::Verbose, ("ResourceQueue(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
 
 namespace mozilla {
 
-ResourceItem::ResourceItem(MediaLargeByteBuffer* aData)
+ResourceItem::ResourceItem(MediaByteBuffer* aData)
   : mData(aData)
 {
 }
 
 size_t
 ResourceItem::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
 {
   // size including this
@@ -77,17 +77,17 @@ ResourceQueue::CopyData(uint64_t aOffset
       offset = 0;
       aCount -= bytes;
       aDest += bytes;
     }
   }
 }
 
 void
-ResourceQueue::AppendItem(MediaLargeByteBuffer* aData)
+ResourceQueue::AppendItem(MediaByteBuffer* aData)
 {
   mLogicalLength += aData->Length();
   Push(new ResourceItem(aData));
 }
 
 uint32_t
 ResourceQueue::Evict(uint64_t aOffset, uint32_t aSizeToEvict,
                      ErrorResult& aRv)
@@ -106,17 +106,17 @@ uint32_t ResourceQueue::EvictBefore(uint
               item, item->mData->Length(), mOffset);
     if (item->mData->Length() + mOffset >= aOffset) {
       if (aOffset <= mOffset) {
         break;
       }
       uint32_t offset = aOffset - mOffset;
       mOffset += offset;
       evicted += offset;
-      nsRefPtr<MediaLargeByteBuffer> data = new MediaLargeByteBuffer;
+      nsRefPtr<MediaByteBuffer> data = new MediaByteBuffer;
       if (!data->AppendElements(item->mData->Elements() + offset,
                                 item->mData->Length() - offset,
                                 fallible)) {
         aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
         return 0;
       }
 
       item->mData = data;
--- a/dom/media/mediasource/ResourceQueue.h
+++ b/dom/media/mediasource/ResourceQueue.h
@@ -21,36 +21,36 @@ class ErrorResult;
 
 // Data is evicted once it reaches a size threshold. This pops the items off
 // the front of the queue and deletes it.  If an eviction happens then the
 // MediaSource is notified (done in SourceBuffer::AppendData) which then
 // requests all SourceBuffers to evict data up to approximately the same
 // timepoint.
 
 struct ResourceItem {
-  explicit ResourceItem(MediaLargeByteBuffer* aData);
+  explicit ResourceItem(MediaByteBuffer* aData);
   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
-  nsRefPtr<MediaLargeByteBuffer> mData;
+  nsRefPtr<MediaByteBuffer> mData;
 };
 
 class ResourceQueue : private nsDeque {
 public:
   ResourceQueue();
 
   // Returns the logical byte offset of the start of the data.
   uint64_t GetOffset();
 
   // Returns the length of all items in the queue plus the offset.
   // This is the logical length of the resource.
   uint64_t GetLength();
 
   // Copies aCount bytes from aOffset in the queue into aDest.
   void CopyData(uint64_t aOffset, uint32_t aCount, char* aDest);
 
-  void AppendItem(MediaLargeByteBuffer* aData);
+  void AppendItem(MediaByteBuffer* aData);
 
   // Tries to evict at least aSizeToEvict from the queue up until
   // aOffset. Returns amount evicted.
   uint32_t Evict(uint64_t aOffset, uint32_t aSizeToEvict,
                  ErrorResult& aRv);
 
   uint32_t EvictBefore(uint64_t aOffset, ErrorResult& aRv);
 
--- a/dom/media/mediasource/SourceBuffer.cpp
+++ b/dom/media/mediasource/SourceBuffer.cpp
@@ -428,17 +428,17 @@ SourceBuffer::CheckEndTime()
   }
 }
 
 void
 SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv)
 {
   MSE_DEBUG("AppendData(aLength=%u)", aLength);
 
-  nsRefPtr<MediaLargeByteBuffer> data = PrepareAppend(aData, aLength, aRv);
+  nsRefPtr<MediaByteBuffer> data = PrepareAppend(aData, aLength, aRv);
   if (!data) {
     return;
   }
   mContentManager->AppendData(data, mTimestampOffset);
 
   StartUpdating();
 
   MOZ_ASSERT(mAppendMode == SourceBufferAppendMode::Segments,
@@ -531,17 +531,17 @@ SourceBuffer::AppendError(bool aDecoderE
   if (aDecoderError) {
     Optional<MediaSourceEndOfStreamError> decodeError(
       MediaSourceEndOfStreamError::Decode);
     ErrorResult dummy;
     mMediaSource->EndOfStream(decodeError, dummy);
   }
 }
 
-already_AddRefed<MediaLargeByteBuffer>
+already_AddRefed<MediaByteBuffer>
 SourceBuffer::PrepareAppend(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv)
 {
   typedef SourceBufferContentManager::EvictDataResult Result;
 
   if (!IsAttached() || mUpdating) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
@@ -579,17 +579,17 @@ SourceBuffer::PrepareAppend(const uint8_
   // to the DASH player to provide a complete media segment.
   if (aLength > mEvictionThreshold ||
       ((mContentManager->GetSize() > mEvictionThreshold - aLength) &&
        evicted != Result::CANT_EVICT)) {
     aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR);
     return nullptr;
   }
 
-  nsRefPtr<MediaLargeByteBuffer> data = new MediaLargeByteBuffer();
+  nsRefPtr<MediaByteBuffer> data = new MediaByteBuffer();
   if (!data->AppendElements(aData, aLength, fallible)) {
     aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR);
     return nullptr;
   }
   // TODO: Test buffer full flag.
   return data.forget();
 }
 
--- a/dom/media/mediasource/SourceBuffer.h
+++ b/dom/media/mediasource/SourceBuffer.h
@@ -27,17 +27,17 @@
 #include "SourceBufferContentManager.h"
 
 class JSObject;
 struct JSContext;
 
 namespace mozilla {
 
 class ErrorResult;
-class MediaLargeByteBuffer;
+class MediaByteBuffer;
 template <typename T> class AsyncEventRunner;
 class TrackBuffersManager;
 
 namespace dom {
 
 using media::TimeUnit;
 using media::TimeIntervals;
 
@@ -152,21 +152,21 @@ private:
   void BufferAppend(uint32_t aAppendID);
 
   // Implement the "Append Error Algorithm".
   // Will call endOfStream() with "decode" error if aDecodeError is true.
   // 3.5.3 Append Error Algorithm
   // http://w3c.github.io/media-source/#sourcebuffer-append-error
   void AppendError(bool aDecoderError);
 
-  // Implements the "Prepare Append Algorithm". Returns MediaLargeByteBuffer object
+  // Implements the "Prepare Append Algorithm". Returns MediaByteBuffer object
   // on success or nullptr (with aRv set) on error.
-  already_AddRefed<MediaLargeByteBuffer> PrepareAppend(const uint8_t* aData,
-                                                       uint32_t aLength,
-                                                       ErrorResult& aRv);
+  already_AddRefed<MediaByteBuffer> PrepareAppend(const uint8_t* aData,
+                                                  uint32_t aLength,
+                                                  ErrorResult& aRv);
 
   void AppendDataCompletedWithSuccess(bool aHasActiveTracks);
   void AppendDataErrored(nsresult aError);
 
   // Set timestampOffset, must be called on the main thread.
   void SetTimestampOffset(const TimeUnit& aTimestampOffset);
 
   nsRefPtr<MediaSource> mMediaSource;
--- a/dom/media/mediasource/SourceBufferContentManager.h
+++ b/dom/media/mediasource/SourceBufferContentManager.h
@@ -28,17 +28,17 @@ public:
 
   static already_AddRefed<SourceBufferContentManager>
   CreateManager(dom::SourceBuffer* aParent, MediaSourceDecoder* aParentDecoder,
                 const nsACString& aType);
 
   // Add data to the end of the input buffer.
   // Returns false if the append failed.
   virtual bool
-  AppendData(MediaLargeByteBuffer* aData, TimeUnit aTimestampOffset) = 0;
+  AppendData(MediaByteBuffer* aData, TimeUnit aTimestampOffset) = 0;
 
   // Run MSE Buffer Append Algorithm
   // 3.5.5 Buffer Append Algorithm.
   // http://w3c.github.io/media-source/index.html#sourcebuffer-buffer-append
   virtual nsRefPtr<AppendPromise> BufferAppend() = 0;
 
   // Abort any pending AppendData.
   virtual void AbortAppendData() = 0;
--- a/dom/media/mediasource/SourceBufferResource.cpp
+++ b/dom/media/mediasource/SourceBufferResource.cpp
@@ -207,17 +207,17 @@ uint32_t
 SourceBufferResource::EvictAll()
 {
   SBR_DEBUG("EvictAll()");
   ReentrantMonitorAutoEnter mon(mMonitor);
   return mInputBuffer.EvictAll();
 }
 
 void
-SourceBufferResource::AppendData(MediaLargeByteBuffer* aData)
+SourceBufferResource::AppendData(MediaByteBuffer* aData)
 {
   SBR_DEBUG("AppendData(aData=%p, aLength=%u)",
             aData->Elements(), aData->Length());
   ReentrantMonitorAutoEnter mon(mMonitor);
   mInputBuffer.AppendItem(aData);
   mEnded = false;
   mon.NotifyAll();
 }
--- a/dom/media/mediasource/SourceBufferResource.h
+++ b/dom/media/mediasource/SourceBufferResource.h
@@ -22,17 +22,17 @@
 
 #define UNIMPLEMENTED() { /* Logging this is too spammy to do by default */ }
 
 class nsIStreamListener;
 
 namespace mozilla {
 
 class MediaDecoder;
-class MediaLargeByteBuffer;
+class MediaByteBuffer;
 
 namespace dom {
 
 class SourceBuffer;
 
 }  // namespace dom
 
 class SourceBufferResource final : public MediaResource
@@ -98,17 +98,17 @@ public:
 
   virtual size_t SizeOfIncludingThis(
                       MallocSizeOf aMallocSizeOf) const override
   {
     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   }
 
   // Used by SourceBuffer.
-  void AppendData(MediaLargeByteBuffer* aData);
+  void AppendData(MediaByteBuffer* aData);
   void Ended();
   bool IsEnded()
   {
     ReentrantMonitorAutoEnter mon(mMonitor);
     return mEnded;
   }
   // Remove data from resource if it holds more than the threshold
   // number of bytes. Returns amount evicted.
--- a/dom/media/mediasource/TrackBuffer.cpp
+++ b/dom/media/mediasource/TrackBuffer.cpp
@@ -134,17 +134,17 @@ TrackBuffer::ContinueShutdown()
   MOZ_ASSERT(!mCurrentDecoder, "Detach() should have been called");
   mInitializedDecoders.Clear();
   mParentDecoder = nullptr;
 
   mShutdownPromise.Resolve(true, __func__);
 }
 
 bool
-TrackBuffer::AppendData(MediaLargeByteBuffer* aData, TimeUnit aTimestampOffset)
+TrackBuffer::AppendData(MediaByteBuffer* aData, TimeUnit aTimestampOffset)
 {
   MOZ_ASSERT(NS_IsMainThread());
   mInputBuffer = aData;
   mTimestampOffset = aTimestampOffset;
   return true;
 }
 
 nsRefPtr<TrackBuffer::AppendPromise>
@@ -157,17 +157,17 @@ TrackBuffer::BufferAppend()
   if (mInputBuffer->IsEmpty()) {
     return AppendPromise::CreateAndResolve(false, __func__);
   }
 
   DecodersToInitialize decoders(this);
   nsRefPtr<AppendPromise> p = mInitializationPromise.Ensure(__func__);
   bool hadInitData = mParser->HasInitData();
   bool hadCompleteInitData = mParser->HasCompleteInitData();
-  nsRefPtr<MediaLargeByteBuffer> oldInit = mParser->InitData();
+  nsRefPtr<MediaByteBuffer> oldInit = mParser->InitData();
   bool newInitData = mParser->IsInitSegmentPresent(mInputBuffer);
 
   // TODO: Run more of the buffer append algorithm asynchronously.
   if (newInitData) {
     MSE_DEBUG("New initialization segment.");
   } else if (!hadInitData) {
     MSE_DEBUG("Non-init segment appended during initialization.");
     mInitializationPromise.Reject(NS_ERROR_FAILURE, __func__);
@@ -257,17 +257,17 @@ TrackBuffer::BufferAppend()
   // required when data is appended.
   NotifyTimeRangesChanged();
 
   mInitializationPromise.Resolve(HasInitSegment(), __func__);
   return p;
 }
 
 bool
-TrackBuffer::AppendDataToCurrentResource(MediaLargeByteBuffer* aData, uint32_t aDuration)
+TrackBuffer::AppendDataToCurrentResource(MediaByteBuffer* aData, uint32_t aDuration)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!mCurrentDecoder) {
     return false;
   }
 
   SourceBufferResource* resource = mCurrentDecoder->GetResource();
   int64_t appendOffset = resource->GetLength();
@@ -719,17 +719,17 @@ TrackBuffer::OnMetadataRead(MetadataHold
   }
   if (mCurrentDecoder != aDecoder) {
     MSE_DEBUG("append was cancelled. Aborting initialization.");
     return;
   }
 
   // Adding an empty buffer will reopen the SourceBufferResource
   if (!aWasEnded) {
-    nsRefPtr<MediaLargeByteBuffer> emptyBuffer = new MediaLargeByteBuffer;
+    nsRefPtr<MediaByteBuffer> emptyBuffer = new MediaByteBuffer;
     aDecoder->GetResource()->AppendData(emptyBuffer);
   }
   // HACK END.
 
   MediaDecoderReader* reader = aDecoder->GetReader();
   reader->SetIdle();
 
   if (reader->IsWaitingOnCDMResource()) {
--- a/dom/media/mediasource/TrackBuffer.h
+++ b/dom/media/mediasource/TrackBuffer.h
@@ -17,25 +17,25 @@
 #include "nsString.h"
 #include "nscore.h"
 #include "TimeUnits.h"
 
 namespace mozilla {
 
 class ContainerParser;
 class MediaSourceDecoder;
-class MediaLargeByteBuffer;
+class MediaByteBuffer;
 
 class TrackBuffer final : public SourceBufferContentManager {
 public:
   TrackBuffer(MediaSourceDecoder* aParentDecoder, const nsACString& aType);
 
   nsRefPtr<ShutdownPromise> Shutdown();
 
-  bool AppendData(MediaLargeByteBuffer* aData, TimeUnit aTimestampOffset) override;
+  bool AppendData(MediaByteBuffer* aData, TimeUnit aTimestampOffset) override;
 
   // Append data to the current decoder.  Also responsible for calling
   // NotifyDataArrived on the decoder to keep buffered range computation up
   // to date.
   nsRefPtr<AppendPromise> BufferAppend() override;
 
   // Evicts data held in the current decoders SourceBufferResource from the
   // start of the buffer through to aPlaybackTime. aThreshold is used to
@@ -114,17 +114,17 @@ private:
   // returns it. The new decoder must be queued using QueueInitializeDecoder
   // for initialization.
   // The decoder is not considered initialized until it is added to
   // mInitializedDecoders.
   already_AddRefed<SourceBufferDecoder> NewDecoder(TimeUnit aTimestampOffset);
 
   // Helper for AppendData, ensures NotifyDataArrived is called whenever
   // data is appended to the current decoder's SourceBufferResource.
-  bool AppendDataToCurrentResource(MediaLargeByteBuffer* aData,
+  bool AppendDataToCurrentResource(MediaByteBuffer* aData,
                                    uint32_t aDuration /* microseconds */);
   // Queue on the parent's decoder task queue a call to NotifyTimeRangesChanged.
   void NotifyTimeRangesChanged();
 
   // Queue execution of InitializeDecoder on mTaskQueue.
   bool QueueInitializeDecoder(SourceBufferDecoder* aDecoder);
 
   // Runs decoder initialization including calling ReadMetadata.  Runs as an
@@ -158,17 +158,17 @@ private:
   void OnMetadataRead(MetadataHolder* aMetadata,
                       SourceBufferDecoder* aDecoder,
                       bool aWasEnded);
 
   void OnMetadataNotRead(ReadMetadataFailureReason aReason,
                          SourceBufferDecoder* aDecoder);
 
   nsAutoPtr<ContainerParser> mParser;
-  nsRefPtr<MediaLargeByteBuffer> mInputBuffer;
+  nsRefPtr<MediaByteBuffer> mInputBuffer;
 
   // A task queue using the shared media thread pool.  Used exclusively to
   // initialize (i.e. call ReadMetadata on) decoders as they are created via
   // NewDecoder.
   RefPtr<MediaTaskQueue> mTaskQueue;
 
   // All of the decoders managed by this TrackBuffer.  Access protected by
   // mParentDecoder's monitor.
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -33,17 +33,17 @@ AppendStateToStr(TrackBuffersManager::Ap
     case TrackBuffersManager::AppendState::PARSING_MEDIA_SEGMENT:
       return "PARSING_MEDIA_SEGMENT";
     default:
       return "IMPOSSIBLE";
   }
 }
 
 TrackBuffersManager::TrackBuffersManager(dom::SourceBuffer* aParent, MediaSourceDecoder* aParentDecoder, const nsACString& aType)
-  : mInputBuffer(new MediaLargeByteBuffer)
+  : mInputBuffer(new MediaByteBuffer)
   , mAppendState(AppendState::WAITING_FOR_SEGMENT)
   , mBufferFull(false)
   , mFirstInitializationSegmentReceived(false)
   , mActiveTrack(false)
   , mType(aType)
   , mParser(ContainerParser::CreateForMIMEType(aType))
   , mProcessedInput(0)
   , mAppendRunning(false)
@@ -60,17 +60,17 @@ TrackBuffersManager::TrackBuffersManager
   nsCOMPtr<nsIRunnable> task =
     NS_NewRunnableFunction([self] () {
       self->mMediaSourceDuration.Connect(self->mParentDecoder->CanonicalExplicitDuration());
     });
   GetTaskQueue()->Dispatch(task.forget());
 }
 
 bool
-TrackBuffersManager::AppendData(MediaLargeByteBuffer* aData,
+TrackBuffersManager::AppendData(MediaByteBuffer* aData,
                                 TimeUnit aTimestampOffset)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MSE_DEBUG("Appending %lld bytes", aData->Length());
 
   mEnded = false;
   nsCOMPtr<nsIRunnable> task =
     NS_NewRunnableMethodWithArg<IncomingBuffer>(
@@ -311,23 +311,23 @@ TrackBuffersManager::CompleteResetParser
     mCurrentInputBuffer = new SourceBufferResource(mType);
   }
 
   // We could be left with a demuxer in an unusable state. It needs to be
   // recreated. We store in the InputBuffer an init segment which will be parsed
   // during the next Segment Parser Loop and a new demuxer will be created and
   // initialized.
   if (mFirstInitializationSegmentReceived) {
-    nsRefPtr<MediaLargeByteBuffer> initData = mParser->InitData();
+    nsRefPtr<MediaByteBuffer> initData = mParser->InitData();
     MOZ_ASSERT(initData->Length(), "we must have an init segment");
     // The aim here is really to destroy our current demuxer.
     CreateDemuxerforMIMEType();
     // Recreate our input buffer. We can't directly assign the initData buffer
     // to mInputBuffer as it will get modified in the Segment Parser Loop.
-    mInputBuffer = new MediaLargeByteBuffer;
+    mInputBuffer = new MediaByteBuffer;
     MOZ_ALWAYS_TRUE(mInputBuffer->AppendElements(*initData, fallible));
   }
   RecreateParser();
 
   // 7. Set append state to WAITING_FOR_SEGMENT.
   SetAppendState(AppendState::WAITING_FOR_SEGMENT);
 }
 
@@ -922,17 +922,17 @@ TrackBuffersManager::CodedFrameProcessin
   uint32_t length;
   if (mediaRange.IsNull()) {
     length = mInputBuffer->Length();
     mCurrentInputBuffer->AppendData(mInputBuffer);
     mInputBuffer = nullptr;
   } else {
     // The mediaRange is offset by the init segment position previously added.
     length = mediaRange.mEnd - (mProcessedInput - mInputBuffer->Length());
-    nsRefPtr<MediaLargeByteBuffer> segment = new MediaLargeByteBuffer;
+    nsRefPtr<MediaByteBuffer> segment = new MediaByteBuffer;
     MOZ_ASSERT(mInputBuffer->Length() >= length);
     if (!segment->AppendElements(mInputBuffer->Elements(), length, fallible)) {
       return CodedFrameProcessingPromise::CreateAndReject(NS_ERROR_OUT_OF_MEMORY, __func__);
     }
     mCurrentInputBuffer->AppendData(segment);
     mInputBuffer->RemoveElementsAt(0, length);
   }
   mInputDemuxer->NotifyDataArrived(length, offset);
@@ -1375,17 +1375,17 @@ TrackBuffersManager::ProcessFrame(MediaR
 void
 TrackBuffersManager::RecreateParser()
 {
   MOZ_ASSERT(OnTaskQueue());
   // Recreate our parser for only the data remaining. This is required
   // as it has parsed the entire InputBuffer provided.
   // Once the old TrackBuffer/MediaSource implementation is removed
   // we can optimize this part. TODO
-  nsRefPtr<MediaLargeByteBuffer> initData = mParser->InitData();
+  nsRefPtr<MediaByteBuffer> initData = mParser->InitData();
   mParser = ContainerParser::CreateForMIMEType(mType);
   if (initData) {
     int64_t start, end;
     mParser->ParseStartAndEndTimestamps(initData, start, end);
     mProcessedInput = initData->Length();
   } else {
     mProcessedInput = 0;
   }
--- a/dom/media/mediasource/TrackBuffersManager.h
+++ b/dom/media/mediasource/TrackBuffersManager.h
@@ -15,17 +15,17 @@
 #include "mozilla/Pair.h"
 #include "nsProxyRelease.h"
 #include "nsTArray.h"
 #include "StateMirroring.h"
 
 namespace mozilla {
 
 class ContainerParser;
-class MediaLargeByteBuffer;
+class MediaByteBuffer;
 class MediaRawData;
 class MediaSourceDemuxer;
 class SourceBuffer;
 class SourceBufferResource;
 
 using media::TimeUnit;
 using media::TimeInterval;
 using media::TimeIntervals;
@@ -35,17 +35,17 @@ class TrackBuffersManager : public Sourc
 public:
   typedef MediaPromise<bool, nsresult, /* IsExclusive = */ true> CodedFrameProcessingPromise;
   typedef TrackInfo::TrackType TrackType;
   typedef MediaData::Type MediaType;
   typedef nsTArray<nsRefPtr<MediaRawData>> TrackBuffer;
 
   TrackBuffersManager(dom::SourceBuffer* aParent, MediaSourceDecoder* aParentDecoder, const nsACString& aType);
 
-  bool AppendData(MediaLargeByteBuffer* aData, TimeUnit aTimestampOffset) override;
+  bool AppendData(MediaByteBuffer* aData, TimeUnit aTimestampOffset) override;
 
   nsRefPtr<AppendPromise> BufferAppend() override;
 
   void AbortAppendData() override;
 
   void ResetParserState() override;
 
   nsRefPtr<RangeRemovalPromise> RangeRemoval(TimeUnit aStart, TimeUnit aEnd) override;
@@ -111,22 +111,22 @@ private:
   {
     return mVideoTracks.mNumTracks > 0;
   }
   bool HasAudio() const
   {
     return mAudioTracks.mNumTracks > 0;
   }
 
-  typedef Pair<nsRefPtr<MediaLargeByteBuffer>, TimeUnit> IncomingBuffer;
+  typedef Pair<nsRefPtr<MediaByteBuffer>, TimeUnit> IncomingBuffer;
   void AppendIncomingBuffer(IncomingBuffer aData);
   nsTArray<IncomingBuffer> mIncomingBuffers;
 
   // The input buffer as per http://w3c.github.io/media-source/index.html#sourcebuffer-input-buffer
-  nsRefPtr<MediaLargeByteBuffer> mInputBuffer;
+  nsRefPtr<MediaByteBuffer> mInputBuffer;
   // The current append state as per https://w3c.github.io/media-source/#sourcebuffer-append-state
   // Accessed on both the main thread and the task queue.
   Atomic<AppendState> mAppendState;
   // Buffer full flag as per https://w3c.github.io/media-source/#sourcebuffer-buffer-full-flag.
   // Accessed on both the main thread and the task queue.
   // TODO: Unused for now.
   Atomic<bool> mBufferFull;
   bool mFirstInitializationSegmentReceived;
--- a/dom/media/platforms/gonk/GonkDecoderModule.cpp
+++ b/dom/media/platforms/gonk/GonkDecoderModule.cpp
@@ -63,11 +63,12 @@ GonkDecoderModule::DecoderNeedsConversio
 bool
 GonkDecoderModule::SupportsMimeType(const nsACString& aMimeType)
 {
   return aMimeType.EqualsLiteral("audio/mp4a-latm") ||
     aMimeType.EqualsLiteral("audio/3gpp") ||
     aMimeType.EqualsLiteral("audio/amr-wb") ||
     aMimeType.EqualsLiteral("video/mp4") ||
     aMimeType.EqualsLiteral("video/mp4v-es") ||
-    aMimeType.EqualsLiteral("video/avc");
+    aMimeType.EqualsLiteral("video/avc") ||
+    aMimeType.EqualsLiteral("video/3gpp");
 }
 } // namespace mozilla
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -17,17 +17,19 @@
 #include "mozilla/dom/PCrashReporterParent.h"
 #include "mozilla/ipc/GeckoChildProcessHost.h"
 #include "mozilla/ipc/MessageChannel.h"
 #include "mozilla/plugins/BrowserStreamParent.h"
 #include "mozilla/plugins/PluginAsyncSurrogate.h"
 #include "mozilla/plugins/PluginBridge.h"
 #include "mozilla/plugins/PluginInstanceParent.h"
 #include "mozilla/Preferences.h"
+#ifdef MOZ_ENABLE_PROFILER_SPS
 #include "mozilla/ProfileGatherer.h"
+#endif
 #include "mozilla/ProcessHangMonitor.h"
 #include "mozilla/Services.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/unused.h"
 #include "nsAutoPtr.h"
 #include "nsCRT.h"
 #include "nsIFile.h"
 #include "nsIObserverService.h"
@@ -54,17 +56,19 @@
 #elif XP_MACOSX
 #include "PluginInterposeOSX.h"
 #include "PluginUtilsOSX.h"
 #endif
 
 using base::KillProcess;
 
 using mozilla::PluginLibrary;
+#ifdef MOZ_ENABLE_PROFILER_SPS
 using mozilla::ProfileGatherer;
+#endif
 using mozilla::ipc::MessageChannel;
 using mozilla::ipc::GeckoChildProcessHost;
 using mozilla::dom::PCrashReporterParent;
 using mozilla::dom::CrashReporterParent;
 
 using namespace mozilla;
 using namespace mozilla::plugins;
 using namespace mozilla::plugins::parent;
@@ -3101,23 +3105,26 @@ PluginModuleChromeParent::GatherAsyncPro
 void
 PluginModuleChromeParent::GatheredAsyncProfile(nsIProfileSaveEvent* aSaveEvent)
 {
     if (aSaveEvent && !mProfile.IsEmpty()) {
         aSaveEvent->AddSubProfile(mProfile.get());
         mProfile.Truncate();
     }
 }
+#endif // MOZ_ENABLE_PROFILER_SPS
 
 bool
 PluginModuleChromeParent::RecvProfile(const nsCString& aProfile)
 {
+#ifdef MOZ_ENABLE_PROFILER_SPS
     if (NS_WARN_IF(!mGatherer)) {
         return true;
     }
 
     mProfile = aProfile;
     mGatherer->GatheredOOPProfile();
     mGatherer = nullptr;
+#endif
     return true;
 }
 
-#endif
+
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -30,17 +30,19 @@
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
 
 class nsIProfileSaveEvent;
 class nsPluginTag;
 
 namespace mozilla {
+#ifdef MOZ_ENABLE_PROFILER_SPS
 class ProfileGatherer;
+#endif
 namespace dom {
 class PCrashReporterParent;
 class CrashReporterParent;
 }
 
 namespace plugins {
 //-----------------------------------------------------------------------------
 
@@ -412,18 +414,20 @@ class PluginModuleChromeParent
 
     void CachedSettingChanged();
 
     void OnEnteredCall() override;
     void OnExitedCall() override;
     void OnEnteredSyncSend() override;
     void OnExitedSyncSend() override;
 
+#ifdef  MOZ_ENABLE_PROFILER_SPS
     void GatherAsyncProfile(mozilla::ProfileGatherer* aGatherer);
     void GatheredAsyncProfile(nsIProfileSaveEvent* aSaveEvent);
+#endif
 
     virtual bool
     RecvProfile(const nsCString& aProfile) override;
 
 private:
     virtual void
     EnteredCxxStack() override;
 
@@ -575,17 +579,19 @@ private:
 
     friend class LaunchedTask;
 
     bool                mInitOnAsyncConnect;
     nsresult            mAsyncInitRv;
     NPError             mAsyncInitError;
     dom::ContentParent* mContentParent;
     nsCOMPtr<nsIObserver> mOfflineObserver;
+#ifdef MOZ_ENABLE_PROFILER_SPS
     nsRefPtr<mozilla::ProfileGatherer> mGatherer;
+#endif
     nsCString mProfile;
     bool mIsBlocklisted;
     static bool sInstantiated;
 };
 
 } // namespace plugins
 } // namespace mozilla
 
--- a/dom/tests/unit/test_geolocation_reset_accuracy.js
+++ b/dom/tests/unit/test_geolocation_reset_accuracy.js
@@ -92,16 +92,17 @@ function run_test()
   if (!runningInParent) {
     do_await_remote_message('high_acc_enabled', stop_high_accuracy_watch);
   }
 }
 
 function stop_high_accuracy_watch() {
     geolocation.clearWatch(watchID2);
     check_results();
+    do_test_finished();
 }
 
 function check_results()
 {
   if (runningInParent) {
     // check the provider was set to high accuracy during the test
     do_check_true(provider._seenHigh);
     // check the provider is not currently set to high accuracy
--- a/editor/libeditor/nsHTMLCSSUtils.cpp
+++ b/editor/libeditor/nsHTMLCSSUtils.cpp
@@ -608,22 +608,29 @@ nsHTMLCSSUtils::GetDefaultLengthUnit(nsA
   nsresult rv =
     Preferences::GetString("editor.css.default_length_unit", &aLengthUnit);
   // XXX Why don't you validate the pref value?
   if (NS_FAILED(rv)) {
     aLengthUnit.AssignLiteral("px");
   }
 }
 
-// Unfortunately, CSSStyleDeclaration::GetPropertyCSSValue is not yet implemented...
-// We need then a way to determine the number part and the unit from aString, aString
-// being the result of a GetPropertyValue query...
+// Unfortunately, CSSStyleDeclaration::GetPropertyCSSValue is not yet
+// implemented... We need then a way to determine the number part and the unit
+// from aString, aString being the result of a GetPropertyValue query...
 void
-nsHTMLCSSUtils::ParseLength(const nsAString & aString, float * aValue, nsIAtom ** aUnit)
+nsHTMLCSSUtils::ParseLength(const nsAString& aString, float* aValue,
+                            nsIAtom** aUnit)
 {
+  if (aString.IsEmpty()) {
+    *aValue = 0;
+    *aUnit = NS_NewAtom(aString).take();
+    return;
+  }
+
   nsAString::const_iterator iter;
   aString.BeginReading(iter);
 
   float a = 10.0f , b = 1.0f, value = 0;
   int8_t sign = 1;
   int32_t i = 0, j = aString.Length();
   char16_t c;
   bool floatingPointFound = false;
--- a/gfx/2d/DrawTargetCG.cpp
+++ b/gfx/2d/DrawTargetCG.cpp
@@ -1610,49 +1610,45 @@ DrawTargetCG::CopySurface(SourceSurface 
                           const IntPoint &aDestination)
 {
   if (MOZ2D_ERROR_IF(!mCg)) {
     return;
   }
 
   MarkChanged();
 
-  if (aSurface->GetType() == SurfaceType::COREGRAPHICS_IMAGE ||
-      aSurface->GetType() == SurfaceType::COREGRAPHICS_CGCONTEXT ||
-      aSurface->GetType() == SurfaceType::DATA) {
-    CGImageRef image = GetRetainedImageFromSourceSurface(aSurface);
+  CGImageRef image = GetRetainedImageFromSourceSurface(aSurface);
 
-    // XXX: it might be more efficient for us to do the copy directly if we have access to the bits
+  // XXX: it might be more efficient for us to do the copy directly if we have access to the bits
+
+  CGContextSaveGState(mCg);
+  CGContextSetCTM(mCg, mOriginalTransform);
 
-    CGContextSaveGState(mCg);
-    CGContextSetCTM(mCg, mOriginalTransform);
+  // CopySurface ignores the clip, so we need to use private API to temporarily reset it
+  CGContextResetClip(mCg);
+  CGRect destRect = CGRectMake(aDestination.x, aDestination.y,
+                               aSourceRect.width, aSourceRect.height);
+  CGContextClipToRect(mCg, destRect);
 
-    // CopySurface ignores the clip, so we need to use private API to temporarily reset it
-    CGContextResetClip(mCg);
-    CGRect destRect = CGRectMake(aDestination.x, aDestination.y,
-                                 aSourceRect.width, aSourceRect.height);
-    CGContextClipToRect(mCg, destRect);
+  CGContextSetBlendMode(mCg, kCGBlendModeCopy);
 
-    CGContextSetBlendMode(mCg, kCGBlendModeCopy);
+  CGContextScaleCTM(mCg, 1, -1);
 
-    CGContextScaleCTM(mCg, 1, -1);
-
-    CGRect flippedRect = CGRectMake(aDestination.x - aSourceRect.x, -(aDestination.y - aSourceRect.y + double(CGImageGetHeight(image))),
-                                    CGImageGetWidth(image), CGImageGetHeight(image));
+  CGRect flippedRect = CGRectMake(aDestination.x - aSourceRect.x, -(aDestination.y - aSourceRect.y + double(CGImageGetHeight(image))),
+                                  CGImageGetWidth(image), CGImageGetHeight(image));
 
-    // Quartz seems to copy A8 surfaces incorrectly if we don't initialize them
-    // to transparent first.
-    if (mFormat == SurfaceFormat::A8) {
-      CGContextClearRect(mCg, flippedRect);
-    }
-    CGContextDrawImage(mCg, flippedRect, image);
+  // Quartz seems to copy A8 surfaces incorrectly if we don't initialize them
+  // to transparent first.
+  if (mFormat == SurfaceFormat::A8) {
+    CGContextClearRect(mCg, flippedRect);
+  }
+  CGContextDrawImage(mCg, flippedRect, image);
 
-    CGContextRestoreGState(mCg);
-    CGImageRelease(image);
-  }
+  CGContextRestoreGState(mCg);
+  CGImageRelease(image);
 }
 
 void
 DrawTargetCG::DrawSurfaceWithShadow(SourceSurface *aSurface, const Point &aDest, const Color &aColor, const Point &aOffset, Float aSigma, CompositionOp aOperator)
 {
   if (MOZ2D_ERROR_IF(!mCg)) {
     return;
   }
--- a/gfx/2d/DrawTargetCairo.cpp
+++ b/gfx/2d/DrawTargetCairo.cpp
@@ -1751,16 +1751,17 @@ BorrowedXlibDrawable::Init(DrawTarget* a
     return false;
   }
 
   DrawTargetCairo* cairoDT = static_cast<DrawTargetCairo*>(aDT);
   cairo_surface_t* surf = cairoDT->mSurface;
   if (cairo_surface_get_type(surf) != CAIRO_SURFACE_TYPE_XLIB) {
     return false;
   }
+  cairo_surface_flush(surf);
 
   cairoDT->WillChange();
 
   mDisplay = cairo_xlib_surface_get_display(surf);
   mDrawable = cairo_xlib_surface_get_drawable(surf);
   mScreen = cairo_xlib_surface_get_screen(surf);
   mVisual = cairo_xlib_surface_get_visual(surf);
   mXRenderFormat = cairo_xlib_surface_get_xrender_format(surf);
@@ -1769,16 +1770,19 @@ BorrowedXlibDrawable::Init(DrawTarget* a
 #else
   return false;
 #endif
 }
 
 void
 BorrowedXlibDrawable::Finish()
 {
+  DrawTargetCairo* cairoDT = static_cast<DrawTargetCairo*>(mDT);
+  cairo_surface_t* surf = cairoDT->mSurface;
+  cairo_surface_mark_dirty(surf);
   if (mDrawable) {
     mDrawable = None;
   }
 }
 #endif
 
 }
 }
--- a/gfx/2d/DrawTargetD2D1.cpp
+++ b/gfx/2d/DrawTargetD2D1.cpp
@@ -1448,39 +1448,56 @@ DrawTargetD2D1::CreateBrushForPattern(co
     if (!pat->mSurface) {
       gfxDebug() << "No source surface specified for surface pattern";
       return CreateTransparentBlackBrush();
     }
 
     D2D1_RECT_F samplingBounds;
     Matrix mat = pat->mMatrix;
 
-    bool useSamplingRect = false;
-    if (!pat->mSamplingRect.IsEmpty() &&
-        (pat->mSurface->GetType() == SurfaceType::D2D1_1_IMAGE)) {
-      samplingBounds = D2DRect(pat->mSamplingRect);
-      mat.PreTranslate(pat->mSamplingRect.x, pat->mSamplingRect.y);
-    } else if (!pat->mSamplingRect.IsEmpty()) {
-      // We will do a partial upload of the sampling restricted area from GetImageForSurface.
-      samplingBounds = D2D1::RectF(0, 0, pat->mSamplingRect.width, pat->mSamplingRect.height);
-    } else {
-      samplingBounds = D2D1::RectF(0, 0,
-                                   Float(pat->mSurface->GetSize().width),
-                                   Float(pat->mSurface->GetSize().height));
-    }
-
     MOZ_ASSERT(pat->mSurface->IsValid());
 
-    RefPtr<ID2D1ImageBrush> imageBrush;
     RefPtr<ID2D1Image> image = GetImageForSurface(pat->mSurface, mat, pat->mExtendMode, !pat->mSamplingRect.IsEmpty() ? &pat->mSamplingRect : nullptr);
 
     if (!image) {
       return CreateTransparentBlackBrush();
     }
 
+    bool useSamplingRect = false;
+    if (pat->mSamplingRect.IsEmpty()) {
+      RefPtr<ID2D1Bitmap> bitmap;
+      image->QueryInterface((ID2D1Bitmap**)byRef(bitmap));
+      if (bitmap) {
+        RefPtr<ID2D1BitmapBrush> bitmapBrush;
+        mDC->CreateBitmapBrush(bitmap,
+                               D2D1::BitmapBrushProperties(D2DExtend(pat->mExtendMode),
+                                                           D2DExtend(pat->mExtendMode),
+                                                           D2DFilter(pat->mFilter)),
+                               D2D1::BrushProperties(aAlpha, D2DMatrix(mat)),
+                               byRef(bitmapBrush));
+        if (!bitmapBrush) {
+          gfxWarning() << "Couldn't create bitmap brush!";
+          return CreateTransparentBlackBrush();
+        }
+        return bitmapBrush.forget();
+      }
+    }
+
+    RefPtr<ID2D1ImageBrush> imageBrush;
+    if (pat->mSamplingRect.IsEmpty()) {
+      samplingBounds = D2D1::RectF(0, 0,
+                                   Float(pat->mSurface->GetSize().width),
+                                   Float(pat->mSurface->GetSize().height));
+    } else if (pat->mSurface->GetType() == SurfaceType::D2D1_1_IMAGE) {
+      samplingBounds = D2DRect(pat->mSamplingRect);
+      mat.PreTranslate(pat->mSamplingRect.x, pat->mSamplingRect.y);
+    } else {
+      // We will do a partial upload of the sampling restricted area from GetImageForSurface.
+      samplingBounds = D2D1::RectF(0, 0, pat->mSamplingRect.width, pat->mSamplingRect.height);
+    }
     mDC->CreateImageBrush(image,
                           D2D1::ImageBrushProperties(samplingBounds,
                                                      D2DExtend(pat->mExtendMode),
                                                      D2DExtend(pat->mExtendMode),
                                                      D2DInterpolationMode(pat->mFilter)),
                           D2D1::BrushProperties(aAlpha, D2DMatrix(mat)),
                           byRef(imageBrush));
 
--- a/gfx/2d/HelpersD2D.h
+++ b/gfx/2d/HelpersD2D.h
@@ -122,16 +122,17 @@ static inline IntSize ToIntSize(const D2
 {
   return IntSize(aSize.width, aSize.height);
 }
 
 static inline SurfaceFormat ToPixelFormat(const D2D1_PIXEL_FORMAT &aFormat)
 {
   switch(aFormat.format) {
   case DXGI_FORMAT_A8_UNORM:
+  case DXGI_FORMAT_R8_UNORM:
     return SurfaceFormat::A8;
   case DXGI_FORMAT_B8G8R8A8_UNORM:
     if (aFormat.alphaMode == D2D1_ALPHA_MODE_IGNORE) {
       return SurfaceFormat::B8G8R8X8;
     } else {
       return SurfaceFormat::B8G8R8A8;
     }
   default:
--- a/gfx/layers/IMFYCbCrImage.cpp
+++ b/gfx/layers/IMFYCbCrImage.cpp
@@ -232,17 +232,17 @@ IMFYCbCrImage::GetTextureClient(Composit
 
   if (mTextureClient) {
     return mTextureClient;
   }
 
   RefPtr<ID3D11DeviceContext> ctx;
   device->GetImmediateContext(byRef(ctx));
 
-  CD3D11_TEXTURE2D_DESC newDesc(DXGI_FORMAT_A8_UNORM,
+  CD3D11_TEXTURE2D_DESC newDesc(DXGI_FORMAT_R8_UNORM,
                                 mData.mYSize.width, mData.mYSize.height, 1, 1);
 
   newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
 
   RefPtr<ID3D11Texture2D> textureY;
   HRESULT hr = device->CreateTexture2D(&newDesc, nullptr, byRef(textureY));
   NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
 
--- a/gfx/layers/d3d11/CompositorD3D11.hlsl
+++ b/gfx/layers/d3d11/CompositorD3D11.hlsl
@@ -154,35 +154,35 @@ VS_MASK_3D_OUTPUT LayerQuadMask3DVS(cons
   outp.vTexCoords = TexCoords(aVertex.vPosition.xy);
 
   return outp;
 }
 
 float4 RGBAShaderMask(const VS_MASK_OUTPUT aVertex) : SV_Target
 {
   float2 maskCoords = aVertex.vMaskCoords;
-  float mask = tMask.Sample(sSampler, maskCoords).a;
+  float mask = tMask.Sample(sSampler, maskCoords).r;
   return tRGB.Sample(sSampler, aVertex.vTexCoords) * fLayerOpacity * mask;
 }
 
 float4 RGBAShaderMask3D(const VS_MASK_3D_OUTPUT aVertex) : SV_Target
 {
   float2 maskCoords = aVertex.vMaskCoords.xy / aVertex.vMaskCoords.z;
-  float mask = tMask.Sample(LayerTextureSamplerLinear, maskCoords).a;
+  float mask = tMask.Sample(LayerTextureSamplerLinear, maskCoords).r;
   return tRGB.Sample(sSampler, aVertex.vTexCoords) * fLayerOpacity * mask;
 }
 
 float4 RGBShaderMask(const VS_MASK_OUTPUT aVertex) : SV_Target
 {
   float4 result;
   result = tRGB.Sample(sSampler, aVertex.vTexCoords) * fLayerOpacity;
   result.a = fLayerOpacity;
 
   float2 maskCoords = aVertex.vMaskCoords;
-  float mask = tMask.Sample(sSampler, maskCoords).a;
+  float mask = tMask.Sample(sSampler, maskCoords).r;
   return result * mask;
 }
 
 /* From Rec601:
 [R]   [1.1643835616438356,  0.0,                 1.5960267857142858]      [ Y -  16]
 [G] = [1.1643835616438358, -0.3917622900949137, -0.8129676472377708]    x [Cb - 128]
 [B]   [1.1643835616438356,  2.017232142857143,   8.862867620416422e-17]   [Cr - 128]
 
@@ -191,56 +191,56 @@ For [0,1] instead of [0,255], and to 5 p
 [G] = [1.16438, -0.39176, -0.81297] x [Cb - 0.50196]
 [B]   [1.16438,  2.01723,  0.00000]   [Cr - 0.50196]
 */
 float4 CalculateYCbCrColor(const float2 aTexCoords)
 {
   float4 yuv;
   float4 color;
 
-  yuv.r = tCr.Sample(sSampler, aTexCoords).a - 0.50196;
-  yuv.g = tY.Sample(sSampler, aTexCoords).a  - 0.06275;
-  yuv.b = tCb.Sample(sSampler, aTexCoords).a - 0.50196;
+  yuv.r = tCr.Sample(sSampler, aTexCoords).r - 0.50196;
+  yuv.g = tY.Sample(sSampler, aTexCoords).r  - 0.06275;
+  yuv.b = tCb.Sample(sSampler, aTexCoords).r - 0.50196;
 
   color.r = yuv.g * 1.16438 + yuv.r * 1.59603;
   color.g = yuv.g * 1.16438 - 0.81297 * yuv.r - 0.39176 * yuv.b;
   color.b = yuv.g * 1.16438 + yuv.b * 2.01723;
   color.a = 1.0f;
 
   return color;
 }
 
 float4 YCbCrShaderMask(const VS_MASK_OUTPUT aVertex) : SV_Target
 {
   float2 maskCoords = aVertex.vMaskCoords;
-  float mask = tMask.Sample(sSampler, maskCoords).a;
+  float mask = tMask.Sample(sSampler, maskCoords).r;
 
   return CalculateYCbCrColor(aVertex.vTexCoords) * fLayerOpacity * mask;
 }
 
 PS_OUTPUT ComponentAlphaShaderMask(const VS_MASK_OUTPUT aVertex) : SV_Target
 {
   PS_OUTPUT result;
 
   result.vSrc = tRGB.Sample(sSampler, aVertex.vTexCoords);
   result.vAlpha = 1.0 - tRGBWhite.Sample(sSampler, aVertex.vTexCoords) + result.vSrc;
   result.vSrc.a = result.vAlpha.g;
 
   float2 maskCoords = aVertex.vMaskCoords;
-  float mask = tMask.Sample(sSampler, maskCoords).a;
+  float mask = tMask.Sample(sSampler, maskCoords).r;
   result.vSrc *= fLayerOpacity * mask;
   result.vAlpha *= fLayerOpacity * mask;
 
   return result;
 }
 
 float4 SolidColorShaderMask(const VS_MASK_OUTPUT aVertex) : SV_Target
 {
   float2 maskCoords = aVertex.vMaskCoords;
-  float mask = tMask.Sample(sSampler, maskCoords).a;
+  float mask = tMask.Sample(sSampler, maskCoords).r;
   return fLayerColor * mask;
 }
 
 /*
  *  Un-masked versions
  *************************************************************
  */
 float4 RGBAShader(const VS_OUTPUT aVertex) : SV_Target
--- a/gfx/layers/d3d11/CompositorD3D11Shaders.h
+++ b/gfx/layers/d3d11/CompositorD3D11Shaders.h
@@ -1,11 +1,15 @@
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+//
+//   fxc -nologo -Tvs_4_0_level_9_3 CompositorD3D11.hlsl -ELayerQuadVS
+//    -VnLayerQuadVS -FhtmpShaderHeader
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4x4 mLayerTransform;          // Offset:    0 Size:    64
@@ -25,27 +29,27 @@
 // Name                                 Type  Format         Dim Slot Elements
 // ------------------------------ ---------- ------- ----------- ---- --------
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// POSITION                 0   xy          0     NONE   float   xy  
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// POSITION                 0   xy          0     NONE  float   xy  
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Position              0   xyzw        0      POS   float   xyzw
-// TEXCOORD                 0   xy          1     NONE   float   xy  
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Position              0   xyzw        0      POS  float   xyzw
+// TEXCOORD                 0   xy          1     NONE  float   xy  
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c1         cb0             0         2  ( FLT, FLT, FLT, FLT)
 // c3         cb0             3         8  ( FLT, FLT, FLT, FLT)
@@ -98,20 +102,20 @@ mad r1.xyzw, cb0[6].xyzw, r0.zzzz, r1.xy
 mad o0.xyzw, cb0[7].xyzw, r0.wwww, r1.xyzw
 mad o1.xy, v0.xyxx, cb0[9].zwzz, cb0[9].xyxx
 ret 
 // Approximately 13 instruction slots used
 #endif
 
 const BYTE LayerQuadVS[] =
 {
-     68,  88,  66,  67, 200, 251, 
-     64, 251, 166, 240, 101, 137, 
-    191, 140,  75, 217,   9, 168, 
-     61, 163,   1,   0,   0,   0, 
+     68,  88,  66,  67,  26, 156, 
+     32, 249,  73, 220,  32,  91, 
+     64, 185, 136, 143, 133, 249, 
+    140, 206,   1,   0,   0,   0, 
     180,   6,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     152,   1,   0,   0, 160,   3, 
       0,   0,  28,   4,   0,   0, 
      40,   6,   0,   0,  92,   6, 
       0,   0,  65, 111, 110,  57, 
      88,   1,   0,   0,  88,   1, 
       0,   0,   0,   2, 254, 255, 
@@ -256,27 +260,27 @@ const BYTE LayerQuadVS[] =
     230, 138,  32,   0,   0,   0, 
       0,   0,   9,   0,   0,   0, 
      70, 128,  32,   0,   0,   0, 
       0,   0,   9,   0,   0,   0, 
      62,   0,   0,   1,  83,  84, 
      65,  84, 116,   0,   0,   0, 
      13,   0,   0,   0,   2,   0, 
       0,   0,   0,   0,   0,   0, 
-      3,   0,   0,   0,  12,   0, 
+      3,   0,   0,   0,   6,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   1,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   1,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,  82,  68,  69,  70, 
       4,   2,   0,   0,   1,   0, 
@@ -357,20 +361,20 @@ const BYTE LayerQuadVS[] =
       0, 171,   0,   0,   3,   0, 
       1,   0,   1,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
      77, 105,  99, 114, 111, 115, 
     111, 102, 116,  32,  40,  82, 
      41,  32,  72,  76,  83,  76, 
      32,  83, 104,  97, 100, 101, 
     114,  32,  67, 111, 109, 112, 
-    105, 108, 101, 114,  32,  54, 
-     46,  51,  46,  57,  54,  48, 
-     48,  46,  49,  54,  51,  56, 
-     52,   0, 171, 171,  73,  83, 
+    105, 108, 101, 114,  32,  57, 
+     46,  50,  57,  46,  57,  53, 
+     50,  46,  51,  49,  49,  49, 
+      0, 171, 171, 171,  73,  83, 
      71,  78,  44,   0,   0,   0, 
       1,   0,   0,   0,   8,   0, 
       0,   0,  32,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,   3,   3, 
       0,   0,  80,  79,  83,  73, 
      84,  73,  79,  78,   0, 171, 
@@ -387,17 +391,21 @@ const BYTE LayerQuadVS[] =
       0,   0,   3,  12,   0,   0, 
      83,  86,  95,  80, 111, 115, 
     105, 116, 105, 111, 110,   0, 
      84,  69,  88,  67,  79,  79, 
      82,  68,   0, 171, 171, 171
 };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+//
+//   fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -ESolidColorShader
+//    -VnSolidColorShader -FhtmpShaderHeader
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16
@@ -417,27 +425,27 @@ const BYTE LayerQuadVS[] =
 // Name                                 Type  Format         Dim Slot Elements
 // ------------------------------ ---------- ------- ----------- ---- --------
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Position              0   xyzw        0      POS   float       
-// TEXCOORD                 0   xy          1     NONE   float       
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Position              0   xyzw        0      POS  float       
+// TEXCOORD                 0   xy          1     NONE  float       
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Target                0   xyzw        0   TARGET   float   xyzw
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Target                0   xyzw        0   TARGET  float   xyzw
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c0         cb0             0         1  ( FLT, FLT, FLT, FLT)
 //
@@ -453,20 +461,20 @@ dcl_constantbuffer cb0[1], immediateInde
 dcl_output o0.xyzw
 mov o0.xyzw, cb0[0].xyzw
 ret 
 // Approximately 2 instruction slots used
 #endif
 
 const BYTE SolidColorShader[] =
 {
-     68,  88,  66,  67,  30, 148, 
-    104, 202, 165,  39,  58, 182, 
-    100, 205,  95, 195,  52, 137, 
-    197, 241,   1,   0,   0,   0, 
+     68,  88,  66,  67, 204,   8, 
+      5, 100,  51,  20, 107, 176, 
+    111, 165, 149, 245, 134, 187, 
+     83,  96,   1,   0,   0,   0, 
     224,   3,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     132,   0,   0,   0, 204,   0, 
       0,   0,  72,   1,   0,   0, 
      84,   3,   0,   0, 172,   3, 
       0,   0,  65, 111, 110,  57, 
      68,   0,   0,   0,  68,   0, 
       0,   0,   0,   2, 255, 255, 
@@ -592,19 +600,19 @@ const BYTE SolidColorShader[] =
      81, 117,  97, 100,   0, 118, 
      77,  97, 115, 107,  81, 117, 
      97, 100,   0,  77, 105,  99, 
     114, 111, 115, 111, 102, 116, 
      32,  40,  82,  41,  32,  72, 
      76,  83,  76,  32,  83, 104, 
      97, 100, 101, 114,  32,  67, 
     111, 109, 112, 105, 108, 101, 
-    114,  32,  54,  46,  51,  46, 
-     57,  54,  48,  48,  46,  49, 
-     54,  51,  56,  52,   0, 171, 
+    114,  32,  57,  46,  50,  57, 
+     46,  57,  53,  50,  46,  51, 
+     49,  49,  49,   0, 171, 171, 
      73,  83,  71,  78,  80,   0, 
       0,   0,   2,   0,   0,   0, 
       8,   0,   0,   0,  56,   0, 
       0,   0,   0,   0,   0,   0, 
       1,   0,   0,   0,   3,   0, 
       0,   0,   0,   0,   0,   0, 
      15,   0,   0,   0,  68,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -622,17 +630,21 @@ const BYTE SolidColorShader[] =
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,  15,   0, 
       0,   0,  83,  86,  95,  84, 
      97, 114, 103, 101, 116,   0, 
     171, 171
 };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+//
+//   fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -ERGBShader
+//    -VnRGBShader -FhtmpShaderHeader
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16 [unused]
@@ -654,27 +666,27 @@ const BYTE SolidColorShader[] =
 // sSampler                          sampler      NA          NA    0        1
 // tRGB                              texture  float4          2d    0        1
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Position              0   xyzw        0      POS   float       
-// TEXCOORD                 0   xy          1     NONE   float   xy  
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Position              0   xyzw        0      POS  float       
+// TEXCOORD                 0   xy          1     NONE  float   xy  
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Target                0   xyzw        0   TARGET   float   xyzw
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Target                0   xyzw        0   TARGET  float   xyzw
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c0         cb0             1         1  ( FLT, FLT, FLT, FLT)
 //
@@ -708,20 +720,20 @@ sample r0.xyzw, v1.xyxx, t0.xyzw, s0
 mul o0.xyz, r0.xyzx, cb0[1].xxxx
 mov o0.w, cb0[1].x
 ret 
 // Approximately 4 instruction slots used
 #endif
 
 const BYTE RGBShader[] =
 {
-     68,  88,  66,  67, 239, 198, 
-     87, 206,  69,  92, 245,  30, 
-    125, 195, 239,  77,  37, 241, 
-    175, 187,   1,   0,   0,   0, 
+     68,  88,  66,  67,  20, 109, 
+    176, 198,  26, 112, 108, 185, 
+    246, 240, 143,  18,  57, 236, 
+    126,  68,   1,   0,   0,   0, 
     232,   4,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     204,   0,   0,   0, 136,   1, 
       0,   0,   4,   2,   0,   0, 
      92,   4,   0,   0, 180,   4, 
       0,   0,  65, 111, 110,  57, 
     140,   0,   0,   0, 140,   0, 
       0,   0,   0,   2, 255, 255, 
@@ -891,19 +903,19 @@ const BYTE RGBShader[] =
      81, 117,  97, 100,   0, 118, 
      77,  97, 115, 107,  81, 117, 
      97, 100,   0,  77, 105,  99, 
     114, 111, 115, 111, 102, 116, 
      32,  40,  82,  41,  32,  72, 
      76,  83,  76,  32,  83, 104, 
      97, 100, 101, 114,  32,  67, 
     111, 109, 112, 105, 108, 101, 
-    114,  32,  54,  46,  51,  46, 
-     57,  54,  48,  48,  46,  49, 
-     54,  51,  56,  52,   0, 171, 
+    114,  32,  57,  46,  50,  57, 
+     46,  57,  53,  50,  46,  51, 
+     49,  49,  49,   0, 171, 171, 
      73,  83,  71,  78,  80,   0, 
       0,   0,   2,   0,   0,   0, 
       8,   0,   0,   0,  56,   0, 
       0,   0,   0,   0,   0,   0, 
       1,   0,   0,   0,   3,   0, 
       0,   0,   0,   0,   0,   0, 
      15,   0,   0,   0,  68,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -921,17 +933,21 @@ const BYTE RGBShader[] =
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,  15,   0, 
       0,   0,  83,  86,  95,  84, 
      97, 114, 103, 101, 116,   0, 
     171, 171
 };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+//
+//   fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -ERGBAShader
+//    -VnRGBAShader -FhtmpShaderHeader
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16 [unused]
@@ -953,27 +969,27 @@ const BYTE RGBShader[] =
 // sSampler                          sampler      NA          NA    0        1
 // tRGB                              texture  float4          2d    0        1
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Position              0   xyzw        0      POS   float       
-// TEXCOORD                 0   xy          1     NONE   float   xy  
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Position              0   xyzw        0      POS  float       
+// TEXCOORD                 0   xy          1     NONE  float   xy  
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Target                0   xyzw        0   TARGET   float   xyzw
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Target                0   xyzw        0   TARGET  float   xyzw
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c0         cb0             1         1  ( FLT, FLT, FLT, FLT)
 //
@@ -1005,20 +1021,20 @@ dcl_temps 1
 sample r0.xyzw, v1.xyxx, t0.xyzw, s0
 mul o0.xyzw, r0.xyzw, cb0[1].xxxx
 ret 
 // Approximately 3 instruction slots used
 #endif
 
 const BYTE RGBAShader[] =
 {
-     68,  88,  66,  67, 230,  59, 
-     90,  23,  60,  77,  18, 113, 
-     14, 129, 183, 152, 233,  55, 
-    111,  42,   1,   0,   0,   0, 
+     68,  88,  66,  67, 214,  26, 
+    168, 112,  65, 151,  75,  99, 
+    196,  63, 136, 104, 158, 202, 
+    217,   7,   1,   0,   0,   0, 
     196,   4,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     192,   0,   0,   0, 100,   1, 
       0,   0, 224,   1,   0,   0, 
      56,   4,   0,   0, 144,   4, 
       0,   0,  65, 111, 110,  57, 
     128,   0,   0,   0, 128,   0, 
       0,   0,   0,   2, 255, 255, 
@@ -1182,19 +1198,19 @@ const BYTE RGBAShader[] =
      81, 117,  97, 100,   0, 118, 
      77,  97, 115, 107,  81, 117, 
      97, 100,   0,  77, 105,  99, 
     114, 111, 115, 111, 102, 116, 
      32,  40,  82,  41,  32,  72, 
      76,  83,  76,  32,  83, 104, 
      97, 100, 101, 114,  32,  67, 
     111, 109, 112, 105, 108, 101, 
-    114,  32,  54,  46,  51,  46, 
-     57,  54,  48,  48,  46,  49, 
-     54,  51,  56,  52,   0, 171, 
+    114,  32,  57,  46,  50,  57, 
+     46,  57,  53,  50,  46,  51, 
+     49,  49,  49,   0, 171, 171, 
      73,  83,  71,  78,  80,   0, 
       0,   0,   2,   0,   0,   0, 
       8,   0,   0,   0,  56,   0, 
       0,   0,   0,   0,   0,   0, 
       1,   0,   0,   0,   3,   0, 
       0,   0,   0,   0,   0,   0, 
      15,   0,   0,   0,  68,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -1212,17 +1228,21 @@ const BYTE RGBAShader[] =
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,  15,   0, 
       0,   0,  83,  86,  95,  84, 
      97, 114, 103, 101, 116,   0, 
     171, 171
 };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+//
+//   fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -EComponentAlphaShader
+//    -VnComponentAlphaShader -FhtmpShaderHeader
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16 [unused]
@@ -1245,28 +1265,28 @@ const BYTE RGBAShader[] =
 // tRGB                              texture  float4          2d    0        1
 // tRGBWhite                         texture  float4          2d    1        1
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Position              0   xyzw        0      POS   float       
-// TEXCOORD                 0   xy          1     NONE   float   xy  
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Position              0   xyzw        0      POS  float       
+// TEXCOORD                 0   xy          1     NONE  float   xy  
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Target                0   xyzw        0   TARGET   float   xyzw
-// SV_Target                1   xyzw        1   TARGET   float   xyzw
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Target                0   xyzw        0   TARGET  float   xyzw
+// SV_Target                1   xyzw        1   TARGET  float   xyzw
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c0         cb0             1         1  ( FLT, FLT, FLT, FLT)
 //
@@ -1314,20 +1334,20 @@ mov r1.w, r0.y
 mul o1.xyzw, r0.xyzw, cb0[1].xxxx
 mul o0.xyzw, r1.xyzw, cb0[1].xxxx
 ret 
 // Approximately 8 instruction slots used
 #endif
 
 const BYTE ComponentAlphaShader[] =
 {
-     68,  88,  66,  67, 186, 162, 
-     72,  42,  69,  36, 160,  68, 
-    108, 121, 216, 238, 108,  37, 
-      6, 145,   1,   0,   0,   0, 
+     68,  88,  66,  67, 207, 238, 
+    180, 151, 111,  52, 137,   3, 
+     45, 243, 229, 223,  99, 172, 
+     89,   3,   1,   0,   0,   0, 
      68,   6,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
      64,   1,   0,   0, 160,   2, 
       0,   0,  28,   3,   0,   0, 
     160,   5,   0,   0, 248,   5, 
       0,   0,  65, 111, 110,  57, 
       0,   1,   0,   0,   0,   1, 
       0,   0,   0,   2, 255, 255, 
@@ -1440,17 +1460,17 @@ const BYTE ComponentAlphaShader[] =
       1,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   2,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
-      1,   0,   0,   0,   0,   0, 
+      2,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,  82,  68, 
      69,  70, 124,   2,   0,   0, 
       1,   0,   0,   0, 192,   0, 
@@ -1551,19 +1571,19 @@ const BYTE ComponentAlphaShader[] =
      81, 117,  97, 100,   0, 118, 
      77,  97, 115, 107,  81, 117, 
      97, 100,   0,  77, 105,  99, 
     114, 111, 115, 111, 102, 116, 
      32,  40,  82,  41,  32,  72, 
      76,  83,  76,  32,  83, 104, 
      97, 100, 101, 114,  32,  67, 
     111, 109, 112, 105, 108, 101, 
-    114,  32,  54,  46,  51,  46, 
-     57,  54,  48,  48,  46,  49, 
-     54,  51,  56,  52,   0, 171, 
+    114,  32,  57,  46,  50,  57, 
+     46,  57,  53,  50,  46,  51, 
+     49,  49,  49,   0, 171, 171, 
      73,  83,  71,  78,  80,   0, 
       0,   0,   2,   0,   0,   0, 
       8,   0,   0,   0,  56,   0, 
       0,   0,   0,   0,   0,   0, 
       1,   0,   0,   0,   3,   0, 
       0,   0,   0,   0,   0,   0, 
      15,   0,   0,   0,  68,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -1585,17 +1605,21 @@ const BYTE ComponentAlphaShader[] =
       0,   0,   3,   0,   0,   0, 
       1,   0,   0,   0,  15,   0, 
       0,   0,  83,  86,  95,  84, 
      97, 114, 103, 101, 116,   0, 
     171, 171
 };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+//
+//   fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -EYCbCrShader
+//    -VnYCbCrShader -FhtmpShaderHeader
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16 [unused]
@@ -1619,27 +1643,27 @@ const BYTE ComponentAlphaShader[] =
 // tCb                               texture  float4          2d    1        1
 // tCr                               texture  float4          2d    2        1
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Position              0   xyzw        0      POS   float       
-// TEXCOORD                 0   xy          1     NONE   float   xy  
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Position              0   xyzw        0      POS  float       
+// TEXCOORD                 0   xy          1     NONE  float   xy  
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Target                0   xyzw        0   TARGET   float   xyzw
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Target                0   xyzw        0   TARGET  float   xyzw
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c0         cb0             1         1  ( FLT, FLT, FLT, FLT)
 //
@@ -1659,64 +1683,64 @@ const BYTE ComponentAlphaShader[] =
     def c1, -0.50195998, -0.0627499968, 1.59603, 0.812969983
     def c2, 1.16437995, 2.01723003, 0.391759992, 1
     dcl t0.xy
     dcl_2d s0
     dcl_2d s1
     dcl_2d s2
     texld r0, t0, s0
     texld r1, t0, s2
-    add r0.x, r1.w, c1.x
-    mul r0.xy, r0.x, c1.zwzw
-    add r0.z, r0.w, c1.y
-    mad r0.y, r0.z, c2.x, -r0.y
-    mad r1.x, r0.z, c2.x, r0.x
+    add r0.y, r1.x, c1.x
+    mul r0.yz, r0.y, c1.xzww
+    add r0.x, r0.x, c1.y
+    mad r0.z, r0.x, c2.x, -r0.z
+    mad r1.x, r0.x, c2.x, r0.y
     texld r2, t0, s1
-    add r0.x, r2.w, c1.x
-    mad r1.y, r0.x, -c2.z, r0.y
-    mul r0.x, r0.x, c2.y
-    mad r1.z, r0.z, c2.x, r0.x
+    add r0.y, r2.x, c1.x
+    mad r1.y, r0.y, -c2.z, r0.z
+    mul r0.y, r0.y, c2.y
+    mad r1.z, r0.x, c2.x, r0.y
     mov r1.w, c2.w
     mul r0, r1, c0.x
     mov oC0, r0
 
 // approximately 15 instruction slots used (3 texture, 12 arithmetic)
 ps_4_0
 dcl_constantbuffer cb0[2], immediateIndexed
 dcl_sampler s0, mode_default
 dcl_resource_texture2d (float,float,float,float) t0
 dcl_resource_texture2d (float,float,float,float) t1
 dcl_resource_texture2d (float,float,float,float) t2
 dcl_input_ps linear v1.xy
 dcl_output o0.xyzw
 dcl_temps 3
 sample r0.xyzw, v1.xyxx, t2.xyzw, s0
-add r0.x, r0.w, l(-0.501960)
+add r0.x, r0.x, l(-0.501960)
 mul r0.xy, r0.xxxx, l(1.596030, 0.812970, 0.000000, 0.000000)
 sample r1.xyzw, v1.xyxx, t0.xyzw, s0
-add r0.z, r1.w, l(-0.062750)
+add r0.z, r1.x, l(-0.062750)
 mad r0.y, r0.z, l(1.164380), -r0.y
 mad r1.x, r0.z, l(1.164380), r0.x
 sample r2.xyzw, v1.xyxx, t1.xyzw, s0
-add r0.x, r2.w, l(-0.501960)
+add r0.x, r2.x, l(-0.501960)
 mad r1.y, -r0.x, l(0.391760), r0.y
 mul r0.x, r0.x, l(2.017230)
 mad r1.z, r0.z, l(1.164380), r0.x
 mov r1.w, l(1.000000)
 mul o0.xyzw, r1.xyzw, cb0[1].xxxx
 ret 
 // Approximately 15 instruction slots used
 #endif
 
 const BYTE YCbCrShader[] =
 {
-     68,  88,  66,  67, 181, 118, 
-    100,  53, 248, 120, 136,  92, 
-     59, 190,  18, 201, 139, 224, 
-     32, 141,   1,   0,   0,   0, 
+     68,  88,  66,  67,  54,  63, 
+    153,   7,  84, 231,  22,  28, 
+    117, 160,  57,  24, 123, 163, 
+     52, 109,   1,   0,   0,   0, 
     212,   7,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     220,   1,   0,   0,  44,   4, 
       0,   0, 168,   4,   0,   0, 
      72,   7,   0,   0, 160,   7, 
       0,   0,  65, 111, 110,  57, 
     156,   1,   0,   0, 156,   1, 
       0,   0,   0,   2, 255, 255, 
@@ -1746,45 +1770,45 @@ const BYTE YCbCrShader[] =
      15, 160,  31,   0,   0,   2, 
       0,   0,   0, 144,   2,   8, 
      15, 160,  66,   0,   0,   3, 
       0,   0,  15, 128,   0,   0, 
     228, 176,   0,   8, 228, 160, 
      66,   0,   0,   3,   1,   0, 
      15, 128,   0,   0, 228, 176, 
       2,   8, 228, 160,   2,   0, 
-      0,   3,   0,   0,   1, 128, 
-      1,   0, 255, 128,   1,   0, 
+      0,   3,   0,   0,   2, 128, 
+      1,   0,   0, 128,   1,   0, 
       0, 160,   5,   0,   0,   3, 
-      0,   0,   3, 128,   0,   0, 
-      0, 128,   1,   0, 238, 160, 
+      0,   0,   6, 128,   0,   0, 
+     85, 128,   1,   0, 248, 160, 
       2,   0,   0,   3,   0,   0, 
-      4, 128,   0,   0, 255, 128, 
+      1, 128,   0,   0,   0, 128, 
       1,   0,  85, 160,   4,   0, 
-      0,   4,   0,   0,   2, 128, 
-      0,   0, 170, 128,   2,   0, 
-      0, 160,   0,   0,  85, 129, 
+      0,   4,   0,   0,   4, 128, 
+      0,   0,   0, 128,   2,   0, 
+      0, 160,   0,   0, 170, 129, 
       4,   0,   0,   4,   1,   0, 
-      1, 128,   0,   0, 170, 128, 
+      1, 128,   0,   0,   0, 128, 
       2,   0,   0, 160,   0,   0, 
-      0, 128,  66,   0,   0,   3, 
+     85, 128,  66,   0,   0,   3, 
       2,   0,  15, 128,   0,   0, 
     228, 176,   1,   8, 228, 160, 
       2,   0,   0,   3,   0,   0, 
-      1, 128,   2,   0, 255, 128, 
+      2, 128,   2,   0,   0, 128, 
       1,   0,   0, 160,   4,   0, 
       0,   4,   1,   0,   2, 128, 
-      0,   0,   0, 128,   2,   0, 
-    170, 161,   0,   0,  85, 128, 
+      0,   0,  85, 128,   2,   0, 
+    170, 161,   0,   0, 170, 128, 
       5,   0,   0,   3,   0,   0, 
-      1, 128,   0,   0,   0, 128, 
+      2, 128,   0,   0,  85, 128, 
       2,   0,  85, 160,   4,   0, 
       0,   4,   1,   0,   4, 128, 
-      0,   0, 170, 128,   2,   0, 
-      0, 160,   0,   0,   0, 128, 
+      0,   0,   0, 128,   2,   0, 
+      0, 160,   0,   0,  85, 128, 
       1,   0,   0,   2,   1,   0, 
       8, 128,   2,   0, 255, 160, 
       5,   0,   0,   3,   0,   0, 
      15, 128,   1,   0, 228, 128, 
       0,   0,   0, 160,   1,   0, 
       0,   2,   0,   8,  15, 128, 
       0,   0, 228, 128, 255, 255, 
       0,   0,  83,  72,  68,  82, 
@@ -1811,34 +1835,34 @@ const BYTE YCbCrShader[] =
      69,   0,   0,   9, 242,   0, 
      16,   0,   0,   0,   0,   0, 
      70,  16,  16,   0,   1,   0, 
       0,   0,  70, 126,  16,   0, 
       2,   0,   0,   0,   0,  96, 
      16,   0,   0,   0,   0,   0, 
       0,   0,   0,   7,  18,   0, 
      16,   0,   0,   0,   0,   0, 
-     58,   0,  16,   0,   0,   0, 
+     10,   0,  16,   0,   0,   0, 
       0,   0,   1,  64,   0,   0, 
     115, 128,   0, 191,  56,   0, 
       0,  10,  50,   0,  16,   0, 
       0,   0,   0,   0,   6,   0, 
      16,   0,   0,   0,   0,   0, 
       2,  64,   0,   0, 182,  74, 
     204,  63, 205,  30,  80,  63, 
       0,   0,   0,   0,   0,   0, 
       0,   0,  69,   0,   0,   9, 
     242,   0,  16,   0,   1,   0, 
       0,   0,  70,  16,  16,   0, 
       1,   0,   0,   0,  70, 126, 
      16,   0,   0,   0,   0,   0, 
       0,  96,  16,   0,   0,   0, 
       0,   0,   0,   0,   0,   7, 
      66,   0,  16,   0,   0,   0, 
-      0,   0,  58,   0,  16,   0, 
+      0,   0,  10,   0,  16,   0, 
       1,   0,   0,   0,   1,  64, 
       0,   0,  18, 131, 128, 189, 
      50,   0,   0,  10,  34,   0, 
      16,   0,   0,   0,   0,   0, 
      42,   0,  16,   0,   0,   0, 
       0,   0,   1,  64,   0,   0, 
     103,  10, 149,  63,  26,   0, 
      16, 128,  65,   0,   0,   0, 
@@ -1851,17 +1875,17 @@ const BYTE YCbCrShader[] =
       0,   0,   0,   0,  69,   0, 
       0,   9, 242,   0,  16,   0, 
       2,   0,   0,   0,  70,  16, 
      16,   0,   1,   0,   0,   0, 
      70, 126,  16,   0,   1,   0, 
       0,   0,   0,  96,  16,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   7,  18,   0,  16,   0, 
-      0,   0,   0,   0,  58,   0, 
+      0,   0,   0,   0,  10,   0, 
      16,   0,   2,   0,   0,   0, 
       1,  64,   0,   0, 115, 128, 
       0, 191,  50,   0,   0,  10, 
      34,   0,  16,   0,   1,   0, 
       0,   0,  10,   0,  16, 128, 
      65,   0,   0,   0,   0,   0, 
       0,   0,   1,  64,   0,   0, 
     196, 148, 200,  62,  26,   0, 
@@ -1885,17 +1909,17 @@ const BYTE YCbCrShader[] =
      70,  14,  16,   0,   1,   0, 
       0,   0,   6, 128,  32,   0, 
       0,   0,   0,   0,   1,   0, 
       0,   0,  62,   0,   0,   1, 
      83,  84,  65,  84, 116,   0, 
       0,   0,  15,   0,   0,   0, 
       3,   0,   0,   0,   0,   0, 
       0,   0,   2,   0,   0,   0, 
-     10,   0,   0,   0,   0,   0, 
+      6,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       1,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   3,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -2011,19 +2035,19 @@ const BYTE YCbCrShader[] =
      97, 100,   0, 118,  77,  97, 
     115, 107,  81, 117,  97, 100, 
       0,  77, 105,  99, 114, 111, 
     115, 111, 102, 116,  32,  40, 
      82,  41,  32,  72,  76,  83, 
      76,  32,  83, 104,  97, 100, 
     101, 114,  32,  67, 111, 109, 
     112, 105, 108, 101, 114,  32, 
-     54,  46,  51,  46,  57,  54, 
-     48,  48,  46,  49,  54,  51, 
-     56,  52,   0, 171,  73,  83, 
+     57,  46,  50,  57,  46,  57, 
+     53,  50,  46,  51,  49,  49, 
+     49,   0, 171, 171,  73,  83, 
      71,  78,  80,   0,   0,   0, 
       2,   0,   0,   0,   8,   0, 
       0,   0,  56,   0,   0,   0, 
       0,   0,   0,   0,   1,   0, 
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,  15,   0, 
       0,   0,  68,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -2040,17 +2064,21 @@ const BYTE YCbCrShader[] =
       0,   0,   0,   0,   0,   0, 
       3,   0,   0,   0,   0,   0, 
       0,   0,  15,   0,   0,   0, 
      83,  86,  95,  84,  97, 114, 
     103, 101, 116,   0, 171, 171
 };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+//
+//   fxc -nologo -Tvs_4_0_level_9_3 CompositorD3D11.hlsl -ELayerQuadMaskVS
+//    -VnLayerQuadMaskVS -FhtmpShaderHeader
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4x4 mLayerTransform;          // Offset:    0 Size:    64
@@ -2070,28 +2098,28 @@ const BYTE YCbCrShader[] =
 // Name                                 Type  Format         Dim Slot Elements
 // ------------------------------ ---------- ------- ----------- ---- --------
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// POSITION                 0   xy          0     NONE   float   xy  
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// POSITION                 0   xy          0     NONE  float   xy  
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Position              0   xyzw        0      POS   float   xyzw
-// TEXCOORD                 0   xy          1     NONE   float   xy  
-// TEXCOORD                 1     zw        1     NONE   float     zw
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Position              0   xyzw        0      POS  float   xyzw
+// TEXCOORD                 0   xy          1     NONE  float   xy  
+// TEXCOORD                 1     zw        1     NONE  float     zw
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c1         cb0             0         2  ( FLT, FLT, FLT, FLT)
 // c3         cb0             3         9  ( FLT, FLT, FLT, FLT)
@@ -2153,20 +2181,20 @@ mad r1.xyzw, cb0[6].xyzw, r0.zzzz, r1.xy
 mad o0.xyzw, cb0[7].xyzw, r0.wwww, r1.xyzw
 mad o1.xy, v0.xyxx, cb0[9].zwzz, cb0[9].xyxx
 ret 
 // Approximately 16 instruction slots used
 #endif
 
 const BYTE LayerQuadMaskVS[] =
 {
-     68,  88,  66,  67, 223, 251, 
-     10,  17,  13,  90,  47,  25, 
-    119, 198,  20, 157, 124, 193, 
-    251, 234,   1,   0,   0,   0, 
+     68,  88,  66,  67,  15, 196, 
+    252, 199, 211, 188,  92,  26, 
+     46, 113, 249,  29, 135, 110, 
+     83, 119,   1,   0,   0,   0, 
     120,   7,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     224,   1,   0,   0,  76,   4, 
       0,   0, 200,   4,   0,   0, 
     212,   6,   0,   0,   8,   7, 
       0,   0,  65, 111, 110,  57, 
     160,   1,   0,   0, 160,   1, 
       0,   0,   0,   2, 254, 255, 
@@ -2340,17 +2368,17 @@ const BYTE LayerQuadMaskVS[] =
      32,   0,   0,   0,   0,   0, 
       9,   0,   0,   0,  70, 128, 
      32,   0,   0,   0,   0,   0, 
       9,   0,   0,   0,  62,   0, 
       0,   1,  83,  84,  65,  84, 
     116,   0,   0,   0,  16,   0, 
       0,   0,   2,   0,   0,   0, 
       0,   0,   0,   0,   4,   0, 
-      0,   0,  14,   0,   0,   0, 
+      0,   0,   8,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   1,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -2441,19 +2469,19 @@ const BYTE LayerQuadMaskVS[] =
       0,   0,   3,   0,   1,   0, 
       1,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,  77, 105, 
      99, 114, 111, 115, 111, 102, 
     116,  32,  40,  82,  41,  32, 
      72,  76,  83,  76,  32,  83, 
     104,  97, 100, 101, 114,  32, 
      67, 111, 109, 112, 105, 108, 
-    101, 114,  32,  54,  46,  51, 
-     46,  57,  54,  48,  48,  46, 
-     49,  54,  51,  56,  52,   0, 
+    101, 114,  32,  57,  46,  50, 
+     57,  46,  57,  53,  50,  46, 
+     51,  49,  49,  49,   0, 171, 
     171, 171,  73,  83,  71,  78, 
      44,   0,   0,   0,   1,   0, 
       0,   0,   8,   0,   0,   0, 
      32,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       3,   0,   0,   0,   0,   0, 
       0,   0,   3,   3,   0,   0, 
      80,  79,  83,  73,  84,  73, 
@@ -2475,17 +2503,21 @@ const BYTE LayerQuadMaskVS[] =
      12,   3,   0,   0,  83,  86, 
      95,  80, 111, 115, 105, 116, 
     105, 111, 110,   0,  84,  69, 
      88,  67,  79,  79,  82,  68, 
       0, 171, 171, 171
 };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+//
+//   fxc -nologo -Tvs_4_0_level_9_3 CompositorD3D11.hlsl -ELayerQuadMask3DVS
+//    -VnLayerQuadMask3DVS -FhtmpShaderHeader
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4x4 mLayerTransform;          // Offset:    0 Size:    64
@@ -2505,28 +2537,28 @@ const BYTE LayerQuadMaskVS[] =
 // Name                                 Type  Format         Dim Slot Elements
 // ------------------------------ ---------- ------- ----------- ---- --------
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// POSITION                 0   xy          0     NONE   float   xy  
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// POSITION                 0   xy          0     NONE  float   xy  
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Position              0   xyzw        0      POS   float   xyzw
-// TEXCOORD                 0   xy          1     NONE   float   xy  
-// TEXCOORD                 1   xyz         2     NONE   float   xyz 
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Position              0   xyzw        0      POS  float   xyzw
+// TEXCOORD                 0   xy          1     NONE  float   xy  
+// TEXCOORD                 1   xyz         2     NONE  float   xyz 
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c1         cb0             0         2  ( FLT, FLT, FLT, FLT)
 // c3         cb0             3         9  ( FLT, FLT, FLT, FLT)
@@ -2592,20 +2624,20 @@ mad o1.xy, v0.xyxx, cb0[9].zwzz, cb0[9].
 mov r0.z, l(1.000000)
 mul o2.xyz, r0.wwww, r0.xyzx
 ret 
 // Approximately 17 instruction slots used
 #endif
 
 const BYTE LayerQuadMask3DVS[] =
 {
-     68,  88,  66,  67, 151, 141, 
-     11,  11, 111, 244,  17, 242, 
-    119, 116, 248,  53, 235, 192, 
-     38, 193,   1,   0,   0,   0, 
+     68,  88,  66,  67, 100,  40, 
+     55,  29, 238,  71, 107,  78, 
+    214, 182,  73, 149, 138,  22, 
+    163, 187,   1,   0,   0,   0, 
     204,   7,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
      24,   2,   0,   0, 160,   4, 
       0,   0,  28,   5,   0,   0, 
      40,   7,   0,   0,  92,   7, 
       0,   0,  65, 111, 110,  57, 
     216,   1,   0,   0, 216,   1, 
       0,   0,   0,   2, 254, 255, 
@@ -2793,27 +2825,27 @@ const BYTE LayerQuadMask3DVS[] =
      16,   0,   2,   0,   0,   0, 
     246,  15,  16,   0,   0,   0, 
       0,   0,  70,   2,  16,   0, 
       0,   0,   0,   0,  62,   0, 
       0,   1,  83,  84,  65,  84, 
     116,   0,   0,   0,  17,   0, 
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,   4,   0, 
-      0,   0,  15,   0,   0,   0, 
+      0,   0,   9,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   1,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
-      0,   0,   1,   0,   0,   0, 
+      0,   0,   2,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
      82,  68,  69,  70,   4,   2, 
       0,   0,   1,   0,   0,   0, 
@@ -2894,19 +2926,19 @@ const BYTE LayerQuadMask3DVS[] =
       0,   0,   3,   0,   1,   0, 
       1,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,  77, 105, 
      99, 114, 111, 115, 111, 102, 
     116,  32,  40,  82,  41,  32, 
      72,  76,  83,  76,  32,  83, 
     104,  97, 100, 101, 114,  32, 
      67, 111, 109, 112, 105, 108, 
-    101, 114,  32,  54,  46,  51, 
-     46,  57,  54,  48,  48,  46, 
-     49,  54,  51,  56,  52,   0, 
+    101, 114,  32,  57,  46,  50, 
+     57,  46,  57,  53,  50,  46, 
+     51,  49,  49,  49,   0, 171, 
     171, 171,  73,  83,  71,  78, 
      44,   0,   0,   0,   1,   0, 
       0,   0,   8,   0,   0,   0, 
      32,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       3,   0,   0,   0,   0,   0, 
       0,   0,   3,   3,   0,   0, 
      80,  79,  83,  73,  84,  73, 
@@ -2928,17 +2960,21 @@ const BYTE LayerQuadMask3DVS[] =
       7,   8,   0,   0,  83,  86, 
      95,  80, 111, 115, 105, 116, 
     105, 111, 110,   0,  84,  69, 
      88,  67,  79,  79,  82,  68, 
       0, 171, 171, 171
 };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+//
+//   fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -ESolidColorShaderMask
+//    -VnSolidColorShaderMask -FhtmpShaderHeader
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16
@@ -2960,28 +2996,28 @@ const BYTE LayerQuadMask3DVS[] =
 // sSampler                          sampler      NA          NA    0        1
 // tMask                             texture  float4          2d    3        1
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Position              0   xyzw        0      POS   float       
-// TEXCOORD                 0   xy          1     NONE   float       
-// TEXCOORD                 1     zw        1     NONE   float     zw
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Position              0   xyzw        0      POS  float       
+// TEXCOORD                 0   xy          1     NONE  float       
+// TEXCOORD                 1     zw        1     NONE  float     zw
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Target                0   xyzw        0   TARGET   float   xyzw
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Target                0   xyzw        0   TARGET  float   xyzw
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c0         cb0             0         1  ( FLT, FLT, FLT, FLT)
 //
@@ -2995,39 +3031,39 @@ const BYTE LayerQuadMask3DVS[] =
 //
 // Level9 shader bytecode:
 //
     ps_2_x
     dcl t0
     dcl_2d s0
     mov r0.xy, t0.wzzw
     texld r0, r0, s0
-    mul r0, r0.w, c0
+    mul r0, r0.x, c0
     mov oC0, r0
 
 // approximately 4 instruction slots used (1 texture, 3 arithmetic)
 ps_4_0
 dcl_constantbuffer cb0[1], immediateIndexed
 dcl_sampler s0, mode_default
 dcl_resource_texture2d (float,float,float,float) t3
 dcl_input_ps linear v1.zw
 dcl_output o0.xyzw
 dcl_temps 1
 sample r0.xyzw, v1.zwzz, t3.xyzw, s0
-mul o0.xyzw, r0.wwww, cb0[0].xyzw
+mul o0.xyzw, r0.xxxx, cb0[0].xyzw
 ret 
 // Approximately 3 instruction slots used
 #endif
 
 const BYTE SolidColorShaderMask[] =
 {
-     68,  88,  66,  67, 236, 109, 
-     19, 151,  23, 187, 157, 205, 
-    112, 188,  91, 187, 108, 106, 
-    138,  14,   1,   0,   0,   0, 
+     68,  88,  66,  67, 218,  73, 
+     87,  32, 206,  67,  79,  54, 
+     31, 104, 228, 152, 133, 115, 
+    245,   3,   1,   0,   0,   0, 
     232,   4,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     204,   0,   0,   0, 112,   1, 
       0,   0, 236,   1,   0,   0, 
      68,   4,   0,   0, 180,   4, 
       0,   0,  65, 111, 110,  57, 
     140,   0,   0,   0, 140,   0, 
       0,   0,   0,   2, 255, 255, 
@@ -3044,17 +3080,17 @@ const BYTE SolidColorShaderMask[] =
      31,   0,   0,   2,   0,   0, 
       0, 144,   0,   8,  15, 160, 
       1,   0,   0,   2,   0,   0, 
       3, 128,   0,   0, 235, 176, 
      66,   0,   0,   3,   0,   0, 
      15, 128,   0,   0, 228, 128, 
       0,   8, 228, 160,   5,   0, 
       0,   3,   0,   0,  15, 128, 
-      0,   0, 255, 128,   0,   0, 
+      0,   0,   0, 128,   0,   0, 
     228, 160,   1,   0,   0,   2, 
       0,   8,  15, 128,   0,   0, 
     228, 128, 255, 255,   0,   0, 
      83,  72,  68,  82, 156,   0, 
       0,   0,  64,   0,   0,   0, 
      39,   0,   0,   0,  89,   0, 
       0,   4,  70, 142,  32,   0, 
       0,   0,   0,   0,   1,   0, 
@@ -3071,17 +3107,17 @@ const BYTE SolidColorShaderMask[] =
       0,   0,  69,   0,   0,   9, 
     242,   0,  16,   0,   0,   0, 
       0,   0, 230,  26,  16,   0, 
       1,   0,   0,   0,  70, 126, 
      16,   0,   3,   0,   0,   0, 
       0,  96,  16,   0,   0,   0, 
       0,   0,  56,   0,   0,   8, 
     242,  32,  16,   0,   0,   0, 
-      0,   0, 246,  15,  16,   0, 
+      0,   0,   6,   0,  16,   0, 
       0,   0,   0,   0,  70, 142, 
      32,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,  62,   0, 
       0,   1,  83,  84,  65,  84, 
     116,   0,   0,   0,   3,   0, 
       0,   0,   1,   0,   0,   0, 
       0,   0,   0,   0,   2,   0, 
       0,   0,   1,   0,   0,   0, 
@@ -3193,19 +3229,19 @@ const BYTE SolidColorShaderMask[] =
      81, 117,  97, 100,   0, 118, 
      77,  97, 115, 107,  81, 117, 
      97, 100,   0,  77, 105,  99, 
     114, 111, 115, 111, 102, 116, 
      32,  40,  82,  41,  32,  72, 
      76,  83,  76,  32,  83, 104, 
      97, 100, 101, 114,  32,  67, 
     111, 109, 112, 105, 108, 101, 
-    114,  32,  54,  46,  51,  46, 
-     57,  54,  48,  48,  46,  49, 
-     54,  51,  56,  52,   0, 171, 
+    114,  32,  57,  46,  50,  57, 
+     46,  57,  53,  50,  46,  51, 
+     49,  49,  49,   0, 171, 171, 
      73,  83,  71,  78, 104,   0, 
       0,   0,   3,   0,   0,   0, 
       8,   0,   0,   0,  80,   0, 
       0,   0,   0,   0,   0,   0, 
       1,   0,   0,   0,   3,   0, 
       0,   0,   0,   0,   0,   0, 
      15,   0,   0,   0,  92,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -3227,17 +3263,21 @@ const BYTE SolidColorShaderMask[] =
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,  15,   0, 
       0,   0,  83,  86,  95,  84, 
      97, 114, 103, 101, 116,   0, 
     171, 171
 };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+//
+//   fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -ERGBShaderMask
+//    -VnRGBShaderMask -FhtmpShaderHeader
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16 [unused]
@@ -3260,28 +3300,28 @@ const BYTE SolidColorShaderMask[] =
 // tRGB                              texture  float4          2d    0        1
 // tMask                             texture  float4          2d    3        1
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Position              0   xyzw        0      POS   float       
-// TEXCOORD                 0   xy          1     NONE   float   xy  
-// TEXCOORD                 1     zw        1     NONE   float     zw
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Position              0   xyzw        0      POS  float       
+// TEXCOORD                 0   xy          1     NONE  float   xy  
+// TEXCOORD                 1     zw        1     NONE  float     zw
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Target                0   xyzw        0   TARGET   float   xyzw
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Target                0   xyzw        0   TARGET  float   xyzw
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c0         cb0             1         1  ( FLT, FLT, FLT, FLT)
 //
@@ -3300,44 +3340,44 @@ const BYTE SolidColorShaderMask[] =
     dcl t0
     dcl_2d s0
     dcl_2d s1
     mov r0.xy, t0.wzzw
     texld r1, t0, s1
     texld r0, r0, s0
     mul r1.xyz, r1, c0.x
     mov r1.w, c0.x
-    mul r0, r0.w, r1
+    mul r0, r0.x, r1
     mov oC0, r0
 
 // approximately 7 instruction slots used (2 texture, 5 arithmetic)
 ps_4_0
 dcl_constantbuffer cb0[2], immediateIndexed
 dcl_sampler s0, mode_default
 dcl_resource_texture2d (float,float,float,float) t0
 dcl_resource_texture2d (float,float,float,float) t3
 dcl_input_ps linear v1.xy
 dcl_input_ps linear v1.zw
 dcl_output o0.xyzw
 dcl_temps 2
 sample r0.xyzw, v1.xyxx, t0.xyzw, s0
 mul r0.xyz, r0.xyzx, cb0[1].xxxx
 sample r1.xyzw, v1.zwzz, t3.xyzw, s0
 mov r0.w, cb0[1].x
-mul o0.xyzw, r0.xyzw, r1.wwww
+mul o0.xyzw, r0.xyzw, r1.xxxx
 ret 
 // Approximately 6 instruction slots used
 #endif
 
 const BYTE RGBShaderMask[] =
 {
-     68,  88,  66,  67,  30,  30, 
-     87,  58, 114, 156, 251, 151, 
-     29,  94,  34, 100, 228, 250, 
-     37, 251,   1,   0,   0,   0, 
+     68,  88,  66,  67,  77,  94, 
+    252, 215, 133,  78, 101, 216, 
+    220,   8,  70, 254,  89, 142, 
+    130, 135,   1,   0,   0,   0, 
     192,   5,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
       8,   1,   0,   0,  32,   2, 
       0,   0, 156,   2,   0,   0, 
      28,   5,   0,   0, 140,   5, 
       0,   0,  65, 111, 110,  57, 
     200,   0,   0,   0, 200,   0, 
       0,   0,   0,   2, 255, 255, 
@@ -3364,17 +3404,17 @@ const BYTE RGBShaderMask[] =
       0,   0,  15, 128,   0,   0, 
     228, 128,   0,   8, 228, 160, 
       5,   0,   0,   3,   1,   0, 
       7, 128,   1,   0, 228, 128, 
       0,   0,   0, 160,   1,   0, 
       0,   2,   1,   0,   8, 128, 
       0,   0,   0, 160,   5,   0, 
       0,   3,   0,   0,  15, 128, 
-      0,   0, 255, 128,   1,   0, 
+      0,   0,   0, 128,   1,   0, 
     228, 128,   1,   0,   0,   2, 
       0,   8,  15, 128,   0,   0, 
     228, 128, 255, 255,   0,   0, 
      83,  72,  68,  82,  16,   1, 
       0,   0,  64,   0,   0,   0, 
      68,   0,   0,   0,  89,   0, 
       0,   4,  70, 142,  32,   0, 
       0,   0,   0,   0,   2,   0, 
@@ -3412,17 +3452,17 @@ const BYTE RGBShaderMask[] =
       0,  96,  16,   0,   0,   0, 
       0,   0,  54,   0,   0,   6, 
     130,   0,  16,   0,   0,   0, 
       0,   0,  10, 128,  32,   0, 
       0,   0,   0,   0,   1,   0, 
       0,   0,  56,   0,   0,   7, 
     242,  32,  16,   0,   0,   0, 
       0,   0,  70,  14,  16,   0, 
-      0,   0,   0,   0, 246,  15, 
+      0,   0,   0,   0,   6,   0, 
      16,   0,   1,   0,   0,   0, 
      62,   0,   0,   1,  83,  84, 
      65,  84, 116,   0,   0,   0, 
       6,   0,   0,   0,   2,   0, 
       0,   0,   0,   0,   0,   0, 
       3,   0,   0,   0,   2,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   1,   0, 
@@ -3539,19 +3579,19 @@ const BYTE RGBShaderMask[] =
      81, 117,  97, 100,   0, 118, 
      77,  97, 115, 107,  81, 117, 
      97, 100,   0,  77, 105,  99, 
     114, 111, 115, 111, 102, 116, 
      32,  40,  82,  41,  32,  72, 
      76,  83,  76,  32,  83, 104, 
      97, 100, 101, 114,  32,  67, 
     111, 109, 112, 105, 108, 101, 
-    114,  32,  54,  46,  51,  46, 
-     57,  54,  48,  48,  46,  49, 
-     54,  51,  56,  52,   0, 171, 
+    114,  32,  57,  46,  50,  57, 
+     46,  57,  53,  50,  46,  51, 
+     49,  49,  49,   0, 171, 171, 
      73,  83,  71,  78, 104,   0, 
       0,   0,   3,   0,   0,   0, 
       8,   0,   0,   0,  80,   0, 
       0,   0,   0,   0,   0,   0, 
       1,   0,   0,   0,   3,   0, 
       0,   0,   0,   0,   0,   0, 
      15,   0,   0,   0,  92,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -3573,17 +3613,21 @@ const BYTE RGBShaderMask[] =
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,  15,   0, 
       0,   0,  83,  86,  95,  84, 
      97, 114, 103, 101, 116,   0, 
     171, 171
 };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+//
+//   fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -ERGBAShaderMask
+//    -VnRGBAShaderMask -FhtmpShaderHeader
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16 [unused]
@@ -3606,28 +3650,28 @@ const BYTE RGBShaderMask[] =
 // tRGB                              texture  float4          2d    0        1
 // tMask                             texture  float4          2d    3        1
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Position              0   xyzw        0      POS   float       
-// TEXCOORD                 0   xy          1     NONE   float   xy  
-// TEXCOORD                 1     zw        1     NONE   float     zw
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Position              0   xyzw        0      POS  float       
+// TEXCOORD                 0   xy          1     NONE  float   xy  
+// TEXCOORD                 1     zw        1     NONE  float     zw
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Target                0   xyzw        0   TARGET   float   xyzw
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Target                0   xyzw        0   TARGET  float   xyzw
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c0         cb0             1         1  ( FLT, FLT, FLT, FLT)
 //
@@ -3645,43 +3689,43 @@ const BYTE RGBShaderMask[] =
     ps_2_x
     dcl t0
     dcl_2d s0
     dcl_2d s1
     mov r0.xy, t0.wzzw
     texld r1, t0, s1
     texld r0, r0, s0
     mul r1, r1, c0.x
-    mul r0, r0.w, r1
+    mul r0, r0.x, r1
     mov oC0, r0
 
 // approximately 6 instruction slots used (2 texture, 4 arithmetic)
 ps_4_0
 dcl_constantbuffer cb0[2], immediateIndexed
 dcl_sampler s0, mode_default
 dcl_resource_texture2d (float,float,float,float) t0
 dcl_resource_texture2d (float,float,float,float) t3
 dcl_input_ps linear v1.xy
 dcl_input_ps linear v1.zw
 dcl_output o0.xyzw
 dcl_temps 2
 sample r0.xyzw, v1.xyxx, t0.xyzw, s0
 mul r0.xyzw, r0.xyzw, cb0[1].xxxx
 sample r1.xyzw, v1.zwzz, t3.xyzw, s0
-mul o0.xyzw, r0.xyzw, r1.wwww
+mul o0.xyzw, r0.xyzw, r1.xxxx
 ret 
 // Approximately 5 instruction slots used
 #endif
 
 const BYTE RGBAShaderMask[] =
 {
-     68,  88,  66,  67, 188,  13, 
-    191, 168, 231, 201,  42, 209, 
-     88, 243,  29,  35, 226,  31, 
-    145,  20,   1,   0,   0,   0, 
+     68,  88,  66,  67, 138,  69, 
+     81, 181, 217,  15, 199,  10, 
+    146, 208, 232, 248,  24,  27, 
+    141,  26,   1,   0,   0,   0, 
     156,   5,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     252,   0,   0,   0, 252,   1, 
       0,   0, 120,   2,   0,   0, 
     248,   4,   0,   0, 104,   5, 
       0,   0,  65, 111, 110,  57, 
     188,   0,   0,   0, 188,   0, 
       0,   0,   0,   2, 255, 255, 
@@ -3706,17 +3750,17 @@ const BYTE RGBAShaderMask[] =
       0,   0, 228, 176,   1,   8, 
     228, 160,  66,   0,   0,   3, 
       0,   0,  15, 128,   0,   0, 
     228, 128,   0,   8, 228, 160, 
       5,   0,   0,   3,   1,   0, 
      15, 128,   1,   0, 228, 128, 
       0,   0,   0, 160,   5,   0, 
       0,   3,   0,   0,  15, 128, 
-      0,   0, 255, 128,   1,   0, 
+      0,   0,   0, 128,   1,   0, 
     228, 128,   1,   0,   0,   2, 
       0,   8,  15, 128,   0,   0, 
     228, 128, 255, 255,   0,   0, 
      83,  72,  68,  82, 248,   0, 
       0,   0,  64,   0,   0,   0, 
      62,   0,   0,   0,  89,   0, 
       0,   4,  70, 142,  32,   0, 
       0,   0,   0,   0,   2,   0, 
@@ -3750,17 +3794,17 @@ const BYTE RGBAShaderMask[] =
     242,   0,  16,   0,   1,   0, 
       0,   0, 230,  26,  16,   0, 
       1,   0,   0,   0,  70, 126, 
      16,   0,   3,   0,   0,   0, 
       0,  96,  16,   0,   0,   0, 
       0,   0,  56,   0,   0,   7, 
     242,  32,  16,   0,   0,   0, 
       0,   0,  70,  14,  16,   0, 
-      0,   0,   0,   0, 246,  15, 
+      0,   0,   0,   0,   6,   0, 
      16,   0,   1,   0,   0,   0, 
      62,   0,   0,   1,  83,  84, 
      65,  84, 116,   0,   0,   0, 
       5,   0,   0,   0,   2,   0, 
       0,   0,   0,   0,   0,   0, 
       3,   0,   0,   0,   2,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   1,   0, 
@@ -3877,19 +3921,19 @@ const BYTE RGBAShaderMask[] =
      81, 117,  97, 100,   0, 118, 
      77,  97, 115, 107,  81, 117, 
      97, 100,   0,  77, 105,  99, 
     114, 111, 115, 111, 102, 116, 
      32,  40,  82,  41,  32,  72, 
      76,  83,  76,  32,  83, 104, 
      97, 100, 101, 114,  32,  67, 
     111, 109, 112, 105, 108, 101, 
-    114,  32,  54,  46,  51,  46, 
-     57,  54,  48,  48,  46,  49, 
-     54,  51,  56,  52,   0, 171, 
+    114,  32,  57,  46,  50,  57, 
+     46,  57,  53,  50,  46,  51, 
+     49,  49,  49,   0, 171, 171, 
      73,  83,  71,  78, 104,   0, 
       0,   0,   3,   0,   0,   0, 
       8,   0,   0,   0,  80,   0, 
       0,   0,   0,   0,   0,   0, 
       1,   0,   0,   0,   3,   0, 
       0,   0,   0,   0,   0,   0, 
      15,   0,   0,   0,  92,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -3911,17 +3955,21 @@ const BYTE RGBAShaderMask[] =
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,  15,   0, 
       0,   0,  83,  86,  95,  84, 
      97, 114, 103, 101, 116,   0, 
     171, 171
 };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+//
+//   fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -ERGBAShaderMask3D
+//    -VnRGBAShaderMask3D -FhtmpShaderHeader
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16 [unused]
@@ -3945,28 +3993,28 @@ const BYTE RGBAShaderMask[] =
 // tRGB                              texture  float4          2d    0        1
 // tMask                             texture  float4          2d    3        1
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Position              0   xyzw        0      POS   float       
-// TEXCOORD                 0   xy          1     NONE   float   xy  
-// TEXCOORD                 1   xyz         2     NONE   float   xyz 
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Position              0   xyzw        0      POS  float       
+// TEXCOORD                 0   xy          1     NONE  float   xy  
+// TEXCOORD                 1   xyz         2     NONE  float   xyz 
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Target                0   xyzw        0   TARGET   float   xyzw
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Target                0   xyzw        0   TARGET  float   xyzw
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c0         cb0             1         1  ( FLT, FLT, FLT, FLT)
 //
@@ -3986,17 +4034,17 @@ const BYTE RGBAShaderMask[] =
     dcl t1.xyz
     dcl_2d s0
     dcl_2d s1
     rcp r0.w, t1.z
     mul r0.xy, r0.w, t1
     texld r1, t0, s0
     texld r0, r0, s1
     mul r1, r1, c0.x
-    mul r0, r0.w, r1
+    mul r0, r0.x, r1
     mov oC0, r0
 
 // approximately 7 instruction slots used (2 texture, 5 arithmetic)
 ps_4_0
 dcl_constantbuffer cb0[2], immediateIndexed
 dcl_sampler s0, mode_default
 dcl_sampler s1, mode_default
 dcl_resource_texture2d (float,float,float,float) t0
@@ -4004,27 +4052,27 @@ dcl_resource_texture2d (float,float,floa
 dcl_input_ps linear v1.xy
 dcl_input_ps linear v2.xyz
 dcl_output o0.xyzw
 dcl_temps 2
 div r0.xy, v2.xyxx, v2.zzzz
 sample r0.xyzw, r0.xyxx, t3.xyzw, s1
 sample r1.xyzw, v1.xyxx, t0.xyzw, s0
 mul r1.xyzw, r1.xyzw, cb0[1].xxxx
-mul o0.xyzw, r0.wwww, r1.xyzw
+mul o0.xyzw, r0.xxxx, r1.xyzw
 ret 
 // Approximately 6 instruction slots used
 #endif
 
 const BYTE RGBAShaderMask3D[] =
 {
-     68,  88,  66,  67, 113, 141, 
-     78,  23, 128, 223, 235,  10, 
-      0,  97,  49, 111,  47,  53, 
-    229,  55,   1,   0,   0,   0, 
+     68,  88,  66,  67,   4, 135, 
+     55,   9, 144, 137,  25,  77, 
+     92, 150, 209,   2,  32, 225, 
+     75, 182,   1,   0,   0,   0, 
      24,   6,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
      24,   1,   0,   0,  64,   2, 
       0,   0, 188,   2,   0,   0, 
     116,   5,   0,   0, 228,   5, 
       0,   0,  65, 111, 110,  57, 
     216,   0,   0,   0, 216,   0, 
       0,   0,   0,   2, 255, 255, 
@@ -4054,17 +4102,17 @@ const BYTE RGBAShaderMask3D[] =
     228, 176,   0,   8, 228, 160, 
      66,   0,   0,   3,   0,   0, 
      15, 128,   0,   0, 228, 128, 
       1,   8, 228, 160,   5,   0, 
       0,   3,   1,   0,  15, 128, 
       1,   0, 228, 128,   0,   0, 
       0, 160,   5,   0,   0,   3, 
       0,   0,  15, 128,   0,   0, 
-    255, 128,   1,   0, 228, 128, 
+      0, 128,   1,   0, 228, 128, 
       1,   0,   0,   2,   0,   8, 
      15, 128,   0,   0, 228, 128, 
     255, 255,   0,   0,  83,  72, 
      68,  82,  32,   1,   0,   0, 
      64,   0,   0,   0,  72,   0, 
       0,   0,  89,   0,   0,   4, 
      70, 142,  32,   0,   0,   0, 
       0,   0,   2,   0,   0,   0, 
@@ -4103,17 +4151,17 @@ const BYTE RGBAShaderMask3D[] =
       0,  96,  16,   0,   0,   0, 
       0,   0,  56,   0,   0,   8, 
     242,   0,  16,   0,   1,   0, 
       0,   0,  70,  14,  16,   0, 
       1,   0,   0,   0,   6, 128, 
      32,   0,   0,   0,   0,   0, 
       1,   0,   0,   0,  56,   0, 
       0,   7, 242,  32,  16,   0, 
-      0,   0,   0,   0, 246,  15, 
+      0,   0,   0,   0,   6,   0, 
      16,   0,   0,   0,   0,   0, 
      70,  14,  16,   0,   1,   0, 
       0,   0,  62,   0,   0,   1, 
      83,  84,  65,  84, 116,   0, 
       0,   0,   6,   0,   0,   0, 
       2,   0,   0,   0,   0,   0, 
       0,   0,   3,   0,   0,   0, 
       3,   0,   0,   0,   0,   0, 
@@ -4241,19 +4289,19 @@ const BYTE RGBAShaderMask3D[] =
      97, 100,   0, 118,  77,  97, 
     115, 107,  81, 117,  97, 100, 
       0,  77, 105,  99, 114, 111, 
     115, 111, 102, 116,  32,  40, 
      82,  41,  32,  72,  76,  83, 
      76,  32,  83, 104,  97, 100, 
     101, 114,  32,  67, 111, 109, 
     112, 105, 108, 101, 114,  32, 
-     54,  46,  51,  46,  57,  54, 
-     48,  48,  46,  49,  54,  51, 
-     56,  52,   0, 171,  73,  83, 
+     57,  46,  50,  57,  46,  57, 
+     53,  50,  46,  51,  49,  49, 
+     49,   0, 171, 171,  73,  83, 
      71,  78, 104,   0,   0,   0, 
       3,   0,   0,   0,   8,   0, 
       0,   0,  80,   0,   0,   0, 
       0,   0,   0,   0,   1,   0, 
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,  15,   0, 
       0,   0,  92,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -4274,17 +4322,21 @@ const BYTE RGBAShaderMask3D[] =
       0,   0,   0,   0,   0,   0, 
       3,   0,   0,   0,   0,   0, 
       0,   0,  15,   0,   0,   0, 
      83,  86,  95,  84,  97, 114, 
     103, 101, 116,   0, 171, 171
 };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+//
+//   fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -EYCbCrShaderMask
+//    -VnYCbCrShaderMask -FhtmpShaderHeader
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16 [unused]
@@ -4309,28 +4361,28 @@ const BYTE RGBAShaderMask3D[] =
 // tCr                               texture  float4          2d    2        1
 // tMask                             texture  float4          2d    3        1
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Position              0   xyzw        0      POS   float       
-// TEXCOORD                 0   xy          1     NONE   float   xy  
-// TEXCOORD                 1     zw        1     NONE   float     zw
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Position              0   xyzw        0      POS  float       
+// TEXCOORD                 0   xy          1     NONE  float   xy  
+// TEXCOORD                 1     zw        1     NONE  float     zw
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Target                0   xyzw        0   TARGET   float   xyzw
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Target                0   xyzw        0   TARGET  float   xyzw
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c0         cb0             1         1  ( FLT, FLT, FLT, FLT)
 //
@@ -4352,71 +4404,71 @@ const BYTE RGBAShaderMask3D[] =
     def c2, 1.16437995, 2.01723003, 0.391759992, 1
     dcl t0
     dcl_2d s0
     dcl_2d s1
     dcl_2d s2
     dcl_2d s3
     texld r0, t0, s1
     texld r1, t0, s3
-    add r0.x, r1.w, c1.x
-    mul r0.xy, r0.x, c1.zwzw
-    add r0.z, r0.w, c1.y
-    mad r0.y, r0.z, c2.x, -r0.y
-    mad r1.x, r0.z, c2.x, r0.x
+    add r0.y, r1.x, c1.x
+    mul r0.yz, r0.y, c1.xzww
+    add r0.x, r0.x, c1.y
+    mad r0.z, r0.x, c2.x, -r0.z
+    mad r1.x, r0.x, c2.x, r0.y
     mov r2.xy, t0.wzzw
     texld r3, t0, s2
     texld r2, r2, s0
-    add r0.x, r3.w, c1.x
-    mad r1.y, r0.x, -c2.z, r0.y
-    mul r0.x, r0.x, c2.y
-    mad r1.z, r0.z, c2.x, r0.x
+    add r0.y, r3.x, c1.x
+    mad r1.y, r0.y, -c2.z, r0.z
+    mul r0.y, r0.y, c2.y
+    mad r1.z, r0.x, c2.x, r0.y
     mov r1.w, c2.w
     mul r0, r1, c0.x
-    mul r0, r2.w, r0
+    mul r0, r2.x, r0
     mov oC0, r0
 
 // approximately 18 instruction slots used (4 texture, 14 arithmetic)
 ps_4_0
 dcl_constantbuffer cb0[2], immediateIndexed
 dcl_sampler s0, mode_default
 dcl_resource_texture2d (float,float,float,float) t0
 dcl_resource_texture2d (float,float,float,float) t1
 dcl_resource_texture2d (float,float,float,float) t2
 dcl_resource_texture2d (float,float,float,float) t3
 dcl_input_ps linear v1.xy
 dcl_input_ps linear v1.zw
 dcl_output o0.xyzw
 dcl_temps 3
 sample r0.xyzw, v1.xyxx, t2.xyzw, s0
-add r0.x, r0.w, l(-0.501960)
+add r0.x, r0.x, l(-0.501960)
 mul r0.xy, r0.xxxx, l(1.596030, 0.812970, 0.000000, 0.000000)
 sample r1.xyzw, v1.xyxx, t0.xyzw, s0
-add r0.z, r1.w, l(-0.062750)
+add r0.z, r1.x, l(-0.062750)
 mad r0.y, r0.z, l(1.164380), -r0.y
 mad r1.x, r0.z, l(1.164380), r0.x
 sample r2.xyzw, v1.xyxx, t1.xyzw, s0
-add r0.x, r2.w, l(-0.501960)
+add r0.x, r2.x, l(-0.501960)
 mad r1.y, -r0.x, l(0.391760), r0.y
 mul r0.x, r0.x, l(2.017230)
 mad r1.z, r0.z, l(1.164380), r0.x
 mov r1.w, l(1.000000)
 mul r0.xyzw, r1.xyzw, cb0[1].xxxx
 sample r1.xyzw, v1.zwzz, t3.xyzw, s0
-mul o0.xyzw, r0.xyzw, r1.wwww
+mul o0.xyzw, r0.xyzw, r1.xxxx
 ret 
 // Approximately 17 instruction slots used
 #endif
 
 const BYTE YCbCrShaderMask[] =
 {
-     68,  88,  66,  67, 103, 162, 
-    223, 236, 236, 142, 143, 151, 
-     73, 154, 187, 112,  81, 114, 
-    229, 251,   1,   0,   0,   0, 
+     68,  88,  66,  67,  74,  33, 
+    155, 235,  22, 178,  84, 169, 
+    113,  91, 240,  98, 157, 143, 
+    221,  19,   1,   0,   0,   0, 
     168,   8,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
      24,   2,   0,   0, 196,   4, 
       0,   0,  64,   5,   0,   0, 
       4,   8,   0,   0, 116,   8, 
       0,   0,  65, 111, 110,  57, 
     216,   1,   0,   0, 216,   1, 
       0,   0,   0,   2, 255, 255, 
@@ -4449,56 +4501,56 @@ const BYTE YCbCrShaderMask[] =
      31,   0,   0,   2,   0,   0, 
       0, 144,   3,   8,  15, 160, 
      66,   0,   0,   3,   0,   0, 
      15, 128,   0,   0, 228, 176, 
       1,   8, 228, 160,  66,   0, 
       0,   3,   1,   0,  15, 128, 
       0,   0, 228, 176,   3,   8, 
     228, 160,   2,   0,   0,   3, 
-      0,   0,   1, 128,   1,   0, 
-    255, 128,   1,   0,   0, 160, 
+      0,   0,   2, 128,   1,   0, 
+      0, 128,   1,   0,   0, 160, 
       5,   0,   0,   3,   0,   0, 
-      3, 128,   0,   0,   0, 128, 
-      1,   0, 238, 160,   2,   0, 
-      0,   3,   0,   0,   4, 128, 
-      0,   0, 255, 128,   1,   0, 
+      6, 128,   0,   0,  85, 128, 
+      1,   0, 248, 160,   2,   0, 
+      0,   3,   0,   0,   1, 128, 
+      0,   0,   0, 128,   1,   0, 
      85, 160,   4,   0,   0,   4, 
-      0,   0,   2, 128,   0,   0, 
-    170, 128,   2,   0,   0, 160, 
-      0,   0,  85, 129,   4,   0, 
+      0,   0,   4, 128,   0,   0, 
+      0, 128,   2,   0,   0, 160, 
+      0,   0, 170, 129,   4,   0, 
       0,   4,   1,   0,   1, 128, 
-      0,   0, 170, 128,   2,   0, 
-      0, 160,   0,   0,   0, 128, 
+      0,   0,   0, 128,   2,   0, 
+      0, 160,   0,   0,  85, 128, 
       1,   0,   0,   2,   2,   0, 
       3, 128,   0,   0, 235, 176, 
      66,   0,   0,   3,   3,   0, 
      15, 128,   0,   0, 228, 176, 
       2,   8, 228, 160,  66,   0, 
       0,   3,   2,   0,  15, 128, 
       2,   0, 228, 128,   0,   8, 
     228, 160,   2,   0,   0,   3, 
-      0,   0,   1, 128,   3,   0, 
-    255, 128,   1,   0,   0, 160, 
+      0,   0,   2, 128,   3,   0, 
+      0, 128,   1,   0,   0, 160, 
       4,   0,   0,   4,   1,   0, 
-      2, 128,   0,   0,   0, 128, 
+      2, 128,   0,   0,  85, 128, 
       2,   0, 170, 161,   0,   0, 
-     85, 128,   5,   0,   0,   3, 
-      0,   0,   1, 128,   0,   0, 
-      0, 128,   2,   0,  85, 160, 
+    170, 128,   5,   0,   0,   3, 
+      0,   0,   2, 128,   0,   0, 
+     85, 128,   2,   0,  85, 160, 
       4,   0,   0,   4,   1,   0, 
-      4, 128,   0,   0, 170, 128, 
+      4, 128,   0,   0,   0, 128, 
       2,   0,   0, 160,   0,   0, 
-      0, 128,   1,   0,   0,   2, 
+     85, 128,   1,   0,   0,   2, 
       1,   0,   8, 128,   2,   0, 
     255, 160,   5,   0,   0,   3, 
       0,   0,  15, 128,   1,   0, 
     228, 128,   0,   0,   0, 160, 
       5,   0,   0,   3,   0,   0, 
-     15, 128,   2,   0, 255, 128, 
+     15, 128,   2,   0,   0, 128, 
       0,   0, 228, 128,   1,   0, 
       0,   2,   0,   8,  15, 128, 
       0,   0, 228, 128, 255, 255, 
       0,   0,  83,  72,  68,  82, 
     164,   2,   0,   0,  64,   0, 
       0,   0, 169,   0,   0,   0, 
      89,   0,   0,   4,  70, 142, 
      32,   0,   0,   0,   0,   0, 
@@ -4525,17 +4577,17 @@ const BYTE YCbCrShaderMask[] =
       3,   0,   0,   0,  69,   0, 
       0,   9, 242,   0,  16,   0, 
       0,   0,   0,   0,  70,  16, 
      16,   0,   1,   0,   0,   0, 
      70, 126,  16,   0,   2,   0, 
       0,   0,   0,  96,  16,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   7,  18,   0,  16,   0, 
-      0,   0,   0,   0,  58,   0, 
+      0,   0,   0,   0,  10,   0, 
      16,   0,   0,   0,   0,   0, 
       1,  64,   0,   0, 115, 128, 
       0, 191,  56,   0,   0,  10, 
      50,   0,  16,   0,   0,   0, 
       0,   0,   6,   0,  16,   0, 
       0,   0,   0,   0,   2,  64, 
       0,   0, 182,  74, 204,  63, 
     205,  30,  80,  63,   0,   0, 
@@ -4543,17 +4595,17 @@ const BYTE YCbCrShaderMask[] =
      69,   0,   0,   9, 242,   0, 
      16,   0,   1,   0,   0,   0, 
      70,  16,  16,   0,   1,   0, 
       0,   0,  70, 126,  16,   0, 
       0,   0,   0,   0,   0,  96, 
      16,   0,   0,   0,   0,   0, 
       0,   0,   0,   7,  66,   0, 
      16,   0,   0,   0,   0,   0, 
-     58,   0,  16,   0,   1,   0, 
+     10,   0,  16,   0,   1,   0, 
       0,   0,   1,  64,   0,   0, 
      18, 131, 128, 189,  50,   0, 
       0,  10,  34,   0,  16,   0, 
       0,   0,   0,   0,  42,   0, 
      16,   0,   0,   0,   0,   0, 
       1,  64,   0,   0, 103,  10, 
     149,  63,  26,   0,  16, 128, 
      65,   0,   0,   0,   0,   0, 
@@ -4566,17 +4618,17 @@ const BYTE YCbCrShaderMask[] =
       0,   0,  69,   0,   0,   9, 
     242,   0,  16,   0,   2,   0, 
       0,   0,  70,  16,  16,   0, 
       1,   0,   0,   0,  70, 126, 
      16,   0,   1,   0,   0,   0, 
       0,  96,  16,   0,   0,   0, 
       0,   0,   0,   0,   0,   7, 
      18,   0,  16,   0,   0,   0, 
-      0,   0,  58,   0,  16,   0, 
+      0,   0,  10,   0,  16,   0, 
       2,   0,   0,   0,   1,  64, 
       0,   0, 115, 128,   0, 191, 
      50,   0,   0,  10,  34,   0, 
      16,   0,   1,   0,   0,   0, 
      10,   0,  16, 128,  65,   0, 
       0,   0,   0,   0,   0,   0, 
       1,  64,   0,   0, 196, 148, 
     200,  62,  26,   0,  16,   0, 
@@ -4604,23 +4656,23 @@ const BYTE YCbCrShaderMask[] =
      16,   0,   1,   0,   0,   0, 
     230,  26,  16,   0,   1,   0, 
       0,   0,  70, 126,  16,   0, 
       3,   0,   0,   0,   0,  96, 
      16,   0,   0,   0,   0,   0, 
      56,   0,   0,   7, 242,  32, 
      16,   0,   0,   0,   0,   0, 
      70,  14,  16,   0,   0,   0, 
-      0,   0, 246,  15,  16,   0, 
+      0,   0,   6,   0,  16,   0, 
       1,   0,   0,   0,  62,   0, 
       0,   1,  83,  84,  65,  84, 
     116,   0,   0,   0,  17,   0, 
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,   3,   0, 
-      0,   0,  11,   0,   0,   0, 
+      0,   0,   7,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   1,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       4,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -4742,19 +4794,19 @@ const BYTE YCbCrShaderMask[] =
      81, 117,  97, 100,   0, 118, 
      77,  97, 115, 107,  81, 117, 
      97, 100,   0,  77, 105,  99, 
     114, 111, 115, 111, 102, 116, 
      32,  40,  82,  41,  32,  72, 
      76,  83,  76,  32,  83, 104, 
      97, 100, 101, 114,  32,  67, 
     111, 109, 112, 105, 108, 101, 
-    114,  32,  54,  46,  51,  46, 
-     57,  54,  48,  48,  46,  49, 
-     54,  51,  56,  52,   0, 171, 
+    114,  32,  57,  46,  50,  57, 
+     46,  57,  53,  50,  46,  51, 
+     49,  49,  49,   0, 171, 171, 
      73,  83,  71,  78, 104,   0, 
       0,   0,   3,   0,   0,   0, 
       8,   0,   0,   0,  80,   0, 
       0,   0,   0,   0,   0,   0, 
       1,   0,   0,   0,   3,   0, 
       0,   0,   0,   0,   0,   0, 
      15,   0,   0,   0,  92,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -4776,17 +4828,22 @@ const BYTE YCbCrShaderMask[] =
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,  15,   0, 
       0,   0,  83,  86,  95,  84, 
      97, 114, 103, 101, 116,   0, 
     171, 171
 };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+//
+//   fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl
+//    -EComponentAlphaShaderMask -VnComponentAlphaShaderMask
+//    -FhtmpShaderHeader
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16 [unused]
@@ -4810,29 +4867,29 @@ const BYTE YCbCrShaderMask[] =
 // tRGBWhite                         texture  float4          2d    1        1
 // tMask                             texture  float4          2d    3        1
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Position              0   xyzw        0      POS   float       
-// TEXCOORD                 0   xy          1     NONE   float   xy  
-// TEXCOORD                 1     zw        1     NONE   float     zw
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Position              0   xyzw        0      POS  float       
+// TEXCOORD                 0   xy          1     NONE  float   xy  
+// TEXCOORD                 1     zw        1     NONE  float     zw
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Target                0   xyzw        0   TARGET   float   xyzw
-// SV_Target                1   xyzw        1   TARGET   float   xyzw
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Target                0   xyzw        0   TARGET  float   xyzw
+// SV_Target                1   xyzw        1   TARGET  float   xyzw
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c0         cb0             1         1  ( FLT, FLT, FLT, FLT)
 //
@@ -4851,17 +4908,17 @@ const BYTE YCbCrShaderMask[] =
     ps_2_x
     def c1, 1, 0, 0, 0
     dcl t0
     dcl_2d s0
     dcl_2d s1
     dcl_2d s2
     mov r0.xy, t0.wzzw
     texld r0, r0, s0
-    mul r0.x, r0.w, c0.x
+    mul r0.x, r0.x, c0.x
     texld r1, t0, s1
     texld r2, t0, s2
     add r2, r1, -r2
     add r2, r2, c1.x
     mov r1.w, r2.y
     mul r2, r0.x, r2
     mul r0, r0.x, r1
     mov oC0, r0
@@ -4880,29 +4937,29 @@ dcl_output o0.xyzw
 dcl_output o1.xyzw
 dcl_temps 3
 sample r0.xyzw, v1.xyxx, t1.xyzw, s0
 sample r1.xyzw, v1.xyxx, t0.xyzw, s0
 add r0.xyzw, -r0.xyzw, r1.xyzw
 add r0.xyzw, r0.xyzw, l(1.000000, 1.000000, 1.000000, 1.000000)
 mov r1.w, r0.y
 sample r2.xyzw, v1.zwzz, t3.xyzw, s0
-mul r2.x, r2.w, cb0[1].x
+mul r2.x, r2.x, cb0[1].x
 mul o0.xyzw, r1.xyzw, r2.xxxx
 mul o1.xyzw, r0.xyzw, r2.xxxx
 ret 
 // Approximately 10 instruction slots used
 #endif
 
 const BYTE ComponentAlphaShaderMask[] =
 {
-     68,  88,  66,  67, 245,  71, 
-    211, 223, 156, 101, 223, 204, 
-    145, 138,  53,  12,  16, 220, 
-    106,  83,   1,   0,   0,   0, 
+     68,  88,  66,  67, 214,  67, 
+    206,  69,  12, 117, 144,  46, 
+    127, 133, 145, 240,  56, 186, 
+    119, 195,   1,   0,   0,   0, 
      20,   7,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     124,   1,   0,   0,  52,   3, 
       0,   0, 176,   3,   0,   0, 
      88,   6,   0,   0, 200,   6, 
       0,   0,  65, 111, 110,  57, 
      60,   1,   0,   0,  60,   1, 
       0,   0,   0,   2, 255, 255, 
@@ -4928,17 +4985,17 @@ const BYTE ComponentAlphaShaderMask[] =
      15, 160,  31,   0,   0,   2, 
       0,   0,   0, 144,   2,   8, 
      15, 160,   1,   0,   0,   2, 
       0,   0,   3, 128,   0,   0, 
     235, 176,  66,   0,   0,   3, 
       0,   0,  15, 128,   0,   0, 
     228, 128,   0,   8, 228, 160, 
       5,   0,   0,   3,   0,   0, 
-      1, 128,   0,   0, 255, 128, 
+      1, 128,   0,   0,   0, 128, 
       0,   0,   0, 160,  66,   0, 
       0,   3,   1,   0,  15, 128, 
       0,   0, 228, 176,   1,   8, 
     228, 160,  66,   0,   0,   3, 
       2,   0,  15, 128,   0,   0, 
     228, 176,   2,   8, 228, 160, 
       2,   0,   0,   3,   2,   0, 
      15, 128,   1,   0, 228, 128, 
@@ -5012,17 +5069,17 @@ const BYTE ComponentAlphaShaderMask[] =
       0,   0,  69,   0,   0,   9, 
     242,   0,  16,   0,   2,   0, 
       0,   0, 230,  26,  16,   0, 
       1,   0,   0,   0,  70, 126, 
      16,   0,   3,   0,   0,   0, 
       0,  96,  16,   0,   0,   0, 
       0,   0,  56,   0,   0,   8, 
      18,   0,  16,   0,   2,   0, 
-      0,   0,  58,   0,  16,   0, 
+      0,   0,  10,   0,  16,   0, 
       2,   0,   0,   0,  10, 128, 
      32,   0,   0,   0,   0,   0, 
       1,   0,   0,   0,  56,   0, 
       0,   7, 242,  32,  16,   0, 
       0,   0,   0,   0,  70,  14, 
      16,   0,   1,   0,   0,   0, 
       6,   0,  16,   0,   2,   0, 
       0,   0,  56,   0,   0,   7, 
@@ -5039,17 +5096,17 @@ const BYTE ComponentAlphaShaderMask[] =
       0,   0,   0,   0,   1,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   1,   0, 
+      0,   0,   0,   0,   2,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,  82,  68,  69,  70, 
     160,   2,   0,   0,   1,   0, 
@@ -5157,19 +5214,19 @@ const BYTE ComponentAlphaShaderMask[] =
      97, 100,   0, 118,  77,  97, 
     115, 107,  81, 117,  97, 100, 
       0,  77, 105,  99, 114, 111, 
     115, 111, 102, 116,  32,  40, 
      82,  41,  32,  72,  76,  83, 
      76,  32,  83, 104,  97, 100, 
     101, 114,  32,  67, 111, 109, 
     112, 105, 108, 101, 114,  32, 
-     54,  46,  51,  46,  57,  54, 
-     48,  48,  46,  49,  54,  51, 
-     56,  52,   0, 171,  73,  83, 
+     57,  46,  50,  57,  46,  57, 
+     53,  50,  46,  51,  49,  49, 
+     49,   0, 171, 171,  73,  83, 
      71,  78, 104,   0,   0,   0, 
       3,   0,   0,   0,   8,   0, 
       0,   0,  80,   0,   0,   0, 
       0,   0,   0,   0,   1,   0, 
       0,   0,   3,   0,   0,   0, 
       0,   0,   0,   0,  15,   0, 
       0,   0,  92,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
--- a/gfx/layers/d3d11/CompositorD3D11ShadersVR.h
+++ b/gfx/layers/d3d11/CompositorD3D11ShadersVR.h
@@ -1,11 +1,15 @@
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+//
+//   fxc -nologo -Tvs_4_0_level_9_3 CompositorD3D11VR.hlsl
+//    -EOculusVRDistortionVS -VnOculusVRDistortionVS -FhtmpShaderHeader
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 VREyeToSource;              // Offset:    0 Size:    16
@@ -19,34 +23,34 @@
 // Name                                 Type  Format         Dim Slot Elements
 // ------------------------------ ---------- ------- ----------- ---- --------
 // $Globals                          cbuffer      NA          NA    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// POSITION                 0   xy          0     NONE   float   xy  
-// TEXCOORD                 0   xy          1     NONE   float   xy  
-// TEXCOORD                 1   xy          2     NONE   float   xy  
-// TEXCOORD                 2   xy          3     NONE   float   xy  
-// COLOR                    0   xyzw        4     NONE   float   xyzw
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// POSITION                 0   xy          0     NONE  float   xy  
+// TEXCOORD                 0   xy          1     NONE  float   xy  
+// TEXCOORD                 1   xy          2     NONE  float   xy  
+// TEXCOORD                 2   xy          3     NONE  float   xy  
+// COLOR                    0   xyzw        4     NONE  float   xyzw
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Position              0   xyzw        0      POS   float   xyzw
-// TEXCOORD                 0   xyz         1     NONE   float   xyz 
-// TEXCOORD                 1   xyz         2     NONE   float   xyz 
-// TEXCOORD                 2   xyz         3     NONE   float   xyz 
-// COLOR                    0   xyzw        4     NONE   float   xyzw
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Position              0   xyzw        0      POS  float   xyzw
+// TEXCOORD                 0   xyz         1     NONE  float   xyz 
+// TEXCOORD                 1   xyz         2     NONE  float   xyz 
+// TEXCOORD                 2   xyz         3     NONE  float   xyz 
+// COLOR                    0   xyzw        4     NONE  float   xyzw
 //
 //
 // Constant buffer to DX9 shader constant mappings:
 //
 // Target Reg Buffer  Start Reg # of Regs        Data Conversion
 // ---------- ------- --------- --------- ----------------------
 // c1         cb0             0         2  ( FLT, FLT, FLT, FLT)
 //
@@ -101,20 +105,20 @@ mad o3.xy, v3.xyxx, cb0[0].zwzz, cb0[0].
 mov o3.z, l(1.000000)
 mov o4.xyzw, v4.xyzw
 ret 
 // Approximately 10 instruction slots used
 #endif
 
 const BYTE OculusVRDistortionVS[] =
 {
-     68,  88,  66,  67,   3,  61, 
-    196, 122,  10,  53,  44, 234, 
-     18, 242, 195, 238,  42,  90, 
-     72, 193,   1,   0,   0,   0, 
+     68,  88,  66,  67, 206, 154, 
+    203,  64, 121,  47, 121, 169, 
+    222, 206, 108, 175, 167, 227, 
+    154,  37,   1,   0,   0,   0, 
     244,   5,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     108,   1,   0,   0,  44,   3, 
       0,   0, 168,   3,   0,   0, 
     176,   4,   0,   0,  80,   5, 
       0,   0,  65, 111, 110,  57, 
      44,   1,   0,   0,  44,   1, 
       0,   0,   0,   2, 254, 255, 
@@ -240,17 +244,17 @@ const BYTE OculusVRDistortionVS[] =
     128,  63,  54,   0,   0,   5, 
     242,  32,  16,   0,   4,   0, 
       0,   0,  70,  30,  16,   0, 
       4,   0,   0,   0,  62,   0, 
       0,   1,  83,  84,  65,  84, 
     116,   0,   0,   0,  10,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,  10,   0, 
-      0,   0,   4,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   1,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -298,19 +302,19 @@ const BYTE OculusVRDistortionVS[] =
      99,  97, 108, 101,  65, 110, 
     100,  79, 102, 102, 115, 101, 
     116,   0,  77, 105,  99, 114, 
     111, 115, 111, 102, 116,  32, 
      40,  82,  41,  32,  72,  76, 
      83,  76,  32,  83, 104,  97, 
     100, 101, 114,  32,  67, 111, 
     109, 112, 105, 108, 101, 114, 
-     32,  54,  46,  51,  46,  57, 
-     54,  48,  48,  46,  49,  54, 
-     51,  56,  52,   0, 171, 171, 
+     32,  57,  46,  50,  57,  46, 
+     57,  53,  50,  46,  51,  49, 
+     49,  49,   0, 171, 171, 171, 
      73,  83,  71,  78, 152,   0, 
       0,   0,   5,   0,   0,   0, 
       8,   0,   0,   0, 128,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   3,   0, 
       0,   0,   0,   0,   0,   0, 
       3,   3,   0,   0, 137,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -358,44 +362,48 @@ const BYTE OculusVRDistortionVS[] =
       0,   0,  83,  86,  95,  80, 
     111, 115, 105, 116, 105, 111, 
     110,   0,  84,  69,  88,  67, 
      79,  79,  82,  68,   0,  67, 
      79,  76,  79,  82,   0, 171
 };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
+//
+//
+//   fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11VR.hlsl
+//    -EOculusVRDistortionPS -VnOculusVRDistortionPS -FhtmpShaderHeader
 //
 //
 // Resource Bindings:
 //
 // Name                                 Type  Format         Dim Slot Elements
 // ------------------------------ ---------- ------- ----------- ---- --------
 // Linear                            sampler      NA          NA    0        1
 // Texture                           texture  float4          2d    0        1
 //
 //
 //
 // Input signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Position              0   xyzw        0      POS   float       
-// TEXCOORD                 0   xyz         1     NONE   float   xy  
-// TEXCOORD                 1   xyz         2     NONE   float   xy  
-// TEXCOORD                 2   xyz         3     NONE   float   xy  
-// COLOR                    0   xyzw        4     NONE   float   x   
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Position              0   xyzw        0      POS  float       
+// TEXCOORD                 0   xyz         1     NONE  float   xy  
+// TEXCOORD                 1   xyz         2     NONE  float   xy  
+// TEXCOORD                 2   xyz         3     NONE  float   xy  
+// COLOR                    0   xyzw        4     NONE  float   x   
 //
 //
 // Output signature:
 //
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Target                0   xyzw        0   TARGET   float   xyzw
+// Name                 Index   Mask Register SysValue Format   Used
+// -------------------- ----- ------ -------- -------- ------ ------
+// SV_Target                0   xyzw        0   TARGET  float   xyzw
 //
 //
 // Sampler/Resource to DX9 shader sampler mappings:
 //
 // Target Sampler Source Sampler  Source Resource
 // -------------- --------------- ----------------
 // s0             s0              t0               
 //
@@ -436,25 +444,25 @@ sample r0.xyzw, v3.xyxx, t0.xyzw, s0
 mul o0.z, r0.z, v4.x
 mov o0.w, l(1.000000)
 ret 
 // Approximately 8 instruction slots used
 #endif
 
 const BYTE OculusVRDistortionPS[] =
 {
-     68,  88,  66,  67, 108, 219, 
-     61, 216,  27,   0,  27, 222, 
-    242, 132, 183,  21, 166, 141, 
-    130,  39,   1,   0,   0,   0, 
-    128,   4,   0,   0,   6,   0, 
+     68,  88,  66,  67,  48, 161, 
+    127, 216, 149, 107,  53,  57, 
+    164,  84,  84, 154,  58, 227, 
+    125,  61,   1,   0,   0,   0, 
+    124,   4,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
      60,   1,   0,   0, 132,   2, 
       0,   0,   0,   3,   0,   0, 
-    168,   3,   0,   0,  76,   4, 
+    164,   3,   0,   0,  72,   4, 
       0,   0,  65, 111, 110,  57, 
     252,   0,   0,   0, 252,   0, 
       0,   0,   0,   2, 255, 255, 
     212,   0,   0,   0,  40,   0, 
       0,   0,   0,   0,  40,   0, 
       0,   0,  40,   0,   0,   0, 
      40,   0,   1,   0,  36,   0, 
       0,   0,  40,   0,   0,   0, 
@@ -564,17 +572,17 @@ const BYTE OculusVRDistortionPS[] =
       0,   0,   0,   0,   0,   0, 
       0,   0,   1,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
-     82,  68,  69,  70, 160,   0, 
+     82,  68,  69,  70, 156,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   2,   0, 
       0,   0,  28,   0,   0,   0, 
       0,   4, 255, 255,   0,   1, 
       0,   0, 107,   0,   0,   0, 
      92,   0,   0,   0,   3,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
@@ -589,48 +597,48 @@ const BYTE OculusVRDistortionPS[] =
     110, 101,  97, 114,   0,  84, 
     101, 120, 116, 117, 114, 101, 
       0,  77, 105,  99, 114, 111, 
     115, 111, 102, 116,  32,  40, 
      82,  41,  32,  72,  76,  83, 
      76,  32,  83, 104,  97, 100, 
     101, 114,  32,  67, 111, 109, 
     112, 105, 108, 101, 114,  32, 
-     54,  46,  51,  46,  57,  54, 
-     48,  48,  46,  49,  54,  51, 
-     56,  52,   0, 171, 171, 171, 
-     73,  83,  71,  78, 156,   0, 
-      0,   0,   5,   0,   0,   0, 
-      8,   0,   0,   0, 128,   0, 
-      0,   0,   0,   0,   0,   0, 
-      1,   0,   0,   0,   3,   0, 
-      0,   0,   0,   0,   0,   0, 
-     15,   0,   0,   0, 140,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   3,   0, 
-      0,   0,   1,   0,   0,   0, 
-      7,   3,   0,   0, 140,   0, 
+     57,  46,  50,  57,  46,  57, 
+     53,  50,  46,  51,  49,  49, 
+     49,   0,  73,  83,  71,  78, 
+    156,   0,   0,   0,   5,   0, 
+      0,   0,   8,   0,   0,   0, 
+    128,   0,   0,   0,   0,   0, 
       0,   0,   1,   0,   0,   0, 
-      0,   0,   0,   0,   3,   0, 
-      0,   0,   2,   0,   0,   0, 
-      7,   3,   0,   0, 140,   0, 
-      0,   0,   2,   0,   0,   0, 
-      0,   0,   0,   0,   3,   0, 
-      0,   0,   3,   0,   0,   0, 
-      7,   3,   0,   0, 149,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   3,   0, 
-      0,   0,   4,   0,   0,   0, 
-     15,   1,   0,   0,  83,  86, 
-     95,  80, 111, 115, 105, 116, 
-    105, 111, 110,   0,  84,  69, 
-     88,  67,  79,  79,  82,  68, 
-      0,  67,  79,  76,  79,  82, 
-      0, 171,  79,  83,  71,  78, 
-     44,   0,   0,   0,   1,   0, 
-      0,   0,   8,   0,   0,   0, 
-     32,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
       3,   0,   0,   0,   0,   0, 
       0,   0,  15,   0,   0,   0, 
-     83,  86,  95,  84,  97, 114, 
-    103, 101, 116,   0, 171, 171
+    140,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      3,   0,   0,   0,   1,   0, 
+      0,   0,   7,   3,   0,   0, 
+    140,   0,   0,   0,   1,   0, 
+      0,   0,   0,   0,   0,   0, 
+      3,   0,   0,   0,   2,   0, 
+      0,   0,   7,   3,   0,   0, 
+    140,   0,   0,   0,   2,   0, 
+      0,   0,   0,   0,   0,   0, 
+      3,   0,   0,   0,   3,   0, 
+      0,   0,   7,   3,   0,   0, 
+    149,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      3,   0,   0,   0,   4,   0, 
+      0,   0,  15,   1,   0,   0, 
+     83,  86,  95,  80, 111, 115, 
+    105, 116, 105, 111, 110,   0, 
+     84,  69,  88,  67,  79,  79, 
+     82,  68,   0,  67,  79,  76, 
+     79,  82,   0, 171,  79,  83, 
+     71,  78,  44,   0,   0,   0, 
+      1,   0,   0,   0,   8,   0, 
+      0,   0,  32,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   3,   0,   0,   0, 
+      0,   0,   0,   0,  15,   0, 
+      0,   0,  83,  86,  95,  84, 
+     97, 114, 103, 101, 116,   0, 
+    171, 171
 };
--- a/gfx/layers/d3d11/TextureD3D11.cpp
+++ b/gfx/layers/d3d11/TextureD3D11.cpp
@@ -29,17 +29,17 @@ SurfaceFormatToDXGIFormat(gfx::SurfaceFo
       return DXGI_FORMAT_B8G8R8A8_UNORM;
     case SurfaceFormat::B8G8R8X8:
       return DXGI_FORMAT_B8G8R8A8_UNORM;
     case SurfaceFormat::R8G8B8A8:
       return DXGI_FORMAT_R8G8B8A8_UNORM;
     case SurfaceFormat::R8G8B8X8:
       return DXGI_FORMAT_R8G8B8A8_UNORM;
     case SurfaceFormat::A8: