Merge m-c to fx-team, a=merge
authorWes Kocher <wkocher@mozilla.com>
Fri, 14 Oct 2016 14:51:15 -0700
changeset 318084 9696d132b1691d15ff845550d13ef9a6cfc78049
parent 318083 e412b386433b8c8ba83a28a1df310d9ad0b20285 (current diff)
parent 318044 de5d73a0568d1c3d50da32169026cc68ee09b1ae (diff)
child 318085 6ed5592738b6c40ea8aefcf8b699de9f60f30a91
push id33211
push usercbook@mozilla.com
push dateMon, 17 Oct 2016 09:38:38 +0000
treeherderautoland@e4ef6fa03aa8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone52.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to fx-team, a=merge
gfx/layers/d3d11/CompositorD3D11Shaders.h
gfx/layers/d3d9/LayerManagerD3D9Shaders.h
--- a/browser/base/content/browser-media.js
+++ b/browser/base/content/browser-media.js
@@ -229,16 +229,20 @@ let gDecoderDoctorHandler = {
       }
       if (AppConstants.platform == "linux") {
         return gNavigatorBundle.getString("decoder.noCodecsLinux.message");
       }
     }
     if (type == "cannot-initialize-pulseaudio") {
       return gNavigatorBundle.getString("decoder.noPulseAudio.message");
     }
+    if (type == "unsupported-libavcodec" &&
+        AppConstants.platform == "linux") {
+      return gNavigatorBundle.getString("decoder.unsupportedLibavcodec.message");
+    }
     return "";
   },
 
   getSumoForLearnHowButton(type) {
     if (AppConstants.platform == "win") {
       return "fix-video-audio-problems-firefox-windows";
     }
     if (type == "cannot-initialize-pulseaudio") {
--- a/browser/base/content/test/general/browser_decoderDoctor.js
+++ b/browser/base/content/test/general/browser_decoderDoctor.js
@@ -103,8 +103,20 @@ add_task(function* test_cannot_initializ
     return;
   }
 
   let message = gNavigatorBundle.getString("decoder.noPulseAudio.message");
   yield test_decoder_doctor_notification("cannot-initialize-pulseaudio",
                                          message,
                                          {sumo: "fix-common-audio-and-video-issues"});
 });
+
+add_task(function* test_unsupported_libavcodec() {
+  // This is only sent on Linux.
+  if (AppConstants.platform != "linux") {
+    return;
+  }
+
+  let message = gNavigatorBundle.getString("decoder.unsupportedLibavcodec.message");
+  yield test_decoder_doctor_notification("unsupported-libavcodec",
+                                         message,
+                                         {noLearnMoreButton: true});
+});
--- a/browser/components/extensions/ext-windows.js
+++ b/browser/components/extensions/ext-windows.js
@@ -155,38 +155,34 @@ extensions.registerSchemaAPI("windows", 
 
         WindowManager.updateGeometry(window, createData);
 
         // TODO: focused, type
 
         return new Promise(resolve => {
           window.addEventListener("load", function listener() {
             window.removeEventListener("load", listener);
-
-            if (createData.state == "maximized" || createData.state == "normal" ||
-                (createData.state == "fullscreen" && AppConstants.platform != "macosx")) {
+            if (["maximized", "normal"].includes(createData.state)) {
               window.document.documentElement.setAttribute("sizemode", createData.state);
-            } else if (createData.state !== null) {
-              // window.minimize() has no effect until the window has been shown.
-              return promiseObserved("document-shown", doc => doc == window.document).then(() => {
-                WindowManager.setState(window, createData.state);
-                resolve();
-              });
             }
-            resolve();
+            resolve(promiseObserved("browser-delayed-startup-finished", win => win == window));
           });
         }).then(() => {
+          // Some states only work after delayed-startup-finished
+          if (["minimized", "fullscreen", "docked"].includes(createData.state)) {
+            WindowManager.setState(window, createData.state);
+          }
           if (allowScriptsToClose) {
             for (let {linkedBrowser} of window.gBrowser.tabs) {
               onXULFrameLoaderCreated({target: linkedBrowser});
               linkedBrowser.addEventListener( // eslint-disable-line mozilla/balanced-listeners
                                              "XULFrameLoaderCreated", onXULFrameLoaderCreated);
             }
           }
-          return WindowManager.convert(extension, window);
+          return WindowManager.convert(extension, window, {populate: true});
         });
       },
 
       update: function(windowId, updateInfo) {
         if (updateInfo.state !== null && updateInfo.state != "normal") {
           if (updateInfo.left !== null || updateInfo.top !== null ||
               updateInfo.width !== null || updateInfo.height !== null) {
             return Promise.reject({message: `"state": "${updateInfo.state}" may not be combined with "left", "top", "width", or "height"`});
--- a/browser/components/extensions/test/browser/browser_ext_windows_create.js
+++ b/browser/components/extensions/test/browser/browser_ext_windows_create.js
@@ -30,16 +30,17 @@ add_task(function* testWindowCreate() {
               // "maximized" states.
               browser.test.assertTrue(window.state == "normal" || window.state == "maximized",
                                       `Expected window.state (currently ${window.state}) to be "normal" but will accept "maximized"`);
             } else {
               browser.test.assertEq(params[key], window[key], `Got expected value for window.${key}`);
             }
           }
 
+          browser.test.assertEq(1, window.tabs.length, "tabs property got populated");
           return checkWindow(expected).then(() => {
             if (keep) {
               return window;
             }
             if (params.state == "fullscreen" && os == "win") {
               // FIXME: Closing a fullscreen window causes a window leak in
               // Windows tests.
               return browser.windows.update(window.id, {state: "normal"}).then(() => {
--- a/browser/components/extensions/test/browser/browser_ext_windows_create_tabId.js
+++ b/browser/components/extensions/test/browser/browser_ext_windows_create_tabId.js
@@ -19,35 +19,37 @@ add_task(function* testWindowCreate() {
           if (changeInfo.url === expected) {
             browser.tabs.onUpdated.removeListener(listener);
             resolve();
           }
         });
       });
     };
 
-    let windowId;
+    let windowId, tabId;
     browser.windows.getCurrent().then(window => {
       windowId = window.id;
 
       browser.test.log("Create additional tab in window 1");
       return browser.tabs.create({windowId, url: "about:blank"});
     }).then(tab => {
+      tabId = tab.id;
       browser.test.log("Create a new window, adopting the new tab");
 
       // Note that we want to check against actual boolean values for
       // all of the `incognito` property tests.
       browser.test.assertEq(false, tab.incognito, "Tab is not private");
 
       return Promise.all([
         promiseTabAttached(),
-        browser.windows.create({tabId: tab.id}),
+        browser.windows.create({tabId: tabId}),
       ]);
     }).then(([, window]) => {
       browser.test.assertEq(false, window.incognito, "New window is not private");
+      browser.test.assertEq(tabId, window.tabs[0].id, "tabs property populated correctly");
 
       browser.test.log("Close the new window");
       return browser.windows.remove(window.id);
     }).then(() => {
       browser.test.log("Create a new private window");
 
       return browser.windows.create({incognito: true});
     }).then(privateWindow => {
@@ -108,16 +110,20 @@ add_task(function* testWindowCreate() {
                                   "Create call failed as expected");
         }
       );
     }).then(() => {
       browser.test.log("Try to create a window with two URLs");
 
       return browser.windows.create({url: ["http://example.com/", "http://example.org/"]});
     }).then(window => {
+      browser.test.assertEq(2, window.tabs.length, "2 tabs were opened in new window");
+      browser.test.assertEq("about:blank", window.tabs[0].url, "about:blank, page not loaded yet");
+      browser.test.assertEq("about:blank", window.tabs[1].url, "about:blank, page not loaded yet");
+
       return Promise.all([
         promiseTabUpdated("http://example.com/"),
         promiseTabUpdated("http://example.org/"),
         Promise.resolve(window),
       ]);
     }).then(([, , window]) => {
       return browser.windows.get(window.id, {populate: true});
     }).then(window => {
@@ -140,9 +146,8 @@ add_task(function* testWindowCreate() {
 
     background,
   });
 
   yield extension.startup();
   yield extension.awaitFinish("window-create");
   yield extension.unload();
 });
-
--- a/browser/components/uitour/UITour.jsm
+++ b/browser/components/uitour/UITour.jsm
@@ -6,16 +6,17 @@
 
 this.EXPORTED_SYMBOLS = ["UITour"];
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/AppConstants.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Preferences.jsm");
 Cu.import("resource://gre/modules/Promise.jsm");
 Cu.import("resource:///modules/RecentWindow.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/TelemetryController.jsm");
 Cu.import("resource://gre/modules/Timer.jsm");
 
 Cu.importGlobalProperties(["URL"]);
 
@@ -1860,16 +1861,19 @@ this.UITour = {
             data = {engines: [], searchEngineIdentifier: ""};
           }
           this.sendPageCallback(aMessageManager, aCallbackID, data);
         });
         break;
       case "sync":
         this.sendPageCallback(aMessageManager, aCallbackID, {
           setup: Services.prefs.prefHasUserValue("services.sync.username"),
+          desktopDevices: Preferences.get("services.sync.clients.devices.desktop", 0),
+          mobileDevices: Preferences.get("services.sync.clients.devices.mobile", 0),
+          totalDevices: Preferences.get("services.sync.numClients", 0),
         });
         break;
       case "canReset":
         this.sendPageCallback(aMessageManager, aCallbackID, ResetProfile.resetSupported());
         break;
       default:
         log.error("getConfiguration: Unknown configuration requested: " + aConfiguration);
         break;
--- a/browser/components/uitour/test/browser_UITour_sync.js
+++ b/browser/components/uitour/test/browser_UITour_sync.js
@@ -16,16 +16,44 @@ add_UITour_task(function* test_checkSync
 });
 
 add_UITour_task(function* test_checkSyncSetup_enabled() {
   Services.prefs.setCharPref("services.sync.username", "uitour@tests.mozilla.org");
   let result = yield getConfigurationPromise("sync");
   is(result.setup, true, "Sync should be setup");
 });
 
+add_UITour_task(function* test_checkSyncCounts() {
+  Services.prefs.setIntPref("services.sync.clients.devices.desktop", 4);
+  Services.prefs.setIntPref("services.sync.clients.devices.mobile", 5);
+  Services.prefs.setIntPref("services.sync.numClients", 9);
+  let result = yield getConfigurationPromise("sync");
+  is(result.mobileDevices, 5, "mobileDevices should be set");
+  is(result.desktopDevices, 4, "desktopDevices should be set");
+  is(result.totalDevices, 9, "totalDevices should be set");
+
+  Services.prefs.clearUserPref("services.sync.clients.devices.desktop");
+  result = yield getConfigurationPromise("sync");
+  is(result.mobileDevices, 5, "mobileDevices should be set");
+  is(result.desktopDevices, 0, "desktopDevices should be 0");
+  is(result.totalDevices, 9, "totalDevices should be set");
+
+  Services.prefs.clearUserPref("services.sync.clients.devices.mobile");
+  result = yield getConfigurationPromise("sync");
+  is(result.mobileDevices, 0, "mobileDevices should be 0");
+  is(result.desktopDevices, 0, "desktopDevices should be 0");
+  is(result.totalDevices, 9, "totalDevices should be set");
+
+  Services.prefs.clearUserPref("services.sync.numClients");
+  result = yield getConfigurationPromise("sync");
+  is(result.mobileDevices, 0, "mobileDevices should be 0");
+  is(result.desktopDevices, 0, "desktopDevices should be 0");
+  is(result.totalDevices, 0, "totalDevices should be 0");
+});
+
 // The showFirefoxAccounts API is sync related, so we test that here too...
 add_UITour_task(function* test_firefoxAccountsNoParams() {
   yield gContentAPI.showFirefoxAccounts();
   yield BrowserTestUtils.browserLoaded(gTestTab.linkedBrowser, false,
                                        "about:accounts?action=signup&entrypoint=uitour");
 });
 
 add_UITour_task(function* test_firefoxAccountsValidParams() {
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -730,16 +730,17 @@ decoder.noCodecs.button = Learn how
 decoder.noCodecs.accesskey = L
 decoder.noCodecs.message = To play video, you may need to install Microsoft’s Media Feature Pack.
 decoder.noCodecsVista.message = To play video, you may need to install Microsoft’s Platform Update Supplement for Windows Vista.
 decoder.noCodecsXP.message = To play video, you may need to enable Adobe’s Primetime Content Decryption Module.
 decoder.noCodecsLinux.message = To play video, you may need to install the required video codecs.
 decoder.noHWAcceleration.message = To improve video quality, you may need to install Microsoft’s Media Feature Pack.
 decoder.noHWAccelerationVista.message = To improve video quality, you may need to install Microsoft’s Platform Update Supplement for Windows Vista.
 decoder.noPulseAudio.message = To play audio, you may need to install the required PulseAudio software.
+decoder.unsupportedLibavcodec.message = libavcodec may be vulnerable or is not supported, and should be updated to play video.
 
 permissions.remove.tooltip = Clear this permission and ask again
 
 # LOCALIZATION NOTE (aboutDialog.architecture.*):
 # The sixtyFourBit and thirtyTwoBit strings describe the architecture of the
 # current Firefox build: 32-bit or 64-bit. These strings are used in parentheses
 # between the Firefox version and the "What's new" link in the About dialog,
 # e.g.: "48.0.2 (32-bit) <What's new>" or "51.0a1 (2016-09-05) (64-bit)".
--- a/devtools/client/debugger/debugger-view.js
+++ b/devtools/client/debugger/debugger-view.js
@@ -447,17 +447,17 @@ var DebuggerView = {
    */
   _setEditorMode: function (aUrl, aContentType = "", aTextContent = "") {
     // Use JS mode for files with .js and .jsm extensions.
     if (SourceUtils.isJavaScript(aUrl, aContentType)) {
       return void this.editor.setMode(Editor.modes.js);
     }
 
     if (aContentType === "text/wasm") {
-      return void this.editor.setMode(Editor.modes.wasm);
+      return void this.editor.setMode(Editor.modes.text);
     }
 
     // Use HTML mode for files in which the first non whitespace character is
     // &lt;, regardless of extension.
     if (aTextContent.match(/^\s*</)) {
       return void this.editor.setMode(Editor.modes.html);
     }
 
--- a/devtools/client/locales/en-US/netmonitor.properties
+++ b/devtools/client/locales/en-US/netmonitor.properties
@@ -300,8 +300,56 @@ netRequest.cookies=Cookies
 # LOCALIZATION NOTE (netRequest.params): A label used for URL parameters tab
 # This tab displays data parsed from URL query string.
 netRequest.params=Params
 
 # LOCALIZATION NOTE (netRequest.callstack): A label used for request stacktrace tab
 # This tab displays the request's JavaScript stack trace. Should be identical to
 # debuggerUI.tabs.callstack
 netRequest.callstack=Call Stack
+
+# LOCALIZATION NOTE (certmgr.subjectinfo.label):
+# A label used for a certificate section in security tab.
+# This section displays Name and organization who has been assigned the fingerprints
+certmgr.subjectinfo.label=Issued To
+
+# LOCALIZATION NOTE (certmgr.certdetail.cn):
+# A label used for Issued To and Issued By sub-section in security tab
+certmgr.certdetail.cn=Common Name (CN):
+
+# LOCALIZATION NOTE (certmgr.certdetail.o):
+# A label used for Issued To and Issued By sub-section in security tab
+certmgr.certdetail.o=Organization (O):
+
+# LOCALIZATION NOTE (certmgr.certdetail.ou):
+# A label used for Issued To and Issued By sub-section in security tab
+certmgr.certdetail.ou=Organizational Unit (OU):
+
+# LOCALIZATION NOTE (certmgr.issuerinfo.label):
+# A label used for a certificate section in security tab
+# This section displays Name and organization who issued the fingerprints
+certmgr.issuerinfo.label=Issued By
+
+# LOCALIZATION NOTE (certmgr.periodofvalidity.label):
+# A label used for a certificate section in security tab
+# This section displays the valide period of this fingerprints
+certmgr.periodofvalidity.label=Period of Validity
+
+# LOCALIZATION NOTE (certmgr.certdetail.cn):
+# A label used for Period of Validity sub-section in security tab
+certmgr.begins=Begins On:
+
+# LOCALIZATION NOTE (certmgr.certdetail.cn):
+# A label used for Period of Validity sub-section in security tab
+certmgr.expires=Expires On:
+
+# LOCALIZATION NOTE (certmgr.fingerprints.label):
+# A label used for a certificate section in security tab
+# This section displays the valide period of this fingerprints
+certmgr.fingerprints.label=Fingerprints
+
+# LOCALIZATION NOTE (certmgr.certdetail.sha256fingerprint):
+# A label used for Fingerprints sub-section in security tab
+certmgr.certdetail.sha256fingerprint=SHA-256 Fingerprint:
+
+# LOCALIZATION NOTE (certmgr.certdetail.sha1fingerprint):
+# A label used for Fingerprints sub-section in security tab
+certmgr.certdetail.sha1fingerprint=SHA1 Fingerprint:
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/.eslintrc
@@ -0,0 +1,12 @@
+{
+  // Extend from the devtools eslintrc.
+  "extends": "../../.eslintrc",
+
+  "rules": {
+    // The netmonitor is being migrated to HTML and cleaned of
+    // chrome-privileged code, so this rule disallows requiring chrome
+    // code. Some files in the netmonitor disable this rule still. The
+    // goal is to enable the rule globally on all files.
+    "mozilla/reject-some-requires": [2, "^(chrome|chrome:.*|resource:.*|devtools/server/.*|.*\\.jsm|devtools/shared/platform/(chome|content)/.*)$"],
+  },
+}
--- a/devtools/client/netmonitor/har/har-automation.js
+++ b/devtools/client/netmonitor/har/har-automation.js
@@ -1,13 +1,13 @@
 /* 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";
-
+/* eslint-disable mozilla/reject-some-requires */
 const { Ci } = require("chrome");
 const { Class } = require("sdk/core/heritage");
 const { resolve } = require("promise");
 const Services = require("Services");
 
 loader.lazyRequireGetter(this, "HarCollector", "devtools/client/netmonitor/har/har-collector", true);
 loader.lazyRequireGetter(this, "HarExporter", "devtools/client/netmonitor/har/har-exporter", true);
 loader.lazyRequireGetter(this, "HarUtils", "devtools/client/netmonitor/har/har-utils", true);
--- a/devtools/client/netmonitor/har/har-exporter.js
+++ b/devtools/client/netmonitor/har/har-exporter.js
@@ -1,16 +1,17 @@
 /* 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";
-
+/* eslint-disable mozilla/reject-some-requires */
 const { Cc, Ci } = require("chrome");
 const Services = require("Services");
+/* eslint-disable mozilla/reject-some-requires */
 const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
 const { resolve } = require("promise");
 const { HarUtils } = require("./har-utils.js");
 const { HarBuilder } = require("./har-builder.js");
 
 XPCOMUtils.defineLazyGetter(this, "clipboardHelper", function () {
   return Cc["@mozilla.org/widget/clipboardhelper;1"]
     .getService(Ci.nsIClipboardHelper);
--- a/devtools/client/netmonitor/har/har-utils.js
+++ b/devtools/client/netmonitor/har/har-utils.js
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
-
+/* eslint-disable mozilla/reject-some-requires */
 const { Ci, Cc, CC } = require("chrome");
+/* eslint-disable mozilla/reject-some-requires */
 const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "dirService", function () {
   return Cc["@mozilla.org/file/directory_service;1"]
     .getService(Ci.nsIProperties);
 });
 
 XPCOMUtils.defineLazyGetter(this, "ZipWriter", function () {
--- a/devtools/client/netmonitor/netmonitor-controller.js
+++ b/devtools/client/netmonitor/netmonitor-controller.js
@@ -30,16 +30,17 @@ var BrowserLoaderModule = {};
 Cu.import("resource://devtools/client/shared/browser-loader.js", BrowserLoaderModule);
 var { loader, require } = BrowserLoaderModule.BrowserLoader({
   baseURI: "resource://devtools/client/netmonitor/",
   window
 });
 
 const promise = require("promise");
 const Services = require("Services");
+/* eslint-disable mozilla/reject-some-requires */
 const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
 const EventEmitter = require("devtools/shared/event-emitter");
 const Editor = require("devtools/client/sourceeditor/editor");
 const {TimelineFront} = require("devtools/shared/fronts/timeline");
 const {Task} = require("devtools/shared/task");
 const {Prefs} = require("./prefs");
 const {EVENTS} = require("./events");
 
--- a/devtools/client/netmonitor/netmonitor-view.js
+++ b/devtools/client/netmonitor/netmonitor-view.js
@@ -7,17 +7,19 @@
 /* globals Prefs, gNetwork, setInterval, setTimeout, clearInterval, clearTimeout, btoa */
 /* exported $, $all */
 "use strict";
 
 XPCOMUtils.defineLazyGetter(this, "NetworkHelper", function () {
   return require("devtools/shared/webconsole/network-helper");
 });
 
+/* eslint-disable mozilla/reject-some-requires */
 const {VariablesView} = require("resource://devtools/client/shared/widgets/VariablesView.jsm");
+/* eslint-disable mozilla/reject-some-requires */
 const {VariablesViewController} = require("resource://devtools/client/shared/widgets/VariablesViewController.jsm");
 const {ToolSidebar} = require("devtools/client/framework/sidebar");
 const {testing: isTesting} = require("devtools/shared/flags");
 const {ViewHelpers, Heritage} = require("devtools/client/shared/widgets/view-helpers");
 const {PluralForm} = require("devtools/shared/plural-form");
 const {Filters} = require("./filter-predicates");
 const {getFormDataSections,
        formDataURI,
--- a/devtools/client/netmonitor/netmonitor.xul
+++ b/devtools/client/netmonitor/netmonitor.xul
@@ -4,18 +4,16 @@
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
 <?xml-stylesheet href="chrome://devtools/content/shared/widgets/widgets.css" type="text/css"?>
 <?xml-stylesheet href="chrome://devtools/skin/widgets.css" type="text/css"?>
 <?xml-stylesheet href="chrome://devtools/skin/netmonitor.css" type="text/css"?>
 <!DOCTYPE window [
   <!ENTITY % netmonitorDTD SYSTEM "chrome://devtools/locale/netmonitor.dtd">
   %netmonitorDTD;
-  <!ENTITY % certManagerDTD SYSTEM "chrome://pippki/locale/certManager.dtd">
-  %certManagerDTD;
 ]>
 
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         xmlns:html="http://www.w3.org/1999/xhtml">
 
   <script type="application/javascript;version=1.8"
           src="chrome://devtools/content/shared/theme-switching.js"/>
   <script type="text/javascript" src="netmonitor-controller.js"/>
@@ -83,17 +81,20 @@
 
   <keyset>
     <key id="freeTextFilterKey"
          key="&netmonitorUI.footer.filterFreetext.key;"
          modifiers="accel"
          command="freeTextFilterCommand"/>
   </keyset>
 
-  <deck id="body" class="theme-sidebar" flex="1">
+  <deck id="body"
+        class="theme-sidebar"
+        data-localization-bundle="devtools/locale/netmonitor.properties"
+        flex="1">
 
     <vbox id="network-inspector-view" flex="1">
       <hbox id="netmonitor-toolbar" class="devtools-toolbar">
         <toolbarbutton id="requests-menu-clear-button"
                        class="devtools-toolbarbutton devtools-clear-icon"
                        tooltiptext="&netmonitorUI.footer.clear;"/>
         <hbox id="requests-menu-filter-buttons">
           <button id="requests-menu-filter-all-button"
@@ -715,122 +716,125 @@
                     </vbox>
                     <vbox id="security-info-certificate"
                           class="tabpanel-summary-container">
                         <label class="plain tabpanel-summary-label"
                                value="&netmonitorUI.security.certificate;"/>
                       <vbox class="security-info-section">
                         <vbox class="tabpanel-summary-container">
                           <label class="plain tabpanel-summary-label"
-                                 value="&certmgr.subjectinfo.label;" flex="1"/>
+                                 data-localization="content=certmgr.subjectinfo.label" flex="1"/>
                         </vbox>
                         <vbox class="security-info-section">
                           <hbox class="tabpanel-summary-container"
                                 align="baseline">
                             <label class="plain tabpanel-summary-label"
-                                   value="&certmgr.certdetail.cn;:"/>
+                                   data-localization="content=certmgr.certdetail.cn"/>
                             <textbox id="security-cert-subject-cn"
                                      class="plain tabpanel-summary-value devtools-monospace cropped-textbox"
                                      flex="1"
                                      readonly="true"/>
                           </hbox>
                           <hbox class="tabpanel-summary-container"
                                 align="baseline">
                             <label class="plain tabpanel-summary-label"
-                                   value="&certmgr.certdetail.o;:"/>
+                                   data-localization="content=certmgr.certdetail.o"/>
                             <textbox id="security-cert-subject-o"
                                      class="plain tabpanel-summary-value devtools-monospace cropped-textbox"
                                      flex="1"
                                      readonly="true"/>
                           </hbox>
                           <hbox class="tabpanel-summary-container"
                                 align="baseline">
                             <label class="plain tabpanel-summary-label"
-                                   value="&certmgr.certdetail.ou;:"/>
+                                   data-localization="content=certmgr.certdetail.ou"/>
                             <textbox id="security-cert-subject-ou"
                                      class="plain tabpanel-summary-value devtools-monospace cropped-textbox"
                                      flex="1"
                                      readonly="true"/>
                           </hbox>
                         </vbox>
                         <vbox class="tabpanel-summary-container">
                           <label class="plain tabpanel-summary-label"
-                                 value="&certmgr.issuerinfo.label;" flex="1"/>
+                                 data-localization="content=certmgr.issuerinfo.label"
+                                 flex="1"/>
                         </vbox>
                         <vbox class="security-info-section">
                           <hbox class="tabpanel-summary-container"
                                 align="baseline">
                             <label class="plain tabpanel-summary-label"
-                                   value="&certmgr.certdetail.cn;:"/>
+                                   data-localization="content=certmgr.certdetail.cn"/>
                             <textbox id="security-cert-issuer-cn"
                                      class="plain tabpanel-summary-value devtools-monospace cropped-textbox"
                                      flex="1"
                                      readonly="true"/>
                           </hbox>
                           <hbox class="tabpanel-summary-container"
                                 align="baseline">
                             <label class="plain tabpanel-summary-label"
-                                   value="&certmgr.certdetail.o;:"/>
+                                   data-localization="content=certmgr.certdetail.o"/>
                             <textbox id="security-cert-issuer-o"
                                      class="plain tabpanel-summary-value devtools-monospace cropped-textbox"
                                      flex="1"
                                      readonly="true"/>
                           </hbox>
                           <hbox class="tabpanel-summary-container"
                                 align="baseline">
                             <label class="plain tabpanel-summary-label"
-                                   value="&certmgr.certdetail.ou;:"/>
+                                   data-localization="content=certmgr.certdetail.ou"/>
                             <textbox id="security-cert-issuer-ou"
                                      class="plain tabpanel-summary-value devtools-monospace cropped-textbox"
                                      flex="1"
                                      readonly="true"/>
                           </hbox>
                         </vbox>
                         <vbox class="tabpanel-summary-container">
                           <label class="plain tabpanel-summary-label"
-                                 value="&certmgr.periodofvalidity.label;" flex="1"/>
+                                 data-localization="content=certmgr.periodofvalidity.label"
+                                 flex="1"/>
                         </vbox>
                         <vbox class="security-info-section">
                           <hbox class="tabpanel-summary-container"
                                 align="baseline">
                             <label class="plain tabpanel-summary-label"
-                                   value="&certmgr.begins;:"/>
+                                   data-localization="content=certmgr.begins"/>
                             <textbox id="security-cert-validity-begins"
                                      class="plain tabpanel-summary-value devtools-monospace cropped-textbox"
                                      flex="1"
                                      readonly="true"/>
                           </hbox>
                           <hbox class="tabpanel-summary-container"
                                 align="baseline">
                             <label class="plain tabpanel-summary-label"
-                                   value="&certmgr.expires;:"/>
+                                   data-localization="content=certmgr.expires"/>
                             <textbox id="security-cert-validity-expires"
                                      class="plain tabpanel-summary-value devtools-monospace cropped-textbox"
                                      flex="1"
                                      readonly="true"/>
                           </hbox>
                         </vbox>
                         <vbox class="tabpanel-summary-container">
                           <label class="plain tabpanel-summary-label"
-                                 value="&certmgr.fingerprints.label;" flex="1"/>
+                                 data-localization="content=certmgr.fingerprints.label"
+                                 flex="1"/>
                         </vbox>
                         <vbox class="security-info-section">
                           <hbox class="tabpanel-summary-container"
                                 align="baseline">
                             <label class="plain tabpanel-summary-label"
-                                   value="&certmgr.certdetail.sha256fingerprint;:"/>
+                                   data-localization="content=certmgr.certdetail.sha256fingerprint"/>
                             <textbox id="security-cert-sha256-fingerprint"
                                      class="plain tabpanel-summary-value devtools-monospace cropped-textbox"
                                      flex="1"
                                      readonly="true"/>
                           </hbox>
                           <hbox class="tabpanel-summary-container"
                                 align="baseline">
                             <label class="plain tabpanel-summary-label"
-                                   value="&certmgr.certdetail.sha1fingerprint;:"/>
+                                   data-localization="content=certmgr.certdetail.sha1fingerprint"/>
                             <textbox id="security-cert-sha1-fingerprint"
                                      class="plain tabpanel-summary-value devtools-monospace cropped-textbox"
                                      flex="1"
                                      readonly="true"/>
                           </hbox>
                         </vbox>
                       </vbox>
                     </vbox>
--- a/devtools/client/netmonitor/panel.js
+++ b/devtools/client/netmonitor/panel.js
@@ -3,19 +3,21 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const promise = require("promise");
 const EventEmitter = require("devtools/shared/event-emitter");
 const { Task } = require("devtools/shared/task");
+const { localizeMarkup } = require("devtools/shared/l10n");
 
 function NetMonitorPanel(iframeWindow, toolbox) {
   this.panelWin = iframeWindow;
+  this.panelDoc = iframeWindow.document;
   this._toolbox = toolbox;
 
   this._view = this.panelWin.NetMonitorView;
   this._controller = this.panelWin.NetMonitorController;
   this._controller._target = this.target;
   this._controller._toolbox = this._toolbox;
 
   EventEmitter.decorate(this);
@@ -29,16 +31,19 @@ NetMonitorPanel.prototype = {
    *
    * @return object
    *         A promise that is resolved when the NetMonitor completes opening.
    */
   open: Task.async(function* () {
     if (this._opening) {
       return this._opening;
     }
+    // Localize all the nodes containing a data-localization attribute.
+    localizeMarkup(this.panelDoc);
+
     let deferred = promise.defer();
     this._opening = deferred.promise;
 
     // Local monitoring needs to make the target remote.
     if (!this.target.isRemote) {
       yield this.target.makeRemote();
     }
 
--- a/devtools/client/netmonitor/request-utils.js
+++ b/devtools/client/netmonitor/request-utils.js
@@ -1,10 +1,10 @@
 "use strict";
-
+/* eslint-disable mozilla/reject-some-requires */
 const { Ci } = require("chrome");
 const { KeyCodes } = require("devtools/client/shared/keycodes");
 const { Task } = require("devtools/shared/task");
 const NetworkHelper = require("devtools/shared/webconsole/network-helper");
 
 /**
  * Helper method to get a wrapped function which can be bound to as
  * an event listener directly and is executed only when data-key is
--- a/devtools/client/netmonitor/requests-menu-view.js
+++ b/devtools/client/netmonitor/requests-menu-view.js
@@ -1,16 +1,17 @@
 /* globals document, window, dumpn, $, $all, gNetwork, EVENTS, Prefs,
            NetMonitorController, NetMonitorView */
 "use strict";
-
+/* eslint-disable mozilla/reject-some-requires */
 const { Cc, Ci, Cu } = require("chrome");
 const Services = require("Services");
 const {Task} = require("devtools/shared/task");
 const {DeferredTask} = Cu.import("resource://gre/modules/DeferredTask.jsm", {});
+/* eslint-disable mozilla/reject-some-requires */
 const {SideMenuWidget} = require("resource://devtools/client/shared/widgets/SideMenuWidget.jsm");
 const {HTMLTooltip} = require("devtools/client/shared/widgets/tooltip/HTMLTooltip");
 const {setImageTooltip, getImageDimensions} =
   require("devtools/client/shared/widgets/tooltip/ImageTooltipHelper");
 const {Heritage, WidgetMethods, setNamedTimeout} =
   require("devtools/client/shared/widgets/view-helpers");
 const {gDevTools} = require("devtools/client/framework/devtools");
 const {Curl, CurlUtils} = require("devtools/client/shared/curl");
--- a/devtools/client/themes/rules.css
+++ b/devtools/client/themes/rules.css
@@ -323,17 +323,17 @@
   visibility: hidden;
 }
 
 .ruleview-expander {
   vertical-align: middle;
   display: inline-block;
 }
 
-.ruleview-expander.theme-twisty:dir(rtl) {
+.ruleview-rule .ruleview-expander.theme-twisty:dir(rtl) {
   /* for preventing .theme-twisty's wrong direction in rtl; Bug 1296648 */
   transform: none;
 }
 
 .ruleview-newproperty {
   /* (enable checkbox width: 12px) + (expander width: 15px) */
   margin-inline-start: 27px;
 }
--- a/dom/animation/Animation.cpp
+++ b/dom/animation/Animation.cpp
@@ -659,22 +659,32 @@ Animation::GetCurrentOrPendingStartTime(
     return result;
   }
 
   if (mPendingReadyTime.IsNull() || mHoldTime.IsNull()) {
     return result;
   }
 
   // Calculate the equivalent start time from the pending ready time.
-  // This is the same as the calculation performed in ResumeAt and will
-  // need to incorporate the playbackRate when implemented (bug 1127380).
-  result.SetValue(mPendingReadyTime.Value() - mHoldTime.Value());
+  result = StartTimeFromReadyTime(mPendingReadyTime.Value());
+
   return result;
 }
 
+TimeDuration
+Animation::StartTimeFromReadyTime(const TimeDuration& aReadyTime) const
+{
+  MOZ_ASSERT(!mHoldTime.IsNull(), "Hold time should be set in order to"
+                                  " convert a ready time to a start time");
+  if (mPlaybackRate == 0) {
+    return aReadyTime;
+  }
+  return aReadyTime - mHoldTime.Value().MultDouble(1 / mPlaybackRate);
+}
+
 TimeStamp
 Animation::AnimationTimeToTimeStamp(const StickyTimeDuration& aTime) const
 {
   // Initializes to null. Return the same object every time to benefit from
   // return-value-optimization.
   TimeStamp result;
 
   // We *don't* check for mTimeline->TracksWallclockTime() here because that
@@ -1061,22 +1071,19 @@ Animation::ResumeAt(const TimeDuration& 
              "Expected to resume a play-pending animation");
   MOZ_ASSERT(mHoldTime.IsNull() != mStartTime.IsNull(),
              "An animation in the play-pending state should have either a"
              " resolved hold time or resolved start time (but not both)");
 
   // If we aborted a pending pause operation we will already have a start time
   // we should use. In all other cases, we resolve it from the ready time.
   if (mStartTime.IsNull()) {
+    mStartTime = StartTimeFromReadyTime(aReadyTime);
     if (mPlaybackRate != 0) {
-      mStartTime.SetValue(aReadyTime -
-                          (mHoldTime.Value().MultDouble(1 / mPlaybackRate)));
       mHoldTime.SetNull();
-    } else {
-      mStartTime.SetValue(aReadyTime);
     }
   }
   mPendingState = PendingState::NotPending;
 
   UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
 
   if (mReady) {
     mReady->MaybeResolve(this);
--- a/dom/animation/Animation.h
+++ b/dom/animation/Animation.h
@@ -235,59 +235,63 @@ public:
    *
    * This method returns the start time, if resolved. Otherwise, if we have
    * a pending ready time, it returns the corresponding start time. If neither
    * of those are available, it returns null.
    */
   Nullable<TimeDuration> GetCurrentOrPendingStartTime() const;
 
   /**
+   * Calculates the corresponding start time to use for an animation that is
+   * currently pending with current time |mHoldTime| but should behave
+   * as if it began or resumed playback at timeline time |aReadyTime|.
+   */
+  TimeDuration StartTimeFromReadyTime(const TimeDuration& aReadyTime) const;
+
+  /**
    * Converts a time in the timescale of this Animation's currentTime, to a
    * TimeStamp. Returns a null TimeStamp if the conversion cannot be performed
    * because of the current state of this Animation (e.g. it has no timeline, a
    * zero playbackRate, an unresolved start time etc.) or the value of the time
    * passed-in (e.g. an infinite time).
    */
   TimeStamp AnimationTimeToTimeStamp(const StickyTimeDuration& aTime) const;
 
   bool IsPausedOrPausing() const
   {
     return PlayState() == AnimationPlayState::Paused ||
            mPendingState == PendingState::PausePending;
   }
 
-  bool HasInPlayEffect() const
-  {
-    return GetEffect() && GetEffect()->IsInPlay();
-  }
   bool HasCurrentEffect() const
   {
     return GetEffect() && GetEffect()->IsCurrent();
   }
   bool IsInEffect() const
   {
     return GetEffect() && GetEffect()->IsInEffect();
   }
 
   /**
-   * "Playing" is different to "running". An animation in its delay phase is
-   * still running but we only consider it playing when it is in its active
-   * interval. This definition is used for fetching the animations that are
-   * candidates for running on the compositor (since we don't ship animations
-   * to the compositor when they are in their delay phase or paused including
-   * being effectively paused due to having a zero playback rate).
+   * Returns true if this animation's playback state makes it a candidate for
+   * running on the compositor.
+   * We send animations to the compositor when their target effect is 'current'
+   * (a definition that is roughly equivalent to when they are in their before
+   * or active phase). However, we don't send animations to the compositor when
+   * they are paused/pausing (including being effectively paused due to
+   * having a zero playback rate), have a zero-duration active interval, or have
+   * no target effect at all.
    */
-  bool IsPlaying() const
+  bool IsPlayableOnCompositor() const
   {
-    // We need to have an effect in its active interval, and
-    // be either running or waiting to run with a non-zero playback rate.
-    return HasInPlayEffect() &&
+    return HasCurrentEffect() &&
            mPlaybackRate != 0.0 &&
            (PlayState() == AnimationPlayState::Running ||
-            mPendingState == PendingState::PlayPending);
+            mPendingState == PendingState::PlayPending) &&
+           !GetEffect()->IsActiveDurationZero();
   }
   bool IsRelevant() const { return mIsRelevant; }
   void UpdateRelevance();
 
   /**
    * Returns true if this Animation has a lower composite order than aOther.
    */
   bool HasLowerCompositeOrderThan(const Animation& aOther) const;
--- a/dom/animation/AnimationEffectReadOnly.cpp
+++ b/dom/animation/AnimationEffectReadOnly.cpp
@@ -39,27 +39,16 @@ NS_INTERFACE_MAP_END
 AnimationEffectReadOnly::AnimationEffectReadOnly(
   nsIDocument* aDocument, AnimationEffectTimingReadOnly* aTiming)
   : mDocument(aDocument)
   , mTiming(aTiming)
 {
   MOZ_ASSERT(aTiming);
 }
 
-// https://w3c.github.io/web-animations/#in-play
-bool
-AnimationEffectReadOnly::IsInPlay() const
-{
-  if (!mAnimation || mAnimation->PlayState() == AnimationPlayState::Finished) {
-    return false;
-  }
-
-  return GetComputedTiming().mPhase == ComputedTiming::AnimationPhase::Active;
-}
-
 // https://w3c.github.io/web-animations/#current
 bool
 AnimationEffectReadOnly::IsCurrent() const
 {
   if (!mAnimation || mAnimation->PlayState() == AnimationPlayState::Finished) {
     return false;
   }
 
--- a/dom/animation/AnimationEffectReadOnly.h
+++ b/dom/animation/AnimationEffectReadOnly.h
@@ -44,19 +44,22 @@ public:
   virtual ElementPropertyTransition* AsTransition() { return nullptr; }
   virtual const ElementPropertyTransition* AsTransition() const
   {
     return nullptr;
   }
 
   nsISupports* GetParentObject() const { return mDocument; }
 
-  bool IsInPlay() const;
   bool IsCurrent() const;
   bool IsInEffect() const;
+  bool IsActiveDurationZero() const
+  {
+    return SpecifiedTiming().ActiveDuration() == StickyTimeDuration();
+  }
 
   already_AddRefed<AnimationEffectTimingReadOnly> Timing();
   const TimingParams& SpecifiedTiming() const
   {
     return mTiming->AsTimingParams();
   }
   void SetSpecifiedTiming(const TimingParams& aTiming);
 
--- a/dom/animation/EffectCompositor.cpp
+++ b/dom/animation/EffectCompositor.cpp
@@ -126,17 +126,17 @@ FindAnimationsForCompositor(const nsIFra
     content = content->GetParent();
   }
 
   bool foundSome = false;
   for (KeyframeEffectReadOnly* effect : *effects) {
     MOZ_ASSERT(effect && effect->GetAnimation());
     Animation* animation = effect->GetAnimation();
 
-    if (!animation->IsPlaying()) {
+    if (!animation->IsPlayableOnCompositor()) {
       continue;
     }
 
     AnimationPerformanceWarning::Type warningType;
     if (aProperty == eCSSProperty_transform &&
         effect->ShouldBlockAsyncTransformAnimations(aFrame,
                                                     warningType)) {
       if (aMatches) {
--- a/dom/animation/KeyframeEffectReadOnly.cpp
+++ b/dom/animation/KeyframeEffectReadOnly.cpp
@@ -190,20 +190,16 @@ KeyframeEffectReadOnly::SetKeyframes(nsT
     MaybeUpdateFrameForCompositor();
   }
 }
 
 const AnimationProperty*
 KeyframeEffectReadOnly::GetEffectiveAnimationOfProperty(
   nsCSSPropertyID aProperty) const
 {
-  if (!IsInEffect()) {
-    return nullptr;
-  }
-
   EffectSet* effectSet =
     EffectSet::GetEffectSet(mTarget->mElement, mTarget->mPseudoType);
   for (size_t propIdx = 0, propEnd = mProperties.Length();
        propIdx != propEnd; ++propIdx) {
     if (aProperty == mProperties[propIdx].mProperty) {
       const AnimationProperty* result = &mProperties[propIdx];
       // Skip if there is a property of animation level that is overridden
       // by !important rules.
@@ -1133,27 +1129,21 @@ KeyframeEffectReadOnly::CanAnimateTransf
   return true;
 }
 
 bool
 KeyframeEffectReadOnly::ShouldBlockAsyncTransformAnimations(
   const nsIFrame* aFrame,
   AnimationPerformanceWarning::Type& aPerformanceWarning) const
 {
-  // We currently only expect this method to be called when this effect
-  // is attached to a playing Animation. If that ever changes we'll need
-  // to update this to only return true when that is the case since paused,
-  // filling, cancelled Animations etc. shouldn't stop other Animations from
+  // We currently only expect this method to be called for effects whose
+  // animations are eligible for the compositor since, Animations that are
+  // paused, zero-duration, finished etc. should not block other animations from
   // running on the compositor.
-  MOZ_ASSERT(mAnimation && mAnimation->IsPlaying());
-
-  // Should not block other animations if this effect is not in-effect.
-  if (!IsInEffect()) {
-    return false;
-  }
+  MOZ_ASSERT(mAnimation && mAnimation->IsPlayableOnCompositor());
 
   EffectSet* effectSet =
     EffectSet::GetEffectSet(mTarget->mElement, mTarget->mPseudoType);
   for (const AnimationProperty& property : mProperties) {
     // If there is a property for animations level that is overridden by
     // !important rules, it should not block other animations from running
     // on the compositor.
     // NOTE: We don't currently check for !important rules for properties that
--- a/dom/animation/test/chrome/test_running_on_compositor.html
+++ b/dom/animation/test/chrome/test_running_on_compositor.html
@@ -5,27 +5,35 @@
        running on the compositor or not</title>
 <script type="application/javascript" src="../testharness.js"></script>
 <script type="application/javascript" src="../testharnessreport.js"></script>
 <script type="application/javascript" src="../testcommon.js"></script>
 <style>
 @keyframes anim {
   to { transform: translate(100px) }
 }
+@keyframes transform-starts-with-none {
+    0% { transform: none }
+   99% { transform: none }
+  100% { transform: translate(100px) }
+}
+@keyframes opacity {
+  to { opacity: 0 }
+}
 @keyframes background_and_translate {
   to { background-color: red; transform: translate(100px); }
 }
 @keyframes background {
   to { background-color: red; }
 }
 @keyframes rotate {
   from { transform: rotate(0deg); }
   to { transform: rotate(360deg); }
 }
-@keyframes rotate_and_opacity {
+@keyframes rotate-and-opacity {
   from { transform: rotate(0deg); opacity: 1;}
   to { transform: rotate(360deg); opacity: 0;}
 }
 div {
   /* Element needs geometry to be eligible for layerization */
   width: 100px;
   height: 100px;
   background-color: white;
@@ -165,27 +173,16 @@ promise_test(function(t) {
     return waitForFrame();
   }).then(function() {
     assert_animation_is_not_running_on_compositor(animation,
        'Animation reports that it is NOT running on the compositor'
        + ' on the next tick after animation.cancel() is called');
   });
 }, 'isRunningOnCompositor is false when animation.cancel() is called');
 
-promise_test(function(t) {
-  var div = addDiv(t, { style: 'animation: anim 100s 100s' });
-  var animation = div.getAnimations()[0];
-
-  return animation.ready.then(function() {
-    assert_animation_is_not_running_on_compositor(animation,
-       'Animation reports that it is NOT running on the compositor'
-       + ' while in the delay phase');
-  });
-}, 'isRunningOnCompositor is false while in the delay phase');
-
 // This is to test that we don't simply clobber the flag when ticking
 // animations and then set it again during painting.
 promise_test(function(t) {
   var div = addDiv(t, { style: 'animation: anim 100s' });
   var animation = div.getAnimations()[0];
 
   return animation.ready.then(function() {
     return new Promise(function(resolve) {
@@ -286,17 +283,17 @@ promise_test(function(t) {
   return animation.ready.then(function() {
     assert_animation_is_running_on_compositor(animation,
        'Transition reports that it is running on the compositor'
        + ' during playback for opacity transition');
   });
 }, 'isRunningOnCompositor for transitions');
 
 promise_test(function(t) {
-  var div = addDiv(t, { style: 'animation: rotate_and_opacity 100s; ' +
+  var div = addDiv(t, { style: 'animation: rotate-and-opacity 100s; ' +
                                'backface-visibility: hidden; ' +
                                'transform: none !important;' });
   var animation = div.getAnimations()[0];
 
   return animation.ready.then(function() {
     assert_animation_is_running_on_compositor(animation,
        'If an animation has a property that can run on the compositor and a '
        + 'property that cannot (due to Gecko limitations) but where the latter'
@@ -460,20 +457,19 @@ promise_test(function(t) {
 promise_test(function(t) {
   var div = addDiv(t);
   var animation = div.animate({ opacity: [ 0, 1 ] },
                               { duration: 100 * MS_PER_SEC,
                                 delay: 100 * MS_PER_SEC,
                                 fill: 'backwards' });
 
   return animation.ready.then(function() {
-    // Will be fixed in bug 1223658.
-    assert_animation_is_not_running_on_compositor(animation,
+    assert_animation_is_running_on_compositor(animation,
                   'Animation with fill:backwards in delay phase reports ' +
-                  'that it is NOT running on the compositor');
+                  'that it is running on the compositor');
 
     animation.currentTime = 100 * MS_PER_SEC;
     return waitForFrame();
  }).then(function() {
     assert_animation_is_running_on_compositor(animation,
                   'Animation with fill:backwards in delay phase reports ' +
                   'that it is running on the compositor after delay phase');
   });
@@ -704,16 +700,235 @@ promise_test(function(t) {
                   'A higher-priority animation begins to running on the ' +
                   'compositor after being applied to an element which has ' +
                   'a lower-priority-animation');
   });
 }, 'Animation begins running on the compositor after being applied ' +
    'to an element which has a lower-priority animation once after ' +
    'disassociating with an element');
 
+var delayPhaseTests = [
+  {
+    desc: 'script animation of opacity',
+    setupAnimation: function(t) {
+      return addDiv(t).animate(
+        { opacity: [0, 1] },
+        { delay: 100 * MS_PER_SEC, duration: 100 * MS_PER_SEC });
+    },
+  },
+  {
+    desc: 'script animation of transform',
+    setupAnimation: function(t) {
+      return addDiv(t).animate(
+        { transform: ['translateX(0px)', 'translateX(100px)'] },
+        { delay: 100 * MS_PER_SEC, duration: 100 * MS_PER_SEC });
+    },
+  },
+  {
+    desc: 'CSS animation of opacity',
+    setupAnimation: function(t) {
+      return addDiv(t, { style: 'animation: opacity 100s 100s' })
+        .getAnimations()[0];
+    },
+  },
+  {
+    desc: 'CSS animation of transform',
+    setupAnimation: function(t) {
+      return addDiv(t, { style: 'animation: anim 100s 100s' })
+        .getAnimations()[0];
+    },
+  },
+  {
+    desc: 'CSS transition of opacity',
+    setupAnimation: function(t) {
+      var div = addDiv(t, { style: 'transition: opacity 100s 100s' });
+      getComputedStyle(div).opacity;
+
+      div.style.opacity = 0;
+      return div.getAnimations()[0];
+    },
+  },
+  {
+    desc: 'CSS transition of transform',
+    setupAnimation: function(t) {
+      var div = addDiv(t, { style: 'transition: transform 100s 100s' });
+      getComputedStyle(div).transform;
+
+      div.style.transform = 'translateX(100px)';
+      return div.getAnimations()[0];
+    },
+  },
+];
+
+delayPhaseTests.forEach(function(test) {
+  promise_test(function(t) {
+    var animation = test.setupAnimation(t);
+
+    return animation.ready.then(function() {
+      assert_animation_is_running_on_compositor(animation,
+         test.desc + ' reports that it is running on the '
+         + 'compositor even though it is in the delay phase');
+    });
+  }, 'isRunningOnCompositor for ' + test.desc + ' is true even though ' +
+     'it is in the delay phase');
+});
+
+// The purpose of thie test cases is to check that
+// NS_FRAME_MAY_BE_TRANSFORMED flag on the associated nsIFrame persists
+// after transform style on the frame is removed.
+var delayPhaseWithTransformStyleTests = [
+  {
+    desc: 'script animation of transform with transform style',
+    setupAnimation: function(t) {
+      return addDiv(t, { style: 'transform: translateX(10px)' }).animate(
+        { transform: ['translateX(0px)', 'translateX(100px)'] },
+        { delay: 100 * MS_PER_SEC, duration: 100 * MS_PER_SEC });
+    },
+  },
+  {
+    desc: 'CSS animation of transform with transform style',
+    setupAnimation: function(t) {
+      return addDiv(t, { style: 'animation: anim 100s 100s;' +
+                                'transform: translateX(10px)' })
+        .getAnimations()[0];
+    },
+  },
+  {
+    desc: 'CSS transition of transform with transform style',
+    setupAnimation: function(t) {
+      var div = addDiv(t, { style: 'transition: transform 100s 100s;' +
+                                   'transform: translateX(10px)'});
+      getComputedStyle(div).transform;
+
+      div.style.transform = 'translateX(100px)';
+      return div.getAnimations()[0];
+    },
+  },
+];
+
+delayPhaseWithTransformStyleTests.forEach(function(test) {
+  promise_test(function(t) {
+    var animation = test.setupAnimation(t);
+
+    return animation.ready.then(function() {
+      assert_animation_is_running_on_compositor(animation,
+         test.desc + ' reports that it is running on the '
+         + 'compositor even though it is in the delay phase');
+    }).then(function() {
+      // Remove the initial transform style during delay phase.
+      animation.effect.target.style.transform = 'none';
+      return animation.ready;
+    }).then(function() {
+      assert_animation_is_running_on_compositor(animation,
+         test.desc + ' reports that it keeps running on the '
+         + 'compositor after removing the initial transform style');
+    });
+  }, 'isRunningOnCompositor for ' + test.desc + ' is true after removing ' +
+     'the initial transform style during the delay phase');
+});
+
+var startsWithNoneTests = [
+  {
+    desc: 'script animation of transform starts with transform:none segment',
+    setupAnimation: function(t) {
+      return addDiv(t).animate(
+        { transform: ['none', 'none', 'translateX(100px)'] }, 100 * MS_PER_SEC);
+    },
+  },
+  {
+    desc: 'CSS animation of transform starts with transform:none segment',
+    setupAnimation: function(t) {
+      return addDiv(t,
+        { style: 'animation: transform-starts-with-none 100s 100s' })
+          .getAnimations()[0];
+    },
+  },
+];
+
+startsWithNoneTests.forEach(function(test) {
+  promise_test(function(t) {
+    var animation = test.setupAnimation(t);
+
+    return animation.ready.then(function() {
+      assert_animation_is_running_on_compositor(animation,
+         test.desc + ' reports that it is running on the '
+         + 'compositor even though it is in transform:none segment');
+    });
+  }, 'isRunningOnCompositor for ' + test.desc + ' is true even though ' +
+     'it is in transform:none segment');
+});
+
+promise_test(function(t) {
+  var div = addDiv(t, { style: 'opacity: 1 ! important' });
+
+  var animation = div.animate(
+    { opacity: [0, 1] },
+    { delay: 100 * MS_PER_SEC, duration: 100 * MS_PER_SEC });
+
+  return animation.ready.then(function() {
+    assert_animation_is_not_running_on_compositor(animation,
+      'Opacity animation on an element which has opacity:1 important style'
+      + 'reports that it is not running on the compositor');
+    // Clear the opacity style on the target element.
+    div.style.setProperty("opacity", "1", "");
+    return waitForFrame();
+  }).then(function() {
+    assert_animation_is_running_on_compositor(animation,
+      'Opacity animations reports that it is running on the compositor after '
+      + 'clearing the opacity style on the element');
+  });
+}, 'Clearing *important* opacity style on the target element sends the ' +
+   'animation to the compositor even if the animation is in the delay phase');
+
+promise_test(function(t) {
+  var opaqueDiv = addDiv(t, { style: 'opacity: 1 ! important' });
+  var anotherDiv = addDiv(t);
+
+  var animation = opaqueDiv.animate(
+    { opacity: [0, 1] },
+    { delay: 100 * MS_PER_SEC, duration: 100 * MS_PER_SEC });
+
+  return animation.ready.then(function() {
+    assert_animation_is_not_running_on_compositor(animation,
+      'Opacity animation on an element which has opacity:1 important style'
+      + 'reports that it is not running on the compositor');
+    // Changing target element to another element which has no opacity style.
+    animation.effect.target = anotherDiv;
+    return waitForFrame();
+  }).then(function() {
+    assert_animation_is_running_on_compositor(animation,
+      'Opacity animations reports that it is running on the compositor after '
+      + 'changing the target element to another elemenent having no '
+      + 'opacity style');
+  });
+}, 'Changing target element of opacity animation sends the animation to the ' +
+   'the compositor even if the animation is in the delay phase');
+
+promise_test(function(t) {
+  var animation =
+    addDivAndAnimate(t,
+                     {},
+                     { width: ['100px', '200px'] },
+                     { duration: 100 * MS_PER_SEC, delay: 100 * MS_PER_SEC });
+
+  return animation.ready.then(function() {
+    assert_animation_is_not_running_on_compositor(animation,
+      'Width animation reports that it is not running on the compositor '
+      + 'in the delay phase');
+    // Changing to property runnable on the compositor.
+    animation.effect.setKeyframes({ opacity: [0, 1] });
+    return waitForFrame();
+  }).then(function() {
+    assert_animation_is_running_on_compositor(animation,
+      'Opacity animation reports that it is running on the compositor '
+      + 'after changing the property from width property in the delay phase');
+  });
+}, 'Dynamic change to a property runnable on the compositor ' +
+   'in the delay phase');
+
 promise_test(function(t) {
   var div = addDiv(t, { style: 'transition: opacity 100s; ' +
                                'opacity: 0 !important' });
   getComputedStyle(div).opacity;
 
   div.style.setProperty('opacity', '1', 'important');
   getComputedStyle(div).opacity;
 
--- a/dom/base/ShadowRoot.cpp
+++ b/dom/base/ShadowRoot.cpp
@@ -740,33 +740,24 @@ ShadowRootStyleSheetList::ShadowRootStyl
   MOZ_COUNT_CTOR(ShadowRootStyleSheetList);
 }
 
 ShadowRootStyleSheetList::~ShadowRootStyleSheetList()
 {
   MOZ_COUNT_DTOR(ShadowRootStyleSheetList);
 }
 
-CSSStyleSheet*
+StyleSheet*
 ShadowRootStyleSheetList::IndexedGetter(uint32_t aIndex, bool& aFound)
 {
   aFound = aIndex < mShadowRoot->mProtoBinding->SheetCount();
-
   if (!aFound) {
     return nullptr;
   }
-
-  // XXXheycam Return null until ServoStyleSheet implements the right
-  // DOM interfaces.
-  StyleSheet* sheet = mShadowRoot->mProtoBinding->StyleSheetAt(aIndex);
-  if (sheet->IsServo()) {
-    NS_ERROR("stylo: can't return ServoStyleSheets to script yet");
-    return nullptr;
-  }
-  return sheet->AsGecko();
+  return mShadowRoot->mProtoBinding->StyleSheetAt(aIndex);
 }
 
 uint32_t
 ShadowRootStyleSheetList::Length()
 {
   return mShadowRoot->mProtoBinding->SheetCount();
 }
 
--- a/dom/base/ShadowRoot.h
+++ b/dom/base/ShadowRoot.h
@@ -197,18 +197,18 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ShadowRootStyleSheetList, StyleSheetList)
 
   virtual nsINode* GetParentObject() const override
   {
     return mShadowRoot;
   }
 
-  virtual uint32_t Length() override;
-  virtual CSSStyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) override;
+  uint32_t Length() override;
+  StyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) override;
 
 protected:
   virtual ~ShadowRootStyleSheetList();
 
   RefPtr<ShadowRoot> mShadowRoot;
 };
 
 } // namespace dom
--- a/dom/base/StyleSheetList.h
+++ b/dom/base/StyleSheetList.h
@@ -8,35 +8,35 @@
 #define mozilla_dom_StyleSheetList_h
 
 #include "nsIDOMStyleSheetList.h"
 #include "nsWrapperCache.h"
 
 class nsINode;
 
 namespace mozilla {
-class CSSStyleSheet;
+class StyleSheet;
 
 namespace dom {
 
 class StyleSheetList : public nsIDOMStyleSheetList
                      , public nsWrapperCache
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(StyleSheetList)
   NS_DECL_NSIDOMSTYLESHEETLIST
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override final;
 
   virtual nsINode* GetParentObject() const = 0;
 
   virtual uint32_t Length() = 0;
-  virtual CSSStyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) = 0;
-  CSSStyleSheet* Item(uint32_t aIndex)
+  virtual StyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) = 0;
+  StyleSheet* Item(uint32_t aIndex)
   {
     bool dummy = false;
     return IndexedGetter(aIndex, dummy);
   }
 
 protected:
   virtual ~StyleSheetList() {}
 };
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -587,35 +587,25 @@ nsDOMStyleSheetList::Length()
   // observer notification to figure out if new ones have
   // been added or removed.
   if (-1 == mLength) {
     mLength = mDocument->GetNumberOfStyleSheets();
   }
   return mLength;
 }
 
-CSSStyleSheet*
+StyleSheet*
 nsDOMStyleSheetList::IndexedGetter(uint32_t aIndex, bool& aFound)
 {
   if (!mDocument || aIndex >= (uint32_t)mDocument->GetNumberOfStyleSheets()) {
     aFound = false;
     return nullptr;
   }
-
   aFound = true;
-  StyleSheet* sheet = mDocument->GetStyleSheetAt(aIndex);
-  NS_ASSERTION(sheet, "Must have a sheet");
-
-  // XXXheycam Return null until ServoStyleSheet implements the right DOM
-  // interfaces.
-  if (sheet->IsServo()) {
-    NS_ERROR("stylo: can't return a ServoStyleSheet to the DOM yet");
-    return nullptr;
-  }
-  return sheet->AsGecko();
+  return mDocument->GetStyleSheetAt(aIndex);
 }
 
 void
 nsDOMStyleSheetList::NodeWillBeDestroyed(const nsINode *aNode)
 {
   mDocument = nullptr;
 }
 
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -301,19 +301,18 @@ public:
   // nsIMutationObserver
   NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
 
   virtual nsINode* GetParentObject() const override
   {
     return mDocument;
   }
 
-  virtual uint32_t Length() override;
-  virtual mozilla::CSSStyleSheet*
-  IndexedGetter(uint32_t aIndex, bool& aFound) override;
+  uint32_t Length() override;
+  mozilla::StyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) override;
 
 protected:
   virtual ~nsDOMStyleSheetList();
 
   int32_t       mLength;
   nsIDocument*  mDocument;
 };
 
--- a/dom/base/nsHostObjectURI.cpp
+++ b/dom/base/nsHostObjectURI.cpp
@@ -36,17 +36,17 @@ NS_INTERFACE_MAP_BEGIN(nsHostObjectURI)
   else
 NS_INTERFACE_MAP_END_INHERITING(mozilla::net::nsSimpleURI)
 
 // nsIURIWithBlobImpl methods:
 
 NS_IMETHODIMP
 nsHostObjectURI::GetBlobImpl(nsISupports** aBlobImpl)
 {
-  RefPtr<BlobImpl> blobImpl(mBlobImpl);
+  RefPtr<mozilla::dom::BlobImpl> blobImpl(mBlobImpl);
   blobImpl.forget(aBlobImpl);
   return NS_OK;
 }
 
 // nsIURIWithPrincipal methods:
 
 NS_IMETHODIMP
 nsHostObjectURI::GetPrincipal(nsIPrincipal** aPrincipal)
--- a/dom/base/nsStyleLinkElement.h
+++ b/dom/base/nsStyleLinkElement.h
@@ -34,25 +34,17 @@ class ShadowRoot;
 class nsStyleLinkElement : public nsIStyleSheetLinkingElement
 {
 public:
   nsStyleLinkElement();
   virtual ~nsStyleLinkElement();
 
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override = 0;
 
-  mozilla::CSSStyleSheet* GetSheet() const
-  {
-    // XXXheycam Return nullptr for ServoStyleSheets until we have a way of
-    // exposing them to script.
-    NS_ASSERTION(!mStyleSheet || mStyleSheet->IsGecko(),
-                 "stylo: ServoStyleSheets can't be exposed to script yet");
-    return mStyleSheet && mStyleSheet->IsGecko() ? mStyleSheet->AsGecko() :
-                                                   nullptr;
-  }
+  mozilla::StyleSheet* GetSheet() const { return mStyleSheet; }
 
   // nsIStyleSheetLinkingElement  
   NS_IMETHOD SetStyleSheet(mozilla::StyleSheet* aStyleSheet) override;
   NS_IMETHOD_(mozilla::StyleSheet*) GetStyleSheet() override;
   NS_IMETHOD InitStyleLinkElement(bool aDontLoadStyle) override;
   NS_IMETHOD UpdateStyleSheet(nsICSSLoaderObserver* aObserver,
                               bool* aWillNotify,
                               bool* aIsAlternate,
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -303,17 +303,17 @@ DOMInterfaces = {
     'nativeType': 'nsROCSSPrimitiveValue',
 },
 
 'CSSStyleDeclaration': {
     'nativeType': 'nsICSSDeclaration'
 },
 
 'CSSStyleSheet': {
-    'nativeType': 'mozilla::CSSStyleSheet',
+    'nativeType': 'mozilla::StyleSheet',
     'binaryNames': { 'ownerRule': 'DOMOwnerRule' },
 },
 
 'CSSValue': {
     'concrete': False
 },
 
 'CSSValueList': {
@@ -922,17 +922,18 @@ DOMInterfaces = {
     'headerFile': 'mozilla/dom/WorkerScope.h',
 },
 
 'Storage': {
     'nativeType': 'mozilla::dom::DOMStorage',
 },
 
 'StyleSheet': {
-    'nativeType': 'mozilla::CSSStyleSheet',
+    'nativeType': 'mozilla::StyleSheet',
+    'headerFile': 'mozilla/StyleSheetInlines.h',
 },
 
 'SVGAnimatedLengthList': {
     'nativeType': 'mozilla::DOMSVGAnimatedLengthList',
     'headerFile': 'DOMSVGAnimatedLengthList.h',
 },
 
 'SVGAnimatedNumberList': {
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -3106,18 +3106,24 @@ class CGGetPerInterfaceObject(CGAbstract
             }
 
             /*
              * The object might _still_ be null, but that's OK.
              *
              * Calling fromMarkedLocation() is safe because protoAndIfaceCache is
              * traced by TraceProtoAndIfaceCache() and its contents are never
              * changed after they have been set.
+             *
+             * Calling address() avoids the read read barrier that does gray
+             * unmarking, but it's not possible for the object to be gray here.
              */
-            return JS::Handle<JSObject*>::fromMarkedLocation(protoAndIfaceCache.EntrySlotMustExist(${id}).address());
+
+            const JS::Heap<JSObject*>& entrySlot = protoAndIfaceCache.EntrySlotMustExist(${id});
+            MOZ_ASSERT_IF(entrySlot, !JS::ObjectIsMarkedGray(entrySlot));
+            return JS::Handle<JSObject*>::fromMarkedLocation(entrySlot.address());
             """,
             id=self.id)
 
 
 class CGGetProtoObjectHandleMethod(CGGetPerInterfaceObject):
     """
     A method for getting the interface prototype object.
     """
--- a/dom/canvas/test/crash/mochitest.ini
+++ b/dom/canvas/test/crash/mochitest.ini
@@ -8,8 +8,9 @@ support-files =
   file_1251091-1.html
   1251091-1.png
 
 [test_bug1233613.html]
 [test_texImage2D.html]
 [test_616401.html]
 [test_798802-1.html]
 [test_1251091-1.html]
+[test_createImageBitmap-video.html]
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/crash/test_createImageBitmap-video.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1309838
+-->
+<head>
+  <title>Test for canvas crashing</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<body>
+  <script class="testbody" type="application/javascript">
+  SimpleTest.waitForExplicitFinish();
+
+  var v = document.createElement("video");
+  document.body.appendChild(v);
+  v.src ="data:video/ogg;base64,T2dnUwACAAAAAAAAAAC1v/BfAAAAAMVFfV4BHgF2b3JiaXMAAAAAAUSsAAD/////APQBAP////+4AU9nZ1MAAAAAAAAAAAAAtb/wXwEAAAB6cK4REC3//////////////////wYDdm9yYmlzHQAAAFhpcGguT3JnIGxpYlZvcmJpcyBJIDIwMDMwOTA5AAAAAAEFdm9yYmlzKUJDVgEACAAAADFMKMSA0JBVAAAQAAAgmDYQa6e11lprgqR2WmuqtdZaaya1tlprrbXWWmuttdZaa6211lpjIDRkFQAABABAKEoStGRSTEopZSBHjnLkOUjKJ6UoRwpi4jnoPfVka02mpORbTUopJQgNWQUAAAIAQAghhBBSSCGFFFJIIYUUYoghpphiyimnnHLKKccggwwyyCCDTDLppKOOOuqss846Cy200EIMscQSU2011tpzEMoopZRSSimllFJKKaWMMcYIQkNWAQAgAAAEQgYZZJBBCCGFFFKKKaaccgwy6IDQkFUAACAAgAAAAADHkBRJsRzL0RxP8iTPEi1REz3TM0XTNE3TNW1Vd3VVV3XVVnXVVmXTNW3TVmXTVXVXl3VXtnVd13Vd13Vd13Vd13Vd13Xdtm0gNGQVACABAKAjOZriKaJiGq7iOqoFhIasAgBkAAAEAKAJniEqoiZqouZpnud5nud5nud5nud5ngeEhqwCAAABAAQAAAAAAKBpmqZpmqZpmqZpmqZpmqZpmqZpmmZZlmVZlmVZlmVZlmVZlmVZlmVZlmVZlmVZlmVZlmVZlmVZlmVZQGjIKgBAAgBAx3EkR1IkRVIkx3IsBwgNWQUAyAAACABAUizFUjTHczxHdETHdExJlVTJlVzLtVwNCA1ZBQAAAgAIAAAAAABAEzTFUizHkixPMzVVUz1VVDXVUz3VVFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVYHQkFUAAAQAAAGdZphqgAgzklkgNGQVAIAAAAAQgQxTDAgNWQUAAAQAAEiR5CSJkpNSSjkMksUkqZSTUkp5FJNHNckYlFJKKaWUUkoppZRSSikMkuUoqZSTUkpJjJLFKKlSk1JKeZSTJzXJ2JNSSimllFJKKaWUUkpZkJInLekalFJKSY6SBi3Z1JNSSolSlCg52Z6UUkoppZRSSimllFJK+aCUD0IppZRSSrnak2s9KaWUUkoZo5TwSSmllFJKKaWUUkoppZRSyghCQ1YBAEAAAIBx1iiHopPofHGGcqYpSCqUJnRvkqPkOcmttNycbsI5p5tTzvnknHOC0JBVAAAgAACEEFJIIYUUUkghhRRSiCGGGHLIKaegggoqqaSiiiqqrLLMMssss8wyyyyzzDLrrKOOOgsphJJCC63VGGuMsdXenLQ1RymdlFJKKaWUzjnnnCA0ZBUAAAIAQCBkkEEGGWUUUoghppxyyimopJIKCA1ZBQAAAgAIAAAAECXTMR3RERXRER3RER3RER3P8RxPEiXR8ixRMz1TNE3TVWVXlnXZlm1Xl3Vbl33bt3Xbtn3d2I3fOI7jOI7jOI7jOI7jOI5jCEJDVgEAIAAAAEIIIYQUUkghhZRiijHnoIMQQimB0JBVAAAgAIAAAAAARXEUx5EcSZIkS7IszdI0TdM0T/REz/RUzxVl0RZtz/Vs0fZcT/VUTxVVUzVd01Vd13Vd1VVlVXZt27Zt27Zt27Zt27Zt27ZlIDRkFQAgAQCgIzmSIimSIjmOIzmSBISGrAIAZAAABACgKIriOI7kWJIlaZIomZZquZrs6Z4u6qIOhIasAgAAAQAEAAAAAABgiIZoiI5oiZooiqIoiqIoiqIoiqIoiqIoiqIoiqIoiqIoiqIoiqIoiqIoiqIoiqIoip7neZ7neZ7neUBoyCoAQAIAQEdyJMdSLEVSJMVyLAcIDVkFAMgAAAgAwDEcQ1Ikx7IsS9M0z/M8T/REURRF01RNFQgNWQUAAAIACAAAAAAAQFEUy7EcSdIcTxIdURIl0RIlURM1URRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURSB0JCVAAAZAAClxRgjhBCOoxZTTD1YzEEHLdRgQWqt5RaEpZRDjDkNGoTUSUm1d4w5xAyiIDoJGTQCeq69dtoQ5kH4IHKFJAhCQ1YEAFEAAIAxiDHDGHLOScmkRM4xCZ2UyDlHpZPSUSktphgzKSWmFGPknKPSScmkpBhLih2lEmOJrQAAgAAHAIAAC6HQkBUBQBQAAIIMUgophZRSzCnGkFKKMeUcUko5pphTzjkIHYSKMQadgxAppRxTzCnGHITMQeWcg9BBKAAAIMABACDAQig0ZEUAECcA4JAkz5M0SxQlSxNFTxRd1xNF15U0zRQ1UVRVyxNN1VRV2RZNVZYlTRNFS/RUUxNFVRVVU5ZNVbVlzzRt2VRV3xZV1bZl3RZ+V7Z93RNN2RZV1bZNVbV1WbaFYbZ1X5g0zTQ10VNVzRNV1VRV2zZV1bY1UVRVUVVlWVRVWVZdWRdWV/aNy/NU1TNN2RVV1ZVVWfVtVXZ931RVXVdl2fdVWTZ+29aF39aFpaiqtm66ri6ssqwLty7TdeE3Spommpooqqrmiapqqqptm6pq25YnqqqoqrbsmaZqq7Is7Kor274miqoqqqrsiqrqyqrs6roqu74uqqquq67s66bq+rru+9iy7iuj6uq6KsvCr8quLty+b9R13xg+05RtU1V131RV3bd1XVhuW1eWUVV9XZVlYVhlWRh24UcXhsKoqrquyq7vq7JsDLuvK8vtG8My6zrj9oXhuH1fWY5lyReOpWvbvjH7NuX2haWv/MowHEeeadqyqKq6baqu7cu6rSy37xvDqKq+rsoy4XRl3deNX1lu3TeOUXV1XZVlYVllWRh24VeWXfhxbZty+zpltn2lbxz5vjCUbVtoCz/l9n3lGJYh4xgSAAAw4AAAEGBCGSg0ZEUAECcAACnlnGIKQqUYhA5CSh2ElCrGIGSOSamYgxJKSS2EklrFGISKMQkZc1JCCS2FUlrqIKQUSmktlJJaai3GlFqLHYSUQikthVJaSy3FllqLtWIMQuaYhIw5KKGUlkIpqWXOSemck9I5J6WU1FopqbWKMSmZc1I65ySFUloqJbUWSmmtlNJaSaW11lqsrbVYQymphVJaKyW1llqqrbVWa8UYhMwxCRlzUEIpLYVSUqsYk9I5RyVzTkoppbVSSmqZc1I656R0zkkpqbRWUmktlNJaSSW2UEprrbVaU2qthlJaK6W0VlJprbVWa2utxg5CSqGU1kIpraXWakytxRhKaa2U0lpJqbXWYq2ttVpDCa2FUlorJbXWWqqxtRZrai3G1lqtLbZaY6wx11pzTinFmFqqsbVWa4stt1hrzh2ElEIprYVSWkutxZhaizWU0lIppbVQSmstthpTa7GGUlorpbRWUmqttVZri63GlFKMrbUaU2qxxlpzji22nFqLtbVWa2qt1lhrzrHGHAsAABhwAAAIMKEMFBqyEgCIAgAgCFHKOSkJQo45R6lBiDnnKFWOQSihtYo5KKG01jknoaUYO+egpBZjSamlGGstKbUWY60FAAAUOAAABNigKbE4QKEhKwGAKAAAxhiEGIPQGKMUYxAag5RiDEKkFGPOQYiUUsw5CBljzkEoJWPMOQilhBBKKCWlEEIopaRUAABAgQMAQIANmhKLAxQasiIAiAIAAIxBjCHGEHROSiclctBJ6aQ0EEJqnaXOUmqxxJhZKrGVGBsIHbWQWkatxFha7KiVGEtsBQCAHTgAgB1YCIWGrAQA8gAAEGSUYsw55xBCSjHmnHMIIaUYc845pRRjjjnnnFKKMeacc44x5phzEELIGGPOOQghdM45ByGEEDrnnIMQQgidc85BCCGEzjnnIIQQQgEAQAUOAAABNopsTjASVGjISgAgDwAAMEYp5yCU0ijFGIRSUmqUYgxCKSlVzkEoJaXWKucglJJSax2EUlJqrcYOQikptRZjKSWl1mKstZSSUosx1ppaii3WWnNOqcUYY605FwCAu+AAAHZgo8jmBCNBhYasBADyAAAQhJRijDHnkFJMMcaYc0gpxRhjzDnFFGOMOeecUowxxpxzjjHGmHPOOccYY8w555xjjDnnnHPOMcacc84555xzzjnnnHPOOeecc845AQBABQ4AAAE2imxOMBJUaMhKACAPAAAwBkIIIYQQQQghhBBCaCCEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBC55xzzjnnnHPOOeecc84555wTAOJ44QDoM2GjyOYEI0GFhqwEAFIBAABjEGJMQkqtNUw5ByGV2GJsFHMOQkkxthg5J6Gl1mLMtXJOSkqxxVpzJ6WlGGvOPfcOSmsx9pxzziWlGmvtPffeS2ut1pp77rmn1mrtPffee28txpxr7r333mrNtffee+891lhzz7333nsBACYRDgCICzasjnBSNBZYaMgqACAGAIAwxBiEEFJKKaWUYooxxhhjjDHGnHPOOeecc84555wTAACY4AAAEGAFuzJLqzaKmzrJiz4IfEJHbEaGXErFTE4EPVJDLVaCHVrBDV4AFhqyEgAgAwBAIMcee2stQsw5SSXGEiGlIJRaQ6WYclBiixlSRilnMXXMKcYYxVw6h5RBEEPoIGPGKEqptVI6hKC0mGNsmXIAAAAIAgAMRMhMIFAABQYyAOAAIUEKACgsMHQMFwEBuYSMAoPCMeGcdNoAAAQhMkMkIhaDxIRqoKiYDgAWFxjyASBDYyPt4gK6DHBBF3cdCCEIQQhicQAFJODghBueeMMTbnCCTlGpgwAAAAAAQACABwCAZAOIiIhmjqPD4wMkRGSEpMTkBCUAAAAAAIAA4AMAIEkBIiKimePo8PgACREZISkxOUEJAAAAAAAAAAAAAgICAAAAAAABAAAAAgJPZ2dTAASgJAAAAAAAALW/8F8CAAAA8j39PyUwRVBWUv+mQkI/REA/Uk5J9powJigtF1JTT/9FNjU1T1JD1XEBVAG1Dct/jByBHJl980qgQA54nE5NqcyTJJ6RWTPMYAzKGKUZYPWENVZgPoJJ8csC/AjRDFgq8Z4JsLTRsjiAAICWgDMX6f+u99258y1+ZpU83o6++bBdskkeb9PffVkrN/QkGn5ei1Y4/B0PKdWRqctr7iYB1P2WE3n/anGvjigc4fM8OA63aD+7WKlI2VX4OpKp0PQ1VhAQ477aZ/uduNiRFYk5kYu/CX/dYfz8YVxGiTCpIG66v6ZieUzI+L8PqmGtLgr0JY9UrE+Ta5F19hcO+5cQW4pL+96GOriCTbY01AWwldRBtpCVm6E4OTjzt0Xz4yztve5sTCMZqzFJiU+ZFQFWWREyxm8eLK3Sku06EAyCmyH0IwTiAAw6lzvENtI2ZHUvOUC09oRrvK/3hq4FniaRdTBA5DnfjR62RT87bVMFriFyeVpHyfNOMbty+czA6o2S/3hGeM+FJJdT6cX0NlRkyvL868oLZbPSZ+0OswlE/vQpX8GdObfJ+PHNAADfn93dBXT/yQDAc9MAoP8UAOizkAD0mMDKWyUA8N8BsOm4MwgAjBVg+39nEQEAI8CfCQCMBTRfAIARcO8HADAEpnRbHQA4gAkYgWMMABzADhBFAACYV7kZKmLjekCCjfr85v0pZaKYZ9nwcDgcdrvda/Dy+GbZbEaRIqUM69fXo/d+Zi0AWLoZa+ztIcsDSo5DqQKqNA+b1oEQQohhGJbS7HDqSXXJ6FgAMK3N3n/XWkEpAThOaVEzm6ispCUEhaIoJSEiiHBZlJnBzEwLF+/eKT/dN9MTGqEoSgCU0t00QggAAJi0UQpUQa+WpRQAKCCvhjwAB+dc81jh162XuOIAAAAAhOozA4CUUuaTw0tdZz/LLAAADgCXwgAAgLlIKBk/bwWDUiQAAAAu0AwAAKD+pcZxFjlHAABwBICABgAAgNxLwmnZQEgIAACOBdDRAABAqfyBqJKtY2YAAAAgJFId+nN9iBf5S3/lq7yll/RQHvQr3ZeH96gvCgAYOjw2BAAAAFkn+5sCAADf0foVAHAA/EGPe1m6sM7UlEwATgj5AoGEwRJW9qzHfSlY22TuwvC4sGh/YIJ+SAU8S3qc9AyJetTjJrtLlYdUaGAXJ7kQvmWz9DFvWB2hdRifBJoAnBAP2RI2DZawsmcT6ZJydnkMMcqNa2S4NByPUxgZ0J7lfAh3Wn0dkhT/9QoheCLgicE9QyMBBDqPWRmpTGji/c9sX4HLhHgkAQbuWuH9SGk24gt7Z65SisiJK/rBEzfJJd3YeTilCcPJg1EQR+ES+R7yTSyD9DlvGB2hKMZmJgCXiQtEEomQwZL8sMK8SBQkEyfWrk9wYQMO4i35sNFkxSBSRBMCtGc9H7I7qX45Jin+awMR3CpXIQH8NY97GUQKDd7/zPYVkIkj6CGR6mOl9/2yp5X6YXX0AVVgnO6sbgjkQntGGqGyqnSeQRob5okDjC2ASwh4gAgABDqPBRmpspDm/c9sT+HJOALZDyFuovTeP06NpT7pRpix5nGiNbNlEEd7PCZk9FghWSrwX8ZnD08kXJtnTm0S/ElvdHq5O22NC4f9z2xPIR+bKl3jSuIMbYHgCTbJ/kQtFoZ7pzsx1emt9/AMknpztOu0Qyp4SKPyeUo+snVG0EutI17l2m6eTfglQBB1rEjoBiQil5NUp0qbqUlrejfJzjbJapeX0Nc+Pp7sx4OpPByd3TJnRN6oU8ffmTWmevr9XPvX34her6dNtoTox11PBN/X1JmJ828MIFqAG4MrHlTxFnugym+sftwksyFr6+6qkZmgCX8fNeeBWoOpJZdnRV7+fN0l438fv5+WrOM/M+c2d4y3wj+C8lz4xnJiPzUP0e9+3hzoVAj6FPzahgADNry7HQ/DMAzDcDO+PS6HYbECDgDgABTAPYdWWAEA+NdQUcp5cv1fnm1tTf3UXi6Yv0xMhiHvAhsB2lrfq2wisuyxKzU9KevHcvnItjwXLy/YzheqTwvlp2r5xH5hwX7h7OKXs2d/zi68XrywYF+tWouymfcSvArwC6jA0CSYbwGCaJ5np2F+ltOsvKdhJSuNrLze3Ud5Og1Mp/I4lcesvA54AfiZ3vf7u0/8+7/7dOxiBUDg3Ed5nE5vj/PYj5OW+VkOWNCv4/Pr+ep6zVD9OD0RDezhPPdnZj6dmZmBAI9yYpyemJhgDwB4HZ+dZwI2FXy79x8QYMKbwHEceRxHHrmpI2kHAFCYCmOMMQAAxOrxICH2KR1Orv1hxiiTRNpWliZpoZvl8GSo/NLhhaCpkWQoDkGMoJ6ow2ToJsAloEfSFAECAIxyF6gv8G7mDHdTXMUhc0D1BP3AYamXLCHQ5ADnVrtZ5l7827zy/Ewrh5k+bmpi2ag8T5HDkCePVrtZ4sVTlGdISXMAHAnPBx8MxDwQgNNAAn6vzzFo22ZbUlL5f5c3c9we7NceFr3/d3kzO/WAX3ty/GUCFAnfZicMxDgQAAYCKuBt/92XrrUiNUno9s2v5EiJvwbRNV4krgEcCV9WbxiIcSAADARkAq/7v1WlRkqqSfH/DwnojZQuwv+yy5fSKfwBDAkvuw0DMY0AnAIq4G77XKVpNdSRcspsvJNzO/AR8v7OT1m9P7/b8vYjs9QAFAm/O+dgCEY2eAAAACTgd/vbN02tAAAU5W4XpONvqgcK/Gq7tseRP/5nTCwI+3X2JYPN0tv79trW1Kw13rN8/s7hu2i3//cfPVPh+jfn/ySxXI/m7/3b514JS3559++7/Uwcw4WL/y0AvPEWsGNydi8Y9H0e6ui6j7+fbdzKZGpCHZ84/9lxUnv7l4f/K2p/Hs6M7Z8+iuvUffXm7Ca0d0aT8cjxnTgs37eXSwqbTY/cDKmN0Eg4WKejJTLEAR2SYv4J4kT7Y/BCbvv2yUTRCkxcciN+dgc/DXz2bz/OT+7bPNwe2MWDc2mhM2uFOw9kPf1fHGJGdOkb71NedsUPF4R3MmI1zWzdKUXvkhbsThgRJwwAvBkAIMk3pwENV5A6gEsAwMLEAvQQoHCXdNMqDJcAcHnwplWPv8suEbPYZ1a4SUSE1FwORoJzt4XWsllI1V6T8PwrkmwOhUWaeIhxbuaNVziInv+zadWOnkRDbUTkgRl1VET7db4vxTM8IaYYF5AS5o4lKqU2PiJOflOekJ5G2UsdmmEhu/n92/fL1+3t7fHhNPXTWL5dUntO7dNnrG9T54Ip/pIzq/zx+YAi9u5SRMrjNYnbbEpQ/NJGTgCMbbwc3oV7+MXxccDp1TkwPKdZ6cMIysAei6DBLMx0B+RjOtmYKC4Mp91uir9FBqZmQaZ9lDGpqTYdY/HgpNLNzubeni4n3So+vA+wbZr9/Fs1JYGCYh3Etz6mgEoDWe8SKmRTeHBTSb2R0ThHQaLaFxQpabQFXhoDvXjcAoADzPGWgdecUXGn2KpRZ2hKDC50/8T4LLGCi2hR1E/DnD7nJXrbLXxe/XACyMwgaKe9rFVea90AzPluCy4AHHmrD2WAKfj+ixU9s153Zo0P2twCs7PB8VtZqP5RGwIJiqFcmbdCrGXeML8/vR6s8T44ObIAkMK+aQbGaW9zpnd3CCuS3+wW9ubjZFo4IWlm7WMTVCOEyooc+Whgp6YynxnJd9T1Fr2fAEah/rzbyo2g0twjpblNi6i4r3dl43aq97aaJt7/3czcr3jV/lav7m6OqAXLoNjbzu7FcU/UsPm970B8WX6D6BJ8E75Cyr7mTgCk6Y725txMOM7y33ujc2e1seEm1kIAkiXu2krl837l4Xn0tfHX7s39wzfhlshid23zT3h9/+is8M/Q+H3/1tCRrdseiO7ceTgX/ojMq82g/ygAJAn7FTj3v9hp/+/DdsbqudbsE8gBJ1IF/zrXan32/x9/Ff/fSOPcoNvWbm5Zli5/7MlP4eBAJ4WfFlPPg3zc5N0bADoV/N6GL26g2YYDe2l+Nc/zdI6do82x6kUeC6TupFXdMgoA2Bh6EW4aCobfF/HZz5ntu/b7/uwSsI0j1+/Pp9aZsrJs3ngyNuYLdoU+Aice6g/R7neebPrTg2NWEcDgHn1Kn/0vSDLhSeW88EqQfHsoQj06jH1GfobYgWoTjHccCk9C5NwDdfbiPTMx38+Eyp0UoRYCbmj6F4SKYT6LzH71+v0yJuSnqZaYKbJ5YjSxlDEtlQURSdWBUDASVPNCqopEB/52lpTj94TpZKwXv1MdxELSAD4V/HVrHzDAhgUg2GWTcwKMAAAAkKzOB3mZwup9nH2mMft57M8ghXfZdxZPxrw1LJ5o3oQYP1OAeKI5cqRDs3OkaigSGelovRNngEgb5ztoHkKbusQIB+Ii/Wwo4uSNCErm20btGJaWz9LyWRqgiGMADg==";
+  v.addEventListener("playing", function() {
+    var x = createImageBitmap(v);
+    x.then(function() {
+      ok(false, "Can't have an image bitmap for this video.");
+    }, function() {
+      ok(true, "Yay, rejected but no crash!");
+    }).then(function() {
+      SimpleTest.finish();
+    });
+  });
+  v.play();
+  </script>
+</body>
+</html>
+
--- a/dom/html/HTMLLinkElement.cpp
+++ b/dom/html/HTMLLinkElement.cpp
@@ -90,32 +90,31 @@ NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION
 NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLElement)
 
 
 NS_IMPL_ELEMENT_CLONE(HTMLLinkElement)
 
 bool
 HTMLLinkElement::Disabled()
 {
-  CSSStyleSheet* ss = GetSheet();
+  StyleSheet* ss = GetSheet();
   return ss && ss->Disabled();
 }
 
 NS_IMETHODIMP
 HTMLLinkElement::GetMozDisabled(bool* aDisabled)
 {
   *aDisabled = Disabled();
   return NS_OK;
 }
 
 void
 HTMLLinkElement::SetDisabled(bool aDisabled)
 {
-  CSSStyleSheet* ss = GetSheet();
-  if (ss) {
+  if (StyleSheet* ss = GetSheet()) {
     ss->SetDisabled(aDisabled);
   }
 }
 
 NS_IMETHODIMP
 HTMLLinkElement::SetMozDisabled(bool aDisabled)
 {
   SetDisabled(aDisabled);
--- a/dom/html/HTMLStyleElement.cpp
+++ b/dom/html/HTMLStyleElement.cpp
@@ -63,32 +63,31 @@ HTMLStyleElement::GetMozDisabled(bool* a
 
   *aDisabled = Disabled();
   return NS_OK;
 }
 
 bool
 HTMLStyleElement::Disabled()
 {
-  CSSStyleSheet* ss = GetSheet();
+  StyleSheet* ss = GetSheet();
   return ss && ss->Disabled();
 }
 
 NS_IMETHODIMP
 HTMLStyleElement::SetMozDisabled(bool aDisabled)
 {
   SetDisabled(aDisabled);
   return NS_OK;
 }
 
 void
 HTMLStyleElement::SetDisabled(bool aDisabled)
 {
-  CSSStyleSheet* ss = GetSheet();
-  if (ss) {
+  if (StyleSheet* ss = GetSheet()) {
     ss->SetDisabled(aDisabled);
   }
 }
 
 NS_IMPL_STRING_ATTR(HTMLStyleElement, Media, media)
 NS_IMPL_BOOL_ATTR(HTMLStyleElement, Scoped, scoped)
 NS_IMPL_STRING_ATTR(HTMLStyleElement, Type, type)
 
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -126,16 +126,17 @@ MediaLoadUnsupportedMimeType=HTTP “Content-Type” of “%1$S” is not supported. Load of media resource %2$S failed.
 MediaLoadDecodeError=Media resource %S could not be decoded.
 MediaWidevineNoWMFNoSilverlight=Trying to play Widevine with no Windows Media Foundation (nor Silverlight fallback), see https://support.mozilla.org/kb/fix-video-audio-problems-firefox-windows
 # LOCALIZATION NOTE: %S is a comma-separated list of codecs (e.g. 'video/mp4, video/webm')
 MediaWMFNeeded=To play video formats %S, you need to install extra Microsoft software, see https://support.mozilla.org/kb/fix-video-audio-problems-firefox-windows
 # LOCALIZATION NOTE: %S is a comma-separated list of codecs (e.g. 'video/mp4, video/webm')
 MediaUnsupportedBeforeWindowsVista=Video formats %S unsupported by Microsoft before Windows Vista
 # LOCALIZATION NOTE: %S is a comma-separated list of codecs (e.g. 'video/mp4, video/webm')
 MediaPlatformDecoderNotFound=The video on this page can’t be played. Your system may not have the required video codecs for: %S
+MediaUnsupportedLibavcodec=The video on this page can’t be played. Your system has an unsupported version of libavcodec
 # LOCALIZATION NOTE: %S is a comma-separated list of codecs (e.g. 'video/mp4, video/webm')
 MediaCannotPlayNoDecoders=Cannot play media. No decoders for requested formats: %S
 # LOCALIZATION NOTE: %S is a comma-separated list of codecs (e.g. 'video/mp4, video/webm')
 MediaNoDecoders=No decoders for some of the requested formats: %S
 MediaCannotInitializePulseAudio=Unable to use PulseAudio
 # LOCALIZATION NOTE: Do not translate "MediaRecorder".
 MediaRecorderMultiTracksNotSupported=MediaRecorder does not support recording multiple tracks of the same type at this time.
 # LOCALIZATION NOTE: %S is the ID of the MediaStreamTrack passed to MediaStream.addTrack(). Do not translate "MediaStreamTrack" and "AudioChannel".
--- a/dom/media/DecoderDoctorDiagnostics.cpp
+++ b/dom/media/DecoderDoctorDiagnostics.cpp
@@ -15,16 +15,20 @@
 #include "nsIObserverService.h"
 #include "nsIScriptError.h"
 #include "nsITimer.h"
 #include "nsIWeakReference.h"
 #include "nsPluginHost.h"
 #include "nsPrintfCString.h"
 #include "VideoUtils.h"
 
+#if defined(MOZ_FFMPEG)
+#include "FFmpegRuntimeLinker.h"
+#endif
+
 #if defined(XP_WIN)
 #include "mozilla/WindowsVersion.h"
 #endif
 
 static mozilla::LazyLogModule sDecoderDoctorLog("DecoderDoctor");
 #define DD_LOG(level, arg, ...) MOZ_LOG(sDecoderDoctorLog, level, (arg, ##__VA_ARGS__))
 #define DD_DEBUG(arg, ...) DD_LOG(mozilla::LogLevel::Debug, arg, ##__VA_ARGS__)
 #define DD_INFO(arg, ...) DD_LOG(mozilla::LogLevel::Info, arg, ##__VA_ARGS__)
@@ -262,27 +266,31 @@ static const NotificationAndReportString
   { dom::DecoderDoctorNotificationType::Cannot_play,
     "MediaCannotPlayNoDecoders" };
 static const NotificationAndReportStringId sMediaNoDecoders =
   { dom::DecoderDoctorNotificationType::Can_play_but_some_missing_decoders,
     "MediaNoDecoders" };
 static const NotificationAndReportStringId sCannotInitializePulseAudio =
   { dom::DecoderDoctorNotificationType::Cannot_initialize_pulseaudio,
     "MediaCannotInitializePulseAudio" };
+static const NotificationAndReportStringId sUnsupportedLibavcodec =
+  { dom::DecoderDoctorNotificationType::Unsupported_libavcodec,
+    "MediaUnsupportedLibavcodec" };
 
 static const NotificationAndReportStringId*
 sAllNotificationsAndReportStringIds[] =
 {
   &sMediaWidevineNoWMFNoSilverlight,
   &sMediaWMFNeeded,
   &sMediaUnsupportedBeforeWindowsVista,
   &sMediaPlatformDecoderNotFound,
   &sMediaCannotPlayNoDecoders,
   &sMediaNoDecoders,
-  &sCannotInitializePulseAudio
+  &sCannotInitializePulseAudio,
+  &sUnsupportedLibavcodec,
 };
 
 static void
 DispatchNotification(nsISupports* aSubject,
                      const NotificationAndReportStringId& aNotification,
                      bool aIsSolved,
                      const nsAString& aFormats)
 {
@@ -577,21 +585,44 @@ DecoderDoctorDocumentWatcher::Synthesize
           ReportAnalysis(mDocument, sMediaUnsupportedBeforeWindowsVista,
                          false, formatsRequiringWMF);
         }
         return;
       }
 #endif
 #if defined(MOZ_FFMPEG)
       if (!formatsRequiringFFMpeg.IsEmpty()) {
-        DD_INFO("DecoderDoctorDocumentWatcher[%p, doc=%p]::SynthesizeAnalysis() - unplayable formats: %s -> Cannot play media because platform decoder was not found",
-                this, mDocument, NS_ConvertUTF16toUTF8(formatsRequiringFFMpeg).get());
-        ReportAnalysis(mDocument, sMediaPlatformDecoderNotFound,
-                       false, formatsRequiringFFMpeg);
-        return;
+        switch (FFmpegRuntimeLinker::LinkStatusCode()) {
+          case FFmpegRuntimeLinker::LinkStatus_INVALID_FFMPEG_CANDIDATE:
+          case FFmpegRuntimeLinker::LinkStatus_UNUSABLE_LIBAV57:
+          case FFmpegRuntimeLinker::LinkStatus_INVALID_LIBAV_CANDIDATE:
+          case FFmpegRuntimeLinker::LinkStatus_OBSOLETE_FFMPEG:
+          case FFmpegRuntimeLinker::LinkStatus_OBSOLETE_LIBAV:
+          case FFmpegRuntimeLinker::LinkStatus_INVALID_CANDIDATE:
+            DD_INFO("DecoderDoctorDocumentWatcher[%p, doc=%p]::SynthesizeAnalysis() - unplayable formats: %s -> Cannot play media because of unsupported %s (Reason: %s)",
+                    this, mDocument,
+                    NS_ConvertUTF16toUTF8(formatsRequiringFFMpeg).get(),
+                    FFmpegRuntimeLinker::LinkStatusLibraryName(),
+                    FFmpegRuntimeLinker::LinkStatusString());
+            ReportAnalysis(mDocument, sUnsupportedLibavcodec,
+                           false, formatsRequiringFFMpeg);
+            return;
+          case FFmpegRuntimeLinker::LinkStatus_INIT:
+            MOZ_FALLTHROUGH_ASSERT("Unexpected LinkStatus_INIT");
+          case FFmpegRuntimeLinker::LinkStatus_SUCCEEDED:
+            MOZ_FALLTHROUGH_ASSERT("Unexpected LinkStatus_SUCCEEDED");
+          case FFmpegRuntimeLinker::LinkStatus_NOT_FOUND:
+            DD_INFO("DecoderDoctorDocumentWatcher[%p, doc=%p]::SynthesizeAnalysis() - unplayable formats: %s -> Cannot play media because platform decoder was not found (Reason: %s)",
+                    this, mDocument,
+                    NS_ConvertUTF16toUTF8(formatsRequiringFFMpeg).get(),
+                    FFmpegRuntimeLinker::LinkStatusString());
+            ReportAnalysis(mDocument, sMediaPlatformDecoderNotFound,
+                           false, formatsRequiringFFMpeg);
+            return;
+        }
       }
 #endif
       DD_INFO("DecoderDoctorDocumentWatcher[%p, doc=%p]::SynthesizeAnalysis() - Cannot play media, unplayable formats: %s",
               this, mDocument, NS_ConvertUTF16toUTF8(unplayableFormats).get());
       ReportAnalysis(mDocument, sMediaCannotPlayNoDecoders,
                      false, unplayableFormats);
       return;
     }
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -190,32 +190,17 @@ public:
   virtual ~StateObject() {}
   virtual void Enter() {}; // Entry action.
   virtual void Exit() {};  // Exit action.
   virtual void Step() {}   // Perform a 'cycle' of this state object.
   virtual State GetState() const = 0;
 
   // Event handlers for various events.
   // Return true if the event is handled by this state object.
-  virtual bool HandleDormant(bool aDormant)
-  {
-    if (!aDormant) {
-      return true;
-    }
-    mMaster->mQueuedSeek.mTarget =
-      SeekTarget(mMaster->mCurrentPosition,
-                 SeekTarget::Accurate,
-                 MediaDecoderEventVisibility::Suppressed);
-    // SeekJob asserts |mTarget.IsValid() == !mPromise.IsEmpty()| so we
-    // need to create the promise even it is not used at all.
-    RefPtr<MediaDecoder::SeekPromise> unused =
-      mMaster->mQueuedSeek.mPromise.Ensure(__func__);
-    SetState(DECODER_STATE_DORMANT);
-    return true;
-  }
+  virtual bool HandleDormant(bool aDormant);
 
   virtual bool HandleCDMProxyReady() { return false; }
 
   virtual bool HandleAudioDecoded(MediaData* aAudio) { return false; }
 
   virtual bool HandleVideoDecoded(MediaData* aVideo, TimeStamp aDecodeStart)
   {
     return false;
@@ -224,30 +209,57 @@ public:
   virtual bool HandleEndOfStream() { return false; }
 
   virtual bool HandleWaitingForData() { return false; }
 
   virtual RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) = 0;
 
   virtual bool HandleAudioCaptured() { return false; }
 
+  virtual RefPtr<ShutdownPromise> HandleShutdown();
+
   virtual void DumpDebugInfo() {}
 
 protected:
   using Master = MediaDecoderStateMachine;
   explicit StateObject(Master* aPtr) : mMaster(aPtr) {}
   TaskQueue* OwnerThread() const { return mMaster->mTaskQueue; }
   MediaResource* Resource() const { return mMaster->mResource; }
   MediaDecoderReaderWrapper* Reader() const { return mMaster->mReader; }
   const MediaInfo& Info() const { return mMaster->Info(); }
 
+public:
+  // TODO: this function is public because VisibilityChanged() calls it.
+  // We should handle visibility changes in state objects so this function
+  // can be made protected again.
+  //
   // Note this function will delete the current state object.
   // Don't access members to avoid UAF after this call.
-  void SetState(State aState) { mMaster->SetState(aState); }
-
+  template <class S, typename... Ts>
+  void SetState(Ts&&... aArgs)
+  {
+    // keep mMaster in a local object because mMaster will become invalid after
+    // the current state object is deleted.
+    auto master = mMaster;
+
+    UniquePtr<StateObject> s = MakeUnique<S>(master, Forward<Ts>(aArgs)...);
+    if (master->mState == s->GetState() &&
+        master->mState != DECODER_STATE_SEEKING) {
+      return;
+    }
+
+    SLOG("change state to: %s", ToStateStr(s->GetState()));
+
+    Exit();
+    master->mState = s->GetState();
+    master->mStateObj = Move(s); // Will delete |this|!
+    master->mStateObj->Enter();
+  }
+
+protected:
   // Take a raw pointer in order not to change the life cycle of MDSM.
   // It is guaranteed to be valid by MDSM.
   Master* mMaster;
 };
 
 class MediaDecoderStateMachine::DecodeMetadataState
   : public MediaDecoderStateMachine::StateObject
 {
@@ -292,81 +304,17 @@ public:
 
   RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
   {
     MOZ_DIAGNOSTIC_ASSERT(false, "Can't seek while decoding metadata.");
     return MediaDecoder::SeekPromise::CreateAndReject(true, __func__);
   }
 
 private:
-  void OnMetadataRead(MetadataHolder* aMetadata)
-  {
-    mMetadataRequest.Complete();
-
-    // Set mode to PLAYBACK after reading metadata.
-    Resource()->SetReadMode(MediaCacheStream::MODE_PLAYBACK);
-
-    mMaster->mInfo = Some(aMetadata->mInfo);
-    mMaster->mMetadataTags = aMetadata->mTags.forget();
-
-    if (Info().mMetadataDuration.isSome()) {
-      mMaster->RecomputeDuration();
-    } else if (Info().mUnadjustedMetadataEndTime.isSome()) {
-      RefPtr<Master> master = mMaster;
-      Reader()->AwaitStartTime()->Then(OwnerThread(), __func__,
-        [master] () {
-          NS_ENSURE_TRUE_VOID(!master->IsShutdown());
-          auto& info = master->mInfo.ref();
-          TimeUnit unadjusted = info.mUnadjustedMetadataEndTime.ref();
-          TimeUnit adjustment = master->mReader->StartTime();
-          info.mMetadataDuration.emplace(unadjusted - adjustment);
-          master->RecomputeDuration();
-        }, [master, this] () {
-          SWARN("Adjusting metadata end time failed");
-        }
-      );
-    }
-
-    if (mMaster->HasVideo()) {
-      SLOG("Video decode isAsync=%d HWAccel=%d videoQueueSize=%d",
-           Reader()->IsAsync(),
-           Reader()->VideoIsHardwareAccelerated(),
-           mMaster->GetAmpleVideoFrames());
-    }
-
-    // In general, we wait until we know the duration before notifying the decoder.
-    // However, we notify  unconditionally in this case without waiting for the start
-    // time, since the caller might be waiting on metadataloaded to be fired before
-    // feeding in the CDM, which we need to decode the first frame (and
-    // thus get the metadata). We could fix this if we could compute the start
-    // time by demuxing without necessaring decoding.
-    bool waitingForCDM = Info().IsEncrypted() && !mMaster->mCDMProxy;
-
-    mMaster->mNotifyMetadataBeforeFirstFrame =
-      mMaster->mDuration.Ref().isSome() || waitingForCDM;
-
-    if (mMaster->mNotifyMetadataBeforeFirstFrame) {
-      mMaster->EnqueueLoadedMetadataEvent();
-    }
-
-    if (mPendingDormant) {
-      // No need to store mQueuedSeek because we are at position 0.
-      SetState(DECODER_STATE_DORMANT);
-      return;
-    }
-
-    if (waitingForCDM) {
-      // Metadata parsing was successful but we're still waiting for CDM caps
-      // to become available so that we can build the correct decryptor/decoder.
-      SetState(DECODER_STATE_WAIT_FOR_CDM);
-      return;
-    }
-
-    SetState(DECODER_STATE_DECODING_FIRSTFRAME);
-  }
+  void OnMetadataRead(MetadataHolder* aMetadata);
 
   void OnMetadataNotRead(const MediaResult& aError)
   {
     mMetadataRequest.Complete();
     SWARN("Decode metadata failed, shutting down decoder");
     mMaster->DecodeError(aError);
   }
 
@@ -384,30 +332,19 @@ class MediaDecoderStateMachine::WaitForC
 public:
   explicit WaitForCDMState(Master* aPtr) : StateObject(aPtr) {}
 
   State GetState() const override
   {
     return DECODER_STATE_WAIT_FOR_CDM;
   }
 
-  bool HandleDormant(bool aDormant) override
-  {
-    if (aDormant) {
-      // No need to store mQueuedSeek because we are at position 0.
-      SetState(DECODER_STATE_DORMANT);
-    }
-    return true;
-  }
-
-  bool HandleCDMProxyReady() override
-  {
-    SetState(DECODER_STATE_DECODING_FIRSTFRAME);
-    return true;
-  }
+  bool HandleDormant(bool aDormant) override;
+
+  bool HandleCDMProxyReady() override;
 
   RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
   {
     SLOG("Not Enough Data to seek at this stage, queuing seek");
     mMaster->mQueuedSeek.RejectIfExists(__func__);
     mMaster->mQueuedSeek.mTarget = aTarget;
     return mMaster->mQueuedSeek.mPromise.Ensure(__func__);
   }
@@ -428,61 +365,34 @@ public:
     mMaster->mReader->ReleaseResources();
   }
 
   State GetState() const override
   {
     return DECODER_STATE_DORMANT;
   }
 
-  bool HandleDormant(bool aDormant) override
-  {
-    if (!aDormant) {
-      // Exit dormant state. Check if we need the CDMProxy to start decoding.
-      SetState(Info().IsEncrypted() && !mMaster->mCDMProxy
-        ? DECODER_STATE_WAIT_FOR_CDM
-        : DECODER_STATE_DECODING_FIRSTFRAME);
-    }
-    return true;
-  }
+  bool HandleDormant(bool aDormant) override;
 
   RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
   {
     SLOG("Not Enough Data to seek at this stage, queuing seek");
     mMaster->mQueuedSeek.RejectIfExists(__func__);
     mMaster->mQueuedSeek.mTarget = aTarget;
     return mMaster->mQueuedSeek.mPromise.Ensure(__func__);
   }
 };
 
 class MediaDecoderStateMachine::DecodingFirstFrameState
   : public MediaDecoderStateMachine::StateObject
 {
 public:
   explicit DecodingFirstFrameState(Master* aPtr) : StateObject(aPtr) {}
 
-  void Enter() override
-  {
-    // Handle pending seek.
-    if (mMaster->mQueuedSeek.Exists() &&
-        (mMaster->mSentFirstFrameLoadedEvent ||
-         Reader()->ForceZeroStartTime())) {
-      mMaster->InitiateSeek(Move(mMaster->mQueuedSeek));
-      return;
-    }
-
-    // Transition to DECODING if we've decoded first frames.
-    if (mMaster->mSentFirstFrameLoadedEvent) {
-      SetState(DECODER_STATE_DECODING);
-      return;
-    }
-
-    // Dispatch tasks to decode first frames.
-    mMaster->DispatchDecodeTasksIfNeeded();
-  }
+  void Enter() override;
 
   State GetState() const override
   {
     return DECODER_STATE_DECODING_FIRSTFRAME;
   }
 
   bool HandleAudioDecoded(MediaData* aAudio) override
   {
@@ -499,90 +409,31 @@ public:
   }
 
   bool HandleEndOfStream() override
   {
     MaybeFinishDecodeFirstFrame();
     return true;
   }
 
-  RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
-  {
-    // Should've transitioned to DECODING in Enter()
-    // if mSentFirstFrameLoadedEvent is true.
-    MOZ_ASSERT(!mMaster->mSentFirstFrameLoadedEvent);
-
-    if (!Reader()->ForceZeroStartTime()) {
-      SLOG("Not Enough Data to seek at this stage, queuing seek");
-      mMaster->mQueuedSeek.RejectIfExists(__func__);
-      mMaster->mQueuedSeek.mTarget = aTarget;
-      return mMaster->mQueuedSeek.mPromise.Ensure(__func__);
-    }
-
-    // Since ForceZeroStartTime() is true, we should've transitioned to SEEKING
-    // in Enter() if there is any queued seek.
-    MOZ_ASSERT(!mMaster->mQueuedSeek.Exists());
-
-    SLOG("Changed state to SEEKING (to %lld)", aTarget.GetTime().ToMicroseconds());
-    SeekJob seekJob;
-    seekJob.mTarget = aTarget;
-    RefPtr<MediaDecoder::SeekPromise> p = seekJob.mPromise.Ensure(__func__);
-    mMaster->InitiateSeek(Move(seekJob));
-    return p.forget();
-  }
+  RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override;
 
 private:
   // Notify FirstFrameLoaded if having decoded first frames and
   // transition to SEEKING if there is any pending seek, or DECODING otherwise.
-  void MaybeFinishDecodeFirstFrame()
-  {
-    MOZ_ASSERT(!mMaster->mSentFirstFrameLoadedEvent);
-
-    if ((mMaster->IsAudioDecoding() && mMaster->AudioQueue().GetSize() == 0) ||
-        (mMaster->IsVideoDecoding() && mMaster->VideoQueue().GetSize() == 0)) {
-      return;
-    }
-
-    mMaster->FinishDecodeFirstFrame();
-
-    if (mMaster->mQueuedSeek.Exists()) {
-      mMaster->InitiateSeek(Move(mMaster->mQueuedSeek));
-    } else {
-      SetState(DECODER_STATE_DECODING);
-    }
-  }
+  void MaybeFinishDecodeFirstFrame();
 };
 
 class MediaDecoderStateMachine::DecodingState
   : public MediaDecoderStateMachine::StateObject
 {
 public:
   explicit DecodingState(Master* aPtr) : StateObject(aPtr) {}
 
-  void Enter() override
-  {
-    MOZ_ASSERT(mMaster->mSentFirstFrameLoadedEvent);
-    // Pending seek should've been handled by DECODING_FIRSTFRAME before
-    // transitioning to DECODING.
-    MOZ_ASSERT(!mMaster->mQueuedSeek.Exists());
-
-    if (mMaster->CheckIfDecodeComplete()) {
-      SetState(DECODER_STATE_COMPLETED);
-      return;
-    }
-
-    mDecodeStartTime = TimeStamp::Now();
-
-    MaybeStopPrerolling();
-
-    // Ensure that we've got tasks enqueued to decode data if we need to.
-    mMaster->DispatchDecodeTasksIfNeeded();
-
-    mMaster->ScheduleStateMachine();
-  }
+  void Enter() override;
 
   void Exit() override
   {
     if (!mDecodeStartTime.IsNull()) {
       TimeDuration decodeDuration = TimeStamp::Now() - mDecodeStartTime;
       SLOG("Exiting DECODING, decoded for %.3lfs", decodeDuration.ToSeconds());
     }
   }
@@ -602,17 +453,17 @@ public:
     }
 
     mMaster->UpdatePlaybackPositionPeriodically();
 
     MOZ_ASSERT(!mMaster->IsPlaying() ||
                mMaster->IsStateMachineScheduled(),
                "Must have timer scheduled");
 
-    mMaster->MaybeStartBuffering();
+    MaybeStartBuffering();
   }
 
   State GetState() const override
   {
     return DECODER_STATE_DECODING;
   }
 
   bool HandleAudioDecoded(MediaData* aAudio) override
@@ -625,36 +476,19 @@ public:
   bool HandleVideoDecoded(MediaData* aVideo, TimeStamp aDecodeStart) override
   {
     mMaster->Push(aVideo, MediaData::VIDEO_DATA);
     MaybeStopPrerolling();
     CheckSlowDecoding(aDecodeStart);
     return true;
   }
 
-  RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
-  {
-    mMaster->mQueuedSeek.RejectIfExists(__func__);
-    SLOG("Changed state to SEEKING (to %lld)", aTarget.GetTime().ToMicroseconds());
-    SeekJob seekJob;
-    seekJob.mTarget = aTarget;
-    RefPtr<MediaDecoder::SeekPromise> p = seekJob.mPromise.Ensure(__func__);
-    mMaster->InitiateSeek(Move(seekJob));
-    return p.forget();
-  }
-
-  bool HandleEndOfStream() override
-  {
-    if (mMaster->CheckIfDecodeComplete()) {
-      SetState(DECODER_STATE_COMPLETED);
-    } else {
-      MaybeStopPrerolling();
-    }
-    return true;
-  }
+  RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override;
+
+  bool HandleEndOfStream() override;
 
   bool HandleWaitingForData() override
   {
     MaybeStopPrerolling();
     return true;
   }
 
   bool HandleAudioCaptured() override
@@ -666,16 +500,18 @@ public:
   }
 
   void DumpDebugInfo() override
   {
     SDUMP("mIsPrerolling=%d", mIsPrerolling);
   }
 
 private:
+  void MaybeStartBuffering();
+
   void CheckSlowDecoding(TimeStamp aDecodeStart)
   {
     // For non async readers, if the requested video sample was slow to
     // arrive, increase the amount of audio we buffer to ensure that we
     // don't run out of audio. This is unnecessary for async readers,
     // since they decode audio and video on different threads so they
     // are unlikely to run out of decoded audio.
     if (Reader()->IsAsync()) {
@@ -816,58 +652,31 @@ public:
     mMaster->SetMediaDecoderReaderWrapperCallback();
   }
 
   State GetState() const override
   {
     return DECODER_STATE_SEEKING;
   }
 
-  bool HandleDormant(bool aDormant) override
-  {
-    if (!aDormant) {
-      return true;
-    }
-    MOZ_ASSERT(!mMaster->mQueuedSeek.Exists());
-    MOZ_ASSERT(mSeekJob.Exists());
-    // Because both audio and video decoders are going to be reset in this
-    // method later, we treat a VideoOnly seek task as a normal Accurate
-    // seek task so that while it is resumed, both audio and video playback
-    // are handled.
-    if (mSeekJob.mTarget.IsVideoOnly()) {
-      mSeekJob.mTarget.SetType(SeekTarget::Accurate);
-      mSeekJob.mTarget.SetVideoOnly(false);
-    }
-    mMaster->mQueuedSeek = Move(mSeekJob);
-    SetState(DECODER_STATE_DORMANT);
-    return true;
-  }
+  bool HandleDormant(bool aDormant) override;
 
   bool HandleAudioDecoded(MediaData* aAudio) override
   {
     MOZ_ASSERT(false);
     return true;
   }
 
   bool HandleVideoDecoded(MediaData* aVideo, TimeStamp aDecodeStart) override
   {
     MOZ_ASSERT(false);
     return true;
   }
 
-  RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
-  {
-    mMaster->mQueuedSeek.RejectIfExists(__func__);
-    SLOG("Changed state to SEEKING (to %lld)", aTarget.GetTime().ToMicroseconds());
-    SeekJob seekJob;
-    seekJob.mTarget = aTarget;
-    RefPtr<MediaDecoder::SeekPromise> p = seekJob.mPromise.Ensure(__func__);
-    mMaster->InitiateSeek(Move(seekJob));
-    return p.forget();
-  }
+  RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override;
 
 private:
   void OnSeekTaskResolved(const SeekTaskResolveValue& aValue)
   {
     mSeekTaskRequest.Complete();
 
     if (aValue.mSeekedAudioData) {
       mMaster->Push(aValue.mSeekedAudioData, MediaData::AUDIO_DATA);
@@ -902,89 +711,17 @@ private:
 
     if (aValue.mIsVideoQueueFinished) {
       mMaster->VideoQueue().Finish();
     }
 
     mMaster->DecodeError(aValue.mError);
   }
 
-  void SeekCompleted()
-  {
-    int64_t seekTime = mSeekTask->GetSeekTarget().GetTime().ToMicroseconds();
-    int64_t newCurrentTime = seekTime;
-
-    // Setup timestamp state.
-    RefPtr<MediaData> video = mMaster->VideoQueue().PeekFront();
-    if (seekTime == mMaster->Duration().ToMicroseconds()) {
-      newCurrentTime = seekTime;
-    } else if (mMaster->HasAudio()) {
-      RefPtr<MediaData> audio = mMaster->AudioQueue().PeekFront();
-      // Though we adjust the newCurrentTime in audio-based, and supplemented
-      // by video. For better UX, should NOT bind the slide position to
-      // the first audio data timestamp directly.
-      // While seeking to a position where there's only either audio or video, or
-      // seeking to a position lies before audio or video, we need to check if
-      // seekTime is bounded in suitable duration. See Bug 1112438.
-      int64_t audioStart = audio ? audio->mTime : seekTime;
-      // We only pin the seek time to the video start time if the video frame
-      // contains the seek time.
-      if (video && video->mTime <= seekTime && video->GetEndTime() > seekTime) {
-        newCurrentTime = std::min(audioStart, video->mTime);
-      } else {
-        newCurrentTime = audioStart;
-      }
-    } else {
-      newCurrentTime = video ? video->mTime : seekTime;
-    }
-
-    // Change state to DECODING or COMPLETED now.
-    bool isLiveStream = Resource()->IsLiveStream();
-    State nextState;
-    if (newCurrentTime == mMaster->Duration().ToMicroseconds() && !isLiveStream) {
-      // Seeked to end of media, move to COMPLETED state. Note we don't do
-      // this when playing a live stream, since the end of media will advance
-      // once we download more data!
-      // Explicitly set our state so we don't decode further, and so
-      // we report playback ended to the media element.
-      nextState = DECODER_STATE_COMPLETED;
-    } else {
-      nextState = DECODER_STATE_DECODING;
-    }
-
-    // We want to resolve the seek request prior finishing the first frame
-    // to ensure that the seeked event is fired prior loadeded.
-    mSeekJob.Resolve(nextState == DECODER_STATE_COMPLETED, __func__);
-
-    // Notify FirstFrameLoaded now if we haven't since we've decoded some data
-    // for readyState to transition to HAVE_CURRENT_DATA and fire 'loadeddata'.
-    if (!mMaster->mSentFirstFrameLoadedEvent) {
-      // Only MSE can start seeking before finishing decoding first frames.
-      MOZ_ASSERT(Reader()->ForceZeroStartTime());
-      mMaster->FinishDecodeFirstFrame();
-    }
-
-    // Ensure timestamps are up to date.
-    if (!mSeekJob.mTarget.IsVideoOnly()) {
-      // Don't update playback position for video-only seek.
-      // Otherwise we might have |newCurrentTime > mMediaSink->GetPosition()|
-      // and fail the assertion in GetClock() since we didn't stop MediaSink.
-      mMaster->UpdatePlaybackPositionInternal(newCurrentTime);
-    }
-
-    // Try to decode another frame to detect if we're at the end...
-    SLOG("Seek completed, mCurrentPosition=%lld", mMaster->mCurrentPosition.Ref());
-
-    if (video) {
-      mMaster->mMediaSink->Redraw(Info().mVideo);
-      mMaster->mOnPlaybackEvent.Notify(MediaEventType::Invalidate);
-    }
-
-    SetState(nextState);
-  }
+  void SeekCompleted();
 
   SeekJob mSeekJob;
   MozPromiseRequestHolder<SeekTask::SeekTaskPromise> mSeekTaskRequest;
   RefPtr<SeekTask> mSeekTask;
 };
 
 class MediaDecoderStateMachine::BufferingState
   : public MediaDecoderStateMachine::StateObject
@@ -1003,58 +740,17 @@ public:
     MediaStatistics stats = mMaster->GetStatistics();
     SLOG("Playback rate: %.1lfKB/s%s download rate: %.1lfKB/s%s",
          stats.mPlaybackRate/1024, stats.mPlaybackRateReliable ? "" : " (unreliable)",
          stats.mDownloadRate/1024, stats.mDownloadRateReliable ? "" : " (unreliable)");
 
     mMaster->ScheduleStateMachineIn(USECS_PER_S);
   }
 
-  void Step() override
-  {
-    TimeStamp now = TimeStamp::Now();
-    MOZ_ASSERT(!mBufferingStart.IsNull(), "Must know buffering start time.");
-
-    // With buffering heuristics we will remain in the buffering state if
-    // we've not decoded enough data to begin playback, or if we've not
-    // downloaded a reasonable amount of data inside our buffering time.
-    if (Reader()->UseBufferingHeuristics()) {
-      TimeDuration elapsed = now - mBufferingStart;
-      bool isLiveStream = Resource()->IsLiveStream();
-      if ((isLiveStream || !mMaster->CanPlayThrough()) &&
-          elapsed < TimeDuration::FromSeconds(mBufferingWait * mMaster->mPlaybackRate) &&
-          mMaster->HasLowBufferedData(mBufferingWait * USECS_PER_S) &&
-          Resource()->IsExpectingMoreData()) {
-        SLOG("Buffering: wait %ds, timeout in %.3lfs",
-             mBufferingWait, mBufferingWait - elapsed.ToSeconds());
-        mMaster->ScheduleStateMachineIn(USECS_PER_S);
-        return;
-      }
-    } else if (mMaster->OutOfDecodedAudio() || mMaster->OutOfDecodedVideo()) {
-      MOZ_ASSERT(Reader()->IsWaitForDataSupported(),
-                 "Don't yet have a strategy for non-heuristic + non-WaitForData");
-      mMaster->DispatchDecodeTasksIfNeeded();
-      MOZ_ASSERT(mMaster->mMinimizePreroll ||
-                 !mMaster->OutOfDecodedAudio() ||
-                 Reader()->IsRequestingAudioData() ||
-                 Reader()->IsWaitingAudioData());
-      MOZ_ASSERT(mMaster->mMinimizePreroll ||
-                 !mMaster->OutOfDecodedVideo() ||
-                 Reader()->IsRequestingVideoData() ||
-                 Reader()->IsWaitingVideoData());
-      SLOG("In buffering mode, waiting to be notified: outOfAudio: %d, "
-           "mAudioStatus: %s, outOfVideo: %d, mVideoStatus: %s",
-           mMaster->OutOfDecodedAudio(), mMaster->AudioRequestStatus(),
-           mMaster->OutOfDecodedVideo(), mMaster->VideoRequestStatus());
-      return;
-    }
-
-    SLOG("Buffered for %.3lfs", (now - mBufferingStart).ToSeconds());
-    SetState(DECODER_STATE_DECODING);
-  }
+  void Step() override;
 
   State GetState() const override
   {
     return DECODER_STATE_BUFFERING;
   }
 
   bool HandleAudioDecoded(MediaData* aAudio) override
   {
@@ -1069,37 +765,19 @@ public:
   {
     // This might be the sample we need to exit buffering.
     // Schedule Step() to check it.
     mMaster->Push(aVideo, MediaData::VIDEO_DATA);
     mMaster->ScheduleStateMachine();
     return true;
   }
 
-  bool HandleEndOfStream() override
-  {
-    if (mMaster->CheckIfDecodeComplete()) {
-      SetState(DECODER_STATE_COMPLETED);
-    } else {
-      // Check if we can exit buffering.
-      mMaster->ScheduleStateMachine();
-    }
-    return true;
-  }
-
-  RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
-  {
-    mMaster->mQueuedSeek.RejectIfExists(__func__);
-    SLOG("Changed state to SEEKING (to %lld)", aTarget.GetTime().ToMicroseconds());
-    SeekJob seekJob;
-    seekJob.mTarget = aTarget;
-    RefPtr<MediaDecoder::SeekPromise> p = seekJob.mPromise.Ensure(__func__);
-    mMaster->InitiateSeek(Move(seekJob));
-    return p.forget();
-  }
+  bool HandleEndOfStream() override;
+
+  RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override;
 
 private:
   TimeStamp mBufferingStart;
 
   // The maximum number of second we spend buffering when we are short on
   // unbuffered data.
   const uint32_t mBufferingWait = 15;
 };
@@ -1163,26 +841,17 @@ public:
     }
   }
 
   State GetState() const override
   {
     return DECODER_STATE_COMPLETED;
   }
 
-  RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
-  {
-    mMaster->mQueuedSeek.RejectIfExists(__func__);
-    SLOG("Changed state to SEEKING (to %lld)", aTarget.GetTime().ToMicroseconds());
-    SeekJob seekJob;
-    seekJob.mTarget = aTarget;
-    RefPtr<MediaDecoder::SeekPromise> p = seekJob.mPromise.Ensure(__func__);
-    mMaster->InitiateSeek(Move(seekJob));
-    return p.forget();
-  }
+  RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override;
 
   bool HandleAudioCaptured() override
   {
     // MediaSink is changed. Schedule Step() to check if we can start playback.
     mMaster->ScheduleStateMachine();
     return true;
   }
 
@@ -1191,20 +860,17 @@ private:
 };
 
 class MediaDecoderStateMachine::ShutdownState
   : public MediaDecoderStateMachine::StateObject
 {
 public:
   explicit ShutdownState(Master* aPtr) : StateObject(aPtr) {}
 
-  void Enter() override
-  {
-    mMaster->mIsShutdown = true;
-  }
+  void Enter() override;
 
   void Exit() override
   {
     MOZ_DIAGNOSTIC_ASSERT(false, "Shouldn't escape the SHUTDOWN state.");
   }
 
   State GetState() const override
   {
@@ -1216,18 +882,575 @@ public:
     return true;
   }
 
   RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
   {
     MOZ_DIAGNOSTIC_ASSERT(false, "Can't seek in shutdown state.");
     return MediaDecoder::SeekPromise::CreateAndReject(true, __func__);
   }
+
+  RefPtr<ShutdownPromise> HandleShutdown() override
+  {
+    MOZ_DIAGNOSTIC_ASSERT(false, "Already shutting down.");
+    return nullptr;
+  }
 };
 
+bool
+MediaDecoderStateMachine::
+StateObject::HandleDormant(bool aDormant)
+{
+  if (!aDormant) {
+    return true;
+  }
+  mMaster->mQueuedSeek.mTarget =
+    SeekTarget(mMaster->mCurrentPosition,
+               SeekTarget::Accurate,
+               MediaDecoderEventVisibility::Suppressed);
+  // SeekJob asserts |mTarget.IsValid() == !mPromise.IsEmpty()| so we
+  // need to create the promise even it is not used at all.
+  RefPtr<MediaDecoder::SeekPromise> unused =
+    mMaster->mQueuedSeek.mPromise.Ensure(__func__);
+  SetState<DormantState>();
+  return true;
+}
+
+RefPtr<ShutdownPromise>
+MediaDecoderStateMachine::
+StateObject::HandleShutdown()
+{
+  auto master = mMaster;
+  SetState<ShutdownState>();
+
+  return master->mReader->Shutdown()
+    ->Then(master->OwnerThread(), __func__, master,
+           &MediaDecoderStateMachine::FinishShutdown,
+           &MediaDecoderStateMachine::FinishShutdown)
+    ->CompletionPromise();
+}
+
+void
+MediaDecoderStateMachine::
+DecodeMetadataState::OnMetadataRead(MetadataHolder* aMetadata)
+{
+  mMetadataRequest.Complete();
+
+  // Set mode to PLAYBACK after reading metadata.
+  Resource()->SetReadMode(MediaCacheStream::MODE_PLAYBACK);
+
+  mMaster->mInfo = Some(aMetadata->mInfo);
+  mMaster->mMetadataTags = aMetadata->mTags.forget();
+
+  if (Info().mMetadataDuration.isSome()) {
+    mMaster->RecomputeDuration();
+  } else if (Info().mUnadjustedMetadataEndTime.isSome()) {
+    RefPtr<Master> master = mMaster;
+    Reader()->AwaitStartTime()->Then(OwnerThread(), __func__,
+      [master] () {
+        NS_ENSURE_TRUE_VOID(!master->IsShutdown());
+        auto& info = master->mInfo.ref();
+        TimeUnit unadjusted = info.mUnadjustedMetadataEndTime.ref();
+        TimeUnit adjustment = master->mReader->StartTime();
+        info.mMetadataDuration.emplace(unadjusted - adjustment);
+        master->RecomputeDuration();
+      }, [master, this] () {
+        SWARN("Adjusting metadata end time failed");
+      }
+    );
+  }
+
+  if (mMaster->HasVideo()) {
+    SLOG("Video decode isAsync=%d HWAccel=%d videoQueueSize=%d",
+         Reader()->IsAsync(),
+         Reader()->VideoIsHardwareAccelerated(),
+         mMaster->GetAmpleVideoFrames());
+  }
+
+  // In general, we wait until we know the duration before notifying the decoder.
+  // However, we notify  unconditionally in this case without waiting for the start
+  // time, since the caller might be waiting on metadataloaded to be fired before
+  // feeding in the CDM, which we need to decode the first frame (and
+  // thus get the metadata). We could fix this if we could compute the start
+  // time by demuxing without necessaring decoding.
+  bool waitingForCDM = Info().IsEncrypted() && !mMaster->mCDMProxy;
+
+  mMaster->mNotifyMetadataBeforeFirstFrame =
+    mMaster->mDuration.Ref().isSome() || waitingForCDM;
+
+  if (mMaster->mNotifyMetadataBeforeFirstFrame) {
+    mMaster->EnqueueLoadedMetadataEvent();
+  }
+
+  if (mPendingDormant) {
+    // No need to store mQueuedSeek because we are at position 0.
+    SetState<DormantState>();
+    return;
+  }
+
+  if (waitingForCDM) {
+    // Metadata parsing was successful but we're still waiting for CDM caps
+    // to become available so that we can build the correct decryptor/decoder.
+    SetState<WaitForCDMState>();
+    return;
+  }
+
+  SetState<DecodingFirstFrameState>();
+}
+
+bool
+MediaDecoderStateMachine::
+WaitForCDMState::HandleDormant(bool aDormant)
+{
+  if (aDormant) {
+    // No need to store mQueuedSeek because we are at position 0.
+    SetState<DormantState>();
+  }
+  return true;
+}
+
+bool
+MediaDecoderStateMachine::
+DormantState::HandleDormant(bool aDormant)
+{
+  if (!aDormant) {
+    // Exit dormant state. Check if we need the CDMProxy to start decoding.
+    if (Info().IsEncrypted() && !mMaster->mCDMProxy) {
+      SetState<WaitForCDMState>();
+    } else {
+      SetState<DecodingFirstFrameState>();
+    }
+  }
+  return true;
+}
+
+bool
+MediaDecoderStateMachine::
+WaitForCDMState::HandleCDMProxyReady()
+{
+  SetState<DecodingFirstFrameState>();
+  return true;
+}
+
+void
+MediaDecoderStateMachine::
+DecodingFirstFrameState::Enter()
+{
+  // Handle pending seek.
+  if (mMaster->mQueuedSeek.Exists() &&
+      (mMaster->mSentFirstFrameLoadedEvent ||
+       Reader()->ForceZeroStartTime())) {
+    SetState<SeekingState>(Move(mMaster->mQueuedSeek));
+    return;
+  }
+
+  // Transition to DECODING if we've decoded first frames.
+  if (mMaster->mSentFirstFrameLoadedEvent) {
+    SetState<DecodingState>();
+    return;
+  }
+
+  // Dispatch tasks to decode first frames.
+  mMaster->DispatchDecodeTasksIfNeeded();
+}
+
+RefPtr<MediaDecoder::SeekPromise>
+MediaDecoderStateMachine::
+DecodingFirstFrameState::HandleSeek(SeekTarget aTarget)
+{
+  // Should've transitioned to DECODING in Enter()
+  // if mSentFirstFrameLoadedEvent is true.
+  MOZ_ASSERT(!mMaster->mSentFirstFrameLoadedEvent);
+
+  if (!Reader()->ForceZeroStartTime()) {
+    SLOG("Not Enough Data to seek at this stage, queuing seek");
+    mMaster->mQueuedSeek.RejectIfExists(__func__);
+    mMaster->mQueuedSeek.mTarget = aTarget;
+    return mMaster->mQueuedSeek.mPromise.Ensure(__func__);
+  }
+
+  // Since ForceZeroStartTime() is true, we should've transitioned to SEEKING
+  // in Enter() if there is any queued seek.
+  MOZ_ASSERT(!mMaster->mQueuedSeek.Exists());
+
+  SLOG("Changed state to SEEKING (to %lld)", aTarget.GetTime().ToMicroseconds());
+  SeekJob seekJob;
+  seekJob.mTarget = aTarget;
+  RefPtr<MediaDecoder::SeekPromise> p = seekJob.mPromise.Ensure(__func__);
+  SetState<SeekingState>(Move(seekJob));
+  return p.forget();
+}
+
+void
+MediaDecoderStateMachine::
+DecodingFirstFrameState::MaybeFinishDecodeFirstFrame()
+{
+  MOZ_ASSERT(!mMaster->mSentFirstFrameLoadedEvent);
+
+  if ((mMaster->IsAudioDecoding() && mMaster->AudioQueue().GetSize() == 0) ||
+      (mMaster->IsVideoDecoding() && mMaster->VideoQueue().GetSize() == 0)) {
+    return;
+  }
+
+  mMaster->FinishDecodeFirstFrame();
+
+  if (mMaster->mQueuedSeek.Exists()) {
+    SetState<SeekingState>(Move(mMaster->mQueuedSeek));
+  } else {
+    SetState<DecodingState>();
+  }
+}
+
+void
+MediaDecoderStateMachine::
+DecodingState::Enter()
+{
+  MOZ_ASSERT(mMaster->mSentFirstFrameLoadedEvent);
+  // Pending seek should've been handled by DECODING_FIRSTFRAME before
+  // transitioning to DECODING.
+  MOZ_ASSERT(!mMaster->mQueuedSeek.Exists());
+
+  if (mMaster->CheckIfDecodeComplete()) {
+    SetState<CompletedState>();
+    return;
+  }
+
+  mDecodeStartTime = TimeStamp::Now();
+
+  MaybeStopPrerolling();
+
+  // Ensure that we've got tasks enqueued to decode data if we need to.
+  mMaster->DispatchDecodeTasksIfNeeded();
+
+  mMaster->ScheduleStateMachine();
+}
+
+RefPtr<MediaDecoder::SeekPromise>
+MediaDecoderStateMachine::
+DecodingState::HandleSeek(SeekTarget aTarget)
+{
+  mMaster->mQueuedSeek.RejectIfExists(__func__);
+  SLOG("Changed state to SEEKING (to %lld)", aTarget.GetTime().ToMicroseconds());
+  SeekJob seekJob;
+  seekJob.mTarget = aTarget;
+  RefPtr<MediaDecoder::SeekPromise> p = seekJob.mPromise.Ensure(__func__);
+  SetState<SeekingState>(Move(seekJob));
+  return p.forget();
+}
+
+bool
+MediaDecoderStateMachine::
+DecodingState::HandleEndOfStream()
+{
+  if (mMaster->CheckIfDecodeComplete()) {
+    SetState<CompletedState>();
+  } else {
+    MaybeStopPrerolling();
+  }
+  return true;
+}
+
+void
+MediaDecoderStateMachine::
+DecodingState::MaybeStartBuffering()
+{
+  // Buffering makes senses only after decoding first frames.
+  MOZ_ASSERT(mMaster->mSentFirstFrameLoadedEvent);
+
+  // Don't enter buffering when MediaDecoder is not playing.
+  if (mMaster->mPlayState != MediaDecoder::PLAY_STATE_PLAYING) {
+    return;
+  }
+
+  // Don't enter buffering while prerolling so that the decoder has a chance to
+  // enqueue some decoded data before we give up and start buffering.
+  if (!mMaster->IsPlaying()) {
+    return;
+  }
+
+  // No more data to download. No need to enter buffering.
+  if (!Resource()->IsExpectingMoreData()) {
+    return;
+  }
+
+  bool shouldBuffer;
+  if (Reader()->UseBufferingHeuristics()) {
+    shouldBuffer = mMaster->HasLowDecodedData() && mMaster->HasLowBufferedData();
+  } else {
+    MOZ_ASSERT(Reader()->IsWaitForDataSupported());
+    shouldBuffer =
+      (mMaster->OutOfDecodedAudio() && Reader()->IsWaitingAudioData()) ||
+      (mMaster->OutOfDecodedVideo() && Reader()->IsWaitingVideoData());
+  }
+  if (shouldBuffer) {
+    SetState<BufferingState>();
+  }
+}
+
+bool
+MediaDecoderStateMachine::
+SeekingState::HandleDormant(bool aDormant)
+{
+  if (!aDormant) {
+    return true;
+  }
+  MOZ_ASSERT(!mMaster->mQueuedSeek.Exists());
+  MOZ_ASSERT(mSeekJob.Exists());
+  // Because both audio and video decoders are going to be reset in this
+  // method later, we treat a VideoOnly seek task as a normal Accurate
+  // seek task so that while it is resumed, both audio and video playback
+  // are handled.
+  if (mSeekJob.mTarget.IsVideoOnly()) {
+    mSeekJob.mTarget.SetType(SeekTarget::Accurate);
+    mSeekJob.mTarget.SetVideoOnly(false);
+  }
+  mMaster->mQueuedSeek = Move(mSeekJob);
+  SetState<DormantState>();
+  return true;
+}
+
+RefPtr<MediaDecoder::SeekPromise>
+MediaDecoderStateMachine::
+SeekingState::HandleSeek(SeekTarget aTarget)
+{
+  mMaster->mQueuedSeek.RejectIfExists(__func__);
+  SLOG("Changed state to SEEKING (to %lld)", aTarget.GetTime().ToMicroseconds());
+  SeekJob seekJob;
+  seekJob.mTarget = aTarget;
+  RefPtr<MediaDecoder::SeekPromise> p = seekJob.mPromise.Ensure(__func__);
+  SetState<SeekingState>(Move(seekJob));
+  return p.forget();
+}
+
+void
+MediaDecoderStateMachine::
+SeekingState::SeekCompleted()
+{
+  int64_t seekTime = mSeekTask->GetSeekTarget().GetTime().ToMicroseconds();
+  int64_t newCurrentTime = seekTime;
+
+  // Setup timestamp state.
+  RefPtr<MediaData> video = mMaster->VideoQueue().PeekFront();
+  if (seekTime == mMaster->Duration().ToMicroseconds()) {
+    newCurrentTime = seekTime;
+  } else if (mMaster->HasAudio()) {
+    RefPtr<MediaData> audio = mMaster->AudioQueue().PeekFront();
+    // Though we adjust the newCurrentTime in audio-based, and supplemented
+    // by video. For better UX, should NOT bind the slide position to
+    // the first audio data timestamp directly.
+    // While seeking to a position where there's only either audio or video, or
+    // seeking to a position lies before audio or video, we need to check if
+    // seekTime is bounded in suitable duration. See Bug 1112438.
+    int64_t audioStart = audio ? audio->mTime : seekTime;
+    // We only pin the seek time to the video start time if the video frame
+    // contains the seek time.
+    if (video && video->mTime <= seekTime && video->GetEndTime() > seekTime) {
+      newCurrentTime = std::min(audioStart, video->mTime);
+    } else {
+      newCurrentTime = audioStart;
+    }
+  } else {
+    newCurrentTime = video ? video->mTime : seekTime;
+  }
+
+  // Change state to DECODING or COMPLETED now.
+  bool isLiveStream = Resource()->IsLiveStream();
+  State nextState;
+  if (newCurrentTime == mMaster->Duration().ToMicroseconds() && !isLiveStream) {
+    // Seeked to end of media, move to COMPLETED state. Note we don't do
+    // this when playing a live stream, since the end of media will advance
+    // once we download more data!
+    // Explicitly set our state so we don't decode further, and so
+    // we report playback ended to the media element.
+    nextState = DECODER_STATE_COMPLETED;
+  } else {
+    nextState = DECODER_STATE_DECODING;
+  }
+
+  // We want to resolve the seek request prior finishing the first frame
+  // to ensure that the seeked event is fired prior loadeded.
+  mSeekJob.Resolve(nextState == DECODER_STATE_COMPLETED, __func__);
+
+  // Notify FirstFrameLoaded now if we haven't since we've decoded some data
+  // for readyState to transition to HAVE_CURRENT_DATA and fire 'loadeddata'.
+  if (!mMaster->mSentFirstFrameLoadedEvent) {
+    // Only MSE can start seeking before finishing decoding first frames.
+    MOZ_ASSERT(Reader()->ForceZeroStartTime());
+    mMaster->FinishDecodeFirstFrame();
+  }
+
+  // Ensure timestamps are up to date.
+  if (!mSeekJob.mTarget.IsVideoOnly()) {
+    // Don't update playback position for video-only seek.
+    // Otherwise we might have |newCurrentTime > mMediaSink->GetPosition()|
+    // and fail the assertion in GetClock() since we didn't stop MediaSink.
+    mMaster->UpdatePlaybackPositionInternal(newCurrentTime);
+  }
+
+  // Try to decode another frame to detect if we're at the end...
+  SLOG("Seek completed, mCurrentPosition=%lld", mMaster->mCurrentPosition.Ref());
+
+  if (video) {
+    mMaster->mMediaSink->Redraw(Info().mVideo);
+    mMaster->mOnPlaybackEvent.Notify(MediaEventType::Invalidate);
+  }
+
+  if (nextState == DECODER_STATE_COMPLETED) {
+    SetState<CompletedState>();
+  } else {
+    SetState<DecodingState>();
+  }
+}
+
+void
+MediaDecoderStateMachine::
+BufferingState::Step()
+{
+  TimeStamp now = TimeStamp::Now();
+  MOZ_ASSERT(!mBufferingStart.IsNull(), "Must know buffering start time.");
+
+  // With buffering heuristics we will remain in the buffering state if
+  // we've not decoded enough data to begin playback, or if we've not
+  // downloaded a reasonable amount of data inside our buffering time.
+  if (Reader()->UseBufferingHeuristics()) {
+    TimeDuration elapsed = now - mBufferingStart;
+    bool isLiveStream = Resource()->IsLiveStream();
+    if ((isLiveStream || !mMaster->CanPlayThrough()) &&
+        elapsed < TimeDuration::FromSeconds(mBufferingWait * mMaster->mPlaybackRate) &&
+        mMaster->HasLowBufferedData(mBufferingWait * USECS_PER_S) &&
+        Resource()->IsExpectingMoreData()) {
+      SLOG("Buffering: wait %ds, timeout in %.3lfs",
+           mBufferingWait, mBufferingWait - elapsed.ToSeconds());
+      mMaster->ScheduleStateMachineIn(USECS_PER_S);
+      return;
+    }
+  } else if (mMaster->OutOfDecodedAudio() || mMaster->OutOfDecodedVideo()) {
+    MOZ_ASSERT(Reader()->IsWaitForDataSupported(),
+               "Don't yet have a strategy for non-heuristic + non-WaitForData");
+    mMaster->DispatchDecodeTasksIfNeeded();
+    MOZ_ASSERT(mMaster->mMinimizePreroll ||
+               !mMaster->OutOfDecodedAudio() ||
+               Reader()->IsRequestingAudioData() ||
+               Reader()->IsWaitingAudioData());
+    MOZ_ASSERT(mMaster->mMinimizePreroll ||
+               !mMaster->OutOfDecodedVideo() ||
+               Reader()->IsRequestingVideoData() ||
+               Reader()->IsWaitingVideoData());
+    SLOG("In buffering mode, waiting to be notified: outOfAudio: %d, "
+         "mAudioStatus: %s, outOfVideo: %d, mVideoStatus: %s",
+         mMaster->OutOfDecodedAudio(), mMaster->AudioRequestStatus(),
+         mMaster->OutOfDecodedVideo(), mMaster->VideoRequestStatus());
+    return;
+  }
+
+  SLOG("Buffered for %.3lfs", (now - mBufferingStart).ToSeconds());
+  SetState<DecodingState>();
+}
+
+bool
+MediaDecoderStateMachine::
+BufferingState::HandleEndOfStream()
+{
+  if (mMaster->CheckIfDecodeComplete()) {
+    SetState<CompletedState>();
+  } else {
+    // Check if we can exit buffering.
+    mMaster->ScheduleStateMachine();
+  }
+  return true;
+}
+
+RefPtr<MediaDecoder::SeekPromise>
+MediaDecoderStateMachine::
+BufferingState::HandleSeek(SeekTarget aTarget)
+{
+  mMaster->mQueuedSeek.RejectIfExists(__func__);
+  SLOG("Changed state to SEEKING (to %lld)", aTarget.GetTime().ToMicroseconds());
+  SeekJob seekJob;
+  seekJob.mTarget = aTarget;
+  RefPtr<MediaDecoder::SeekPromise> p = seekJob.mPromise.Ensure(__func__);
+  SetState<SeekingState>(Move(seekJob));
+  return p.forget();
+}
+
+RefPtr<MediaDecoder::SeekPromise>
+MediaDecoderStateMachine::
+CompletedState::HandleSeek(SeekTarget aTarget)
+{
+  mMaster->mQueuedSeek.RejectIfExists(__func__);
+  SLOG("Changed state to SEEKING (to %lld)", aTarget.GetTime().ToMicroseconds());
+  SeekJob seekJob;
+  seekJob.mTarget = aTarget;
+  RefPtr<MediaDecoder::SeekPromise> p = seekJob.mPromise.Ensure(__func__);
+  SetState<SeekingState>(Move(seekJob));
+  return p.forget();
+}
+
+void
+MediaDecoderStateMachine::
+ShutdownState::Enter()
+{
+  auto master = mMaster;
+
+  master->mIsShutdown = true;
+  master->mDelayedScheduler.Reset();
+  master->mBufferedUpdateRequest.DisconnectIfExists();
+  master->mQueuedSeek.RejectIfExists(__func__);
+
+  // Shutdown happens while decode timer is active, we need to disconnect and
+  // dispose of the timer.
+  master->mVideoDecodeSuspendTimer.Reset();
+
+  master->mCDMProxyPromise.DisconnectIfExists();
+
+  if (master->IsPlaying()) {
+    master->StopPlayback();
+  }
+
+  // To break the cycle-reference between MediaDecoderReaderWrapper and MDSM.
+  master->CancelMediaDecoderReaderWrapperCallback();
+
+  master->Reset();
+
+  master->mMediaSink->Shutdown();
+
+  // Prevent dangling pointers by disconnecting the listeners.
+  master->mAudioQueueListener.Disconnect();
+  master->mVideoQueueListener.Disconnect();
+  master->mMetadataManager.Disconnect();
+
+  // Disconnect canonicals and mirrors before shutting down our task queue.
+  master->mBuffered.DisconnectIfConnected();
+  master->mIsReaderSuspended.DisconnectIfConnected();
+  master->mEstimatedDuration.DisconnectIfConnected();
+  master->mExplicitDuration.DisconnectIfConnected();
+  master->mPlayState.DisconnectIfConnected();
+  master->mNextPlayState.DisconnectIfConnected();
+  master->mVolume.DisconnectIfConnected();
+  master->mPreservesPitch.DisconnectIfConnected();
+  master->mSameOriginMedia.DisconnectIfConnected();
+  master->mMediaPrincipalHandle.DisconnectIfConnected();
+  master->mPlaybackBytesPerSecond.DisconnectIfConnected();
+  master->mPlaybackRateReliable.DisconnectIfConnected();
+  master->mDecoderPosition.DisconnectIfConnected();
+  master->mMediaSeekable.DisconnectIfConnected();
+  master->mMediaSeekableOnlyInBufferedRanges.DisconnectIfConnected();
+  master->mIsVisible.DisconnectIfConnected();
+
+  master->mDuration.DisconnectAll();
+  master->mIsShutdown.DisconnectAll();
+  master->mNextFrameStatus.DisconnectAll();
+  master->mCurrentPosition.DisconnectAll();
+  master->mPlaybackOffset.DisconnectAll();
+  master->mIsAudioDataAudible.DisconnectAll();
+
+  // Shut down the watch manager to stop further notifications.
+  master->mWatchManager.Shutdown();
+}
+
 #define INIT_WATCHABLE(name, val) \
   name(val, "MediaDecoderStateMachine::" #name)
 #define INIT_MIRROR(name, val) \
   name(mTaskQueue, val, "MediaDecoderStateMachine::" #name " (Mirror)")
 #define INIT_CANONICAL(name, val) \
   name(mTaskQueue, val, "MediaDecoderStateMachine::" #name " (Canonical)")
 
 MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
@@ -1828,53 +2051,16 @@ void MediaDecoderStateMachine::MaybeStar
   if (!IsPlaying()) {
     mMediaSink->SetPlaying(true);
     MOZ_ASSERT(IsPlaying());
   }
 
   DispatchDecodeTasksIfNeeded();
 }
 
-void
-MediaDecoderStateMachine::MaybeStartBuffering()
-{
-  MOZ_ASSERT(OnTaskQueue());
-  // Buffering makes senses only after decoding first frames.
-  MOZ_ASSERT(mSentFirstFrameLoadedEvent);
-  MOZ_ASSERT(mState == DECODER_STATE_DECODING);
-
-  // Don't enter buffering when MediaDecoder is not playing.
-  if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING) {
-    return;
-  }
-
-  // Don't enter buffering while prerolling so that the decoder has a chance to
-  // enqueue some decoded data before we give up and start buffering.
-  if (!IsPlaying()) {
-    return;
-  }
-
-  // No more data to download. No need to enter buffering.
-  if (!mResource->IsExpectingMoreData()) {
-    return;
-  }
-
-  bool shouldBuffer;
-  if (mReader->UseBufferingHeuristics()) {
-    shouldBuffer = HasLowDecodedData() && HasLowBufferedData();
-  } else {
-    MOZ_ASSERT(mReader->IsWaitForDataSupported());
-    shouldBuffer = (OutOfDecodedAudio() && mReader->IsWaitingAudioData()) ||
-                   (OutOfDecodedVideo() && mReader->IsWaitingVideoData());
-  }
-  if (shouldBuffer) {
-    SetState(DECODER_STATE_BUFFERING);
-  }
-}
-
 void MediaDecoderStateMachine::UpdatePlaybackPositionInternal(int64_t aTime)
 {
   MOZ_ASSERT(OnTaskQueue());
   SAMPLE_LOG("UpdatePlaybackPositionInternal(%lld)", aTime);
 
   mCurrentPosition = aTime;
   NS_ASSERTION(mCurrentPosition >= 0, "CurrentTime should be positive!");
   mObservedDuration = std::max(mObservedDuration.Ref(),
@@ -1914,64 +2100,16 @@ MediaDecoderStateMachine::ToStateStr(Sta
 
 const char*
 MediaDecoderStateMachine::ToStateStr()
 {
   MOZ_ASSERT(OnTaskQueue());
   return ToStateStr(mState);
 }
 
-void
-MediaDecoderStateMachine::SetState(State aState)
-{
-  MOZ_ASSERT(OnTaskQueue());
-  if (mState == aState) {
-    return;
-  }
-
-  DECODER_LOG("MDSM state: %s -> %s", ToStateStr(), ToStateStr(aState));
-
-  MOZ_ASSERT(mState == mStateObj->GetState());
-  mStateObj->Exit();
-  mState = aState;
-
-  switch (mState) {
-    case DECODER_STATE_DECODING_METADATA:
-      mStateObj = MakeUnique<DecodeMetadataState>(this);
-      break;
-    case DECODER_STATE_WAIT_FOR_CDM:
-      mStateObj = MakeUnique<WaitForCDMState>(this);
-      break;
-    case DECODER_STATE_DORMANT:
-      mStateObj = MakeUnique<DormantState>(this);
-      break;
-    case DECODER_STATE_DECODING_FIRSTFRAME:
-      mStateObj = MakeUnique<DecodingFirstFrameState>(this);
-      break;
-    case DECODER_STATE_DECODING:
-      mStateObj = MakeUnique<DecodingState>(this);
-      break;
-    case DECODER_STATE_BUFFERING:
-      mStateObj = MakeUnique<BufferingState>(this);
-      break;
-    case DECODER_STATE_COMPLETED:
-      mStateObj = MakeUnique<CompletedState>(this);
-      break;
-    case DECODER_STATE_SHUTDOWN:
-      mStateObj = MakeUnique<ShutdownState>(this);
-      break;
-    default:
-      MOZ_ASSERT_UNREACHABLE("Invalid state.");
-      break;
-  }
-
-  MOZ_ASSERT(mState == mStateObj->GetState());
-  mStateObj->Enter();
-}
-
 void MediaDecoderStateMachine::VolumeChanged()
 {
   MOZ_ASSERT(OnTaskQueue());
   mMediaSink->SetVolume(mVolume);
 }
 
 void MediaDecoderStateMachine::RecomputeDuration()
 {
@@ -2023,84 +2161,17 @@ MediaDecoderStateMachine::SetDormant(boo
   MOZ_ASSERT(OnTaskQueue());
   mStateObj->HandleDormant(aDormant);
 }
 
 RefPtr<ShutdownPromise>
 MediaDecoderStateMachine::Shutdown()
 {
   MOZ_ASSERT(OnTaskQueue());
-
-  SetState(DECODER_STATE_SHUTDOWN);
-
-  mDelayedScheduler.Reset();
-
-  mBufferedUpdateRequest.DisconnectIfExists();
-
-  mQueuedSeek.RejectIfExists(__func__);
-
-  // Shutdown happens will decode timer is active, we need to disconnect and
-  // dispose of the timer.
-  mVideoDecodeSuspendTimer.Reset();
-
-  mCDMProxyPromise.DisconnectIfExists();
-
-  if (IsPlaying()) {
-    StopPlayback();
-  }
-
-  // To break the cycle-reference between MediaDecoderReaderWrapper and MDSM.
-  CancelMediaDecoderReaderWrapperCallback();
-
-  Reset();
-
-  mMediaSink->Shutdown();
-
-  // Prevent dangling pointers by disconnecting the listeners.
-  mAudioQueueListener.Disconnect();
-  mVideoQueueListener.Disconnect();
-  mMetadataManager.Disconnect();
-
-  // Disconnect canonicals and mirrors before shutting down our task queue.
-  mBuffered.DisconnectIfConnected();
-  mIsReaderSuspended.DisconnectIfConnected();
-  mEstimatedDuration.DisconnectIfConnected();
-  mExplicitDuration.DisconnectIfConnected();
-  mPlayState.DisconnectIfConnected();
-  mNextPlayState.DisconnectIfConnected();
-  mVolume.DisconnectIfConnected();
-  mPreservesPitch.DisconnectIfConnected();
-  mSameOriginMedia.DisconnectIfConnected();
-  mMediaPrincipalHandle.DisconnectIfConnected();
-  mPlaybackBytesPerSecond.DisconnectIfConnected();
-  mPlaybackRateReliable.DisconnectIfConnected();
-  mDecoderPosition.DisconnectIfConnected();
-  mMediaSeekable.DisconnectIfConnected();
-  mMediaSeekableOnlyInBufferedRanges.DisconnectIfConnected();
-  mIsVisible.DisconnectIfConnected();
-
-  mDuration.DisconnectAll();
-  mIsShutdown.DisconnectAll();
-  mNextFrameStatus.DisconnectAll();
-  mCurrentPosition.DisconnectAll();
-  mPlaybackOffset.DisconnectAll();
-  mIsAudioDataAudible.DisconnectAll();
-
-  // Shut down the watch manager to stop further notifications.
-  mWatchManager.Shutdown();
-
-  DECODER_LOG("Shutdown started");
-
-  // Put a task in the decode queue to shutdown the reader.
-  // the queue to spin down.
-  return mReader->Shutdown()
-    ->Then(OwnerThread(), __func__, this,
-           &MediaDecoderStateMachine::FinishShutdown,
-           &MediaDecoderStateMachine::FinishShutdown)
-    ->CompletionPromise();
+  return mStateObj->HandleShutdown();
 }
 
 void MediaDecoderStateMachine::PlayStateChanged()
 {
   MOZ_ASSERT(OnTaskQueue());
 
   if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING) {
     mVideoDecodeSuspendTimer.Reset();
@@ -2234,17 +2305,17 @@ void MediaDecoderStateMachine::Visibilit
                                  type,
                                  MediaDecoderEventVisibility::Suppressed,
                                  true /* aVideoOnly */);
 
     RefPtr<MediaDecoder::SeekPromise> p = seekJob.mPromise.Ensure(__func__);
     p->Then(AbstractThread::MainThread(), __func__,
             [start, info, hw](){ ReportRecoveryTelemetry(start, info, hw); },
             [](){});
-    InitiateSeek(Move(seekJob));
+    mStateObj->SetState<SeekingState>(Move(seekJob));
   }
 }
 
 void MediaDecoderStateMachine::BufferedRangeUpdated()
 {
   MOZ_ASSERT(OnTaskQueue());
 
   // While playing an unseekable stream of unknown duration, mObservedDuration
@@ -2367,29 +2438,16 @@ MediaDecoderStateMachine::DispatchDecode
     DECODER_LOG("Dispatching SetIdle() audioQueue=%lld videoQueue=%lld",
                 GetDecodedAudioDuration(),
                 VideoQueue().Duration());
     mReader->SetIdle();
   }
 }
 
 void
-MediaDecoderStateMachine::InitiateSeek(SeekJob aSeekJob)
-{
-  MOZ_ASSERT(OnTaskQueue());
-
-  // Note we can't call SetState(DECODER_STATE_SEEKING) which does nothing
-  // if we are already in the SEEKING state.
-  mStateObj->Exit();
-  mState = DECODER_STATE_SEEKING;
-  mStateObj = MakeUnique<SeekingState>(this, Move(aSeekJob));
-  mStateObj->Enter();
-}
-
-void
 MediaDecoderStateMachine::DispatchAudioDecodeTaskIfNeeded()
 {
   MOZ_ASSERT(OnTaskQueue());
   if (!IsShutdown() && NeedToDecodeAudio()) {
     EnsureAudioDecodeTaskQueued();
   }
 }
 
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -342,18 +342,16 @@ private:
   // Resets all state related to decoding and playback, emptying all buffers
   // and aborting all pending operations on the decode task queue.
   void Reset(TrackSet aTracks = TrackSet(TrackInfo::kAudioTrack,
                                          TrackInfo::kVideoTrack));
 
 protected:
   virtual ~MediaDecoderStateMachine();
 
-  void SetState(State aState);
-
   void BufferedRangeUpdated();
 
   void ReaderSuspendedChanged();
 
   // Inserts MediaData* samples into their respective MediaQueues.
   // aSample must not be null.
 
   void Push(MediaData* aSample, MediaData::Type aSampleType);
@@ -453,36 +451,29 @@ protected:
   // The decoder monitor must be held.
   void StopPlayback();
 
   // If the conditions are right, sets internal state which causes playback
   // of media to begin or resume.
   // Must be called with the decode monitor held.
   void MaybeStartPlayback();
 
-  // Check to see if we don't have enough data to play up to the next frame.
-  // If we don't, switch to buffering mode.
-  void MaybeStartBuffering();
-
   // Moves the decoder into the shutdown state, and dispatches an error
   // event to the media element. This begins shutting down the decoder.
   // The decoder monitor must be held. This is only called on the
   // decode thread.
   void DecodeError(const MediaResult& aError);
 
   // Dispatches a LoadedMetadataEvent.
   // This is threadsafe and can be called on any thread.
   // The decoder monitor must be held.
   void EnqueueLoadedMetadataEvent();
 
   void EnqueueFirstFrameLoadedEvent();
 
-  // Clears any previous seeking state and initiates a new seek on the decoder.
-  void InitiateSeek(SeekJob aSeekJob);
-
   void DispatchAudioDecodeTaskIfNeeded();
   void DispatchVideoDecodeTaskIfNeeded();
 
   // Dispatch a task to decode audio if there is not.
   void EnsureAudioDecodeTaskQueued();
 
   // Dispatch a task to decode video if there is not.
   void EnsureVideoDecodeTaskQueued();
--- a/dom/media/MediaPrefs.h
+++ b/dom/media/MediaPrefs.h
@@ -107,16 +107,17 @@ private:
 #endif
 #ifdef MOZ_WIDGET_ANDROID
   DECL_MEDIA_PREF("media.android-media-codec.enabled",        PDMAndroidMediaCodecEnabled, bool, false);
   DECL_MEDIA_PREF("media.android-media-codec.preferred",      PDMAndroidMediaCodecPreferred, bool, false);
   DECL_MEDIA_PREF("media.android-remote-codec.enabled",       PDMAndroidRemoteCodecEnabled, bool, false);
 #endif
 #ifdef MOZ_FFMPEG
   DECL_MEDIA_PREF("media.ffmpeg.enabled",                     PDMFFmpegEnabled, bool, true);
+  DECL_MEDIA_PREF("media.libavcodec.allow-obsolete",          LibavcodecAllowObsolete, bool, false);
 #endif
 #ifdef MOZ_FFVPX
   DECL_MEDIA_PREF("media.ffvpx.enabled",                      PDMFFVPXEnabled, bool, true);
 #endif
 #ifdef XP_WIN
   DECL_MEDIA_PREF("media.wmf.enabled",                        PDMWMFEnabled, bool, true);
   DECL_MEDIA_PREF("media.decoder-doctor.wmf-disabled-is-failure", DecoderDoctorWMFDisabledIsFailure, bool, false);
   DECL_MEDIA_PREF("media.webm.intel_decoder.enabled",         PDMWMFIntelDecoderEnabled, bool, false);
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -1592,18 +1592,16 @@ RTCPeerConnectionStatic.prototype = {
 
   registerPeerConnectionLifecycleCallback: function(cb) {
     _globalPCList._registerPeerConnectionLifecycleCallback(this._winID, cb);
   },
 };
 
 function RTCDTMFSender(sender) {
   this._sender = sender;
-  this.duration = 100;
-  this.interToneGap = 70;
 }
 RTCDTMFSender.prototype = {
   classDescription: "RTCDTMFSender",
   classID: PC_DTMF_SENDER_CID,
   contractID: PC_DTMF_SENDER_CONTRACT,
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
 
   get toneBuffer() {
@@ -1621,20 +1619,18 @@ RTCDTMFSender.prototype = {
   insertDTMF: function(tones, duration, interToneGap) {
     this._sender._pc._checkClosed();
 
     if (this._sender._pc._senders.indexOf(this._sender.__DOM_IMPL__) == -1) {
       throw new this._sender._pc._win.DOMException("RTCRtpSender is stopped",
                                                    "InvalidStateError");
     }
 
-    this.duration = Math.max(40, Math.min(duration, 6000));
-
+    duration = Math.max(40, Math.min(duration, 6000));
     if (interToneGap < 30) interToneGap = 30;
-    this.interToneGap = interToneGap;
 
     tones = tones.toUpperCase();
 
     if (tones.match(/[^0-9A-D#*,]/)) {
       throw new this._sender._pc._win.DOMException("Invalid DTMF characters",
                                                    "InvalidCharacterError");
     }
 
--- a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp
@@ -1,14 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "FFmpegLibWrapper.h"
 #include "FFmpegLog.h"
+#include "MediaPrefs.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/Types.h"
 #include "prlink.h"
 
 #define AV_LOG_DEBUG    48
 
 namespace mozilla
 {
@@ -18,39 +19,52 @@ FFmpegLibWrapper::FFmpegLibWrapper()
   PodZero(this);
 }
 
 FFmpegLibWrapper::~FFmpegLibWrapper()
 {
   Unlink();
 }
 
-bool
+FFmpegLibWrapper::LinkResult
 FFmpegLibWrapper::Link()
 {
   if (!mAVCodecLib || !mAVUtilLib) {
     Unlink();
-    return false;
+    return LinkResult::NoProvidedLib;
   }
 
   avcodec_version =
     (decltype(avcodec_version))PR_FindSymbol(mAVCodecLib, "avcodec_version");
   if (!avcodec_version) {
     Unlink();
-    return false;
+    return LinkResult::NoAVCodecVersion;
   }
   uint32_t version = avcodec_version();
-  mVersion = (version >> 16) & 0xff;
-  uint32_t micro = version & 0xff;
-  if (mVersion == 57 && micro < 100) {
-    // a micro version >= 100 indicates that it's FFmpeg (as opposed to LibAV).
-    // Due to current AVCodecContext binary incompatibility we can only
-    // support FFmpeg 57 at this stage.
-    Unlink();
-    return false;
+  uint32_t macro = (version >> 16) & 0xFFu;
+  mVersion = static_cast<int>(macro);
+  uint32_t micro = version & 0xFFu;
+  // A micro version >= 100 indicates that it's FFmpeg (as opposed to LibAV).
+  bool isFFMpeg = micro >= 100;
+  if (!isFFMpeg) {
+    if (macro == 57) {
+      // Due to current AVCodecContext binary incompatibility we can only
+      // support FFmpeg 57 at this stage.
+      Unlink();
+      return LinkResult::CannotUseLibAV57;
+    }
+#ifdef MOZ_FFMPEG
+    if (version < (54u << 16 | 35u << 8 | 1u)
+        && !MediaPrefs::LibavcodecAllowObsolete()) {
+      // Refuse any libavcodec version prior to 54.35.1.
+      // (Unless media.libavcodec.allow-obsolete==true)
+      Unlink();
+      return LinkResult::BlockedOldLibAVVersion;
+    }
+#endif
   }
 
   enum {
     AV_FUNC_AVUTIL_MASK = 1 << 8,
     AV_FUNC_53 = 1 << 0,
     AV_FUNC_54 = 1 << 1,
     AV_FUNC_55 = 1 << 2,
     AV_FUNC_56 = 1 << 3,
@@ -59,17 +73,17 @@ FFmpegLibWrapper::Link()
     AV_FUNC_AVUTIL_54 = AV_FUNC_54 | AV_FUNC_AVUTIL_MASK,
     AV_FUNC_AVUTIL_55 = AV_FUNC_55 | AV_FUNC_AVUTIL_MASK,
     AV_FUNC_AVUTIL_56 = AV_FUNC_56 | AV_FUNC_AVUTIL_MASK,
     AV_FUNC_AVUTIL_57 = AV_FUNC_57 | AV_FUNC_AVUTIL_MASK,
     AV_FUNC_AVCODEC_ALL = AV_FUNC_53 | AV_FUNC_54 | AV_FUNC_55 | AV_FUNC_56 | AV_FUNC_57,
     AV_FUNC_AVUTIL_ALL = AV_FUNC_AVCODEC_ALL | AV_FUNC_AVUTIL_MASK
   };
 
-  switch (mVersion) {
+  switch (macro) {
     case 53:
       version = AV_FUNC_53;
       break;
     case 54:
       version = AV_FUNC_54;
       break;
     case 55:
       version = AV_FUNC_55;
@@ -78,33 +92,40 @@ FFmpegLibWrapper::Link()
       version = AV_FUNC_56;
       break;
     case 57:
       version = AV_FUNC_57;
       break;
     default:
       FFMPEG_LOG("Unknown avcodec version");
       Unlink();
-      return false;
+      return isFFMpeg
+             ? ((macro > 57)
+                ? LinkResult::UnknownFutureFFMpegVersion
+                : LinkResult::UnknownOlderFFMpegVersion)
+             // All LibAV versions<54.35.1 are blocked, therefore we must be
+             // dealing with a later one.
+             : LinkResult::UnknownFutureLibAVVersion;
   }
 
 #define AV_FUNC_OPTION(func, ver)                                              \
   if ((ver) & version) {                                                       \
     if (!(func = (decltype(func))PR_FindSymbol(((ver) & AV_FUNC_AVUTIL_MASK) ? mAVUtilLib : mAVCodecLib, #func))) { \
       FFMPEG_LOG("Couldn't load function " # func);                            \
     }                                                                          \
   } else {                                                                     \
     func = (decltype(func))nullptr;                                            \
   }
 
 #define AV_FUNC(func, ver)                                                     \
   AV_FUNC_OPTION(func, ver)                                                    \
   if ((ver) & version && !func) {                                              \
     Unlink();                                                                  \
-    return false;                                                              \
+    return isFFMpeg ? LinkResult::MissingFFMpegFunction                        \
+                    : LinkResult::MissingLibAVFunction;                        \
   }
 
   AV_FUNC(av_lockmgr_register, AV_FUNC_AVCODEC_ALL)
   AV_FUNC(avcodec_alloc_context3, AV_FUNC_AVCODEC_ALL)
   AV_FUNC(avcodec_close, AV_FUNC_AVCODEC_ALL)
   AV_FUNC(avcodec_decode_audio4, AV_FUNC_AVCODEC_ALL)
   AV_FUNC(avcodec_decode_video2, AV_FUNC_AVCODEC_ALL)
   AV_FUNC(avcodec_find_decoder, AV_FUNC_AVCODEC_ALL)
@@ -128,17 +149,17 @@ FFmpegLibWrapper::Link()
 #undef AV_FUNC
 #undef AV_FUNC_OPTION
 
   avcodec_register_all();
 #ifdef DEBUG
   av_log_set_level(AV_LOG_DEBUG);
 #endif
 
-  return true;
+  return LinkResult::Success;
 }
 
 void
 FFmpegLibWrapper::Unlink()
 {
   if (av_lockmgr_register) {
     // Registering a null lockmgr cause the destruction of libav* global mutexes
     // as the default lockmgr that allocated them will be deregistered.
--- a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h
+++ b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h
@@ -18,20 +18,33 @@ struct PRLibrary;
 namespace mozilla
 {
 
 struct FFmpegLibWrapper
 {
   FFmpegLibWrapper();
   ~FFmpegLibWrapper();
 
-  // Attempt to resolve all symbols. Return true of successful.
+  enum class LinkResult
+  {
+    Success,
+    NoProvidedLib,
+    NoAVCodecVersion,
+    CannotUseLibAV57,
+    BlockedOldLibAVVersion,
+    UnknownFutureLibAVVersion,
+    UnknownFutureFFMpegVersion,
+    UnknownOlderFFMpegVersion,
+    MissingFFMpegFunction,
+    MissingLibAVFunction,
+  };
+  // Examine mAVCodecLib and mAVUtilLib, and attempt to resolve all symbols.
   // Upon failure, the entire object will be reset and any attached libraries
   // will be unlinked.
-  bool Link();
+  LinkResult Link();
 
   // Reset the wrapper and unlink all attached libraries.
   void Unlink();
 
   // indicate the version of libavcodec linked to.
   // 0 indicates that the function wasn't initialized with Link().
   int mVersion;
 
--- a/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.cpp
@@ -10,16 +10,17 @@
 #include "FFmpegLog.h"
 #include "prlink.h"
 
 namespace mozilla
 {
 
 FFmpegRuntimeLinker::LinkStatus FFmpegRuntimeLinker::sLinkStatus =
   LinkStatus_INIT;
+const char* FFmpegRuntimeLinker::sLinkStatusLibraryName = "";
 
 template <int V> class FFmpegDecoderModule
 {
 public:
   static already_AddRefed<PlatformDecoderModule> Create(FFmpegLibWrapper*);
 };
 
 static FFmpegLibWrapper sLibAV;
@@ -40,42 +41,88 @@ static const char* sLibs[] = {
   "libavcodec.so.54",
   "libavcodec.so.53",
 #endif
 };
 
 /* static */ bool
 FFmpegRuntimeLinker::Init()
 {
-  if (sLinkStatus) {
+  if (sLinkStatus != LinkStatus_INIT) {
     return sLinkStatus == LinkStatus_SUCCEEDED;
   }
 
+  // While going through all possible libs, this status will be updated with a
+  // more precise error if possible.
+  sLinkStatus = LinkStatus_NOT_FOUND;
+
   for (size_t i = 0; i < ArrayLength(sLibs); i++) {
     const char* lib = sLibs[i];
     PRLibSpec lspec;
     lspec.type = PR_LibSpec_Pathname;
     lspec.value.pathname = lib;
     sLibAV.mAVCodecLib = PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL);
     if (sLibAV.mAVCodecLib) {
       sLibAV.mAVUtilLib = sLibAV.mAVCodecLib;
-      if (sLibAV.Link()) {
-        sLinkStatus = LinkStatus_SUCCEEDED;
-        return true;
+      switch (sLibAV.Link()) {
+        case FFmpegLibWrapper::LinkResult::Success:
+          sLinkStatus = LinkStatus_SUCCEEDED;
+          sLinkStatusLibraryName = lib;
+          return true;
+        case FFmpegLibWrapper::LinkResult::NoProvidedLib:
+          MOZ_ASSERT_UNREACHABLE("Incorrectly-setup sLibAV");
+          break;
+        case FFmpegLibWrapper::LinkResult::NoAVCodecVersion:
+          if (sLinkStatus > LinkStatus_INVALID_CANDIDATE) {
+            sLinkStatus = LinkStatus_INVALID_CANDIDATE;
+            sLinkStatusLibraryName = lib;
+          }
+          break;
+        case FFmpegLibWrapper::LinkResult::CannotUseLibAV57:
+          if (sLinkStatus > LinkStatus_UNUSABLE_LIBAV57) {
+            sLinkStatus = LinkStatus_UNUSABLE_LIBAV57;
+            sLinkStatusLibraryName = lib;
+          }
+          break;
+        case FFmpegLibWrapper::LinkResult::BlockedOldLibAVVersion:
+          if (sLinkStatus > LinkStatus_OBSOLETE_LIBAV) {
+            sLinkStatus = LinkStatus_OBSOLETE_LIBAV;
+            sLinkStatusLibraryName = lib;
+          }
+          break;
+        case FFmpegLibWrapper::LinkResult::UnknownFutureLibAVVersion:
+        case FFmpegLibWrapper::LinkResult::MissingLibAVFunction:
+          if (sLinkStatus > LinkStatus_INVALID_LIBAV_CANDIDATE) {
+            sLinkStatus = LinkStatus_INVALID_LIBAV_CANDIDATE;
+            sLinkStatusLibraryName = lib;
+          }
+          break;
+        case FFmpegLibWrapper::LinkResult::UnknownFutureFFMpegVersion:
+        case FFmpegLibWrapper::LinkResult::MissingFFMpegFunction:
+          if (sLinkStatus > LinkStatus_INVALID_FFMPEG_CANDIDATE) {
+            sLinkStatus = LinkStatus_INVALID_FFMPEG_CANDIDATE;
+            sLinkStatusLibraryName = lib;
+          }
+          break;
+        case FFmpegLibWrapper::LinkResult::UnknownOlderFFMpegVersion:
+          if (sLinkStatus > LinkStatus_OBSOLETE_FFMPEG) {
+            sLinkStatus = LinkStatus_OBSOLETE_FFMPEG;
+            sLinkStatusLibraryName = lib;
+          }
+          break;
       }
     }
   }
 
   FFMPEG_LOG("H264/AAC codecs unsupported without [");
   for (size_t i = 0; i < ArrayLength(sLibs); i++) {
     FFMPEG_LOG("%s %s", i ? "," : " ", sLibs[i]);
   }
   FFMPEG_LOG(" ]\n");
 
-  sLinkStatus = LinkStatus_FAILED;
   return false;
 }
 
 /* static */ already_AddRefed<PlatformDecoderModule>
 FFmpegRuntimeLinker::CreateDecoderModule()
 {
   if (!Init()) {
     return nullptr;
@@ -87,9 +134,36 @@ FFmpegRuntimeLinker::CreateDecoderModule
     case 55:
     case 56: module = FFmpegDecoderModule<55>::Create(&sLibAV); break;
     case 57: module = FFmpegDecoderModule<57>::Create(&sLibAV); break;
     default: module = nullptr;
   }
   return module.forget();
 }
 
+/* static */ const char*
+FFmpegRuntimeLinker::LinkStatusString()
+{
+  switch (sLinkStatus) {
+    case LinkStatus_INIT:
+      return "Libavcodec not initialized yet";
+    case LinkStatus_SUCCEEDED:
+      return "Libavcodec linking succeeded";
+    case LinkStatus_INVALID_FFMPEG_CANDIDATE:
+      return "Invalid FFMpeg libavcodec candidate";
+    case LinkStatus_UNUSABLE_LIBAV57:
+      return "Unusable LibAV's libavcodec 57";
+    case LinkStatus_INVALID_LIBAV_CANDIDATE:
+      return "Invalid LibAV libavcodec candidate";
+    case LinkStatus_OBSOLETE_FFMPEG:
+      return "Obsolete FFMpeg libavcodec candidate";
+    case LinkStatus_OBSOLETE_LIBAV:
+      return "Obsolete LibAV libavcodec candidate";
+    case LinkStatus_INVALID_CANDIDATE:
+      return "Invalid libavcodec candidate";
+    case LinkStatus_NOT_FOUND:
+      return "Libavcodec not found";
+  }
+  MOZ_ASSERT_UNREACHABLE("Unknown sLinkStatus value");
+  return "?";
+}
+
 } // namespace mozilla
--- a/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.h
+++ b/dom/media/platforms/ffmpeg/FFmpegRuntimeLinker.h
@@ -12,20 +12,35 @@
 namespace mozilla
 {
 
 class FFmpegRuntimeLinker
 {
 public:
   static bool Init();
   static already_AddRefed<PlatformDecoderModule> CreateDecoderModule();
+  enum LinkStatus
+  {
+    LinkStatus_INIT = 0,  // Never been linked.
+    LinkStatus_SUCCEEDED, // Found a usable library.
+    // The following error statuses are sorted from most to least preferred
+    // (i.e., if more than one happens, the top one is chosen.)
+    LinkStatus_INVALID_FFMPEG_CANDIDATE, // Found ffmpeg with unexpected contents.
+    LinkStatus_UNUSABLE_LIBAV57, // Found LibAV 57, which we cannot use.
+    LinkStatus_INVALID_LIBAV_CANDIDATE, // Found libav with unexpected contents.
+    LinkStatus_OBSOLETE_FFMPEG,
+    LinkStatus_OBSOLETE_LIBAV,
+    LinkStatus_INVALID_CANDIDATE, // Found some lib with unexpected contents.
+    LinkStatus_NOT_FOUND, // Haven't found any library with an expected name.
+  };
+  static LinkStatus LinkStatusCode() { return sLinkStatus; }
+  static const char* LinkStatusString();
+  // Library name to which the sLinkStatus applies, or "" if not applicable.
+  static const char* LinkStatusLibraryName() { return sLinkStatusLibraryName; }
 
 private:
-  static enum LinkStatus {
-    LinkStatus_INIT = 0,
-    LinkStatus_FAILED,
-    LinkStatus_SUCCEEDED
-  } sLinkStatus;
+  static LinkStatus sLinkStatus;
+  static const char* sLinkStatusLibraryName;
 };
 
 }
 
 #endif // __FFmpegRuntimeLinker_h__
--- a/dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp
+++ b/dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp
@@ -89,17 +89,17 @@ FFVPXRuntimeLinker::Init()
   }
   sFFVPXLib.mAVUtilLib = MozAVLink(libname);
   PR_FreeLibraryName(libname);
   libname = PR_GetLibraryName(rootPath.get(), "mozavcodec");
   if (libname) {
     sFFVPXLib.mAVCodecLib = MozAVLink(libname);
     PR_FreeLibraryName(libname);
   }
-  if (sFFVPXLib.Link()) {
+  if (sFFVPXLib.Link() == FFmpegLibWrapper::LinkResult::Success) {
     sLinkStatus = LinkStatus_SUCCEEDED;
     return true;
   }
   return false;
 }
 
 /* static */ already_AddRefed<PlatformDecoderModule>
 FFVPXRuntimeLinker::CreateDecoderModule()
--- a/dom/media/tests/mochitest/test_peerConnection_insertDTMF.html
+++ b/dom/media/tests/mochitest/test_peerConnection_insertDTMF.html
@@ -14,26 +14,21 @@ createHTML({
 
 function insertdtmftest(pc) {
   ok(pc.getSenders().length > 0, "have senders");
   var sender = pc.getSenders()[0];
   ok(sender.dtmf, "sender has dtmf object");
 
   ok(sender.dtmf.toneBuffer === "", "sender should start with empty tonebuffer");
 
+  // These will trigger assertions on debug builds if we do not enforce the
+  // specified minimums and maximums for duration and interToneGap.
   sender.dtmf.insertDTMF("A", 10);
-  is(sender.dtmf.duration, 40, "minimum duration is 40");
   sender.dtmf.insertDTMF("A", 10000);
-  is(sender.dtmf.duration, 6000, "maximum duration is 6000");
   sender.dtmf.insertDTMF("A", 70, 10);
-  is(sender.dtmf.duration, 70, "default duration is 70");
-  is(sender.dtmf.interToneGap, 30, "minimum interToneGap is 30");
-  sender.dtmf.insertDTMF("", 100, 40);
-  is(sender.dtmf.duration, 100, "duration is 70");
-  is(sender.dtmf.interToneGap, 40, "interToneGap is 40");
 
   var threw = false;
   try {
     sender.dtmf.insertDTMF("bad tones");
   } catch (ex) {
     threw = true;
     is(ex.code, DOMException.INVALID_CHARACTER_ERR, "Expected InvalidCharacterError");
   }
--- a/dom/u2f/NSSU2FTokenRemote.h
+++ b/dom/u2f/NSSU2FTokenRemote.h
@@ -7,17 +7,17 @@
 #ifndef NSSU2FTokenRemote_h
 #define NSSU2FTokenRemote_h
 
 #include "nsIU2FToken.h"
 
 class NSSU2FTokenRemote : public nsIU2FToken
 {
 public:
-  NS_DECL_ISUPPORTS
+  NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIU2FTOKEN
 
   NSSU2FTokenRemote();
 
 private:
   virtual ~NSSU2FTokenRemote();
 };
 
--- a/dom/u2f/U2F.cpp
+++ b/dom/u2f/U2F.cpp
@@ -1,69 +1,59 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "hasht.h"
+#include "mozilla/dom/CallbackFunction.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/CryptoBuffer.h"
 #include "mozilla/dom/NSSU2FTokenRemote.h"
 #include "mozilla/dom/U2F.h"
-#include "mozilla/dom/U2FBinding.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/ReentrantMonitor.h"
 #include "nsContentUtils.h"
 #include "nsINSSU2FToken.h"
 #include "nsNetCID.h"
 #include "nsNSSComponent.h"
 #include "nsURLParsers.h"
+#include "nsXPCOMCIDInternal.h"
 #include "pk11pub.h"
 
 using mozilla::dom::ContentChild;
 
 namespace mozilla {
 namespace dom {
 
 #define PREF_U2F_SOFTTOKEN_ENABLED "security.webauth.u2f_enable_softtoken"
 #define PREF_U2F_USBTOKEN_ENABLED  "security.webauth.u2f_enable_usbtoken"
 
+NS_NAMED_LITERAL_CSTRING(kPoolName, "WebAuth_U2F-IO");
 NS_NAMED_LITERAL_STRING(kFinishEnrollment, "navigator.id.finishEnrollment");
 NS_NAMED_LITERAL_STRING(kGetAssertion, "navigator.id.getAssertion");
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(U2F)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(U2F)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(U2F)
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(U2F, mParent)
 
 static mozilla::LazyLogModule gWebauthLog("webauth_u2f");
 
-template <class CB, class Rsp>
-void
-SendError(CB* aCallback, ErrorCode aErrorCode)
-{
-  Rsp response;
-  response.mErrorCode.Construct(static_cast<uint32_t>(aErrorCode));
-
-  ErrorResult rv;
-  aCallback->Call(response, rv);
-  NS_WARNING_ASSERTION(!rv.Failed(), "callback failed");
-  // Useful exceptions already got reported.
-  rv.SuppressException();
-}
-
 static nsresult
 AssembleClientData(const nsAString& aOrigin, const nsAString& aTyp,
                    const nsAString& aChallenge, CryptoBuffer& aClientData)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   ClientData clientDataObject;
   clientDataObject.mTyp.Construct(aTyp); // "Typ" from the U2F specification
   clientDataObject.mChallenge.Construct(aChallenge);
   clientDataObject.mOrigin.Construct(aOrigin);
 
   nsAutoString json;
   if (NS_WARN_IF(!clientDataObject.ToJSON(json))) {
     return NS_ERROR_FAILURE;
@@ -71,496 +61,885 @@ AssembleClientData(const nsAString& aOri
 
   if (NS_WARN_IF(!aClientData.Assign(NS_ConvertUTF16toUTF8(json)))) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   return NS_OK;
 }
 
-U2FTask::U2FTask(const nsAString& aOrigin, const nsAString& aAppId)
+U2FStatus::U2FStatus()
+  : mCount(0)
+  , mIsStopped(false)
+  , mReentrantMonitor("U2FStatus")
+{}
+
+U2FStatus::~U2FStatus()
+{}
+
+void
+U2FStatus::WaitGroupAdd()
+{
+  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+
+  mCount += 1;
+  MOZ_LOG(gWebauthLog, LogLevel::Debug,
+          ("U2FStatus::WaitGroupAdd, now %d", mCount));
+}
+
+void
+U2FStatus::WaitGroupDone()
+{
+  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+
+  MOZ_ASSERT(mCount > 0);
+  mCount -= 1;
+  MOZ_LOG(gWebauthLog, LogLevel::Debug,
+          ("U2FStatus::WaitGroupDone, now %d", mCount));
+  if (mCount == 0) {
+    mReentrantMonitor.NotifyAll();
+  }
+}
+
+void
+U2FStatus::WaitGroupWait()
+{
+  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+  MOZ_LOG(gWebauthLog, LogLevel::Debug,
+          ("U2FStatus::WaitGroupWait, now %d", mCount));
+
+  while (mCount > 0) {
+    mReentrantMonitor.Wait();
+  }
+
+  MOZ_ASSERT(mCount == 0);
+  MOZ_LOG(gWebauthLog, LogLevel::Debug,
+          ("U2FStatus::Wait completed, now count=%d stopped=%d", mCount,
+           mIsStopped));
+}
+
+void
+U2FStatus::Stop(const ErrorCode aErrorCode)
+{
+  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+  MOZ_ASSERT(!mIsStopped);
+  mIsStopped = true;
+  mErrorCode = aErrorCode;
+
+  // TODO: Let WaitGroupWait exit early upon a Stop. Requires consideration of
+  // threads calling IsStopped() followed by WaitGroupDone(). Right now, Stop
+  // prompts work tasks to end early, but it could also prompt an immediate
+  // "Go ahead" to the thread waiting at WaitGroupWait.
+}
+
+void
+U2FStatus::Stop(const ErrorCode aErrorCode, const nsAString& aResponse)
+{
+  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+  Stop(aErrorCode);
+  mResponse = aResponse;
+}
+
+bool
+U2FStatus::IsStopped()
+{
+  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+  return mIsStopped;
+}
+
+ErrorCode
+U2FStatus::GetErrorCode()
+{
+  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+  MOZ_ASSERT(mIsStopped);
+  return mErrorCode;
+}
+
+nsString
+U2FStatus::GetResponse()
+{
+  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+  MOZ_ASSERT(mIsStopped);
+  return mResponse;
+}
+
+U2FTask::U2FTask(const nsAString& aOrigin, const nsAString& aAppId,
+                 const Authenticator& aAuthenticator)
   : mOrigin(aOrigin)
   , mAppId(aAppId)
+  , mAuthenticator(aAuthenticator)
 {}
 
 U2FTask::~U2FTask()
 {}
 
+RefPtr<U2FPromise>
+U2FTask::Execute()
+{
+  RefPtr<U2FPromise> p = mPromise.Ensure(__func__);
+
+  nsCOMPtr<nsIRunnable> r(this);
+
+  // TODO: Use a thread pool here, but we have to solve the PContentChild issues
+  // of being in a worker thread.
+  AbstractThread::MainThread()->Dispatch(r.forget());
+  return p;
+}
+
+U2FPrepTask::U2FPrepTask(const Authenticator& aAuthenticator)
+  : mAuthenticator(aAuthenticator)
+{}
+
+U2FPrepTask::~U2FPrepTask()
+{}
+
+RefPtr<U2FPrepPromise>
+U2FPrepTask::Execute()
+{
+  RefPtr<U2FPrepPromise> p = mPromise.Ensure(__func__);
+
+  nsCOMPtr<nsIRunnable> r(this);
+
+  // TODO: Use a thread pool here, but we have to solve the PContentChild issues
+  // of being in a worker thread.
+  AbstractThread::MainThread()->Dispatch(r.forget());
+  return p;
+}
+
+U2FIsRegisteredTask::U2FIsRegisteredTask(const Authenticator& aAuthenticator,
+                                         const LocalRegisteredKey& aRegisteredKey)
+  : U2FPrepTask(aAuthenticator)
+  , mRegisteredKey(aRegisteredKey)
+{}
+
+U2FIsRegisteredTask::~U2FIsRegisteredTask()
+{}
+
+NS_IMETHODIMP
+U2FIsRegisteredTask::Run()
+{
+  bool isCompatible = false;
+  nsresult rv = mAuthenticator->IsCompatibleVersion(mRegisteredKey.mVersion,
+                                                    &isCompatible);
+  if (NS_FAILED(rv)) {
+    mPromise.Reject(ErrorCode::OTHER_ERROR, __func__);
+    return NS_ERROR_FAILURE;
+  }
+
+  if (!isCompatible) {
+    mPromise.Reject(ErrorCode::BAD_REQUEST, __func__);
+    return NS_ERROR_FAILURE;
+  }
+
+  // Decode the key handle
+  CryptoBuffer keyHandle;
+  rv = keyHandle.FromJwkBase64(mRegisteredKey.mKeyHandle);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    mPromise.Reject(ErrorCode::BAD_REQUEST, __func__);
+    return NS_ERROR_FAILURE;
+  }
+
+  // We ignore mTransports, as it is intended to be used for sorting the
+  // available devices by preference, but is not an exclusion factor.
+
+  bool isRegistered = false;
+  rv = mAuthenticator->IsRegistered(keyHandle.Elements(), keyHandle.Length(),
+                                    &isRegistered);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    mPromise.Reject(ErrorCode::OTHER_ERROR, __func__);
+    return NS_ERROR_FAILURE;
+  }
+
+  if (isRegistered) {
+    mPromise.Reject(ErrorCode::DEVICE_INELIGIBLE, __func__);
+    return NS_OK;
+  }
+
+  mPromise.Resolve(mAuthenticator, __func__);
+  return NS_OK;
+}
+
 U2FRegisterTask::U2FRegisterTask(const nsAString& aOrigin,
                                  const nsAString& aAppId,
-                                 const Sequence<RegisterRequest>& aRegisterRequests,
-                                 const Sequence<RegisteredKey>& aRegisteredKeys,
-                                 U2FRegisterCallback* aCallback,
-                                 const Sequence<Authenticator>& aAuthenticators)
-  : U2FTask(aOrigin, aAppId)
-  , mRegisterRequests(aRegisterRequests)
-  , mRegisteredKeys(aRegisteredKeys)
-  , mCallback(aCallback)
-  , mAuthenticators(aAuthenticators)
+                                 const Authenticator& aAuthenticator,
+                                 const CryptoBuffer& aAppParam,
+                                 const CryptoBuffer& aChallengeParam,
+                                 const LocalRegisterRequest& aRegisterEntry)
+  : U2FTask(aOrigin, aAppId, aAuthenticator)
+  , mAppParam(aAppParam)
+  , mChallengeParam(aChallengeParam)
+  , mRegisterEntry(aRegisterEntry)
 {}
 
 U2FRegisterTask::~U2FRegisterTask()
+{}
+
+NS_IMETHODIMP
+U2FRegisterTask::Run()
+{
+  bool isCompatible = false;
+  nsresult rv = mAuthenticator->IsCompatibleVersion(mRegisterEntry.mVersion,
+                                                    &isCompatible);
+  if (NS_FAILED(rv)) {
+    mPromise.Reject(ErrorCode::OTHER_ERROR, __func__);
+    return NS_ERROR_FAILURE;
+  }
+
+  if (!isCompatible) {
+    mPromise.Reject(ErrorCode::BAD_REQUEST, __func__);
+    return NS_ERROR_FAILURE;
+  }
+
+  uint8_t* buffer;
+  uint32_t bufferlen;
+  rv = mAuthenticator->Register(mAppParam.Elements(),
+                                mAppParam.Length(),
+                                mChallengeParam.Elements(),
+                                mChallengeParam.Length(),
+                                &buffer, &bufferlen);
+  if (NS_WARN_IF(NS_FAILED(rv)))  {
+    mPromise.Reject(ErrorCode::OTHER_ERROR, __func__);
+    return NS_ERROR_FAILURE;
+  }
+
+  MOZ_ASSERT(buffer);
+  CryptoBuffer regData;
+  if (NS_WARN_IF(!regData.Assign(buffer, bufferlen))) {
+    free(buffer);
+    mPromise.Reject(ErrorCode::OTHER_ERROR, __func__);
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  free(buffer);
+
+  // Assemble a response object to return
+  nsString clientDataBase64;
+  nsString registrationDataBase64;
+  nsresult rvClientData = mRegisterEntry.mClientData.ToJwkBase64(clientDataBase64);
+  nsresult rvRegistrationData = regData.ToJwkBase64(registrationDataBase64);
+
+  if (NS_WARN_IF(NS_FAILED(rvClientData)) ||
+      NS_WARN_IF(NS_FAILED(rvRegistrationData))) {
+    mPromise.Reject(ErrorCode::OTHER_ERROR, __func__);
+    return NS_ERROR_FAILURE;
+  }
+
+  RegisterResponse response;
+  response.mClientData.Construct(clientDataBase64);
+  response.mRegistrationData.Construct(registrationDataBase64);
+  response.mErrorCode.Construct(static_cast<uint32_t>(ErrorCode::OK));
+
+  nsString responseStr;
+  if (NS_WARN_IF(!response.ToJSON(responseStr))) {
+    return NS_ERROR_FAILURE;
+  }
+  mPromise.Resolve(responseStr, __func__);
+  return NS_OK;
+}
+
+U2FSignTask::U2FSignTask(const nsAString& aOrigin,
+                         const nsAString& aAppId,
+                         const nsAString& aVersion,
+                         const Authenticator& aAuthenticator,
+                         const CryptoBuffer& aAppParam,
+                         const CryptoBuffer& aChallengeParam,
+                         const CryptoBuffer& aClientData,
+                         const CryptoBuffer& aKeyHandle)
+  : U2FTask(aOrigin, aAppId, aAuthenticator)
+  , mVersion(aVersion)
+  , mAppParam(aAppParam)
+  , mChallengeParam(aChallengeParam)
+  , mClientData(aClientData)
+  , mKeyHandle(aKeyHandle)
+{}
+
+U2FSignTask::~U2FSignTask()
+{}
+
+NS_IMETHODIMP
+U2FSignTask::Run()
+{
+  bool isCompatible = false;
+  nsresult rv = mAuthenticator->IsCompatibleVersion(mVersion, &isCompatible);
+  if (NS_FAILED(rv)) {
+    mPromise.Reject(ErrorCode::OTHER_ERROR, __func__);
+    return NS_ERROR_FAILURE;
+  }
+
+  if (!isCompatible) {
+    mPromise.Reject(ErrorCode::BAD_REQUEST, __func__);
+    return NS_ERROR_FAILURE;
+  }
+
+  bool isRegistered = false;
+  rv = mAuthenticator->IsRegistered(mKeyHandle.Elements(), mKeyHandle.Length(),
+                                    &isRegistered);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    mPromise.Reject(ErrorCode::OTHER_ERROR, __func__);
+    return NS_ERROR_FAILURE;
+  }
+
+  if (!isRegistered) {
+    mPromise.Reject(ErrorCode::DEVICE_INELIGIBLE, __func__);
+    return NS_OK;
+  }
+
+  CryptoBuffer signatureData;
+  uint8_t* buffer;
+  uint32_t bufferlen;
+  rv = mAuthenticator->Sign(mAppParam.Elements(), mAppParam.Length(),
+                            mChallengeParam.Elements(), mChallengeParam.Length(),
+                            mKeyHandle.Elements(), mKeyHandle.Length(),
+                            &buffer, &bufferlen);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    mPromise.Reject(ErrorCode::OTHER_ERROR, __func__);
+    return NS_ERROR_FAILURE;
+  }
+
+  MOZ_ASSERT(buffer);
+  if (NS_WARN_IF(!signatureData.Assign(buffer, bufferlen))) {
+    free(buffer);
+    mPromise.Reject(ErrorCode::OTHER_ERROR, __func__);
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  free(buffer);
+
+  // Assemble a response object to return
+  nsString clientDataBase64;
+  nsString signatureDataBase64;
+  nsString keyHandleBase64;
+  nsresult rvClientData = mClientData.ToJwkBase64(clientDataBase64);
+  nsresult rvSignatureData = signatureData.ToJwkBase64(signatureDataBase64);
+  nsresult rvKeyHandle = mKeyHandle.ToJwkBase64(keyHandleBase64);
+  if (NS_WARN_IF(NS_FAILED(rvClientData)) ||
+      NS_WARN_IF(NS_FAILED(rvSignatureData) ||
+      NS_WARN_IF(NS_FAILED(rvKeyHandle)))) {
+    mPromise.Reject(ErrorCode::OTHER_ERROR, __func__);
+    return NS_ERROR_FAILURE;
+  }
+
+  SignResponse response;
+  response.mKeyHandle.Construct(keyHandleBase64);
+  response.mClientData.Construct(clientDataBase64);
+  response.mSignatureData.Construct(signatureDataBase64);
+  response.mErrorCode.Construct(static_cast<uint32_t>(ErrorCode::OK));
+
+  nsString responseStr;
+  if (NS_WARN_IF(!response.ToJSON(responseStr))) {
+    return NS_ERROR_FAILURE;
+  }
+  mPromise.Resolve(responseStr, __func__);
+  return NS_OK;
+}
+
+U2FRunnable::U2FRunnable(const nsAString& aOrigin, const nsAString& aAppId)
+  : mOrigin(aOrigin)
+  , mAppId(aAppId)
+{}
+
+U2FRunnable::~U2FRunnable()
+{}
+
+// EvaluateAppIDAndRunTask determines whether the supplied FIDO AppID is valid for
+// the current FacetID, e.g., the current origin.
+// See https://fidoalliance.org/specs/fido-u2f-v1.0-nfc-bt-amendment-20150514/fido-appid-and-facets.html
+// for a description of the algorithm.
+ErrorCode
+U2FRunnable::EvaluateAppID()
+{
+  nsCOMPtr<nsIURLParser> urlParser =
+      do_GetService(NS_STDURLPARSER_CONTRACTID);
+
+  MOZ_ASSERT(urlParser);
+
+  uint32_t facetSchemePos;
+  int32_t facetSchemeLen;
+  uint32_t facetAuthPos;
+  int32_t facetAuthLen;
+  // Facet is the specification's way of referring to the web origin.
+  nsAutoCString facetUrl = NS_ConvertUTF16toUTF8(mOrigin);
+  nsresult rv = urlParser->ParseURL(facetUrl.get(), mOrigin.Length(),
+                                    &facetSchemePos, &facetSchemeLen,
+                                    &facetAuthPos, &facetAuthLen,
+                                    nullptr, nullptr);      // ignore path
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return ErrorCode::BAD_REQUEST;
+  }
+
+  nsAutoCString facetScheme(Substring(facetUrl, facetSchemePos, facetSchemeLen));
+  nsAutoCString facetAuth(Substring(facetUrl, facetAuthPos, facetAuthLen));
+
+  uint32_t appIdSchemePos;
+  int32_t appIdSchemeLen;
+  uint32_t appIdAuthPos;
+  int32_t appIdAuthLen;
+  // AppID is user-supplied. It's quite possible for this parse to fail.
+  nsAutoCString appIdUrl = NS_ConvertUTF16toUTF8(mAppId);
+  rv = urlParser->ParseURL(appIdUrl.get(), mAppId.Length(),
+                           &appIdSchemePos, &appIdSchemeLen,
+                           &appIdAuthPos, &appIdAuthLen,
+                           nullptr, nullptr);      // ignore path
+  if (NS_FAILED(rv)) {
+    return ErrorCode::BAD_REQUEST;
+  }
+
+  nsAutoCString appIdScheme(Substring(appIdUrl, appIdSchemePos, appIdSchemeLen));
+  nsAutoCString appIdAuth(Substring(appIdUrl, appIdAuthPos, appIdAuthLen));
+
+  // If the facetId (origin) is not HTTPS, reject
+  if (!facetScheme.LowerCaseEqualsLiteral("https")) {
+    return ErrorCode::BAD_REQUEST;
+  }
+
+  // If the appId is empty or null, overwrite it with the facetId and accept
+  if (mAppId.IsEmpty() || mAppId.EqualsLiteral("null")) {
+    mAppId.Assign(mOrigin);
+    return ErrorCode::OK;
+  }
+
+  // if the appId URL is not HTTPS, reject.
+  if (!appIdScheme.LowerCaseEqualsLiteral("https")) {
+    return ErrorCode::BAD_REQUEST;
+  }
+
+  // If the facetId and the appId auths match, accept
+  if (facetAuth == appIdAuth) {
+    return ErrorCode::OK;
+  }
+
+  // TODO(Bug 1244959) Implement the remaining algorithm.
+  return ErrorCode::BAD_REQUEST;
+}
+
+U2FRegisterRunnable::U2FRegisterRunnable(const nsAString& aOrigin,
+                                         const nsAString& aAppId,
+                                         const Sequence<RegisterRequest>& aRegisterRequests,
+                                         const Sequence<RegisteredKey>& aRegisteredKeys,
+                                         const Sequence<Authenticator>& aAuthenticators,
+                                         U2FRegisterCallback* aCallback)
+  : U2FRunnable(aOrigin, aAppId)
+  , mAuthenticators(aAuthenticators)
+  // U2FRegisterCallback does not support threadsafe refcounting, and must be
+  // used and destroyed on main.
+  , mCallback(new nsMainThreadPtrHolder<U2FRegisterCallback>(aCallback))
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // The WebIDL dictionary types RegisterRequest and RegisteredKey cannot
+  // be copied to this thread, so store them serialized.
+  for (size_t i = 0; i < aRegisterRequests.Length(); ++i) {
+    RegisterRequest req(aRegisterRequests[i]);
+
+    // Check for required attributes
+    if (!req.mChallenge.WasPassed() || !req.mVersion.WasPassed()) {
+      continue;
+    }
+
+    LocalRegisterRequest localReq;
+    localReq.mVersion = req.mVersion.Value();
+    localReq.mChallenge = req.mChallenge.Value();
+
+    nsresult rv = AssembleClientData(mOrigin, kFinishEnrollment,
+                                     localReq.mChallenge, localReq.mClientData);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      continue;
+    }
+
+    mRegisterRequests.AppendElement(localReq);
+  }
+
+  for (size_t i = 0; i < aRegisteredKeys.Length(); ++i) {
+    RegisteredKey key(aRegisteredKeys[i]);
+
+    // Check for required attributes
+    if (!key.mVersion.WasPassed() || !key.mKeyHandle.WasPassed()) {
+      continue;
+    }
+
+    LocalRegisteredKey localKey;
+    localKey.mVersion = key.mVersion.Value();
+    localKey.mKeyHandle = key.mKeyHandle.Value();
+    if (key.mAppId.WasPassed()) {
+      localKey.mAppId.SetValue(key.mAppId.Value());
+    }
+
+    mRegisteredKeys.AppendElement(localKey);
+  }
+}
+
+U2FRegisterRunnable::~U2FRegisterRunnable()
 {
   nsNSSShutDownPreventionLock locker;
 
   if (isAlreadyShutDown()) {
     return;
   }
   shutdown(ShutdownCalledFrom::Object);
 }
 
 void
-U2FRegisterTask::ReturnError(ErrorCode aCode)
+U2FRegisterRunnable::SetTimeout(const int32_t aTimeoutMillis)
+{
+  opt_mTimeoutSeconds.SetValue(aTimeoutMillis);
+}
+
+void
+U2FRegisterRunnable::SendResponse(const RegisterResponse& aResponse)
 {
-  SendError<U2FRegisterCallback, RegisterResponse>(mCallback.get(), aCode);
+  MOZ_ASSERT(NS_IsMainThread());
+
+  ErrorResult rv;
+  mCallback->Call(aResponse, rv);
+  NS_WARNING_ASSERTION(!rv.Failed(), "callback failed");
+  // Useful exceptions already got reported.
+  rv.SuppressException();
 }
 
 NS_IMETHODIMP
-U2FRegisterTask::Run()
+U2FRegisterRunnable::Run()
 {
+  MOZ_ASSERT(!NS_IsMainThread());
+
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown()) {
-    ReturnError(ErrorCode::OTHER_ERROR);
     return NS_ERROR_FAILURE;
   }
 
-  for (size_t i = 0; i < mRegisteredKeys.Length(); ++i) {
-    RegisteredKey request(mRegisteredKeys[i]);
+  // Create a Status object to keep track of when we're done
+  RefPtr<U2FStatus> status = new U2FStatus();
 
-    // Check for required attributes
-    if (!(request.mKeyHandle.WasPassed() &&
-          request.mVersion.WasPassed())) {
-      continue;
-    }
+  // Evaluate the AppID
+  ErrorCode appIdResult = EvaluateAppID();
+  if (appIdResult != ErrorCode::OK) {
+    status->Stop(appIdResult);
+  }
 
-    // Do not permit an individual RegisteredKey to assert a different AppID
-    if (request.mAppId.WasPassed() && mAppId != request.mAppId.Value()) {
-      continue;
-    }
-
-    // Decode the key handle
-    CryptoBuffer keyHandle;
-    nsresult rv = keyHandle.FromJwkBase64(request.mKeyHandle.Value());
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      ReturnError(ErrorCode::BAD_REQUEST);
-      return NS_ERROR_FAILURE;
+  // First, we must determine if any of the RegisteredKeys are already
+  // registered, e.g., in the whitelist.
+  for (LocalRegisteredKey key: mRegisteredKeys) {
+    nsTArray<RefPtr<U2FPrepPromise>> prepPromiseList;
+    for (size_t a = 0; a < mAuthenticators.Length(); ++a) {
+      Authenticator token(mAuthenticators[a]);
+      RefPtr<U2FIsRegisteredTask> compTask = new U2FIsRegisteredTask(token, key);
+      prepPromiseList.AppendElement(compTask->Execute());
     }
 
-    // We ignore mTransports, as it is intended to be used for sorting the
-    // available devices by preference, but is not an exclusion factor.
-
-    bool isCompatible = false;
-    bool isRegistered = false;
+    // Treat each call to Promise::All as a work unit, as it completes together
+    status->WaitGroupAdd();
 
-    // Determine if the provided keyHandle is registered at any device. If so,
-    // then we'll return DEVICE_INELIGIBLE to signify we're already registered.
-    for (auto token : mAuthenticators) {
-      rv = token->IsCompatibleVersion(request.mVersion.Value(), &isCompatible);
-      if (NS_FAILED(rv)) {
-        ReturnError(ErrorCode::OTHER_ERROR);
-        return NS_ERROR_FAILURE;
-      }
-      if (!isCompatible) {
-        continue;
-      }
+    U2FPrepPromise::All(AbstractThread::MainThread(), prepPromiseList)
+    ->Then(AbstractThread::MainThread(), __func__,
+      [status] (const nsTArray<Authenticator>& aTokens) {
+        MOZ_LOG(gWebauthLog, LogLevel::Debug,
+                ("ALL: None of the RegisteredKeys were recognized. n=%d",
+                 aTokens.Length()));
 
-      rv = token->IsRegistered(keyHandle.Elements(), keyHandle.Length(),
-                               &isRegistered);
-      if (NS_FAILED(rv)) {
-        ReturnError(ErrorCode::OTHER_ERROR);
-        return NS_ERROR_FAILURE;
-      }
-
-      if (isCompatible && isRegistered) {
-        ReturnError(ErrorCode::DEVICE_INELIGIBLE);
-        return NS_OK;
-      }
-    }
+        status->WaitGroupDone();
+      },
+      [status] (ErrorCode aErrorCode) {
+        status->Stop(aErrorCode);
+        status->WaitGroupDone();
+    });
   }
 
-  // Search the requests in order for the first some token can fulfill
-  for (size_t i = 0; i < mRegisterRequests.Length(); ++i) {
-    RegisterRequest request(mRegisterRequests[i]);
+  // Wait for all the IsRegistered tasks to complete
+  status->WaitGroupWait();
+
+  // Check to see whether we're supposed to stop, because one of the keys was
+  // recognized.
+  if (status->IsStopped()) {
+    status->WaitGroupAdd();
+    AbstractThread::MainThread()->Dispatch(NS_NewRunnableFunction(
+      [status, this] () {
+        RegisterResponse response;
+        response.mErrorCode.Construct(
+            static_cast<uint32_t>(status->GetErrorCode()));
+        SendResponse(response);
+        status->WaitGroupDone();
+      }
+    ));
+
+    // Don't exit until the main thread runnable completes
+    status->WaitGroupWait();
+    return NS_OK;
+  }
 
-    // Check for equired attributes
-    if (!(request.mVersion.WasPassed() &&
-        request.mChallenge.WasPassed())) {
+  // Since we're continuing, we hash the AppID into the AppParam
+  nsCString cAppId = NS_ConvertUTF16toUTF8(mAppId);
+  CryptoBuffer appParam;
+  if (!appParam.SetLength(SHA256_LENGTH, fallible)) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  // Note: This could use nsICryptoHash to avoid having to interact with NSS
+  // directly.
+  SECStatus srv;
+  srv = PK11_HashBuf(SEC_OID_SHA256, appParam.Elements(),
+                     reinterpret_cast<const uint8_t*>(cAppId.BeginReading()),
+                     cAppId.Length());
+  if (srv != SECSuccess) {
+    return NS_ERROR_FAILURE;
+  }
+
+  // Now proceed to actually register a new key.
+  for (LocalRegisterRequest req : mRegisterRequests) {
+    // Hash the ClientData into the ChallengeParam
+    CryptoBuffer challengeParam;
+    if (!challengeParam.SetLength(SHA256_LENGTH, fallible)) {
       continue;
     }
 
-    CryptoBuffer clientData;
-    nsresult rv = AssembleClientData(mOrigin, kFinishEnrollment,
-                                     request.mChallenge.Value(),
-                                     clientData);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      ReturnError(ErrorCode::OTHER_ERROR);
-      return NS_ERROR_FAILURE;
-    }
-
-    // Hash the AppID and the ClientData into the AppParam and ChallengeParam
-    SECStatus srv;
-    nsCString cAppId = NS_ConvertUTF16toUTF8(mAppId);
-    CryptoBuffer appParam;
-    CryptoBuffer challengeParam;
-    if (!appParam.SetLength(SHA256_LENGTH, fallible) ||
-        !challengeParam.SetLength(SHA256_LENGTH, fallible)) {
-      ReturnError(ErrorCode::OTHER_ERROR);
-      return NS_ERROR_FAILURE;
-    }
-
-    srv = PK11_HashBuf(SEC_OID_SHA256, appParam.Elements(),
-                       reinterpret_cast<const uint8_t*>(cAppId.BeginReading()),
-                       cAppId.Length());
-    if (srv != SECSuccess) {
-      ReturnError(ErrorCode::OTHER_ERROR);
-      return NS_ERROR_FAILURE;
-    }
-
     srv = PK11_HashBuf(SEC_OID_SHA256, challengeParam.Elements(),
-                       clientData.Elements(), clientData.Length());
+                       req.mClientData.Elements(), req.mClientData.Length());
     if (srv != SECSuccess) {
-      ReturnError(ErrorCode::OTHER_ERROR);
-      return NS_ERROR_FAILURE;
-    }
-
-    // Get the registration data from the token
-    CryptoBuffer regData;
-    bool registerSuccess = false;
-    bool isCompatible = false;
-
-    for (auto token : mAuthenticators) {
-      rv = token->IsCompatibleVersion(request.mVersion.Value(), &isCompatible);
-      if (NS_FAILED(rv)) {
-        ReturnError(ErrorCode::OTHER_ERROR);
-        return NS_ERROR_FAILURE;
-      }
-
-      if (isCompatible) {
-        uint8_t* buffer;
-        uint32_t bufferlen;
-        nsresult rv;
-        rv = token->Register(appParam.Elements(), appParam.Length(),
-                             challengeParam.Elements(), challengeParam.Length(),
-                             &buffer, &bufferlen);
-        if (NS_FAILED(rv)) {
-          ReturnError(ErrorCode::OTHER_ERROR);
-          return NS_ERROR_FAILURE;
-        }
-
-        MOZ_ASSERT(buffer);
-        if (NS_WARN_IF(!regData.Assign(buffer, bufferlen))) {
-          free(buffer);
-          ReturnError(ErrorCode::OTHER_ERROR);
-          return NS_ERROR_OUT_OF_MEMORY;
-        }
-
-        free(buffer);
-        registerSuccess = true;
-        break;
-      }
-    }
-
-    if (!registerSuccess) {
-      // Try another request
       continue;
     }
 
-    // Assemble a response object to return
-    nsString clientDataBase64, registrationDataBase64;
-    nsresult rvClientData =
-      clientData.ToJwkBase64(clientDataBase64);
-    nsresult rvRegistrationData =
-      regData.ToJwkBase64(registrationDataBase64);
-    if (NS_WARN_IF(NS_FAILED(rvClientData)) ||
-        NS_WARN_IF(NS_FAILED(rvRegistrationData))) {
-      ReturnError(ErrorCode::OTHER_ERROR);
-      return NS_ERROR_FAILURE;
+    for (size_t a = 0; a < mAuthenticators.Length(); ++a) {
+      Authenticator token(mAuthenticators[a]);
+      RefPtr<U2FRegisterTask> registerTask = new U2FRegisterTask(mOrigin, mAppId,
+                                                                 token, appParam,
+                                                                 challengeParam,
+                                                                 req);
+      status->WaitGroupAdd();
+
+      registerTask->Execute()->Then(AbstractThread::MainThread(), __func__,
+        [status, this] (nsString aResponse) {
+          if (status->IsStopped()) {
+            return;
+          }
+          status->Stop(ErrorCode::OK, aResponse);
+          status->WaitGroupDone();
+        },
+        [status, this] (ErrorCode aErrorCode) {
+          if (status->IsStopped()) {
+            return;
+          }
+          status->Stop(aErrorCode);
+          status->WaitGroupDone();
+     });
+    }
+  }
+
+  // Wait until the first key is successfuly generated
+  status->WaitGroupWait();
+
+  // If none of the tasks completed, then nothing could satisfy.
+  if (!status->IsStopped()) {
+    status->Stop(ErrorCode::BAD_REQUEST);
+  }
+
+  // Transmit back to the JS engine from the Main Thread
+  status->WaitGroupAdd();
+  AbstractThread::MainThread()->Dispatch(NS_NewRunnableFunction(
+    [status, this] () {
+      RegisterResponse response;
+      if (status->GetErrorCode() == ErrorCode::OK) {
+        response.Init(status->GetResponse());
+      } else {
+        response.mErrorCode.Construct(
+            static_cast<uint32_t>(status->GetErrorCode()));
+      }
+      SendResponse(response);
+      status->WaitGroupDone();
+    }
+  ));
+
+  // TODO: Add timeouts, Bug 1301793
+  status->WaitGroupWait();
+  return NS_OK;
+}
+
+U2FSignRunnable::U2FSignRunnable(const nsAString& aOrigin,
+                                 const nsAString& aAppId,
+                                 const nsAString& aChallenge,
+                                 const Sequence<RegisteredKey>& aRegisteredKeys,
+                                 const Sequence<Authenticator>& aAuthenticators,
+                                 U2FSignCallback* aCallback)
+  : U2FRunnable(aOrigin, aAppId)
+  , mAuthenticators(aAuthenticators)
+  // U2FSignCallback does not support threadsafe refcounting, and must be used
+  // and destroyed on main.
+  , mCallback(new nsMainThreadPtrHolder<U2FSignCallback>(aCallback))
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // Convert WebIDL objects to generic structs to pass between threads
+  for (size_t i = 0; i < aRegisteredKeys.Length(); ++i) {
+    RegisteredKey key(aRegisteredKeys[i]);
+
+    // Check for required attributes
+    if (!key.mVersion.WasPassed() || !key.mKeyHandle.WasPassed()) {
+      continue;
     }
 
-    RegisterResponse response;
-    response.mClientData.Construct(clientDataBase64);
-    response.mRegistrationData.Construct(registrationDataBase64);
-    response.mErrorCode.Construct(static_cast<uint32_t>(ErrorCode::OK));
+    LocalRegisteredKey localKey;
+    localKey.mVersion = key.mVersion.Value();
+    localKey.mKeyHandle = key.mKeyHandle.Value();
+    if (key.mAppId.WasPassed()) {
+      localKey.mAppId.SetValue(key.mAppId.Value());
+    }
 
-    ErrorResult result;
-    mCallback->Call(response, result);
-    NS_WARNING_ASSERTION(!result.Failed(), "callback failed");
-    // Useful exceptions already got reported.
-    result.SuppressException();
-    return NS_OK;
+    mRegisteredKeys.AppendElement(localKey);
   }
 
-  // Nothing could satisfy
-  ReturnError(ErrorCode::BAD_REQUEST);
-  return NS_ERROR_FAILURE;
+  // Assemble a clientData object
+  nsresult rv = AssembleClientData(aOrigin, kGetAssertion, aChallenge,
+                                   mClientData);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    MOZ_LOG(gWebauthLog, LogLevel::Warning,
+            ("Failed to AssembleClientData for the U2FSignRunnable."));
+    return;
+  }
 }
 
-U2FSignTask::U2FSignTask(const nsAString& aOrigin,
-                         const nsAString& aAppId,
-                         const nsAString& aChallenge,
-                         const Sequence<RegisteredKey>& aRegisteredKeys,
-                         U2FSignCallback* aCallback,
-                         const Sequence<Authenticator>& aAuthenticators)
-  : U2FTask(aOrigin, aAppId)
-  , mChallenge(aChallenge)
-  , mRegisteredKeys(aRegisteredKeys)
-  , mCallback(aCallback)
-  , mAuthenticators(aAuthenticators)
-{}
-
-U2FSignTask::~U2FSignTask()
+U2FSignRunnable::~U2FSignRunnable()
 {
   nsNSSShutDownPreventionLock locker;
+
   if (isAlreadyShutDown()) {
     return;
   }
   shutdown(ShutdownCalledFrom::Object);
 }
 
 void
-U2FSignTask::ReturnError(ErrorCode aCode)
+U2FSignRunnable::SetTimeout(const int32_t aTimeoutMillis)
+{
+  opt_mTimeoutSeconds.SetValue(aTimeoutMillis);
+}
+
+void
+U2FSignRunnable::SendResponse(const SignResponse& aResponse)
 {
-  SendError<U2FSignCallback, SignResponse>(mCallback.get(), aCode);
+  MOZ_ASSERT(NS_IsMainThread());
+
+  ErrorResult rv;
+  mCallback->Call(aResponse, rv);
+  NS_WARNING_ASSERTION(!rv.Failed(), "callback failed");
+  // Useful exceptions already got reported.
+  rv.SuppressException();
 }
 
 NS_IMETHODIMP
-U2FSignTask::Run()
+U2FSignRunnable::Run()
 {
+  MOZ_ASSERT(!NS_IsMainThread());
+
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown()) {
-    ReturnError(ErrorCode::OTHER_ERROR);
     return NS_ERROR_FAILURE;
   }
 
-  // Search the requests for one a token can fulfill
-  for (size_t i = 0; i < mRegisteredKeys.Length(); i += 1) {
-    RegisteredKey request(mRegisteredKeys[i]);
+  // Create a Status object to keep track of when we're done
+  RefPtr<U2FStatus> status = new U2FStatus();
 
-    // Check for required attributes
-    if (!(request.mVersion.WasPassed() &&
-          request.mKeyHandle.WasPassed())) {
-      continue;
-    }
+  // Evaluate the AppID
+  ErrorCode appIdResult = EvaluateAppID();
+  if (appIdResult != ErrorCode::OK) {
+    status->Stop(appIdResult);
+  }
 
-    // Do not permit an individual RegisteredKey to assert a different AppID
-    if (request.mAppId.WasPassed() && mAppId != request.mAppId.Value()) {
-      continue;
-    }
-
-    // Assemble a clientData object
-    CryptoBuffer clientData;
-    nsresult rv = AssembleClientData(mOrigin, kGetAssertion, mChallenge,
-                                     clientData);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      ReturnError(ErrorCode::OTHER_ERROR);
-      return NS_ERROR_FAILURE;
-    }
+  // Hash the AppID and the ClientData into the AppParam and ChallengeParam
+  nsCString cAppId = NS_ConvertUTF16toUTF8(mAppId);
+  CryptoBuffer appParam;
+  CryptoBuffer challengeParam;
+  if (!appParam.SetLength(SHA256_LENGTH, fallible) ||
+      !challengeParam.SetLength(SHA256_LENGTH, fallible)) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
 
-    // Hash the AppID and the ClientData into the AppParam and ChallengeParam
-    SECStatus srv;
-    nsCString cAppId = NS_ConvertUTF16toUTF8(mAppId);
-    CryptoBuffer appParam;
-    CryptoBuffer challengeParam;
-    if (!appParam.SetLength(SHA256_LENGTH, fallible) ||
-        !challengeParam.SetLength(SHA256_LENGTH, fallible)) {
-      ReturnError(ErrorCode::OTHER_ERROR);
-      return NS_ERROR_FAILURE;
-    }
+  SECStatus srv;
+  srv = PK11_HashBuf(SEC_OID_SHA256, appParam.Elements(),
+                     reinterpret_cast<const uint8_t*>(cAppId.BeginReading()),
+                     cAppId.Length());
+  if (srv != SECSuccess) {
+    return NS_ERROR_FAILURE;
+  }
 
-    srv = PK11_HashBuf(SEC_OID_SHA256, appParam.Elements(),
-                       reinterpret_cast<const uint8_t*>(cAppId.BeginReading()),
-                       cAppId.Length());
-    if (srv != SECSuccess) {
-      ReturnError(ErrorCode::OTHER_ERROR);
-      return NS_ERROR_FAILURE;
-    }
+  srv = PK11_HashBuf(SEC_OID_SHA256, challengeParam.Elements(),
+                     mClientData.Elements(), mClientData.Length());
+  if (srv != SECSuccess) {
+    return NS_ERROR_FAILURE;
+  }
 
-    srv = PK11_HashBuf(SEC_OID_SHA256, challengeParam.Elements(),
-                       clientData.Elements(), clientData.Length());
-    if (srv != SECSuccess) {
-      ReturnError(ErrorCode::OTHER_ERROR);
-      return NS_ERROR_FAILURE;
+  // Search the signing requests for one a token can fulfill
+  for (LocalRegisteredKey key : mRegisteredKeys) {
+    // Do not permit an individual RegisteredKey to assert a different AppID
+    if (!key.mAppId.IsNull() && mAppId != key.mAppId.Value()) {
+      continue;
     }
 
     // Decode the key handle
     CryptoBuffer keyHandle;
-    rv = keyHandle.FromJwkBase64(request.mKeyHandle.Value());
+    nsresult rv = keyHandle.FromJwkBase64(key.mKeyHandle);
     if (NS_WARN_IF(NS_FAILED(rv))) {
-      ReturnError(ErrorCode::OTHER_ERROR);
-      return NS_ERROR_FAILURE;
+      continue;
     }
 
-    // Get the signature from the token
-    CryptoBuffer signatureData;
-    bool signSuccess = false;
-
     // We ignore mTransports, as it is intended to be used for sorting the
     // available devices by preference, but is not an exclusion factor.
 
-    for (size_t a = 0; a < mAuthenticators.Length() && !signSuccess; ++a) {
+    for (size_t a = 0; a < mAuthenticators.Length() ; ++a) {
       Authenticator token(mAuthenticators[a]);
-      bool isCompatible = false;
-      bool isRegistered = false;
-
-      rv = token->IsCompatibleVersion(request.mVersion.Value(), &isCompatible);
-      if (NS_FAILED(rv)) {
-        ReturnError(ErrorCode::OTHER_ERROR);
-        return NS_ERROR_FAILURE;
-      }
-      if (!isCompatible) {
-        continue;
-      }
 
-      rv = token->IsRegistered(keyHandle.Elements(), keyHandle.Length(),
-                               &isRegistered);
-      if (NS_FAILED(rv)) {
-        ReturnError(ErrorCode::OTHER_ERROR);
-        return NS_ERROR_FAILURE;
-      }
-
-      if (isCompatible && isRegistered) {
-        uint8_t* buffer;
-        uint32_t bufferlen;
-        nsresult rv = token->Sign(appParam.Elements(), appParam.Length(),
-                                  challengeParam.Elements(), challengeParam.Length(),
-                                  keyHandle.Elements(), keyHandle.Length(),
-                                  &buffer, &bufferlen);
-        if (NS_FAILED(rv)) {
-          ReturnError(ErrorCode::OTHER_ERROR);
-          return NS_ERROR_FAILURE;
-        }
+      RefPtr<U2FSignTask> signTask = new U2FSignTask(mOrigin, mAppId,
+                                                     key.mVersion, token,
+                                                     appParam, challengeParam,
+                                                     mClientData, keyHandle);
+      status->WaitGroupAdd();
 
-        MOZ_ASSERT(buffer);
-        if (NS_WARN_IF(!signatureData.Assign(buffer, bufferlen))) {
-          free(buffer);
-          ReturnError(ErrorCode::OTHER_ERROR);
-          return NS_ERROR_OUT_OF_MEMORY;
-        }
-
-        free(buffer);
-        signSuccess = true;
-      }
-    }
-
-    if (!signSuccess) {
-      // Try another request
-      continue;
+      signTask->Execute()->Then(AbstractThread::MainThread(), __func__,
+        [status, this] (nsString aResponse) {
+          if (status->IsStopped()) {
+            return;
+          }
+          status->Stop(ErrorCode::OK, aResponse);
+          status->WaitGroupDone();
+        },
+        [status, this] (ErrorCode aErrorCode) {
+          if (status->IsStopped()) {
+            return;
+          }
+          status->Stop(aErrorCode);
+          status->WaitGroupDone();
+      });
     }
-
-    // Assemble a response object to return
-    nsString clientDataBase64, signatureDataBase64;
-    nsresult rvClientData =
-      clientData.ToJwkBase64(clientDataBase64);
-    nsresult rvSignatureData =
-      signatureData.ToJwkBase64(signatureDataBase64);
-    if (NS_WARN_IF(NS_FAILED(rvClientData)) ||
-        NS_WARN_IF(NS_FAILED(rvSignatureData))) {
-      ReturnError(ErrorCode::OTHER_ERROR);
-      return NS_ERROR_FAILURE;
-    }
-    SignResponse response;
-    response.mKeyHandle.Construct(request.mKeyHandle.Value());
-    response.mClientData.Construct(clientDataBase64);
-    response.mSignatureData.Construct(signatureDataBase64);
-    response.mErrorCode.Construct(static_cast<uint32_t>(ErrorCode::OK));
-
-    ErrorResult result;
-    mCallback->Call(response, result);
-    NS_WARNING_ASSERTION(!result.Failed(), "callback failed");
-    // Useful exceptions already got reported.
-    result.SuppressException();
-    return NS_OK;
   }
 
-  // Nothing could satisfy
-  ReturnError(ErrorCode::DEVICE_INELIGIBLE);
-  return NS_ERROR_FAILURE;
-}
-
-// EvaluateAppIDAndRunTask determines whether the supplied FIDO AppID is valid for
-// the current FacetID, e.g., the current origin.
-// See https://fidoalliance.org/specs/fido-u2f-v1.0-nfc-bt-amendment-20150514/fido-appid-and-facets.html
-// for a description of the algorithm.
-static void
-EvaluateAppIDAndRunTask(U2FTask* aTask)
-{
-  MOZ_ASSERT(aTask);
+  // Wait for the authenticators to finish
+  status->WaitGroupWait();
 
-  nsCOMPtr<nsIURLParser> urlParser =
-      do_GetService(NS_STDURLPARSER_CONTRACTID);
-
-  MOZ_ASSERT(urlParser);
-
-  uint32_t facetSchemePos;
-  int32_t facetSchemeLen;
-  uint32_t facetAuthPos;
-  int32_t facetAuthLen;
-  // Facet is the specification's way of referring to the web origin.
-  nsAutoCString facetUrl = NS_ConvertUTF16toUTF8(aTask->mOrigin);
-  nsresult rv = urlParser->ParseURL(facetUrl.get(), aTask->mOrigin.Length(),
-                                    &facetSchemePos, &facetSchemeLen,
-                                    &facetAuthPos, &facetAuthLen,
-                                    nullptr, nullptr);      // ignore path
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    aTask->ReturnError(ErrorCode::BAD_REQUEST);
-    return;
+  // If none of the tasks completed, then nothing could satisfy.
+  if (!status->IsStopped()) {
+    status->Stop(ErrorCode::DEVICE_INELIGIBLE);
   }
 
-  nsAutoCString facetScheme(Substring(facetUrl, facetSchemePos, facetSchemeLen));
-  nsAutoCString facetAuth(Substring(facetUrl, facetAuthPos, facetAuthLen));
-
-  uint32_t appIdSchemePos;
-  int32_t appIdSchemeLen;
-  uint32_t appIdAuthPos;
-  int32_t appIdAuthLen;
-  // AppID is user-supplied. It's quite possible for this parse to fail.
-  nsAutoCString appIdUrl = NS_ConvertUTF16toUTF8(aTask->mAppId);
-  rv = urlParser->ParseURL(appIdUrl.get(), aTask->mAppId.Length(),
-                           &appIdSchemePos, &appIdSchemeLen,
-                           &appIdAuthPos, &appIdAuthLen,
-                           nullptr, nullptr);      // ignore path
-  if (NS_FAILED(rv)) {
-    aTask->ReturnError(ErrorCode::BAD_REQUEST);
-    return;
-  }
-
-  nsAutoCString appIdScheme(Substring(appIdUrl, appIdSchemePos, appIdSchemeLen));
-  nsAutoCString appIdAuth(Substring(appIdUrl, appIdAuthPos, appIdAuthLen));
+  // Transmit back to the JS engine from the Main Thread
+  status->WaitGroupAdd();
+  AbstractThread::MainThread()->Dispatch(NS_NewRunnableFunction(
+    [status, this] () {
+      SignResponse response;
+      if (status->GetErrorCode() == ErrorCode::OK) {
+        response.Init(status->GetResponse());
+      } else {
+        response.mErrorCode.Construct(
+          static_cast<uint32_t>(status->GetErrorCode()));
+      }
+      SendResponse(response);
+      status->WaitGroupDone();
+    }
+  ));
 
-  // If the facetId (origin) is not HTTPS, reject
-  if (!facetScheme.LowerCaseEqualsLiteral("https")) {
-    aTask->ReturnError(ErrorCode::BAD_REQUEST);
-    return;
-  }
-
-  // If the appId is empty or null, overwrite it with the facetId and accept
-  if (aTask->mAppId.IsEmpty() || aTask->mAppId.EqualsLiteral("null")) {
-    aTask->mAppId.Assign(aTask->mOrigin);
-    aTask->Run();
-    return;
-  }
-
-  // if the appId URL is not HTTPS, reject.
-  if (!appIdScheme.LowerCaseEqualsLiteral("https")) {
-    aTask->ReturnError(ErrorCode::BAD_REQUEST);
-    return;
-  }
-
-  // If the facetId and the appId auths match, accept
-  if (facetAuth == appIdAuth) {
-    aTask->Run();
-    return;
-  }
-
-  // TODO(Bug 1244959) Implement the remaining algorithm.
-  aTask->ReturnError(ErrorCode::BAD_REQUEST);
-  return;
+  // TODO: Add timeouts, Bug 1301793
+  status->WaitGroupWait();
+  return NS_OK;
 }
 
 U2F::U2F()
+  : mInitialized(false)
 {}
 
 U2F::~U2F()
 {
   nsNSSShutDownPreventionLock locker;
 
   if (isAlreadyShutDown()) {
     return;
@@ -572,16 +951,17 @@ U2F::~U2F()
 U2F::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return U2FBinding::Wrap(aCx, this, aGivenProto);
 }
 
 void
 U2F::Init(nsPIDOMWindowInner* aParent, ErrorResult& aRv)
 {
+  MOZ_ASSERT(!mInitialized);
   MOZ_ASSERT(!mParent);
   mParent = do_QueryInterface(aParent);
   MOZ_ASSERT(mParent);
 
   nsCOMPtr<nsIDocument> doc = mParent->GetDoc();
   MOZ_ASSERT(doc);
 
   nsIPrincipal* principal = doc->NodePrincipal();
@@ -591,79 +971,84 @@ U2F::Init(nsPIDOMWindowInner* aParent, E
   }
 
   if (NS_WARN_IF(mOrigin.IsEmpty())) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
   if (!EnsureNSSInitializedChromeOrContent()) {
-    MOZ_LOG(gWebauthLog, LogLevel::Debug, ("Failed to get NSS context for U2F"));
+    MOZ_LOG(gWebauthLog, LogLevel::Debug,
+            ("Failed to get NSS context for U2F"));
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
+
+  // This only functions in e10s mode
+  if (XRE_IsParentProcess()) {
+    MOZ_LOG(gWebauthLog, LogLevel::Debug,
+            ("Is non-e10s Process, U2F not available"));
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
   // Monolithically insert compatible nsIU2FToken objects into mAuthenticators.
   // In future functionality expansions, this is where we could add a dynamic
   // add/remove interface.
   if (Preferences::GetBool(PREF_U2F_SOFTTOKEN_ENABLED)) {
-    if (!XRE_IsParentProcess()) {
-      MOZ_LOG(gWebauthLog, LogLevel::Debug,
-        ("Is e10s Process, getting remote U2F soft token"));
-
-      if (!mAuthenticators.AppendElement(new NSSU2FTokenRemote(),
-                                         mozilla::fallible)) {
-        aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
-        return;
-      }
-    } else {
-       MOZ_LOG(gWebauthLog, LogLevel::Debug,
-        ("Is non-e10s Process, getting direct U2F soft token"));
-
-      nsCOMPtr<nsINSSU2FToken> softToken =
-        do_GetService(NS_NSSU2FTOKEN_CONTRACTID);
-      if (NS_WARN_IF(!softToken)) {
-        aRv.Throw(NS_ERROR_FAILURE);
-        return;
-      }
-
-      if (!mAuthenticators.AppendElement(softToken, mozilla::fallible)) {
-        aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
-        return;
-      }
+    if (!mAuthenticators.AppendElement(new NSSU2FTokenRemote(),
+                                       mozilla::fallible)) {
+      aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+      return;
     }
   }
+
+  mInitialized = true;
 }
 
 void
 U2F::Register(const nsAString& aAppId,
               const Sequence<RegisterRequest>& aRegisterRequests,
               const Sequence<RegisteredKey>& aRegisteredKeys,
               U2FRegisterCallback& aCallback,
               const Optional<Nullable<int32_t>>& opt_aTimeoutSeconds,
               ErrorResult& aRv)
 {
-  RefPtr<U2FRegisterTask> registerTask = new U2FRegisterTask(mOrigin, aAppId,
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (!mInitialized) {
+    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
+    return;
+  }
+
+  RefPtr<SharedThreadPool> pool = SharedThreadPool::Get(kPoolName);
+  RefPtr<U2FRegisterRunnable> task = new U2FRegisterRunnable(mOrigin, aAppId,
                                                              aRegisterRequests,
                                                              aRegisteredKeys,
-                                                             &aCallback,
-                                                             mAuthenticators);
-
-  EvaluateAppIDAndRunTask(registerTask);
+                                                             mAuthenticators,
+                                                             &aCallback);
+  pool->Dispatch(task.forget(), NS_DISPATCH_NORMAL);
 }
 
 void
 U2F::Sign(const nsAString& aAppId,
           const nsAString& aChallenge,
           const Sequence<RegisteredKey>& aRegisteredKeys,
           U2FSignCallback& aCallback,
           const Optional<Nullable<int32_t>>& opt_aTimeoutSeconds,
           ErrorResult& aRv)
 {
-  RefPtr<U2FSignTask> signTask = new U2FSignTask(mOrigin, aAppId, aChallenge,
-                                                 aRegisteredKeys, &aCallback,
-                                                 mAuthenticators);
+  MOZ_ASSERT(NS_IsMainThread());
 
-  EvaluateAppIDAndRunTask(signTask);
+  if (!mInitialized) {
+    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
+    return;
+  }
+
+  RefPtr<SharedThreadPool> pool = SharedThreadPool::Get(kPoolName);
+  RefPtr<U2FSignRunnable> task = new U2FSignRunnable(mOrigin, aAppId, aChallenge,
+                                                     aRegisteredKeys,
+                                                     mAuthenticators, &aCallback);
+  pool->Dispatch(task.forget(), NS_DISPATCH_NORMAL);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/u2f/U2F.h
+++ b/dom/u2f/U2F.h
@@ -6,120 +6,278 @@
 
 #ifndef mozilla_dom_U2F_h
 #define mozilla_dom_U2F_h
 
 #include "js/TypeDecls.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/Nullable.h"
+#include "mozilla/dom/U2FBinding.h"
 #include "mozilla/ErrorResult.h"
+#include "mozilla/MozPromise.h"
+#include "mozilla/ReentrantMonitor.h"
+#include "mozilla/SharedThreadPool.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIU2FToken.h"
 #include "nsNSSShutDown.h"
 #include "nsPIDOMWindow.h"
+#include "nsProxyRelease.h"
 #include "nsWrapperCache.h"
 
 #include "USBToken.h"
 
 namespace mozilla {
 namespace dom {
 
+class U2FRegisterCallback;
+class U2FSignCallback;
+
+// Defined in U2FBinding.h by the U2F.webidl; their use requires a JSContext.
 struct RegisterRequest;
 struct RegisteredKey;
-class U2FRegisterCallback;
-class U2FSignCallback;
+
+// These structs are analogs to the WebIDL versions, but can be used on worker
+// threads which lack a JSContext.
+struct LocalRegisterRequest
+{
+  nsString mChallenge;
+  nsString mVersion;
+  CryptoBuffer mClientData;
+};
+
+struct LocalRegisteredKey
+{
+  nsString mKeyHandle;
+  nsString mVersion;
+  Nullable<nsString> mAppId;
+  // TODO: Support transport preferences
+  // Nullable<nsTArray<Transport>> mTransports;
+};
 
 // These enumerations are defined in the FIDO U2F Javascript API under the
 // interface "ErrorCode" as constant integers, and thus in the U2F.webidl file.
 // Any changes to these must occur in both locations.
 enum class ErrorCode {
   OK = 0,
   OTHER_ERROR = 1,
   BAD_REQUEST = 2,
   CONFIGURATION_UNSUPPORTED = 3,
   DEVICE_INELIGIBLE = 4,
   TIMEOUT = 5
 };
 
 typedef nsCOMPtr<nsIU2FToken> Authenticator;
+typedef MozPromise<nsString, ErrorCode, false> U2FPromise;
+typedef MozPromise<Authenticator, ErrorCode, false> U2FPrepPromise;
+
+// U2FPrepTasks return lists of Authenticators that are OK to
+// proceed; they're useful for culling incompatible Authenticators.
+// Currently, only IsRegistered is supported.
+class U2FPrepTask : public Runnable
+{
+public:
+  explicit U2FPrepTask(const Authenticator& aAuthenticator);
+
+  RefPtr<U2FPrepPromise> Execute();
+
+protected:
+  virtual ~U2FPrepTask();
+
+  Authenticator mAuthenticator;
+  MozPromiseHolder<U2FPrepPromise> mPromise;
+};
+
+// Determine whether the provided Authenticator already knows
+// of the provided Registered Key.
+class U2FIsRegisteredTask final : public U2FPrepTask
+{
+public:
+  U2FIsRegisteredTask(const Authenticator& aAuthenticator,
+                      const LocalRegisteredKey& aRegisteredKey);
+
+  NS_DECL_NSIRUNNABLE
+private:
+  ~U2FIsRegisteredTask();
+
+  LocalRegisteredKey mRegisteredKey;
+};
 
 class U2FTask : public Runnable
 {
 public:
   U2FTask(const nsAString& aOrigin,
-          const nsAString& aAppId);
+          const nsAString& aAppId,
+          const Authenticator& aAuthenticator);
+
+  RefPtr<U2FPromise> Execute();
 
   nsString mOrigin;
   nsString mAppId;
-
-  virtual
-  void ReturnError(ErrorCode code) = 0;
+  Authenticator mAuthenticator;
 
 protected:
   virtual ~U2FTask();
+
+  MozPromiseHolder<U2FPromise> mPromise;
 };
 
-class U2FRegisterTask final : public nsNSSShutDownObject,
-                              public U2FTask
+// Use the provided Authenticator to Register a new scoped credential
+// for the provided application.
+class U2FRegisterTask final : public U2FTask
 {
 public:
   U2FRegisterTask(const nsAString& aOrigin,
                   const nsAString& aAppId,
-                  const Sequence<RegisterRequest>& aRegisterRequests,
-                  const Sequence<RegisteredKey>& aRegisteredKeys,
-                  U2FRegisterCallback* aCallback,
-                  const Sequence<Authenticator>& aAuthenticators);
+                  const Authenticator& aAuthenticator,
+                  const CryptoBuffer& aAppParam,
+                  const CryptoBuffer& aChallengeParam,
+                  const LocalRegisterRequest& aRegisterEntry);
+
+  NS_DECL_NSIRUNNABLE
+private:
+  ~U2FRegisterTask();
+
+  CryptoBuffer mAppParam;
+  CryptoBuffer mChallengeParam;
+  LocalRegisterRequest mRegisterEntry;
+};
+
+// Generate an assertion using the provided Authenticator for the given origin
+// and provided application to attest to ownership of a valid scoped credential.
+class U2FSignTask final : public U2FTask
+{
+public:
+  U2FSignTask(const nsAString& aOrigin,
+              const nsAString& aAppId,
+              const nsAString& aVersion,
+              const Authenticator& aAuthenticator,
+              const CryptoBuffer& aAppParam,
+              const CryptoBuffer& aChallengeParam,
+              const CryptoBuffer& aClientData,
+              const CryptoBuffer& aKeyHandle);
+
+  NS_DECL_NSIRUNNABLE
+private:
+  ~U2FSignTask();
+
+  nsString mVersion;
+  CryptoBuffer mAppParam;
+  CryptoBuffer mChallengeParam;
+  CryptoBuffer mClientData;
+  CryptoBuffer mKeyHandle;
+};
+
+// Mediate inter-thread communication for multiple authenticators being queried
+// in concert. Operates as a cyclic buffer with a stop-work method.
+class U2FStatus
+{
+public:
+  U2FStatus();
+
+  void WaitGroupAdd();
+  void WaitGroupDone();
+  void WaitGroupWait();
+
+  void Stop(const ErrorCode aErrorCode);
+  void Stop(const ErrorCode aErrorCode, const nsAString& aResponse);
+  bool IsStopped();
+  ErrorCode GetErrorCode();
+  nsString GetResponse();
+
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(U2FStatus)
+
+private:
+  ~U2FStatus();
+
+  uint16_t mCount;
+  bool mIsStopped;
+  nsString mResponse;
+  ErrorCode mErrorCode;
+  ReentrantMonitor mReentrantMonitor;
+};
+
+// U2FRunnables run to completion, performing a single U2F operation such as
+// registering, or signing.
+class U2FRunnable : public Runnable
+                  , public nsNSSShutDownObject
+{
+public:
+  U2FRunnable(const nsAString& aOrigin, const nsAString& aAppId);
 
   // No NSS resources to release.
   virtual
   void virtualDestroyNSSReference() override {};
 
-  void ReturnError(ErrorCode code) override;
+protected:
+  virtual ~U2FRunnable();
+  ErrorCode EvaluateAppID();
 
-  NS_DECL_NSIRUNNABLE
-private:
-  ~U2FRegisterTask();
-
-  Sequence<RegisterRequest> mRegisterRequests;
-  Sequence<RegisteredKey> mRegisteredKeys;
-  RefPtr<U2FRegisterCallback> mCallback;
-  Sequence<Authenticator> mAuthenticators;
+  nsString mOrigin;
+  nsString mAppId;
 };
 
-class U2FSignTask final : public nsNSSShutDownObject,
-                          public U2FTask
+// This U2FRunnable completes a single application-requested U2F Register
+// operation.
+class U2FRegisterRunnable : public U2FRunnable
 {
 public:
-  U2FSignTask(const nsAString& aOrigin,
-              const nsAString& aAppId,
-              const nsAString& aChallenge,
-              const Sequence<RegisteredKey>& aRegisteredKeys,
-              U2FSignCallback* aCallback,
-              const Sequence<Authenticator>& aAuthenticators);
+  U2FRegisterRunnable(const nsAString& aOrigin,
+                      const nsAString& aAppId,
+                      const Sequence<RegisterRequest>& aRegisterRequests,
+                      const Sequence<RegisteredKey>& aRegisteredKeys,
+                      const Sequence<Authenticator>& aAuthenticators,
+                      U2FRegisterCallback* aCallback);
 
-  // No NSS resources to release.
-  virtual
-  void virtualDestroyNSSReference() override {};
-
-  void ReturnError(ErrorCode code) override;
+  void SendResponse(const RegisterResponse& aResponse);
+  void SetTimeout(const int32_t aTimeoutMillis);
 
   NS_DECL_NSIRUNNABLE
+
 private:
-  ~U2FSignTask();
+  ~U2FRegisterRunnable();
+
+  nsTArray<LocalRegisterRequest> mRegisterRequests;
+  nsTArray<LocalRegisteredKey> mRegisteredKeys;
+  nsTArray<Authenticator> mAuthenticators;
+  nsMainThreadPtrHandle<U2FRegisterCallback> mCallback;
+  Nullable<int32_t> opt_mTimeoutSeconds;
+};
+
+// This U2FRunnable completes a single application-requested U2F Sign operation.
+class U2FSignRunnable : public U2FRunnable
+{
+public:
+  U2FSignRunnable(const nsAString& aOrigin,
+                  const nsAString& aAppId,
+                  const nsAString& aChallenge,
+                  const Sequence<RegisteredKey>& aRegisteredKeys,
+                  const Sequence<Authenticator>& aAuthenticators,
+                  U2FSignCallback* aCallback);
+
+  void SendResponse(const SignResponse& aResponse);
+  void SetTimeout(const int32_t aTimeoutMillis);
+
+  NS_DECL_NSIRUNNABLE
+
+private:
+  ~U2FSignRunnable();
 
   nsString mChallenge;
-  Sequence<RegisteredKey> mRegisteredKeys;
-  RefPtr<U2FSignCallback> mCallback;
-  Sequence<Authenticator> mAuthenticators;
+  CryptoBuffer mClientData;
+  nsTArray<LocalRegisteredKey> mRegisteredKeys;
+  nsTArray<Authenticator> mAuthenticators;
+  nsMainThreadPtrHandle<U2FSignCallback> mCallback;
+  Nullable<int32_t> opt_mTimeoutSeconds;
 };
 
-class U2F final : public nsISupports,
-                  public nsWrapperCache,
-                  public nsNSSShutDownObject
+// The U2F Class is used by the JS engine to initiate U2F operations.
+class U2F final : public nsISupports
+                , public nsWrapperCache
+                , public nsNSSShutDownObject
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(U2F)
 
   U2F();
 
   nsPIDOMWindowInner*
@@ -153,16 +311,17 @@ public:
   // No NSS resources to release.
   virtual
   void virtualDestroyNSSReference() override {};
 
 private:
   nsCOMPtr<nsPIDOMWindowInner> mParent;
   nsString mOrigin;
   Sequence<Authenticator> mAuthenticators;
+  bool mInitialized;
 
   ~U2F();
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_U2F_h
--- a/dom/u2f/tests/mochitest.ini
+++ b/dom/u2f/tests/mochitest.ini
@@ -7,15 +7,23 @@ support-files =
   frame_register.html
   frame_register_sign.html
   pkijs/asn1.js
   pkijs/common.js
   pkijs/x509_schema.js
   pkijs/x509_simpl.js
   u2futil.js
 
+# Feature does not function on e10s (Disabled in Bug 1297552)
 [test_util_methods.html]
+skip-if = !e10s
 [test_no_token.html]
+skip-if = !e10s
 [test_register.html]
+skip-if = !e10s
 [test_register_sign.html]
+skip-if = !e10s
 [test_appid_facet.html]
+skip-if = !e10s
 [test_appid_facet_insecure.html]
+skip-if = !e10s
 [test_appid_facet_subdomain.html]
+skip-if = !e10s
--- a/dom/webidl/DecoderDoctorNotification.webidl
+++ b/dom/webidl/DecoderDoctorNotification.webidl
@@ -4,16 +4,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
 enum DecoderDoctorNotificationType {
   "cannot-play",
   "platform-decoder-not-found",
   "can-play-but-some-missing-decoders",
   "cannot-initialize-pulseaudio",
+  "unsupported-libavcodec",
 };
 
 dictionary DecoderDoctorNotification {
   required DecoderDoctorNotificationType type;
   // True when the issue has been solved.
   required boolean isSolved;
   // Key from dom.properties, used for telemetry and prefs.
   required DOMString decoderDoctorReportId;
--- a/dom/webidl/RTCDTMFSender.webidl
+++ b/dom/webidl/RTCDTMFSender.webidl
@@ -9,11 +9,9 @@
 
 [JSImplementation="@mozilla.org/dom/rtcdtmfsender;1"]
 interface RTCDTMFSender : EventTarget {
     void insertDTMF(DOMString tones,
                     optional unsigned long duration = 100,
                     optional unsigned long interToneGap = 70);
              attribute EventHandler  ontonechange;
     readonly attribute DOMString     toneBuffer;
-    readonly attribute unsigned long duration;
-    readonly attribute unsigned long interToneGap;
 };
--- a/dom/xbl/nsXBLProtoImplMethod.cpp
+++ b/dom/xbl/nsXBLProtoImplMethod.cpp
@@ -248,21 +248,17 @@ nsXBLProtoImplMethod::Write(nsIObjectOut
   MOZ_ASSERT(IsCompiled());
   if (GetCompiledMethodPreserveColor()) {
     nsresult rv = aStream->Write8(XBLBinding_Serialize_Method);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = aStream->WriteWStringZ(mName);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    // Calling fromMarkedLocation() is safe because mMethod is traced by the
-    // Trace() method above, and because its value is never changed after it has
-    // been set to a compiled method.
-    JS::Handle<JSObject*> method =
-      JS::Handle<JSObject*>::fromMarkedLocation(mMethod.AsHeapObject().address());
+    JS::Rooted<JSObject*> method(RootingCx(), GetCompiledMethod());
     return XBL_SerializeFunction(aStream, method);
   }
 
   return NS_OK;
 }
 
 nsresult
 nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement, JSAddonId* aAddonId)
@@ -337,19 +333,15 @@ nsXBLProtoImplAnonymousMethod::Write(nsI
   MOZ_ASSERT(IsCompiled());
   if (GetCompiledMethodPreserveColor()) {
     nsresult rv = aStream->Write8(aType);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = aStream->WriteWStringZ(mName);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    // Calling fromMarkedLocation() is safe because mMethod is traced by the
-    // Trace() method above, and because its value is never changed after it has
-    // been set to a compiled method.
-    JS::Handle<JSObject*> method =
-      JS::Handle<JSObject*>::fromMarkedLocation(mMethod.AsHeapObject().address());
+    JS::Rooted<JSObject*> method(RootingCx(), GetCompiledMethod());
     rv = XBL_SerializeFunction(aStream, method);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
--- a/dom/xbl/nsXBLProtoImplProperty.cpp
+++ b/dom/xbl/nsXBLProtoImplProperty.cpp
@@ -15,21 +15,21 @@
 #include "nsXBLPrototypeBinding.h"
 #include "nsXBLSerialize.h"
 #include "xpcpublic.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsXBLProtoImplProperty::nsXBLProtoImplProperty(const char16_t* aName,
-                                               const char16_t* aGetter, 
+                                               const char16_t* aGetter,
                                                const char16_t* aSetter,
                                                const char16_t* aReadOnly,
                                                uint32_t aLineNumber) :
-  nsXBLProtoImplMember(aName), 
+  nsXBLProtoImplMember(aName),
   mJSAttributes(JSPROP_ENUMERATE)
 #ifdef DEBUG
   , mIsCompiled(false)
 #endif
 {
   MOZ_COUNT_CTOR(nsXBLProtoImplProperty);
 
   if (aReadOnly) {
@@ -305,17 +305,17 @@ nsXBLProtoImplProperty::Read(nsIObjectIn
   if (aType == XBLBinding_Serialize_GetterProperty ||
       aType == XBLBinding_Serialize_GetterSetterProperty) {
     nsresult rv = XBL_DeserializeFunction(aStream, &getterObject);
     NS_ENSURE_SUCCESS(rv, rv);
 
     mJSAttributes |= JSPROP_GETTER | JSPROP_SHARED;
   }
   mGetter.SetJSFunction(getterObject);
-  
+
   JS::Rooted<JSObject*> setterObject(cx);
   if (aType == XBLBinding_Serialize_SetterProperty ||
       aType == XBLBinding_Serialize_GetterSetterProperty) {
     nsresult rv = XBL_DeserializeFunction(aStream, &setterObject);
     NS_ENSURE_SUCCESS(rv, rv);
 
     mJSAttributes |= JSPROP_SETTER | JSPROP_SHARED;
   }
@@ -347,29 +347,24 @@ nsXBLProtoImplProperty::Write(nsIObjectO
     type |= XBLBinding_Serialize_ReadOnly;
   }
 
   nsresult rv = aStream->Write8(type);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = aStream->WriteWStringZ(mName);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // The calls to fromMarkedLocation() below are safe because mSetter and
-  // mGetter are traced by the Trace() method above, and because their values
-  // are never changed after they have been set to a compiled function.
   MOZ_ASSERT_IF(mJSAttributes & (JSPROP_GETTER | JSPROP_SETTER), mIsCompiled);
 
   if (mJSAttributes & JSPROP_GETTER) {
-    JS::Handle<JSObject*> function =
-      JS::Handle<JSObject*>::fromMarkedLocation(mGetter.AsHeapObject().address());
+    JS::Rooted<JSObject*> function(RootingCx(), mGetter.GetJSFunction());
     rv = XBL_SerializeFunction(aStream, function);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   if (mJSAttributes & JSPROP_SETTER) {
-     JS::Handle<JSObject*> function =
-      JS::Handle<JSObject*>::fromMarkedLocation(mSetter.AsHeapObject().address());
+    JS::Rooted<JSObject*> function(RootingCx(), mSetter.GetJSFunction());
     rv = XBL_SerializeFunction(aStream, function);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
--- a/dom/xul/XULDocument.cpp
+++ b/dom/xul/XULDocument.cpp
@@ -2839,17 +2839,17 @@ XULDocument::ResumeWalk()
                     // stale and must be reloaded.
                     bool blocked;
                     rv = LoadScript(scriptproto, &blocked);
                     // If the script cannot be loaded, just keep going!
 
                     if (NS_SUCCEEDED(rv) && blocked)
                         return NS_OK;
                 }
-                else if (scriptproto->GetScriptObject()) {
+                else if (scriptproto->HasScriptObject()) {
                     // An inline script
                     rv = ExecuteScript(scriptproto);
                     if (NS_FAILED(rv)) return rv;
                 }
             }
             break;
 
             case nsXULPrototypeNode::eType_Text: {
@@ -3205,17 +3205,17 @@ XULDocument::ReportMissingOverlay(nsIURI
 nsresult
 XULDocument::LoadScript(nsXULPrototypeScript* aScriptProto, bool* aBlock)
 {
     // Load a transcluded script
     nsresult rv;
 
     bool isChromeDoc = IsChromeURI(mDocumentURI);
 
-    if (isChromeDoc && aScriptProto->GetScriptObject()) {
+    if (isChromeDoc && aScriptProto->HasScriptObject()) {
         rv = ExecuteScript(aScriptProto);
 
         // Ignore return value from execution, and don't block
         *aBlock = false;
         return NS_OK;
     }
 
     // Try the XUL script cache, in case two XUL documents source the same
@@ -3228,17 +3228,17 @@ XULDocument::LoadScript(nsXULPrototypeSc
             nsXULPrototypeCache::GetInstance()->GetScript(
                                    aScriptProto->mSrcURI);
         if (newScriptObject) {
             // The script language for a proto must remain constant - we
             // can't just change it for this unexpected language.
             aScriptProto->Set(newScriptObject);
         }
 
-        if (aScriptProto->GetScriptObject()) {
+        if (aScriptProto->HasScriptObject()) {
             rv = ExecuteScript(aScriptProto);
 
             // Ignore return value from execution, and don't block
             *aBlock = false;
             return NS_OK;
         }
     }
 
@@ -3348,17 +3348,17 @@ XULDocument::OnStreamComplete(nsIStreamL
             // completes.
             JS::SourceBufferHolder srcBuf(mOffThreadCompileStringBuf,
                                           mOffThreadCompileStringLength,
                                           JS::SourceBufferHolder::GiveOwnership);
             mOffThreadCompileStringBuf = nullptr;
             mOffThreadCompileStringLength = 0;
 
             rv = mCurrentScriptProto->Compile(srcBuf, uri, 1, this, this);
-            if (NS_SUCCEEDED(rv) && !mCurrentScriptProto->GetScriptObject()) {
+            if (NS_SUCCEEDED(rv) && !mCurrentScriptProto->HasScriptObject()) {
                 // We will be notified via OnOffThreadCompileComplete when the
                 // compile finishes. Keep the contents of the compiled script
                 // alive until the compilation finishes.
                 mOffThreadCompiling = true;
                 // If the JS engine did not take the source buffer, then take
                 // it back here to ensure it remains alive.
                 mOffThreadCompileStringBuf = srcBuf.take();
                 if (mOffThreadCompileStringBuf) {
@@ -3373,17 +3373,17 @@ XULDocument::OnStreamComplete(nsIStreamL
     return OnScriptCompileComplete(mCurrentScriptProto->GetScriptObject(), rv);
 }
 
 NS_IMETHODIMP
 XULDocument::OnScriptCompileComplete(JSScript* aScript, nsresult aStatus)
 {
     // When compiling off thread the script will not have been attached to the
     // script proto yet.
-    if (aScript && !mCurrentScriptProto->GetScriptObject())
+    if (aScript && !mCurrentScriptProto->HasScriptObject())
         mCurrentScriptProto->Set(aScript);
 
     // Allow load events to be fired once off thread compilation finishes.
     if (mOffThreadCompiling) {
         mOffThreadCompiling = false;
         UnblockOnload(false);
     }
 
@@ -3426,21 +3426,21 @@ XULDocument::OnScriptCompileComplete(JSS
         // containing a companion nsXULPrototypeScript node that owns a
         // GC root protecting the script object.  Otherwise, the script
         // cache entry will dangle once the uncached prototype document
         // is released when its owning XULDocument is unloaded.
         //
         // (See http://bugzilla.mozilla.org/show_bug.cgi?id=98207 for
         // the true crime story.)
         bool useXULCache = nsXULPrototypeCache::GetInstance()->IsEnabled();
-  
-        if (useXULCache && IsChromeURI(mDocumentURI) && scriptProto->GetScriptObject()) {
+
+        if (useXULCache && IsChromeURI(mDocumentURI) && scriptProto->HasScriptObject()) {
+            JS::Rooted<JSScript*> script(RootingCx(), scriptProto->GetScriptObject());
             nsXULPrototypeCache::GetInstance()->PutScript(
-                               scriptProto->mSrcURI,
-                               scriptProto->GetScriptObject());
+                               scriptProto->mSrcURI, script);
         }
 
         if (mIsWritingFastLoad && mCurrentPrototype != mMasterPrototype) {
             // If we are loading an overlay script, try to serialize
             // it to the FastLoad file here.  Master scripts will be
             // serialized when the master prototype document gets
             // written, at the bottom of ResumeWalk.  That way, master
             // out-of-line scripts are serialized in the same order that
@@ -3469,17 +3469,17 @@ XULDocument::OnScriptCompileComplete(JSS
                      "waiting for wrong script to load?");
         doc->mCurrentScriptProto = nullptr;
 
         // Unlink doc from scriptProto's list before executing and resuming
         *docp = doc->mNextSrcLoadWaiter;
         doc->mNextSrcLoadWaiter = nullptr;
 
         // Execute only if we loaded and compiled successfully, then resume
-        if (NS_SUCCEEDED(aStatus) && scriptProto->GetScriptObject()) {
+        if (NS_SUCCEEDED(aStatus) && scriptProto->HasScriptObject()) {
             doc->ExecuteScript(scriptProto);
         }
         doc->ResumeWalk();
         NS_RELEASE(doc);
     }
 
     return rv;
 }
@@ -3490,35 +3490,35 @@ XULDocument::ExecuteScript(nsXULPrototyp
     NS_PRECONDITION(aScript != nullptr, "null ptr");
     NS_ENSURE_TRUE(aScript, NS_ERROR_NULL_POINTER);
     NS_ENSURE_TRUE(mScriptGlobalObject, NS_ERROR_NOT_INITIALIZED);
 
     nsresult rv;
     rv = mScriptGlobalObject->EnsureScriptEnvironment();
     NS_ENSURE_SUCCESS(rv, rv);
 
-    JS::HandleScript scriptObject = aScript->GetScriptObject();
-    NS_ENSURE_TRUE(scriptObject, NS_ERROR_UNEXPECTED);
-
     // Execute the precompiled script with the given version
     nsAutoMicroTask mt;
 
     // We're about to run script via JS::CloneAndExecuteScript, so we need an
     // AutoEntryScript. This is Gecko specific and not in any spec.
     AutoEntryScript aes(mScriptGlobalObject, "precompiled XUL <script> element");
     JSContext* cx = aes.cx();
+
+    JS::Rooted<JSScript*> scriptObject(cx, aScript->GetScriptObject());
+    NS_ENSURE_TRUE(scriptObject, NS_ERROR_UNEXPECTED);
+
     JS::Rooted<JSObject*> baseGlobal(cx, JS::CurrentGlobalOrNull(cx));
     NS_ENSURE_TRUE(xpc::Scriptability::Get(baseGlobal).Allowed(), NS_OK);
 
     JSAddonId* addonId = mCurrentPrototype ? MapURIToAddonID(mCurrentPrototype->GetURI()) : nullptr;
     JS::Rooted<JSObject*> global(cx, xpc::GetAddonScope(cx, baseGlobal, addonId));
     NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
 
     JS::ExposeObjectToActiveJS(global);
-    xpc_UnmarkGrayScript(scriptObject);
     JSAutoCompartment ac(cx, global);
 
     // The script is in the compilation scope. Clone it into the target scope
     // and execute it. On failure, ~AutoScriptEntry will handle exceptions, so
     // there is no need to manually check the return value.
     JS::RootedValue rval(cx);
     JS::CloneAndExecuteScript(cx, scriptObject, &rval);
 
--- a/dom/xul/nsXULContentSink.cpp
+++ b/dom/xul/nsXULContentSink.cpp
@@ -524,17 +524,17 @@ XULContentSinkImpl::HandleEndElement(con
     }
     break;
 
     case nsXULPrototypeNode::eType_Script: {
         nsXULPrototypeScript* script =
             static_cast<nsXULPrototypeScript*>(node.get());
 
         // If given a src= attribute, we must ignore script tag content.
-        if (!script->mSrcURI && !script->GetScriptObject()) {
+        if (!script->mSrcURI && !script->HasScriptObject()) {
             nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
 
             script->mOutOfLine = false;
             if (doc)
                 script->Compile(mText, mTextLength, mDocumentURL,
                                 script->mLineNo, doc);
         }
 
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -2249,17 +2249,17 @@ nsXULPrototypeElement::Serialize(nsIObje
             } else {
                 tmp = aStream->WriteCompoundObject(script->mSrcURI,
                                                    NS_GET_IID(nsIURI),
                                                    true);
                 if (NS_FAILED(tmp)) {
                   rv = tmp;
                 }
 
-                if (script->GetScriptObject()) {
+                if (script->HasScriptObject()) {
                     // This may return NS_OK without muxing script->mSrcURI's
                     // data into the cache file, in the case where that
                     // muxed document is already there (written by a prior
                     // session, or by an earlier cache episode during this
                     // session).
                     tmp = script->SerializeOutOfLine(aStream, aProtoDoc);
                     if (NS_FAILED(tmp)) {
                       rv = tmp;
@@ -2526,25 +2526,20 @@ nsXULPrototypeScript::Serialize(nsIObjec
 
     // Write basic prototype data
     nsresult rv;
     rv = aStream->Write32(mLineNo);
     if (NS_FAILED(rv)) return rv;
     rv = aStream->Write32(mLangVersion);
     if (NS_FAILED(rv)) return rv;
 
-    // Calling fromMarkedLocation() is safe because we trace mScriptObject in
-    // TraceScriptObject() and because its value is never changed after it has
-    // been set.
-    JS::Handle<JSScript*> script =
-        JS::Handle<JSScript*>::fromMarkedLocation(mScriptObject.address());
     JSContext* cx = jsapi.cx();
+    JS::Rooted<JSScript*> script(cx, mScriptObject);
     MOZ_ASSERT(xpc::CompilationScope() == JS::CurrentGlobalOrNull(cx));
-    return nsContentUtils::XPConnect()->WriteScript(aStream, cx,
-                                                    xpc_UnmarkGrayScript(script));
+    return nsContentUtils::XPConnect()->WriteScript(aStream, cx, script);
 }
 
 nsresult
 nsXULPrototypeScript::SerializeOutOfLine(nsIObjectOutputStream* aStream,
                                          nsXULPrototypeDocument* aProtoDoc)
 {
     nsresult rv = NS_ERROR_NOT_IMPLEMENTED;
 
@@ -2668,18 +2663,20 @@ nsXULPrototypeScript::DeserializeOutOfLi
             // error.
             if (NS_SUCCEEDED(rv))
                 rv = Deserialize(objectInput, aProtoDoc, nullptr, nullptr);
 
             if (NS_SUCCEEDED(rv)) {
                 if (useXULCache && mSrcURI) {
                     bool isChrome = false;
                     mSrcURI->SchemeIs("chrome", &isChrome);
-                    if (isChrome)
-                        cache->PutScript(mSrcURI, GetScriptObject());
+                    if (isChrome) {
+                        JS::Rooted<JSScript*> script(RootingCx(), GetScriptObject());
+                        cache->PutScript(mSrcURI, script);
+                    }
                 }
                 cache->FinishInputStream(mSrcURI);
             } else {
                 // If mSrcURI is not in the cache,
                 // rv will be NS_ERROR_NOT_AVAILABLE and we'll try to
                 // update the cache file to hold a serialization of
                 // this script, once it has finished loading.
                 if (rv != NS_ERROR_NOT_AVAILABLE)
--- a/dom/xul/nsXULElement.h
+++ b/dom/xul/nsXULElement.h
@@ -230,26 +230,25 @@ public:
                      nsIURI* aURI, uint32_t aLineNo,
                      nsIDocument* aDocument,
                      nsIOffThreadScriptReceiver *aOffThreadReceiver = nullptr);
 
     void UnlinkJSObjects();
 
     void Set(JSScript* aObject);
 
-    // It's safe to return a handle because we trace mScriptObject, no one ever
-    // uses the handle (or the script object) past the point at which the
-    // nsXULPrototypeScript dies, and we can't get memmoved so the
-    // &mScriptObject pointer can't go stale.
-    JS::Handle<JSScript*> GetScriptObject()
+    bool HasScriptObject()
     {
-        // Calling fromMarkedLocation() is safe because we trace mScriptObject in
-        // TraceScriptObject() and because its value is never changed after it has
-        // been set.
-        return JS::Handle<JSScript*>::fromMarkedLocation(mScriptObject.address());
+        // Conversion to bool doesn't trigger mScriptObject's read barrier.
+        return mScriptObject;
+    }
+
+    JSScript* GetScriptObject()
+    {
+        return mScriptObject;
     }
 
     void TraceScriptObject(JSTracer* aTrc)
     {
         JS::TraceEdge(aTrc, &mScriptObject, "active window XUL prototype script");
     }
 
     void Trace(const TraceCallbacks& aCallbacks, void* aClosure)
--- a/gfx/2d/DrawTargetD2D1.cpp
+++ b/gfx/2d/DrawTargetD2D1.cpp
@@ -171,16 +171,20 @@ DrawTargetD2D1::DrawSurface(SourceSurfac
   }
 
   if (bitmap && aSurfOptions.mSamplingBounds == SamplingBounds::UNBOUNDED) {
     mDC->DrawBitmap(bitmap, D2DRect(aDest), aOptions.mAlpha,
                     D2DFilter(aSurfOptions.mSamplingFilter), D2DRect(aSource));
   } else {
     // This has issues ignoring the alpha channel on windows 7 with images marked opaque.
     MOZ_ASSERT(aSurface->GetFormat() != SurfaceFormat::B8G8R8X8);
+
+    // Bug 1275478 - D2D1 cannot draw A8 surface correctly.
+    MOZ_ASSERT(aSurface->GetFormat() != SurfaceFormat::A8);
+
     mDC->CreateImageBrush(image,
                           D2D1::ImageBrushProperties(samplingBounds,
                                                      D2D1_EXTEND_MODE_CLAMP,
                                                      D2D1_EXTEND_MODE_CLAMP,
                                                      D2DInterpolationMode(aSurfOptions.mSamplingFilter)),
                           D2D1::BrushProperties(aOptions.mAlpha, D2DMatrix(transform)),
                           getter_AddRefs(brush));
     mDC->FillRectangle(D2DRect(aDest), brush);
--- a/gfx/gl/GLBlitHelper.cpp
+++ b/gfx/gl/GLBlitHelper.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* vim: set ts=8 sts=4 et sw=4 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/. */
 
+#include "gfxUtils.h"
 #include "GLBlitHelper.h"
 #include "GLContext.h"
 #include "GLScreenBuffer.h"
 #include "ScopedGLHelpers.h"
 #include "mozilla/Preferences.h"
 #include "ImageContainer.h"
 #include "HeapCopyOfStackArray.h"
 #include "mozilla/gfx/Matrix.h"
@@ -54,16 +55,17 @@ GLBlitHelper::GLBlitHelper(GLContext* gl
     , mTexNV12PlanarBlit_Program(0)
     , mFBO(0)
     , mSrcTexY(0)
     , mSrcTexCb(0)
     , mSrcTexCr(0)
     , mSrcTexEGL(0)
     , mYTexScaleLoc(-1)
     , mCbCrTexScaleLoc(-1)
+    , mYuvColorMatrixLoc(-1)
     , mTexWidth(0)
     , mTexHeight(0)
     , mCurYScale(1.0f)
     , mCurCbCrScale(1.0f)
 {
 }
 
 GLBlitHelper::~GLBlitHelper()
@@ -166,47 +168,57 @@ GLBlitHelper::InitTexQuadProgram(BlitTyp
         void main()                                                     \n\
         {                                                               \n\
             gl_FragColor = texture2D(uTexUnit,                          \n\
                 (uTextureTransform * vec4(vTexCoord, 0.0, 1.0)).xy);    \n\
         }                                                               \n\
     ";
 #endif
     /* 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]
+    [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]
 
     For [0,1] instead of [0,255], and to 5 places:
-    [R] [1.16438, 0.00000, 1.59603] [ Y - 0.06275]
+    [R]   [1.16438,  0.00000,  1.59603]   [ Y - 0.06275]
     [G] = [1.16438, -0.39176, -0.81297] x [Cb - 0.50196]
-    [B] [1.16438, 2.01723, 0.00000] [Cr - 0.50196]
+    [B]   [1.16438,  2.01723,  0.00000]   [Cr - 0.50196]
+
+    From Rec709:
+    [R]   [1.1643835616438356,  4.2781193979771426e-17, 1.7927410714285714]     [ Y -  16]
+    [G] = [1.1643835616438358, -0.21324861427372963,   -0.532909328559444]    x [Cb - 128]
+    [B]   [1.1643835616438356,  2.1124017857142854,     0.0]                    [Cr - 128]
+
+    For [0,1] instead of [0,255], and to 5 places:
+    [R]   [1.16438,  0.00000,  1.79274]   [ Y - 0.06275]
+    [G] = [1.16438, -0.21325, -0.53291] x [Cb - 0.50196]
+    [B]   [1.16438,  2.11240,  0.00000]   [Cr - 0.50196]
     */
     const char kTexYUVPlanarBlit_FragShaderSource[] = "\
         #version 100                                                        \n\
         #ifdef GL_ES                                                        \n\
         precision mediump float;                                            \n\
         #endif                                                              \n\
         varying vec2 vTexCoord;                                             \n\
         uniform sampler2D uYTexture;                                        \n\
         uniform sampler2D uCbTexture;                                       \n\
         uniform sampler2D uCrTexture;                                       \n\
         uniform vec2 uYTexScale;                                            \n\
         uniform vec2 uCbCrTexScale;                                         \n\
+        uniform mat3 uYuvColorMatrix;                                       \n\
         void main()                                                         \n\
         {                                                                   \n\
             float y = texture2D(uYTexture, vTexCoord * uYTexScale).r;       \n\
             float cb = texture2D(uCbTexture, vTexCoord * uCbCrTexScale).r;  \n\
             float cr = texture2D(uCrTexture, vTexCoord * uCbCrTexScale).r;  \n\
-            y = (y - 0.06275) * 1.16438;                                    \n\
+            y = y - 0.06275;                                                \n\
             cb = cb - 0.50196;                                              \n\
             cr = cr - 0.50196;                                              \n\
-            gl_FragColor.r = y + cr * 1.59603;                              \n\
-            gl_FragColor.g = y - 0.81297 * cr - 0.39176 * cb;               \n\
-            gl_FragColor.b = y + cb * 2.01723;                              \n\
+            vec3 yuv = vec3(y, cb, cr);                                     \n\
+            gl_FragColor.rgb = uYuvColorMatrix * yuv;                       \n\
             gl_FragColor.a = 1.0;                                           \n\
         }                                                                   \n\
     ";
 
 #ifdef XP_MACOSX
     const char kTexNV12PlanarBlit_FragShaderSource[] = "\
         #version 100                                                             \n\
         #extension GL_ARB_texture_rectangle : require                            \n\
@@ -404,23 +416,25 @@ GLBlitHelper::InitTexQuadProgram(BlitTyp
                 mGL->fUniform1i(texUnitLoc, 0);
                 break;
             }
             case ConvertPlanarYCbCr: {
                 GLint texY = mGL->fGetUniformLocation(program, "uYTexture");
                 GLint texCb = mGL->fGetUniformLocation(program, "uCbTexture");
                 GLint texCr = mGL->fGetUniformLocation(program, "uCrTexture");
                 mYTexScaleLoc = mGL->fGetUniformLocation(program, "uYTexScale");
-                mCbCrTexScaleLoc= mGL->fGetUniformLocation(program, "uCbCrTexScale");
+                mCbCrTexScaleLoc = mGL->fGetUniformLocation(program, "uCbCrTexScale");
+                mYuvColorMatrixLoc = mGL->fGetUniformLocation(program, "uYuvColorMatrix");
 
                 DebugOnly<bool> hasUniformLocations = texY != -1 &&
                                                       texCb != -1 &&
                                                       texCr != -1 &&
                                                       mYTexScaleLoc != -1 &&
-                                                      mCbCrTexScaleLoc != -1;
+                                                      mCbCrTexScaleLoc != -1 &&
+                                                      mYuvColorMatrixLoc != -1;
                 MOZ_ASSERT(hasUniformLocations, "uniforms not found");
 
                 mGL->fUniform1i(texY, Channel_Y);
                 mGL->fUniform1i(texCb, Channel_Cb);
                 mGL->fUniform1i(texCr, Channel_Cr);
                 break;
             }
             case ConvertMacIOSurfaceImage: {
@@ -785,16 +799,19 @@ GLBlitHelper::BlitPlanarYCbCrImage(layer
     BindAndUploadYUVTexture(Channel_Cb, yuvData->mCbCrStride, yuvData->mCbCrSize.height, yuvData->mCbChannel, needsAllocation);
     BindAndUploadYUVTexture(Channel_Cr, yuvData->mCbCrStride, yuvData->mCbCrSize.height, yuvData->mCrChannel, needsAllocation);
 
     if (needsAllocation) {
         mGL->fUniform2f(mYTexScaleLoc, (float)yuvData->mYSize.width/yuvData->mYStride, 1.0f);
         mGL->fUniform2f(mCbCrTexScaleLoc, (float)yuvData->mCbCrSize.width/yuvData->mCbCrStride, 1.0f);
     }
 
+    float* yuvToRgb = gfxUtils::Get3x3YuvColorMatrix(yuvData->mYUVColorSpace);
+    mGL->fUniformMatrix3fv(mYuvColorMatrixLoc, 1, 0, yuvToRgb);
+
     mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
     for (int i = 0; i < 3; i++) {
         mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
         mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, oldTex[i]);
     }
     return true;
 }
 
--- a/gfx/gl/GLBlitHelper.h
+++ b/gfx/gl/GLBlitHelper.h
@@ -85,16 +85,17 @@ class GLBlitHelper final
     GLuint mTexNV12PlanarBlit_Program;
     GLuint mFBO;
     GLuint mSrcTexY;
     GLuint mSrcTexCb;
     GLuint mSrcTexCr;
     GLuint mSrcTexEGL;
     GLint mYTexScaleLoc;
     GLint mCbCrTexScaleLoc;
+    GLint mYuvColorMatrixLoc;
     int mTexWidth;
     int mTexHeight;
 
     // Cache some uniform values
     float mCurYScale;
     float mCurCbCrScale;
 
     void UseBlitProgram();
--- a/gfx/layers/Effects.h
+++ b/gfx/layers/Effects.h
@@ -153,21 +153,24 @@ struct EffectRGB : public TexturedEffect
     : TexturedEffect(EffectTypes::RGB, aTexture, aPremultiplied, aSamplingFilter)
   {}
 
   virtual const char* Name() { return "EffectRGB"; }
 };
 
 struct EffectYCbCr : public TexturedEffect
 {
-  EffectYCbCr(TextureSource *aSource, gfx::SamplingFilter aSamplingFilter)
+  EffectYCbCr(TextureSource *aSource, YUVColorSpace aYUVColorSpace, gfx::SamplingFilter aSamplingFilter)
     : TexturedEffect(EffectTypes::YCBCR, aSource, false, aSamplingFilter)
+    , mYUVColorSpace(aYUVColorSpace)
   {}
 
   virtual const char* Name() { return "EffectYCbCr"; }
+
+  YUVColorSpace mYUVColorSpace;
 };
 
 struct EffectNV12 : public TexturedEffect
 {
   EffectNV12(TextureSource *aSource, gfx::SamplingFilter aSamplingFilter)
     : TexturedEffect(EffectTypes::NV12, aSource, false, aSamplingFilter)
   {}
 
@@ -234,32 +237,56 @@ CreateTexturedEffect(gfx::SurfaceFormat 
   switch (aFormat) {
   case gfx::SurfaceFormat::B8G8R8A8:
   case gfx::SurfaceFormat::B8G8R8X8:
   case gfx::SurfaceFormat::R8G8B8X8:
   case gfx::SurfaceFormat::R5G6B5_UINT16:
   case gfx::SurfaceFormat::R8G8B8A8:
     result = new EffectRGB(aSource, isAlphaPremultiplied, aSamplingFilter);
     break;
-  case gfx::SurfaceFormat::YUV:
-    result = new EffectYCbCr(aSource, aSamplingFilter);
-    break;
   case gfx::SurfaceFormat::NV12:
     result = new EffectNV12(aSource, aSamplingFilter);
     break;
+  case gfx::SurfaceFormat::YUV:
+    MOZ_ASSERT_UNREACHABLE("gfx::SurfaceFormat::YUV is invalid");
+    break;
   default:
     NS_WARNING("unhandled program type");
     break;
   }
 
   result->mState = state;
 
   return result.forget();
 }
 
+inline already_AddRefed<TexturedEffect>
+CreateTexturedEffect(TextureHost* aHost,
+                     TextureSource* aSource,
+                     const gfx::SamplingFilter aSamplingFilter,
+                     bool isAlphaPremultiplied,
+                     const LayerRenderState &state = LayerRenderState())
+{
+  MOZ_ASSERT(aHost);
+  MOZ_ASSERT(aSource);
+
+  RefPtr<TexturedEffect> result;
+  if (aHost->GetReadFormat() == gfx::SurfaceFormat::YUV) {
+    MOZ_ASSERT(aHost->GetYUVColorSpace() != YUVColorSpace::UNKNOWN);
+    result = new EffectYCbCr(aSource, aHost->GetYUVColorSpace(), aSamplingFilter);
+  } else {
+    result = CreateTexturedEffect(aHost->GetReadFormat(),
+                                  aSource,
+                                  aSamplingFilter,
+                                  isAlphaPremultiplied,
+                                  state);
+  }
+  return result.forget();
+}
+
 /**
  * Create a textured effect based on aSource format and the presence of
  * aSourceOnWhite.
  *
  * aSourceOnWhite can be null.
  */
 inline already_AddRefed<TexturedEffect>
 CreateTexturedEffect(TextureSource* aSource,
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -668,54 +668,36 @@ SampleAnimations(Layer* aLayer, TimeStam
           AnimData& animData = animationData[i];
 
           activeAnimations = true;
 
           MOZ_ASSERT(!animation.startTime().IsNull(),
                      "Failed to resolve start time of pending animations");
           TimeDuration elapsedDuration =
             (aPoint - animation.startTime()).MultDouble(animation.playbackRate());
-          // Skip animations that are yet to start.
-          //
-          // Currently, this should only happen when the refresh driver is under test
-          // control and is made to produce a time in the past or is restored from
-          // test control causing it to jump backwards in time.
-          //
-          // Since activeAnimations is true, this could mean we keep compositing
-          // unnecessarily during the delay, but so long as this only happens while
-          // the refresh driver is under test control that should be ok.
-          if (elapsedDuration.ToSeconds() < 0) {
-            continue;
-          }
-
           TimingParams timing;
           timing.mDuration.emplace(animation.duration());
-          // Currently animations run on the compositor have their delay factored
-          // into their start time, hence the delay is effectively zero.
-          timing.mDelay = TimeDuration(0);
+          timing.mDelay = animation.delay();
           timing.mIterations = animation.iterations();
           timing.mIterationStart = animation.iterationStart();
           timing.mDirection =
             static_cast<dom::PlaybackDirection>(animation.direction());
-          // Animations typically only run on the compositor during their active
-          // interval but if we end up sampling them outside that range (for
-          // example, while they are waiting to be removed) we currently just
-          // assume that we should fill.
-          timing.mFill = dom::FillMode::Both;
+          timing.mFill = static_cast<dom::FillMode>(animation.fillMode());
           timing.mFunction =
             AnimationUtils::TimingFunctionToComputedTimingFunction(
               animation.easingFunction());
 
           ComputedTiming computedTiming =
             dom::AnimationEffectReadOnly::GetComputedTimingAt(
               Nullable<TimeDuration>(elapsedDuration), timing,
               animation.playbackRate());
 
-          MOZ_ASSERT(!computedTiming.mProgress.IsNull(),
-                     "iteration progress should not be null");
+          if (computedTiming.mProgress.IsNull()) {
+            continue;
+          }
 
           uint32_t segmentIndex = 0;
           size_t segmentSize = animation.segments().Length();
           AnimationSegment* segment = animation.segments().Elements();
           while (segment->endPortion() < computedTiming.mProgress.Value() &&
                  segmentIndex < segmentSize - 1) {
             ++segment;
             ++segmentIndex;
--- a/gfx/layers/composite/ImageHost.cpp
+++ b/gfx/layers/composite/ImageHost.cpp
@@ -346,17 +346,17 @@ ImageHost::Composite(LayerComposite* aLa
       // BindTextureSource above should have returned false!
       MOZ_ASSERT(false);
       return;
     }
 
     bool isAlphaPremultiplied =
         !(mCurrentTextureHost->GetFlags() & TextureFlags::NON_PREMULTIPLIED);
     RefPtr<TexturedEffect> effect =
-        CreateTexturedEffect(mCurrentTextureHost->GetReadFormat(),
+        CreateTexturedEffect(mCurrentTextureHost,
             mCurrentTextureSource.get(), aSamplingFilter, isAlphaPremultiplied,
             GetRenderState());
     if (!effect) {
       return;
     }
 
     if (!GetCompositor()->SupportsEffect(effect->mType)) {
       return;
@@ -606,17 +606,17 @@ ImageHost::GenEffect(const gfx::Sampling
   if (!mCurrentTextureHost->BindTextureSource(mCurrentTextureSource)) {
     return nullptr;
   }
   bool isAlphaPremultiplied = true;
   if (mCurrentTextureHost->GetFlags() & TextureFlags::NON_PREMULTIPLIED) {
     isAlphaPremultiplied = false;
   }
 
-  return CreateTexturedEffect(mCurrentTextureHost->GetReadFormat(),
+  return CreateTexturedEffect(mCurrentTextureHost,
                               mCurrentTextureSource,
                               aSamplingFilter,
                               isAlphaPremultiplied,
                               GetRenderState());
 }
 
 void
 ImageHost::SetImageContainer(ImageContainerParent* aImageContainer)
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -802,16 +802,26 @@ BufferTextureHost::GetFormat() const
   if (mFormat == gfx::SurfaceFormat::YUV &&
     mCompositor &&
     !mCompositor->SupportsEffect(EffectTypes::YCBCR)) {
     return gfx::SurfaceFormat::R8G8B8X8;
   }
   return mFormat;
 }
 
+YUVColorSpace
+BufferTextureHost::GetYUVColorSpace() const
+{
+  if (mFormat == gfx::SurfaceFormat::YUV) {
+    const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
+    return desc.yUVColorSpace();
+  }
+  return YUVColorSpace::UNKNOWN;
+}
+
 bool
 BufferTextureHost::MaybeUpload(nsIntRegion *aRegion)
 {
   auto serial = mFirstSource ? mFirstSource->GetUpdateSerial() : 0;
 
   if (serial == mUpdateSerial) {
     return true;
   }
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -416,16 +416,18 @@ public:
    */
   virtual gfx::SurfaceFormat GetFormat() const = 0;
   /**
    * Return the format used for reading the texture.
    * Apple's YCBCR_422 is R8G8B8X8.
    */
   virtual gfx::SurfaceFormat GetReadFormat() const { return GetFormat(); }
 
+  virtual YUVColorSpace GetYUVColorSpace() const { return YUVColorSpace::UNKNOWN; }
+
   /**
    * Called during the transaction. The TextureSource may or may not be composited.
    *
    * Note that this is called outside of lock/unlock.
    */
   virtual void PrepareTextureSource(CompositableTextureSourceRef& aTexture) {}
 
   /**
@@ -696,16 +698,18 @@ public:
    * Return the format that is exposed to the compositor when calling
    * BindTextureSource.
    *
    * If the shared format is YCbCr and the compositor does not support it,
    * GetFormat will be RGB32 (even though mFormat is SurfaceFormat::YUV).
    */
   virtual gfx::SurfaceFormat GetFormat() const override;
 
+  virtual YUVColorSpace GetYUVColorSpace() const override;
+
   virtual gfx::IntSize GetSize() const override { return mSize; }
 
   virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override;
 
   virtual bool HasIntermediateBuffer() const override { return mHasIntermediateBuffer; }
 
   virtual BufferTextureHost* AsBufferTextureHost() override { return this; }
 
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -14,16 +14,17 @@
 #include "mozilla/gfx/DeviceManagerDx.h"
 #include "mozilla/layers/ImageHost.h"
 #include "mozilla/layers/ContentHost.h"
 #include "mozilla/layers/Effects.h"
 #include "nsWindowsHelpers.h"
 #include "gfxPrefs.h"
 #include "gfxConfig.h"
 #include "gfxCrashReporterUtils.h"
+#include "gfxUtils.h"
 #include "mozilla/gfx/StackArray.h"
 #include "mozilla/Services.h"
 #include "mozilla/widget/WinCompositorWidget.h"
 
 #include "mozilla/EnumeratedArray.h"
 #include "mozilla/Telemetry.h"
 #include "BlendShaderConstants.h"
 
@@ -883,16 +884,19 @@ CompositorD3D11::DrawQuad(const gfx::Rec
       }
 
       if (!source->GetSubSource(Y) || !source->GetSubSource(Cb) || !source->GetSubSource(Cr)) {
         // This can happen if we failed to upload the textures, most likely
         // because of unsupported dimensions (we don't tile YCbCr textures).
         return;
       }
 
+      float* yuvToRgb = gfxUtils::Get4x3YuvColorMatrix(ycbcrEffect->mYUVColorSpace);
+      memcpy(&mPSConstants.yuvColorMatrix, yuvToRgb, sizeof(mPSConstants.yuvColorMatrix));
+
       TextureSourceD3D11* sourceY  = source->GetSubSource(Y)->AsSourceD3D11();
       TextureSourceD3D11* sourceCb = source->GetSubSource(Cb)->AsSourceD3D11();
       TextureSourceD3D11* sourceCr = source->GetSubSource(Cr)->AsSourceD3D11();
 
       ID3D11ShaderResourceView* srViews[3] = { sourceY->GetShaderResourceView(),
                                                sourceCb->GetShaderResourceView(),
                                                sourceCr->GetShaderResourceView() };
       mContext->PSSetShaderResources(TexSlot::Y, 3, srViews);
--- a/gfx/layers/d3d11/CompositorD3D11.h
+++ b/gfx/layers/d3d11/CompositorD3D11.h
@@ -30,16 +30,17 @@ struct VertexShaderConstants
   float backdropTransform[4][4];
 };
 
 struct PixelShaderConstants
 {
   float layerColor[4];
   float layerOpacity[4];
   int blendConfig[4];
+  float yuvColorMatrix[3][4];
 };
 
 struct DeviceAttachmentsD3D11;
 
 class CompositorD3D11 : public Compositor
 {
 public:
   CompositorD3D11(CompositorBridgeParent* aParent, widget::CompositorWidget* aWidget);
--- a/gfx/layers/d3d11/CompositorD3D11.hlsl
+++ b/gfx/layers/d3d11/CompositorD3D11.hlsl
@@ -20,16 +20,18 @@ float4 fLayerColor : register(ps, c0);
 float fLayerOpacity : register(ps, c1);
 
 // x = layer type
 // y = mask type
 // z = blend op
 // w = is premultiplied
 uint4 iBlendConfig : register(ps, c2);
 
+row_major float3x3 mYuvColorMatrix : register(ps, c3);
+
 sampler sSampler : register(ps, s0);
 
 // The mix-blend mega shader uses all variables, so we have to make sure they
 // are assigned fixed slots.
 Texture2D tRGB : register(ps, t0);
 Texture2D tY : register(ps, t1);
 Texture2D tCb : register(ps, t2);
 Texture2D tCr : register(ps, t3);
@@ -185,29 +187,37 @@ float4 RGBShaderMask(const VS_MASK_OUTPU
 [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]
 
 For [0,1] instead of [0,255], and to 5 places:
 [R]   [1.16438,  0.00000,  1.59603]   [ Y - 0.06275]
 [G] = [1.16438, -0.39176, -0.81297] x [Cb - 0.50196]
 [B]   [1.16438,  2.01723,  0.00000]   [Cr - 0.50196]
+
+From Rec709:
+[R]   [1.1643835616438356,  4.2781193979771426e-17, 1.7927410714285714]     [ Y -  16]
+[G] = [1.1643835616438358, -0.21324861427372963,   -0.532909328559444]    x [Cb - 128]
+[B]   [1.1643835616438356,  2.1124017857142854,     0.0]                    [Cr - 128]
+
+For [0,1] instead of [0,255], and to 5 places:
+[R]   [1.16438,  0.00000,  1.79274]   [ Y - 0.06275]
+[G] = [1.16438, -0.21325, -0.53291] x [Cb - 0.50196]
+[B]   [1.16438,  2.11240,  0.00000]   [Cr - 0.50196]
 */
 float4 CalculateYCbCrColor(const float2 aTexCoords)
 {
-  float4 yuv;
+  float3 yuv;
   float4 color;
 
-  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;
+  yuv.x = tY.Sample(sSampler, aTexCoords).r  - 0.06275;
+  yuv.y = tCb.Sample(sSampler, aTexCoords).r - 0.50196;
+  yuv.z = tCr.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.rgb = mul(mYuvColorMatrix, yuv);
   color.a = 1.0f;
 
   return color;
 }
 
 float4 YCbCrShaderMask(const VS_MASK_OUTPUT aVertex) : SV_Target
 {
   float2 maskCoords = aVertex.vMaskCoords.xy / aVertex.vMaskCoords.z;
old mode 100644
new mode 100755
--- a/gfx/layers/d3d11/CompositorD3D11Shaders.h
+++ b/gfx/layers/d3d11/CompositorD3D11Shaders.h
@@ -1,12 +1,12 @@
 struct ShaderBytes { const void* mData; size_t mLength; };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 10.0.10011.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 10.1
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4x4 mLayerTransform;          // Offset:    0 Size:    64
@@ -14,16 +14,17 @@ struct ShaderBytes { const void* mData; 
 //   float4 vRenderTargetOffset;        // Offset:  128 Size:    16
 //   float4 vTextureCoords;             // Offset:  144 Size:    16
 //   float4 vLayerQuad;                 // Offset:  160 Size:    16
 //   float4 vMaskQuad;                  // Offset:  176 Size:    16 [unused]
 //   float4x4 mBackdropTransform;       // Offset:  192 Size:    64 [unused]
 //   float4 fLayerColor;                // Offset:  256 Size:    16 [unused]
 //   float fLayerOpacity;               // Offset:  272 Size:     4 [unused]
 //   uint4 iBlendConfig;                // Offset:  288 Size:    16 [unused]
+//   row_major float3x3 mYuvColorMatrix;// Offset:  304 Size:    44 [unused]
 //
 // }
 //
 //
 // Resource Bindings:
 //
 // Name                                 Type  Format         Dim      HLSL Bind  Count
 // ------------------------------ ---------- ------- ----------- -------------- ------
@@ -101,25 +102,25 @@ 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, 112,  85, 
-    167,  74,  15, 232,  29,  85, 
-    162,  39, 212, 215,  65, 102, 
-    169, 150,   1,   0,   0,   0, 
-     24,   7,   0,   0,   6,   0, 
+     68,  88,  66,  67, 250,  65, 
+     94, 205, 254, 155,  52,  90, 
+     43, 147, 203, 201, 141,  74, 
+     80, 143,   1,   0,   0,   0, 
+     68,   7,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     152,   1,   0,   0, 160,   3, 
       0,   0,  28,   4,   0,   0, 
-    140,   6,   0,   0, 192,   6, 
+    184,   6,   0,   0, 236,   6, 
       0,   0,  65, 111, 110,  57, 
      88,   1,   0,   0,  88,   1, 
       0,   0,   0,   2, 254, 255, 
      24,   1,   0,   0,  64,   0, 
       0,   0,   2,   0,  36,   0, 
       0,   0,  60,   0,   0,   0, 
      60,   0,   0,   0,  36,   0, 
       1,   0,  60,   0,   0,   0, 
@@ -277,72 +278,76 @@ const BYTE LayerQuadVS[] =
       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,  82,  68,  69,  70, 
-    104,   2,   0,   0,   1,   0, 
+    148,   2,   0,   0,   1,   0, 
       0,   0,  72,   0,   0,   0, 
       1,   0,   0,   0,  28,   0, 
       0,   0,   0,   4, 254, 255, 
-      0,   1,   0,   0,  52,   2, 
+      0,   1,   0,   0, 108,   2, 
       0,   0,  60,   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,  36,  71, 
     108, 111,  98,  97, 108, 115, 
       0, 171, 171, 171,  60,   0, 
-      0,   0,  10,   0,   0,   0, 
-     96,   0,   0,   0,  48,   1, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,  80,   1, 
+      0,   0,  11,   0,   0,   0, 
+     96,   0,   0,   0,  96,   1, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0, 104,   1, 
       0,   0,   0,   0,   0,   0, 
      64,   0,   0,   0,   2,   0, 
-      0,   0,  96,   1,   0,   0, 
-      0,   0,   0,   0, 112,   1, 
+      0,   0, 120,   1,   0,   0, 
+      0,   0,   0,   0, 136,   1, 
       0,   0,  64,   0,   0,   0, 
      64,   0,   0,   0,   2,   0, 
-      0,   0,  96,   1,   0,   0, 
-      0,   0,   0,   0, 124,   1, 
+      0,   0, 120,   1,   0,   0, 
+      0,   0,   0,   0, 148,   1, 
       0,   0, 128,   0,   0,   0, 
      16,   0,   0,   0,   2,   0, 
-      0,   0, 144,   1,   0,   0, 
-      0,   0,   0,   0, 160,   1, 
+      0,   0, 168,   1,   0,   0, 
+      0,   0,   0,   0, 184,   1, 
       0,   0, 144,   0,   0,   0, 
      16,   0,   0,   0,   2,   0, 
-      0,   0, 176,   1,   0,   0, 
-      0,   0,   0,   0, 192,   1, 
+      0,   0, 200,   1,   0,   0, 
+      0,   0,   0,   0, 216,   1, 
       0,   0, 160,   0,   0,   0, 
      16,   0,   0,   0,   2,   0, 
-      0,   0, 176,   1,   0,   0, 
-      0,   0,   0,   0, 203,   1, 
+      0,   0, 200,   1,   0,   0, 
+      0,   0,   0,   0, 227,   1, 
       0,   0, 176,   0,   0,   0, 
      16,   0,   0,   0,   0,   0, 
-      0,   0, 176,   1,   0,   0, 
-      0,   0,   0,   0, 213,   1, 
+      0,   0, 200,   1,   0,   0, 
+      0,   0,   0,   0, 237,   1, 
       0,   0, 192,   0,   0,   0, 
      64,   0,   0,   0,   0,   0, 
-      0,   0,  96,   1,   0,   0, 
-      0,   0,   0,   0, 232,   1, 
+      0,   0, 120,   1,   0,   0, 
+      0,   0,   0,   0,   0,   2, 
       0,   0,   0,   1,   0,   0, 
      16,   0,   0,   0,   0,   0, 
-      0,   0, 144,   1,   0,   0, 
-      0,   0,   0,   0, 244,   1, 
+      0,   0, 168,   1,   0,   0, 
+      0,   0,   0,   0,  12,   2, 
       0,   0,  16,   1,   0,   0, 
       4,   0,   0,   0,   0,   0, 
-      0,   0,   4,   2,   0,   0, 
-      0,   0,   0,   0,  20,   2, 
+      0,   0,  28,   2,   0,   0, 
+      0,   0,   0,   0,  44,   2, 
       0,   0,  32,   1,   0,   0, 
      16,   0,   0,   0,   0,   0, 
-      0,   0,  36,   2,   0,   0, 
+      0,   0,  60,   2,   0,   0, 
+      0,   0,   0,   0,  76,   2, 
+      0,   0,  48,   1,   0,   0, 
+     44,   0,   0,   0,   0,   0, 
+      0,   0,  92,   2,   0,   0, 
       0,   0,   0,   0, 109,  76, 
      97, 121, 101, 114,  84, 114, 
      97, 110, 115, 102, 111, 114, 
     109,   0,   3,   0,   3,   0, 
       4,   0,   4,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
     109,  80, 114, 111, 106, 101, 
      99, 116, 105, 111, 110,   0, 
@@ -371,71 +376,75 @@ const BYTE LayerQuadVS[] =
     121,   0, 171, 171,   0,   0, 
       3,   0,   1,   0,   1,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0, 105,  66, 108, 101, 
     110, 100,  67, 111, 110, 102, 
     105, 103,   0, 171, 171, 171, 
       1,   0,  19,   0,   1,   0, 
       4,   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,  49,  48,  46, 
-     48,  46,  49,  48,  48,  49, 
-     49,  46,  49,  54,  51,  56, 
-     52,   0,  73,  83,  71,  78, 
-     44,   0,   0,   0,   1,   0, 
+      0,   0,   0,   0, 109,  89, 
+    117, 118,  67, 111, 108, 111, 
+    114,  77,  97, 116, 114, 105, 
+    120,   0,   2,   0,   3,   0, 
+      3,   0,   3,   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,  49, 
+     48,  46,  49,   0,  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, 
+    171, 171,  79,  83,  71,  78, 
+     80,   0,   0,   0,   2,   0, 
       0,   0,   8,   0,   0,   0, 
-     32,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
+     56,   0,   0,   0,   0,   0, 
+      0,   0,   1,   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, 171, 171, 
-     79,  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,   0,   0,   3,   0, 
-      0,   0,   1,   0,   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
+      0,   0,  15,   0,   0,   0, 
+     68,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      3,   0,   0,   0,   1,   0, 
+      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
 };
 ShaderBytes sLayerQuadVS = { LayerQuadVS, sizeof(LayerQuadVS) };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 10.0.10011.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 10.1
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16
 //   float fLayerOpacity;               // Offset:   16 Size:     4 [unused]
 //   uint4 iBlendConfig;                // Offset:   32 Size:    16 [unused]
-//   float4x4 mLayerTransform;          // Offset:   48 Size:    64 [unused]
-//   float4x4 mProjection;              // Offset:  112 Size:    64 [unused]
-//   float4 vRenderTargetOffset;        // Offset:  176 Size:    16 [unused]
-//   float4 vTextureCoords;             // Offset:  192 Size:    16 [unused]
-//   float4 vLayerQuad;                 // Offset:  208 Size:    16 [unused]
-//   float4 vMaskQuad;                  // Offset:  224 Size:    16 [unused]
-//   float4x4 mBackdropTransform;       // Offset:  240 Size:    64 [unused]
+//   row_major float3x3 mYuvColorMatrix;// Offset:   48 Size:    44 [unused]
+//   float4x4 mLayerTransform;          // Offset:   96 Size:    64 [unused]
+//   float4x4 mProjection;              // Offset:  160 Size:    64 [unused]
+//   float4 vRenderTargetOffset;        // Offset:  224 Size:    16 [unused]
+//   float4 vTextureCoords;             // Offset:  240 Size:    16 [unused]
+//   float4 vLayerQuad;                 // Offset:  256 Size:    16 [unused]
+//   float4 vMaskQuad;                  // Offset:  272 Size:    16 [unused]
+//   float4x4 mBackdropTransform;       // Offset:  288 Size:    64 [unused]
 //
 // }
 //
 //
 // Resource Bindings:
 //
 // Name                                 Type  Format         Dim      HLSL Bind  Count
 // ------------------------------ ---------- ------- ----------- -------------- ------
@@ -476,25 +485,25 @@ 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, 232, 227, 
-     42, 205, 188, 244, 239,  58, 
-     34,  67,  23,  11,   8, 108, 
-    224,  50,   1,   0,   0,   0, 
-     68,   4,   0,   0,   6,   0, 
+     68,  88,  66,  67, 181,   3, 
+     20,   0, 202,  78, 164,  59, 
+    210, 171, 118, 253, 118, 104, 
+    133, 184,   1,   0,   0,   0, 
+    112,   4,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     132,   0,   0,   0, 204,   0, 
       0,   0,  72,   1,   0,   0, 
-    184,   3,   0,   0,  16,   4, 
+    228,   3,   0,   0,  60,   4, 
       0,   0,  65, 111, 110,  57, 
      68,   0,   0,   0,  68,   0, 
       0,   0,   0,   2, 255, 255, 
      20,   0,   0,   0,  48,   0, 
       0,   0,   1,   0,  36,   0, 
       0,   0,  48,   0,   0,   0, 
      48,   0,   0,   0,  36,   0, 
       0,   0,  48,   0,   0,   0, 
@@ -531,165 +540,174 @@ const BYTE SolidColorShader[] =
       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, 104,   2,   0,   0, 
+     69,  70, 148,   2,   0,   0, 
       1,   0,   0,   0,  72,   0, 
       0,   0,   1,   0,   0,   0, 
      28,   0,   0,   0,   0,   4, 
     255, 255,   0,   1,   0,   0, 
-     52,   2,   0,   0,  60,   0, 
+    108,   2,   0,   0,  60,   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, 
      36,  71, 108, 111,  98,  97, 
     108, 115,   0, 171, 171, 171, 
-     60,   0,   0,   0,  10,   0, 
+     60,   0,   0,   0,  11,   0, 
       0,   0,  96,   0,   0,   0, 
-     48,   1,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-     80,   1,   0,   0,   0,   0, 
+     96,   1,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+    104,   1,   0,   0,   0,   0, 
       0,   0,  16,   0,   0,   0, 
-      2,   0,   0,   0,  92,   1, 
-      0,   0,   0,   0,   0,   0, 
-    108,   1,   0,   0,  16,   0, 
+      2,   0,   0,   0, 116,   1, 
+      0,   0,   0,   0,   0,   0, 
+    132,   1,   0,   0,  16,   0, 
       0,   0,   4,   0,   0,   0, 
-      0,   0,   0,   0, 124,   1, 
-      0,   0,   0,   0,   0,   0, 
-    140,   1,   0,   0,  32,   0, 
+      0,   0,   0,   0, 148,   1, 
+      0,   0,   0,   0,   0,   0, 
+    164,   1,   0,   0,  32,   0, 
       0,   0,  16,   0,   0,   0, 
-      0,   0,   0,   0, 156,   1, 
-      0,   0,   0,   0,   0,   0, 
-    172,   1,   0,   0,  48,   0, 
-      0,   0,  64,   0,   0,   0, 
-      0,   0,   0,   0, 188,   1, 
-      0,   0,   0,   0,   0,   0, 
-    204,   1,   0,   0, 112,   0, 
+      0,   0,   0,   0, 180,   1, 
+      0,   0,   0,   0,   0,   0, 
+    196,   1,   0,   0,  48,   0, 
+      0,   0,  44,   0,   0,   0, 
+      0,   0,   0,   0, 212,   1, 
+      0,   0,   0,   0,   0,   0, 
+    228,   1,   0,   0,  96,   0, 
       0,   0,  64,   0,   0,   0, 
-      0,   0,   0,   0, 188,   1, 
-      0,   0,   0,   0,   0,   0, 
-    216,   1,   0,   0, 176,   0, 
+      0,   0,   0,   0, 244,   1, 
+      0,   0,   0,   0,   0,   0, 
+      4,   2,   0,   0, 160,   0, 
+      0,   0,  64,   0,   0,   0, 
+      0,   0,   0,   0, 244,   1, 
+      0,   0,   0,   0,   0,   0, 
+     16,   2,   0,   0, 224,   0, 
       0,   0,  16,   0,   0,   0, 
-      0,   0,   0,   0,  92,   1, 
-      0,   0,   0,   0,   0,   0, 
-    236,   1,   0,   0, 192,   0, 
+      0,   0,   0,   0, 116,   1, 
+      0,   0,   0,   0,   0,   0, 
+     36,   2,   0,   0, 240,   0, 
       0,   0,  16,   0,   0,   0, 
-      0,   0,   0,   0, 252,   1, 
-      0,   0,   0,   0,   0,   0, 
-     12,   2,   0,   0, 208,   0, 
+      0,   0,   0,   0,  52,   2, 
+      0,   0,   0,   0,   0,   0, 
+     68,   2,   0,   0,   0,   1, 
       0,   0,  16,   0,   0,   0, 
-      0,   0,   0,   0, 252,   1, 
-      0,   0,   0,   0,   0,   0, 
-     23,   2,   0,   0, 224,   0, 
+      0,   0,   0,   0,  52,   2, 
+      0,   0,   0,   0,   0,   0, 
+     79,   2,   0,   0,  16,   1, 
       0,   0,  16,   0,   0,   0, 
-      0,   0,   0,   0, 252,   1, 
-      0,   0,   0,   0,   0,   0, 
-     33,   2,   0,   0, 240,   0, 
+      0,   0,   0,   0,  52,   2, 
+      0,   0,   0,   0,   0,   0, 
+     89,   2,   0,   0,  32,   1, 
       0,   0,  64,   0,   0,   0, 
-      0,   0,   0,   0, 188,   1, 
+      0,   0,   0,   0, 244,   1, 
       0,   0,   0,   0,   0,   0, 
     102,  76,  97, 121, 101, 114, 
      67, 111, 108, 111, 114,   0, 
       1,   0,   3,   0,   1,   0, 
       4,   0,   0,   0,   0,   0, 
       0,   0,   0,   0, 102,  76, 
      97, 121, 101, 114,  79, 112, 
      97,  99, 105, 116, 121,   0, 
     171, 171,   0,   0,   3,   0, 
       1,   0,   1,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
     105,  66, 108, 101, 110, 100, 
      67, 111, 110, 102, 105, 103, 
       0, 171, 171, 171,   1,   0, 
      19,   0,   1,   0,   4,   0, 
       0,   0,   0,   0,   0,   0, 
-      0,   0, 109,  76,  97, 121, 
-    101, 114,  84, 114,  97, 110, 
-    115, 102, 111, 114, 109,   0, 
-      3,   0,   3,   0,   4,   0, 
+      0,   0, 109,  89, 117, 118, 
+     67, 111, 108, 111, 114,  77, 
+     97, 116, 114, 105, 120,   0, 
+      2,   0,   3,   0,   3,   0, 
+      3,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0, 109,  76, 
+     97, 121, 101, 114,  84, 114, 
+     97, 110, 115, 102, 111, 114, 
+    109,   0,   3,   0,   3,   0, 
+      4,   0,   4,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+    109,  80, 114, 111, 106, 101, 
+     99, 116, 105, 111, 110,   0, 
+    118,  82, 101, 110, 100, 101, 
+    114,  84,  97, 114, 103, 101, 
+    116,  79, 102, 102, 115, 101, 
+    116,   0, 118,  84, 101, 120, 
+    116, 117, 114, 101,  67, 111, 
+    111, 114, 100, 115,   0, 171, 
+      1,   0,   3,   0,   1,   0, 
       4,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0, 109,  80, 
-    114, 111, 106, 101,  99, 116, 
-    105, 111, 110,   0, 118,  82, 
-    101, 110, 100, 101, 114,  84, 
-     97, 114, 103, 101, 116,  79, 
-    102, 102, 115, 101, 116,   0, 
-    118,  84, 101, 120, 116, 117, 
-    114, 101,  67, 111, 111, 114, 
-    100, 115,   0, 171,   1,   0, 
-      3,   0,   1,   0,   4,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0, 118,  76,  97, 121, 
-    101, 114,  81, 117,  97, 100, 
-      0, 118,  77,  97, 115, 107, 
-     81, 117,  97, 100,   0, 109, 
-     66,  97,  99, 107, 100, 114, 
-    111, 112,  84, 114,  97, 110, 
-    115, 102, 111, 114, 109,   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,  49, 
-     48,  46,  48,  46,  49,  48, 
-     48,  49,  49,  46,  49,  54, 
-     51,  56,  52,   0,  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,   0,   0, 118,  76, 
+     97, 121, 101, 114,  81, 117, 
+     97, 100,   0, 118,  77,  97, 
+    115, 107,  81, 117,  97, 100, 
+      0, 109,  66,  97,  99, 107, 
+    100, 114, 111, 112,  84, 114, 
+     97, 110, 115, 102, 111, 114, 
+    109,   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,  49,  48,  46,  49,   0, 
+     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,   0,   0,   3,   0, 
+      0,   0,   1,   0,   0,   0, 
+      3,   0,   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,  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,  68,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   3,   0,   0,   0, 
-      1,   0,   0,   0,   3,   0, 
-      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,  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
+      0,   0,  83,  86,  95,  84, 
+     97, 114, 103, 101, 116,   0, 
+    171, 171
 };
 ShaderBytes sSolidColorShader = { SolidColorShader, sizeof(SolidColorShader) };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 10.0.10011.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 10.1
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16 [unused]
 //   float fLayerOpacity;               // Offset:   16 Size:     4
 //   uint4 iBlendConfig;                // Offset:   32 Size:    16 [unused]
-//   float4x4 mLayerTransform;          // Offset:   48 Size:    64 [unused]
-//   float4x4 mProjection;              // Offset:  112 Size:    64 [unused]
-//   float4 vRenderTargetOffset;        // Offset:  176 Size:    16 [unused]
-//   float4 vTextureCoords;             // Offset:  192 Size:    16 [unused]
-//   float4 vLayerQuad;                 // Offset:  208 Size:    16 [unused]
-//   float4 vMaskQuad;                  // Offset:  224 Size:    16 [unused]
-//   float4x4 mBackdropTransform;       // Offset:  240 Size:    64 [unused]
+//   row_major float3x3 mYuvColorMatrix;// Offset:   48 Size:    44 [unused]
+//   float4x4 mLayerTransform;          // Offset:   96 Size:    64 [unused]
+//   float4x4 mProjection;              // Offset:  160 Size:    64 [unused]
+//   float4 vRenderTargetOffset;        // Offset:  224 Size:    16 [unused]
+//   float4 vTextureCoords;             // Offset:  240 Size:    16 [unused]
+//   float4 vLayerQuad;                 // Offset:  256 Size:    16 [unused]
+//   float4 vMaskQuad;                  // Offset:  272 Size:    16 [unused]
+//   float4x4 mBackdropTransform;       // Offset:  288 Size:    64 [unused]
 //
 // }
 //
 //
 // Resource Bindings:
 //
 // Name                                 Type  Format         Dim      HLSL Bind  Count
 // ------------------------------ ---------- ------- ----------- -------------- ------
@@ -750,25 +768,25 @@ 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, 125, 240, 
-    204, 179, 182, 100,  41,   5, 
-      9, 193, 104, 239, 180, 186, 
-    251,   1,   1,   0,   0,   0, 
-     76,   5,   0,   0,   6,   0, 
+     68,  88,  66,  67, 181,  57, 
+    113, 191, 104, 206, 206,  65, 
+    235, 158,  87, 241, 179, 224, 
+     69, 235,   1,   0,   0,   0, 
+    120,   5,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     204,   0,   0,   0, 136,   1, 
       0,   0,   4,   2,   0,   0, 
-    192,   4,   0,   0,  24,   5, 
+    236,   4,   0,   0,  68,   5, 
       0,   0,  65, 111, 110,  57, 
     140,   0,   0,   0, 140,   0, 
       0,   0,   0,   2, 255, 255, 
      88,   0,   0,   0,  52,   0, 
       0,   0,   1,   0,  40,   0, 
       0,   0,  52,   0,   0,   0, 
      52,   0,   1,   0,  36,   0, 
       0,   0,  52,   0,   0,   0, 
@@ -836,22 +854,22 @@ const BYTE RGBShader[] =
       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, 180,   2, 
+     82,  68,  69,  70, 224,   2, 
       0,   0,   1,   0,   0,   0, 
     148,   0,   0,   0,   3,   0, 
       0,   0,  28,   0,   0,   0, 
       0,   4, 255, 255,   0,   1, 
-      0,   0, 128,   2,   0,   0, 
+      0,   0, 184,   2,   0,   0, 
     124,   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,   1,   0, 
       0,   0, 133,   0,   0,   0, 
       2,   0,   0,   0,   5,   0, 
       0,   0,   4,   0,   0,   0, 
@@ -862,152 +880,161 @@ const BYTE RGBShader[] =
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   1,   0, 
       0,   0,   0,   0,   0,   0, 
     115,  83,  97, 109, 112, 108, 
     101, 114,   0, 116,  82,  71, 
      66,   0,  36,  71, 108, 111, 
      98,  97, 108, 115,   0, 171, 
-    138,   0,   0,   0,  10,   0, 
+    138,   0,   0,   0,  11,   0, 
       0,   0, 172,   0,   0,   0, 
-     48,   1,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-    156,   1,   0,   0,   0,   0, 
+     96,   1,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+    180,   1,   0,   0,   0,   0, 
       0,   0,  16,   0,   0,   0, 
-      0,   0,   0,   0, 168,   1, 
-      0,   0,   0,   0,   0,   0, 
-    184,   1,   0,   0,  16,   0, 
+      0,   0,   0,   0, 192,   1, 
+      0,   0,   0,   0,   0,   0, 
+    208,   1,   0,   0,  16,   0, 
       0,   0,   4,   0,   0,   0, 
-      2,   0,   0,   0, 200,   1, 
-      0,   0,   0,   0,   0,   0, 
-    216,   1,   0,   0,  32,   0, 
+      2,   0,   0,   0, 224,   1, 
+      0,   0,   0,   0,   0,   0, 
+    240,   1,   0,   0,  32,   0, 
       0,   0,  16,   0,   0,   0, 
-      0,   0,   0,   0, 232,   1, 
-      0,   0,   0,   0,   0,   0, 
-    248,   1,   0,   0,  48,   0, 
-      0,   0,  64,   0,   0,   0, 
-      0,   0,   0,   0,   8,   2, 
-      0,   0,   0,   0,   0,   0, 
-     24,   2,   0,   0, 112,   0, 
+      0,   0,   0,   0,   0,   2, 
+      0,   0,   0,   0,   0,   0, 
+     16,   2,   0,   0,  48,   0, 
+      0,   0,  44,   0,   0,   0, 
+      0,   0,   0,   0,  32,   2, 
+      0,   0,   0,   0,   0,   0, 
+     48,   2,   0,   0,  96,   0, 
       0,   0,  64,   0,   0,   0, 
-      0,   0,   0,   0,   8,   2, 
-      0,   0,   0,   0,   0,   0, 
-     36,   2,   0,   0, 176,   0, 
+      0,   0,   0,   0,  64,   2, 
+      0,   0,   0,   0,   0,   0, 
+     80,   2,   0,   0, 160,   0, 
+      0,   0,  64,   0,   0,   0, 
+      0,   0,   0,   0,  64,   2, 
+      0,   0,   0,   0,   0,   0, 
+     92,   2,   0,   0, 224,   0, 
       0,   0,  16,   0,   0,   0, 
-      0,   0,   0,   0, 168,   1, 
-      0,   0,   0,   0,   0,   0, 
-     56,   2,   0,   0, 192,   0, 
+      0,   0,   0,   0, 192,   1, 
+      0,   0,   0,   0,   0,   0, 
+    112,   2,   0,   0, 240,   0, 
       0,   0,  16,   0,   0,   0, 
-      0,   0,   0,   0,  72,   2, 
-      0,   0,   0,   0,   0,   0, 
-     88,   2,   0,   0, 208,   0, 
+      0,   0,   0,   0, 128,   2, 
+      0,   0,   0,   0,   0,   0, 
+    144,   2,   0,   0,   0,   1, 
       0,   0,  16,   0,   0,   0, 
-      0,   0,   0,   0,  72,   2, 
-      0,   0,   0,   0,   0,   0, 
-     99,   2,   0,   0, 224,   0, 
+      0,   0,   0,   0, 128,   2, 
+      0,   0,   0,   0,   0,   0, 
+    155,   2,   0,   0,  16,   1, 
       0,   0,  16,   0,   0,   0, 
-      0,   0,   0,   0,  72,   2, 
-      0,   0,   0,   0,   0,   0, 
-    109,   2,   0,   0, 240,   0, 
+      0,   0,   0,   0, 128,   2, 
+      0,   0,   0,   0,   0,   0, 
+    165,   2,   0,   0,  32,   1, 
       0,   0,  64,   0,   0,   0, 
-      0,   0,   0,   0,   8,   2, 
+      0,   0,   0,   0,  64,   2, 
       0,   0,   0,   0,   0,   0, 
     102,  76,  97, 121, 101, 114, 
      67, 111, 108, 111, 114,   0, 
       1,   0,   3,   0,   1,   0, 
       4,   0,   0,   0,   0,   0, 
       0,   0,   0,   0, 102,  76, 
      97, 121, 101, 114,  79, 112, 
      97,  99, 105, 116, 121,   0, 
     171, 171,   0,   0,   3,   0, 
       1,   0,   1,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
     105,  66, 108, 101, 110, 100, 
      67, 111, 110, 102, 105, 103, 
       0, 171, 171, 171,   1,   0, 
      19,   0,   1,   0,   4,   0, 
       0,   0,   0,   0,   0,   0, 
-      0,   0, 109,  76,  97, 121, 
-    101, 114,  84, 114,  97, 110, 
-    115, 102, 111, 114, 109,   0, 
-      3,   0,   3,   0,   4,   0, 
+      0,   0, 109,  89, 117, 118, 
+     67, 111, 108, 111, 114,  77, 
+     97, 116, 114, 105, 120,   0, 
+      2,   0,   3,   0,   3,   0, 
+      3,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0, 109,  76, 
+     97, 121, 101, 114,  84, 114, 
+     97, 110, 115, 102, 111, 114, 
+    109,   0,   3,   0,   3,   0, 
+      4,   0,   4,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+    109,  80, 114, 111, 106, 101, 
+     99, 116, 105, 111, 110,   0, 
+    118,  82, 101, 110, 100, 101, 
+    114,  84,  97, 114, 103, 101, 
+    116,  79, 102, 102, 115, 101, 
+    116,   0, 118,  84, 101, 120, 
+    116, 117, 114, 101,  67, 111, 
+    111, 114, 100, 115,   0, 171, 
+      1,   0,   3,   0,   1,   0, 
       4,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0, 109,  80, 
-    114, 111, 106, 101,  99, 116, 
-    105, 111, 110,   0, 118,  82, 
-    101, 110, 100, 101, 114,  84, 
-     97, 114, 103, 101, 116,  79, 
-    102, 102, 115, 101, 116,   0, 
-    118,  84, 101, 120, 116, 117, 
-    114, 101,  67, 111, 111, 114, 
-    100, 115,   0, 171,   1,   0, 
-      3,   0,   1,   0,   4,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0, 118,  76,  97, 121, 
-    101, 114,  81, 117,  97, 100, 
-      0, 118,  77,  97, 115, 107, 
-     81, 117,  97, 100,   0, 109, 
-     66,  97,  99, 107, 100, 114, 
-    111, 112,  84, 114,  97, 110, 
-    115, 102, 111, 114, 109,   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,  49, 
-     48,  46,  48,  46,  49,  48, 
-     48,  49,  49,  46,  49,  54, 
-     51,  56,  52,   0,  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,   0,   0, 118,  76, 
+     97, 121, 101, 114,  81, 117, 
+     97, 100,   0, 118,  77,  97, 
+    115, 107,  81, 117,  97, 100, 
+      0, 109,  66,  97,  99, 107, 
+    100, 114, 111, 112,  84, 114, 
+     97, 110, 115, 102, 111, 114, 
+    109,   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,  49,  48,  46,  49,   0, 
+     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,   0,   0,   3,   0, 
+      0,   0,   1,   0,   0,   0, 
+      3,   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,  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,  68,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   3,   0,   0,   0, 
-      1,   0,   0,   0,   3,   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,  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
+      0,   0,  83,  86,  95,  84, 
+     97, 114, 103, 101, 116,   0, 
+    171, 171
 };
 ShaderBytes sRGBShader = { RGBShader, sizeof(RGBShader) };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 10.0.10011.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 10.1
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16 [unused]
 //   float fLayerOpacity;               // Offset:   16 Size:     4
 //   uint4 iBlendConfig;                // Offset:   32 Size:    16 [unused]
-//   float4x4 mLayerTransform;          // Offset:   48 Size:    64 [unused]
-//   float4x4 mProjection;              // Offset:  112 Size:    64 [unused]
-//   float4 vRenderTargetOffset;        // Offset:  176 Size:    16 [unused]
-//   float4 vTextureCoords;             // Offset:  192 Size:    16 [unused]
-//   float4 vLayerQuad;                 // Offset:  208 Size:    16 [unused]
-//   float4 vMaskQuad;                  // Offset:  224 Size:    16 [unused]
-//   float4x4 mBackdropTransform;       // Offset:  240 Size:    64 [unused]
+//   row_major float3x3 mYuvColorMatrix;// Offset:   48 Size:    44 [unused]
+//   float4x4 mLayerTransform;          // Offset:   96 Size:    64 [unused]
+//   float4x4 mProjection;              // Offset:  160 Size:    64 [unused]
+//   float4 vRenderTargetOffset;        // Offset:  224 Size:    16 [unused]
+//   float4 vTextureCoords;             // Offset:  240 Size:    16 [unused]
+//   float4 vLayerQuad;                 // Offset:  256 Size:    16 [unused]
+//   float4 vMaskQuad;                  // Offset:  272 Size:    16 [unused]
+//   float4x4 mBackdropTransform;       // Offset:  288 Size:    64 [unused]
 //
 // }
 //
 //
 // Resource Bindings:
 //
 // Name                                 Type  Format         Dim      HLSL Bind  Count
 // ------------------------------ ---------- ------- ----------- -------------- ------
@@ -1066,25 +1093,25 @@ 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, 199, 240, 
-    113, 171,  34, 194, 134, 123, 
-    243,  63, 156, 246,   8, 157, 
-     15,  85,   1,   0,   0,   0, 
-     40,   5,   0,   0,   6,   0, 
+     68,  88,  66,  67,   0,  64, 
+     93, 222,  73, 216, 128,  20, 
+     42,  69,  82, 179, 209, 122, 
+    136, 190,   1,   0,   0,   0, 
+     84,   5,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     192,   0,   0,   0, 100,   1, 
       0,   0, 224,   1,   0,   0, 
-    156,   4,   0,   0, 244,   4, 
+    200,   4,   0,   0,  32,   5, 
       0,   0,  65, 111, 110,  57, 
     128,   0,   0,   0, 128,   0, 
       0,   0,   0,   2, 255, 255, 
      76,   0,   0,   0,  52,   0, 
       0,   0,   1,   0,  40,   0, 
       0,   0,  52,   0,   0,   0, 
      52,   0,   1,   0,  36,   0, 
       0,   0,  52,   0,   0,   0, 
@@ -1146,22 +1173,22 @@ const BYTE RGBAShader[] =
       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, 
-     82,  68,  69,  70, 180,   2, 
+     82,  68,  69,  70, 224,   2, 
       0,   0,   1,   0,   0,   0, 
     148,   0,   0,   0,   3,   0, 
       0,   0,  28,   0,   0,   0, 
       0,   4, 255, 255,   0,   1, 
-      0,   0, 128,   2,   0,   0, 
+      0,   0, 184,   2,   0,   0, 
     124,   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,   1,   0, 
       0,   0, 133,   0,   0,   0, 
       2,   0,   0,   0,   5,   0, 
       0,   0,   4,   0,   0,   0, 
@@ -1172,152 +1199,161 @@ const BYTE RGBAShader[] =
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   1,   0, 
       0,   0,   0,   0,   0,   0, 
     115,  83,  97, 109, 112, 108, 
     101, 114,   0, 116,  82,  71, 
      66,   0,  36,  71, 108, 111, 
      98,  97, 108, 115,   0, 171, 
-    138,   0,   0,   0,  10,   0, 
+    138,   0,   0,   0,  11,   0, 
       0,   0, 172,   0,   0,   0, 
-     48,   1,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-    156,   1,   0,   0,   0,   0, 
+     96,   1,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+    180,   1,   0,   0,   0,   0, 
       0,   0,  16,   0,   0,   0, 
-      0,   0,   0,   0, 168,   1, 
-      0,   0,   0,   0,   0,   0, 
-    184,   1,   0,   0,  16,   0, 
+      0,   0,   0,   0, 192,   1, 
+      0,   0,   0,   0,   0,   0, 
+    208,   1,   0,   0,  16,   0, 
       0,   0,   4,   0,   0,   0, 
-      2,   0,   0,   0, 200,   1, 
-      0,   0,   0,   0,   0,   0, 
-    216,   1,   0,   0,  32,   0, 
+      2,   0,   0,   0, 224,   1, 
+      0,   0,   0,   0,   0,   0, 
+    240,   1,   0,   0,  32,   0, 
       0,   0,  16,   0,   0,   0, 
-      0,   0,   0,   0, 232,   1, 
-      0,   0,   0,   0,   0,   0, 
-    248,   1,   0,   0,  48,   0, 
-      0,   0,  64,   0,   0,   0, 
-      0,   0,   0,   0,   8,   2, 
-      0,   0,   0,   0,   0,   0, 
-     24,   2,   0,   0, 112,   0, 
+      0,   0,   0,   0,   0,   2, 
+      0,   0,   0,   0,   0,   0, 
+     16,   2,   0,   0,  48,   0, 
+      0,   0,  44,   0,   0,   0, 
+      0,   0,   0,   0,  32,   2, 
+      0,   0,   0,   0,   0,   0, 
+     48,   2,   0,   0,  96,   0, 
       0,   0,  64,   0,   0,   0, 
-      0,   0,   0,   0,   8,   2, 
-      0,   0,   0,   0,   0,   0, 
-     36,   2,   0,   0, 176,   0, 
+      0,   0,   0,   0,  64,   2, 
+      0,   0,   0,   0,   0,   0, 
+     80,   2,   0,   0, 160,   0, 
+      0,   0,  64,   0,   0,   0, 
+      0,   0,   0,   0,  64,   2, 
+      0,   0,   0,   0,   0,   0, 
+     92,   2,   0,   0, 224,   0, 
       0,   0,  16,   0,   0,   0, 
-      0,   0,   0,   0, 168,   1, 
-      0,   0,   0,   0,   0,   0, 
-     56,   2,   0,   0, 192,   0, 
+      0,   0,   0,   0, 192,   1, 
+      0,   0,   0,   0,   0,   0, 
+    112,   2,   0,   0, 240,   0, 
       0,   0,  16,   0,   0,   0, 
-      0,   0,   0,   0,  72,   2, 
-      0,   0,   0,   0,   0,   0, 
-     88,   2,   0,   0, 208,   0, 
+      0,   0,   0,   0, 128,   2, 
+      0,   0,   0,   0,   0,   0, 
+    144,   2,   0,   0,   0,   1, 
       0,   0,  16,   0,   0,   0, 
-      0,   0,   0,   0,  72,   2, 
-      0,   0,   0,   0,   0,   0, 
-     99,   2,   0,   0, 224,   0, 
+      0,   0,   0,   0, 128,   2, 
+      0,   0,   0,   0,   0,   0, 
+    155,   2,   0,   0,  16,   1, 
       0,   0,  16,   0,   0,   0, 
-      0,   0,   0,   0,  72,   2, 
-      0,   0,   0,   0,   0,   0, 
-    109,   2,   0,   0, 240,   0, 
+      0,   0,   0,   0, 128,   2, 
+      0,   0,   0,   0,   0,   0, 
+    165,   2,   0,   0,  32,   1, 
       0,   0,  64,   0,   0,   0, 
-      0,   0,   0,   0,   8,   2, 
+      0,   0,   0,   0,  64,   2, 
       0,   0,   0,   0,   0,   0, 
     102,  76,  97, 121, 101, 114, 
      67, 111, 108, 111, 114,   0, 
       1,   0,   3,   0,   1,   0, 
       4,   0,   0,   0,   0,   0, 
       0,   0,   0,   0, 102,  76, 
      97, 121, 101, 114,  79, 112, 
      97,  99, 105, 116, 121,   0, 
     171, 171,   0,   0,   3,   0, 
       1,   0,   1,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
     105,  66, 108, 101, 110, 100, 
      67, 111, 110, 102, 105, 103, 
       0, 171, 171, 171,   1,   0, 
      19,   0,   1,   0,   4,   0, 
       0,   0,   0,   0,   0,   0, 
-      0,   0, 109,  76,  97, 121, 
-    101, 114,  84, 114,  97, 110, 
-    115, 102, 111, 114, 109,   0, 
-      3,   0,   3,   0,   4,   0, 
+      0,   0, 109,  89, 117, 118, 
+     67, 111, 108, 111, 114,  77, 
+     97, 116, 114, 105, 120,   0, 
+      2,   0,   3,   0,   3,   0, 
+      3,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0, 109,  76, 
+     97, 121, 101, 114,  84, 114, 
+     97, 110, 115, 102, 111, 114, 
+    109,   0,   3,   0,   3,   0, 
+      4,   0,   4,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+    109,  80, 114, 111, 106, 101, 
+     99, 116, 105, 111, 110,   0, 
+    118,  82, 101, 110, 100, 101, 
+    114,  84,  97, 114, 103, 101, 
+    116,  79, 102, 102, 115, 101, 
+    116,   0, 118,  84, 101, 120, 
+    116, 117, 114, 101,  67, 111, 
+    111, 114, 100, 115,   0, 171, 
+      1,   0,   3,   0,   1,   0, 
       4,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0, 109,  80, 
-    114, 111, 106, 101,  99, 116, 
-    105, 111, 110,   0, 118,  82, 
-    101, 110, 100, 101, 114,  84, 
-     97, 114, 103, 101, 116,  79, 
-    102, 102, 115, 101, 116,   0, 
-    118,  84, 101, 120, 116, 117, 
-    114, 101,  67, 111, 111, 114, 
-    100, 115,   0, 171,   1,   0, 
-      3,   0,   1,   0,   4,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0, 118,  76,  97, 121, 
-    101, 114,  81, 117,  97, 100, 
-      0, 118,  77,  97, 115, 107, 
-     81, 117,  97, 100,   0, 109, 
-     66,  97,  99, 107, 100, 114, 
-    111, 112,  84, 114,  97, 110, 
-    115, 102, 111, 114, 109,   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,  49, 
-     48,  46,  48,  46,  49,  48, 
-     48,  49,  49,  46,  49,  54, 
-     51,  56,  52,   0,  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,   0,   0, 118,  76, 
+     97, 121, 101, 114,  81, 117, 
+     97, 100,   0, 118,  77,  97, 
+    115, 107,  81, 117,  97, 100, 
+      0, 109,  66,  97,  99, 107, 
+    100, 114, 111, 112,  84, 114, 
+     97, 110, 115, 102, 111, 114, 
+    109,   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,  49,  48,  46,  49,   0, 
+     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,   0,   0,   3,   0, 
+      0,   0,   1,   0,   0,   0, 
+      3,   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,  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,  68,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   3,   0,   0,   0, 
-      1,   0,   0,   0,   3,   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,  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
+      0,   0,  83,  86,  95,  84, 
+     97, 114, 103, 101, 116,   0, 
+    171, 171
 };
 ShaderBytes sRGBAShader = { RGBAShader, sizeof(RGBAShader) };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 10.0.10011.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 10.1
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16 [unused]
 //   float fLayerOpacity;               // Offset:   16 Size:     4
 //   uint4 iBlendConfig;                // Offset:   32 Size:    16 [unused]
-//   float4x4 mLayerTransform;          // Offset:   48 Size:    64 [unused]
-//   float4x4 mProjection;              // Offset:  112 Size:    64 [unused]
-//   float4 vRenderTargetOffset;        // Offset:  176 Size:    16 [unused]
-//   float4 vTextureCoords;             // Offset:  192 Size:    16 [unused]
-//   float4 vLayerQuad;                 // Offset:  208 Size:    16 [unused]
-//   float4 vMaskQuad;                  // Offset:  224 Size:    16 [unused]
-//   float4x4 mBackdropTransform;       // Offset:  240 Size:    64 [unused]
+//   row_major float3x3 mYuvColorMatrix;// Offset:   48 Size:    44 [unused]
+//   float4x4 mLayerTransform;          // Offset:   96 Size:    64 [unused]
+//   float4x4 mProjection;              // Offset:  160 Size:    64 [unused]
+//   float4 vRenderTargetOffset;        // Offset:  224 Size:    16 [unused]
+//   float4 vTextureCoords;             // Offset:  240 Size:    16 [unused]
+//   float4 vLayerQuad;                 // Offset:  256 Size:    16 [unused]
+//   float4 vMaskQuad;                  // Offset:  272 Size:    16 [unused]
+//   float4x4 mBackdropTransform;       // Offset:  288 Size:    64 [unused]
 //
 // }
 //
 //
 // Resource Bindings:
 //
 // Name                                 Type  Format         Dim      HLSL Bind  Count
 // ------------------------------ ---------- ------- ----------- -------------- ------
@@ -1394,25 +1430,25 @@ 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, 207,  79, 
-     99, 143,  94, 253,  50, 234, 
-    183, 114, 100, 130, 114, 218, 
-    230, 139,   1,   0,   0,   0, 
-    168,   6,   0,   0,   6,   0, 
+     68,  88,  66,  67, 168, 127, 
+    203,  56, 125, 182, 211,  23, 
+    166, 215, 189, 218, 181,  48, 
+    227,  73,   1,   0,   0,   0, 
+    212,   6,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
      64,   1,   0,   0, 160,   2, 
       0,   0,  28,   3,   0,   0, 
-      4,   6,   0,   0,  92,   6, 
+     48,   6,   0,   0, 136,   6, 
       0,   0,  65, 111, 110,  57, 
       0,   1,   0,   0,   0,   1, 
       0,   0,   0,   2, 255, 255, 
     200,   0,   0,   0,  56,   0, 
       0,   0,   1,   0,  44,   0, 
       0,   0,  56,   0,   0,   0, 
      56,   0,   2,   0,  36,   0, 
       0,   0,  56,   0,   0,   0, 
@@ -1527,22 +1563,22 @@ const BYTE ComponentAlphaShader[] =
       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, 224,   2,   0,   0, 
+     69,  70,  12,   3,   0,   0, 
       1,   0,   0,   0, 192,   0, 
       0,   0,   4,   0,   0,   0, 
      28,   0,   0,   0,   0,   4, 
     255, 255,   0,   1,   0,   0, 
-    172,   2,   0,   0, 156,   0, 
+    228,   2,   0,   0, 156,   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,   1,   0,   0,   0, 
     165,   0,   0,   0,   2,   0, 
       0,   0,   5,   0,   0,   0, 
       4,   0,   0,   0, 255, 255, 
@@ -1560,156 +1596,165 @@ const BYTE ComponentAlphaShader[] =
       0,   0,   0,   0,   1,   0, 
       0,   0,   0,   0,   0,   0, 
     115,  83,  97, 109, 112, 108, 
     101, 114,   0, 116,  82,  71, 
      66,   0, 116,  82,  71,  66, 
      87, 104, 105, 116, 101,   0, 
      36,  71, 108, 111,  98,  97, 
     108, 115,   0, 171, 171, 171, 
-    180,   0,   0,   0,  10,   0, 
+    180,   0,   0,   0,  11,   0, 
       0,   0, 216,   0,   0,   0, 
-     48,   1,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-    200,   1,   0,   0,   0,   0, 
+     96,   1,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+    224,   1,   0,   0,   0,   0, 
       0,   0,  16,   0,   0,   0, 
-      0,   0,   0,   0, 212,   1, 
-      0,   0,   0,   0,   0,   0, 
-    228,   1,   0,   0,  16,   0, 
+      0,   0,   0,   0, 236,   1, 
+      0,   0,   0,   0,   0,   0, 
+    252,   1,   0,   0,  16,   0, 
       0,   0,   4,   0,   0,   0, 
-      2,   0,   0,   0, 244,   1, 
-      0,   0,   0,   0,   0,   0, 
-      4,   2,   0,   0,  32,   0, 
+      2,   0,   0,   0,  12,   2, 
+      0,   0,   0,   0,   0,   0, 
+     28,   2,   0,   0,  32,   0, 
       0,   0,  16,   0,   0,   0, 
-      0,   0,   0,   0,  20,   2, 
-      0,   0,   0,   0,   0,   0, 
-     36,   2,   0,   0,  48,   0, 
-      0,   0,  64,   0,   0,   0, 
-      0,   0,   0,   0,  52,   2, 
-      0,   0,   0,   0,   0,   0, 
-     68,   2,   0,   0, 112,   0, 
+      0,   0,   0,   0,  44,   2, 
+      0,   0,   0,   0,   0,   0, 
+     60,   2,   0,   0,  48,   0, 
+      0,   0,  44,   0,   0,   0, 
+      0,   0,   0,   0,  76,   2, 
+      0,   0,   0,   0,   0,   0, 
+     92,   2,   0,   0,  96,   0, 
       0,   0,  64,   0,   0,   0, 
-      0,   0,   0,   0,  52,   2, 
-      0,   0,   0,   0,   0,   0, 
-     80,   2,   0,   0, 176,   0, 
+      0,   0,   0,   0, 108,   2, 
+      0,   0,   0,   0,   0,   0, 
+    124,   2,   0,   0, 160,   0, 
+      0,   0,  64,   0,   0,   0, 
+      0,   0,   0,   0, 108,   2, 
+      0,   0,   0,   0,   0,   0, 
+    136,   2,   0,   0, 224,   0, 
       0,   0,  16,   0,   0,   0, 
-      0,   0,   0,   0, 212,   1, 
-      0,   0,   0,   0,   0,   0, 
-    100,   2,   0,   0, 192,   0, 
+      0,   0,   0,   0, 236,   1, 
+      0,   0,   0,   0,   0,   0, 
+    156,   2,   0,   0, 240,   0, 
       0,   0,  16,   0,   0,   0, 
-      0,   0,   0,   0, 116,   2, 
-      0,   0,   0,   0,   0,   0, 
-    132,   2,   0,   0, 208,   0, 
+      0,   0,   0,   0, 172,   2, 
+      0,   0,   0,   0,   0,   0, 
+    188,   2,   0,   0,   0,   1, 
       0,   0,  16,   0,   0,   0, 
-      0,   0,   0,   0, 116,   2, 
-      0,   0,   0,   0,   0,   0, 
-    143,   2,   0,   0, 224,   0, 
+      0,   0,   0,   0, 172,   2, 
+      0,   0,   0,   0,   0,   0, 
+    199,   2,   0,   0,  16,   1, 
       0,   0,  16,   0,   0,   0, 
-      0,   0,   0,   0, 116,   2, 
-      0,   0,   0,   0,   0,   0, 
-    153,   2,   0,   0, 240,   0, 
+      0,   0,   0,   0, 172,   2, 
+      0,   0,   0,   0,   0,   0, 
+    209,   2,   0,   0,  32,   1, 
       0,   0,  64,   0,   0,   0, 
-      0,   0,   0,   0,  52,   2, 
+      0,   0,   0,   0, 108,   2, 
       0,   0,   0,   0,   0,   0, 
     102,  76,  97, 121, 101, 114, 
      67, 111, 108, 111, 114,   0, 
       1,   0,   3,   0,   1,   0, 
       4,   0,   0,   0,   0,   0, 
       0,   0,   0,   0, 102,  76, 
      97, 121, 101, 114,  79, 112, 
      97,  99, 105, 116, 121,   0, 
     171, 171,   0,   0,   3,   0, 
       1,   0,   1,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
     105,  66, 108, 101, 110, 100, 
      67, 111, 110, 102, 105, 103, 
       0, 171, 171, 171,   1,   0, 
      19,   0,   1,   0,   4,   0, 
       0,   0,   0,   0,   0,   0, 
-      0,   0, 109,  76,  97, 121, 
-    101, 114,  84, 114,  97, 110, 
-    115, 102, 111, 114, 109,   0, 
-      3,   0,   3,   0,   4,   0, 
+      0,   0, 109,  89, 117, 118, 
+     67, 111, 108, 111, 114,  77, 
+     97, 116, 114, 105, 120,   0, 
+      2,   0,   3,   0,   3,   0, 
+      3,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0, 109,  76, 
+     97, 121, 101, 114,  84, 114, 
+     97, 110, 115, 102, 111, 114, 
+    109,   0,   3,   0,   3,   0, 
+      4,   0,   4,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+    109,  80, 114, 111, 106, 101, 
+     99, 116, 105, 111, 110,   0, 
+    118,  82, 101, 110, 100, 101, 
+    114,  84,  97, 114, 103, 101, 
+    116,  79, 102, 102, 115, 101, 
+    116,   0, 118,  84, 101, 120, 
+    116, 117, 114, 101,  67, 111, 
+    111, 114, 100, 115,   0, 171, 
+      1,   0,   3,   0,   1,   0, 
       4,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0, 109,  80, 
-    114, 111, 106, 101,  99, 116, 
-    105, 111, 110,   0, 118,  82, 
-    101, 110, 100, 101, 114,  84, 
-     97, 114, 103, 101, 116,  79, 
-    102, 102, 115, 101, 116,   0, 
-    118,  84, 101, 120, 116, 117, 
-    114, 101,  67, 111, 111, 114, 
-    100, 115,   0, 171,   1,   0, 
-      3,   0,   1,   0,   4,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0, 118,  76,  97, 121, 
-    101, 114,  81, 117,  97, 100, 
-      0, 118,  77,  97, 115, 107, 
-     81, 117,  97, 100,   0, 109, 
-     66,  97,  99, 107, 100, 114, 
-    111, 112,  84, 114,  97, 110, 
-    115, 102, 111, 114, 109,   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,  49, 
-     48,  46,  48,  46,  49,  48, 
-     48,  49,  49,  46,  49,  54, 
-     51,  56,  52,   0,  73,  83, 
-     71,  78,  80,   0,   0,   0, 
+      0,   0,   0,   0, 118,  76, 
+     97, 121, 101, 114,  81, 117, 
+     97, 100,   0, 118,  77,  97, 
+    115, 107,  81, 117,  97, 100, 
+      0, 109,  66,  97,  99, 107, 
+    100, 114, 111, 112,  84, 114, 
+     97, 110, 115, 102, 111, 114, 
+    109,   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,  49,  48,  46,  49,   0, 
+     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,   0,   0,   3,   0, 
+      0,   0,   1,   0,   0,   0, 
+      3,   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,  79,  83, 
+     71,  78,  68,   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, 
       0,   0,   3,   0,   0,   0, 
-      1,   0,   0,   0,   3,   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,  79,  83,  71,  78, 
-     68,   0,   0,   0,   2,   0, 
-      0,   0,   8,   0,   0,   0, 
-     56,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      3,   0,   0,   0,   0,   0, 
-      0,   0,  15,   0,   0,   0, 
-     56,   0,   0,   0,   1,   0, 
-      0,   0,   0,   0,   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
+      0,   0,   0,   0,  15,   0, 
+      0,   0,  56,   0,   0,   0, 
+      1,   0,   0,   0,   0,   0, 
+      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
 };
 ShaderBytes sComponentAlphaShader = { ComponentAlphaShader, sizeof(ComponentAlphaShader) };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 10.0.10011.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 10.1
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16 [unused]
 //   float fLayerOpacity;               // Offset:   16 Size:     4
 //   uint4 iBlendConfig;                // Offset:   32 Size:    16 [unused]
-//   float4x4 mLayerTransform;          // Offset:   48 Size:    64 [unused]
-//   float4x4 mProjection;              // Offset:  112 Size:    64 [unused]
-//   float4 vRenderTargetOffset;        // Offset:  176 Size:    16 [unused]
-//   float4 vTextureCoords;             // Offset:  192 Size:    16 [unused]
-//   float4 vLayerQuad;                 // Offset:  208 Size:    16 [unused]
-//   float4 vMaskQuad;                  // Offset:  224 Size:    16 [unused]
-//   float4x4 mBackdropTransform;       // Offset:  240 Size:    64 [unused]
+//   row_major float3x3 mYuvColorMatrix;// Offset:   48 Size:    44
+//   float4x4 mLayerTransform;          // Offset:   96 Size:    64 [unused]
+//   float4x4 mProjection;              // Offset:  160 Size:    64 [unused]
+//   float4 vRenderTargetOffset;        // Offset:  224 Size:    16 [unused]
+//   float4 vTextureCoords;             // Offset:  240 Size:    16 [unused]
+//   float4 vLayerQuad;                 // Offset:  256 Size:    16 [unused]
+//   float4 vMaskQuad;                  // Offset:  272 Size:    16 [unused]
+//   float4x4 mBackdropTransform;       // Offset:  288 Size:    64 [unused]
 //
 // }
 //
 //
 // Resource Bindings:
 //
 // Name                                 Type  Format         Dim      HLSL Bind  Count
 // ------------------------------ ---------- ------- ----------- -------------- ------
@@ -1736,378 +1781,348 @@ ShaderBytes sComponentAlphaShader = { Co
 // 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)
+// c1         cb0             3         3  ( FLT, FLT, FLT, FLT)
 //
 //
 // Sampler/Resource to DX9 shader sampler mappings:
 //
 // Target Sampler Source Sampler  Source Resource
 // -------------- --------------- ----------------
 // s0             s0              t1               
 // s1             s0              t2               
 // s2             s0              t3               
 //
 //
 // Level9 shader bytecode:
 //
     ps_2_x
-    def c1, -0.50195998, -0.0627499968, 1.59603, 0.812969983
-    def c2, 1.16437995, 2.01723003, 0.391759992, 1
+    def c4, -0.0627499968, -0.50195998, 1, 0
     dcl t0.xy
     dcl_2d s0
     dcl_2d s1
     dcl_2d s2
-    texld r0, t0, s0
+    mov r0.w, c4.z
+    texld r1, t0, s1
+    texld r2, t0, s0
+    add r2.x, r2.x, c4.x
+    add r2.y, r1.x, c4.y
     texld r1, t0, s2
-    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.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
+    add r2.z, r1.x, c4.y
+    dp3 r0.x, c1, r2
+    dp3 r0.y, c2, r2
+    dp3 r0.z, c3, r2
+    mul r0, r0, c0.x
     mov oC0, r0
 
-// approximately 15 instruction slots used (3 texture, 12 arithmetic)
+// approximately 12 instruction slots used (3 texture, 9 arithmetic)
 ps_4_0
-dcl_constantbuffer CB0[2], immediateIndexed
+dcl_constantbuffer CB0[6], immediateIndexed
 dcl_sampler s0, mode_default
 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_output o0.xyzw
 dcl_temps 3
-sample r0.xyzw, v1.xyxx, t3.xyzw, s0
-add r0.x, r0.x, l(-0.501960)
-mul r0.xy, r0.xxxx, l(1.596030, 0.812970, 0.000000, 0.000000)
+mov r0.w, l(1.000000)
 sample r1.xyzw, v1.xyxx, t1.xyzw, s0
-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
+add r1.x, r1.x, l(-0.062750)
 sample r2.xyzw, v1.xyxx, t2.xyzw, s0
-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
+add r1.y, r2.x, l(-0.501960)
+sample r2.xyzw, v1.xyxx, t3.xyzw, s0
+add r1.z, r2.x, l(-0.501960)
+dp3 r0.x, cb0[3].xyzx, r1.xyzx
+dp3 r0.y, cb0[4].xyzx, r1.xyzx
+dp3 r0.z, cb0[5].xyzx, r1.xyzx
+mul o0.xyzw, r0.xyzw, cb0[1].xxxx
 ret 
-// Approximately 15 instruction slots used
+// Approximately 12 instruction slots used
 #endif
 
 const BYTE YCbCrShader[] =
 {
-     68,  88,  66,  67,  38, 102, 
-    184,  10,  33,  16, 211, 116, 
-    233, 219, 255, 155, 108,  20, 
-     81, 243,   1,   0,   0,   0, 
-     56,   8,   0,   0,   6,   0, 
+     68,  88,  66,  67,  56, 199, 
+     91,   5, 215, 233, 204,  14, 
+    193, 166, 163,  11, 246, 123, 
+    165,  88,   1,   0,   0,   0, 
+    156,   7,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
-    220,   1,   0,   0,  44,   4, 
-      0,   0, 168,   4,   0,   0, 
-    172,   7,   0,   0,   4,   8, 
+    144,   1,   0,   0, 100,   3, 
+      0,   0, 224,   3,   0,   0, 
+     16,   7,   0,   0, 104,   7, 
       0,   0,  65, 111, 110,  57, 
-    156,   1,   0,   0, 156,   1, 
+     80,   1,   0,   0,  80,   1, 
       0,   0,   0,   2, 255, 255, 
-     96,   1,   0,   0,  60,   0, 
-      0,   0,   1,   0,  48,   0, 
-      0,   0,  60,   0,   0,   0, 
-     60,   0,   3,   0,  36,   0, 
-      0,   0,  60,   0,   1,   0, 
+      8,   1,   0,   0,  72,   0, 
+      0,   0,   2,   0,  48,   0, 
+      0,   0,  72,   0,   0,   0, 
+     72,   0,   3,   0,  36,   0, 
+      0,   0,  72,   0,   1,   0, 
       0,   0,   2,   0,   1,   0, 
       3,   0,   2,   0,   0,   0, 
       1,   0,   1,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      3,   0,   3,   0,   1,   0, 
       0,   0,   0,   0,   1,   2, 
     255, 255,  81,   0,   0,   5, 
-      1,   0,  15, 160, 115, 128, 
-      0, 191,  18, 131, 128, 189, 
-    182,  74, 204,  63, 205,  30, 
-     80,  63,  81,   0,   0,   5, 
-      2,   0,  15, 160, 103,  10, 
-    149,  63,  76,  26,   1,  64, 
-    196, 148, 200,  62,   0,   0, 
-    128,  63,  31,   0,   0,   2, 
+      4,   0,  15, 160,  18, 131, 
+    128, 189, 115, 128,   0, 191, 
+      0,   0, 128,  63,   0,   0, 
+      0,   0,  31,   0,   0,   2, 
       0,   0,   0, 128,   0,   0, 
       3, 176,  31,   0,   0,   2, 
       0,   0,   0, 144,   0,   8, 
      15, 160,  31,   0,   0,   2, 
       0,   0,   0, 144,   1,   8, 
      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, 
+     15, 160,   1,   0,   0,   2, 
+      0,   0,   8, 128,   4,   0, 
+    170, 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, 
+      0,   8, 228, 160,   2,   0, 
+      0,   3,   2,   0,   1, 128, 
+      2,   0,   0, 128,   4,   0, 
+      0, 160,   2,   0,   0,   3, 
+      2,   0,   2, 128,   1,   0, 
+      0, 128,   4,   0,  85, 160, 
      66,   0,   0,   3,   1,   0, 
      15, 128,   0,   0, 228, 176, 
       2,   8, 228, 160,   2,   0, 
-      0,   3,   0,   0,   2, 128, 
-      1,   0,   0, 128,   1,   0, 
-      0, 160,   5,   0,   0,   3, 
-      0,   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,   4, 128, 
-      0,   0,   0, 128,   2,   0, 
-      0, 160,   0,   0, 170, 129, 
-      4,   0,   0,   4,   1,   0, 
-      1, 128,   0,   0,   0, 128, 
-      2,   0,   0, 160,   0,   0, 
-     85, 128,  66,   0,   0,   3, 
-      2,   0,  15, 128,   0,   0, 
-    228, 176,   1,   8, 228, 160, 
-      2,   0,   0,   3,   0,   0, 
-      2, 128,   2,   0,   0, 128, 
-      1,   0,   0, 160,   4,   0, 
-      0,   4,   1,   0,   2, 128, 
-      0,   0,  85, 128,   2,   0, 
-    170, 161,   0,   0, 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,   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, 
-     72,   2,   0,   0,  64,   0, 
-      0,   0, 146,   0,   0,   0, 
-     89,   0,   0,   4,  70, 142, 
-     32,   0,   0,   0,   0,   0, 
-      2,   0,   0,   0,  90,   0, 
-      0,   3,   0,  96,  16,   0, 
-      0,   0,   0,   0,  88,  24, 
+      0,   3,   2,   0,   4, 128, 
+      1,   0,   0, 128,   4,   0, 
+     85, 160,   8,   0,   0,   3, 
+      0,   0,   1, 128,   1,   0, 
+    228, 160,   2,   0, 228, 128, 
+      8,   0,   0,   3,   0,   0, 
+      2, 128,   2,   0, 228, 160, 
+      2,   0, 228, 128,   8,   0, 
+      0,   3,   0,   0,   4, 128, 
+      3,   0, 228, 160,   2,   0, 
+    228, 128,   5,   0,   0,   3, 
+      0,   0,  15, 128,   0,   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, 204,   1,   0,   0, 
+     64,   0,   0,   0, 115,   0, 
+      0,   0,  89,   0,   0,   4, 
+     70, 142,  32,   0,   0,   0, 
+      0,   0,   6,   0,   0,   0, 
+     90,   0,   0,   3,   0,  96, 
+     16,   0,   0,   0,   0,   0, 
+     88,  24,   0,   4,   0, 112, 
+     16,   0,   1,   0,   0,   0, 
+     85,  85,   0,   0,  88,  24, 
       0,   4,   0, 112,  16,   0, 
-      1,   0,   0,   0,  85,  85, 
+      2,   0,   0,   0,  85,  85, 
       0,   0,  88,  24,   0,   4, 
-      0, 112,  16,   0,   2,   0, 
+      0, 112,  16,   0,   3,   0, 
       0,   0,  85,  85,   0,   0, 
-     88,  24,   0,   4,   0, 112, 
-     16,   0,   3,   0,   0,   0, 
-     85,  85,   0,   0,  98,  16, 
-      0,   3,  50,  16,  16,   0, 
-      1,   0,   0,   0, 101,   0, 
-      0,   3, 242,  32,  16,   0, 
-      0,   0,   0,   0, 104,   0, 
-      0,   2,   3,   0,   0,   0, 
+     98,  16,   0,   3,  50,  16, 
+     16,   0,   1,   0,   0,   0, 
+    101,   0,   0,   3, 242,  32, 
+     16,   0,   0,   0,   0,   0, 
+    104,   0,   0,   2,   3,   0, 
+      0,   0,  54,   0,   0,   5, 
+    130,   0,  16,   0,   0,   0, 
+      0,   0,   1,  64,   0,   0, 
+      0,   0, 128,  63,  69,   0, 
+      0,   9, 242,   0,  16,   0, 
+      1,   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, 
+      1,   0,   0,   0,  10,   0, 
+     16,   0,   1,   0,   0,   0, 
+      1,  64,   0,   0,  18, 131, 
+    128, 189,  69,   0,   0,   9, 
+    242,   0,  16,   0,   2,   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, 
+     34,   0,  16,   0,   1,   0, 
+      0,   0,  10,   0,  16,   0, 
+      2,   0,   0,   0,   1,  64, 
+      0,   0, 115, 128,   0, 191, 
      69,   0,   0,   9, 242,   0, 
-     16,   0,   0,   0,   0,   0, 
+     16,   0,   2,   0,   0,   0, 
      70,  16,  16,   0,   1,   0, 
       0,   0,  70, 126,  16,   0, 
       3,   0,   0,   0,   0,  96, 
      16,   0,   0,   0,   0,   0, 
-      0,   0,   0,   7,  18,   0, 
-     16,   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,   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, 
+      0,   0,   0,   7,  66,   0, 
      16,   0,   1,   0,   0,   0, 
-      0,  96,  16,   0,   0,   0, 
-      0,   0,   0,   0,   0,   7, 
-     66,   0,  16,   0,   0,   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, 
-      0,   0,   0,   0,  50,   0, 
-      0,   9,  18,   0,  16,   0, 
-      1,   0,   0,   0,  42,   0, 
-     16,   0,   0,   0,   0,   0, 
-      1,  64,   0,   0, 103,  10, 
-    149,  63,  10,   0,  16,   0, 
-      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,   2,   0, 
-      0,   0,   0,  96,  16,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   7,  18,   0,  16,   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, 
+     10,   0,  16,   0,   2,   0, 
       0,   0,   1,  64,   0,   0, 
-    196, 148, 200,  62,  26,   0, 
-     16,   0,   0,   0,   0,   0, 
-     56,   0,   0,   7,  18,   0, 
-     16,   0,   0,   0,   0,   0, 
-     10,   0,  16,   0,   0,   0, 
-      0,   0,   1,  64,   0,   0, 
-     76,  26,   1,  64,  50,   0, 
-      0,   9,  66,   0,  16,   0, 
-      1,   0,   0,   0,  42,   0, 
-     16,   0,   0,   0,   0,   0, 
-      1,  64,   0,   0, 103,  10, 
-    149,  63,  10,   0,  16,   0, 
-      0,   0,   0,   0,  54,   0, 
-      0,   5, 130,   0,  16,   0, 
-      1,   0,   0,   0,   1,  64, 
-      0,   0,   0,   0, 128,  63, 
-     56,   0,   0,   8, 242,  32, 
-     16,   0,   0,   0,   0,   0, 
-     70,  14,  16,   0,   1,   0, 
-      0,   0,   6, 128,  32,   0, 
+    115, 128,   0, 191,  16,   0, 
+      0,   8,  18,   0,  16,   0, 
+      0,   0,   0,   0,  70, 130, 
+     32,   0,   0,   0,   0,   0, 
+      3,   0,   0,   0,  70,   2, 
+     16,   0,   1,   0,   0,   0, 
+     16,   0,   0,   8,  34,   0, 
+     16,   0,   0,   0,   0,   0, 
+     70, 130,  32,   0,   0,   0, 
+      0,   0,   4,   0,   0,   0, 
+     70,   2,  16,   0,   1,   0, 
+      0,   0,  16,   0,   0,   8, 
+     66,   0,  16,   0,   0,   0, 
+      0,   0,  70, 130,  32,   0, 
+      0,   0,   0,   0,   5,   0, 
+      0,   0,  70,   2,  16,   0, 
+      1,   0,   0,   0,  56,   0, 
+      0,   8, 242,  32,  16,   0, 
+      0,   0,   0,   0,  70,  14, 
+     16,   0,   0,   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, 
+     12,   0,   0,   0,   3,   0, 
+      0,   0,   0,   0,   0,   0, 
+      2,   0,   0,   0,   7,   0, 
+      0,   0,   0,   0,   0,   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, 
-      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, 
-      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, 252,   2,   0,   0, 
-      1,   0,   0,   0, 220,   0, 
-      0,   0,   5,   0,   0,   0, 
-     28,   0,   0,   0,   0,   4, 
-    255, 255,   0,   1,   0,   0, 
-    200,   2,   0,   0, 188,   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,   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, 
+     40,   3,   0,   0,   1,   0, 
+      0,   0, 220,   0,   0,   0, 
+      5,   0,   0,   0,  28,   0, 
+      0,   0,   0,   4, 255, 255, 
+      0,   1,   0,   0,   0,   3, 
+      0,   0, 188,   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, 
-    197,   0,   0,   0,   2,   0, 
-      0,   0,   5,   0,   0,   0, 
-      4,   0,   0,   0, 255, 255, 
-    255, 255,   1,   0,   0,   0, 
-      1,   0,   0,   0,  13,   0, 
-      0,   0, 200,   0,   0,   0, 
-      2,   0,   0,   0,   5,   0, 
-      0,   0,   4,   0,   0,   0, 
-    255, 255, 255, 255,   2,   0, 
-      0,   0,   1,   0,   0,   0, 
-     13,   0,   0,   0, 204,   0, 
+      1,   0,   0,   0, 197,   0, 
       0,   0,   2,   0,   0,   0, 
       5,   0,   0,   0,   4,   0, 
       0,   0, 255, 255, 255, 255, 
-      3,   0,   0,   0,   1,   0, 
+      1,   0,   0,   0,   1,   0, 
       0,   0,  13,   0,   0,   0, 
-    208,   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, 115,  83,  97, 109, 
-    112, 108, 101, 114,   0, 116, 
-     89,   0, 116,  67,  98,   0, 
-    116,  67, 114,   0,  36,  71, 
-    108, 111,  98,  97, 108, 115, 
-      0, 171, 171, 171, 208,   0, 
-      0,   0,  10,   0,   0,   0, 
-    244,   0,   0,   0,  48,   1, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0, 228,   1, 
-      0,   0,   0,   0,   0,   0, 
-     16,   0,   0,   0,   0,   0, 
-      0,   0, 240,   1,   0,   0, 
-      0,   0,   0,   0,   0,   2, 
-      0,   0,  16,   0,   0,   0, 
-      4,   0,   0,   0,   2,   0, 
-      0,   0,  16,   2,   0,   0, 
-      0,   0,   0,   0,  32,   2, 
-      0,   0,  32,   0,   0,   0, 
-     16,   0,   0,   0,   0,   0, 
-      0,   0,  48,   2,   0,   0, 
-      0,   0,   0,   0,  64,   2, 
-      0,   0,  48,   0,   0,   0, 
-     64,   0,   0,   0,   0,   0, 
-      0,   0,  80,   2,   0,   0, 
-      0,   0,   0,   0,  96,   2, 
-      0,   0, 112,   0,   0,   0, 
-     64,   0,   0,   0,   0,   0, 
-      0,   0,  80,   2,   0,   0, 
-      0,   0,   0,   0, 108,   2, 
-      0,   0, 176,   0,   0,   0, 
-     16,   0,   0,   0,   0,   0, 
-      0,   0, 240,   1,   0,   0, 
-      0,   0,   0,   0, 128,   2, 
-      0,   0, 192,   0,   0,   0, 
-     16,   0,   0,   0,   0,   0, 
-      0,   0, 144,   2,   0,   0, 
-      0,   0,   0,   0, 160,   2, 
-      0,   0, 208,   0,   0,   0, 
-     16,   0,   0,   0,   0,   0, 
-      0,   0, 144,   2,   0,   0, 
-      0,   0,   0,   0, 171,   2, 
-      0,   0, 224,   0,   0,   0, 
-     16,   0,   0,   0,   0,   0, 
-      0,   0, 144,   2,   0,   0, 
-      0,   0,   0,   0, 181,   2, 
-      0,   0, 240,   0,   0,   0, 
-     64,   0,   0,   0,   0,   0, 
-      0,   0,  80,   2,   0,   0, 
-      0,   0,   0,   0, 102,  76, 
-     97, 121, 101, 114,  67, 111, 
-    108, 111, 114,   0,   1,   0, 
-      3,   0,   1,   0,   4,   0, 
-      0,   0,   0,   0,   0,   0, 
+    200,   0,   0,   0,   2,   0, 
+      0,   0,   5,   0,   0,   0, 
+      4,   0,   0,   0, 255, 255, 
+    255, 255,   2,   0,   0,   0, 
+      1,   0,   0,   0,  13,   0, 
+      0,   0, 204,   0,   0,   0, 
+      2,   0,   0,   0,   5,   0, 
+      0,   0,   4,   0,   0,   0, 
+    255, 255, 255, 255,   3,   0, 
+      0,   0,   1,   0,   0,   0, 
+     13,   0,   0,   0, 208,   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, 
+    115,  83,  97, 109, 112, 108, 
+    101, 114,   0, 116,  89,   0, 
+    116,  67,  98,   0, 116,  67, 
+    114,   0,  36,  71, 108, 111, 
+     98,  97, 108, 115,   0, 171, 
+    171, 171, 208,   0,   0,   0, 
+     11,   0,   0,   0, 244,   0, 
+      0,   0,  96,   1,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0, 252,   1,   0,   0, 
+      0,   0,   0,   0,  16,   0, 
+      0,   0,   0,   0,   0,   0, 
+      8,   2,   0,   0,   0,   0, 
+      0,   0,  24,   2,   0,   0, 
+     16,   0,   0,   0,   4,   0, 
+      0,   0,   2,   0,   0,   0, 
+     40,   2,   0,   0,   0,   0, 
+      0,   0,  56,   2,   0,   0, 
+     32,   0,   0,   0,  16,   0, 
+      0,   0,   0,   0,   0,   0, 
+     72,   2,   0,   0,   0,   0, 
+      0,   0,  88,   2,   0,   0, 
+     48,   0,   0,   0,  44,   0, 
+      0,   0,   2,   0,   0,   0, 
+    104,   2,   0,   0,   0,   0, 
+      0,   0, 120,   2,   0,   0, 
+     96,   0,   0,   0,  64,   0, 
+      0,   0,   0,   0,   0,   0, 
+    136,   2,   0,   0,   0,   0, 
+      0,   0, 152,   2,   0,   0, 
+    160,   0,   0,   0,  64,   0, 
+      0,   0,   0,   0,   0,   0, 
+    136,   2,   0,   0,   0,   0, 
+      0,   0, 164,   2,   0,   0, 
+    224,   0,   0,   0,  16,   0, 
+      0,   0,   0,   0,   0,   0, 
+      8,   2,   0,   0,   0,   0, 
+      0,   0, 184,   2,   0,   0, 
+    240,   0,   0,   0,  16,   0, 
+      0,   0,   0,   0,   0,   0, 
+    200,   2,   0,   0,   0,   0, 
+      0,   0, 216,   2,   0,   0, 
+      0,   1,   0,   0,  16,   0, 
+      0,   0,   0,   0,   0,   0, 
+    200,   2,   0,   0,   0,   0, 
+      0,   0, 227,   2,   0,   0, 
+     16,   1,   0,   0,  16,   0, 
+      0,   0,   0,   0,   0,   0, 
+    200,   2,   0,   0,   0,   0, 
+      0,   0, 237,   2,   0,   0, 
+     32,   1,   0,   0,  64,   0, 
+      0,   0,   0,   0,   0,   0, 
+    136,   2,   0,   0,   0,   0, 
       0,   0, 102,  76,  97, 121, 
-    101, 114,  79, 112,  97,  99, 
-    105, 116, 121,   0, 171, 171, 
-      0,   0,   3,   0,   1,   0, 
-      1,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0, 105,  66, 
-    108, 101, 110, 100,  67, 111, 
-    110, 102, 105, 103,   0, 171, 
-    171, 171,   1,   0,  19,   0, 
+    101, 114,  67, 111, 108, 111, 
+    114,   0,   1,   0,   3,   0, 
       1,   0,   4,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
+    102,  76,  97, 121, 101, 114, 
+     79, 112,  97,  99, 105, 116, 
+    121,   0, 171, 171,   0,   0, 
+      3,   0,   1,   0,   1,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0, 105,  66, 108, 101, 
+    110, 100,  67, 111, 110, 102, 
+    105, 103,   0, 171, 171, 171, 
+      1,   0,  19,   0,   1,   0, 
+      4,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0, 109,  89, 
+    117, 118,  67, 111, 108, 111, 
+    114,  77,  97, 116, 114, 105, 
+    120,   0,   2,   0,   3,   0, 
+      3,   0,   3,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
     109,  76,  97, 121, 101, 114, 
      84, 114,  97, 110, 115, 102, 
     111, 114, 109,   0,   3,   0, 
       3,   0,   4,   0,   4,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0, 109,  80, 114, 111, 
     106, 101,  99, 116, 105, 111, 
     110,   0, 118,  82, 101, 110, 
@@ -2127,19 +2142,17 @@ const BYTE YCbCrShader[] =
      84, 114,  97, 110, 115, 102, 
     111, 114, 109,   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,  49,  48,  46, 
-     48,  46,  49,  48,  48,  49, 
-     49,  46,  49,  54,  51,  56, 
-     52,   0,  73,  83,  71,  78, 
+     49,   0,  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,   0,   0, 
@@ -2157,17 +2170,17 @@ const BYTE YCbCrShader[] =
       0,   0,   0,   0,   0,   0, 
      15,   0,   0,   0,  83,  86, 
      95,  84,  97, 114, 103, 101, 
     116,   0, 171, 171
 };
 ShaderBytes sYCbCrShader = { YCbCrShader, sizeof(YCbCrShader) };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 10.0.10011.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 10.1
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4x4 mLayerTransform;          // Offset:    0 Size:    64
@@ -2175,16 +2188,17 @@ ShaderBytes sYCbCrShader = { YCbCrShader
 //   float4 vRenderTargetOffset;        // Offset:  128 Size:    16
 //   float4 vTextureCoords;             // Offset:  144 Size:    16
 //   float4 vLayerQuad;                 // Offset:  160 Size:    16
 //   float4 vMaskQuad;                  // Offset:  176 Size:    16
 //   float4x4 mBackdropTransform;       // Offset:  192 Size:    64 [unused]
 //   float4 fLayerColor;                // Offset:  256 Size:    16 [unused]
 //   float fLayerOpacity;               // Offset:  272 Size:     4 [unused]
 //   uint4 iBlendConfig;                // Offset:  288 Size:    16 [unused]
+//   row_major float3x3 mYuvColorMatrix;// Offset:  304 Size:    44 [unused]
 //
 // }
 //
 //
 // Resource Bindings:
 //
 // Name                                 Type  Format         Dim      HLSL Bind  Count
 // ------------------------------ ---------- ------- ----------- -------------- ------
@@ -2277,25 +2291,25 @@ div r0.xy, r0.xyxx, cb0[11].zwzz
 mov r0.z, l(1.000000)
 mul o2.xyz, r1.wwww, r0.xyzx
 ret 
 // Approximately 18 instruction slots used
 #endif
 
 const BYTE LayerQuadMaskVS[] =
 {
-     68,  88,  66,  67, 170, 122, 
-    113,  58, 123,  23, 243, 241, 
-    143, 157, 226, 223, 154,  53, 
-    167, 168,   1,   0,   0,   0, 
-     64,   8,   0,   0,   6,   0, 
+     68,  88,  66,  67,  47,  28, 
+    196, 228,  98,  79,  27, 152, 
+    192,  25, 215, 128,  59, 234, 
+    245, 240,   1,   0,   0,   0, 
+    108,   8,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
      20,   2,   0,   0, 176,   4, 
       0,   0,  44,   5,   0,   0, 
-    156,   7,   0,   0, 208,   7, 
+    200,   7,   0,   0, 252,   7, 
       0,   0,  65, 111, 110,  57, 
     212,   1,   0,   0, 212,   1, 
       0,   0,   0,   2, 254, 255, 
     148,   1,   0,   0,  64,   0, 
       0,   0,   2,   0,  36,   0, 
       0,   0,  60,   0,   0,   0, 
      60,   0,   0,   0,  36,   0, 
       1,   0,  60,   0,   0,   0, 
@@ -2498,72 +2512,76 @@ const BYTE LayerQuadMaskVS[] =
       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,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,  82,  68, 
-     69,  70, 104,   2,   0,   0, 
+     69,  70, 148,   2,   0,   0, 
       1,   0,   0,   0,  72,   0, 
       0,   0,   1,   0,   0,   0, 
      28,   0,   0,   0,   0,   4, 
     254, 255,   0,   1,   0,   0, 
-     52,   2,   0,   0,  60,   0, 
+    108,   2,   0,   0,  60,   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, 
      36,  71, 108, 111,  98,  97, 
     108, 115,   0, 171, 171, 171, 
-     60,   0,   0,   0,  10,   0, 
+     60,   0,   0,   0,  11,   0, 
       0,   0,  96,   0,   0,   0, 
-     48,   1,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-     80,   1,   0,   0,   0,   0, 
+     96,   1,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+    104,   1,   0,   0,   0,   0, 
       0,   0,  64,   0,   0,   0, 
-      2,   0,   0,   0,  96,   1, 
-      0,   0,   0,   0,   0,   0, 
-    112,   1,   0,   0,  64,   0, 
+      2,   0,   0,   0, 120,   1, 
+      0,   0,   0,   0,   0,   0, 
+    136,   1,   0,   0,  64,   0, 
       0,   0,  64,   0,   0,   0, 
-      2,   0,   0,   0,  96,   1, 
-      0,   0,   0,   0,   0,   0, 
-    124,   1,   0,   0, 128,   0, 
+      2,   0,   0,   0, 120,   1, 
+      0,   0,   0,   0,   0,   0, 
+    148,   1,   0,   0, 128,   0, 
       0,   0,  16,   0,   0,   0, 
-      2,   0,   0,   0, 144,   1, 
-      0,   0,   0,   0,   0,   0, 
-    160,   1,   0,   0, 144,   0, 
+      2,   0,   0,   0, 168,   1, 
+      0,   0,   0,   0,   0,   0, 
+    184,   1,   0,   0, 144,   0, 
       0,   0,  16,   0,   0,   0, 
-      2,   0,   0,   0, 176,   1, 
-      0,   0,   0,   0,   0,   0, 
-    192,   1,   0,   0, 160,   0, 
+      2,   0,   0,   0, 200,   1, 
+      0,   0,   0,   0,   0,   0, 
+    216,   1,   0,   0, 160,   0, 
       0,   0,  16,   0,   0,   0, 
-      2,   0,   0,   0, 176,   1, 
-      0,   0,   0,   0,   0,   0, 
-    203,   1,   0,   0, 176,   0, 
+      2,   0,   0,   0, 200,   1, 
+      0,   0,   0,   0,   0,   0, 
+    227,   1,   0,   0, 176,   0, 
       0,   0,  16,   0,   0,   0, 
-      2,   0,   0,   0, 176,   1, 
-      0,   0,   0,   0,   0,   0, 
-    213,   1,   0,   0, 192,   0, 
+      2,   0,   0,   0, 200,   1, 
+      0,   0,   0,   0,   0,   0, 
+    237,   1,   0,   0, 192,   0, 
       0,   0,  64,   0,   0,   0, 
-      0,   0,   0,   0,  96,   1, 
-      0,   0,   0,   0,   0,   0, 
-    232,   1,   0,   0,   0,   1, 
+      0,   0,   0,   0, 120,   1, 
+      0,   0,   0,   0,   0,   0, 
+      0,   2,   0,   0,   0,   1, 
       0,   0,  16,   0,   0,   0, 
-      0,   0,   0,   0, 144,   1, 
-      0,   0,   0,   0,   0,   0, 
-    244,   1,   0,   0,  16,   1, 
+      0,   0,   0,   0, 168,   1, 
+      0,   0,   0,   0,   0,   0, 
+     12,   2,   0,   0,  16,   1, 
       0,   0,   4,   0,   0,   0, 
-      0,   0,   0,   0,   4,   2, 
-      0,   0,   0,   0,   0,   0, 
-     20,   2,   0,   0,  32,   1, 
+      0,   0,   0,   0,  28,   2, 
+      0,   0,   0,   0,   0,   0, 
+     44,   2,   0,   0,  32,   1, 
       0,   0,  16,   0,   0,   0, 
-      0,   0,   0,   0,  36,   2, 
+      0,   0,   0,   0,  60,   2, 
+      0,   0,   0,   0,   0,   0, 
+     76,   2,   0,   0,  48,   1, 
+      0,   0,  44,   0,   0,   0, 
+      0,   0,   0,   0,  92,   2, 
       0,   0,   0,   0,   0,   0, 
     109,  76,  97, 121, 101, 114, 
      84, 114,  97, 110, 115, 102, 
     111, 114, 109,   0,   3,   0, 
       3,   0,   4,   0,   4,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0, 109,  80, 114, 111, 
     106, 101,  99, 116, 105, 111, 
@@ -2593,74 +2611,79 @@ const BYTE LayerQuadMaskVS[] =
       0,   0,   3,   0,   1,   0, 
       1,   0,   0,   0,   0,   0, 
       0,   0,   0,   0, 105,  66, 
     108, 101, 110, 100,  67, 111, 
     110, 102, 105, 103,   0, 171, 
     171, 171,   1,   0,  19,   0, 
       1,   0,   4,   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,  49, 
-     48,  46,  48,  46,  49,  48, 
-     48,  49,  49,  46,  49,  54, 
-     51,  56,  52,   0,  73,  83, 
-     71,  78,  44,   0,   0,   0, 
-      1,   0,   0,   0,   8,   0, 
-      0,   0,  32,   0,   0,   0, 
+    109,  89, 117, 118,  67, 111, 
+    108, 111, 114,  77,  97, 116, 
+    114, 105, 120,   0,   2,   0, 
+      3,   0,   3,   0,   3,   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,  49,  48,  46,  49,   0, 
+     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, 171, 171,  79,  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, 
       0,   0,   3,   0,   0,   0, 
-      0,   0,   0,   0,   3,   3, 
-      0,   0,  80,  79,  83,  73, 
-     84,  73,  79,  78,   0, 171, 
-    171, 171,  79,  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,   0,   0, 
-      3,   0,   0,   0,   1,   0, 
-      0,   0,   3,  12,   0,   0, 
-     92,   0,   0,   0,   1,   0, 
-      0,   0,   0,   0,   0,   0, 
-      3,   0,   0,   0,   2,   0, 
-      0,   0,   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
+      1,   0,   0,   0,   3,  12, 
+      0,   0,  92,   0,   0,   0, 
+      1,   0,   0,   0,   0,   0, 
+      0,   0,   3,   0,   0,   0, 
+      2,   0,   0,   0,   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
 };
 ShaderBytes sLayerQuadMaskVS = { LayerQuadMaskVS, sizeof(LayerQuadMaskVS) };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 10.0.10011.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 10.1
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16
 //   float fLayerOpacity;               // Offset:   16 Size:     4 [unused]
 //   uint4 iBlendConfig;                // Offset:   32 Size:    16 [unused]
-//   float4x4 mLayerTransform;          // Offset:   48 Size:    64 [unused]
-//   float4x4 mProjection;              // Offset:  112 Size:    64 [unused]
-//   float4 vRenderTargetOffset;        // Offset:  176 Size:    16 [unused]
-//   float4 vTextureCoords;             // Offset:  192 Size:    16 [unused]
-//   float4 vLayerQuad;                 // Offset:  208 Size:    16 [unused]
-//   float4 vMaskQuad;                  // Offset:  224 Size:    16 [unused]
-//   float4x4 mBackdropTransform;       // Offset:  240 Size:    64 [unused]
+//   row_major float3x3 mYuvColorMatrix;// Offset:   48 Size:    44 [unused]
+//   float4x4 mLayerTransform;          // Offset:   96 Size:    64 [unused]
+//   float4x4 mProjection;              // Offset:  160 Size:    64 [unused]
+//   float4 vRenderTargetOffset;        // Offset:  224 Size:    16 [unused]
+//   float4 vTextureCoords;             // Offset:  240 Size:    16 [unused]
+//   float4 vLayerQuad;                 // Offset:  256 Size:    16 [unused]
+//   float4 vMaskQuad;                  // Offset:  272 Size:    16 [unused]
+//   float4x4 mBackdropTransform;       // Offset:  288 Size:    64 [unused]
 //
 // }
 //
 //
 // Resource Bindings:
 //
 // Name                                 Type  Format         Dim      HLSL Bind  Count
 // ------------------------------ ---------- ------- ----------- -------------- ------
@@ -2723,25 +2746,25 @@ div r0.xy, v2.xyxx, v2.zzzz
 sample r0.xyzw, r0.xyxx, t5.xyzw, s0
 mul o0.xyzw, r0.xxxx, cb0[0].xyzw
 ret 
 // Approximately 4 instruction slots used
 #endif
 
 const BYTE SolidColorShaderMask[] =
 {
-     68,  88,  66,  67, 136,  34, 
-    160,  50,  38, 225, 198,  78, 
-    252,  58, 191, 192, 204,  38, 
-     60, 224,   1,   0,   0,   0, 
-    120,   5,   0,   0,   6,   0, 
+     68,  88,  66,  67,  11,   0, 
+     43, 127, 123,  42, 253, 228, 
+      4, 220,   7, 130,  11,  94, 
+    213, 177,   1,   0,   0,   0, 
+    164,   5,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     220,   0,   0,   0, 156,   1, 
       0,   0,  24,   2,   0,   0, 
-    212,   4,   0,   0,  68,   5, 
+      0,   5,   0,   0, 112,   5, 
       0,   0,  65, 111, 110,  57, 
     156,   0,   0,   0, 156,   0, 
       0,   0,   0,   2, 255, 255, 
     104,   0,   0,   0,  52,   0, 
       0,   0,   1,   0,  40,   0, 
       0,   0,  52,   0,   0,   0, 
      52,   0,   1,   0,  36,   0, 
       0,   0,  52,   0,   5,   0, 
@@ -2813,21 +2836,21 @@ const BYTE SolidColorShaderMask[] =
       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,  82,  68,  69,  70, 
-    180,   2,   0,   0,   1,   0, 
+    224,   2,   0,   0,   1,   0, 
       0,   0, 148,   0,   0,   0, 
       3,   0,   0,   0,  28,   0, 
       0,   0,   0,   4, 255, 255, 
-      0,   1,   0,   0, 128,   2, 
+      0,   1,   0,   0, 184,   2, 
       0,   0, 124,   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, 
       1,   0,   0,   0, 133,   0, 
       0,   0,   2,   0,   0,   0, 
       5,   0,   0,   0,   4,   0, 
@@ -2839,156 +2862,164 @@ const BYTE SolidColorShaderMask[] =
       0,   0,   0,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
       1,   0,   0,   0,   0,   0, 
       0,   0, 115,  83,  97, 109, 
     112, 108, 101, 114,   0, 116, 
      77,  97, 115, 107,   0,  36, 
      71, 108, 111,  98,  97, 108, 
     115,   0, 139,   0,   0,   0, 
-     10,   0,   0,   0, 172,   0, 
-      0,   0,  48,   1,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0, 156,   1,   0,   0, 
+     11,   0,   0,   0, 172,   0, 
+      0,   0,  96,   1,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0, 180,   1,   0,   0, 
       0,   0,   0,   0,  16,   0, 
       0,   0,   2,   0,   0,   0, 
-    168,   1,   0,   0,   0,   0, 
-      0,   0, 184,   1,   0,   0, 
+    192,   1,   0,   0,   0,   0, 
+      0,   0, 208,   1,   0,   0, 
      16,   0,   0,   0,   4,   0, 
       0,   0,   0,   0,   0,   0, 
-    200,   1,   0,   0,   0,   0, 
-      0,   0, 216,   1,   0,   0, 
+    224,   1,   0,   0,   0,   0, 
+      0,   0, 240,   1,   0,   0, 
      32,   0,   0,   0,  16,   0, 
       0,   0,   0,   0,   0,   0, 
-    232,   1,   0,   0,   0,   0, 
-      0,   0, 248,   1,   0,   0, 
-     48,   0,   0,   0,  64,   0, 
-      0,   0,   0,   0,   0,   0, 
-      8,   2,   0,   0,   0,   0, 
-      0,   0,  24,   2,   0,   0, 
-    112,   0,   0,   0,  64,   0, 
-      0,   0,   0,   0,   0,   0, 
-      8,   2,   0,   0,   0,   0, 
-      0,   0,  36,   2,   0,   0, 
-    176,   0,   0,   0,  16,   0, 
-      0,   0,   0,   0,   0,   0, 
-    168,   1,   0,   0,   0,   0, 
-      0,   0,  56,   2,   0,   0, 
-    192,   0,   0,   0,  16,   0, 
-      0,   0,   0,   0,   0,   0, 
-     72,   2,   0,   0,   0,   0, 
-      0,   0,  88,   2,   0,   0, 
-    208,   0,   0,   0,  16,   0, 
-      0,   0,   0,   0,   0,   0, 
-     72,   2,   0,   0,   0,   0, 
-      0,   0,  99,   2,   0,   0, 
+      0,   2,   0,   0,   0,   0, 
+      0,   0,  16,   2,   0,   0, 
+     48,   0,   0,   0,  44,   0, 
+      0,   0,   0,   0,   0,   0, 
+     32,   2,   0,   0,   0,   0, 
+      0,   0,  48,   2,   0,   0, 
+     96,   0,   0,   0,  64,   0, 
+      0,   0,   0,   0,   0,   0, 
+     64,   2,   0,   0,   0,   0, 
+      0,   0,  80,   2,   0,   0, 
+    160,   0,   0,   0,  64,   0, 
+      0,   0,   0,   0,   0,   0, 
+     64,   2,   0,   0,   0,   0, 
+      0,   0,  92,   2,   0,   0, 
     224,   0,   0,   0,  16,   0, 
       0,   0,   0,   0,   0,   0, 
-     72,   2,   0,   0,   0,   0, 
-      0,   0, 109,   2,   0,   0, 
-    240,   0,   0,   0,  64,   0, 
-      0,   0,   0,   0,   0,   0, 
-      8,   2,   0,   0,   0,   0, 
+    192,   1,   0,   0,   0,   0, 
+      0,   0, 112,   2,   0,   0, 
+    240,   0,   0,   0,  16,   0, 
+      0,   0,   0,   0,   0,   0, 
+    128,   2,   0,   0,   0,   0, 
+      0,   0, 144,   2,   0,   0, 
+      0,   1,   0,   0,  16,   0, 
+      0,   0,   0,   0,   0,   0, 
+    128,   2,   0,   0,   0,   0, 
+      0,   0, 155,   2,   0,   0, 
+     16,   1,   0,   0,  16,   0, 
+      0,   0,   0,   0,   0,   0, 
+    128,   2,   0,   0,   0,   0, 
+      0,   0, 165,   2,   0,   0, 
+     32,   1,   0,   0,  64,   0, 
+      0,   0,   0,   0,   0,   0, 
+     64,   2,   0,   0,   0,   0, 
       0,   0, 102,  76,  97, 121, 
     101, 114,  67, 111, 108, 111, 
     114,   0,   1,   0,   3,   0, 
       1,   0,   4,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
     102,  76,  97, 121, 101, 114, 
      79, 112,  97,  99, 105, 116, 
     121,   0, 171, 171,   0,   0, 
       3,   0,   1,   0,   1,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0, 105,  66, 108, 101, 
     110, 100,  67, 111, 110, 102, 
     105, 103,   0, 171, 171, 171, 
       1,   0,  19,   0,   1,   0, 
       4,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0, 109,  76, 
-     97, 121, 101, 114,  84, 114, 
-     97, 110, 115, 102, 111, 114, 
-    109,   0,   3,   0,   3,   0, 
-      4,   0,   4,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-    109,  80, 114, 111, 106, 101, 
-     99, 116, 105, 111, 110,   0, 
-    118,  82, 101, 110, 100, 101, 
-    114,  84,  97, 114, 103, 101, 
-    116,  79, 102, 102, 115, 101, 
-    116,   0, 118,  84, 101, 120, 
-    116, 117, 114, 101,  67, 111, 
-    111, 114, 100, 115,   0, 171, 
-      1,   0,   3,   0,   1,   0, 
-      4,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0, 118,  76, 
-     97, 121, 101, 114,  81, 117, 
-     97, 100,   0, 118,  77,  97, 
-    115, 107,  81, 117,  97, 100, 
-      0, 109,  66,  97,  99, 107, 
-    100, 114, 111, 112,  84, 114, 
-     97, 110, 115, 102, 111, 114, 
-    109,   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,  49,  48,  46,  48,  46, 
-     49,  48,  48,  49,  49,  46, 
-     49,  54,  51,  56,  52,   0, 
-     73,  83,  71,  78, 104,   0, 
+      0,   0,   0,   0, 109,  89, 
+    117, 118,  67, 111, 108, 111, 
+    114,  77,  97, 116, 114, 105, 
+    120,   0,   2,   0,   3,   0, 
+      3,   0,   3,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+    109,  76,  97, 121, 101, 114, 
+     84, 114,  97, 110, 115, 102, 
+    111, 114, 109,   0,   3,   0, 
+      3,   0,   4,   0,   4,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0, 109,  80, 114, 111, 
+    106, 101,  99, 116, 105, 111, 
+    110,   0, 118,  82, 101, 110, 
+    100, 101, 114,  84,  97, 114, 
+    103, 101, 116,  79, 102, 102, 
+    115, 101, 116,   0, 118,  84, 
+    101, 120, 116, 117, 114, 101, 
+     67, 111, 111, 114, 100, 115, 
+      0, 171,   1,   0,   3,   0, 
+      1,   0,   4,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+    118,  76,  97, 121, 101, 114, 
+     81, 117,  97, 100,   0, 118, 
+     77,  97, 115, 107,  81, 117, 
+     97, 100,   0, 109,  66,  97, 
+     99, 107, 100, 114, 111, 112, 
+     84, 114,  97, 110, 115, 102, 
+    111, 114, 109,   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,  49,  48,  46, 
+     49,   0,  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,   0,   0, 
+      3,   0,   0,   0,   1,   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, 
+     92,   0,   0,   0,   1,   0, 
+      0,   0,   0,   0,   0,   0, 
+      3,   0,   0,   0,   2,   0, 
+      0,   0,   7,   7,   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, 
+     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,   1,   0,   0,   0, 
-      3,   0,   0,   0,  92,   0, 
-      0,   0,   1,   0,   0,   0, 
-      0,   0,   0,   0,   3,   0, 
-      0,   0,   2,   0,   0,   0, 
-      7,   7,   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,  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
+      0,   0,   0,   0,   0,   0, 
+     15,   0,   0,   0,  83,  86, 
+     95,  84,  97, 114, 103, 101, 
+    116,   0, 171, 171
 };
 ShaderBytes sSolidColorShaderMask = { SolidColorShaderMask, sizeof(SolidColorShaderMask) };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 10.0.10011.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 10.1
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16 [unused]
 //   float fLayerOpacity;               // Offset:   16 Size:     4
 //   uint4 iBlendConfig;                // Offset:   32 Size:    16 [unused]
-//   float4x4 mLayerTransform;          // Offset:   48 Size:    64 [unused]
-//   float4x4 mProjection;              // Offset:  112 Size:    64 [unused]
-//   float4 vRenderTargetOffset;        // Offset:  176 Size:    16 [unused]
-//   float4 vTextureCoords;             // Offset:  192 Size:    16 [unused]
-//   float4 vLayerQuad;                 // Offset:  208 Size:    16 [unused]
-//   float4 vMaskQuad;                  // Offset:  224 Size:    16 [unused]
-//   float4x4 mBackdropTransform;       // Offset:  240 Size:    64 [unused]
+//   row_major float3x3 mYuvColorMatrix;// Offset:   48 Size:    44 [unused]
+//   float4x4 mLayerTransform;          // Offset:   96 Size:    64 [unused]
+//   float4x4 mProjection;              // Offset:  160 Size:    64 [unused]
+//   float4 vRenderTargetOffset;        // Offset:  224 Size:    16 [unused]
+//   float4 vTextureCoords;             // Offset:  240 Size:    16 [unused]
+//   float4 vLayerQuad;                 // Offset:  256 Size:    16 [unused]
+//   float4 vMaskQuad;                  // Offset:  272 Size:    16 [unused]
+//   float4x4 mBackdropTransform;       // Offset:  288 Size:    64 [unused]
 //
 // }
 //
 //
 // Resource Bindings:
 //
 // Name                                 Type  Format         Dim      HLSL Bind  Count
 // ------------------------------ ---------- ------- ----------- -------------- ------
@@ -3063,25 +3094,25 @@ sample r1.xyzw, r1.xyxx, t5.xyzw, s0
 mov r0.w, cb0[1].x
 mul o0.xyzw, r0.xyzw, r1.xxxx
 ret 
 // Approximately 7 instruction slots used
 #endif
 
 const BYTE RGBShaderMask[] =
 {
-     68,  88,  66,  67,  79, 247, 
-    118, 147, 119, 222,  85,  19, 
-    212, 225, 110,  66, 228, 229, 
-    204, 201,   1,   0,   0,   0, 
-     92,   6,   0,   0,   6,   0, 
+     68,  88,  66,  67,  89, 221, 
+     15,  22, 232, 140, 114, 122, 
+    200,  15, 217, 125, 153,  18, 
+    224,   0,   1,   0,   0,   0, 
+    136,   6,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
      36,   1,   0,   0,  88,   2, 
       0,   0, 212,   2,   0,   0, 
-    184,   5,   0,   0,  40,   6, 
+    228,   5,   0,   0,  84,   6, 
       0,   0,  65, 111, 110,  57, 
     228,   0,   0,   0, 228,   0, 
       0,   0,   0,   2, 255, 255, 
     172,   0,   0,   0,  56,   0, 
       0,   0,   1,   0,  44,   0, 
       0,   0,  56,   0,   0,   0, 
      56,   0,   2,   0,  36,   0, 
       0,   0,  56,   0,   0,   0, 
@@ -3184,22 +3215,22 @@ const BYTE RGBShaderMask[] =
       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, 220,   2,   0,   0, 
+     69,  70,   8,   3,   0,   0, 
       1,   0,   0,   0, 188,   0, 
       0,   0,   4,   0,   0,   0, 
      28,   0,   0,   0,   0,   4, 
     255, 255,   0,   1,   0,   0, 
-    168,   2,   0,   0, 156,   0, 
+    224,   2,   0,   0, 156,   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,   1,   0,   0,   0, 
     165,   0,   0,   0,   2,   0, 
       0,   0,   5,   0,   0,   0, 
       4,   0,   0,   0, 255, 255, 
@@ -3217,156 +3248,164 @@ const BYTE RGBShaderMask[] =
       0,   0,   0,   0,   1,   0, 
       0,   0,   0,   0,   0,   0, 
     115,  83,  97, 109, 112, 108, 
     101, 114,   0, 116,  82,  71, 
      66,   0, 116,  77,  97, 115, 
     107,   0,  36,  71, 108, 111, 
      98,  97, 108, 115,   0, 171, 
     171, 171, 176,   0,   0,   0, 
-     10,   0,   0,   0, 212,   0, 
-      0,   0,  48,   1,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0, 196,   1,   0,   0, 
+     11,   0,   0,   0, 212,   0, 
+      0,   0,  96,   1,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0, 220,   1,   0,   0, 
       0,   0,   0,   0,  16,   0, 
       0,   0,   0,   0,   0,   0, 
-    208,   1,   0,   0,   0,   0, 
-      0,   0, 224,   1,   0,   0, 
+    232,   1,   0,   0,   0,   0, 
+      0,   0, 248,   1,   0,   0, 
      16,   0,   0,   0,   4,   0, 
       0,   0,   2,   0,   0,   0, 
-    240,   1,   0,   0,   0,   0, 
-      0,   0,   0,   2,   0,   0, 
+      8,   2,   0,   0,   0,   0, 
+      0,   0,  24,   2,   0,   0, 
      32,   0,   0,   0,  16,   0, 
       0,   0,   0,   0,   0,   0, 
-     16,   2,   0,   0,   0,   0, 
-      0,   0,  32,   2,   0,   0, 
-     48,   0,   0,   0,  64,   0, 
-      0,   0,   0,   0,   0,   0, 
-     48,   2,   0,   0,   0,   0, 
-      0,   0,  64,   2,   0,   0, 
-    112,   0,   0,   0,  64,   0, 
-      0,   0,   0,   0,   0,   0, 
-     48,   2,   0,   0,   0,   0, 
-      0,   0,  76,   2,   0,   0, 
-    176,   0,   0,   0,  16,   0, 
-      0,   0,   0,   0,   0,   0, 
-    208,   1,   0,   0,   0,   0, 
-      0,   0,  96,   2,   0,   0, 
-    192,   0,   0,   0,  16,   0, 
-      0,   0,   0,   0,   0,   0, 
-    112,   2,   0,   0,   0,   0, 
-      0,   0, 128,   2,   0,   0, 
-    208,   0,   0,   0,  16,   0, 
-      0,   0,   0,   0,   0,   0, 
-    112,   2,   0,   0,   0,   0, 
-      0,   0, 139,   2,   0,   0, 
+     40,   2,   0,   0,   0,   0, 
+      0,   0,  56,   2,   0,   0, 
+     48,   0,   0,   0,  44,   0, 
+      0,   0,   0,   0,   0,   0, 
+     72,   2,   0,   0,   0,   0, 
+      0,   0,  88,   2,   0,   0, 
+     96,   0,   0,   0,  64,   0, 
+      0,   0,   0,   0,   0,   0, 
+    104,   2,   0,   0,   0,   0, 
+      0,   0, 120,   2,   0,   0, 
+    160,   0,   0,   0,  64,   0, 
+      0,   0,   0,   0,   0,   0, 
+    104,   2,   0,   0,   0,   0, 
+      0,   0, 132,   2,   0,   0, 
     224,   0,   0,   0,  16,   0, 
       0,   0,   0,   0,   0,   0, 
-    112,   2,   0,   0,   0,   0, 
-      0,   0, 149,   2,   0,   0, 
-    240,   0,   0,   0,  64,   0, 
-      0,   0,   0,   0,   0,   0, 
-     48,   2,   0,   0,   0,   0, 
+    232,   1,   0,   0,   0,   0, 
+      0,   0, 152,   2,   0,   0, 
+    240,   0,   0,   0,  16,   0, 
+      0,   0,   0,   0,   0,   0, 
+    168,   2,   0,   0,   0,   0, 
+      0,   0, 184,   2,   0,   0, 
+      0,   1,   0,   0,  16,   0, 
+      0,   0,   0,   0,   0,   0, 
+    168,   2,   0,   0,   0,   0, 
+      0,   0, 195,   2,   0,   0, 
+     16,   1,   0,   0,  16,   0, 
+      0,   0,   0,   0,   0,   0, 
+    168,   2,   0,   0,   0,   0, 
+      0,   0, 205,   2,   0,   0, 
+     32,   1,   0,   0,  64,   0, 
+      0,   0,   0,   0,   0,   0, 
+    104,   2,   0,   0,   0,   0, 
       0,   0, 102,  76,  97, 121, 
     101, 114,  67, 111, 108, 111, 
     114,   0,   1,   0,   3,   0, 
       1,   0,   4,   0,   0,   0, 
       0,   0,   0,   0,   0,   0, 
     102,  76,  97, 121, 101, 114, 
      79, 112,  97,  99, 105, 116, 
     121,   0, 171, 171,   0,   0, 
       3,   0,   1,   0,   1,   0, 
       0,   0,   0,   0,   0,   0, 
       0,   0, 105,  66, 108, 101, 
     110, 100,  67, 111, 110, 102, 
     105, 103,   0, 171, 171, 171, 
       1,   0,  19,   0,   1,   0, 
       4,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0, 109,  76, 
-     97, 121, 101, 114,  84, 114, 
-     97, 110, 115, 102, 111, 114, 
-    109,   0,   3,   0,   3,   0, 
-      4,   0,   4,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-    109,  80, 114, 111, 106, 101, 
-     99, 116, 105, 111, 110,   0, 
-    118,  82, 101, 110, 100, 101, 
-    114,  84,  97, 114, 103, 101, 
-    116,  79, 102, 102, 115, 101, 
-    116,   0, 118,  84, 101, 120, 
-    116, 117, 114, 101,  67, 111, 
-    111, 114, 100, 115,   0, 171, 
-      1,   0,   3,   0,   1,   0, 
-      4,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0, 118,  76, 
-     97, 121, 101, 114,  81, 117, 
-     97, 100,   0, 118,  77,  97, 
-    115, 107,  81, 117,  97, 100, 
-      0, 109,  66,  97,  99, 107, 
-    100, 114, 111, 112,  84, 114, 
-     97, 110, 115, 102, 111, 114, 
-    109,   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,  49,  48,  46,  48,  46, 
-     49,  48,  48,  49,  49,  46, 
-     49,  54,  51,  56,  52,   0, 
-     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, 109,  89, 
+    117, 118,  67, 111, 108, 111, 
+    114,  77,  97, 116, 114, 105, 
+    120,   0,   2,   0,   3,   0, 
+      3,   0,   3,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+    109,  76,  97, 121, 101, 114, 
+     84, 114,  97, 110, 115, 102, 
+    111, 114, 109,   0,   3,   0, 
+      3,   0,   4,   0,   4,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0, 109,  80, 114, 111, 
+    106, 101,  99, 116, 105, 111, 
+    110,   0, 118,  82, 101, 110, 
+    100, 101, 114,  84,  97, 114, 
+    103, 101, 116,  79, 102, 102, 
+    115, 101, 116,   0, 118,  84, 
+    101, 120, 116, 117, 114, 101, 
+     67, 111, 111, 114, 100, 115, 
+      0, 171,   1,   0,   3,   0, 
+      1,   0,   4,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+    118,  76,  97, 121, 101, 114, 
+     81, 117,  97, 100,   0, 118, 
+     77,  97, 115, 107,  81, 117, 
+     97, 100,   0, 109,  66,  97, 
+     99, 107, 100, 114, 111, 112, 
+     84, 114,  97, 110, 115, 102, 
+    111, 114, 109,   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,  49,  48,  46, 
+     49,   0,  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,   0,   0, 
+      3,   0,   0,   0,   1,   0, 
+      0,   0,   3,   3,   0,   0, 
+     92,   0,   0,   0,   1,   0, 
+      0,   0,   0,   0,   0,   0, 
+      3,   0,   0,   0,   2,   0, 
+      0,   0,   7,   7,   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, 
+     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,   1,   0,   0,   0, 
-      3,   3,   0,   0,  92,   0, 
-      0,   0,   1,   0,   0,   0, 
-      0,   0,   0,   0,   3,   0, 
-      0,   0,   2,   0,   0,   0, 
-      7,   7,   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,  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
+      0,   0,   0,   0,   0,   0, 
+     15,   0,   0,   0,  83,  86, 
+     95,  84,  97, 114, 103, 101, 
+    116,   0, 171, 171
 };
 ShaderBytes sRGBShaderMask = { RGBShaderMask, sizeof(RGBShaderMask) };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 10.0.10011.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 10.1
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4 fLayerColor;                // Offset:    0 Size:    16 [unused]
 //   float fLayerOpacity;               // Offset:   16 Size:     4
 //   uint4 iBlendConfig;                // Offset:   32 Size:    16 [unused]
-//   float4x4 mLayerTransform;          // Offset:   48 Size:    64 [unused]
-//   float4x4 mProjection;              // Offset:  112 Size:    64 [unused]
-//   float4 vRenderTargetOffset;        // Offset:  176 Size:    16 [unused]
-//   float4 vTextureCoords;             // Offset:  192 Size:    16 [unused]
-//   float4 vLayerQuad;                 // Offset:  208 Size:    16 [unused]
-//   float4 vMaskQuad;                  // Offset:  224 Size:    16 [unused]
-//   float4x4 mBackdropTransform;       // Offset:  240 Size:    64 [unused]
+//   row_major float3x3 mYuvColorMatrix;// Offset:   48 Size:    44 [unused]
+//   float4x4 mLayerTransform;          // Offset:   96 Size:    64 [unused]
+//   float4x4 mProjection;              // Offset:  160 Size:    64 [unused]
+//   float4 vRenderTargetOffset;        // Offset:  224 Size:    16 [unused]
+//   float4 vTextureCoords;             // Offset:  240 Size:    16 [unused]
+//   float4 vLayerQuad;                 // Offset:  256 Size:    16 [unused]
+//   float4 vMaskQuad;                  // Offset:  272 Size:    16 [unused]
+//   float4x4 mBackdropTransform;       // Offset:  288 Size:    64 [unused]
 //
 // }
 //
 //
 // Resource Bindings:
 //
 // Name                                 Type  Format         Dim      HLSL Bind  Count
 // ------------------------------ ---------- ------- ----------- -------------- ------
@@ -3439,25 +3478,25 @@ sample r1.xyzw, v1.xyxx, t0.xyzw, s0
 mul r1.xyzw, r1.xyzw, cb0[1].xxxx
 mul o0.xyzw, r0.xxxx, r1.xyzw
 ret 
 // Approximately 6 instruction slots used
 #endif
 
 const BYTE RGBAShaderMask[] =
 {
-     68,  88,  66,  67, 100,  50, 
-    112, 237, 158, 118, 201, 119, 
-    153, 231, 223, 176, 232, 201, 
-    145, 152,   1,   0,   0,   0, 
-     56,   6,   0,   0,   6,   0, 
+     68,  88,  66,  67, 195, 236, 
+    129, 118, 244,  48, 247, 117, 
+    155, 208,   5,  31,   9, 224, 
+     75,  19,   1,   0,   0,   0, 
+    100,   6,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
      24,   1,   0,   0,  52,   2, 
       0,   0, 176,   2,   0,   0, 
-    148,   5,   0,   0,   4,   6, 
+    192,   5,   0,   0,  48,   6, 
       0,   0,  65, 111, 110,  57, 
     216,   0,   0,   0, 216,   0, 
       0,   0,   0,   2, 255, 255, 
     160,   0,   0,   0,  56,   0, 
       0,   0,   1,   0,  44,   0, 
       0,   0,  56,   0,   0,   0, 
      56,   0,   2,   0,  36,   0, 
       0,   0,  56,   0,   0,   0, 
@@ -3554,22 +3593,22 @@ const BYTE RGBAShaderMask[] =
       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,  82,  68, 
-     69,  70, 220,   2,   0,   0, 
+     69,  70,   8,   3,   0,   0, 
       1,   0,   0,   0, 188,   0, 
       0,   0,   4,   0,   0,   0, 
      28,   0,   0,   0,   0,   4, 
     255, 255,   0,   1,   0,   0, 
-    168,   2,   0,   0, 156,   0, 
+    224,   2,   0,   0, 156,   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,   1,   0,   0,   0, 
     165,   0,   0,   0,   2,   0, 
       0,   0,   5,   0,   0,   0, 
       4,   0,   0,   0, 255, 255, 
@@ -3587,156 +3626,164 @@ const BYTE RGBAShaderMask[] =
       0,   0,   0,   0,   1,   0, 
       0,   0,   0,   0,   0,   0, 
     115,  83,  97, 109, 112, 108, 
     101, 114,   0, 116,  82,  71, 
      66,   0, 116,  77,  97, 115, 
     107,   0,  36,  71, 108, 111, 
      98,  97, 108, 115,   0, 171, 
     171, 171, 176,   0,   0,   0, 
-     10,   0,   0,   0, 212,   0, 
-      0,   0,  48,   1,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0, 196,   1,   0,   0, 
+     11,   0,   0,   0, 212,   0, 
+      0,   0,  96,   1,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0, 220,   1,   0,   0, 
       0,   0,   0,   0,  16,   0, 
       0,   0,   0,   0,   0,   0, 
-    208,   1,   0,   0,   0,   0, 
-      0,   0, 224,   1,   0,   0, 
+    232,   1,   0,   0,   0,   0, 
+      0,   0, 248,   1,   0,   0, 
      16,   0,   0,   0,   4,   0, 
       0,   0,   2,   0,   0,   0, 
-    240,   1,   0,   0,   0,   0, 
-      0,   0,   0,   2,   0,   0, 
+      8,   2,   0,   0,   0,   0, 
+      0,   0,  24,   2,   0,   0, 
      32,   0,   0,   0,  16,   0, 
       0,   0,   0,   0,   0,   0, 
-     16,   2,   0,   0,   0,   0, 
-      0,   0,  32,   2,   0,   0, 
-     48,   0,   0,   0,  64,   0, 
-      0,   0,   0,   0,   0,   0, 
-     48,   2,   0,   0,   0,   0, 
-      0,   0,  64,   2,   0,   0, 
-    112,   0,   0,   0,  64,   0, 
-      0,   0,   0,   0,   0,   0, 
-     48,   2,   0,   0,   0,   0, 
-      0,   0,  76,   2,   0,   0, 
-    176,   0,   0,   0,  16,   0, 
-      0,   0,   0,   0,   0,   0, 
-    208,   1,   0,   0,   0,   0, 
-      0,   0,  96,   2,   0,   0, 
-    192,   0,   0,   0,  16,   0, 
-      0,   0,   0,   0,   0,   0, 
-    112,   2,   0,   0,   0,   0, 
-      0,   0, 128,   2,   0,   0, 
-    208,   0,   0,   0,  16,   0, 
-      0,   0,   0,   0,   0,   0, 
-    112,   2,   0,   0,   0,   0, 
-      0,   0, 139,   2,   0,   0, 
+     40,   2,   0,   0,   0,   0, 
+      0,   0,  56,   2,   0,   0, 
+     48,   0,   0,   0,  44,   0, 
+      0,   0,   0,   0,   0,   0, 
+     72,   2,   0,   0,   0,   0, 
+      0,   0,  88,   2,   0,   0, 
+     96,   0,   0,   0,  64,   0, 
+      0,   0,   0,   0,   0,   0, 
+    104,   2,   0,   0,   0,   0, 
+      0,   0, 120,   2,   0,   0, 
+    160,   0,   0,   0,  64,   0, 
+      0,   0,   0,   0,   0,   0, 
+    104,   2,   0,   0,   0,   0, 
+      0,   0, 132,   2,   0,   0,