Merge m-c to oak DONTBUILD
authorRobert Strong <robert.bugzilla@gmail.com>
Wed, 22 Mar 2017 10:21:37 -0700
changeset 558490 2831381e07866444c0d93e5b2e0d0c0f7336b62c
parent 558489 f9a7945fc735958f4034ca2999c89d6226530229 (current diff)
parent 502997 e03e0c60462c775c7558a1dc9d5cf2076c3cd1f9 (diff)
child 558491 829e3ed4b9c57b5fb8d545d13ff64eaa5ea9f4bd
push id52896
push userCallek@gmail.com
push dateFri, 07 Apr 2017 18:15:30 +0000
milestone55.0a1
Merge m-c to oak DONTBUILD
README.txt
browser/themes/windows/loop/toolbar-win10.png
browser/themes/windows/loop/toolbar-win10@2x.png
layout/svg/AutoReferenceLimiter.h
layout/svg/nsISVGChildFrame.h
old-configure.in
testing/mach_commands.py
testing/mochitest/browser.eslintrc.js
testing/mochitest/chrome.eslintrc.js
testing/mochitest/mochitest.eslintrc.js
testing/mochitest/mochitest_options.py
testing/mozbase/docs/devicemanagement.rst
testing/mozbase/docs/mozdevice.rst
testing/mozbase/mozdevice/mozdevice/Zeroconf.py
testing/mozbase/mozdevice/mozdevice/devicemanagerSUT.py
testing/mozbase/mozdevice/mozdevice/sutini.py
testing/mozbase/mozdevice/sut_tests/README.md
testing/mozbase/mozdevice/sut_tests/dmunit.py
testing/mozbase/mozdevice/sut_tests/genfiles.py
testing/mozbase/mozdevice/sut_tests/runtests.py
testing/mozbase/mozdevice/sut_tests/setup-tools.sh
testing/mozbase/mozdevice/sut_tests/test-files/mytext.txt
testing/mozbase/mozdevice/sut_tests/test-files/smalltext.txt
testing/mozbase/mozdevice/sut_tests/test-files/test_script.sh
testing/mozbase/mozdevice/sut_tests/test_datachannel.py
testing/mozbase/mozdevice/sut_tests/test_exec.py
testing/mozbase/mozdevice/sut_tests/test_exec_env.py
testing/mozbase/mozdevice/sut_tests/test_fileExists.py
testing/mozbase/mozdevice/sut_tests/test_getdir.py
testing/mozbase/mozdevice/sut_tests/test_info.py
testing/mozbase/mozdevice/sut_tests/test_prompt.py
testing/mozbase/mozdevice/sut_tests/test_ps.py
testing/mozbase/mozdevice/sut_tests/test_pull.py
testing/mozbase/mozdevice/sut_tests/test_push1.py
testing/mozbase/mozdevice/sut_tests/test_push2.py
testing/mozbase/mozdevice/sut_tests/test_pushbinary.py
testing/mozbase/mozdevice/sut_tests/test_pushsmalltext.py
testing/mozbase/mozdevice/tests/droidsut_launch.py
testing/mozbase/mozdevice/tests/manifest.ini
testing/mozbase/mozdevice/tests/sut.py
testing/mozbase/mozdevice/tests/sut_app.py
testing/mozbase/mozdevice/tests/sut_basic.py
testing/mozbase/mozdevice/tests/sut_chmod.py
testing/mozbase/mozdevice/tests/sut_copytree.py
testing/mozbase/mozdevice/tests/sut_fileExists.py
testing/mozbase/mozdevice/tests/sut_fileMethods.py
testing/mozbase/mozdevice/tests/sut_info.py
testing/mozbase/mozdevice/tests/sut_ip.py
testing/mozbase/mozdevice/tests/sut_kill.py
testing/mozbase/mozdevice/tests/sut_list.py
testing/mozbase/mozdevice/tests/sut_logcat.py
testing/mozbase/mozdevice/tests/sut_mkdir.py
testing/mozbase/mozdevice/tests/sut_movetree.py
testing/mozbase/mozdevice/tests/sut_ps.py
testing/mozbase/mozdevice/tests/sut_pull.py
testing/mozbase/mozdevice/tests/sut_push.py
testing/mozbase/mozdevice/tests/sut_remove.py
testing/mozbase/mozdevice/tests/sut_time.py
testing/mozbase/mozdevice/tests/sut_unpackfile.py
testing/xpcshell/xpcshell.eslintrc.js
toolkit/components/telemetry/Histograms.json
toolkit/crashreporter/nsExceptionHandler.cpp
toolkit/mozapps/installer/upload-files.mk
toolkit/xre/nsAppRunner.cpp
--- a/README.txt
+++ b/README.txt
@@ -1,27 +1,27 @@
 An explanation of the Mozilla Source Code Directory Structure and links to
 project pages with documentation can be found at:
 
     https://developer.mozilla.org/en/Mozilla_Source_Code_Directory_Structure
 
 For information on how to build Mozilla from the source code, see:
 
-    http://developer.mozilla.org/en/docs/Build_Documentation
+    https://developer.mozilla.org/en/docs/Build_Documentation
 
 To have your bug fix / feature added to Mozilla, you should create a patch and
 submit it to Bugzilla (https://bugzilla.mozilla.org). Instructions are at:
 
-    http://developer.mozilla.org/en/docs/Creating_a_patch
-    http://developer.mozilla.org/en/docs/Getting_your_patch_in_the_tree
+    https://developer.mozilla.org/en/docs/Creating_a_patch
+    https://developer.mozilla.org/en/docs/Getting_your_patch_in_the_tree
 
 If you have a question about developing Mozilla, and can't find the solution
-on http://developer.mozilla.org, you can try asking your question in a
+on https://developer.mozilla.org, you can try asking your question in a
 mozilla.* Usenet group, or on IRC at irc.mozilla.org. [The Mozilla news groups
 are accessible on Google Groups, or news.mozilla.org with a NNTP reader.]
 
 You can download nightly development builds from the Mozilla FTP server.
 Keep in mind that nightly builds, which are used by Mozilla developers for
 testing, may be buggy. Firefox nightlies, for example, can be found at:
 
     https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central/
             - or -
-    http://nightly.mozilla.org/
+    https://nightly.mozilla.org/
--- a/accessible/tests/browser/.eslintrc.js
+++ b/accessible/tests/browser/.eslintrc.js
@@ -1,13 +1,13 @@
 "use strict";
 
 module.exports = { // eslint-disable-line no-undef
   "extends": [
-    "../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ],
   // All globals made available in the test environment.
   "globals": {
     // Content scripts have global 'content' object
     "content": true,
 
     "add_task": true,
 
--- a/browser/.eslintrc.js
+++ b/browser/.eslintrc.js
@@ -1,12 +1,15 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../toolkit/.eslintrc.js"
+    "plugin:mozilla/recommended"
   ],
 
   "rules": {
+    // XXX Bug 1326071 - This should be reduced down - probably to 20 or to
+    // be removed & synced with the mozilla/recommended value.
+    "complexity": ["error", {"max": 42}],
+
     "no-shadow": "error",
-    "no-undef": "error"
   }
 };
--- a/browser/app/blocklist.xml
+++ b/browser/app/blocklist.xml
@@ -2175,16 +2175,21 @@
       <infoURL>https://get.adobe.com/flashplayer/</infoURL>
       <versionRange maxVersion="24.0.0.186" minVersion="23.0.0.207" severity="0" vulnerabilitystatus="1"/>
     </pluginItem>
     <pluginItem blockID="p1420">
       <match exp="(NPSWF32.*\.dll)|(NPSWF64.*\.dll)|(Flash\ Player\.plugin)" name="filename"/>
       <infoURL>https://get.adobe.com/flashplayer/</infoURL>
       <versionRange maxVersion="23.0.0.205" minVersion="23.0.0.185" severity="0" vulnerabilitystatus="1"/>
     </pluginItem>
+    <pluginItem blockID="26c2a4e2-9aff-4ab1-b654-20e478b375f0" os="Linux">
+      <match exp="libflashplayer\.so" name="filename"/>
+      <infoURL>https://get.adobe.com/flashplayer/</infoURL>
+      <versionRange maxVersion="24.0.0.221" minVersion="24.0.0.194" severity="0" vulnerabilitystatus="1"/>
+    </pluginItem>
     <pluginItem blockID="p248">
       <match exp="Scorch\.plugin" name="filename"/>
       <versionRange maxVersion="6.2.0b88" minVersion="0" severity="1"/>
     </pluginItem>
     <pluginItem blockID="p1141">
       <match exp="JavaAppletPlugin\.plugin" name="filename"/>
       <infoURL>https://java.com/</infoURL>
       <versionRange maxVersion="Java 7 Update 97" minVersion="Java 7 Update 91" severity="0" vulnerabilitystatus="1"/>
@@ -2201,16 +2206,21 @@
         <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
           <versionRange maxVersion="17.0.1" minVersion="0.1"/>
         </targetApplication>
       </versionRange>
     </pluginItem>
     <pluginItem blockID="p31">
       <match exp="NPMySrch.dll" name="filename"/>
     </pluginItem>
+    <pluginItem blockID="2b608fae-1750-4a06-a142-0bc9ba17a7d0">
+      <match exp="(NPSWF32.*\.dll)|(NPSWF64.*\.dll)|(Flash\ Player\.plugin)" name="filename"/>
+      <infoURL>https://get.adobe.com/flashplayer/</infoURL>
+      <versionRange maxVersion="24.0.0.221" minVersion="24.0.0.194" severity="0" vulnerabilitystatus="1"/>
+    </pluginItem>
     <pluginItem blockID="p1020">
       <match exp="(NPSWF32.*\.dll)|(NPSWF64.*\.dll)|(Flash\ Player\.plugin)" name="filename"/>
       <infoURL>https://get.adobe.com/flashplayer/</infoURL>
       <versionRange maxVersion="13.*" minVersion="13.0" severity="0" vulnerabilitystatus="1"/>
     </pluginItem>
     <pluginItem blockID="p958">
       <match exp="Java\(TM\) Platform SE 7 U(79|80)(\s[^\d\._U]|$)" name="name"/>
       <match exp="npjp2\.dll" name="filename"/>
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -799,48 +799,51 @@ addMessageListener("ContextMenu:SaveVide
   let ctxDraw = canvas.getContext("2d");
   ctxDraw.drawImage(video, 0, 0);
   sendAsyncMessage("ContextMenu:SaveVideoFrameAsImage:Result", {
     dataURL: canvas.toDataURL("image/jpeg", ""),
   });
 });
 
 addMessageListener("ContextMenu:MediaCommand", (message) => {
-  let media = message.objects.element;
-
-  switch (message.data.command) {
-    case "play":
-      media.play();
-      break;
-    case "pause":
-      media.pause();
-      break;
-    case "loop":
-      media.loop = !media.loop;
-      break;
-    case "mute":
-      media.muted = true;
-      break;
-    case "unmute":
-      media.muted = false;
-      break;
-    case "playbackRate":
-      media.playbackRate = message.data.data;
-      break;
-    case "hidecontrols":
-      media.removeAttribute("controls");
-      break;
-    case "showcontrols":
-      media.setAttribute("controls", "true");
-      break;
-    case "fullscreen":
-      if (content.document.fullscreenEnabled)
-        media.requestFullscreen();
-      break;
-  }
+  E10SUtils.wrapHandlingUserInput(
+    content, message.data.handlingUserInput,
+    () => {
+      let media = message.objects.element;
+      switch (message.data.command) {
+        case "play":
+          media.play();
+          break;
+        case "pause":
+          media.pause();
+          break;
+        case "loop":
+          media.loop = !media.loop;
+          break;
+        case "mute":
+          media.muted = true;
+          break;
+        case "unmute":
+          media.muted = false;
+          break;
+        case "playbackRate":
+          media.playbackRate = message.data.data;
+          break;
+        case "hidecontrols":
+          media.removeAttribute("controls");
+          break;
+        case "showcontrols":
+          media.setAttribute("controls", "true");
+          break;
+        case "fullscreen":
+          if (content.document.fullscreenEnabled)
+            media.requestFullscreen();
+          break;
+      }
+    });
 });
 
 addMessageListener("ContextMenu:Canvas:ToBlobURL", (message) => {
   message.objects.target.toBlob((blob) => {
     let blobURL = URL.createObjectURL(blob);
     sendAsyncMessage("ContextMenu:Canvas:ToBlobURL:Result", { blobURL });
   });
 });
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -1736,18 +1736,23 @@ nsContextMenu.prototype = {
   },
 
   switchPageDirection: function CM_switchPageDirection() {
     this.browser.messageManager.sendAsyncMessage("SwitchDocumentDirection");
   },
 
   mediaCommand : function CM_mediaCommand(command, data) {
     let mm = this.browser.messageManager;
+    let win = this.browser.ownerGlobal;
+    let windowUtils = win.QueryInterface(Ci.nsIInterfaceRequestor)
+                         .getInterface(Ci.nsIDOMWindowUtils);
     mm.sendAsyncMessage("ContextMenu:MediaCommand",
-                        {command: command, data: data},
+                        {command: command,
+                         data: data,
+                         handlingUserInput: windowUtils.isHandlingUserInput},
                         {element: this.target});
   },
 
   copyMediaLocation : function () {
     var clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].
                     getService(Ci.nsIClipboardHelper);
     clipboard.copyString(this.mediaURL);
   },
--- a/browser/base/content/test/alerts/.eslintrc.js
+++ b/browser/base/content/test/alerts/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/base/content/test/captivePortal/.eslintrc.js
+++ b/browser/base/content/test/captivePortal/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/base/content/test/chrome/.eslintrc.js
+++ b/browser/base/content/test/chrome/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/chrome.eslintrc.js"
+    "plugin:mozilla/chrome-test"
   ]
 };
--- a/browser/base/content/test/forms/browser_selectpopup_colors.js
+++ b/browser/base/content/test/forms/browser_selectpopup_colors.js
@@ -55,16 +55,23 @@ const GENERIC_OPTION_STYLED_AS_IMPORTANT
 
 const TRANSLUCENT_SELECT_BECOMES_OPAQUE =
   "<html><head>" +
   "<body><select id='one' style='background-color: rgba(255,255,255,.55);'>" +
   '  <option value="One">{"color": "rgb(0, 0, 0)", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
   '  <option value="Two" selected="true">{"end": "true"}</option>' +
   "</select></body></html>";
 
+const TRANSLUCENT_SELECT_APPLIES_ON_BASE_COLOR =
+  "<html><head>" +
+  "<body><select id='one' style='background-color: rgba(255,0,0,.55);'>" +
+  '  <option value="One">{"color": "rgb(0, 0, 0)", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
+  '  <option value="Two" selected="true">{"end": "true"}</option>' +
+  "</select></body></html>";
+
 const DISABLED_OPTGROUP_AND_OPTIONS =
   "<html><head>" +
   "<body><select id='one'>" +
   "  <optgroup label='{\"color\": \"rgb(0, 0, 0)\", \"backgroundColor\": \"buttonface\"}'>" +
   '    <option disabled="">{"color": "GrayText", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
   '    <option>{"color": "rgb(0, 0, 0)", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
   '    <option disabled="">{"color": "GrayText", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
   '    <option>{"color": "rgb(0, 0, 0)", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>' +
@@ -135,18 +142,43 @@ function* testSelectColors(select, itemC
 
   is(selectPopup.parentNode.itemCount, itemCount, "Correct number of items");
   let child = selectPopup.firstChild;
   let idx = 1;
 
   if (!options.skipSelectColorTest) {
     is(getComputedStyle(selectPopup).color, options.selectColor,
       "popup has expected foreground color");
-    is(getComputedStyle(selectPopup).backgroundColor, options.selectBgColor,
-      "popup has expected background color");
+
+    // Combine the select popup's backgroundColor and the
+    // backgroundImage color to get the color that is seen by
+    // the user.
+    let base = getComputedStyle(selectPopup).backgroundColor;
+    let [/* unused */, bR, bG, bB] =
+      base.match(/rgb\((\d+), (\d+), (\d+)\)/);
+    bR = parseInt(bR, 10);
+    bG = parseInt(bG, 10);
+    bB = parseInt(bB, 10);
+    let topCoat = getComputedStyle(selectPopup).backgroundImage;
+    if (topCoat == "none") {
+      is(`rgb(${bR}, ${bG}, ${bB})`, options.selectBgColor,
+        "popup has expected background color");
+    } else {
+      let [/* unused */, /* unused */, tR, tG, tB, tA] =
+        topCoat.match(/(rgba?\((\d+), (\d+), (\d+)(?:, (0\.\d+))?\)), \1/);
+      tR = parseInt(tR, 10);
+      tG = parseInt(tG, 10);
+      tB = parseInt(tB, 10);
+      tA = parseFloat(tA) || 1;
+      let actualR = Math.round(tR * tA + bR * (1 - tA));
+      let actualG = Math.round(tG * tA + bG * (1 - tA));
+      let actualB = Math.round(tB * tA + bB * (1 - tA));
+      is(`rgb(${actualR}, ${actualG}, ${actualB})`, options.selectBgColor,
+        "popup has expected background color");
+    }
   }
 
   ok(!child.selected, "The first child should not be selected");
   while (child) {
     testOptionColors(idx, child, menulist);
     idx++;
     child = child.nextSibling;
   }
@@ -212,24 +244,37 @@ add_task(function* test_select_backgroun
 });
 
 // This test checks when a <select> element has a background set, and the
 // options have their own background set which is equal to the default
 // user-agent background color, but should be used because the select
 // background color has been changed.
 add_task(function* test_translucent_select_becomes_opaque() {
   // The popup is requested to show a translucent background
-  // but we force the alpha channel to 1 on the popup.
+  // but we apply the requested background color on the system's base color.
   let options = {
     selectColor: "rgb(0, 0, 0)",
     selectBgColor: "rgb(255, 255, 255)"
   };
   yield testSelectColors(TRANSLUCENT_SELECT_BECOMES_OPAQUE, 2, options);
 });
 
+// This test checks when a popup has a translucent background color,
+// and that the color painted to the screen of the translucent background
+// matches what the user expects.
+add_task(function* test_translucent_select_applies_on_base_color() {
+  // The popup is requested to show a translucent background
+  // but we apply the requested background color on the system's base color.
+  let options = {
+    selectColor: "rgb(0, 0, 0)",
+    selectBgColor: "rgb(255, 115, 115)"
+  };
+  yield testSelectColors(TRANSLUCENT_SELECT_APPLIES_ON_BASE_COLOR, 2, options);
+});
+
 add_task(function* test_disabled_optgroup_and_options() {
   // The colors used by this test are platform-specific.
   if (AppConstants.platform != "win") {
     return;
   }
 
   yield testSelectColors(DISABLED_OPTGROUP_AND_OPTIONS, 17,
                          {skipSelectColorTest: true});
--- a/browser/base/content/test/general/.eslintrc.js
+++ b/browser/base/content/test/general/.eslintrc.js
@@ -1,8 +1,8 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/browser.eslintrc.js",
-    "../../../../../testing/mochitest/mochitest.eslintrc.js",
+    "plugin:mozilla/browser-test",
+    "plugin:mozilla/mochitest-test",
   ]
 };
--- a/browser/base/content/test/newtab/.eslintrc.js
+++ b/browser/base/content/test/newtab/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/base/content/test/pageinfo/.eslintrc.js
+++ b/browser/base/content/test/pageinfo/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/base/content/test/plugins/.eslintrc.js
+++ b/browser/base/content/test/plugins/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/base/content/test/popupNotifications/.eslintrc.js
+++ b/browser/base/content/test/popupNotifications/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/base/content/test/referrer/.eslintrc.js
+++ b/browser/base/content/test/referrer/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/base/content/test/siteIdentity/.eslintrc.js
+++ b/browser/base/content/test/siteIdentity/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/base/content/test/social/.eslintrc.js
+++ b/browser/base/content/test/social/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/base/content/test/tabPrompts/.eslintrc.js
+++ b/browser/base/content/test/tabPrompts/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/base/content/test/tabcrashed/.eslintrc.js
+++ b/browser/base/content/test/tabcrashed/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/base/content/test/tabs/.eslintrc.js
+++ b/browser/base/content/test/tabs/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/base/content/test/urlbar/.eslintrc.js
+++ b/browser/base/content/test/urlbar/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/base/content/test/webrtc/.eslintrc.js
+++ b/browser/base/content/test/webrtc/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -250,16 +250,29 @@ function openLinkIn(url, where, params) 
   // We don't want to open tabs in popups, so try to find a non-popup window in
   // that case.
   if ((where == "tab" || where == "tabshifted") &&
       w && !w.toolbar.visible) {
     w = getTopWin(true);
     aRelatedToCurrent = false;
   }
 
+  // Teach the principal about the right OA to use, e.g. in case when
+  // opening a link in a new private window, or in a new container tab.
+  // Please note we do not have to do that for SystemPrincipals and we
+  // can not do it for NullPrincipals since NullPrincipals are only
+  // identical if they actually are the same object (See Bug: 1346759)
+  if (aPrincipal && aPrincipal.isCodebasePrincipal) {
+    let attrs = {
+      userContextId: aUserContextId,
+      privateBrowsingId: aIsPrivate || (w && PrivateBrowsingUtils.isWindowPrivate(w)),
+    };
+    aPrincipal = Services.scriptSecurityManager.createCodebasePrincipal(aPrincipal.URI, attrs);
+  }
+
   if (!w || where == "window") {
     // This propagates to window.arguments.
     var sa = Cc["@mozilla.org/array;1"].
              createInstance(Ci.nsIMutableArray);
 
     var wuri = Cc["@mozilla.org/supports-string;1"].
                createInstance(Ci.nsISupportsString);
     wuri.data = url;
--- a/browser/components/.eslintrc.js
+++ b/browser/components/.eslintrc.js
@@ -1,9 +1,9 @@
 "use strict";
 
 module.exports = {
   rules: {
     // XXX Bug 1326071 - This should be reduced down - probably to 20 or to
-    // be removed & synced with the toolkit/.eslintrc.js value.
+    // be removed & synced with the mozilla/recommended value.
     "complexity": ["error", {"max": 69}],
   }
 };
--- a/browser/components/contextualidentity/test/browser/.eslintrc.js
+++ b/browser/components/contextualidentity/test/browser/.eslintrc.js
@@ -1,11 +1,11 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ],
 
   "rules": {
     "no-undef": "error"
   }
 };
--- a/browser/components/customizableui/test/.eslintrc.js
+++ b/browser/components/customizableui/test/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/components/dirprovider/tests/unit/.eslintrc.js
+++ b/browser/components/dirprovider/tests/unit/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/xpcshell/xpcshell.eslintrc.js"
+    "plugin:mozilla/xpcshell-test"
   ]
 };
--- a/browser/components/downloads/test/browser/.eslintrc.js
+++ b/browser/components/downloads/test/browser/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/components/downloads/test/unit/.eslintrc.js
+++ b/browser/components/downloads/test/unit/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/xpcshell/xpcshell.eslintrc.js"
+    "plugin:mozilla/xpcshell-test"
   ]
 };
--- a/browser/components/extensions/test/browser/.eslintrc.js
+++ b/browser/components/extensions/test/browser/.eslintrc.js
@@ -1,12 +1,12 @@
 "use strict";
 
-module.exports = {  // eslint-disable-line no-undef
-  "extends": "../../../../../testing/mochitest/browser.eslintrc.js",
+module.exports = {
+  "extends": "plugin:mozilla/browser-test",
 
   "env": {
     "webextensions": true,
   },
 
   "globals": {
     "NetUtil": true,
     "XPCOMUtils": true,
--- a/browser/components/extensions/test/xpcshell/.eslintrc.js
+++ b/browser/components/extensions/test/xpcshell/.eslintrc.js
@@ -1,9 +1,9 @@
 "use strict";
 
-module.exports = {  // eslint-disable-line no-undef
-  "extends": "../../../../../testing/xpcshell/xpcshell.eslintrc.js",
+module.exports = {
+  "extends": "plugin:mozilla/xpcshell-test",
 
   "globals": {
     "browser": false,
   },
 };
--- a/browser/components/feeds/test/.eslintrc.js
+++ b/browser/components/feeds/test/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../testing/mochitest/mochitest.eslintrc.js"
+    "plugin:mozilla/mochitest-test"
   ]
 };
--- a/browser/components/feeds/test/chrome/.eslintrc.js
+++ b/browser/components/feeds/test/chrome/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/chrome.eslintrc.js"
+    "plugin:mozilla/chrome-test"
   ]
 };
--- a/browser/components/feeds/test/unit/.eslintrc.js
+++ b/browser/components/feeds/test/unit/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/xpcshell/xpcshell.eslintrc.js"
+    "plugin:mozilla/xpcshell-test"
   ]
 };
--- a/browser/components/migration/tests/browser/.eslintrc.js
+++ b/browser/components/migration/tests/browser/.eslintrc.js
@@ -1,9 +1,9 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/browser.eslintrc.js",
-    "../../../../../testing/mochitest/mochitest.eslintrc.js",
+    "plugin:mozilla/browser-test",
+    "plugin:mozilla/mochitest-test",
   ]
 };
 
--- a/browser/components/migration/tests/unit/.eslintrc.js
+++ b/browser/components/migration/tests/unit/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
-module.exports = { // eslint-disable-line no-undef
+module.exports = {
   "extends": [
-    "../../../../../testing/xpcshell/xpcshell.eslintrc.js"
+    "plugin:mozilla/xpcshell-test"
   ]
 };
--- a/browser/components/newtab/tests/browser/.eslintrc.js
+++ b/browser/components/newtab/tests/browser/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/components/newtab/tests/xpcshell/.eslintrc.js
+++ b/browser/components/newtab/tests/xpcshell/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/xpcshell/xpcshell.eslintrc.js"
+    "plugin:mozilla/xpcshell-test"
   ]
 };
--- a/browser/components/originattributes/test/browser/.eslintrc.js
+++ b/browser/components/originattributes/test/browser/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/components/places/tests/browser/.eslintrc.js
+++ b/browser/components/places/tests/browser/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/components/places/tests/chrome/.eslintrc.js
+++ b/browser/components/places/tests/chrome/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/chrome.eslintrc.js"
+    "plugin:mozilla/chrome-test"
   ]
 };
--- a/browser/components/places/tests/unit/.eslintrc.js
+++ b/browser/components/places/tests/unit/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/xpcshell/xpcshell.eslintrc.js"
+    "plugin:mozilla/xpcshell-test"
   ]
 };
--- a/browser/components/preferences/in-content/tests/.eslintrc.js
+++ b/browser/components/preferences/in-content/tests/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/components/privatebrowsing/test/browser/.eslintrc.js
+++ b/browser/components/privatebrowsing/test/browser/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/components/privatebrowsing/test/browser/browser.ini
+++ b/browser/components/privatebrowsing/test/browser/browser.ini
@@ -12,16 +12,17 @@ support-files =
   browser_privatebrowsing_windowtitle_page.html
   head.js
   popup.html
   title.sjs
   empty_file.html
   file_favicon.html
   file_favicon.png
   file_favicon.png^headers^
+  file_triggeringprincipal_oa.html
 
 [browser_privatebrowsing_DownloadLastDirWithCPS.js]
 [browser_privatebrowsing_about.js]
 tags = trackingprotection
 [browser_privatebrowsing_aboutHomeButtonAfterWindowClose.js]
 [browser_privatebrowsing_aboutSessionRestore.js]
 [browser_privatebrowsing_cache.js]
 [browser_privatebrowsing_certexceptionsui.js]
@@ -48,8 +49,9 @@ tags = geolocation
 [browser_privatebrowsing_theming.js]
 [browser_privatebrowsing_ui.js]
 [browser_privatebrowsing_urlbarfocus.js]
 [browser_privatebrowsing_windowtitle.js]
 [browser_privatebrowsing_zoom.js]
 [browser_privatebrowsing_zoomrestore.js]
 [browser_privatebrowsing_newtab_from_popup.js]
 [browser_privatebrowsing_blobUrl.js]
+[browser_oa_private_browsing_window.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/browser/browser_oa_private_browsing_window.js
@@ -0,0 +1,38 @@
+"use strict";
+
+const PATH = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "http://example.com");
+const TEST_PAGE = PATH + "file_triggeringprincipal_oa.html";
+const DUMMY_PAGE = PATH + "empty_file.html";
+
+add_task(function* test_principal_right_click_open_link_in_new_private_win() {
+  yield BrowserTestUtils.withNewTab(TEST_PAGE, function*(browser) {
+    let promiseNewWindow = BrowserTestUtils.waitForNewWindow(true, DUMMY_PAGE);
+
+    // simulate right-click open link in new private window
+    BrowserTestUtils.waitForEvent(document, "popupshown", false, event => {
+      document.getElementById("context-openlinkprivate").doCommand();
+      event.target.hidePopup();
+      return true;
+    });
+    BrowserTestUtils.synthesizeMouseAtCenter("#checkPrincipalOA",
+                                             { type: "contextmenu", button: 2 },
+                                             gBrowser.selectedBrowser);
+    let privateWin = yield promiseNewWindow;
+
+    yield ContentTask.spawn(privateWin.gBrowser.selectedBrowser, {DUMMY_PAGE, TEST_PAGE}, function*({DUMMY_PAGE, TEST_PAGE}) { // eslint-disable-line
+
+      let channel = content.document.docShell.currentDocumentChannel;
+      is(channel.URI.spec, DUMMY_PAGE,
+         "sanity check to ensure we check principal for right URI");
+
+      let triggeringPrincipal = channel.loadInfo.triggeringPrincipal;
+      ok(triggeringPrincipal.isCodebasePrincipal,
+         "sanity check to ensure principal is a codebasePrincipal");
+      is(triggeringPrincipal.URI.spec, TEST_PAGE,
+         "test page must be the triggering page");
+      is(triggeringPrincipal.originAttributes.privateBrowsingId, 1,
+         "must have correct privateBrowsingId");
+    });
+    yield BrowserTestUtils.closeWindow(privateWin);
+  });
+});
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/browser/file_triggeringprincipal_oa.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1348801</title>
+</head>
+<body>
+  <a href="empty_file.html" id="checkPrincipalOA">checkPrincipalOA</a>
+</body>
+</html>
--- a/browser/components/safebrowsing/content/test/.eslintrc.js
+++ b/browser/components/safebrowsing/content/test/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/components/search/test/.eslintrc.js
+++ b/browser/components/search/test/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/components/selfsupport/test/.eslintrc.js
+++ b/browser/components/selfsupport/test/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/components/sessionstore/test/.eslintrc.js
+++ b/browser/components/sessionstore/test/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/components/sessionstore/test/unit/.eslintrc.js
+++ b/browser/components/sessionstore/test/unit/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/xpcshell/xpcshell.eslintrc.js"
+    "plugin:mozilla/xpcshell-test"
   ]
 };
--- a/browser/components/shell/test/.eslintrc.js
+++ b/browser/components/shell/test/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/components/shell/test/unit/.eslintrc.js
+++ b/browser/components/shell/test/unit/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/xpcshell/xpcshell.eslintrc.js"
+    "plugin:mozilla/xpcshell-test"
   ]
 };
--- a/browser/components/syncedtabs/test/browser/.eslintrc.js
+++ b/browser/components/syncedtabs/test/browser/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/components/syncedtabs/test/xpcshell/.eslintrc.js
+++ b/browser/components/syncedtabs/test/xpcshell/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/xpcshell/xpcshell.eslintrc.js"
+    "plugin:mozilla/xpcshell-test"
   ]
 };
--- a/browser/components/tests/browser/.eslintrc.js
+++ b/browser/components/tests/browser/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/components/tests/unit/.eslintrc.js
+++ b/browser/components/tests/unit/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../testing/xpcshell/xpcshell.eslintrc.js"
+    "plugin:mozilla/xpcshell-test"
   ]
 };
--- a/browser/components/translation/test/.eslintrc.js
+++ b/browser/components/translation/test/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/components/translation/test/unit/.eslintrc.js
+++ b/browser/components/translation/test/unit/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/xpcshell/xpcshell.eslintrc.js"
+    "plugin:mozilla/xpcshell-test"
   ]
 };
--- a/browser/components/uitour/test/.eslintrc.js
+++ b/browser/components/uitour/test/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/experiments/test/xpcshell/.eslintrc.js
+++ b/browser/experiments/test/xpcshell/.eslintrc.js
@@ -1,13 +1,13 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../testing/xpcshell/xpcshell.eslintrc.js"
+    "plugin:mozilla/xpcshell-test"
   ],
 
   "rules": {
     "no-unused-vars": ["error", {
       "vars": "all",
       "varsIgnorePattern": "^(Cc|Ci|Cr|Cu|EXPORTED_SYMBOLS)$",
       "args": "none"
     }]
--- a/browser/extensions/formautofill/test/browser/.eslintrc.js
+++ b/browser/extensions/formautofill/test/browser/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
-module.exports = { // eslint-disable-line no-undef
+module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/browser.eslintrc.js",
+    "plugin:mozilla/browser-test",
   ],
 };
--- a/browser/extensions/formautofill/test/unit/.eslintrc.js
+++ b/browser/extensions/formautofill/test/unit/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
-module.exports = { // eslint-disable-line no-undef
+module.exports = {
   "extends": [
-    "../../../../../testing/xpcshell/xpcshell.eslintrc.js",
+    "plugin:mozilla/xpcshell-test",
   ],
 };
--- a/browser/extensions/pdfjs/test/.eslintrc.js
+++ b/browser/extensions/pdfjs/test/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/extensions/pocket/test/.eslintrc.js
+++ b/browser/extensions/pocket/test/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/extensions/webcompat-reporter/test/browser/.eslintrc.js
+++ b/browser/extensions/webcompat-reporter/test/browser/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/extensions/webcompat/test/.eslintrc.js
+++ b/browser/extensions/webcompat/test/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/locales/Makefile.in
+++ b/browser/locales/Makefile.in
@@ -39,16 +39,19 @@ PP_TARGETS += L10N_PREF_JS_EXPORTS
 
 ifneq (,$(filter cocoa,$(MOZ_WIDGET_TOOLKIT)))
 MOZ_PKG_MAC_DSSTORE=$(ABS_DIST)/branding/dsstore
 MOZ_PKG_MAC_BACKGROUND=$(ABS_DIST)/branding/background.png
 MOZ_PKG_MAC_ICON=$(ABS_DIST)/branding/disk.icns
 MOZ_PKG_MAC_EXTRA=--symlink '/Applications:/ '
 endif
 
+MOZ_SFX_PACKAGE=$(topsrcdir)/other-licenses/7zstub/firefox/7zSD.sfx
+MOZ_INSTALLER_PATH=$(topsrcdir)/browser/installer/windows
+
 ifeq (WINNT,$(OS_ARCH))
 UNINSTALLER_PACKAGE_HOOK = $(RM) -r $(STAGEDIST)/uninstall; \
     $(NSINSTALL) -D $(STAGEDIST)/uninstall; \
     cp ../installer/windows/l10ngen/helper.exe $(STAGEDIST)/uninstall; \
     $(RM) $(ABS_DIST)/l10n-stage/setup.exe; \
     cp ../installer/windows/l10ngen/setup.exe $(ABS_DIST)/l10n-stage; \
     $(NULL)
 
--- a/browser/modules/test/browser/.eslintrc.js
+++ b/browser/modules/test/browser/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ]
 };
--- a/browser/modules/test/unit/.eslintrc.js
+++ b/browser/modules/test/unit/.eslintrc.js
@@ -1,7 +1,7 @@
 "use strict";
 
 module.exports = {
   "extends": [
-    "../../../../testing/xpcshell/xpcshell.eslintrc.js"
+    "plugin:mozilla/xpcshell-test"
   ]
 };
deleted file mode 100644
index 59337608dd99609eaa474c2f380ce8c3b717376e..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index b87e1ffa3265f63cf6ecc0acadc5343718919fcb..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/browser/tools/mozscreenshots/.eslintrc.js
+++ b/browser/tools/mozscreenshots/.eslintrc.js
@@ -1,13 +1,13 @@
 "use strict";
 
-module.exports = { // eslint-disable-line no-undef
+module.exports = {
   "extends": [
-    "../../../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ],
 
   "rules": {
     "no-unused-vars": ["error", {
       "vars": "all",
       "varsIgnorePattern": "^(Cc|Ci|Cr|Cu|EXPORTED_SYMBOLS)$",
       "args": "none"
     }]
--- a/build/mobile/remoteautomation.py
+++ b/build/mobile/remoteautomation.py
@@ -322,19 +322,16 @@ class RemoteAutomation(Automation):
             Fetch the full remote log file using devicemanager, process them and
             return whether there were any new log entries since the last call.
             """
             if not self.dm.fileExists(self.proc):
                 return False
             try:
                 newLogContent = self.dm.pullFile(self.proc, self.stdoutlen)
             except DMError:
-                # we currently don't retry properly in the pullFile
-                # function in dmSUT, so an error here is not necessarily
-                # the end of the world
                 return False
             if not newLogContent:
                 return False
 
             self.stdoutlen += len(newLogContent)
 
             if self.messageLogger is None:
                 testStartFilenames = re.findall(r"TEST-START \| ([^\s]*)", newLogContent)
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -75,28 +75,22 @@ CPP_UNIT_TESTS_FILES = $(CPP_UNIT_TESTS)
 CPP_UNIT_TESTS_DEST = $(DIST)/cppunittests
 CPP_UNIT_TESTS_TARGET = target
 INSTALL_TARGETS += CPP_UNIT_TESTS
 endif
 
 run-cppunittests::
 	@$(PYTHON) $(MOZILLA_DIR)/testing/runcppunittests.py --xre-path=$(DIST)/bin --symbols-path=$(DIST)/crashreporter-symbols $(CPP_UNIT_TESTS)
 
-cppunittests-remote: DM_TRANS?=adb
 cppunittests-remote:
-	@if [ '${TEST_DEVICE}' != '' -o '$(DM_TRANS)' = 'adb' ]; then \
-		$(PYTHON) -u $(MOZILLA_DIR)/testing/remotecppunittests.py \
-			--xre-path=$(DEPTH)/dist/bin \
-			--localLib=$(DEPTH)/dist/$(MOZ_APP_NAME) \
-			--dm_trans=$(DM_TRANS) \
-			--deviceIP=${TEST_DEVICE} \
-			$(CPP_UNIT_TESTS) $(EXTRA_TEST_ARGS); \
-	else \
-		echo 'please prepare your host with environment variables for TEST_DEVICE'; \
-	fi
+	$(PYTHON) -u $(MOZILLA_DIR)/testing/remotecppunittests.py \
+		--xre-path=$(DEPTH)/dist/bin \
+		--localLib=$(DEPTH)/dist/$(MOZ_APP_NAME) \
+		--deviceIP=${TEST_DEVICE} \
+		$(CPP_UNIT_TESTS) $(EXTRA_TEST_ARGS); \
 
 endif # COMPILE_ENVIRONMENT
 endif # CPP_UNIT_TESTS
 endif # ENABLE_TESTS
 
 
 #
 # Library rules
@@ -954,16 +948,17 @@ endif
 
 CARGO_BUILD = env $(rustflags_override) \
 	CARGO_TARGET_DIR=$(CARGO_TARGET_DIR) \
 	RUSTC=$(RUSTC) \
 	MOZ_DIST=$(ABS_DIST) \
 	LIBCLANG_PATH=$(MOZ_LIBCLANG_PATH) \
 	CLANG_PATH=$(MOZ_CLANG_PATH) \
 	PKG_CONFIG_ALLOW_CROSS=1 \
+	RUST_BACKTRACE=1 \
 	$(CARGO) build $(cargo_build_flags)
 
 ifdef RUST_LIBRARY_FILE
 
 ifdef RUST_LIBRARY_FEATURES
 rust_features_flag := --features "$(RUST_LIBRARY_FEATURES)"
 endif
 
--- a/devtools/.eslintrc.mochitests.js
+++ b/devtools/.eslintrc.mochitests.js
@@ -1,12 +1,12 @@
 // Parent config file for all devtools browser mochitest files.
 module.exports = {
   "extends": [
-    "../testing/mochitest/browser.eslintrc.js"
+    "plugin:mozilla/browser-test"
   ],
   // All globals made available in the test environment.
   "globals": {
     "DevToolsUtils": true,
     "gDevTools": true,
     "once": true,
     "synthesizeKeyFromKeyTag": true,
     "TargetFactory": true,
--- a/devtools/.eslintrc.xpcshell.js
+++ b/devtools/.eslintrc.xpcshell.js
@@ -1,19 +1,19 @@
 // Parent config file for all devtools xpcshell files.
 module.exports = {
   "extends": [
-    "../testing/xpcshell/xpcshell.eslintrc.js"
+    "plugin:mozilla/xpcshell-test"
   ],
   "rules": {
     // Allow non-camelcase so that run_test doesn't produce a warning.
-    "camelcase": 0,
+    "camelcase": "off",
     // Allow using undefined variables so that tests can refer to functions
     // and variables defined in head.js files, without having to maintain a
     // list of globals in each .eslintrc file.
     // Note that bug 1168340 will eventually help auto-registering globals
     // from head.js files.
-    "no-undef": 0,
-    "block-scoped-var": 0,
+    "no-undef": "off",
+    "block-scoped-var": "off",
     // Tests can always import anything.
-    "mozilla/reject-some-requires": 0,
+    "mozilla/reject-some-requires": "off",
   }
 };
--- a/devtools/client/memory/.eslintrc.js
+++ b/devtools/client/memory/.eslintrc.js
@@ -1,11 +1,11 @@
-"use strict";
-
-module.exports = {
-  "env": {
-    "browser": true,
-  },
-  "globals": {
-    "d3": true,
-    "dagreD3": true,
-  }
-};
+"use strict";
+
+module.exports = {
+  "env": {
+    "browser": true,
+  },
+  "globals": {
+    "d3": true,
+    "dagreD3": true,
+  }
+};
--- a/devtools/client/shared/telemetry.js
+++ b/devtools/client/shared/telemetry.js
@@ -92,16 +92,20 @@ Telemetry.prototype = {
     ruleview: {
       histogram: "DEVTOOLS_RULEVIEW_OPENED_COUNT",
       timerHistogram: "DEVTOOLS_RULEVIEW_TIME_ACTIVE_SECONDS"
     },
     computedview: {
       histogram: "DEVTOOLS_COMPUTEDVIEW_OPENED_COUNT",
       timerHistogram: "DEVTOOLS_COMPUTEDVIEW_TIME_ACTIVE_SECONDS"
     },
+    layoutview: {
+      histogram: "DEVTOOLS_LAYOUTVIEW_OPENED_COUNT",
+      timerHistogram: "DEVTOOLS_LAYOUTVIEW_TIME_ACTIVE_SECONDS"
+    },
     fontinspector: {
       histogram: "DEVTOOLS_FONTINSPECTOR_OPENED_COUNT",
       timerHistogram: "DEVTOOLS_FONTINSPECTOR_TIME_ACTIVE_SECONDS"
     },
     animationinspector: {
       histogram: "DEVTOOLS_ANIMATIONINSPECTOR_OPENED_COUNT",
       timerHistogram: "DEVTOOLS_ANIMATIONINSPECTOR_TIME_ACTIVE_SECONDS"
     },
--- a/devtools/client/shared/test/browser_telemetry_sidebar.js
+++ b/devtools/client/shared/test/browser_telemetry_sidebar.js
@@ -24,17 +24,17 @@ add_task(function* () {
   yield gDevTools.closeToolbox(target);
   gBrowser.removeCurrentTab();
 });
 
 function* testSidebar(toolbox) {
   info("Testing sidebar");
 
   let inspector = toolbox.getCurrentPanel();
-  let sidebarTools = ["ruleview", "computedview", "fontinspector",
+  let sidebarTools = ["ruleview", "computedview", "layoutview", "fontinspector",
                       "animationinspector"];
 
   // Concatenate the array with itself so that we can open each tool twice.
   sidebarTools.push.apply(sidebarTools, sidebarTools);
 
   return new Promise(resolve => {
     // See TOOL_DELAY for why we need setTimeout here
     setTimeout(function selectSidebarTab() {
--- a/devtools/shared/security/tests/chrome/.eslintrc.js
+++ b/devtools/shared/security/tests/chrome/.eslintrc.js
@@ -1,6 +1,6 @@
 "use strict";
 
 module.exports = {
   // Extend from the shared list of defined globals for mochitests.
-  "extends": "../../../../../testing/mochitest/chrome.eslintrc.js"
+  "extends": "plugin:mozilla/chrome-test"
 };
--- a/devtools/shared/webconsole/test/.eslintrc.js
+++ b/devtools/shared/webconsole/test/.eslintrc.js
@@ -1,6 +1,6 @@
 "use strict";
 
 module.exports = {
   // Extend from the shared list of defined globals for mochitests.
-  "extends": "../../../../testing/mochitest/chrome.eslintrc.js"
+  "extends": "plugin:mozilla/chrome-test"
 };
--- a/dom/base/CustomElementRegistry.cpp
+++ b/dom/base/CustomElementRegistry.cpp
@@ -4,16 +4,17 @@
  * 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 "mozilla/dom/CustomElementRegistry.h"
 
 #include "mozilla/dom/CustomElementRegistryBinding.h"
 #include "mozilla/dom/HTMLElementBinding.h"
 #include "mozilla/dom/WebComponentsBinding.h"
+#include "mozilla/dom/DocGroup.h"
 #include "nsIParserService.h"
 #include "jsapi.h"
 
 namespace mozilla {
 namespace dom {
 
 void
 CustomElementCallback::Call()
@@ -210,17 +211,16 @@ CustomElementRegistry::XPCOMShutdown()
 }
 
 /* static */ Maybe<nsTArray<RefPtr<CustomElementData>>>
 CustomElementRegistry::sProcessingStack;
 
 CustomElementRegistry::CustomElementRegistry(nsPIDOMWindowInner* aWindow)
  : mWindow(aWindow)
  , mIsCustomDefinitionRunning(false)
- , mIsBackupQueueProcessing(false)
 {
   MOZ_ASSERT(aWindow);
   MOZ_ASSERT(aWindow->IsInnerWindow());
   MOZ_ALWAYS_TRUE(mConstructors.init());
 
   mozilla::HoldJSObjects(this);
 
   if (!sProcessingStack) {
@@ -463,28 +463,39 @@ CustomElementRegistry::GetCustomPrototyp
   } else {
     aPrototype.set(nullptr);
   }
 }
 
 void
 CustomElementRegistry::UpgradeCandidates(JSContext* aCx,
                                          nsIAtom* aKey,
-                                         CustomElementDefinition* aDefinition)
+                                         CustomElementDefinition* aDefinition,
+                                         ErrorResult& aRv)
 {
+  DocGroup* docGroup = mWindow->GetDocGroup();
+  if (!docGroup) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return;
+  }
+
   nsAutoPtr<nsTArray<nsWeakPtr>> candidates;
   mCandidatesMap.RemoveAndForget(aKey, candidates);
   if (candidates) {
+
+
+    CustomElementReactionsStack* reactionsStack =
+      docGroup->CustomElementReactionsStack();
     for (size_t i = 0; i < candidates->Length(); ++i) {
       nsCOMPtr<Element> elem = do_QueryReferent(candidates->ElementAt(i));
       if (!elem) {
         continue;
       }
 
-      EnqueueUpgradeReaction(elem, aDefinition);
+      reactionsStack->EnqueueUpgradeReaction(this, elem, aDefinition);
     }
   }
 }
 
 JSObject*
 CustomElementRegistry::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return CustomElementRegistryBinding::Wrap(aCx, this, aGivenProto);
@@ -536,17 +547,23 @@ CheckLifeCycleCallbacks(JSContext* aCx,
 void
 CustomElementRegistry::Define(const nsAString& aName,
                               Function& aFunctionConstructor,
                               const ElementDefinitionOptions& aOptions,
                               ErrorResult& aRv)
 {
   // We do this for [CEReaction] temporarily and it will be removed
   // after webidl supports [CEReaction] annotation in bug 1309147.
-  AutoCEReaction ceReaction(this);
+  DocGroup* docGroup = mWindow->GetDocGroup();
+  if (!docGroup) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return;
+  }
+
+  AutoCEReaction ceReaction(docGroup->CustomElementReactionsStack());
   aRv.MightThrowJSException();
 
   AutoJSAPI jsapi;
   if (NS_WARN_IF(!jsapi.Init(mWindow))) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
@@ -767,17 +784,17 @@ CustomElementRegistry::Define(const nsAS
 
   MOZ_ASSERT(mCustomDefinitions.Count() == mConstructors.count(),
              "Number of entries should be the same");
 
   /**
    * 13. 14. 15. Upgrade candidates
    */
   // TODO: Bug 1299363 - Implement custom element v1 upgrade algorithm
-  UpgradeCandidates(cx, nameAtom, definition);
+  UpgradeCandidates(cx, nameAtom, definition, aRv);
 
   /**
    * 16. If this CustomElementRegistry's when-defined promise map contains an
    *     entry with key name:
    *     1. Let promise be the value of that entry.
    *     2. Resolve promise with undefined.
    *     3. Delete the entry with key name from this CustomElementRegistry's
    *        when-defined promise map.
@@ -832,23 +849,16 @@ CustomElementRegistry::WhenDefined(const
   } else {
     mWhenDefinedPromiseMap.Put(nameAtom, promise);
   }
 
   return promise.forget();
 }
 
 void
-CustomElementRegistry::EnqueueUpgradeReaction(Element* aElement,
-                                              CustomElementDefinition* aDefinition)
-{
-  Enqueue(aElement, new CustomElementUpgradeReaction(this, aDefinition));
-}
-
-void
 CustomElementRegistry::Upgrade(Element* aElement,
                                CustomElementDefinition* aDefinition)
 {
   // TODO: This function will be replaced to v1 upgrade in bug 1299363
   aElement->RemoveStates(NS_EVENT_STATE_UNRESOLVED);
 
   // Make sure that the element name matches the name in the definition.
   // (e.g. a definition for x-button extending button should match
@@ -884,42 +894,52 @@ CustomElementRegistry::Upgrade(Element* 
     }
   } // Leave prototype's compartment.
 
   // Enqueuing the created callback will set the CustomElementData on the
   // element, causing prototype swizzling to occur in Element::WrapObject.
   EnqueueLifecycleCallback(nsIDocument::eCreated, aElement, nullptr, aDefinition);
 }
 
+//-----------------------------------------------------
+// CustomElementReactionsStack
 
 void
-CustomElementRegistry::CreateAndPushElementQueue()
+CustomElementReactionsStack::CreateAndPushElementQueue()
 {
   // Push a new element queue onto the custom element reactions stack.
   mReactionsStack.AppendElement();
 }
 
 void
-CustomElementRegistry::PopAndInvokeElementQueue()
+CustomElementReactionsStack::PopAndInvokeElementQueue()
 {
   // Pop the element queue from the custom element reactions stack,
   // and invoke custom element reactions in that queue.
   MOZ_ASSERT(!mReactionsStack.IsEmpty(),
              "Reaction stack shouldn't be empty");
 
   ElementQueue& elementQueue = mReactionsStack.LastElement();
-  CustomElementRegistry::InvokeReactions(elementQueue);
+  InvokeReactions(elementQueue);
   DebugOnly<bool> isRemovedElement = mReactionsStack.RemoveElement(elementQueue);
   MOZ_ASSERT(isRemovedElement,
              "Reaction stack should have an element queue to remove");
 }
 
 void
-CustomElementRegistry::Enqueue(Element* aElement,
-                               CustomElementReaction* aReaction)
+CustomElementReactionsStack::EnqueueUpgradeReaction(CustomElementRegistry* aRegistry,
+                                                    Element* aElement,
+                                                    CustomElementDefinition* aDefinition)
+{
+  Enqueue(aElement, new CustomElementUpgradeReaction(aRegistry, aDefinition));
+}
+
+void
+CustomElementReactionsStack::Enqueue(Element* aElement,
+                                     CustomElementReaction* aReaction)
 {
   // Add element to the current element queue.
   if (!mReactionsStack.IsEmpty()) {
     mReactionsStack.LastElement().AppendElement(do_GetWeakReference(aElement));
     ReactionQueue* reactionQueue =
       mElementReactionQueueMap.LookupOrAdd(aElement);
     reactionQueue->AppendElement(aReaction);
 
@@ -940,23 +960,23 @@ CustomElementRegistry::Enqueue(Element* 
 
   CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
   RefPtr<ProcessBackupQueueRunnable> processBackupQueueRunnable =
     new ProcessBackupQueueRunnable(this);
   context->DispatchToMicroTask(processBackupQueueRunnable.forget());
 }
 
 void
-CustomElementRegistry::InvokeBackupQueue()
+CustomElementReactionsStack::InvokeBackupQueue()
 {
-  CustomElementRegistry::InvokeReactions(mBackupQueue);
+  InvokeReactions(mBackupQueue);
 }
 
 void
-CustomElementRegistry::InvokeReactions(ElementQueue& aElementQueue)
+CustomElementReactionsStack::InvokeReactions(ElementQueue& aElementQueue)
 {
   for (uint32_t i = 0; i < aElementQueue.Length(); ++i) {
     nsCOMPtr<Element> element = do_QueryReferent(aElementQueue[i]);
 
     if (!element) {
       continue;
     }
 
--- a/dom/base/CustomElementRegistry.h
+++ b/dom/base/CustomElementRegistry.h
@@ -160,16 +160,96 @@ public:
     : CustomElementReaction(aRegistry, aDefinition)
   {
   }
 
 private:
    virtual void Invoke(Element* aElement) override;
 };
 
+// https://html.spec.whatwg.org/multipage/scripting.html#custom-element-reactions-stack
+class CustomElementReactionsStack
+{
+public:
+  NS_INLINE_DECL_REFCOUNTING(CustomElementReactionsStack)
+
+  CustomElementReactionsStack()
+    : mIsBackupQueueProcessing(false)
+  {
+  }
+
+  // nsWeakPtr is a weak pointer of Element
+  // The element reaction queues are stored in ElementReactionQueueMap.
+  // We need to lookup ElementReactionQueueMap again to get relevant reaction queue.
+  typedef nsTArray<nsWeakPtr> ElementQueue;
+
+  /**
+   * Enqueue a custom element upgrade reaction
+   * https://html.spec.whatwg.org/multipage/scripting.html#enqueue-a-custom-element-upgrade-reaction
+   */
+  void EnqueueUpgradeReaction(CustomElementRegistry* aRegistry,
+                              Element* aElement,
+                              CustomElementDefinition* aDefinition);
+
+  // [CEReactions] Before executing the algorithm's steps
+  // Push a new element queue onto the custom element reactions stack.
+  void CreateAndPushElementQueue();
+
+  // [CEReactions] After executing the algorithm's steps
+  // Pop the element queue from the custom element reactions stack,
+  // and invoke custom element reactions in that queue.
+  void PopAndInvokeElementQueue();
+
+private:
+  ~CustomElementReactionsStack() {};
+
+  typedef nsTArray<nsAutoPtr<CustomElementReaction>> ReactionQueue;
+  typedef nsClassHashtable<nsISupportsHashKey, ReactionQueue>
+    ElementReactionQueueMap;
+
+  ElementReactionQueueMap mElementReactionQueueMap;
+
+  nsTArray<ElementQueue> mReactionsStack;
+  ElementQueue mBackupQueue;
+  // https://html.spec.whatwg.org/#enqueue-an-element-on-the-appropriate-element-queue
+  bool mIsBackupQueueProcessing;
+
+  void InvokeBackupQueue();
+
+  /**
+   * Invoke custom element reactions
+   * https://html.spec.whatwg.org/multipage/scripting.html#invoke-custom-element-reactions
+   */
+  void InvokeReactions(ElementQueue& aElementQueue);
+
+  void Enqueue(Element* aElement, CustomElementReaction* aReaction);
+
+private:
+  class ProcessBackupQueueRunnable : public mozilla::Runnable {
+    public:
+      explicit ProcessBackupQueueRunnable(CustomElementReactionsStack* aReactionStack)
+        : mReactionStack(aReactionStack)
+      {
+        MOZ_ASSERT(!mReactionStack->mIsBackupQueueProcessing,
+                   "mIsBackupQueueProcessing should be initially false");
+        mReactionStack->mIsBackupQueueProcessing = true;
+      }
+
+      NS_IMETHOD Run() override
+      {
+        mReactionStack->InvokeBackupQueue();
+        mReactionStack->mIsBackupQueueProcessing = false;
+        return NS_OK;
+      }
+
+    private:
+      RefPtr<CustomElementReactionsStack> mReactionStack;
+  };
+};
+
 class CustomElementRegistry final : public nsISupports,
                                     public nsWrapperCache
 {
   // Allow nsDocument to access mCustomDefinitions and mCandidatesMap.
   friend class ::nsDocument;
 
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@@ -205,66 +285,36 @@ public:
   void EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
                                 Element* aCustomElement,
                                 LifecycleCallbackArgs* aArgs,
                                 CustomElementDefinition* aDefinition);
 
   void GetCustomPrototype(nsIAtom* aAtom,
                           JS::MutableHandle<JSObject*> aPrototype);
 
-  /**
-   * Enqueue a custom element upgrade reaction
-   * https://html.spec.whatwg.org/multipage/scripting.html#enqueue-a-custom-element-upgrade-reaction
-   */
-  void EnqueueUpgradeReaction(Element* aElement,
-                              CustomElementDefinition* aDefinition);
-
   void Upgrade(Element* aElement, CustomElementDefinition* aDefinition);
 
-  // [CEReactions] Before executing the algorithm's steps
-  // Push a new element queue onto the custom element reactions stack.
-  void CreateAndPushElementQueue();
-
-  // [CEReactions] After executing the algorithm's steps
-  // Pop the element queue from the custom element reactions stack,
-  // and invoke custom element reactions in that queue.
-  void PopAndInvokeElementQueue();
-
 private:
   ~CustomElementRegistry();
 
   /**
    * Registers an unresolved custom element that is a candidate for
    * upgrade when the definition is registered via registerElement.
    * |aTypeName| is the name of the custom element type, if it is not
    * provided, then element name is used. |aTypeName| should be provided
    * when registering a custom element that extends an existing
    * element. e.g. <button is="x-button">.
    */
   void RegisterUnresolvedElement(Element* aElement,
                                  nsIAtom* aTypeName = nullptr);
 
   void UpgradeCandidates(JSContext* aCx,
                          nsIAtom* aKey,
-                         CustomElementDefinition* aDefinition);
-
-  void InvokeBackupQueue();
-
-  void Enqueue(Element* aElement, CustomElementReaction* aReaction);
-
-  // nsWeakPtr is a weak pointer of Element
-  // The element reaction queues are stored in ElementReactionQueueMap.
-  // We need to lookup ElementReactionQueueMap again to get relevant reaction queue.
-  typedef nsTArray<nsWeakPtr> ElementQueue;
-
-  /**
-   * Invoke custom element reactions
-   * https://html.spec.whatwg.org/multipage/scripting.html#invoke-custom-element-reactions
-   */
-  void InvokeReactions(ElementQueue& aElementQueue);
+                         CustomElementDefinition* aDefinition,
+                         ErrorResult& aRv);
 
   typedef nsClassHashtable<nsISupportsHashKey, CustomElementDefinition>
     DefinitionMap;
   typedef nsClassHashtable<nsISupportsHashKey, nsTArray<nsWeakPtr>>
     CandidateMap;
   typedef JS::GCHashMap<JS::Heap<JSObject*>,
                         nsCOMPtr<nsIAtom>,
                         js::MovableCellHasher<JS::Heap<JSObject*>>,
@@ -296,27 +346,16 @@ private:
   // element queues. Each queue is represented by a sequence of
   // CustomElementData in this array, separated by nullptr that
   // represent the boundaries of the items in the stack. The first
   // queue in the stack is the base element queue.
   static mozilla::Maybe<nsTArray<RefPtr<CustomElementData>>> sProcessingStack;
 
   // It is used to prevent reentrant invocations of element definition.
   bool mIsCustomDefinitionRunning;
-  // https://html.spec.whatwg.org/#enqueue-an-element-on-the-appropriate-element-queue
-  bool mIsBackupQueueProcessing;
-
-  typedef nsTArray<nsAutoPtr<CustomElementReaction>> ReactionQueue;
-  typedef nsClassHashtable<nsISupportsHashKey, ReactionQueue>
-    ElementReactionQueueMap;
-
-  ElementReactionQueueMap mElementReactionQueueMap;
-
-  nsTArray<ElementQueue> mReactionsStack;
-  ElementQueue mBackupQueue;
 
 private:
   class MOZ_RAII AutoSetRunningFlag final {
     public:
       explicit AutoSetRunningFlag(CustomElementRegistry* aRegistry)
         : mRegistry(aRegistry)
       {
         MOZ_ASSERT(!mRegistry->mIsCustomDefinitionRunning,
@@ -327,62 +366,40 @@ private:
       ~AutoSetRunningFlag() {
         mRegistry->mIsCustomDefinitionRunning = false;
       }
 
     private:
       CustomElementRegistry* mRegistry;
   };
 
-private:
-  class ProcessBackupQueueRunnable : public mozilla::Runnable {
-    public:
-      explicit ProcessBackupQueueRunnable(CustomElementRegistry* aRegistry)
-        : mRegistry(aRegistry)
-      {
-        MOZ_ASSERT(!mRegistry->mIsBackupQueueProcessing,
-                   "mIsBackupQueueProcessing should be initially false");
-        mRegistry->mIsBackupQueueProcessing = true;
-      }
-
-      NS_IMETHOD Run() override
-      {
-        mRegistry->InvokeBackupQueue();
-        mRegistry->mIsBackupQueueProcessing = false;
-        return NS_OK;
-      }
-
-    private:
-      RefPtr<CustomElementRegistry> mRegistry;
-  };
-
 public:
   nsISupports* GetParentObject() const;
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   void Define(const nsAString& aName, Function& aFunctionConstructor,
               const ElementDefinitionOptions& aOptions, ErrorResult& aRv);
 
   void Get(JSContext* cx, const nsAString& name,
            JS::MutableHandle<JS::Value> aRetVal);
 
   already_AddRefed<Promise> WhenDefined(const nsAString& aName, ErrorResult& aRv);
 };
 
 class MOZ_RAII AutoCEReaction final {
   public:
-    explicit AutoCEReaction(CustomElementRegistry* aRegistry)
-      : mRegistry(aRegistry) {
-      mRegistry->CreateAndPushElementQueue();
+    explicit AutoCEReaction(CustomElementReactionsStack* aReactionsStack)
+      : mReactionsStack(aReactionsStack) {
+      mReactionsStack->CreateAndPushElementQueue();
     }
     ~AutoCEReaction() {
-      mRegistry->PopAndInvokeElementQueue();
+      mReactionsStack->PopAndInvokeElementQueue();
     }
   private:
-    RefPtr<CustomElementRegistry> mRegistry;
+    RefPtr<CustomElementReactionsStack> mReactionsStack;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 
 #endif // mozilla_dom_CustomElementRegistry_h
--- a/dom/base/DocGroup.h
+++ b/dom/base/DocGroup.h
@@ -10,16 +10,17 @@
 #include "nsISupportsImpl.h"
 #include "nsIPrincipal.h"
 #include "nsTHashtable.h"
 #include "nsString.h"
 
 #include "mozilla/dom/TabGroup.h"
 #include "mozilla/Dispatcher.h"
 #include "mozilla/RefPtr.h"
+#include "mozilla/dom/CustomElementRegistry.h"
 
 namespace mozilla {
 class AbstractThread;
 namespace dom {
 
 // Two browsing contexts are considered "related" if they are reachable from one
 // another through window.opener, window.parent, or window.frames. This is the
 // spec concept of a "unit of related browsing contexts"
@@ -52,16 +53,24 @@ public:
   bool MatchesKey(const nsACString& aKey)
   {
     return aKey == mKey;
   }
   TabGroup* GetTabGroup()
   {
     return mTabGroup;
   }
+  mozilla::dom::CustomElementReactionsStack* CustomElementReactionsStack()
+  {
+    if (!mReactionsStack) {
+      mReactionsStack = new mozilla::dom::CustomElementReactionsStack();
+    }
+
+    return mReactionsStack;
+  }
   void RemoveDocument(nsIDocument* aWindow);
 
   // Iterators for iterating over every document within the DocGroup
   Iterator begin()
   {
     return mDocuments.begin();
   }
   Iterator end()
@@ -91,14 +100,15 @@ private:
   AbstractMainThreadForImpl(TaskCategory aCategory) override;
 
   DocGroup(TabGroup* aTabGroup, const nsACString& aKey);
   ~DocGroup();
 
   nsCString mKey;
   RefPtr<TabGroup> mTabGroup;
   nsTArray<nsIDocument*> mDocuments;
+  RefPtr<mozilla::dom::CustomElementReactionsStack> mReactionsStack;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // defined(DocGroup_h)
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -2067,16 +2067,22 @@ FragmentOrElement::AppendText(const char
 
 bool
 FragmentOrElement::TextIsOnlyWhitespace()
 {
   return false;
 }
 
 bool
+FragmentOrElement::ThreadSafeTextIsOnlyWhitespace() const
+{
+  return false;
+}
+
+bool
 FragmentOrElement::HasTextForTranslation()
 {
   return false;
 }
 
 void
 FragmentOrElement::AppendTextTo(nsAString& aResult)
 {
--- a/dom/base/FragmentOrElement.h
+++ b/dom/base/FragmentOrElement.h
@@ -138,16 +138,17 @@ public:
   // Need to implement this here too to avoid hiding.
   nsresult SetText(const nsAString& aStr, bool aNotify)
   {
     return SetText(aStr.BeginReading(), aStr.Length(), aNotify);
   }
   virtual nsresult AppendText(const char16_t* aBuffer, uint32_t aLength,
                               bool aNotify) override;
   virtual bool TextIsOnlyWhitespace() override;
+  virtual bool ThreadSafeTextIsOnlyWhitespace() const override;
   virtual bool HasTextForTranslation() override;
   virtual void AppendTextTo(nsAString& aResult) override;
   MOZ_MUST_USE
   virtual bool AppendTextTo(nsAString& aResult, const mozilla::fallible_t&) override;
   virtual nsIContent *GetBindingParent() const override;
   virtual nsXBLBinding *GetXBLBinding() const override;
   virtual void SetXBLBinding(nsXBLBinding* aBinding,
                              nsBindingManager* aOldBindingManager = nullptr) override;
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -9626,36 +9626,48 @@ nsDocument::ForgetImagePreload(nsIURI* a
     mPreloadingImages.Remove(aURI, getter_AddRefs(req));
     if (req) {
       // Make sure to cancel the request so imagelib knows it's gone.
       req->CancelAndForgetObserver(NS_BINDING_ABORTED);
     }
   }
 }
 
-EventStates
-nsDocument::GetDocumentState()
+void
+nsDocument::UpdatePossiblyStaleDocumentState()
 {
   if (!mGotDocumentState.HasState(NS_DOCUMENT_STATE_RTL_LOCALE)) {
     if (IsDocumentRightToLeft()) {
       mDocumentState |= NS_DOCUMENT_STATE_RTL_LOCALE;
     }
     mGotDocumentState |= NS_DOCUMENT_STATE_RTL_LOCALE;
   }
   if (!mGotDocumentState.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE)) {
     nsIPresShell* shell = GetShell();
     if (shell && shell->GetPresContext() &&
         shell->GetPresContext()->IsTopLevelWindowInactive()) {
       mDocumentState |= NS_DOCUMENT_STATE_WINDOW_INACTIVE;
     }
     mGotDocumentState |= NS_DOCUMENT_STATE_WINDOW_INACTIVE;
   }
+}
+
+EventStates
+nsDocument::ThreadSafeGetDocumentState() const
+{
   return mDocumentState;
 }
 
+EventStates
+nsDocument::GetDocumentState()
+{
+  UpdatePossiblyStaleDocumentState();
+  return ThreadSafeGetDocumentState();
+}
+
 namespace {
 
 /**
  * Stub for LoadSheet(), since all we want is to get the sheet into
  * the CSSLoader's style cache
  */
 class StubCSSLoaderObserver final : public nsICSSLoaderObserver {
   ~StubCSSLoaderObserver() {}
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -975,17 +975,22 @@ public:
                             ReferrerPolicy aReferrerPolicy,
                             const nsAString& aIntegrity) override;
 
   virtual nsresult LoadChromeSheetSync(nsIURI* uri, bool isAgentSheet,
                                        RefPtr<mozilla::StyleSheet>* aSheet) override;
 
   virtual nsISupports* GetCurrentContentSink() override;
 
-  virtual mozilla::EventStates GetDocumentState() override;
+  virtual mozilla::EventStates GetDocumentState() final;
+  // GetDocumentState() mutates the state due to lazy resolution;
+  // and can't be used during parallel traversal. Use this instead,
+  // and ensure GetDocumentState() has been called first.
+  // This will assert if the state is stale.
+  virtual mozilla::EventStates ThreadSafeGetDocumentState() const final;
 
   // Only BlockOnload should call this!
   void AsyncBlockOnload();
 
   virtual void SetScrollToRef(nsIURI *aDocumentURI) override;
   virtual void ScrollToRef() override;
   virtual void ResetScrolledToRefAlready() override;
   virtual void SetChangeScrollPosWhenScrollingToRef(bool aValue) override;
@@ -1386,16 +1391,17 @@ protected:
   // non-null when this document is in fullscreen mode.
   nsWeakPtr mFullscreenRoot;
 
   mozilla::dom::FlashClassification mFlashClassification;
   // Do not use this value directly. Call the |IsThirdParty()| method, which
   // caches its result here.
   mozilla::Maybe<bool> mIsThirdParty;
 private:
+  void UpdatePossiblyStaleDocumentState();
   static bool CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp);
 
   /**
    * Check if the passed custom element name, aOptions.mIs, is a registered
    * custom element type or not, then return the custom element name for future
    * usage.
    *
    * If there is no existing custom element definition for this name, throw a
--- a/dom/base/nsDocumentWarningList.h
+++ b/dom/base/nsDocumentWarningList.h
@@ -7,8 +7,10 @@
 
 /*
  * This file contains the list of document DOM operations warnings.  It is
  * designed to be used as input to the C preprocessor *only*.
  */
 
 DOCUMENT_WARNING(IgnoringWillChangeOverBudget)
 DOCUMENT_WARNING(PreventDefaultFromPassiveListener)
+DOCUMENT_WARNING(SVGReferenceLoop)
+DOCUMENT_WARNING(SVGReferenceChainLengthExceeded)
--- a/dom/base/nsGenericDOMDataNode.cpp
+++ b/dom/base/nsGenericDOMDataNode.cpp
@@ -978,16 +978,31 @@ nsGenericDOMDataNode::AppendText(const c
                                  bool aNotify)
 {
   return SetTextInternal(mText.GetLength(), 0, aBuffer, aLength, aNotify);
 }
 
 bool
 nsGenericDOMDataNode::TextIsOnlyWhitespace()
 {
+
+  MOZ_ASSERT(NS_IsMainThread());
+  if (!ThreadSafeTextIsOnlyWhitespace()) {
+    UnsetFlags(NS_TEXT_IS_ONLY_WHITESPACE);
+    SetFlags(NS_CACHED_TEXT_IS_ONLY_WHITESPACE);
+    return false;
+  }
+
+  SetFlags(NS_CACHED_TEXT_IS_ONLY_WHITESPACE | NS_TEXT_IS_ONLY_WHITESPACE);
+  return true;
+}
+
+bool
+nsGenericDOMDataNode::ThreadSafeTextIsOnlyWhitespace() const
+{
   // FIXME: should this method take content language into account?
   if (mText.Is2b()) {
     // The fragment contains non-8bit characters and such characters
     // are never considered whitespace.
     return false;
   }
 
   if (HasFlag(NS_CACHED_TEXT_IS_ONLY_WHITESPACE)) {
@@ -996,25 +1011,22 @@ nsGenericDOMDataNode::TextIsOnlyWhitespa
 
   const char* cp = mText.Get1b();
   const char* end = cp + mText.GetLength();
 
   while (cp < end) {
     char ch = *cp;
 
     if (!dom::IsSpaceCharacter(ch)) {
-      UnsetFlags(NS_TEXT_IS_ONLY_WHITESPACE);
-      SetFlags(NS_CACHED_TEXT_IS_ONLY_WHITESPACE);
       return false;
     }
 
     ++cp;
   }
 
-  SetFlags(NS_CACHED_TEXT_IS_ONLY_WHITESPACE | NS_TEXT_IS_ONLY_WHITESPACE);
   return true;
 }
 
 bool
 nsGenericDOMDataNode::HasTextForTranslation()
 {
   if (NodeType() != nsIDOMNode::TEXT_NODE &&
       NodeType() != nsIDOMNode::CDATA_SECTION_NODE) {
--- a/dom/base/nsGenericDOMDataNode.h
+++ b/dom/base/nsGenericDOMDataNode.h
@@ -131,16 +131,17 @@ public:
   // Need to implement this here too to avoid hiding.
   nsresult SetText(const nsAString& aStr, bool aNotify)
   {
     return SetText(aStr.BeginReading(), aStr.Length(), aNotify);
   }
   virtual nsresult AppendText(const char16_t* aBuffer, uint32_t aLength,
                               bool aNotify) override;
   virtual bool TextIsOnlyWhitespace() override;
+  virtual bool ThreadSafeTextIsOnlyWhitespace() const final;
   virtual bool HasTextForTranslation() override;
   virtual void AppendTextTo(nsAString& aResult) override;
   MOZ_MUST_USE
   virtual bool AppendTextTo(nsAString& aResult,
                             const mozilla::fallible_t&) override;
   virtual void SaveSubtreeState() override;
 
 #ifdef DEBUG
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -900,17 +900,19 @@ GK_ATOM(onrdsdisabled, "onrdsdisabled")
 GK_ATOM(onrdsenabled, "onrdsenabled")
 GK_ATOM(onreaderror, "onreaderror")
 GK_ATOM(onreadsuccess, "onreadsuccess")
 GK_ATOM(onready, "onready")
 GK_ATOM(onreadystatechange, "onreadystatechange")
 GK_ATOM(onreceived, "onreceived")
 GK_ATOM(onremoteheld, "onremoteheld")
 GK_ATOM(onremoteresumed, "onremoteresumed")
+GK_ATOM(onrequestprogress, "onrequestprogress")
 GK_ATOM(onresourcetimingbufferfull, "onresourcetimingbufferfull")
+GK_ATOM(onresponseprogress, "onresponseprogress")
 GK_ATOM(onretrieving, "onretrieving")
 GK_ATOM(onRequest, "onRequest")
 GK_ATOM(onrequestmediaplaystatus, "onrequestmediaplaystatus")
 GK_ATOM(onreset, "onreset")
 GK_ATOM(onresuming, "onresuming")
 GK_ATOM(onresize, "onresize")
 GK_ATOM(onrtchange, "onrtchange")
 GK_ATOM(onscanningstatechanged, "onscanningstatechanged")
--- a/dom/base/nsIContent.h
+++ b/dom/base/nsIContent.h
@@ -554,16 +554,21 @@ public:
 
   /**
    * Query method to see if the frame is nothing but whitespace
    * NOTE: Always returns false for elements
    */
   virtual bool TextIsOnlyWhitespace() = 0;
 
   /**
+   * Thread-safe version of TextIsOnlyWhitespace.
+   */
+  virtual bool ThreadSafeTextIsOnlyWhitespace() const = 0;
+
+  /**
    * Method to see if the text node contains data that is useful
    * for a translation: i.e., it consists of more than just whitespace,
    * digits and punctuation.
    * NOTE: Always returns false for elements.
    */
   virtual bool HasTextForTranslation() = 0;
 
   /**
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -2376,16 +2376,17 @@ public:
   virtual int GetDocumentLWTheme() { return Doc_Theme_None; }
 
   /**
    * Returns the document state.
    * Document state bits have the form NS_DOCUMENT_STATE_* and are declared in
    * nsIDocument.h.
    */
   virtual mozilla::EventStates GetDocumentState() = 0;
+  virtual mozilla::EventStates ThreadSafeGetDocumentState() const = 0;
 
   virtual nsISupports* GetCurrentContentSink() = 0;
 
   virtual void SetScrollToRef(nsIURI *aDocumentURI) = 0;
   virtual void ScrollToRef() = 0;
   virtual void ResetScrolledToRefAlready() = 0;
   virtual void SetChangeScrollPosWhenScrollingToRef(bool aValue) = 0;
 
--- a/dom/base/nsImageLoadingContent.cpp
+++ b/dom/base/nsImageLoadingContent.cpp
@@ -89,18 +89,17 @@ nsImageLoadingContent::nsImageLoadingCon
     mLoading(false),
     // mBroken starts out true, since an image without a URI is broken....
     mBroken(true),
     mUserDisabled(false),
     mSuppressed(false),
     mNewRequestsWillNeedAnimationReset(false),
     mStateChangerDepth(0),
     mCurrentRequestRegistered(false),
-    mPendingRequestRegistered(false),
-    mFrameCreateCalled(false)
+    mPendingRequestRegistered(false)
 {
   if (!nsContentUtils::GetImgLoaderForChannel(nullptr, nullptr)) {
     mLoadingEnabled = false;
   }
 
   bool isInconsistent;
   mMostRecentRequestChange = TimeStamp::ProcessCreation(isInconsistent);
 }
@@ -477,20 +476,18 @@ nsImageLoadingContent::CurrentRequestHas
   return HaveSize(mCurrentRequest);
 }
 
 NS_IMETHODIMP_(void)
 nsImageLoadingContent::FrameCreated(nsIFrame* aFrame)
 {
   NS_ASSERTION(aFrame, "aFrame is null");
 
-  mFrameCreateCalled = true;
-
-  TrackImage(mCurrentRequest);
-  TrackImage(mPendingRequest);
+  TrackImage(mCurrentRequest, aFrame);
+  TrackImage(mPendingRequest, aFrame);
 
   // We need to make sure that our image request is registered, if it should
   // be registered.
   nsPresContext* presContext = aFrame->PresContext();
   if (mCurrentRequest) {
     nsLayoutUtils::RegisterImageRequestIfAnimated(presContext, mCurrentRequest,
                                                   &mCurrentRequestRegistered);
   }
@@ -501,18 +498,16 @@ nsImageLoadingContent::FrameCreated(nsIF
   }
 }
 
 NS_IMETHODIMP_(void)
 nsImageLoadingContent::FrameDestroyed(nsIFrame* aFrame)
 {
   NS_ASSERTION(aFrame, "aFrame is null");
 
-  mFrameCreateCalled = false;
-
   // We need to make sure that our image request is deregistered.
   nsPresContext* presContext = GetFramePresContext();
   if (mCurrentRequest) {
     nsLayoutUtils::DeregisterImageRequest(presContext,
                                           mCurrentRequest,
                                           &mCurrentRequestRegistered);
   }
 
@@ -1459,36 +1454,45 @@ nsImageLoadingContent::OnVisibilityChang
 
     case Visibility::UNTRACKED:
       MOZ_ASSERT_UNREACHABLE("Shouldn't notify for untracked visibility");
       break;
   }
 }
 
 void
-nsImageLoadingContent::TrackImage(imgIRequest* aImage)
+nsImageLoadingContent::TrackImage(imgIRequest* aImage,
+                                  nsIFrame* aFrame /*= nullptr */)
 {
   if (!aImage)
     return;
 
   MOZ_ASSERT(aImage == mCurrentRequest || aImage == mPendingRequest,
              "Why haven't we heard of this request?");
 
   nsIDocument* doc = GetOurCurrentDoc();
   if (!doc) {
     return;
   }
 
-  // We only want to track this request if we're visible. Ordinarily we check
-  // the visible count, but that requires a frame; in cases where
-  // GetOurPrimaryFrame() cannot obtain a frame (e.g. <feImage>), we assume
-  // we're visible if FrameCreated() was called.
-  nsIFrame* frame = GetOurPrimaryFrame();
-  if ((frame && frame->GetVisibility() == Visibility::APPROXIMATELY_NONVISIBLE) ||
-      (!frame && !mFrameCreateCalled)) {
+  if (!aFrame) {
+    aFrame = GetOurPrimaryFrame();
+  }
+
+  /* This line is deceptively simple. It hides a lot of subtlety. Before we
+   * create an nsImageFrame we call nsImageFrame::ShouldCreateImageFrameFor
+   * to determine if we should create an nsImageFrame or create a frame based
+   * on the display of the element (ie inline, block, etc). Inline, block, etc
+   * frames don't register for visibility tracking so they will return UNTRACKED
+   * from GetVisibility(). So this line is choosing to mark such images as
+   * visible. Once the image loads we will get an nsImageFrame and the proper
+   * visibility. This is a pitfall of tracking the visibility on the frames
+   * instead of the content node.
+   */
+  if (!aFrame || aFrame->GetVisibility() == Visibility::APPROXIMATELY_NONVISIBLE) {
     return;
   }
 
   if (aImage == mCurrentRequest && !(mCurrentRequestFlags & REQUEST_IS_TRACKED)) {
     mCurrentRequestFlags |= REQUEST_IS_TRACKED;
     doc->ImageTracker()->Add(mCurrentRequest);
   }
   if (aImage == mPendingRequest && !(mPendingRequestFlags & REQUEST_IS_TRACKED)) {
--- a/dom/base/nsImageLoadingContent.h
+++ b/dom/base/nsImageLoadingContent.h
@@ -363,24 +363,29 @@ protected:
    */
   static bool HaveSize(imgIRequest *aImage);
 
   /**
    * Adds/Removes a given imgIRequest from our document's tracker.
    *
    * No-op if aImage is null.
    *
+   * @param aFrame If called from FrameCreated the frame passed to FrameCreated.
+   *               This is our frame, but at the time of the FrameCreated call
+   *               our primary frame pointer hasn't been set yet, so this is
+   *               only way to get our frame.
+   *
    * @param aNonvisibleAction A requested action if the frame has become
    *                          nonvisible. If Nothing(), no action is
    *                          requested. If DISCARD_IMAGES is specified, the
    *                          frame is requested to ask any images it's
    *                          associated with to discard their surfaces if
    *                          possible.
    */
-  void TrackImage(imgIRequest* aImage);
+  void TrackImage(imgIRequest* aImage, nsIFrame* aFrame = nullptr);
   void UntrackImage(imgIRequest* aImage,
                     const Maybe<OnNonvisible>& aNonvisibleAction = Nothing());
 
   /* MEMBERS */
   RefPtr<imgRequestProxy> mCurrentRequest;
   RefPtr<imgRequestProxy> mPendingRequest;
   uint32_t mCurrentRequestFlags;
   uint32_t mPendingRequestFlags;
@@ -453,14 +458,11 @@ protected:
 private:
   /* The number of nested AutoStateChangers currently tracking our state. */
   uint8_t mStateChangerDepth;
 
   // Flags to indicate whether each of the current and pending requests are
   // registered with the refresh driver.
   bool mCurrentRequestRegistered;
   bool mPendingRequestRegistered;
-
-  // True when FrameCreate has been called but FrameDestroy has not.
-  bool mFrameCreateCalled;
 };
 
 #endif // nsImageLoadingContent_h__
--- a/dom/bindings/test/test_proxy_expandos.html
+++ b/dom/bindings/test/test_proxy_expandos.html
@@ -14,55 +14,66 @@ https://bugzilla.mozilla.org/show_bug.cg
 <p id="display"></p>
 <form id="theform"></form>
 <pre id="test">
 <script type="application/javascript">
 
 // Ensure we are in JIT code and attach IC stubs.
 const iterations = 50;
 
-function testFoo(obj, expected, kind) {
+function testFoo(obj, kind, expected) {
   for (var i = 0; i < iterations; i++) {
-    is(obj.foo, expected, "Looking up an expando should work - " + kind);
+    obj.foo = i;
+    is(obj.foo, (expected === undefined) ? i : expected,
+       "Looking up an expando should work - " + kind);
   }
 }
 
 function getPropTests(obj) {
   // Start with a plain data property.
   obj.foo = "bar";
-  testFoo(obj, "bar", "plain");
+  testFoo(obj, "plain");
 
-  // Now change it to a scripted getter.
+  // Now change it to a scripted getter/setter.
   var count = 0;
-  Object.defineProperty(obj, "foo", {get:function() {
+  var getterSetterVal = 0;
+  Object.defineProperty(obj, "foo", {configurable: true, get: function() {
     is(this, obj, "Getter should have the proxy as |this|");
     is(arguments.length, 0, "Shouldn't pass arguments to getters");
     count++;
-    return 123;
-  }, configurable: true});
-  testFoo(obj, 123, "scripted getter");
-  is(count, iterations, "Should have called the getter enough times");
+    return getterSetterVal;
+  }, set: function(v) {
+    is(this, obj, "Setter should have the proxy as |this|");
+    is(arguments.length, 1, "Should pass 1 argument to setters");
+    getterSetterVal = v;
+    count++;
+  }});
+  testFoo(obj, "scripted getter/setter");
+  is(count, iterations * 2, "Should have called the getter/setter enough times");
 
-  // Now try a native getter.
-  Object.defineProperty(obj, "foo", {get: Object.prototype.valueOf, configurable: true});
-  testFoo(obj, obj, "native getter");
+  // Now try a native getter/setter.
+  Object.defineProperty(obj, "foo", {get: Math.abs, set: Math.abs, configurable: true});
+  testFoo(obj, "native getter/setter", NaN);
 }
 
 function getElemTests(obj) {
   // Define two expando properties, then test inline caches for obj[prop]
   // correctly guard on prop being the same.
-  var count = 0;
+  var count = 0, getterSetterVal = 0;
   obj.elem1 = 1;
-  Object.defineProperty(obj, "elem2", {get: function() { count++; return 2; }});
-
+  Object.defineProperty(obj, "elem2", {
+                        get: function() { count++; return getterSetterVal; },
+                        set: function(v) { getterSetterVal = v; count++; }
+  });
   for (var i = 0; i < iterations; i++) {
     var prop = ((i & 1) == 0) ? "elem1" : "elem2";
-    is(obj[prop], (i & 1) + 1, "Should return correct property value");
+    obj[prop] = i;
+    is(obj[prop], i, "Should return correct property value");
   }
-  is(count, iterations / 2, "Should have called the getter enough times");
+  is(count, iterations, "Should have called the getter/setter enough times");
 }
 
 var directExpando = document.getElementsByTagName("*");
 var indirectExpando = document.getElementById("theform");
 
 getPropTests(directExpando);
 getPropTests(indirectExpando);
 
--- a/dom/canvas/ImageBitmap.cpp
+++ b/dom/canvas/ImageBitmap.cpp
@@ -822,25 +822,17 @@ ImageBitmap::CreateInternal(nsIGlobalObj
   nsCOMPtr<nsIPrincipal> principal = aVideoEl.GetCurrentVideoPrincipal();
   bool CORSUsed = aVideoEl.GetCORSMode() != CORS_NONE;
   if (!CheckSecurityForHTMLElements(false, CORSUsed, principal)) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return nullptr;
   }
 
   // Create ImageBitmap.
-  ImageContainer *container = aVideoEl.GetImageContainer();
-
-  if (!container) {
-    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
-    return nullptr;
-  }
-
-  AutoLockImage lockImage(container);
-  layers::Image* data = lockImage.GetImage();
+  RefPtr<layers::Image> data = aVideoEl.GetCurrentImage();
   if (!data) {
     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     return nullptr;
   }
   RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
 
   // Set the picture rectangle.
   if (ret && aCropRect.isSome()) {
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -5552,25 +5552,25 @@ EventStateManager::WheelPrefs::OnPrefCha
   // forget all prefs, it's not problem for performance.
   sInstance->Reset();
   DeltaAccumulator::GetInstance()->Reset();
 }
 
 EventStateManager::WheelPrefs::WheelPrefs()
 {
   Reset();
-  Preferences::RegisterCallback(OnPrefChanged, "mousewheel.", nullptr);
+  Preferences::RegisterPrefixCallback(OnPrefChanged, "mousewheel.");
   Preferences::AddBoolVarCache(&sWheelEventsEnabledOnPlugins,
                                "plugin.mousewheel.enabled",
                                true);
 }
 
 EventStateManager::WheelPrefs::~WheelPrefs()
 {
-  Preferences::UnregisterCallback(OnPrefChanged, "mousewheel.", nullptr);
+  Preferences::UnregisterPrefixCallback(OnPrefChanged, "mousewheel.");
 }
 
 void
 EventStateManager::WheelPrefs::Reset()
 {
   memset(mInit, 0, sizeof(mInit));
 
 }
--- a/dom/fetch/Fetch.cpp
+++ b/dom/fetch/Fetch.cpp
@@ -33,97 +33,215 @@
 #include "mozilla/dom/Request.h"
 #include "mozilla/dom/Response.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/URLSearchParams.h"
 #include "mozilla/dom/workers/ServiceWorkerManager.h"
 #include "mozilla/Telemetry.h"
 
 #include "BodyExtractor.h"
+#include "FetchObserver.h"
 #include "InternalRequest.h"
 #include "InternalResponse.h"
 
 #include "WorkerPrivate.h"
 #include "WorkerRunnable.h"
 #include "WorkerScope.h"
 #include "Workers.h"
 
 namespace mozilla {
 namespace dom {
 
 using namespace workers;
 
+// This class helps the proxying of FetchSignal changes cross threads.
+class FetchSignalProxy final : public FetchSignal::Follower
+{
+  // This is created and released on the main-thread.
+  RefPtr<FetchSignal> mSignalMainThread;
+
+  // This value is used only for the creation of FetchSignal on the
+  // main-thread. They are not updated.
+  const bool mAborted;
+
+  // This runnable propagates changes from the FetchSignal on workers to the
+  // FetchSignal on main-thread.
+  class FetchSignalProxyRunnable final : public Runnable
+  {
+    RefPtr<FetchSignalProxy> mProxy;
+
+  public:
+    explicit FetchSignalProxyRunnable(FetchSignalProxy* aProxy)
+      : mProxy(aProxy)
+    {}
+
+    NS_IMETHOD
+    Run() override
+    {
+      MOZ_ASSERT(NS_IsMainThread());
+      FetchSignal* signal = mProxy->GetOrCreateSignalForMainThread();
+      signal->Abort();
+      return NS_OK;
+    }
+  };
+
+public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FetchSignalProxy)
+
+  explicit FetchSignalProxy(FetchSignal* aSignal)
+    : mAborted(aSignal->Aborted())
+  {
+    Follow(aSignal);
+  }
+
+  void
+  Aborted() override
+  {
+    RefPtr<FetchSignalProxyRunnable> runnable =
+      new FetchSignalProxyRunnable(this);
+    NS_DispatchToMainThread(runnable);
+  }
+
+  FetchSignal*
+  GetOrCreateSignalForMainThread()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    if (!mSignalMainThread) {
+      mSignalMainThread = new FetchSignal(mAborted);
+    }
+    return mSignalMainThread;
+  }
+
+  void
+  Shutdown()
+  {
+    Unfollow();
+  }
+
+private:
+  ~FetchSignalProxy()
+  {
+    NS_ReleaseOnMainThread(mSignalMainThread.forget());
+  }
+};
+
 class WorkerFetchResolver final : public FetchDriverObserver
 {
   friend class MainThreadFetchRunnable;
+  friend class WorkerDataAvailableRunnable;
+  friend class WorkerFetchResponseEndBase;
   friend class WorkerFetchResponseEndRunnable;
   friend class WorkerFetchResponseRunnable;
 
   RefPtr<PromiseWorkerProxy> mPromiseProxy;
+  RefPtr<FetchSignalProxy> mSignalProxy;
+  RefPtr<FetchObserver> mFetchObserver;
+
 public:
   // Returns null if worker is shutting down.
   static already_AddRefed<WorkerFetchResolver>
-  Create(workers::WorkerPrivate* aWorkerPrivate, Promise* aPromise)
+  Create(workers::WorkerPrivate* aWorkerPrivate, Promise* aPromise,
+         FetchSignal* aSignal, FetchObserver* aObserver)
   {
     MOZ_ASSERT(aWorkerPrivate);
     aWorkerPrivate->AssertIsOnWorkerThread();
-    RefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(aWorkerPrivate, aPromise);
+    RefPtr<PromiseWorkerProxy> proxy =
+      PromiseWorkerProxy::Create(aWorkerPrivate, aPromise);
     if (!proxy) {
       return nullptr;
     }
 
-    RefPtr<WorkerFetchResolver> r = new WorkerFetchResolver(proxy);
+    RefPtr<FetchSignalProxy> signalProxy;
+    if (aSignal) {
+      signalProxy = new FetchSignalProxy(aSignal);
+    }
+
+    RefPtr<WorkerFetchResolver> r =
+      new WorkerFetchResolver(proxy, signalProxy, aObserver);
     return r.forget();
   }
 
+  FetchSignal*
+  GetFetchSignal()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    if (!mSignalProxy) {
+      return nullptr;
+    }
+
+    return mSignalProxy->GetOrCreateSignalForMainThread();
+  }
+
   void
   OnResponseAvailableInternal(InternalResponse* aResponse) override;
 
   void
-  OnResponseEnd() override;
+  OnResponseEnd(FetchDriverObserver::EndReason eReason) override;
+
+  void
+  OnDataAvailable() override;
 
 private:
-  explicit WorkerFetchResolver(PromiseWorkerProxy* aProxy)
+   WorkerFetchResolver(PromiseWorkerProxy* aProxy,
+                       FetchSignalProxy* aSignalProxy,
+                       FetchObserver* aObserver)
     : mPromiseProxy(aProxy)
+    , mSignalProxy(aSignalProxy)
+    , mFetchObserver(aObserver)
   {
     MOZ_ASSERT(!NS_IsMainThread());
     MOZ_ASSERT(mPromiseProxy);
   }
 
   ~WorkerFetchResolver()
   {}
 
   virtual void
   FlushConsoleReport() override;
 };
 
 class MainThreadFetchResolver final : public FetchDriverObserver
 {
   RefPtr<Promise> mPromise;
   RefPtr<Response> mResponse;
+  RefPtr<FetchObserver> mFetchObserver;
 
   nsCOMPtr<nsILoadGroup> mLoadGroup;
 
   NS_DECL_OWNINGTHREAD
 public:
-  explicit MainThreadFetchResolver(Promise* aPromise);
+  MainThreadFetchResolver(Promise* aPromise, FetchObserver* aObserver)
+    : mPromise(aPromise)
+    , mFetchObserver(aObserver)
+  {}
 
   void
   OnResponseAvailableInternal(InternalResponse* aResponse) override;
 
   void SetLoadGroup(nsILoadGroup* aLoadGroup)
   {
     mLoadGroup = aLoadGroup;
   }
 
-  virtual void OnResponseEnd() override
+  void
+  OnResponseEnd(FetchDriverObserver::EndReason aReason) override
   {
+    if (aReason == eAborted) {
+      mPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
+    }
+
+    mFetchObserver = nullptr;
+
     FlushConsoleReport();
   }
 
+  void
+  OnDataAvailable() override;
+
 private:
   ~MainThreadFetchResolver();
 
   void FlushConsoleReport() override
   {
     mReporter->FlushConsoleReports(mLoadGroup);
   }
 };
@@ -164,19 +282,21 @@ public:
       fetch = new FetchDriver(mRequest, principal, loadGroup);
       nsAutoCString spec;
       if (proxy->GetWorkerPrivate()->GetBaseURI()) {
         proxy->GetWorkerPrivate()->GetBaseURI()->GetAsciiSpec(spec);
       }
       fetch->SetWorkerScript(spec);
     }
 
+    RefPtr<FetchSignal> signal = mResolver->GetFetchSignal();
+
     // ...but release it before calling Fetch, because mResolver's callback can
     // be called synchronously and they want the mutex, too.
-    return fetch->Fetch(mResolver);
+    return fetch->Fetch(signal, mResolver);
   }
 };
 
 already_AddRefed<Promise>
 FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput,
              const RequestInit& aInit, CallerType aCallerType, ErrorResult& aRv)
 {
   RefPtr<Promise> p = Promise::Create(aGlobal, aRv);
@@ -202,16 +322,28 @@ FetchRequest(nsIGlobalObject* aGlobal, c
 
   RefPtr<Request> request = Request::Constructor(global, aInput, aInit, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   RefPtr<InternalRequest> r = request->GetInternalRequest();
 
+  RefPtr<FetchSignal> signal;
+  if (aInit.mSignal.WasPassed()) {
+    signal = &aInit.mSignal.Value();
+    // Let's FetchDriver to deal with an already aborted signal.
+  }
+
+  RefPtr<FetchObserver> observer;
+  if (aInit.mObserve.WasPassed()) {
+    observer = new FetchObserver(aGlobal, signal);
+    aInit.mObserve.Value().HandleEvent(*observer);
+  }
+
   if (NS_IsMainThread()) {
     nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
     nsCOMPtr<nsIDocument> doc;
     nsCOMPtr<nsILoadGroup> loadGroup;
     nsIPrincipal* principal;
     if (window) {
       doc = window->GetExtantDoc();
       if (!doc) {
@@ -230,70 +362,91 @@ FetchRequest(nsIGlobalObject* aGlobal, c
       if (NS_WARN_IF(NS_FAILED(rv))) {
         aRv.Throw(rv);
         return nullptr;
       }
     }
 
     Telemetry::Accumulate(Telemetry::FETCH_IS_MAINTHREAD, 1);
 
-    RefPtr<MainThreadFetchResolver> resolver = new MainThreadFetchResolver(p);
+    RefPtr<MainThreadFetchResolver> resolver =
+      new MainThreadFetchResolver(p, observer);
     RefPtr<FetchDriver> fetch = new FetchDriver(r, principal, loadGroup);
     fetch->SetDocument(doc);
     resolver->SetLoadGroup(loadGroup);
-    aRv = fetch->Fetch(resolver);
+    aRv = fetch->Fetch(signal, resolver);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
   } else {
     WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
     MOZ_ASSERT(worker);
 
     Telemetry::Accumulate(Telemetry::FETCH_IS_MAINTHREAD, 0);
 
     if (worker->IsServiceWorker()) {
       r->SetSkipServiceWorker();
     }
 
-    RefPtr<WorkerFetchResolver> resolver = WorkerFetchResolver::Create(worker, p);
+    RefPtr<WorkerFetchResolver> resolver =
+      WorkerFetchResolver::Create(worker, p, signal, observer);
     if (!resolver) {
       NS_WARNING("Could not add WorkerFetchResolver workerHolder to worker");
       aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
       return nullptr;
     }
 
-    RefPtr<MainThreadFetchRunnable> run = new MainThreadFetchRunnable(resolver, r);
+    RefPtr<MainThreadFetchRunnable> run =
+      new MainThreadFetchRunnable(resolver, r);
     worker->DispatchToMainThread(run.forget());
   }
 
   return p.forget();
 }
 
-MainThreadFetchResolver::MainThreadFetchResolver(Promise* aPromise)
-  : mPromise(aPromise)
-{
-}
-
 void
 MainThreadFetchResolver::OnResponseAvailableInternal(InternalResponse* aResponse)
 {
   NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver);
   AssertIsOnMainThread();
 
   if (aResponse->Type() != ResponseType::Error) {
+    if (mFetchObserver) {
+      mFetchObserver->SetState(FetchState::Complete);
+    }
+
     nsCOMPtr<nsIGlobalObject> go = mPromise->GetParentObject();
     mResponse = new Response(go, aResponse);
     mPromise->MaybeResolve(mResponse);
   } else {
+    if (mFetchObserver) {
+      mFetchObserver->SetState(FetchState::Errored);
+    }
+
     ErrorResult result;
     result.ThrowTypeError<MSG_FETCH_FAILED>();
     mPromise->MaybeReject(result);
   }
 }
 
+void
+MainThreadFetchResolver::OnDataAvailable()
+{
+  NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver);
+  AssertIsOnMainThread();
+
+  if (!mFetchObserver) {
+    return;
+  }
+
+  if (mFetchObserver->State() == FetchState::Requesting) {
+    mFetchObserver->SetState(FetchState::Responding);
+  }
+}
+
 MainThreadFetchResolver::~MainThreadFetchResolver()
 {
   NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver);
 }
 
 class WorkerFetchResponseRunnable final : public MainThreadWorkerRunnable
 {
   RefPtr<WorkerFetchResolver> mResolver;
@@ -302,71 +455,126 @@ class WorkerFetchResponseRunnable final 
 public:
   WorkerFetchResponseRunnable(WorkerPrivate* aWorkerPrivate,
                               WorkerFetchResolver* aResolver,
                               InternalResponse* aResponse)
     : MainThreadWorkerRunnable(aWorkerPrivate)
     , mResolver(aResolver)
     , mInternalResponse(aResponse)
   {
+     MOZ_ASSERT(mResolver);
   }
 
   bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
   {
     MOZ_ASSERT(aWorkerPrivate);
     aWorkerPrivate->AssertIsOnWorkerThread();
 
     RefPtr<Promise> promise = mResolver->mPromiseProxy->WorkerPromise();
 
     if (mInternalResponse->Type() != ResponseType::Error) {
+      if (mResolver->mFetchObserver) {
+        mResolver->mFetchObserver->SetState(FetchState::Complete);
+      }
+
       RefPtr<nsIGlobalObject> global = aWorkerPrivate->GlobalScope();
       RefPtr<Response> response = new Response(global, mInternalResponse);
       promise->MaybeResolve(response);
     } else {
+      if (mResolver->mFetchObserver) {
+        mResolver->mFetchObserver->SetState(FetchState::Errored);
+      }
+
       ErrorResult result;
       result.ThrowTypeError<MSG_FETCH_FAILED>();
       promise->MaybeReject(result);
     }
     return true;
   }
 };
 
+class WorkerDataAvailableRunnable final : public MainThreadWorkerRunnable
+{
+  RefPtr<WorkerFetchResolver> mResolver;
+public:
+  WorkerDataAvailableRunnable(WorkerPrivate* aWorkerPrivate,
+                              WorkerFetchResolver* aResolver)
+    : MainThreadWorkerRunnable(aWorkerPrivate)
+    , mResolver(aResolver)
+  {
+  }
+
+  bool
+  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+
+    if (mResolver->mFetchObserver &&
+        mResolver->mFetchObserver->State() == FetchState::Requesting) {
+      mResolver->mFetchObserver->SetState(FetchState::Responding);
+    }
+
+    return true;
+  }
+};
+
 class WorkerFetchResponseEndBase
 {
-  RefPtr<PromiseWorkerProxy> mPromiseProxy;
+protected:
+  RefPtr<WorkerFetchResolver> mResolver;
+
 public:
-  explicit WorkerFetchResponseEndBase(PromiseWorkerProxy* aPromiseProxy)
-    : mPromiseProxy(aPromiseProxy)
+  explicit WorkerFetchResponseEndBase(WorkerFetchResolver* aResolver)
+    : mResolver(aResolver)
   {
-    MOZ_ASSERT(mPromiseProxy);
+    MOZ_ASSERT(aResolver);
   }
 
   void
   WorkerRunInternal(WorkerPrivate* aWorkerPrivate)
   {
     MOZ_ASSERT(aWorkerPrivate);
     aWorkerPrivate->AssertIsOnWorkerThread();
-    mPromiseProxy->CleanUp();
+
+    mResolver->mPromiseProxy->CleanUp();
+
+    mResolver->mFetchObserver = nullptr;
+
+    if (mResolver->mSignalProxy) {
+      mResolver->mSignalProxy->Shutdown();
+      mResolver->mSignalProxy = nullptr;
+    }
   }
 };
 
 class WorkerFetchResponseEndRunnable final : public MainThreadWorkerRunnable
                                            , public WorkerFetchResponseEndBase
 {
+  FetchDriverObserver::EndReason mReason;
+
 public:
-  explicit WorkerFetchResponseEndRunnable(PromiseWorkerProxy* aPromiseProxy)
-    : MainThreadWorkerRunnable(aPromiseProxy->GetWorkerPrivate())
-    , WorkerFetchResponseEndBase(aPromiseProxy)
+  WorkerFetchResponseEndRunnable(WorkerPrivate* aWorkerPrivate,
+                                 WorkerFetchResolver* aResolver,
+                                 FetchDriverObserver::EndReason aReason)
+    : MainThreadWorkerRunnable(aWorkerPrivate)
+    , WorkerFetchResponseEndBase(aResolver)
+    , mReason(aReason)
   {
   }
 
   bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
   {
+    if (mReason == FetchDriverObserver::eAborted) {
+      RefPtr<Promise> promise = mResolver->mPromiseProxy->WorkerPromise();
+      promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
+    }
+
     WorkerRunInternal(aWorkerPrivate);
     return true;
   }
 
   nsresult
   Cancel() override
   {
     // Execute Run anyway to make sure we cleanup our promise proxy to avoid
@@ -375,19 +583,20 @@ public:
     return WorkerRunnable::Cancel();
   }
 };
 
 class WorkerFetchResponseEndControlRunnable final : public MainThreadWorkerControlRunnable
                                                   , public WorkerFetchResponseEndBase
 {
 public:
-  explicit WorkerFetchResponseEndControlRunnable(PromiseWorkerProxy* aPromiseProxy)
-    : MainThreadWorkerControlRunnable(aPromiseProxy->GetWorkerPrivate())
-    , WorkerFetchResponseEndBase(aPromiseProxy)
+  WorkerFetchResponseEndControlRunnable(WorkerPrivate* aWorkerPrivate,
+                                        WorkerFetchResolver* aResolver)
+    : MainThreadWorkerControlRunnable(aWorkerPrivate)
+    , WorkerFetchResponseEndBase(aResolver)
   {
   }
 
   bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
   {
     WorkerRunInternal(aWorkerPrivate);
     return true;
@@ -411,32 +620,49 @@ WorkerFetchResolver::OnResponseAvailable
                                     aResponse);
 
   if (!r->Dispatch()) {
     NS_WARNING("Could not dispatch fetch response");
   }
 }
 
 void
-WorkerFetchResolver::OnResponseEnd()
+WorkerFetchResolver::OnDataAvailable()
+{
+  AssertIsOnMainThread();
+
+  MutexAutoLock lock(mPromiseProxy->Lock());
+  if (mPromiseProxy->CleanedUp()) {
+    return;
+  }
+
+  RefPtr<WorkerDataAvailableRunnable> r =
+    new WorkerDataAvailableRunnable(mPromiseProxy->GetWorkerPrivate(), this);
+  Unused << r->Dispatch();
+}
+
+void
+WorkerFetchResolver::OnResponseEnd(FetchDriverObserver::EndReason aReason)
 {
   AssertIsOnMainThread();
   MutexAutoLock lock(mPromiseProxy->Lock());
   if (mPromiseProxy->CleanedUp()) {
     return;
   }
 
   FlushConsoleReport();
 
   RefPtr<WorkerFetchResponseEndRunnable> r =
-    new WorkerFetchResponseEndRunnable(mPromiseProxy);
+    new WorkerFetchResponseEndRunnable(mPromiseProxy->GetWorkerPrivate(),
+                                       this, aReason);
 
   if (!r->Dispatch()) {
     RefPtr<WorkerFetchResponseEndControlRunnable> cr =
-      new WorkerFetchResponseEndControlRunnable(mPromiseProxy);
+      new WorkerFetchResponseEndControlRunnable(mPromiseProxy->GetWorkerPrivate(),
+                                                this);
     // This can fail if the worker thread is canceled or killed causing
     // the PromiseWorkerProxy to give up its WorkerHolder immediately,
     // allowing the worker thread to become Dead.
     if (!cr->Dispatch()) {
       NS_WARNING("Failed to dispatch WorkerFetchResponseEndControlRunnable");
     }
   }
 }
new file mode 100644
--- /dev/null
+++ b/dom/fetch/FetchController.cpp
@@ -0,0 +1,126 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "FetchController.h"
+#include "FetchSignal.h"
+#include "mozilla/dom/FetchControllerBinding.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FetchController, mGlobal, mSignal,
+                                      mFollowingSignal)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(FetchController)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(FetchController)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FetchController)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+/* static */ bool
+FetchController::IsEnabled(JSContext* aCx, JSObject* aGlobal)
+{
+  if (NS_IsMainThread()) {
+    return Preferences::GetBool("dom.fetchController.enabled", false);
+  }
+
+  using namespace workers;
+
+  // Otherwise, check the pref via the WorkerPrivate
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  if (!workerPrivate) {
+    return false;
+  }
+
+  return workerPrivate->FetchControllerEnabled();
+}
+
+/* static */ already_AddRefed<FetchController>
+FetchController::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
+{
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
+  if (!global) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  RefPtr<FetchController> fetchController = new FetchController(global);
+  return fetchController.forget();
+}
+
+FetchController::FetchController(nsIGlobalObject* aGlobal)
+  : mGlobal(aGlobal)
+  , mAborted(false)
+{}
+
+JSObject*
+FetchController::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+  return FetchControllerBinding::Wrap(aCx, this, aGivenProto);
+}
+
+nsIGlobalObject*
+FetchController::GetParentObject() const
+{
+  return mGlobal;
+}
+
+FetchSignal*
+FetchController::Signal()
+{
+  if (!mSignal) {
+    mSignal = new FetchSignal(this, mAborted);
+  }
+
+  return mSignal;
+}
+
+void
+FetchController::Abort()
+{
+  if (mAborted) {
+    return;
+  }
+
+  mAborted = true;
+
+  if (mSignal) {
+    mSignal->Abort();
+  }
+}
+
+void
+FetchController::Follow(FetchSignal& aSignal)
+{
+  FetchSignal::Follower::Follow(&aSignal);
+}
+
+void
+FetchController::Unfollow(FetchSignal& aSignal)
+{
+  if (mFollowingSignal != &aSignal) {
+    return;
+  }
+
+  FetchSignal::Follower::Unfollow();
+}
+
+FetchSignal*
+FetchController::Following() const
+{
+  return mFollowingSignal;
+}
+
+void
+FetchController::Aborted()
+{
+  Abort();
+}
+
+} // dom namespace
+} // mozilla namespace
new file mode 100644
--- /dev/null
+++ b/dom/fetch/FetchController.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_FetchController_h
+#define mozilla_dom_FetchController_h
+
+#include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/FetchSignal.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsWrapperCache.h"
+
+namespace mozilla {
+namespace dom {
+
+class FetchController final : public nsISupports
+                            , public nsWrapperCache
+                            , public FetchSignal::Follower
+{
+public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(FetchController)
+
+  static bool
+  IsEnabled(JSContext* aCx, JSObject* aGlobal);
+
+  static already_AddRefed<FetchController>
+  Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
+
+  explicit FetchController(nsIGlobalObject* aGlobal);
+
+  JSObject*
+  WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+  nsIGlobalObject*
+  GetParentObject() const;
+
+  FetchSignal*
+  Signal();
+
+  void
+  Abort();
+
+  void
+  Follow(FetchSignal& aSignal);
+
+  void
+  Unfollow(FetchSignal& aSignal);
+
+  FetchSignal*
+  Following() const;
+
+  // FetchSignal::Follower
+
+  void Aborted() override;
+
+private:
+  ~FetchController() = default;
+
+  nsCOMPtr<nsIGlobalObject> mGlobal;
+  RefPtr<FetchSignal> mSignal;
+
+  bool mAborted;
+};
+
+} // dom namespace
+} // mozilla namespace
+
+#endif // mozilla_dom_FetchController_h
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -62,17 +62,17 @@ FetchDriver::FetchDriver(InternalRequest
 FetchDriver::~FetchDriver()
 {
   // We assert this since even on failures, we should call
   // FailWithNetworkError().
   MOZ_ASSERT(mResponseAvailableCalled);
 }
 
 nsresult
-FetchDriver::Fetch(FetchDriverObserver* aObserver)
+FetchDriver::Fetch(FetchSignal* aSignal, FetchDriverObserver* aObserver)
 {
   workers::AssertIsOnMainThread();
 #ifdef DEBUG
   MOZ_ASSERT(!mFetchCalled);
   mFetchCalled = true;
 #endif
 
   mObserver = aObserver;
@@ -88,16 +88,28 @@ FetchDriver::Fetch(FetchDriverObserver* 
 
   UniquePtr<mozilla::ipc::PrincipalInfo> principalInfo(new mozilla::ipc::PrincipalInfo());
   nsresult rv = PrincipalToPrincipalInfo(mPrincipal, principalInfo.get());
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   mRequest->SetPrincipalInfo(Move(principalInfo));
+
+  // If the signal is aborted, it's time to inform the observer and terminate
+  // the operation.
+  if (aSignal) {
+    if (aSignal->Aborted()) {
+      Aborted();
+      return NS_OK;
+    }
+
+    Follow(aSignal);
+  }
+
   if (NS_FAILED(HttpFetch())) {
     FailWithNetworkError();
   }
 
   // Any failure is handled by FailWithNetworkError notifying the aObserver.
   return NS_OK;
 }
 
@@ -114,21 +126,17 @@ FetchDriver::HttpFetch()
   nsresult rv;
 
   nsCOMPtr<nsIIOService> ios = do_GetIOService(&rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoCString url;
   mRequest->GetURL(url);
   nsCOMPtr<nsIURI> uri;
-  rv = NS_NewURI(getter_AddRefs(uri),
-                          url,
-                          nullptr,
-                          nullptr,
-                          ios);
+  rv = NS_NewURI(getter_AddRefs(uri), url, nullptr, nullptr, ios);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Unsafe requests aren't allowed with when using no-core mode.
   if (mRequest->Mode() == RequestMode::No_cors &&
       mRequest->UnsafeRequest() &&
       (!mRequest->HasSimpleMethod() ||
        !mRequest->Headers()->HasOnlySimpleHeaders())) {
     MOZ_ASSERT(false, "The API should have caught this");
@@ -356,16 +364,18 @@ FetchDriver::HttpFetch()
       loadInfo->SetCorsPreflightInfo(unsafeHeaders, false);
     }
   }
 
   rv = chan->AsyncOpen2(this);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Step 4 onwards of "HTTP Fetch" is handled internally by Necko.
+
+  mChannel = chan;
   return NS_OK;
 }
 already_AddRefed<InternalResponse>
 FetchDriver::BeginAndGetFilteredResponse(InternalResponse* aResponse,
                                          bool aFoundOpaqueRedirect)
 {
   MOZ_ASSERT(aResponse);
   AutoTArray<nsCString, 4> reqURLList;
@@ -409,19 +419,21 @@ FetchDriver::FailWithNetworkError()
 {
   workers::AssertIsOnMainThread();
   RefPtr<InternalResponse> error = InternalResponse::NetworkError();
   if (mObserver) {
     mObserver->OnResponseAvailable(error);
 #ifdef DEBUG
     mResponseAvailableCalled = true;
 #endif
-    mObserver->OnResponseEnd();
+    mObserver->OnResponseEnd(FetchDriverObserver::eByNetworking);
     mObserver = nullptr;
   }
+
+  mChannel = nullptr;
 }
 
 NS_IMETHODIMP
 FetchDriver::OnStartRequest(nsIRequest* aRequest,
                             nsISupports* aContext)
 {
   workers::AssertIsOnMainThread();
 
@@ -597,27 +609,64 @@ FetchDriver::OnStartRequest(nsIRequest* 
 
   // Try to retarget off main thread.
   if (nsCOMPtr<nsIThreadRetargetableRequest> rr = do_QueryInterface(aRequest)) {
     Unused << NS_WARN_IF(NS_FAILED(rr->RetargetDeliveryTo(sts)));
   }
   return NS_OK;
 }
 
+namespace {
+
+// Runnable to call the observer OnDataAvailable on the main-thread.
+class DataAvailableRunnable final : public Runnable
+{
+  RefPtr<FetchDriverObserver> mObserver;
+
+public:
+  explicit DataAvailableRunnable(FetchDriverObserver* aObserver)
+    : mObserver(aObserver)
+  {
+     MOZ_ASSERT(aObserver);
+  }
+
+  NS_IMETHOD
+  Run() override
+  {
+    mObserver->OnDataAvailable();
+    mObserver = nullptr;
+    return NS_OK;
+  }
+};
+
+} // anonymous namespace
+
 NS_IMETHODIMP
 FetchDriver::OnDataAvailable(nsIRequest* aRequest,
                              nsISupports* aContext,
                              nsIInputStream* aInputStream,
                              uint64_t aOffset,
                              uint32_t aCount)
 {
   // NB: This can be called on any thread!  But we're guaranteed that it is
   // called between OnStartRequest and OnStopRequest, so we don't need to worry
   // about races.
 
+  if (mObserver) {
+    if (NS_IsMainThread()) {
+      mObserver->OnDataAvailable();
+    } else {
+      RefPtr<Runnable> runnable = new DataAvailableRunnable(mObserver);
+      nsresult rv = NS_DispatchToMainThread(runnable);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+    }
+  }
+
   uint32_t aRead;
   MOZ_ASSERT(mResponse);
   MOZ_ASSERT(mPipeOutputStream);
 
   // From "Main Fetch" step 17: SRI-part2.
   if (mResponse->Type() != ResponseType::Error &&
       !mRequest->GetIntegrity().IsEmpty()) {
     MOZ_ASSERT(mSRIDataVerifier);
@@ -719,20 +768,21 @@ FetchDriver::OnStopRequest(nsIRequest* a
       //From "Main Fetch" step 23: Process response.
       MOZ_ASSERT(mResponse);
       mObserver->OnResponseAvailable(mResponse);
       #ifdef DEBUG
         mResponseAvailableCalled = true;
       #endif
     }
 
-    mObserver->OnResponseEnd();
+    mObserver->OnResponseEnd(FetchDriverObserver::eByNetworking);
     mObserver = nullptr;
   }
 
+  mChannel = nullptr;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 FetchDriver::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
                                     nsIChannel* aNewChannel,
                                     uint32_t aFlags,
                                     nsIAsyncVerifyRedirectCallback *aCallback)
@@ -867,10 +917,27 @@ FetchDriver::SetRequestHeaders(nsIHttpCh
         aChannel->SetRequestHeader(NS_LITERAL_CSTRING("origin"),
                                    NS_ConvertUTF16toUTF8(origin),
                                    false /* merge */);
       MOZ_ASSERT(NS_SUCCEEDED(rv));
     }
   }
 }
 
+void
+FetchDriver::Aborted()
+{
+  if (mObserver) {
+  #ifdef DEBUG
+    mResponseAvailableCalled = true;
+  #endif
+    mObserver->OnResponseEnd(FetchDriverObserver::eAborted);
+    mObserver = nullptr;
+  }
+
+  if (mChannel) {
+    mChannel->Cancel(NS_BINDING_ABORTED);
+    mChannel = nullptr;
+  }
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/fetch/FetchDriver.h
+++ b/dom/fetch/FetchDriver.h
@@ -7,16 +7,17 @@
 #ifndef mozilla_dom_FetchDriver_h
 #define mozilla_dom_FetchDriver_h
 
 #include "nsIChannelEventSink.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIStreamListener.h"
 #include "nsIThreadRetargetableStreamListener.h"
 #include "mozilla/ConsoleReportCollector.h"
+#include "mozilla/dom/FetchSignal.h"
 #include "mozilla/dom/SRIMetadata.h"
 #include "mozilla/RefPtr.h"
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/net/ReferrerPolicy.h"
 
 class nsIConsoleReportCollector;
 class nsIDocument;
@@ -44,71 +45,91 @@ public:
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FetchDriverObserver);
   void OnResponseAvailable(InternalResponse* aResponse)
   {
     MOZ_ASSERT(!mGotResponseAvailable);
     mGotResponseAvailable = true;
     OnResponseAvailableInternal(aResponse);
   }
-  virtual void OnResponseEnd()
+
+  enum EndReason
+  {
+    eAborted,
+    eByNetworking,
+  };
+
+  virtual void OnResponseEnd(EndReason aReason)
   { };
 
   nsIConsoleReportCollector* GetReporter() const
   {
     return mReporter;
   }
 
   virtual void FlushConsoleReport() = 0;
+
+  virtual void OnDataAvailable() = 0;
+
 protected:
   virtual ~FetchDriverObserver()
   { };
 
   virtual void OnResponseAvailableInternal(InternalResponse* aResponse) = 0;
 
   nsCOMPtr<nsIConsoleReportCollector> mReporter;
 private:
   bool mGotResponseAvailable;
 };
 
 class FetchDriver final : public nsIStreamListener,
                           public nsIChannelEventSink,
                           public nsIInterfaceRequestor,
-                          public nsIThreadRetargetableStreamListener
+                          public nsIThreadRetargetableStreamListener,
+                          public FetchSignal::Follower
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
   NS_DECL_NSICHANNELEVENTSINK
   NS_DECL_NSIINTERFACEREQUESTOR
   NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
 
-  explicit FetchDriver(InternalRequest* aRequest, nsIPrincipal* aPrincipal,
-                       nsILoadGroup* aLoadGroup);
-  NS_IMETHOD Fetch(FetchDriverObserver* aObserver);
+  FetchDriver(InternalRequest* aRequest,
+              nsIPrincipal* aPrincipal,
+              nsILoadGroup* aLoadGroup);
+
+  nsresult Fetch(FetchSignal* aSignal,
+                 FetchDriverObserver* aObserver);
 
   void
   SetDocument(nsIDocument* aDocument);
 
   void
   SetWorkerScript(const nsACString& aWorkerScirpt)
   {
     MOZ_ASSERT(!aWorkerScirpt.IsEmpty());
     mWorkerScript = aWorkerScirpt;
   }
 
+  // FetchSignal::Follower
+
+  void
+  Aborted() override;
+
 private:
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsCOMPtr<nsILoadGroup> mLoadGroup;
   RefPtr<InternalRequest> mRequest;
   RefPtr<InternalResponse> mResponse;
   nsCOMPtr<nsIOutputStream> mPipeOutputStream;
   RefPtr<FetchDriverObserver> mObserver;
   nsCOMPtr<nsIDocument> mDocument;
+  nsCOMPtr<nsIChannel> mChannel;
   nsAutoPtr<SRICheckDataVerifier> mSRIDataVerifier;
   SRIMetadata mSRIMetadata;
   nsCString mWorkerScript;
 
 #ifdef DEBUG
   bool mResponseAvailableCalled;
   bool mFetchCalled;
 #endif
new file mode 100644
--- /dev/null
+++ b/dom/fetch/FetchObserver.cpp
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "FetchObserver.h"
+#include "mozilla/dom/Event.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(FetchObserver)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(FetchObserver,
+                                                  DOMEventTargetHelper)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(FetchObserver,
+                                                DOMEventTargetHelper)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FetchObserver)
+NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
+
+NS_IMPL_ADDREF_INHERITED(FetchObserver, DOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(FetchObserver, DOMEventTargetHelper)
+
+/* static */ bool
+FetchObserver::IsEnabled(JSContext* aCx, JSObject* aGlobal)
+{
+  if (NS_IsMainThread()) {
+    return Preferences::GetBool("dom.fetchObserver.enabled", false);
+  }
+
+  using namespace workers;
+
+  // Otherwise, check the pref via the WorkerPrivate
+  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
+  if (!workerPrivate) {
+    return false;
+  }
+
+  return workerPrivate->FetchObserverEnabled();
+}
+
+FetchObserver::FetchObserver(nsIGlobalObject* aGlobal,
+                             FetchSignal* aSignal)
+  : DOMEventTargetHelper(aGlobal)
+  , mState(FetchState::Requesting)
+{
+  if (aSignal) {
+    Follow(aSignal);
+  }
+}
+
+JSObject*
+FetchObserver::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+  return FetchObserverBinding::Wrap(aCx, this, aGivenProto);
+}
+
+FetchState
+FetchObserver::State() const
+{
+  return mState;
+}
+
+void
+FetchObserver::Aborted()
+{
+  SetState(FetchState::Aborted);
+}
+
+void
+FetchObserver::SetState(FetchState aState)
+{
+  MOZ_ASSERT(mState < aState);
+
+  if (mState == FetchState::Aborted ||
+      mState == FetchState::Errored ||
+      mState == FetchState::Complete) {
+    // We are already in a final state.
+    return;
+  }
+
+  // We cannot pass from Requesting to Complete directly.
+  if (mState == FetchState::Requesting &&
+      aState == FetchState::Complete) {
+    SetState(FetchState::Responding);
+  }
+
+  mState = aState;
+
+  if (mState == FetchState::Aborted ||
+      mState == FetchState::Errored ||
+      mState == FetchState::Complete) {
+    Unfollow();
+  }
+
+  EventInit init;
+  init.mBubbles = false;
+  init.mCancelable = false;
+
+  // TODO which kind of event should we dispatch here?
+
+  RefPtr<Event> event =
+    Event::Constructor(this, NS_LITERAL_STRING("statechange"), init);
+  event->SetTrusted(true);
+
+  bool dummy;
+  DispatchEvent(event, &dummy);
+}
+
+} // dom namespace
+} // mozilla namespace
new file mode 100644
--- /dev/null
+++ b/dom/fetch/FetchObserver.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_FetchObserver_h
+#define mozilla_dom_FetchObserver_h
+
+#include "mozilla/DOMEventTargetHelper.h"
+#include "mozilla/dom/FetchObserverBinding.h"
+#include "mozilla/dom/FetchSignal.h"
+
+namespace mozilla {
+namespace dom {
+
+class FetchObserver final : public DOMEventTargetHelper
+                          , public FetchSignal::Follower
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FetchObserver, DOMEventTargetHelper)
+
+  static bool
+  IsEnabled(JSContext* aCx, JSObject* aGlobal);
+
+  FetchObserver(nsIGlobalObject* aGlobal, FetchSignal* aSignal);
+
+  JSObject*
+  WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+  FetchState
+  State() const;
+
+  IMPL_EVENT_HANDLER(statechange);
+  IMPL_EVENT_HANDLER(requestprogress);
+  IMPL_EVENT_HANDLER(responseprogress);
+
+  void
+  Aborted() override;
+
+  void
+  SetState(FetchState aState);
+
+private:
+  ~FetchObserver() = default;
+
+  FetchState mState;
+};
+
+} // dom namespace
+} // mozilla namespace
+
+#endif // mozilla_dom_FetchObserver_h
new file mode 100644
--- /dev/null
+++ b/dom/fetch/FetchSignal.cpp
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "FetchSignal.h"
+#include "mozilla/dom/Event.h"
+#include "mozilla/dom/FetchSignalBinding.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(FetchSignal)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(FetchSignal,
+                                                  DOMEventTargetHelper)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mController)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(FetchSignal,
+                                                DOMEventTargetHelper)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mController)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FetchSignal)
+NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
+
+NS_IMPL_ADDREF_INHERITED(FetchSignal, DOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(FetchSignal, DOMEventTargetHelper)
+
+FetchSignal::FetchSignal(FetchController* aController,
+                         bool aAborted)
+  : DOMEventTargetHelper(aController->GetParentObject())
+  , mController(aController)
+  , mAborted(aAborted)
+{}
+
+FetchSignal::FetchSignal(bool aAborted)
+  : mAborted(aAborted)
+{}
+
+JSObject*
+FetchSignal::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+  return FetchSignalBinding::Wrap(aCx, this, aGivenProto);
+}
+
+bool
+FetchSignal::Aborted() const
+{
+  return mAborted;
+}
+
+void
+FetchSignal::Abort()
+{
+  MOZ_ASSERT(!mAborted);
+  mAborted = true;
+
+  // Let's inform the followers.
+  for (uint32_t i = 0; i < mFollowers.Length(); ++i) {
+    mFollowers[i]->Aborted();
+  }
+
+  EventInit init;
+  init.mBubbles = false;
+  init.mCancelable = false;
+
+  // TODO which kind of event should we dispatch here?
+
+  RefPtr<Event> event =
+    Event::Constructor(this, NS_LITERAL_STRING("abort"), init);
+  event->SetTrusted(true);
+
+  bool dummy;
+  DispatchEvent(event, &dummy);
+}
+
+void
+FetchSignal::AddFollower(FetchSignal::Follower* aFollower)
+{
+  MOZ_DIAGNOSTIC_ASSERT(aFollower);
+  if (!mFollowers.Contains(aFollower)) {
+    mFollowers.AppendElement(aFollower);
+  }
+}
+
+void
+FetchSignal::RemoveFollower(FetchSignal::Follower* aFollower)
+{
+  MOZ_DIAGNOSTIC_ASSERT(aFollower);
+  mFollowers.RemoveElement(aFollower);
+}
+
+bool
+FetchSignal::CanAcceptFollower(FetchSignal::Follower* aFollower) const
+{
+  MOZ_DIAGNOSTIC_ASSERT(aFollower);
+
+  if (!mController) {
+    return true;
+  }
+
+  if (aFollower == mController) {
+    return false;
+  }
+
+  FetchSignal* following = mController->Following();
+  if (!following) {
+    return true;
+  }
+
+  return following->CanAcceptFollower(aFollower);
+}
+
+// FetchSignal::Follower
+// ----------------------------------------------------------------------------
+
+FetchSignal::Follower::~Follower()
+{
+  Unfollow();
+}
+
+void
+FetchSignal::Follower::Follow(FetchSignal* aSignal)
+{
+  MOZ_DIAGNOSTIC_ASSERT(aSignal);
+
+  if (!aSignal->CanAcceptFollower(this)) {
+    return;
+  }
+
+  Unfollow();
+
+  mFollowingSignal = aSignal;
+  aSignal->AddFollower(this);
+}
+
+void
+FetchSignal::Follower::Unfollow()
+{
+  if (mFollowingSignal) {
+    mFollowingSignal->RemoveFollower(this);
+    mFollowingSignal = nullptr;
+  }
+}
+
+} // dom namespace
+} // mozilla namespace
new file mode 100644
--- /dev/null
+++ b/dom/fetch/FetchSignal.h
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_FetchSignal_h
+#define mozilla_dom_FetchSignal_h
+
+#include "mozilla/DOMEventTargetHelper.h"
+
+namespace mozilla {
+namespace dom {
+
+class FetchController;
+class FetchSignal;
+
+class FetchSignal final : public DOMEventTargetHelper
+{
+public:
+  // This class must be implemented by objects who want to follow a FetchSignal.
+  class Follower
+  {
+  public:
+    virtual void Aborted() = 0;
+
+  protected:
+    virtual ~Follower();
+
+    void
+    Follow(FetchSignal* aSignal);
+
+    void
+    Unfollow();
+
+    RefPtr<FetchSignal> mFollowingSignal;
+  };
+
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FetchSignal, DOMEventTargetHelper)
+
+  FetchSignal(FetchController* aController, bool aAborted);
+  explicit FetchSignal(bool aAborted);
+
+  JSObject*
+  WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+  bool
+  Aborted() const;
+
+  void
+  Abort();
+
+  IMPL_EVENT_HANDLER(abort);
+
+  void
+  AddFollower(Follower* aFollower);
+
+  void
+  RemoveFollower(Follower* aFollower);
+
+  bool
+  CanAcceptFollower(Follower* aFollower) const;
+
+private:
+  ~FetchSignal() = default;
+
+  RefPtr<FetchController> mController;
+
+  // Raw pointers. Follower unregisters itself in the DTOR.
+  nsTArray<Follower*> mFollowers;
+
+  bool mAborted;
+};
+
+} // dom namespace
+} // mozilla namespace
+
+#endif // mozilla_dom_FetchSignal_h
--- a/dom/fetch/Request.h
+++ b/dom/fetch/Request.h
@@ -7,16 +7,17 @@
 #ifndef mozilla_dom_Request_h
 #define mozilla_dom_Request_h
 
 #include "nsIContentPolicy.h"
 #include "nsISupportsImpl.h"
 #include "nsWrapperCache.h"
 
 #include "mozilla/dom/Fetch.h"
+#include "mozilla/dom/FetchSignal.h"
 #include "mozilla/dom/InternalRequest.h"
 // Required here due to certain WebIDL enums/classes being declared in both
 // files.
 #include "mozilla/dom/RequestBinding.h"
 
 namespace mozilla {
 namespace dom {
 
--- a/dom/fetch/moz.build
+++ b/dom/fetch/moz.build
@@ -6,32 +6,38 @@
 
 with Files("**"):
     BUG_COMPONENT = ("Core", "DOM")
 
 EXPORTS.mozilla.dom += [
     'BodyExtractor.h',
     'ChannelInfo.h',
     'Fetch.h',
+    'FetchController.h',
     'FetchDriver.h',
     'FetchIPCTypes.h',
+    'FetchObserver.h',
+    'FetchSignal.h',
     'FetchUtil.h',
     'Headers.h',
     'InternalHeaders.h',
     'InternalRequest.h',
     'InternalResponse.h',
     'Request.h',
     'Response.h',
 ]
 
 UNIFIED_SOURCES += [
     'BodyExtractor.cpp',
     'ChannelInfo.cpp',
     'Fetch.cpp',
+    'FetchController.cpp',
     'FetchDriver.cpp',
+    'FetchObserver.cpp',
+    'FetchSignal.cpp',
     'FetchUtil.cpp',
     'Headers.cpp',
     'InternalHeaders.cpp',
     'InternalRequest.cpp',
     'InternalResponse.cpp',
     'Request.cpp',
     'Response.cpp',
 ]
--- a/dom/flyweb/FlyWebDiscoveryManager.cpp
+++ b/dom/flyweb/FlyWebDiscoveryManager.cpp
@@ -11,16 +11,17 @@
 #include "jsapi.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/Logging.h"
 #include "nsComponentManagerUtils.h"
 #include "nsServiceManagerUtils.h"
 
 #include "mozilla/dom/FlyWebDiscoveryManager.h"
 #include "mozilla/dom/FlyWebDiscoveryManagerBinding.h"
+#include "mozilla/dom/Element.h"
 
 namespace mozilla {
 namespace dom {
 
 static LazyLogModule gFlyWebDiscoveryManagerLog("FlyWebDiscoveryManager");
 #undef LOG_I
 #define LOG_I(...) MOZ_LOG(mozilla::dom::gFlyWebDiscoveryManagerLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
 #undef LOG_E
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -1025,31 +1025,31 @@ private:
   bool
   IsPlayingThroughTheAudioChannel() const
   {
     // If we have an error, we are not playing.
     if (mOwner->GetError()) {
       return false;
     }
 
+    // We should consider any bfcached page or inactive document as non-playing.
+    if (!mOwner->IsActive()) {
+      return false;
+    }
+
     // It might be resumed from remote, we should keep the audio channel agent.
     if (IsSuspended()) {
       return true;
     }
 
     // Are we paused
     if (mOwner->mPaused) {
       return false;
     }
 
-    // We should consider any bfcached page or inactive document as non-playing.
-    if (!mOwner->IsActive()) {
-      return false;
-    }
-
     // A loop always is playing
     if (mOwner->HasAttr(kNameSpaceID_None, nsGkAtoms::loop)) {
       return true;
     }
 
     // If we are actually playing...
     if (mOwner->IsCurrentlyPlaying()) {
       return true;
@@ -1527,22 +1527,17 @@ HTMLMediaElement::SetVisible(bool aVisib
   }
 
   mDecoder->SetForcedHidden(!aVisible);
 }
 
 already_AddRefed<layers::Image>
 HTMLMediaElement::GetCurrentImage()
 {
-  // Mark the decoder owned by the element as tainted so that the
-  // suspend-video-decoder is disabled.
-  mHasSuspendTaint = true;
-  if (mDecoder) {
-    mDecoder->SetSuspendTaint(true);
-  }
+  MarkAsTainted();
 
   // TODO: In bug 1345404, handle case when video decoder is already suspended.
   ImageContainer* container = GetImageContainer();
   if (!container) {
     return nullptr;
   }
 
   AutoLockImage lockImage(container);
@@ -3329,17 +3324,18 @@ HTMLMediaElement::AddCaptureMediaTrackTo
 
 already_AddRefed<DOMMediaStream>
 HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded,
                                         bool aCaptureAudio,
                                         MediaStreamGraph* aGraph)
 {
   MOZ_RELEASE_ASSERT(aGraph);
 
-    MarkAsContentSource(CallerAPI::CAPTURE_STREAM);
+  MarkAsContentSource(CallerAPI::CAPTURE_STREAM);
+  MarkAsTainted();
 
   nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
   if (!window) {
     return nullptr;
   }
   if (ContainsRestrictedContent()) {
     return nullptr;
   }
@@ -3718,17 +3714,16 @@ HTMLMediaElement::HTMLMediaElement(alrea
     mDownloadSuspendedByCache(false, "HTMLMediaElement::mDownloadSuspendedByCache"),
     mAudioChannel(AudioChannelService::GetDefaultAudioChannel()),
     mDisableVideo(false),
     mHasUserInteraction(false),
     mFirstFrameLoaded(false),
     mDefaultPlaybackStartPosition(0.0),
     mIsAudioTrackAudible(false),
     mHasSuspendTaint(false),
-    mMediaTracksConstructed(false),
     mVisibilityState(Visibility::UNTRACKED),
     mErrorSink(new ErrorSink(this)),
     mAudioChannelWrapper(new AudioChannelAgentCallback(this, mAudioChannel))
 {
   ErrorResult rv;
 
   double defaultVolume = Preferences::GetFloat("media.default_volume", 1.0);
   SetVolume(defaultVolume, rv);
@@ -7418,21 +7413,17 @@ nsIDocument*
 HTMLMediaElement::GetDocument() const
 {
   return OwnerDoc();
 }
 
 void
 HTMLMediaElement::ConstructMediaTracks(const MediaInfo* aInfo)
 {
-  if (mMediaTracksConstructed || !aInfo) {
-    return;
-  }
-
-  mMediaTracksConstructed = true;
+  MOZ_ASSERT(aInfo);
 
   AudioTrackList* audioList = AudioTracks();
   if (audioList && aInfo->HasAudio()) {
     const TrackInfo& info = aInfo->mAudio;
     RefPtr<AudioTrack> track = MediaTrackList::CreateAudioTrack(
     info.mId, info.mKind, info.mLabel, info.mLanguage, info.mEnabled);
 
     audioList->AddTrack(track);
@@ -7456,18 +7447,16 @@ HTMLMediaElement::RemoveMediaTracks()
   if (audioList) {
     audioList->RemoveTracks();
   }
 
   VideoTrackList* videoList = VideoTracks();
   if (videoList) {
     videoList->RemoveTracks();
   }
-
-  mMediaTracksConstructed = false;
 }
 
 class MediaElementGMPCrashHelper : public GMPCrashHelper
 {
 public:
   explicit MediaElementGMPCrashHelper(HTMLMediaElement* aElement)
     : mElement(aElement)
   {
@@ -7486,16 +7475,26 @@ private:
 };
 
 already_AddRefed<GMPCrashHelper>
 HTMLMediaElement::CreateGMPCrashHelper()
 {
   return MakeAndAddRef<MediaElementGMPCrashHelper>(this);
 }
 
+void
+HTMLMediaElement::MarkAsTainted()
+{
+  mHasSuspendTaint = true;
+
+  if (mDecoder) {
+    mDecoder->SetSuspendTaint(true);
+  }
+}
+
 bool HasDebuggerPrivilege(JSContext* aCx, JSObject* aObj)
 {
   return nsContentUtils::CallerHasPermission(aCx,
                                              NS_LITERAL_STRING("debugger"));
  }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -1305,16 +1305,20 @@ protected:
   // and queues a task to resolve them also to dispatch a "playing" event.
   void NotifyAboutPlaying();
 
   already_AddRefed<Promise> CreateDOMPromise(ErrorResult& aRv) const;
 
   // Pass information for deciding the video decode mode to decoder.
   void NotifyDecoderActivityChanges() const;
 
+  // Mark the decoder owned by the element as tainted so that the
+  // suspend-video-decoder is disabled.
+  void MarkAsTainted();
+
   // The current decoder. Load() has been called on this decoder.
   // At most one of mDecoder and mSrcStream can be non-null.
   RefPtr<MediaDecoder> mDecoder;
 
   // The DocGroup-specific AbstractThread::MainThread() of this HTML element.
   RefPtr<AbstractThread> mAbstractMainThread;
 
   // Observers listening to changes to the mDecoder principal.
@@ -1736,20 +1740,16 @@ private:
 
   // True if the audio track is not silent.
   bool mIsAudioTrackAudible;
 
   // True if media element has been marked as 'tainted' and can't
   // participate in video decoder suspending.
   bool mHasSuspendTaint;
 
-  // True if audio tracks and video tracks are constructed and added into the
-  // track list, false if all tracks are removed from the track list.
-  bool mMediaTracksConstructed;
-
   Visibility mVisibilityState;
 
   UniquePtr<ErrorSink> mErrorSink;
 
   // This wrapper will handle all audio channel related stuffs, eg. the operations
   // of tab audio indicator, Fennec's media control.
   // Note: mAudioChannelWrapper might be null after GC happened.
   RefPtr<AudioChannelAgentCallback> mAudioChannelWrapper;
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -320,16 +320,20 @@ LargeAllocationNotOnlyToplevelInTabGroup
 LargeAllocationNonE10S=A Large-Allocation header was ignored due to the document not being loaded out of process.
 GeolocationInsecureRequestIsForbidden=A Geolocation request can only be fulfilled in a secure context.
 # LOCALIZATION NOTE: Do not translate "Large-Allocation", as it is a literal header name.
 LargeAllocationNonWin32=This page would be loaded in a new process due to a Large-Allocation header, however Large-Allocation process creation is disabled on non-Win32 platforms.
 # LOCALIZATION NOTE: Do not translate URL.createObjectURL(MediaStream).
 URLCreateObjectURL_MediaStream=URL.createObjectURL(MediaStream) is deprecated and will be removed soon.
 # LOCALIZATION NOTE: Do not translate xml:base.
 XMLBaseAttributeWarning=Use of xml:base attribute is deprecated and will be removed soon. Please remove any use of it.
+# LOCALIZATION NOTE: %S is the tag name of the element that starts the loop
+SVGReferenceLoopWarning=There is an SVG <%S> reference loop in this document, which will prevent the document rendering correctly.
+# LOCALIZATION NOTE: %S is the tag name of the element that starts the chain
+SVGReferenceChainLengthExceededWarning=There is an SVG <%S> reference chain which is too long in this document, which will prevent the document rendering correctly.
 # LOCALIZATION NOTE: Do not translate "<script>".
 ScriptSourceEmpty=‘%S’ attribute of <script> element is empty.
 # LOCALIZATION NOTE: Do not translate "<script>".
 ScriptSourceInvalidUri=‘%S’ attribute of <script> element is not a valid URI: “%S”
 # LOCALIZATION NOTE: Do not translate "<script>".
 ScriptSourceLoadFailed=Loading failed for the <script> with source “%S”.
 # LOCALIZATION NOTE: Do not translate "<script>".
 ScriptSourceMalformed=<script> source URI is malformed: “%S”.
--- a/dom/media/CubebUtils.cpp
+++ b/dom/media/CubebUtils.cpp
@@ -410,25 +410,21 @@ Maybe<uint32_t> GetCubebMSGLatencyInFram
     return Maybe<uint32_t>();
   }
   MOZ_ASSERT(sCubebMSGLatencyInFrames > 0);
   return Some(sCubebMSGLatencyInFrames);
 }
 
 void InitLibrary()
 {
-  PrefChanged(PREF_VOLUME_SCALE, nullptr);
-  Preferences::RegisterCallback(PrefChanged, PREF_VOLUME_SCALE);
-  PrefChanged(PREF_CUBEB_LATENCY_PLAYBACK, nullptr);
-  PrefChanged(PREF_CUBEB_LATENCY_MSG, nullptr);
-  PrefChanged(PREF_CUBEB_BACKEND, nullptr);
-  Preferences::RegisterCallback(PrefChanged, PREF_CUBEB_BACKEND);
-  Preferences::RegisterCallback(PrefChanged, PREF_CUBEB_LATENCY_PLAYBACK);
-  Preferences::RegisterCallback(PrefChanged, PREF_CUBEB_LATENCY_MSG);
-  Preferences::RegisterCallback(PrefChanged, PREF_CUBEB_LOG_LEVEL);
+  Preferences::RegisterCallbackAndCall(PrefChanged, PREF_VOLUME_SCALE);
+  Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_LATENCY_PLAYBACK);
+  Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_LATENCY_MSG);
+  Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_BACKEND);
+  Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_LOG_LEVEL);
 #ifndef MOZ_WIDGET_ANDROID
   NS_DispatchToMainThread(NS_NewRunnableFunction(&InitBrandName));
 #endif
 }
 
 void ShutdownLibrary()
 {
   Preferences::UnregisterCallback(PrefChanged, PREF_VOLUME_SCALE);
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -388,16 +388,17 @@ MediaDecoder::MediaDecoder(MediaDecoderO
   , mInfiniteStream(false)
   , mOwner(aOwner)
   , mAbstractMainThread(aOwner->AbstractMainThread())
   , mFrameStats(new FrameStatistics())
   , mVideoFrameContainer(aOwner->GetVideoFrameContainer())
   , mPlaybackStatistics(new MediaChannelStatistics())
   , mPinnedForSeek(false)
   , mMinimizePreroll(false)
+  , mMediaTracksConstructed(false)
   , mFiredMetadataLoaded(false)
   , mIsDocumentVisible(false)
   , mElementVisibility(Visibility::UNTRACKED)
   , mIsElementInTree(false)
   , mForcedHidden(false)
   , mHasSuspendTaint(false)
   , INIT_MIRROR(mStateMachineIsShutdown, true)
   , INIT_MIRROR(mBuffered, TimeIntervals())
@@ -801,17 +802,17 @@ MediaDecoder::GetCurrentPrincipal()
   MOZ_ASSERT(NS_IsMainThread());
   return mResource ? mResource->GetCurrentPrincipal() : nullptr;
 }
 
 void
 MediaDecoder::OnMetadataUpdate(TimedMetadata&& aMetadata)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  GetOwner()->RemoveMediaTracks();
+  RemoveMediaTracks();
   MetadataLoaded(nsAutoPtr<MediaInfo>(new MediaInfo(*aMetadata.mInfo)),
                  Move(aMetadata.mTags),
                  MediaDecoderEventVisibility::Observable);
   FirstFrameLoaded(Move(aMetadata.mInfo),
                    MediaDecoderEventVisibility::Observable);
 }
 
 void
@@ -824,17 +825,17 @@ MediaDecoder::MetadataLoaded(nsAutoPtr<M
 
   DECODER_LOG("MetadataLoaded, channels=%u rate=%u hasAudio=%d hasVideo=%d",
               aInfo->mAudio.mChannels, aInfo->mAudio.mRate,
               aInfo->HasAudio(), aInfo->HasVideo());
 
   mMediaSeekable = aInfo->mMediaSeekable;
   mMediaSeekableOnlyInBufferedRanges = aInfo->mMediaSeekableOnlyInBufferedRanges;
   mInfo = aInfo.forget();
-  GetOwner()->ConstructMediaTracks(mInfo);
+  ConstructMediaTracks();
 
   // Make sure the element and the frame (if any) are told about
   // our new size.
   if (aEventVisibility != MediaDecoderEventVisibility::Suppressed) {
     mFiredMetadataLoaded = true;
     GetOwner()->MetadataLoaded(mInfo,
                                nsAutoPtr<const MetadataTags>(aTags.forget()));
   }
@@ -1189,19 +1190,19 @@ MediaDecoder::ChangeState(PlayState aSta
   if (mNextState == aState) {
     mNextState = PLAY_STATE_PAUSED;
   }
 
   DECODER_LOG("ChangeState %s => %s", PlayStateStr(), ToPlayStateStr(aState));
   mPlayState = aState;
 
   if (mPlayState == PLAY_STATE_PLAYING) {
-    GetOwner()->ConstructMediaTracks(mInfo);
+    ConstructMediaTracks();
   } else if (IsEnded()) {
-    GetOwner()->RemoveMediaTracks();
+    RemoveMediaTracks();
   }
 }
 
 void
 MediaDecoder::UpdateLogicalPositionInternal()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
@@ -1758,16 +1759,42 @@ MediaDecoder::GetOwner() const
 {
   MOZ_ASSERT(NS_IsMainThread());
   // Check object lifetime when mOwner points to a media element.
   MOZ_DIAGNOSTIC_ASSERT(!mOwner || !mIsMediaElement || mElement);
   // mOwner is valid until shutdown.
   return mOwner;
 }
 
+void
+MediaDecoder::ConstructMediaTracks()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
+
+  if (mMediaTracksConstructed || !mInfo) {
+    return;
+  }
+
+  GetOwner()->ConstructMediaTracks(mInfo);
+
+  mMediaTracksConstructed = true;
+}
+
+void
+MediaDecoder::RemoveMediaTracks()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
+
+  GetOwner()->RemoveMediaTracks();
+
+  mMediaTracksConstructed = false;
+}
+
 MediaDecoderOwner::NextFrameStatus
 MediaDecoder::NextFrameBufferedStatus()
 {
   MOZ_ASSERT(NS_IsMainThread());
   // Next frame hasn't been decoded yet.
   // Use the buffered range to consider if we have the next frame available.
   media::TimeUnit currentPosition =
     media::TimeUnit::FromMicroseconds(CurrentPosition());
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -395,16 +395,27 @@ private:
    * thread.
    ******/
 
   // Change to a new play state. This updates the mState variable and
   // notifies any thread blocking on this object's monitor of the
   // change. Call on the main thread only.
   virtual void ChangeState(PlayState aState);
 
+  // Called from MetadataLoaded(). Ask its owner to create audio/video tracks
+  // and adds them to its owner's audio/video track list.
+  // Call on the main thread only.
+  void ConstructMediaTracks();
+
+  // Ask its owner to remove all audio tracks and video tracks that are
+  // previously added into the track list.
+  // Call on the main thread only.
+  void RemoveMediaTracks();
+
+
   // Called when the video has completed playing.
   // Call on the main thread only.
   void PlaybackEnded();
 
   void OnSeekRejected();
   void OnSeekResolved();
 
   void SeekingChanged()
@@ -689,16 +700,21 @@ protected:
   dom::AudioChannel mAudioChannel;
 
   // True if the decoder has been directed to minimize its preroll before
   // playback starts. After the first time playback starts, we don't attempt
   // to minimize preroll, as we assume the user is likely to keep playing,
   // or play the media again.
   bool mMinimizePreroll;
 
+  // True if audio tracks and video tracks are constructed and added into the
+  // owenr's track list, false if all tracks are removed from the owner's track
+  // list.
+  bool mMediaTracksConstructed;
+
   // True if we've already fired metadataloaded.
   bool mFiredMetadataLoaded;
 
   // True if the media is seekable (i.e. supports random access).
   bool mMediaSeekable = true;
 
   // True if the media is only seekable within its buffered ranges
   // like WebMs with no cues.
--- a/dom/media/TextTrackList.cpp
+++ b/dom/media/TextTrackList.cpp
@@ -2,16 +2,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/. */
 
 #include "mozilla/dom/TextTrackList.h"
 #include "mozilla/dom/TextTrackListBinding.h"
 #include "mozilla/dom/TrackEvent.h"
 #include "nsThreadUtils.h"
+#include "nsGlobalWindow.h"
 #include "mozilla/dom/TextTrackCue.h"
 #include "mozilla/dom/TextTrackManager.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(TextTrackList,
                                    DOMEventTargetHelper,
@@ -169,24 +170,31 @@ TextTrackList::DispatchTrackEvent(nsIDOM
   return DispatchTrustedEvent(aEvent);
 }
 
 void
 TextTrackList::CreateAndDispatchChangeEvent()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!mPendingTextTrackChange) {
+    nsPIDOMWindowInner* win = GetOwner();
+    if (!win) {
+      return;
+    }
+
     mPendingTextTrackChange = true;
     RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
 
     event->InitEvent(NS_LITERAL_STRING("change"), false, false);
     event->SetTrusted(true);
 
     nsCOMPtr<nsIRunnable> eventRunner = new ChangeEventRunner(this, event);
-    NS_DispatchToMainThread(eventRunner);
+    nsGlobalWindow::Cast(win)->Dispatch(
+      "TextTrackList::CreateAndDispatchChangeEvent", TaskCategory::Other,
+      eventRunner.forget());
   }
 }
 
 void
 TextTrackList::CreateAndDispatchTrackEventRunner(TextTrack* aTrack,
                                                  const nsAString& aEventName)
 {
   nsCOMPtr<nsIThread> thread;
--- a/dom/media/gmp/GMPVideoEncoderParent.cpp
+++ b/dom/media/gmp/GMPVideoEncoderParent.cpp
@@ -11,16 +11,17 @@
 #include "GMPMessageUtils.h"
 #include "nsAutoRef.h"
 #include "GMPContentParent.h"
 #include "mozilla/gmp/GMPTypes.h"
 #include "nsThread.h"
 #include "nsThreadUtils.h"
 #include "runnable_utils.h"
 #include "GMPUtils.h"
+#include "mozilla/SystemGroup.h"
 
 namespace mozilla {
 
 #ifdef LOG
 #undef LOG
 #endif
 
 extern LogModule* GetGMPLog();
--- a/dom/media/gtest/TestBlankVideoDataCreator.cpp
+++ b/dom/media/gtest/TestBlankVideoDataCreator.cpp
@@ -5,23 +5,25 @@
 
 #include "gtest/gtest.h"
 #include "BlankDecoderModule.h"
 
 using namespace mozilla;
 
 TEST(BlankVideoDataCreator, ShouldNotOverflow)
 {
+  RefPtr<MediaRawData> mrd = new MediaRawData();
   const uint32_t width = 1;
   const uint32_t height = 1;
   BlankVideoDataCreator creater(width, height, nullptr);
-  RefPtr<MediaData> data = creater.Create(new MediaRawData());
+  RefPtr<MediaData> data = creater.Create(mrd);
   EXPECT_NE(data.get(), nullptr);
 }
 
 TEST(BlankVideoDataCreator, ShouldOverflow)
 {
+  RefPtr<MediaRawData> mrd = new MediaRawData();
   const uint32_t width = UINT_MAX;
   const uint32_t height = UINT_MAX;
   BlankVideoDataCreator creater(width, height, nullptr);
-  RefPtr<MediaData> data = creater.Create(new MediaRawData());
+  RefPtr<MediaData> data = creater.Create(mrd);
   EXPECT_EQ(data.get(), nullptr);
 }
--- a/dom/media/test/mochitest.ini
+++ b/dom/media/test/mochitest.ini
@@ -1144,16 +1144,22 @@ tags = suspend
 skip-if = toolkit == 'android' # bug 1346705
 tags = suspend
 [test_background_video_suspend.html]
 skip-if = toolkit == 'android' # android(bug 1304480)
 tags = suspend
 [test_background_video_suspend_ends.html]
 skip-if = toolkit == 'android' # bug 1295884, android(bug 1304480, bug 1232305)
 tags = suspend
+[test_background_video_tainted_by_capturestream.html]
+skip-if = toolkit == 'android' # bug 1346705
+tags = suspend
+[test_background_video_tainted_by_createimagebitmap.html]
+skip-if = toolkit == 'android' # bug 1346705
+tags = suspend
 [test_background_video_tainted_by_drawimage.html]
 skip-if = toolkit == 'android' # bug 1346705
 tags = suspend
 [test_background_video_drawimage_with_suspended_video.html]
 skip-if = toolkit == 'android' # bug 1346705
 tags = suspend
 
 [test_temporary_file_blob_video_plays.html]
new file mode 100644
--- /dev/null
+++ b/dom/media/test/test_background_video_tainted_by_capturestream.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test Background Video Is Tainted By captureStream</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="manifest.js"></script>
+<script src="background_video.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+<script type="text/javascript">
+"use strict";
+
+var manager = new MediaTestManager;
+
+function captureVideoAsStream(v) {
+  let stream = v.mozCaptureStream();
+}
+
+startTest({
+  desc: 'Test Background Video Is Tainted By captureStream',
+  prefs: [
+    [ "media.test.video-suspend", true ],
+    [ "media.suspend-bkgnd-video.enabled", true ],
+    [ "media.suspend-bkgnd-video.delay-ms", 1000 ]
+  ],
+  tests: gDecodeSuspendTests,
+  runTest: (test, token) => {
+    ok(true, `${test.name}`);
+    let v = appendVideoToDoc(test.name, token);
+    manager.started(token);
+
+    waitUntilPlaying(v)
+      .then(() => {
+        captureVideoAsStream(v);
+        ok(v.hasSuspendTaint(), "Video is tainted after captured");
+        return checkVideoDoesntSuspend(v);
+      })
+      .then(() => {
+        ok(true, 'Video ended before decode was suspended');
+        manager.finished(token);
+      })
+      .catch((e) => {
+        ok(false, 'Test failed: ' + e.toString());
+        manager.finished(token);
+      });
+  }
+});
+</script>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/media/test/test_background_video_tainted_by_createimagebitmap.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test Background Video Is Tainted By createImageBitmap</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="manifest.js"></script>
+<script src="background_video.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+<script type="text/javascript">
+"use strict";
+
+var manager = new MediaTestManager;
+
+startTest({
+  desc: 'Test Background Video Is Tainted By createImageBitmap',
+  prefs: [
+    [ "media.test.video-suspend", true ],
+    [ "media.suspend-bkgnd-video.enabled", true ],
+    [ "media.suspend-bkgnd-video.delay-ms", 1000 ]
+  ],
+  tests: gDecodeSuspendTests,
+  runTest: (test, token) => {
+    ok(true, `${test.name}`);
+    let v = appendVideoToDoc(test.name, token);
+    manager.started(token);
+
+    waitUntilPlaying(v)
+      .then(() => createImageBitmap(v))
+      .then(() => {
+        ok(v.hasSuspendTaint(), "Video is tainted after drawing to canvas");
+        return checkVideoDoesntSuspend(v);
+      })
+      .then(() => {
+        ok(true, 'Video ended before decode was suspended');
+        manager.finished(token);
+      })
+      .catch((e) => {
+        ok(false, 'Test failed: ' + e.toString());
+        manager.finished(token);
+      });
+  }
+});
+</script>
\ No newline at end of file
--- a/dom/media/test/test_load_same_resource.html
+++ b/dom/media/test/test_load_same_resource.html
@@ -78,15 +78,19 @@ function initTest(test, token) {
   ok(true, `Trying to load ${test.name}, duration=${test.duration}`);
   e.addEventListener("loadeddata", tryClone, {once: true});
   e.token = token;
   manager.started(token);
 }
 
 SimpleTest.waitForExplicitFinish();
 SpecialPowers.pushPrefEnv(
-  {"set": [["logging.MediaDecoder", "Debug"]]},
+  {"set": [
+    ["logging.MediaDecoder", "Debug"],
+    ["logging.nsMediaElement", "Debug"],
+    ["logging.MediaCache", "Debug"],
+  ]},
   manager.runTests.bind(manager, gCloneTests, initTest));
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -1221,23 +1221,19 @@ PluginModuleChromeParent::TakeFullMinidu
     }
 
     bool reportsReady = false;
 
     // Check to see if we already have a browser dump id - with e10s plugin
     // hangs we take this earlier (see ProcessHangMonitor) from a background
     // thread. We do this before we message the main thread about the hang
     // since the posted message will trash our browser stack state.
-    bool exists;
     nsCOMPtr<nsIFile> browserDumpFile;
-    if (!aBrowserDumpId.IsEmpty() &&
-        CrashReporter::GetMinidumpForID(aBrowserDumpId, getter_AddRefs(browserDumpFile)) &&
-        browserDumpFile &&
-        NS_SUCCEEDED(browserDumpFile->Exists(&exists)) && exists)
-    {
+    if (CrashReporter::GetMinidumpForID(aBrowserDumpId,
+                                        getter_AddRefs(browserDumpFile))) {
         // We have a single browser report, generate a new plugin process parent
         // report and pair it up with the browser report handed in.
         reportsReady = mCrashReporter->GenerateMinidumpAndPair(
           this,
           browserDumpFile,
           NS_LITERAL_CSTRING("browser"));
 
         if (!reportsReady) {
@@ -1259,18 +1255,17 @@ PluginModuleChromeParent::TakeFullMinidu
 
     if (reportsReady) {
         aDumpId = mCrashReporter->MinidumpID();
         PLUGIN_LOG_DEBUG(
                 ("generated paired browser/plugin minidumps: %s)",
                  NS_ConvertUTF16toUTF8(aDumpId).get()));
         nsAutoCString additionalDumps("browser");
         nsCOMPtr<nsIFile> pluginDumpFile;
-        if (GetMinidumpForID(aDumpId, getter_AddRefs(pluginDumpFile)) &&
-            pluginDumpFile) {
+        if (GetMinidumpForID(aDumpId, getter_AddRefs(pluginDumpFile))) {
 #ifdef MOZ_CRASHREPORTER_INJECTOR
             // If we have handles to the flash sandbox processes on Windows,
             // include those minidumps as well.
             if (CreatePluginMinidump(mFlashProcess1, 0, pluginDumpFile,
                                      NS_LITERAL_CSTRING("flash1"))) {
                 additionalDumps.AppendLiteral(",flash1");
             }
             if (CreatePluginMinidump(mFlashProcess2, 0, pluginDumpFile,
--- a/dom/svg/SVGSVGElement.cpp
+++ b/dom/svg/SVGSVGElement.cpp
@@ -22,17 +22,17 @@
 #include "nsIDocument.h"
 #include "mozilla/dom/SVGMatrix.h"
 #include "DOMSVGPoint.h"
 #include "nsIFrame.h"
 #include "nsFrameSelection.h"
 #include "nsISVGSVGFrame.h" //XXX
 #include "mozilla/dom/SVGRect.h"
 #include "nsError.h"
-#include "nsISVGChildFrame.h"
+#include "nsSVGDisplayableFrame.h"
 #include "mozilla/dom/SVGSVGElement.h"
 #include "mozilla/dom/SVGSVGElementBinding.h"
 #include "nsSVGUtils.h"
 #include "mozilla/dom/SVGViewElement.h"
 #include "nsStyleUtil.h"
 #include "SVGContentUtils.h"
 
 #include "nsSMILTimeContainer.h"
@@ -802,17 +802,17 @@ SVGSVGElement::WillBeOutermostSVG(nsICon
 
 void
 SVGSVGElement::InvalidateTransformNotifyFrame()
 {
   nsISVGSVGFrame* svgframe = do_QueryFrame(GetPrimaryFrame());
   // might fail this check if we've failed conditional processing
   if (svgframe) {
     svgframe->NotifyViewportOrTransformChanged(
-                nsISVGChildFrame::TRANSFORM_CHANGED);
+                nsSVGDisplayableFrame::TRANSFORM_CHANGED);
   }
 }
 
 bool
 SVGSVGElement::HasPreserveAspectRatio()
 {
   return HasAttr(kNameSpaceID_None, nsGkAtoms::preserveAspectRatio) ||
     mPreserveAspectRatio.IsAnimated();
--- a/dom/svg/SVGTransformableElement.cpp
+++ b/dom/svg/SVGTransformableElement.cpp
@@ -8,17 +8,17 @@
 #include "mozilla/dom/SVGAnimatedTransformList.h"
 #include "mozilla/dom/SVGGraphicsElementBinding.h"
 #include "mozilla/dom/SVGTransformableElement.h"
 #include "mozilla/dom/SVGMatrix.h"
 #include "mozilla/dom/SVGSVGElement.h"
 #include "nsContentUtils.h"
 #include "nsIDOMMutationEvent.h"
 #include "nsIFrame.h"
-#include "nsISVGChildFrame.h"
+#include "nsSVGDisplayableFrame.h"
 #include "mozilla/dom/SVGRect.h"
 #include "nsSVGUtils.h"
 #include "SVGContentUtils.h"
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace dom {
@@ -173,17 +173,17 @@ SVGTransformableElement::GetBBox(const S
                                  ErrorResult& rv)
 {
   nsIFrame* frame = GetPrimaryFrame(FlushType::Layout);
 
   if (!frame || (frame->GetStateBits() & NS_FRAME_IS_NONDISPLAY)) {
     rv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
-  nsISVGChildFrame* svgframe = do_QueryFrame(frame);
+  nsSVGDisplayableFrame* svgframe = do_QueryFrame(frame);
   if (!svgframe) {
     rv.Throw(NS_ERROR_NOT_IMPLEMENTED); // XXX: outer svg
     return nullptr;
   }
 
   if (!NS_SVGNewGetBBoxEnabled()) {
     return NS_NewSVGRect(this, ToRect(nsSVGUtils::GetBBox(frame)));
   } else {
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/fetch/file_fetch_controller.html
@@ -0,0 +1,161 @@
+<script>
+function ok(a, msg) {
+  parent.postMessage({ type: "check", status: !!a, message: msg }, "*");
+}
+
+function is(a, b, msg) {
+  ok(a === b, msg);
+}
+
+function testWebIDL() {
+  ok("FetchController" in self, "We have a FetchController prototype");
+  ok("FetchSignal" in self, "We have a FetchSignal prototype");
+
+  var fc = new FetchController();
+  ok(!!fc, "FetchController can be created");
+  ok(fc instanceof FetchController, "FetchController is a FetchController");
+
+  ok(!!fc.signal, "FetchController has a signal");
+  ok(fc.signal instanceof FetchSignal, "fetchSignal is a FetchSignal");
+  is(fc.signal.aborted, false, "By default FetchSignal.aborted is false");
+  next();
+}
+
+function testUpdateData() {
+  var fc = new FetchController();
+ 
+  is(fc.signal.aborted, false, "By default FetchSignal.aborted is false");
+ 
+  fc.abort();
+  is(fc.signal.aborted, true, "Signal is aborted");
+ 
+  next();
+}
+ 
+function testFollowingOurself() {
+  // Let's follow ourself
+  var fc = new FetchController();
+  fc.follow(fc.signal);
+ 
+  fc.abort();
+  is(fc.signal.aborted, true, "Signal is aborted");
+ 
+  next();
+}
+ 
+function testFollowingOther() {
+  // Let's follow another one
+  var fc1 = new FetchController();
+  var fc2 = new FetchController();
+  fc1.follow(fc2.signal);
+ 
+  fc2.abort();
+ 
+  is(fc1.signal.aborted, true, "Signal is aborted");
+  is(fc2.signal.aborted, true, "Signal is aborted");
+ 
+  next();
+}
+
+function testFollowingLoop() {
+  // fc1 -> fc2 -> fc3 -> fc1
+  var fc1 = new FetchController();
+  var fc2 = new FetchController();
+  var fc3 = new FetchController();
+  fc1.follow(fc2.signal);
+  fc2.follow(fc3.signal);
+  fc3.follow(fc1.signal);
+ 
+  fc3.abort();
+ 
+  is(fc1.signal.aborted, true, "Signal is aborted");
+  is(fc2.signal.aborted, true, "Signal is aborted");
+  is(fc3.signal.aborted, true, "Signal is aborted");
+ 
+  next();
+}
+ 
+function testAbortEvent() {
+  var fc = new FetchController();
+  fc.signal.onabort = function(e) {
+    is(e.type, "abort", "Abort received");
+    next();
+  }
+  fc.abort();
+}
+ 
+function testAbortedFetch() {
+  var fc = new FetchController();
+  fc.abort();
+
+  fetch('slow.sjs', { signal: fc.signal }).then(() => {
+    ok(false, "Fetch should not return a resolved promise");
+  }, e => {
+    is(e.name, "AbortError", "We have an abort error");
+  }).then(next);
+}
+
+function testFetchAndAbort() {
+  var fc = new FetchController();
+
+  var p = fetch('slow.sjs', { signal: fc.signal });
+  fc.abort();
+
+  p.then(() => {
+    ok(false, "Fetch should not return a resolved promise");
+  }, e => {
+    is(e.name, "AbortError", "We have an abort error");
+  }).then(next);
+}
+
+function testWorkerAbortedFetch() {
+  var w = new Worker('worker_fetch_controller.js');
+  w.onmessage = function(e) {
+    ok(e.data, "Abort + Fetch works in workers");
+    next();
+  }
+  w.postMessage('testWorkerAbortedFetch');
+}
+
+function testWorkerFetchAndAbort() {
+  var w = new Worker('worker_fetch_controller.js');
+  w.onmessage = function(e) {
+    ok(e.data, "Abort + Fetch works in workers");
+    next();
+  }
+  w.postMessage('testWorkerFetchAndAbort');
+}
+
+var steps = [
+  // Simple stuff
+  testWebIDL,
+  testUpdateData,
+
+  // Following algorithm
+  testFollowingOurself,
+  testFollowingOther,
+  testFollowingLoop,
+
+  // Event propagation
+  testAbortEvent,
+
+  // fetch + signaling
+  testAbortedFetch,
+  testFetchAndAbort,
+  testWorkerAbortedFetch,
+  testWorkerFetchAndAbort,
+];
+
+function next() {
+  if (!steps.length) {
+    parent.postMessage({ type: "finish" }, "*");
+    return;
+  }
+
+  var step = steps.shift();
+  step();
+}
+
+next();
+
+</script>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/fetch/file_fetch_observer.html
@@ -0,0 +1,146 @@
+<script>
+function ok(a, msg) {
+  parent.postMessage({ type: "check", status: !!a, message: msg }, "*");
+}
+
+function is(a, b, msg) {
+  ok(a === b, msg);
+}
+
+function testObserver() {
+  ok("FetchObserver" in self, "We have a FetchObserver prototype");
+
+  fetch('http://mochi.test:8888/tests/dom/tests/mochitest/fetch/slow.sjs', { observe: o => {
+    ok(!!o, "We have an observer");
+    ok(o instanceof FetchObserver, "The correct object has been passed");
+    is(o.state, "requesting", "By default the state is requesting");
+    next();
+  }});
+}
+
+function testObserveAbort() {
+  var fc = new FetchController();
+
+  fetch('http://mochi.test:8888/tests/dom/tests/mochitest/fetch/slow.sjs', {
+    signal: fc.signal,
+    observe: o => {
+      o.onstatechange = () => {
+        ok(true, "StateChange event dispatched");
+        if (o.state == "aborted") {
+          ok(true, "Aborted!");
+          next();
+        }
+      }
+      fc.abort();
+    }
+  });
+}
+
+function testObserveComplete() {
+  var fc = new FetchController();
+
+  fetch('http://mochi.test:8888/tests/dom/tests/mochitest/fetch/slow.sjs', {
+    signal: fc.signal,
+    observe: o => {
+      o.onstatechange = () => {
+        ok(true, "StateChange event dispatched");
+        if (o.state == "complete") {
+          ok(true, "Operation completed");
+          next();
+        }
+      }
+    }
+  });
+}
+
+function testObserveErrored() {
+  var fc = new FetchController();
+
+  fetch('foo: bar', {
+    signal: fc.signal,
+    observe: o => {
+      o.onstatechange = () => {
+        ok(true, "StateChange event dispatched");
+        if (o.state == "errored") {
+          ok(true, "Operation completed");
+          next();
+        }
+      }
+    }
+  });
+}
+
+function testObserveResponding() {
+  var fc = new FetchController();
+
+  fetch('http://mochi.test:8888/tests/dom/tests/mochitest/fetch/slow.sjs', {
+    signal: fc.signal,
+    observe: o => {
+      o.onstatechange = () => {
+        if (o.state == "responding") {
+          ok(true, "We have responding events");
+          next();
+        }
+      }
+    }
+  });
+}
+
+function workify(worker) {
+  function methods() {
+    function ok(a, msg) {
+      postMessage( { type: 'check', state: !!a, message: msg });
+    };
+    function is(a, b, msg) {
+      postMessage( { type: 'check', state: a === b, message: msg });
+    };
+    function next() {
+      postMessage( { type: 'finish' });
+    };
+  }
+
+  var str = methods.toString();
+  var methodsContent = str.substring(0, str.length - 1).split('\n').splice(1).join('\n');
+
+  str = worker.toString();
+  var workerContent = str.substring(0, str.length - 1).split('\n').splice(1).join('\n');
+
+  var content = methodsContent + workerContent;
+  var url = URL.createObjectURL(new Blob([content], { type: "application/javascript" }));
+  var w = new Worker(url);
+  w.onmessage = e => {
+    if (e.data.type == 'check') {
+      ok(e.data.state, "WORKER: " + e.data.message);
+    } else if (e.data.type == 'finish') {
+      next();
+    } else {
+      ok(false, "Something went wrong");
+    }
+  }
+}
+
+var steps = [
+  testObserver,
+  testObserveAbort,
+  function() { workify(testObserveAbort); },
+  testObserveComplete,
+  function() { workify(testObserveComplete); },
+  testObserveErrored,
+  function() { workify(testObserveErrored); },
+  testObserveResponding,
+  function() { workify(testObserveResponding); },
+];
+
+function next() {
+  if (!steps.length) {
+    parent.postMessage({ type: "finish" }, "*");
+    return;
+  }
+
+  var step = steps.shift();
+  step();
+}
+
+next();
+
+</script>
--- a/dom/tests/mochitest/fetch/mochitest.ini
+++ b/dom/tests/mochitest/fetch/mochitest.ini
@@ -1,32 +1,36 @@
 [DEFAULT]
 support-files =
   fetch_test_framework.js
+  file_fetch_controller.html
   file_fetch_csp_block_frame.html
   file_fetch_csp_block_frame.html^headers^
   test_fetch_basic.js
   test_fetch_basic_http.js
   test_fetch_cors.js
+  file_fetch_observer.html
   test_formdataparsing.js
   test_headers_common.js
   test_request.js
   test_response.js
   utils.js
   nested_worker_wrapper.js
   worker_wrapper.js
   message_receiver.html
   reroute.html
   reroute.js
   reroute.js^headers^
+  slow.sjs
   sw_reroute.js
   empty.js
   empty.js^headers^
   worker_temporaryFileBlob.js
   common_temporaryFileBlob.js
+  worker_fetch_controller.js
   !/dom/xhr/tests/file_XHR_binary1.bin
   !/dom/xhr/tests/file_XHR_binary1.bin^headers^
   !/dom/xhr/tests/file_XHR_binary2.bin
   !/dom/xhr/tests/file_XHR_pass1.xml
   !/dom/xhr/tests/file_XHR_pass2.txt
   !/dom/xhr/tests/file_XHR_pass3.txt
   !/dom/xhr/tests/file_XHR_pass3.txt^headers^
   !/dom/xhr/tests/responseIdentical.sjs
@@ -41,23 +45,25 @@ support-files =
 [test_headers_sw_reroute.html]
 [test_headers_mainthread.html]
 [test_fetch_basic.html]
 [test_fetch_basic_sw_reroute.html]
 [test_fetch_basic_sw_empty_reroute.html]
 [test_fetch_basic_http.html]
 [test_fetch_basic_http_sw_reroute.html]
 [test_fetch_basic_http_sw_empty_reroute.html]
+[test_fetch_controller.html]
 [test_fetch_cors.html]
 skip-if = toolkit == 'android' && debug # Bug 1210282
 [test_fetch_cors_sw_reroute.html]
 skip-if = toolkit == 'android' && debug # Bug 1210282
 [test_fetch_cors_sw_empty_reroute.html]
 skip-if = toolkit == 'android' && debug # Bug 1210282
 [test_fetch_csp_block.html]
+[test_fetch_observer.html]
 [test_fetch_user_control_rp.html]
 [test_formdataparsing.html]
 [test_formdataparsing_sw_reroute.html]
 [test_request.html]
 [test_request_context.html]
 [test_request_sw_reroute.html]
 [test_response.html]
 [test_response_sw_reroute.html]
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/fetch/slow.sjs
@@ -0,0 +1,11 @@
+function handleRequest(request, response)
+{
+  response.processAsync();
+
+  timer = Components.classes["@mozilla.org/timer;1"].
+          createInstance(Components.interfaces.nsITimer);
+  timer.init(function() {
+    response.write("Here the content. But slowly.");
+    response.finish();
+  }, 1000, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
+}
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/fetch/test_fetch_controller.html
@@ -0,0 +1,40 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test FetchController</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+
+SpecialPowers.pushPrefEnv({"set": [["dom.fetchController.enabled", true ]]}, () => {
+  let ifr = document.createElement('iframe');
+  ifr.src = "file_fetch_controller.html";
+  document.body.appendChild(ifr);
+
+  onmessage = function(e) {
+    if (e.data.type == "finish") {
+      SimpleTest.finish();
+      return;
+    }
+
+    if (e.data.type == "check") {
+      ok(e.data.status, e.data.message);
+      return;
+    }
+
+    ok(false, "Something when wrong.");
+  }
+});
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/fetch/test_fetch_observer.html
@@ -0,0 +1,41 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test FetchObserver</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+
+SpecialPowers.pushPrefEnv({"set": [["dom.fetchObserver.enabled", true ],
+                                   ["dom.fetchController.enabled", true ]]}, () => {
+  let ifr = document.createElement('iframe');
+  ifr.src = "file_fetch_observer.html";
+  document.body.appendChild(ifr);
+
+  onmessage = function(e) {
+    if (e.data.type == "finish") {
+      SimpleTest.finish();
+      return;
+    }
+
+    if (e.data.type == "check") {
+      ok(e.data.status, e.data.message);
+      return;
+    }
+
+    ok(false, "Something when wrong.");
+  }
+});
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/fetch/worker_fetch_controller.js
@@ -0,0 +1,27 @@
+function testWorkerAbortedFetch() {
+  var fc = new FetchController();
+  fc.abort();
+
+  fetch('slow.sjs', { signal: fc.signal }).then(() => {
+    postMessage(false);
+  }, e => {
+    postMessage(e.name == "AbortError");
+  });
+}
+
+function testWorkerFetchAndAbort() {
+  var fc = new FetchController();
+
+  var p = fetch('slow.sjs', { signal: fc.signal });
+  fc.abort();
+
+  p.then(() => {
+    postMessage(false);
+  }, e => {
+    postMessage(e.name == "AbortError");
+  });
+}
+
+onmessage = function(e) {
+  self[e.data]();
+}
new file mode 100644
--- /dev/null
+++ b/dom/webidl/FetchController.webidl
@@ -0,0 +1,15 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+[Constructor(), Exposed=(Window,Worker),
+ Func="FetchController::IsEnabled"]
+interface FetchController {
+  readonly attribute FetchSignal signal;
+
+  void abort();
+  void follow(FetchSignal signal);
+  void unfollow(FetchSignal signal);
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/FetchObserver.webidl
@@ -0,0 +1,27 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+callback interface ObserverCallback {
+  void handleEvent(FetchObserver observer);
+};
+
+enum FetchState {
+  // Pending states
+  "requesting", "responding",
+  // Final states
+  "aborted", "errored", "complete"
+};
+
+[Exposed=(Window,Worker),
+ Func="FetchObserver::IsEnabled"]
+interface FetchObserver : EventTarget {
+  readonly attribute FetchState state;
+
+  // Events
+  attribute EventHandler onstatechange;
+  attribute EventHandler onrequestprogress;
+  attribute EventHandler onresponseprogress;
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/FetchSignal.webidl
@@ -0,0 +1,13 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+[Exposed=(Window,Worker),
+ Func="FetchController::IsEnabled"]
+interface FetchSignal : EventTarget {
+  readonly attribute boolean aborted;
+
+  attribute EventHandler onabort;
+};
--- a/dom/webidl/Request.webidl
+++ b/dom/webidl/Request.webidl
@@ -42,16 +42,22 @@ dictionary RequestInit {
   BodyInit? body;
   USVString referrer;
   ReferrerPolicy referrerPolicy;
   RequestMode mode;
   RequestCredentials credentials;
   RequestCache cache;
   RequestRedirect redirect;
   DOMString integrity;
+
+  [Func="FetchController::IsEnabled"]
+  FetchSignal signal;
+
+  [Func="FetchObserver::IsEnabled"]
+  ObserverCallback observe;
 };
 
 // Gecko currently does not ship RequestContext, so please don't use it in IDL
 // that is exposed to script.
 enum RequestContext {
   "audio", "beacon", "cspreport", "download", "embed", "eventsource", "favicon", "fetch",
   "font", "form", "frame", "hyperlink", "iframe", "image", "imageset", "import",
   "internal", "location", "manifest", "object", "ping", "plugin", "prefetch", "script",
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -511,17 +511,20 @@ WEBIDL_FILES = [
     'EventHandler.webidl',
     'EventListener.webidl',
     'EventSource.webidl',
     'EventTarget.webidl',
     'ExtendableEvent.webidl',
     'ExtendableMessageEvent.webidl',
     'FakePluginTagInit.webidl',
     'Fetch.webidl',
+    'FetchController.webidl',
     'FetchEvent.webidl',
+    'FetchObserver.webidl',
+    'FetchSignal.webidl',
     'File.webidl',
     'FileList.webidl',
     'FileMode.webidl',
     'FileReader.webidl',
     'FileReaderSync.webidl',
     'FileSystem.webidl',
     'FileSystemDirectoryEntry.webidl',
     'FileSystemDirectoryReader.webidl',
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -2028,54 +2028,46 @@ RuntimeService::Init()
 
   if (NS_FAILED(obs->AddObserver(this, NS_IOSERVICE_OFFLINE_STATUS_TOPIC, false))) {
     NS_WARNING("Failed to register for offline notification event!");
   }
 
   MOZ_ASSERT(!gRuntimeServiceDuringInit, "This should be false!");
   gRuntimeServiceDuringInit = true;
 
-  if (NS_FAILED(Preferences::RegisterCallback(
+  if (NS_FAILED(Preferences::RegisterPrefixCallback(
                                  LoadJSGCMemoryOptions,
-                                 PREF_JS_OPTIONS_PREFIX PREF_MEM_OPTIONS_PREFIX,
-                                 nullptr)) ||
-      NS_FAILED(Preferences::RegisterCallbackAndCall(
+                                 PREF_JS_OPTIONS_PREFIX PREF_MEM_OPTIONS_PREFIX)) ||
+      NS_FAILED(Preferences::RegisterPrefixCallbackAndCall(
                             LoadJSGCMemoryOptions,
-                            PREF_WORKERS_OPTIONS_PREFIX PREF_MEM_OPTIONS_PREFIX,
-                            nullptr)) ||
+                            PREF_WORKERS_OPTIONS_PREFIX PREF_MEM_OPTIONS_PREFIX)) ||
 #ifdef JS_GC_ZEAL
       NS_FAILED(Preferences::RegisterCallback(
                                              LoadGCZealOptions,
-                                             PREF_JS_OPTIONS_PREFIX PREF_GCZEAL,
-                                             nullptr)) ||
+                                             PREF_JS_OPTIONS_PREFIX PREF_GCZEAL)) ||
 #endif
 
 #define WORKER_SIMPLE_PREF(name, getter, NAME)                                \
       NS_FAILED(Preferences::RegisterCallbackAndCall(                         \
                   WorkerPrefChanged,                                          \
                   name,                                                       \
-                  reinterpret_cast<void*>(WORKERPREF_##NAME),                 \
-                  Preferences::ExactMatch)) ||
+                  reinterpret_cast<void*>(WORKERPREF_##NAME))) ||
 #define WORKER_PREF(name, callback)                                           \
       NS_FAILED(Preferences::RegisterCallbackAndCall(                         \
                   callback,                                                   \
-                  name,                                                       \
-                  nullptr,                                                    \
-                  Preferences::ExactMatch)) ||
+                  name)) ||
 #include "WorkerPrefs.h"
 #undef WORKER_SIMPLE_PREF
 #undef WORKER_PREF
 
-      NS_FAILED(Preferences::RegisterCallbackAndCall(
+      NS_FAILED(Preferences::RegisterPrefixCallbackAndCall(
                                                    LoadContextOptions,
-                                                   PREF_WORKERS_OPTIONS_PREFIX,
-                                                   nullptr)) ||
-      NS_FAILED(Preferences::RegisterCallback(LoadContextOptions,
-                                              PREF_JS_OPTIONS_PREFIX,
-                                              nullptr))) {
+                                                   PREF_WORKERS_OPTIONS_PREFIX)) ||
+      NS_FAILED(Preferences::RegisterPrefixCallback(LoadContextOptions,
+                                                    PREF_JS_OPTIONS_PREFIX))) {
     NS_WARNING("Failed to register pref callbacks!");
   }
 
   MOZ_ASSERT(gRuntimeServiceDuringInit, "Should be true!");
   gRuntimeServiceDuringInit = false;
 
   // We assume atomic 32bit reads/writes. If this assumption doesn't hold on
   // some wacky platform then the worst that could happen is that the close
@@ -2211,51 +2203,45 @@ RuntimeService::Cleanup()
         }
       }
     }
   }
 
   NS_ASSERTION(!mWindowMap.Count(), "All windows should have been released!");
 
   if (mObserved) {
-    if (NS_FAILED(Preferences::UnregisterCallback(LoadContextOptions,
-                                                  PREF_JS_OPTIONS_PREFIX,
-                                                  nullptr)) ||
-        NS_FAILED(Preferences::UnregisterCallback(LoadContextOptions,
-                                                  PREF_WORKERS_OPTIONS_PREFIX,
-                                                  nullptr)) ||
+    if (NS_FAILED(Preferences::UnregisterPrefixCallback(LoadContextOptions,
+                                                        PREF_JS_OPTIONS_PREFIX)) ||
+        NS_FAILED(Preferences::UnregisterPrefixCallback(LoadContextOptions,
+                                                        PREF_WORKERS_OPTIONS_PREFIX)) ||
 
 #define WORKER_SIMPLE_PREF(name, getter, NAME)                                \
       NS_FAILED(Preferences::UnregisterCallback(                              \
                   WorkerPrefChanged,                                          \
                   name,                                                       \
                   reinterpret_cast<void*>(WORKERPREF_##NAME))) ||
 #define WORKER_PREF(name, callback)                                           \
       NS_FAILED(Preferences::UnregisterCallback(                              \
                   callback,                                                   \
-                  name,                                                       \
-                  nullptr)) ||
+                  name)) ||
 #include "WorkerPrefs.h"
 #undef WORKER_SIMPLE_PREF
 #undef WORKER_PREF
 
 #ifdef JS_GC_ZEAL
         NS_FAILED(Preferences::UnregisterCallback(
                                              LoadGCZealOptions,
-                                             PREF_JS_OPTIONS_PREFIX PREF_GCZEAL,
-                                             nullptr)) ||
+                                             PREF_JS_OPTIONS_PREFIX PREF_GCZEAL)) ||
 #endif
-        NS_FAILED(Preferences::UnregisterCallback(
+        NS_FAILED(Preferences::UnregisterPrefixCallback(
                                  LoadJSGCMemoryOptions,
-                                 PREF_JS_OPTIONS_PREFIX PREF_MEM_OPTIONS_PREFIX,
-                                 nullptr)) ||
-        NS_FAILED(Preferences::UnregisterCallback(
+                                 PREF_JS_OPTIONS_PREFIX PREF_MEM_OPTIONS_PREFIX)) ||
+        NS_FAILED(Preferences::UnregisterPrefixCallback(
                             LoadJSGCMemoryOptions,
-                            PREF_WORKERS_OPTIONS_PREFIX PREF_MEM_OPTIONS_PREFIX,
-                            nullptr))) {
+                            PREF_WORKERS_OPTIONS_PREFIX PREF_MEM_OPTIONS_PREFIX))) {
       NS_WARNING("Failed to unregister pref callbacks!");
     }
 
     if (obs) {
       if (NS_FAILED(obs->RemoveObserver(this, GC_REQUEST_OBSERVER_TOPIC))) {
         NS_WARNING("Failed to unregister for GC request notifications!");
       }
 
--- a/dom/workers/WorkerPrefs.h
+++ b/dom/workers/WorkerPrefs.h
@@ -35,15 +35,17 @@ WORKER_SIMPLE_PREF("dom.serviceWorkers.e
 WORKER_SIMPLE_PREF("dom.serviceWorkers.testing.enabled", ServiceWorkersTestingEnabled, SERVICEWORKERS_TESTING_ENABLED)
 WORKER_SIMPLE_PREF("dom.serviceWorkers.openWindow.enabled", OpenWindowEnabled, OPEN_WINDOW_ENABLED)
 WORKER_SIMPLE_PREF("dom.storageManager.enabled", StorageManagerEnabled, STORAGEMANAGER_ENABLED)
 WORKER_SIMPLE_PREF("dom.push.enabled", PushEnabled, PUSH_ENABLED)
 WORKER_SIMPLE_PREF("dom.requestcontext.enabled", RequestContextEnabled, REQUESTCONTEXT_ENABLED)
 WORKER_SIMPLE_PREF("gfx.offscreencanvas.enabled", OffscreenCanvasEnabled, OFFSCREENCANVAS_ENABLED)
 WORKER_SIMPLE_PREF("dom.webkitBlink.dirPicker.enabled", WebkitBlinkDirectoryPickerEnabled, DOM_WEBKITBLINK_DIRPICKER_WEBKITBLINK)
 WORKER_SIMPLE_PREF("dom.netinfo.enabled", NetworkInformationEnabled, NETWORKINFORMATION_ENABLED)
+WORKER_SIMPLE_PREF("dom.fetchController.enabled", FetchControllerEnabled, FETCHCONTROLLER_ENABLED)
+WORKER_SIMPLE_PREF("dom.fetchObserver.enabled", FetchObserverEnabled, FETCHOBSERVER_ENABLED)
 WORKER_PREF("intl.accept_languages", PrefLanguagesChanged)
 WORKER_PREF("general.appname.override", AppNameOverrideChanged)
 WORKER_PREF("general.appversion.override", AppVersionOverrideChanged)
 WORKER_PREF("general.platform.override", PlatformOverrideChanged)
 #ifdef JS_GC_ZEAL
 WORKER_PREF("dom.workers.options.gcZeal", LoadGCZealOptions)
 #endif
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -783,26 +783,16 @@ EditorBase::GetTransactionManager(nsITra
   *aTxnManager = nullptr;
   NS_ENSURE_TRUE(mTxnMgr, NS_ERROR_FAILURE);
 
   NS_ADDREF(*aTxnManager = mTxnMgr);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-EditorBase::SetTransactionManager(nsITransactionManager* aTxnManager)
-{
-  NS_ENSURE_TRUE(aTxnManager, NS_ERROR_FAILURE);
-
-  // nsITransactionManager is builtinclass, so this is safe
-  mTxnMgr = static_cast<nsTransactionManager*>(aTxnManager);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 EditorBase::Undo(uint32_t aCount)
 {
   ForceCompositionEnd();
 
   bool hasTxnMgr, hasTransaction = false;
   CanUndo(&hasTxnMgr, &hasTransaction);
   NS_ENSURE_TRUE(hasTransaction, NS_OK);
 
--- a/editor/libeditor/TextEditor.cpp
+++ b/editor/libeditor/TextEditor.cpp
@@ -181,22 +181,20 @@ EditorPrefsChangedCallback(const char* a
 }
 
 // static
 void
 TextEditor::GetDefaultEditorPrefs(int32_t& aNewlineHandling,
                                   int32_t& aCaretStyle)
 {
   if (sNewlineHandlingPref == -1) {
-    Preferences::RegisterCallback(EditorPrefsChangedCallback,
-                                  "editor.singleLine.pasteNewlines");
-    EditorPrefsChangedCallback("editor.singleLine.pasteNewlines", nullptr);
-    Preferences::RegisterCallback(EditorPrefsChangedCallback,
-                                  "layout.selection.caret_style");
-    EditorPrefsChangedCallback("layout.selection.caret_style", nullptr);
+    Preferences::RegisterCallbackAndCall(EditorPrefsChangedCallback,
+                                         "editor.singleLine.pasteNewlines");
+    Preferences::RegisterCallbackAndCall(EditorPrefsChangedCallback,
+                                         "layout.selection.caret_style");
   }
 
   aNewlineHandling = sNewlineHandlingPref;
   aCaretStyle = sCaretStylePref;
 }
 
 void
 TextEditor::BeginEditorInit()
--- a/editor/nsIEditor.idl
+++ b/editor/nsIEditor.idl
@@ -167,17 +167,17 @@ interface nsIEditor  : nsISupports
     *                    to increase or decrease the count
     */
   void incrementModificationCount(in long aModCount);
 
   /* ------------ Transaction methods -------------- */
 
   /** transactionManager Get the transaction manager the editor is using.
     */
-  attribute nsITransactionManager transactionManager;
+  readonly attribute nsITransactionManager transactionManager;
 
   /** doTransaction() fires a transaction.
     * It is provided here so clients can create their own transactions.
     * If a transaction manager is present, it is used.
     * Otherwise, the transaction is just executed directly.
     *
     * @param aTxn the transaction to execute
     */
--- a/gfx/layers/Compositor.cpp
+++ b/gfx/layers/Compositor.cpp
@@ -43,72 +43,28 @@ Compositor::Compositor(widget::Composito
 Compositor::~Compositor()
 {
   ReadUnlockTextures();
 }
 
 void
 Compositor::Destroy()
 {
-  ReadUnlockTextures();
+  TextureSourceProvider::Destroy();
   FlushPendingNotifyNotUsed();
   mIsDestroyed = true;
 }
 
 void
 Compositor::EndFrame()
 {
   ReadUnlockTextures();
   mLastCompositionEndTime = TimeStamp::Now();
 }
 
-void
-Compositor::ReadUnlockTextures()
-{
-  for (auto& texture : mUnlockAfterComposition) {
-    texture->ReadUnlock();
-  }
-  mUnlockAfterComposition.Clear();
-}
-
-void
-Compositor::UnlockAfterComposition(TextureHost* aTexture)
-{
-  mUnlockAfterComposition.AppendElement(aTexture);
-}
-
-void
-Compositor::NotifyNotUsedAfterComposition(TextureHost* aTextureHost)
-{
-  MOZ_ASSERT(!mIsDestroyed);
-
-  mNotifyNotUsedAfterComposition.AppendElement(aTextureHost);
-
-  // If Compositor holds many TextureHosts without compositing,
-  // the TextureHosts should be flushed to reduce memory consumption.
-  const int thresholdCount = 5;
-  const double thresholdSec = 2.0f;
-  if (mNotifyNotUsedAfterComposition.Length() > thresholdCount) {
-    TimeDuration duration = mLastCompositionEndTime ? TimeStamp::Now() - mLastCompositionEndTime : TimeDuration();
-    // Check if we could flush
-    if (duration.ToSeconds() > thresholdSec) {
-      FlushPendingNotifyNotUsed();
-    }
-  }
-}
-
-void
-Compositor::FlushPendingNotifyNotUsed()
-{
-  for (auto& textureHost : mNotifyNotUsedAfterComposition) {
-    textureHost->CallNotifyNotUsed();
-  }
-  mNotifyNotUsedAfterComposition.Clear();
-}
-
 /* static */ void
 Compositor::AssertOnCompositorThread()
 {
   MOZ_ASSERT(!CompositorThreadHolder::Loop() ||
              CompositorThreadHolder::Loop() == MessageLoop::current(),
              "Can only call this from the compositor thread!");
 }
 
@@ -669,10 +625,19 @@ Compositor::IsValid() const
   return !!mParent;
 }
 
 void
 Compositor::SetDispAcquireFence(Layer* aLayer)
 {
 }
 
+bool
+Compositor::NotifyNotUsedAfterComposition(TextureHost* aTextureHost)
+{
+  if (IsDestroyed() || AsBasicCompositor()) {
+    return false;
+  }
+  return TextureSourceProvider::NotifyNotUsedAfterComposition(aTextureHost);
+}
+
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -13,16 +13,17 @@
 #include "mozilla/gfx/MatrixFwd.h"      // for Matrix4x4
 #include "mozilla/gfx/Point.h"          // for IntSize, Point
 #include "mozilla/gfx/Polygon.h"        // for Polygon
 #include "mozilla/gfx/Rect.h"           // for Rect, IntRect
 #include "mozilla/gfx/Types.h"          // for Float
 #include "mozilla/gfx/Triangle.h"       // for Triangle, TexturedTriangle
 #include "mozilla/layers/CompositorTypes.h"  // for DiagnosticTypes, etc
 #include "mozilla/layers/LayersTypes.h"  // for LayersBackend
+#include "mozilla/layers/TextureSourceProvider.h"
 #include "mozilla/widget/CompositorWidget.h"
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsRegion.h"
 #include <vector>
 #include "mozilla/WidgetUtils.h"
 
 /**
  * Different elements of a web pages are rendered into separate "layers" before
@@ -127,17 +128,16 @@ class Layer;
 class TextureSource;
 class DataTextureSource;
 class CompositingRenderTarget;
 class CompositorBridgeParent;
 class LayerManagerComposite;
 class CompositorOGL;
 class CompositorD3D11;
 class BasicCompositor;
-class TextureHost;
 class TextureReadLock;
 
 enum SurfaceInitMode
 {
   INIT_MODE_NONE,
   INIT_MODE_CLEAR
 };
 
@@ -174,62 +174,42 @@ enum SurfaceInitMode
  *
  * By default, the compositor will render to the screen, to render to a target,
  * call SetTargetContext or SetRenderTarget, the latter with a target created
  * by CreateRenderTarget or CreateRenderTargetFromSource.
  *
  * The target and viewport methods can be called before any DrawQuad call and
  * affect any subsequent DrawQuad calls.
  */
-class Compositor
+class Compositor : public TextureSourceProvider
 {
 protected:
   virtual ~Compositor();
 
 public:
-  NS_INLINE_DECL_REFCOUNTING(Compositor)
-
   explicit Compositor(widget::CompositorWidget* aWidget,
                       CompositorBridgeParent* aParent = nullptr);
 
-  virtual already_AddRefed<DataTextureSource> CreateDataTextureSource(TextureFlags aFlags = TextureFlags::NO_FLAGS) = 0;
-
-  virtual already_AddRefed<DataTextureSource>
-  CreateDataTextureSourceAround(gfx::DataSourceSurface* aSurface) { return nullptr; }
-
-  virtual already_AddRefed<DataTextureSource>
-  CreateDataTextureSourceAroundYCbCr(TextureHost* aTexture) { return nullptr; }
-
   virtual bool Initialize(nsCString* const out_failureReason) = 0;
-  virtual void Destroy();
+  virtual void Destroy() override;
   bool IsDestroyed() const { return mIsDestroyed; }
 
   virtual void DetachWidget() { mWidget = nullptr; }
 
   /**
-   * Return true if the effect type is supported.
-   *
-   * By default Compositor implementations should support all effects but in
-   * some rare cases it is not possible to support an effect efficiently.
-   * This is the case for BasicCompositor with EffectYCbCr.
-   */
-  virtual bool SupportsEffect(EffectTypes aEffect) { return true; }
-
-  /**
    * Request a texture host identifier that may be used for creating textures
    * across process or thread boundaries that are compatible with this
    * compositor.
    */
   virtual TextureFactoryIdentifier GetTextureFactoryIdentifier() = 0;
 
   /**
    * Properties of the compositor.
    */
   virtual bool CanUseCanvasLayerForSize(const gfx::IntSize& aSize) = 0;
-  virtual int32_t GetMaxTextureSize() const = 0;
 
   /**
    * Set the target for rendering. Results will have been written to aTarget by
    * the time that EndFrame returns.
    *
    * If this method is not used, or we pass in nullptr, we target the compositor's
    * usual swap chain and render to the screen.
    */
@@ -467,16 +447,26 @@ public:
 #endif // MOZ_DUMP_PAINTING
 
   virtual LayersBackend GetBackendType() const = 0;
 
   virtual CompositorOGL* AsCompositorOGL() { return nullptr; }
   virtual CompositorD3D11* AsCompositorD3D11() { return nullptr; }
   virtual BasicCompositor* AsBasicCompositor() { return nullptr; }
 
+  virtual Compositor* AsCompositor() override {
+    return this;
+  }
+
+  TimeStamp GetLastCompositionEndTime() const override {
+    return mLastCompositionEndTime;
+  }
+
+  bool NotifyNotUsedAfterComposition(TextureHost* aTextureHost) override;
+
   /**
    * Each Compositor has a unique ID.
    * This ID is used to keep references to each Compositor in a map accessed
    * from the compositor thread only, so that async compositables can find
    * the right compositor parent and schedule compositing even if the compositor
    * changed.
    */
   uint32_t GetCompositorID() const
@@ -538,51 +528,30 @@ public:
   }
   void SetScreenRotation(ScreenRotation aRotation) {
     mScreenRotation = aRotation;
   }
 
   // A stale Compositor has no CompositorBridgeParent; it will not process
   // frames and should not be used.
   void SetInvalid();
-  virtual bool IsValid() const;
+  virtual bool IsValid() const override;
   CompositorBridgeParent* GetCompositorBridgeParent() const {
     return mParent;
   }
 
-  /// Most compositor backends operate asynchronously under the hood. This
-  /// means that when a layer stops using a texture it is often desirable to
-  /// wait for the end of the next composition before releasing the texture's
-  /// ReadLock.
-  /// This function provides a convenient way to do this delayed unlocking, if
-  /// the texture itself requires it.
-  void UnlockAfterComposition(TextureHost* aTexture);
-
-  /// Most compositor backends operate asynchronously under the hood. This
-  /// means that when a layer stops using a texture it is often desirable to
-  /// wait for the end of the next composition before NotifyNotUsed() call.
-  /// This function provides a convenient way to do this delayed NotifyNotUsed()
-  /// call, if the texture itself requires it.
-  /// See bug 1260611 and bug 1252835
-  void NotifyNotUsedAfterComposition(TextureHost* aTextureHost);
-
-  void FlushPendingNotifyNotUsed();
-
 protected:
   void DrawDiagnosticsInternal(DiagnosticFlags aFlags,
                                const gfx::Rect& aVisibleRect,
                                const gfx::IntRect& aClipRect,
                                const gfx::Matrix4x4& transform,
                                uint32_t aFlashCounter);
 
   bool ShouldDrawDiagnostics(DiagnosticFlags);
 
-  // Should be called at the end of each composition.
-  void ReadUnlockTextures();
-
   /**
    * Given a layer rect, clip, and transform, compute the area of the backdrop that
    * needs to be copied for mix-blending. The output transform translates from 0..1
    * space into the backdrop rect space.
    *
    * The transformed layer quad is also optionally returned - this is the same as
    * the result rect, before rounding.
    */
@@ -610,26 +579,16 @@ protected:
                            const gfx::Rect& aRect,
                            const gfx::IntRect& aClipRect,
                            const EffectChain& aEffectChain,
                            gfx::Float aOpacity,
                            const gfx::Matrix4x4& aTransform,
                            const gfx::Rect& aVisibleRect);
 
   /**
-   * An array of locks that will need to be unlocked after the next composition.
-   */
-  nsTArray<RefPtr<TextureHost>> mUnlockAfterComposition;
-
-  /**
-   * An array of TextureHosts that will need to call NotifyNotUsed() after the next composition.
-   */
-  nsTArray<RefPtr<TextureHost>> mNotifyNotUsedAfterComposition;
-
-  /**
    * Last Composition end time.
    */
   TimeStamp mLastCompositionEndTime;
 
   uint32_t mCompositorID;
   DiagnosticTypes mDiagnosticTypes;
   CompositorBridgeParent* mParent;
 
--- a/gfx/layers/LayerScope.cpp
+++ b/gfx/layers/LayerScope.cpp
@@ -913,17 +913,18 @@ SenderHelper::SendLayer(LayerComposite* 
             LayerScope::DrawEnd(nullptr, effect, aWidth, aHeight);
             break;
         }
         case Layer::TYPE_IMAGE:
         case Layer::TYPE_CANVAS:
         case Layer::TYPE_PAINTED: {
             // Get CompositableHost and Compositor
             CompositableHost* compHost = aLayer->GetCompositableHost();
-            Compositor* comp = compHost->GetCompositor();
+            TextureSourceProvider* provider = compHost->GetTextureSourceProvider();
+            Compositor* comp = provider->AsCompositor();
             // Send EffectChain only for CompositorOGL
             if (LayersBackend::LAYERS_OPENGL == comp->GetBackendType()) {
                 CompositorOGL* compOGL = comp->AsCompositorOGL();
                 EffectChain effect;
                 // Generate primary effect (lock and gen)
                 AutoLockCompositableHost lock(compHost);
                 aLayer->GenEffectChain(effect);
 
--- a/gfx/layers/TextureDIB.cpp
+++ b/gfx/layers/TextureDIB.cpp
@@ -374,19 +374,19 @@ TextureHostDirectUpload::Lock()
 void
 TextureHostDirectUpload::Unlock()
 {
   MOZ_ASSERT(mIsLocked);
   mIsLocked = false;
 }
 
 void
-TextureHostDirectUpload::SetCompositor(Compositor* aCompositor)
+TextureHostDirectUpload::SetTextureSourceProvider(TextureSourceProvider* aProvider)
 {
-  mCompositor = aCompositor;
+  mProvider = aProvider;
 }
 
 void
 TextureHostDirectUpload::DeallocateDeviceData()
 {
   if (mTextureSource) {
     mTextureSource->DeallocateDeviceData();
   }
@@ -414,24 +414,24 @@ DIBTextureHost::DIBTextureHost(TextureFl
 
   mSize = mSurface->GetSize();
   mFormat = mSurface->GetSurfaceFormat();
 }
 
 void
 DIBTextureHost::UpdatedInternal(const nsIntRegion* aRegion)
 {
-  if (!mCompositor) {
+  if (!mProvider) {
     // This can happen if we send textures to a compositable that isn't yet
     // attached to a layer.
     return;
   }
 
   if (!mTextureSource) {
-    mTextureSource = mCompositor->CreateDataTextureSource(mFlags);
+    mTextureSource = mProvider->CreateDataTextureSource(mFlags);
   }
 
   if (mSurface->CairoStatus()) {
       gfxWarning() << "Bad Cairo surface internal update " << mSurface->CairoStatus();
       mTextureSource = nullptr;
       return;
   }
   RefPtr<gfxImageSurface> imgSurf = mSurface->GetAsImageSurface();
@@ -463,24 +463,24 @@ static void UnmapFileData(void* aData)
 {
   MOZ_ASSERT(aData);
   ::UnmapViewOfFile(aData);
 }
 
 void
 TextureHostFileMapping::UpdatedInternal(const nsIntRegion* aRegion)
 {
-  if (!mCompositor) {
+  if (!mProvider) {
     // This can happen if we send textures to a compositable that isn't yet
     // attached to a layer.
     return;
   }
 
   if (!mTextureSource) {
-    mTextureSource = mCompositor->CreateDataTextureSource(mFlags);
+    mTextureSource = mProvider->CreateDataTextureSource(mFlags);
   }
 
   uint8_t* data = nullptr;
   int32_t totalBytes = BufferSizeFromDimensions(mSize.width, mSize.height, BytesPerPixel(mFormat));
   if (totalBytes > 0) {
     data = (uint8_t*)::MapViewOfFile(mFileMapping, FILE_MAP_READ, 0, 0, totalBytes);
   }
 
--- a/gfx/layers/TextureDIB.h
+++ b/gfx/layers/TextureDIB.h
@@ -59,35 +59,33 @@ public:
     : TextureHost(aFlags)
     , mFormat(aFormat)
     , mSize(aSize)
     , mIsLocked(false)
   { }
 
   virtual void DeallocateDeviceData() override;
 
-  virtual void SetCompositor(Compositor* aCompositor) override;
-
-  virtual Compositor* GetCompositor() override { return mCompositor; }
+  virtual void SetTextureSourceProvider(TextureSourceProvider* aProvider) override;
 
   virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; }
 
   virtual gfx::IntSize GetSize() const override { return mSize; }
 
   virtual bool Lock() override;
 
   virtual void Unlock() override;
 
   virtual bool HasIntermediateBuffer() const { return true; }
 
   virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override;
 
 protected:
+  RefPtr<TextureSourceProvider> mProvider;
   RefPtr<DataTextureSource> mTextureSource;
-  RefPtr<Compositor> mCompositor;
   gfx::SurfaceFormat mFormat;
   gfx::IntSize mSize;
   bool mIsLocked;
 };
 
 class DIBTextureHost : public TextureHostDirectUpload
 {
 public:
new file mode 100644
--- /dev/null
+++ b/gfx/layers/TextureSourceProvider.cpp
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.0. If a copy of the MPL was not distributed with this
+* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/layers/TextureSourceProvider.h"
+#include "mozilla/layers/TextureHost.h"
+
+namespace mozilla {
+namespace layers {
+
+TextureSourceProvider::~TextureSourceProvider()
+{
+  ReadUnlockTextures();
+}
+
+void
+TextureSourceProvider::ReadUnlockTextures()
+{
+  for (auto& texture : mUnlockAfterComposition) {
+    texture->ReadUnlock();
+  }
+  mUnlockAfterComposition.Clear();
+}
+
+void
+TextureSourceProvider::UnlockAfterComposition(TextureHost* aTexture)
+{
+  mUnlockAfterComposition.AppendElement(aTexture);
+}
+
+bool
+TextureSourceProvider::NotifyNotUsedAfterComposition(TextureHost* aTextureHost)
+{
+  mNotifyNotUsedAfterComposition.AppendElement(aTextureHost);
+
+  // If Compositor holds many TextureHosts without compositing,
+  // the TextureHosts should be flushed to reduce memory consumption.
+  const int thresholdCount = 5;
+  const double thresholdSec = 2.0f;
+  if (mNotifyNotUsedAfterComposition.Length() > thresholdCount) {
+    TimeStamp lastCompositionEndTime = GetLastCompositionEndTime();
+    TimeDuration duration = lastCompositionEndTime ? TimeStamp::Now() - lastCompositionEndTime : TimeDuration();
+    // Check if we could flush
+    if (duration.ToSeconds() > thresholdSec) {
+      FlushPendingNotifyNotUsed();
+    }
+  }
+  return true;
+}
+
+void
+TextureSourceProvider::FlushPendingNotifyNotUsed()
+{
+  for (auto& textureHost : mNotifyNotUsedAfterComposition) {
+    textureHost->CallNotifyNotUsed();
+  }
+  mNotifyNotUsedAfterComposition.Clear();
+}
+
+void
+TextureSourceProvider::Destroy()
+{
+  ReadUnlockTextures();
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/TextureSourceProvider.h
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.0. If a copy of the MPL was not distributed with this
+* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#ifndef mozilla_gfx_layers_TextureSourceProvider_h
+#define mozilla_gfx_layers_TextureSourceProvider_h
+
+#include "nsISupportsImpl.h"
+#include "mozilla/AlreadyAddRefed.h"
+#include "mozilla/TimeStamp.h"
+#include "mozilla/layers/CompositorTypes.h"
+#include "nsTArray.h"
+
+struct ID3D11Device;
+
+namespace mozilla {
+namespace gfx {
+class DataSourceSurface;
+} // namespace gfx
+namespace gl {
+class GLContext;
+} // namespace gl
+namespace layers {
+
+class TextureHost;
+class DataTextureSource;
+class Compositor;
+
+// Provided by a HostLayerManager or Compositor for allocating backend-specific
+// texture types.
+class TextureSourceProvider
+{
+public:
+  NS_INLINE_DECL_REFCOUNTING(TextureSourceProvider)
+
+  virtual already_AddRefed<DataTextureSource>
+  CreateDataTextureSource(TextureFlags aFlags = TextureFlags::NO_FLAGS) = 0;
+
+  virtual already_AddRefed<DataTextureSource>
+  CreateDataTextureSourceAround(gfx::DataSourceSurface* aSurface) {
+    return nullptr;
+  }
+
+  virtual already_AddRefed<DataTextureSource>
+  CreateDataTextureSourceAroundYCbCr(TextureHost* aTexture) {
+    return nullptr;
+  }
+
+  virtual TimeStamp GetLastCompositionEndTime() const = 0;
+
+  // Return true if the effect type is supported.
+  //
+  // By default Compositor implementations should support all effects but in
+  // some rare cases it is not possible to support an effect efficiently.
+  // This is the case for BasicCompositor with EffectYCbCr.
+  virtual bool SupportsEffect(EffectTypes aEffect) { return true; }
+
+  /// Most compositor backends operate asynchronously under the hood. This
+  /// means that when a layer stops using a texture it is often desirable to
+  /// wait for the end of the next composition before releasing the texture's
+  /// ReadLock.
+  /// This function provides a convenient way to do this delayed unlocking, if
+  /// the texture itself requires it.
+  void UnlockAfterComposition(TextureHost* aTexture);
+
+  /// Most compositor backends operate asynchronously under the hood. This
+  /// means that when a layer stops using a texture it is often desirable to
+  /// wait for the end of the next composition before NotifyNotUsed() call.
+  /// This function provides a convenient way to do this delayed NotifyNotUsed()
+  /// call, if the texture itself requires it.
+  /// See bug 1260611 and bug 1252835
+  ///
+  /// Returns true if notified, false otherwise.
+  virtual bool NotifyNotUsedAfterComposition(TextureHost* aTextureHost);
+
+  // If overridden, make sure to call the base function.
+  virtual void Destroy();
+
+  void FlushPendingNotifyNotUsed();
+
+  // If this provider is also a Compositor, return the compositor. Otherwise return
+  // null.
+  virtual Compositor* AsCompositor() {
+    return nullptr;
+  }
+
+#ifdef XP_WIN
+  // On Windows, if this provides Direct3D textures, it must expose the device.
+  virtual ID3D11Device* GetD3D11Device() const {
+    return nullptr;
+  }
+#endif
+
+  // If this provides OpenGL textures, it must expose the GLContext.
+  virtual gl::GLContext* GetGLContext() const {
+    return nullptr;
+  }
+
+  virtual int32_t GetMaxTextureSize() const = 0;
+
+  // Return whether or not this provider is still valid (i.e., is still being
+  // used to composite).
+  virtual bool IsValid() const = 0;
+
+protected:
+  // Should be called at the end of each composition.
+  void ReadUnlockTextures();
+
+protected:
+  virtual ~TextureSourceProvider();
+
+private:
+  // An array of locks that will need to be unlocked after the next composition.
+  nsTArray<RefPtr<TextureHost>> mUnlockAfterComposition;
+
+  // An array of TextureHosts that will need to call NotifyNotUsed() after the next composition.
+  nsTArray<RefPtr<TextureHost>> mNotifyNotUsedAfterComposition;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // mozilla_gfx_layers_TextureSourceProvider_h
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -1081,19 +1081,10 @@ BasicCompositor::NeedsToDeferEndRemoteDr
 }
 
 void
 BasicCompositor::FinishPendingComposite()
 {
   TryToEndRemoteDrawing(/* aForceToEnd */ true);
 }
 
-BasicCompositor*
-AssertBasicCompositor(Compositor* aCompositor)
-{
-  BasicCompositor* compositor = aCompositor ? aCompositor->AsBasicCompositor()
-                                            : nullptr;
-  MOZ_DIAGNOSTIC_ASSERT(!!compositor);
-  return compositor;
-}
-
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/basic/MacIOSurfaceTextureHostBasic.cpp
+++ b/gfx/layers/basic/MacIOSurfaceTextureHostBasic.cpp
@@ -5,21 +5,18 @@
 
 #include "MacIOSurfaceTextureHostBasic.h"
 #include "mozilla/gfx/MacIOSurface.h"
 #include "MacIOSurfaceHelpers.h"
 
 namespace mozilla {
 namespace layers {
 
-MacIOSurfaceTextureSourceBasic::MacIOSurfaceTextureSourceBasic(
-                                BasicCompositor* aCompositor,
-                                MacIOSurface* aSurface)
-  : mCompositor(aCompositor)
-  , mSurface(aSurface)
+MacIOSurfaceTextureSourceBasic::MacIOSurfaceTextureSourceBasic(MacIOSurface* aSurface)
+  : mSurface(aSurface)
 {
   MOZ_COUNT_CTOR(MacIOSurfaceTextureSourceBasic);
 }
 
 MacIOSurfaceTextureSourceBasic::~MacIOSurfaceTextureSourceBasic()
 {
   MOZ_COUNT_DTOR(MacIOSurfaceTextureSourceBasic);
 }
@@ -54,46 +51,41 @@ gfx::SourceSurface*
 MacIOSurfaceTextureSourceBasic::GetSurface(gfx::DrawTarget* aTarget)
 {
   if (!mSourceSurface) {
     mSourceSurface = CreateSourceSurfaceFromMacIOSurface(mSurface);
   }
   return mSourceSurface;
 }
 
-void
-MacIOSurfaceTextureSourceBasic::SetCompositor(Compositor* aCompositor)
-{
-  mCompositor = AssertBasicCompositor(aCompositor);
-}
-
 bool
 MacIOSurfaceTextureHostBasic::Lock()
 {
-  if (!mCompositor) {
+  if (!mProvider) {
     return false;
   }
 
   if (!mTextureSource) {
-    mTextureSource = new MacIOSurfaceTextureSourceBasic(mCompositor, mSurface);
+    mTextureSource = new MacIOSurfaceTextureSourceBasic(mSurface);
   }
   return true;
 }
 
 void
-MacIOSurfaceTextureHostBasic::SetCompositor(Compositor* aCompositor)
+MacIOSurfaceTextureHostBasic::SetTextureSourceProvider(TextureSourceProvider* aProvider)
 {
-  BasicCompositor* compositor = AssertBasicCompositor(aCompositor);
-  if (!compositor) {
+  if (!aProvider->AsCompositor() || !aProvider->AsCompositor()->AsBasicCompositor()) {
     mTextureSource = nullptr;
     return;
   }
-  mCompositor = compositor;
+
+  mProvider = aProvider;
+
   if (mTextureSource) {
-    mTextureSource->SetCompositor(compositor);
+    mTextureSource->SetTextureSourceProvider(aProvider);
   }
 }
 
 gfx::SurfaceFormat
 MacIOSurfaceTextureHostBasic::GetFormat() const {
   return mSurface->HasAlpha() ? gfx::SurfaceFormat::R8G8B8A8 : gfx::SurfaceFormat::B8G8R8X8;
 }
 
--- a/gfx/layers/basic/MacIOSurfaceTextureHostBasic.h
+++ b/gfx/layers/basic/MacIOSurfaceTextureHostBasic.h
@@ -22,52 +22,46 @@ class BasicCompositor;
  * It does not own any GL texture, and attaches its shared handle to one of
  * the compositor's temporary textures when binding.
  */
 class MacIOSurfaceTextureSourceBasic
   : public TextureSourceBasic,
     public TextureSource
 {
 public:
-  MacIOSurfaceTextureSourceBasic(BasicCompositor* aCompositor,
-                                 MacIOSurface* aSurface);
+  explicit MacIOSurfaceTextureSourceBasic(MacIOSurface* aSurface);
   virtual ~MacIOSurfaceTextureSourceBasic();
 
   virtual const char* Name() const override { return "MacIOSurfaceTextureSourceBasic"; }
 
   virtual TextureSourceBasic* AsSourceBasic() override { return this; }
 
   virtual gfx::IntSize GetSize() const override;
   virtual gfx::SurfaceFormat GetFormat() const override;
   virtual gfx::SourceSurface* GetSurface(gfx::DrawTarget* aTarget) override;
 
   virtual void DeallocateDeviceData() override { }
 
-  virtual void SetCompositor(Compositor* aCompositor) override;
-
 protected:
-  RefPtr<BasicCompositor> mCompositor;
   RefPtr<MacIOSurface> mSurface;
   RefPtr<gfx::SourceSurface> mSourceSurface;
 };
 
 /**
  * A TextureHost for shared MacIOSurface
  *
  * Most of the logic actually happens in MacIOSurfaceTextureSourceBasic.
  */
 class MacIOSurfaceTextureHostBasic : public TextureHost
 {
 public:
   MacIOSurfaceTextureHostBasic(TextureFlags aFlags,
                                const SurfaceDescriptorMacIOSurface& aDescriptor);
 
-  virtual void SetCompositor(Compositor* aCompositor) override;
-
-  virtual Compositor* GetCompositor() override { return mCompositor; }
+  virtual void SetTextureSourceProvider(TextureSourceProvider* aProvider) override;
 
   virtual bool Lock() override;
 
   virtual gfx::SurfaceFormat GetFormat() const override;
 
   virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override
   {
     aTexture = mTextureSource;
@@ -81,17 +75,16 @@ public:
 
   virtual gfx::IntSize GetSize() const override;
 
 #ifdef MOZ_LAYERS_HAVE_LOG
   virtual const char* Name() override { return "MacIOSurfaceTextureHostBasic"; }
 #endif
 
 protected:
-  RefPtr<BasicCompositor> mCompositor;
   RefPtr<MacIOSurfaceTextureSourceBasic> mTextureSource;
   RefPtr<MacIOSurface> mSurface;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // MOZILLA_GFX_MACIOSURFACETEXTUREHOSTOGL_BASIC_H
--- a/gfx/layers/basic/X11TextureSourceBasic.cpp
+++ b/gfx/layers/basic/X11TextureSourceBasic.cpp
@@ -8,18 +8,17 @@
 #include "gfx2DGlue.h"
 
 namespace mozilla {
 namespace layers {
 
 using namespace mozilla::gfx;
 
 X11TextureSourceBasic::X11TextureSourceBasic(BasicCompositor* aCompositor, gfxXlibSurface* aSurface)
-  : mCompositor(aCompositor),
-    mSurface(aSurface)
+ : mSurface(aSurface)
 {
 }
 
 IntSize
 X11TextureSourceBasic::GetSize() const
 {
   return mSurface->GetSize();
 }
@@ -37,22 +36,16 @@ X11TextureSourceBasic::GetSurface(DrawTa
   if (!mSourceSurface) {
     mSourceSurface =
         Factory::CreateSourceSurfaceForCairoSurface(mSurface->CairoSurface(),
                                                     GetSize(), GetFormat());
   }
   return mSourceSurface;
 }
 
-void
-X11TextureSourceBasic::SetCompositor(Compositor* aCompositor)
-{
-  mCompositor = AssertBasicCompositor(aCompositor);
-}
-
 SurfaceFormat
 X11TextureSourceBasic::ContentTypeToSurfaceFormat(gfxContentType aType)
 {
   switch (aType) {
     case gfxContentType::COLOR:
       return SurfaceFormat::B8G8R8X8;
     case gfxContentType::ALPHA:
       return SurfaceFormat::A8;
--- a/gfx/layers/basic/X11TextureSourceBasic.h
+++ b/gfx/layers/basic/X11TextureSourceBasic.h
@@ -31,24 +31,21 @@ public:
   virtual gfx::IntSize GetSize() const override;
 
   virtual gfx::SurfaceFormat GetFormat() const override;
 
   virtual gfx::SourceSurface* GetSurface(gfx::DrawTarget* aTarget) override;
 
   virtual void DeallocateDeviceData() override { }
 
-  virtual void SetCompositor(Compositor* aCompositor) override;
-
   virtual void Updated() override { }
 
   static gfx::SurfaceFormat ContentTypeToSurfaceFormat(gfxContentType aType);
 
 protected:
-  RefPtr<BasicCompositor> mCompositor;
   RefPtr<gfxXlibSurface> mSurface;
   RefPtr<gfx::SourceSurface> mSourceSurface;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // MOZILLA_GFX_X11TEXTURESOURCEBASIC__H
--- a/gfx/layers/composite/CanvasLayerComposite.cpp
+++ b/gfx/layers/composite/CanvasLayerComposite.cpp
@@ -59,17 +59,17 @@ CanvasLayerComposite::GetLayer()
 }
 
 void
 CanvasLayerComposite::SetLayerManager(HostLayerManager* aManager)
 {
   LayerComposite::SetLayerManager(aManager);
   mManager = aManager;
   if (mCompositableHost && mCompositor) {
-    mCompositableHost->SetCompositor(mCompositor);
+    mCompositableHost->SetTextureSourceProvider(mCompositor);
   }
 }
 
 void
 CanvasLayerComposite::RenderLayer(const IntRect& aClipRect,
                                   const Maybe<gfx::Polygon>& aGeometry)
 {
   if (!mCompositableHost || !mCompositableHost->IsAttached()) {
@@ -84,17 +84,17 @@ CanvasLayerComposite::RenderLayer(const 
     if (surf) {
       WriteSnapshotToDumpFile(this, surf);
     }
   }
 #endif
 
   RenderWithAllMasks(this, mCompositor, aClipRect,
                      [&](EffectChain& effectChain, const IntRect& clipRect) {
-    mCompositableHost->Composite(this, effectChain,
+    mCompositableHost->Composite(mCompositor, this, effectChain,
                           GetEffectiveOpacity(),
                           GetEffectiveTransform(),
                           GetSamplingFilter(),
                           clipRect);
   });
 
   mCompositableHost->BumpFlashCounter();
 }
--- a/gfx/layers/composite/CompositableHost.cpp
+++ b/gfx/layers/composite/CompositableHost.cpp
@@ -27,60 +27,59 @@ using namespace gfx;
 
 namespace layers {
 
 class Compositor;
 
 CompositableHost::CompositableHost(const TextureInfo& aTextureInfo)
   : mTextureInfo(aTextureInfo)
   , mCompositorID(0)
-  , mCompositor(nullptr)
   , mLayer(nullptr)
   , mFlashCounter(0)
   , mAttached(false)
   , mKeepAttached(false)
 {
   MOZ_COUNT_CTOR(CompositableHost);
 }
 
 CompositableHost::~CompositableHost()
 {
   MOZ_COUNT_DTOR(CompositableHost);
 }
 
 void
 CompositableHost::UseTextureHost(const nsTArray<TimedTexture>& aTextures)
 {
-  if (GetCompositor()) {
+  if (mTextureSourceProvider) {
     for (auto& texture : aTextures) {
-      texture.mTexture->SetCompositor(GetCompositor());
+      texture.mTexture->SetTextureSourceProvider(mTextureSourceProvider);
     }
   }
 }
 
 void
 CompositableHost::UseComponentAlphaTextures(TextureHost* aTextureOnBlack,
                                             TextureHost* aTextureOnWhite)
 {
   MOZ_ASSERT(aTextureOnBlack && aTextureOnWhite);
-  if (GetCompositor()) {
-    aTextureOnBlack->SetCompositor(GetCompositor());
-    aTextureOnWhite->SetCompositor(GetCompositor());
+  if (mTextureSourceProvider) {
+    aTextureOnBlack->SetTextureSourceProvider(mTextureSourceProvider);
+    aTextureOnWhite->SetTextureSourceProvider(mTextureSourceProvider);
   }
 }
 
 void
 CompositableHost::RemoveTextureHost(TextureHost* aTexture)
 {}
 
 void
-CompositableHost::SetCompositor(Compositor* aCompositor)
+CompositableHost::SetTextureSourceProvider(TextureSourceProvider* aProvider)
 {
-  MOZ_ASSERT(aCompositor);
-  mCompositor = aCompositor;
+  MOZ_ASSERT(aProvider);
+  mTextureSourceProvider = aProvider;
 }
 
 bool
 CompositableHost::AddMaskEffect(EffectChain& aEffects,
                                 const gfx::Matrix4x4& aTransform)
 {
   CompositableTextureSourceRef source;
   RefPtr<TextureHost> host = GetAsTextureHost();
@@ -170,10 +169,16 @@ HostLayerManager*
 CompositableHost::GetLayerManager() const
 {
   if (!mLayer || !mLayer->Manager()) {
     return nullptr;
   }
   return mLayer->Manager()->AsHostLayerManager();
 }
 
+TextureSourceProvider*
+CompositableHost::GetTextureSourceProvider() const
+{
+  return mTextureSourceProvider;
+}
+
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/composite/CompositableHost.h
+++ b/gfx/layers/composite/CompositableHost.h
@@ -87,20 +87,21 @@ public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositableHost)
   explicit CompositableHost(const TextureInfo& aTextureInfo);
 
   static already_AddRefed<CompositableHost> Create(const TextureInfo& aTextureInfo);
 
   virtual CompositableType GetType() = 0;
 
   // If base class overrides, it should still call the parent implementation
-  virtual void SetCompositor(Compositor* aCompositor);
+  virtual void SetTextureSourceProvider(TextureSourceProvider* aProvider);
 
   // composite the contents of this buffer host to the compositor's surface
-  virtual void Composite(LayerComposite* aLayer,
+  virtual void Composite(Compositor* aCompositor,
+                         LayerComposite* aLayer,
                          EffectChain& aEffectChain,
                          float aOpacity,
                          const gfx::Matrix4x4& aTransform,
                          const gfx::SamplingFilter aSamplingFilter,
                          const gfx::IntRect& aClipRect,
                          const nsIntRegion* aVisibleRegion = nullptr,
                          const Maybe<gfx::Polygon>& aGeometry = Nothing()) = 0;
 
@@ -135,41 +136,38 @@ public:
    * Adds a mask effect using this texture as the mask, if possible.
    * @return true if the effect was added, false otherwise.
    */
   bool AddMaskEffect(EffectChain& aEffects,
                      const gfx::Matrix4x4& aTransform);
 
   void RemoveMaskEffect();
 
-  Compositor* GetCompositor() const
-  {
-    return mCompositor;
-  }
+  TextureSourceProvider* GetTextureSourceProvider() const;
 
   Layer* GetLayer() const { return mLayer; }
   void SetLayer(Layer* aLayer) { mLayer = aLayer; }
 
   virtual TiledContentHost* AsTiledContentHost() { return nullptr; }
   virtual WebRenderImageHost* AsWebRenderImageHost() { return nullptr; }
 
   typedef uint32_t AttachFlags;
   static const AttachFlags NO_FLAGS = 0;
   static const AttachFlags ALLOW_REATTACH = 1;
   static const AttachFlags KEEP_ATTACHED = 2;
   static const AttachFlags FORCE_DETACH = 2;
 
   virtual void Attach(Layer* aLayer,
-                      Compositor* aCompositor,
+                      TextureSourceProvider* aProvider,
                       AttachFlags aFlags = NO_FLAGS)
   {
-    MOZ_ASSERT(aCompositor, "Compositor is required");
+    MOZ_ASSERT(aProvider);
     NS_ASSERTION(aFlags & ALLOW_REATTACH || !mAttached,
                  "Re-attaching compositables must be explicitly authorised");
-    SetCompositor(aCompositor);
+    SetTextureSourceProvider(aProvider);
     SetLayer(aLayer);
     mAttached = true;
     mKeepAttached = aFlags & KEEP_ATTACHED;
   }
   // Detach this compositable host from its layer.
   // If we are used for async video, then it is not safe to blindly detach since
   // we might be re-attached to a different layer. aLayer is the layer which the
   // caller expects us to be attached to, we will only detach if we are in fact
@@ -240,17 +238,17 @@ public:
 
 protected:
   HostLayerManager* GetLayerManager() const;
 
 protected:
   TextureInfo mTextureInfo;
   AsyncCompositableRef mAsyncRef;
   uint64_t mCompositorID;
-  RefPtr<Compositor> mCompositor;
+  RefPtr<TextureSourceProvider> mTextureSourceProvider;
   Layer* mLayer;
   uint32_t mFlashCounter; // used when the pref "layers.flash-borders" is true.
   bool mAttached;
   bool mKeepAttached;
 };
 
 class AutoLockCompositableHost final
 {
--- a/gfx/layers/composite/ContentHost.cpp
+++ b/gfx/layers/composite/ContentHost.cpp
@@ -27,17 +27,18 @@ ContentHostBase::ContentHostBase(const T
   , mInitialised(false)
 {}
 
 ContentHostBase::~ContentHostBase()
 {
 }
 
 void
-ContentHostTexture::Composite(LayerComposite* aLayer,
+ContentHostTexture::Composite(Compositor* aCompositor,
+                              LayerComposite* aLayer,
                               EffectChain& aEffectChain,
                               float aOpacity,
                               const gfx::Matrix4x4& aTransform,
                               const SamplingFilter aSamplingFilter,
                               const IntRect& aClipRect,
                               const nsIntRegion* aVisibleRegion,
                               const Maybe<gfx::Polygon>& aGeometry)
 {
@@ -176,26 +177,26 @@ ContentHostTexture::Composite(LayerCompo
           gfx::Rect rect(tileScreenRect.x, tileScreenRect.y,
                          tileScreenRect.width, tileScreenRect.height);
 
           effect->mTextureCoords = Rect(Float(tileRegionRect.x) / texRect.width,
                                         Float(tileRegionRect.y) / texRect.height,
                                         Float(tileRegionRect.width) / texRect.width,
                                         Float(tileRegionRect.height) / texRect.height);
 
-          GetCompositor()->DrawGeometry(rect, aClipRect, aEffectChain,
-                                        aOpacity, aTransform, aGeometry);
+          aCompositor->DrawGeometry(rect, aClipRect, aEffectChain,
+                                    aOpacity, aTransform, aGeometry);
 
           if (usingTiles) {
             DiagnosticFlags diagnostics = DiagnosticFlags::CONTENT | DiagnosticFlags::BIGIMAGE;
             if (iterOnWhite) {
               diagnostics |= DiagnosticFlags::COMPONENT_ALPHA;
             }
-            GetCompositor()->DrawDiagnostics(diagnostics, rect, aClipRect,
-                                             aTransform, mFlashCounter);
+            aCompositor->DrawDiagnostics(diagnostics, rect, aClipRect,
+                                         aTransform, mFlashCounter);
           }
         }
       }
     }
 
     if (iterOnWhite) {
       iterOnWhite->NextTile();
     }
@@ -207,18 +208,18 @@ ContentHostTexture::Composite(LayerCompo
   if (iterOnWhite) {
     iterOnWhite->EndBigImageIteration();
   }
 
   DiagnosticFlags diagnostics = DiagnosticFlags::CONTENT;
   if (iterOnWhite) {
     diagnostics |= DiagnosticFlags::COMPONENT_ALPHA;
   }
-  GetCompositor()->DrawDiagnostics(diagnostics, nsIntRegion(mBufferRect), aClipRect,
-                                   aTransform, mFlashCounter);
+  aCompositor->DrawDiagnostics(diagnostics, nsIntRegion(mBufferRect), aClipRect,
+                               aTransform, mFlashCounter);
 }
 
 void
 ContentHostTexture::UseTextureHost(const nsTArray<TimedTexture>& aTextures)
 {
   ContentHostBase::UseTextureHost(aTextures);
   MOZ_ASSERT(aTextures.Length() == 1);
   const TimedTexture& t = aTextures[0];
@@ -249,24 +250,24 @@ ContentHostTexture::UseComponentAlphaTex
     mTextureHost->PrepareTextureSource(mTextureSource);
   }
   if (mTextureHostOnWhite) {
     mTextureHostOnWhite->PrepareTextureSource(mTextureSourceOnWhite);
   }
 }
 
 void
-ContentHostTexture::SetCompositor(Compositor* aCompositor)
+ContentHostTexture::SetTextureSourceProvider(TextureSourceProvider* aProvider)
 {
-  ContentHostBase::SetCompositor(aCompositor);
+  ContentHostBase::SetTextureSourceProvider(aProvider);
   if (mTextureHost) {
-    mTextureHost->SetCompositor(aCompositor);
+    mTextureHost->SetTextureSourceProvider(aProvider);
   }
   if (mTextureHostOnWhite) {
-    mTextureHostOnWhite->SetCompositor(aCompositor);
+    mTextureHostOnWhite->SetTextureSourceProvider(aProvider);
   }
 }
 
 void
 ContentHostTexture::Dump(std::stringstream& aStream,
                          const char* aPrefix,
                          bool aDumpHtml)
 {
--- a/gfx/layers/composite/ContentHost.h
+++ b/gfx/layers/composite/ContentHost.h
@@ -112,26 +112,27 @@ class ContentHostTexture : public Conten
 {
 public:
   explicit ContentHostTexture(const TextureInfo& aTextureInfo)
     : ContentHostBase(aTextureInfo)
     , mLocked(false)
     , mReceivedNewHost(false)
   { }
 
-  virtual void Composite(LayerComposite* aLayer,
+  virtual void Composite(Compositor* aCompositor,
+                         LayerComposite* aLayer,
                          EffectChain& aEffectChain,
                          float aOpacity,
                          const gfx::Matrix4x4& aTransform,
                          const gfx::SamplingFilter aSamplingFilter,
                          const gfx::IntRect& aClipRect,
                          const nsIntRegion* aVisibleRegion = nullptr,
                          const Maybe<gfx::Polygon>& aGeometry = Nothing()) override;
 
-  virtual void SetCompositor(Compositor* aCompositor) override;
+  virtual void SetTextureSourceProvider(TextureSourceProvider* aProvider) override;
 
   virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override;
 
   virtual void Dump(std::stringstream& aStream,
                     const char* aPrefix="",
                     bool aDumpHtml=false) override;
 
   virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
--- a/gfx/layers/composite/GPUVideoTextureHost.cpp
+++ b/gfx/layers/composite/GPUVideoTextureHost.cpp
@@ -46,30 +46,21 @@ bool
 GPUVideoTextureHost::BindTextureSource(CompositableTextureSourceRef& aTexture)
 {
   if (!mWrappedTextureHost) {
     return false;
   }
   return mWrappedTextureHost->BindTextureSource(aTexture);
 }
 
-Compositor*
-GPUVideoTextureHost::GetCompositor()
-{
-  if (!mWrappedTextureHost) {
-    return nullptr;
-  }
-  return mWrappedTextureHost->GetCompositor();
-}
-
 void
-GPUVideoTextureHost::SetCompositor(Compositor* aCompositor)
+GPUVideoTextureHost::SetTextureSourceProvider(TextureSourceProvider* aProvider)
 {
   if (mWrappedTextureHost) {
-    mWrappedTextureHost->SetCompositor(aCompositor);
+    mWrappedTextureHost->SetTextureSourceProvider(aProvider);
   }
 }
 
 YUVColorSpace
 GPUVideoTextureHost::GetYUVColorSpace() const
 {
   if (mWrappedTextureHost) {
     return mWrappedTextureHost->GetYUVColorSpace();
--- a/gfx/layers/composite/GPUVideoTextureHost.h
+++ b/gfx/layers/composite/GPUVideoTextureHost.h
@@ -15,19 +15,17 @@ class GPUVideoTextureHost : public Textu
 {
 public:
  GPUVideoTextureHost(TextureFlags aFlags,
                      const SurfaceDescriptorGPUVideo& aDescriptor);
   virtual ~GPUVideoTextureHost();
 
   virtual void DeallocateDeviceData() override {}
 
-  virtual void SetCompositor(Compositor* aCompositor) override;
-
-  virtual Compositor* GetCompositor() override;
+  virtual void SetTextureSourceProvider(TextureSourceProvider* aProvider) override;
 
   virtual bool Lock() override;
 
   virtual void Unlock() override;
 
   virtual gfx::SurfaceFormat GetFormat() const override;
 
   virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override;
--- a/gfx/layers/composite/ImageHost.cpp
+++ b/gfx/layers/composite/ImageHost.cpp
@@ -172,30 +172,29 @@ ImageHost::GetAsTextureHost(IntRect* aPi
   }
   if (aPictureRect && img) {
     *aPictureRect = img->mPictureRect;
   }
   return img ? img->mTextureHost.get() : nullptr;
 }
 
 void ImageHost::Attach(Layer* aLayer,
-                       Compositor* aCompositor,
+                       TextureSourceProvider* aProvider,
                        AttachFlags aFlags)
 {
-  CompositableHost::Attach(aLayer, aCompositor, aFlags);
+  CompositableHost::Attach(aLayer, aProvider, aFlags);
   for (auto& img : mImages) {
-    if (GetCompositor()) {
-      img.mTextureHost->SetCompositor(GetCompositor());
-    }
+    img.mTextureHost->SetTextureSourceProvider(aProvider);
     img.mTextureHost->Updated();
   }
 }
 
 void
-ImageHost::Composite(LayerComposite* aLayer,
+ImageHost::Composite(Compositor* aCompositor,
+                     LayerComposite* aLayer,
                      EffectChain& aEffectChain,
                      float aOpacity,
                      const gfx::Matrix4x4& aTransform,
                      const gfx::SamplingFilter aSamplingFilter,
                      const gfx::IntRect& aClipRect,
                      const nsIntRegion* aVisibleRegion,
                      const Maybe<gfx::Polygon>& aGeometry)
 {
@@ -209,17 +208,17 @@ ImageHost::Composite(LayerComposite* aLa
     return;
   }
 
   if (uint32_t(imageIndex) + 1 < mImages.Length()) {
     lm->CompositeUntil(mImages[imageIndex + 1].mTimeStamp + TimeDuration::FromMilliseconds(BIAS_TIME_MS));
   }
 
   TimedImage* img = &mImages[imageIndex];
-  img->mTextureHost->SetCompositor(GetCompositor());
+  img->mTextureHost->SetTextureSourceProvider(aCompositor);
   SetCurrentTextureHost(img->mTextureHost);
 
   {
     AutoLockCompositableHost autoLock(this);
     if (autoLock.Failed()) {
       NS_WARNING("failed to lock front buffer");
       return;
     }
@@ -238,17 +237,17 @@ ImageHost::Composite(LayerComposite* aLa
         !(mCurrentTextureHost->GetFlags() & TextureFlags::NON_PREMULTIPLIED);
     RefPtr<TexturedEffect> effect =
         CreateTexturedEffect(mCurrentTextureHost,
             mCurrentTextureSource.get(), aSamplingFilter, isAlphaPremultiplied);
     if (!effect) {
       return;
     }
 
-    if (!GetCompositor()->SupportsEffect(effect->mType)) {
+    if (!aCompositor->SupportsEffect(effect->mType)) {
       return;
     }
 
     DiagnosticFlags diagnosticFlags = DiagnosticFlags::IMAGE;
     if (effect->mType == EffectTypes::NV12) {
       diagnosticFlags |= DiagnosticFlags::NV12;
     } else if (effect->mType == EffectTypes::YCBCR) {
       diagnosticFlags |= DiagnosticFlags::YCBCR;
@@ -297,66 +296,66 @@ ImageHost::Composite(LayerComposite* aLa
         effect->mTextureCoords = Rect(Float(rect.x - tileRect.x) / tileRect.width,
                                       Float(rect.y - tileRect.y) / tileRect.height,
                                       Float(rect.width) / tileRect.width,
                                       Float(rect.height) / tileRect.height);
         if (img->mTextureHost->GetFlags() & TextureFlags::ORIGIN_BOTTOM_LEFT) {
           effect->mTextureCoords.y = effect->mTextureCoords.YMost();
           effect->mTextureCoords.height = -effect->mTextureCoords.height;
         }
-        GetCompositor()->DrawGeometry(rect, aClipRect, aEffectChain,
-                                      aOpacity, aTransform, aGeometry);
-        GetCompositor()->DrawDiagnostics(diagnosticFlags | DiagnosticFlags::BIGIMAGE,
-                                         rect, aClipRect, aTransform, mFlashCounter);
+        aCompositor->DrawGeometry(rect, aClipRect, aEffectChain,
+                                  aOpacity, aTransform, aGeometry);
+        aCompositor->DrawDiagnostics(diagnosticFlags | DiagnosticFlags::BIGIMAGE,
+                                     rect, aClipRect, aTransform, mFlashCounter);
       } while (it->NextTile());
       it->EndBigImageIteration();
       // layer border
-      GetCompositor()->DrawDiagnostics(diagnosticFlags, pictureRect,
-                                       aClipRect, aTransform, mFlashCounter);
+      aCompositor->DrawDiagnostics(diagnosticFlags, pictureRect,
+                                   aClipRect, aTransform, mFlashCounter);
     } else {
       IntSize textureSize = mCurrentTextureSource->GetSize();
       effect->mTextureCoords = Rect(Float(img->mPictureRect.x) / textureSize.width,
                                     Float(img->mPictureRect.y) / textureSize.height,
                                     Float(img->mPictureRect.width) / textureSize.width,
                                     Float(img->mPictureRect.height) / textureSize.height);
 
       if (img->mTextureHost->GetFlags() & TextureFlags::ORIGIN_BOTTOM_LEFT) {
         effect->mTextureCoords.y = effect->mTextureCoords.YMost();
         effect->mTextureCoords.height = -effect->mTextureCoords.height;
       }
 
-      GetCompositor()->DrawGeometry(pictureRect, aClipRect, aEffectChain,
-                                    aOpacity, aTransform, aGeometry);
-      GetCompositor()->DrawDiagnostics(diagnosticFlags,
-                                       pictureRect, aClipRect,
-                                       aTransform, mFlashCounter);
+      aCompositor->DrawGeometry(pictureRect, aClipRect, aEffectChain,
+                                aOpacity, aTransform, aGeometry);
+      aCompositor->DrawDiagnostics(diagnosticFlags,
+                                   pictureRect, aClipRect,
+                                   aTransform, mFlashCounter);
     }
   }
 
   // Update mBias last. This can change which frame ChooseImage(Index) would
   // return, and we don't want to do that until we've finished compositing
   // since callers of ChooseImage(Index) assume the same image will be chosen
   // during a given composition. This must happen after autoLock's
   // destructor!
   mBias = UpdateBias(
       lm->GetCompositionTime(), mImages[imageIndex].mTimeStamp,
       uint32_t(imageIndex + 1) < mImages.Length() ?
           mImages[imageIndex + 1].mTimeStamp : TimeStamp(),
       mBias);
 }
 
 void
-ImageHost::SetCompositor(Compositor* aCompositor)
+ImageHost::SetTextureSourceProvider(TextureSourceProvider* aProvider)
 {
-  if (mCompositor != aCompositor) {
+  if (mTextureSourceProvider != aProvider) {
     for (auto& img : mImages) {
-      img.mTextureHost->SetCompositor(aCompositor);
+      img.mTextureHost->SetTextureSourceProvider(aProvider);
     }
   }
-  CompositableHost::SetCompositor(aCompositor);
+  CompositableHost::SetTextureSourceProvider(aProvider);
 }
 
 void
 ImageHost::PrintInfo(std::stringstream& aStream, const char* aPrefix)
 {
   aStream << aPrefix;
   aStream << nsPrintfCString("ImageHost (0x%p)", this).get();
 
--- a/gfx/layers/composite/ImageHost.h
+++ b/gfx/layers/composite/ImageHost.h
@@ -40,36 +40,37 @@ class ImageHost : public CompositableHos
                   public ImageComposite
 {
 public:
   explicit ImageHost(const TextureInfo& aTextureInfo);
   ~ImageHost();
 
   virtual CompositableType GetType() override { return mTextureInfo.mCompositableType; }
 
-  virtual void Composite(LayerComposite* aLayer,
+  virtual void Composite(Compositor* aCompositor,
+                         LayerComposite* aLayer,
                          EffectChain& aEffectChain,
                          float aOpacity,
                          const gfx::Matrix4x4& aTransform,
                          const gfx::SamplingFilter aSamplingFilter,
                          const gfx::IntRect& aClipRect,
                          const nsIntRegion* aVisibleRegion = nullptr,
                          const Maybe<gfx::Polygon>& aGeometry = Nothing()) override;
 
   virtual void UseTextureHost(const nsTArray<TimedTexture>& aTextures) override;
 
   virtual void RemoveTextureHost(TextureHost* aTexture) override;
 
   virtual TextureHost* GetAsTextureHost(gfx::IntRect* aPictureRect = nullptr) override;
 
   virtual void Attach(Layer* aLayer,
-                      Compositor* aCompositor,
+                      TextureSourceProvider* aProvider,
                       AttachFlags aFlags = NO_FLAGS) override;
 
-  virtual void SetCompositor(Compositor* aCompositor) override;
+  virtual void SetTextureSourceProvider(TextureSourceProvider* aProvider) override;
 
   gfx::IntSize GetImageSize() const override;
 
   virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
 
   virtual void Dump(std::stringstream& aStream,
                     const char* aPrefix = "",
                     bool aDumpHtml = false) override;
--- a/gfx/layers/composite/ImageLayerComposite.cpp
+++ b/gfx/layers/composite/ImageLayerComposite.cpp
@@ -71,17 +71,17 @@ ImageLayerComposite::GetLayer()
 }
 
 void
 ImageLayerComposite::SetLayerManager(HostLayerManager* aManager)
 {
   LayerComposite::SetLayerManager(aManager);
   mManager = aManager;
   if (mImageHost) {
-    mImageHost->SetCompositor(mCompositor);
+    mImageHost->SetTextureSourceProvider(mCompositor);
   }
 }
 
 void
 ImageLayerComposite::RenderLayer(const IntRect& aClipRect,
                                  const Maybe<gfx::Polygon>& aGeometry)
 {
   if (!mImageHost || !mImageHost->IsAttached()) {
@@ -96,18 +96,18 @@ ImageLayerComposite::RenderLayer(const I
     }
   }
 #endif
 
   mCompositor->MakeCurrent();
 
   RenderWithAllMasks(this, mCompositor, aClipRect,
                      [&](EffectChain& effectChain, const IntRect& clipRect) {
-    mImageHost->SetCompositor(mCompositor);
-    mImageHost->Composite(this, effectChain,
+    mImageHost->SetTextureSourceProvider(mCompositor);
+    mImageHost->Composite(mCompositor, this, effectChain,
                           GetEffectiveOpacity(),
                           GetEffectiveTransformForBuffer(),
                           GetSamplingFilter(),
                           clipRect);
   });
   mImageHost->BumpFlashCounter();
 }
 
--- a/gfx/layers/composite/LayerManagerComposite.h
+++ b/gfx/layers/composite/LayerManagerComposite.h
@@ -111,16 +111,17 @@ public:
                                                 const Maybe<uint32_t>& aPresShellId) = 0;
   virtual void UpdateApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid,
                                                 const CSSIntRegion& aRegion) = 0;
 
   virtual void NotifyShadowTreeTransaction() {}
   virtual void BeginTransactionWithDrawTarget(gfx::DrawTarget* aTarget,
                                               const gfx::IntRect& aRect) = 0;
   virtual Compositor* GetCompositor() const = 0;
+  virtual TextureSourceProvider* GetTextureSourceProvider() const = 0;
   virtual void EndTransaction(const TimeStamp& aTimeStamp,
                               EndTransactionFlags aFlags = END_DEFAULT) = 0;
   virtual void UpdateRenderBounds(const gfx::IntRect& aRect) {}
 
   // Called by CompositorBridgeParent when a new compositor has been created due
   // to a device reset. The layer manager must clear any cached resources
   // attached to the old compositor, and make a best effort at ignoring
   // layer or texture updates against the old compositor.
@@ -352,18 +353,20 @@ public:
     *regionForScrollFrame = aRegion;
   }
 
   CSSIntRegion* GetApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid)
   {
     return mVisibleRegions.Get(aGuid);
   }
 
-  Compositor* GetCompositor() const override
-  {
+  Compositor* GetCompositor() const override {
+    return mCompositor;
+  }
+  TextureSourceProvider* GetTextureSourceProvider() const override {
     return mCompositor;
   }
 
   // Called by CompositorBridgeParent when a new compositor has been created due
   // to a device reset. The layer manager must clear any cached resources
   // attached to the old compositor, and make a best effort at ignoring
   // layer or texture updates against the old compositor.
   void ChangeCompositor(Compositor* aNewCompositor) override;
--- a/gfx/layers/composite/PaintedLayerComposite.cpp
+++ b/gfx/layers/composite/PaintedLayerComposite.cpp
@@ -80,33 +80,33 @@ PaintedLayerComposite::GetLayer()
 }
 
 void
 PaintedLayerComposite::SetLayerManager(HostLayerManager* aManager)
 {
   LayerComposite::SetLayerManager(aManager);
   mManager = aManager;
   if (mBuffer && mCompositor) {
-    mBuffer->SetCompositor(mCompositor);
+    mBuffer->SetTextureSourceProvider(mCompositor);
   }
 }
 
 void
 PaintedLayerComposite::RenderLayer(const gfx::IntRect& aClipRect,
                                    const Maybe<gfx::Polygon>& aGeometry)
 {
   if (!mBuffer || !mBuffer->IsAttached()) {
     return;
   }
   PROFILER_LABEL("PaintedLayerComposite", "RenderLayer",
     js::ProfileEntry::Category::GRAPHICS);
 
   Compositor* compositor = mCompositeManager->GetCompositor();
 
-  MOZ_ASSERT(mBuffer->GetCompositor() == compositor &&
+  MOZ_ASSERT(mBuffer->GetTextureSourceProvider() == compositor &&
              mBuffer->GetLayer() == this,
              "buffer is corrupted");
 
   const nsIntRegion visibleRegion = GetLocalVisibleRegion().ToUnknownRegion();
 
 #ifdef MOZ_DUMP_PAINTING
   if (gfxEnv::DumpCompositorTextures()) {
     RefPtr<gfx::DataSourceSurface> surf = mBuffer->GetAsSurface();
@@ -116,17 +116,17 @@ PaintedLayerComposite::RenderLayer(const
   }
 #endif
 
   RenderWithAllMasks(this, compositor, aClipRect,
                      [&](EffectChain& effectChain,
                      const gfx::IntRect& clipRect) {
     mBuffer->SetPaintWillResample(MayResample());
 
-    mBuffer->Composite(this, effectChain, GetEffectiveOpacity(),
+    mBuffer->Composite(compositor, this, effectChain, GetEffectiveOpacity(),
                        GetEffectiveTransform(), GetSamplingFilter(),
                        clipRect, &visibleRegion, aGeometry);
   });
 
   mBuffer->BumpFlashCounter();
 
   compositor->MakeCurrent();
 }
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -315,24 +315,23 @@ void TextureHost::Finalize()
     DeallocateDeviceData();
   }
 }
 
 void
 TextureHost::UnbindTextureSource()
 {
   if (mReadLock) {
-    auto compositor = GetCompositor();
     // This TextureHost is not used anymore. Since most compositor backends are
     // working asynchronously under the hood a compositor could still be using
     // this texture, so it is generally best to wait until the end of the next
     // composition before calling ReadUnlock. We ask the compositor to take care
     // of that for us.
-    if (compositor) {
-      compositor->UnlockAfterComposition(this);
+    if (mProvider) {
+      mProvider->UnlockAfterComposition(this);
     } else {
       // GetCompositor returned null which means no compositor can be using this
       // texture. We can ReadUnlock right away.
       ReadUnlock();
     }
   }
 }
 
@@ -352,31 +351,28 @@ TextureHost::NotifyNotUsed()
   }
 
   // Do not need to call NotifyNotUsed() if TextureHost does not have
   // TextureFlags::RECYCLE flag.
   if (!(GetFlags() & TextureFlags::RECYCLE)) {
     return;
   }
 
-  auto compositor = GetCompositor();
   // The following cases do not need to defer NotifyNotUsed until next Composite.
   // - TextureHost does not have Compositor.
   // - Compositor is BasicCompositor.
   // - TextureHost has intermediate buffer.
   //   end of buffer usage.
-  if (!compositor ||
-      compositor->IsDestroyed() ||
-      compositor->AsBasicCompositor() ||
-      HasIntermediateBuffer()) {
+  if (!mProvider ||
+      HasIntermediateBuffer() ||
+      !mProvider->NotifyNotUsedAfterComposition(this))
+  {
     static_cast<TextureParent*>(mActor)->NotifyNotUsed(mFwdTransactionId);
     return;
   }
-
-  compositor->NotifyNotUsedAfterComposition(this);
 }
 
 void
 TextureHost::CallNotifyNotUsed()
 {
   if (!mActor) {
     return;
   }
@@ -433,17 +429,16 @@ TextureSource::Name() const
 {
   MOZ_CRASH("GFX: TextureSource without class name");
   return "TextureSource";
 }
   
 BufferTextureHost::BufferTextureHost(const BufferDescriptor& aDesc,
                                      TextureFlags aFlags)
 : TextureHost(aFlags)
-, mCompositor(nullptr)
 , mUpdateSerial(1)
 , mLocked(false)
 , mNeedsFullUpdate(false)
 {
   mDescriptor = aDesc;
   switch (mDescriptor.type()) {
     case BufferDescriptor::TYCbCrDescriptor: {
       const YCbCrDescriptor& ycbcr = mDescriptor.get_YCbCrDescriptor();
@@ -487,38 +482,29 @@ BufferTextureHost::UpdatedInternal(const
   }
   if (GetFlags() & TextureFlags::IMMEDIATE_UPLOAD) {
     DebugOnly<bool> result = MaybeUpload(!mNeedsFullUpdate ? &mMaybeUpdatedRegion : nullptr);
     NS_WARNING_ASSERTION(result, "Failed to upload a texture");
   }
 }
 
 void
-BufferTextureHost::SetCompositor(Compositor* aCompositor)
+BufferTextureHost::SetTextureSourceProvider(TextureSourceProvider* aProvider)
 {
-  MOZ_ASSERT(aCompositor);
-  if (mCompositor == aCompositor) {
+  if (mProvider == aProvider) {
     return;
   }
-  if (aCompositor && mCompositor &&
-      aCompositor->GetBackendType() == mCompositor->GetBackendType()) {
-    RefPtr<TextureSource> it = mFirstSource;
-    while (it) {
-      it->SetCompositor(aCompositor);
-      it = it->GetNextSibling();
-    }
-  }
   if (mFirstSource && mFirstSource->IsOwnedBy(this)) {
     mFirstSource->SetOwner(nullptr);
   }
   if (mFirstSource) {
     mFirstSource = nullptr;
     mNeedsFullUpdate = true;
   }
-  mCompositor = aCompositor;
+  mProvider = aProvider;
 }
 
 void
 BufferTextureHost::DeallocateDeviceData()
 {
   if (mFirstSource && mFirstSource->NumCompositableRefs() > 0) {
     return;
   }
@@ -600,30 +586,30 @@ BufferTextureHost::EnsureWrappingTexture
     return true;
   }
   // We don't own it, apparently.
   if (mFirstSource) {
     mNeedsFullUpdate = true;
     mFirstSource = nullptr;
   }
 
-  if (!mCompositor) {
+  if (!mProvider) {
     return false;
   }
 
   if (mFormat == gfx::SurfaceFormat::YUV) {
-    mFirstSource = mCompositor->CreateDataTextureSourceAroundYCbCr(this);
+    mFirstSource = mProvider->CreateDataTextureSourceAroundYCbCr(this);
   } else {
     RefPtr<gfx::DataSourceSurface> surf =
       gfx::Factory::CreateWrappingDataSourceSurface(GetBuffer(),
         ImageDataSerializer::ComputeRGBStride(mFormat, mSize.width), mSize, mFormat);
     if (!surf) {
       return false;
     }
-    mFirstSource = mCompositor->CreateDataTextureSourceAround(surf);
+    mFirstSource = mProvider->CreateDataTextureSourceAround(surf);
   }
 
   if (!mFirstSource) {
     // BasicCompositor::CreateDataTextureSourceAround never returns null
     // and we don't expect to take this branch if we are using another backend.
     // Returning false is fine but if we get into this situation it probably
     // means something fishy is going on, like a texture being used with
     // several compositor backends.
@@ -635,27 +621,27 @@ BufferTextureHost::EnsureWrappingTexture
   mFirstSource->SetOwner(this);
 
   return true;
 }
 
 static
 bool IsCompatibleTextureSource(TextureSource* aTexture,
                                const BufferDescriptor& aDescriptor,
-                               Compositor* aCompositor)
+                               TextureSourceProvider* aProvider)
 {
-  if (!aCompositor) {
+  if (!aProvider) {
     return false;
   }
 
   switch (aDescriptor.type()) {
     case BufferDescriptor::TYCbCrDescriptor: {
       const YCbCrDescriptor& ycbcr = aDescriptor.get_YCbCrDescriptor();
 
-      if (!aCompositor->SupportsEffect(EffectTypes::YCBCR)) {
+      if (!aProvider->SupportsEffect(EffectTypes::YCBCR)) {
         return aTexture->GetFormat() == gfx::SurfaceFormat::B8G8R8X8
             && aTexture->GetSize() == ycbcr.ySize();
       }
 
       if (aTexture->GetFormat() != gfx::SurfaceFormat::A8
           || aTexture->GetSize() != ycbcr.ySize()) {
         return false;
       }
@@ -719,33 +705,33 @@ BufferTextureHost::PrepareTextureSource(
     mNeedsFullUpdate = true;
     mFirstSource = nullptr;
   }
 
   DataTextureSource* texture = aTexture.get() ? aTexture->AsDataTextureSource() : nullptr;
 
   bool compatibleFormats = texture && IsCompatibleTextureSource(texture,
                                                                 mDescriptor,
-                                                                mCompositor);
+                                                                mProvider);
 
   bool shouldCreateTexture = !compatibleFormats
                            || texture->NumCompositableRefs() > 1
                            || texture->HasOwner();
 
   if (!shouldCreateTexture) {
     mFirstSource = texture;
     mFirstSource->SetOwner(this);
     mNeedsFullUpdate = true;
 
     // It's possible that texture belonged to a different compositor,
     // so make sure we update it (and all of its siblings) to the
     // current one.
     RefPtr<TextureSource> it = mFirstSource;
     while (it) {
-      it->SetCompositor(mCompositor);
+      it->SetTextureSourceProvider(mProvider);
       it = it->GetNextSibling();
     }
   }
 }
 
 bool
 BufferTextureHost::BindTextureSource(CompositableTextureSourceRef& aTexture)
 {
@@ -775,18 +761,18 @@ gfx::SurfaceFormat
 BufferTextureHost::GetFormat() const
 {
   // mFormat is the format of the data that we share with the content process.
   // GetFormat, on the other hand, expects the format that we present to the
   // Compositor (it is used to choose the effect type).
   // if the compositor does not support YCbCr effects, we give it a RGBX texture
   // instead (see BufferTextureHost::Upload)
   if (mFormat == gfx::SurfaceFormat::YUV &&
-    mCompositor &&
-    !mCompositor->SupportsEffect(EffectTypes::YCBCR)) {
+      mProvider &&
+      !mProvider->SupportsEffect(EffectTypes::YCBCR)) {
     return gfx::SurfaceFormat::R8G8B8X8;
   }
   return mFormat;
 }
 
 YUVColorSpace
 BufferTextureHost::GetYUVColorSpace() const
 {
@@ -837,53 +823,53 @@ BufferTextureHost::Upload(nsIntRegion *a
   if (!buf) {
     // We don't have a buffer; a possible cause is that the IPDL actor
     // is already dead. This inevitably happens as IPDL actors can die
     // at any time, so we want to silently return in this case.
     // another possible cause is that IPDL failed to map the shmem when
     // deserializing it.
     return false;
   }
-  if (!mCompositor) {
+  if (!mProvider) {
     // This can happen if we send textures to a compositable that isn't yet
     // attached to a layer.
     return false;
   }
   if (!mHasIntermediateBuffer && EnsureWrappingTextureSource()) {
     return true;
   }
 
   if (mFormat == gfx::SurfaceFormat::UNKNOWN) {
     NS_WARNING("BufferTextureHost: unsupported format!");
     return false;
   } else if (mFormat == gfx::SurfaceFormat::YUV) {
     const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
 
-    if (!mCompositor->SupportsEffect(EffectTypes::YCBCR)) {
+    if (!mProvider->SupportsEffect(EffectTypes::YCBCR)) {
       RefPtr<gfx::DataSourceSurface> surf =
         ImageDataSerializer::DataSourceSurfaceFromYCbCrDescriptor(buf, mDescriptor.get_YCbCrDescriptor());
       if (NS_WARN_IF(!surf)) {
         return false;
       }
       if (!mFirstSource) {
-        mFirstSource = mCompositor->CreateDataTextureSource(mFlags|TextureFlags::RGB_FROM_YCBCR);
+        mFirstSource = mProvider->CreateDataTextureSource(mFlags|TextureFlags::RGB_FROM_YCBCR);
         mFirstSource->SetOwner(this);
       }
       mFirstSource->Update(surf, aRegion);
       return true;
     }
 
     RefPtr<DataTextureSource> srcY;
     RefPtr<DataTextureSource> srcU;
     RefPtr<DataTextureSource> srcV;
     if (!mFirstSource) {
       // We don't support BigImages for YCbCr compositing.
-      srcY = mCompositor->CreateDataTextureSource(mFlags|TextureFlags::DISALLOW_BIGIMAGE);
-      srcU = mCompositor->CreateDataTextureSource(mFlags|TextureFlags::DISALLOW_BIGIMAGE);
-      srcV = mCompositor->CreateDataTextureSource(mFlags|TextureFlags::DISALLOW_BIGIMAGE);
+      srcY = mProvider->CreateDataTextureSource(mFlags|TextureFlags::DISALLOW_BIGIMAGE);
+      srcU = mProvider->CreateDataTextureSource(mFlags|TextureFlags::DISALLOW_BIGIMAGE);
+      srcV = mProvider->CreateDataTextureSource(mFlags|TextureFlags::DISALLOW_BIGIMAGE);
       mFirstSource = srcY;
       mFirstSource->SetOwner(this);
       srcY->SetNextSibling(srcU);
       srcU->SetNextSibling(srcV);
     } else {
       // mFormat never changes so if this was created as a YCbCr host and already
       // contains a source it should already have 3 sources.
       // BufferTextureHost only uses DataTextureSources so it is safe to assume
@@ -920,17 +906,17 @@ BufferTextureHost::Upload(nsIntRegion *a
         !srcV->Update(tempCr)) {
       NS_WARNING("failed to update the DataTextureSource");
       return false;
     }
   } else {
     // non-YCbCr case
     nsIntRegion* regionToUpdate = aRegion;
     if (!mFirstSource) {
-      mFirstSource = mCompositor->CreateDataTextureSource(mFlags);
+      mFirstSource = mProvider->CreateDataTextureSource(mFlags);
       mFirstSource->SetOwner(this);
       if (mFlags & TextureFlags::COMPONENT_ALPHA) {
         // Update the full region the first time for component alpha textures.
         regionToUpdate = nullptr;
       }
     }
 
     RefPtr<gfx::DataSourceSurface> surf =
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -129,17 +129,17 @@ public:
   virtual WrappingTextureSourceYCbCrBasic* AsWrappingTextureSourceYCbCrBasic() { return nullptr; }
 
   /**
    * Overload this if the TextureSource supports big textures that don't fit in
    * one device texture and must be tiled internally.
    */
   virtual BigImageIterator* AsBigImageIterator() { return nullptr; }
 
-  virtual void SetCompositor(Compositor* aCompositor) {}
+  virtual void SetTextureSourceProvider(TextureSourceProvider* aProvider) {}
 
   virtual void Unbind() {}
 
   void SetNextSibling(TextureSource* aTexture) { mNextSibling = aTexture; }
 
   TextureSource* GetNextSibling() const { return mNextSibling; }
 
   /**
@@ -446,23 +446,25 @@ public:
    * upload for example.
    *
    * @param aRegion The region that has been changed, if nil, it means that the
    * entire surface should be updated.
    */
    void Updated(const nsIntRegion* aRegion = nullptr);
 
   /**
-   * Sets this TextureHost's compositor.
-   * A TextureHost can change compositor on certain occasions, in particular if
-   * it belongs to an async Compositable.
+   * Sets this TextureHost's compositor. A TextureHost can change compositor
+   * on certain occasions, in particular if it belongs to an async Compositable.
    * aCompositor can be null, in which case the TextureHost must cleanup  all
-   * of it's device textures.
+   * of its device textures.
+   *
+   * Setting mProvider from this callback implicitly causes the texture to
+   * be locked for an extra frame after being detached from a compositable.
    */
-  virtual void SetCompositor(Compositor* aCompositor) {}
+  virtual void SetTextureSourceProvider(TextureSourceProvider* aProvider) {}
 
   /**
    * Should be overridden in order to deallocate the data that is associated
    * with the rendering backend, such as GL textures.
    */
   virtual void DeallocateDeviceData() {}
 
   /**
@@ -576,18 +578,16 @@ public:
   void SetLastFwdTransactionId(uint64_t aTransactionId);
 
   void DeserializeReadLock(const ReadLockDescriptor& aDesc,
                            ISurfaceAllocator* aAllocator);
   void SetReadLock(TextureReadLock* aReadLock);
 
   TextureReadLock* GetReadLock() { return mReadLock; }
 
-  virtual Compositor* GetCompositor() = 0;
-
   virtual BufferTextureHost* AsBufferTextureHost() { return nullptr; }
 
   virtual WebRenderTextureHost* AsWebRenderTextureHost() { return nullptr; }
 
 protected:
   void ReadUnlock();
 
   void RecycleTexture(TextureFlags aFlags);
@@ -598,24 +598,26 @@ protected:
    * Called when mCompositableCount becomes 0.
    */
   void NotifyNotUsed();
 
   // for Compositor.
   void CallNotifyNotUsed();
 
   PTextureParent* mActor;
+  RefPtr<TextureSourceProvider> mProvider;
   RefPtr<TextureReadLock> mReadLock;
   TextureFlags mFlags;
   int mCompositableCount;
   uint64_t mFwdTransactionId;
 
   friend class Compositor;
   friend class TextureParent;
   friend class TiledLayerBufferComposite;
+  friend class TextureSourceProvider;
 };
 
 /**
  * TextureHost that wraps a random access buffer such as a Shmem or some raw
  * memory.
  *
  * This TextureHost is backend-independent and the backend-specific bits are
  * in the TextureSource.
@@ -644,19 +646,17 @@ public:
   virtual void PrepareTextureSource(CompositableTextureSourceRef& aTexture) override;
 
   virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override;
 
   virtual void UnbindTextureSource() override;
 
   virtual void DeallocateDeviceData() override;
 
-  virtual void SetCompositor(Compositor* aCompositor) override;
-
-  virtual Compositor* GetCompositor() override { return mCompositor; }
+  virtual void SetTextureSourceProvider(TextureSourceProvider* aProvider) override;
 
   /**
    * 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).
    */
--- a/gfx/layers/composite/TiledContentHost.cpp
+++ b/gfx/layers/composite/TiledContentHost.cpp
@@ -52,24 +52,24 @@ TiledLayerBufferComposite::TiledLayerBuf
 {}
 
 TiledLayerBufferComposite::~TiledLayerBufferComposite()
 {
   Clear();
 }
 
 void
-TiledLayerBufferComposite::SetCompositor(Compositor* aCompositor)
+TiledLayerBufferComposite::SetTextureSourceProvider(TextureSourceProvider* aProvider)
 {
-  MOZ_ASSERT(aCompositor);
+  MOZ_ASSERT(aProvider);
   for (TileHost& tile : mRetainedTiles) {
     if (tile.IsPlaceholderTile()) continue;
-    tile.mTextureHost->SetCompositor(aCompositor);
+    tile.mTextureHost->SetTextureSourceProvider(aProvider);
     if (tile.mTextureHostOnWhite) {
-      tile.mTextureHostOnWhite->SetCompositor(aCompositor);
+      tile.mTextureHostOnWhite->SetTextureSourceProvider(aProvider);
     }
   }
 }
 
 void
 TiledLayerBufferComposite::AddAnimationInvalidation(nsIntRegion& aRegion)
 {
   // We need to invalidate rects where we have a tile that is in the
@@ -111,20 +111,20 @@ TiledContentHost::GenEffect(const gfx::S
   return CreateTexturedEffect(tile.mTextureSource,
                               nullptr,
                               aSamplingFilter,
                               true);
 }
 
 void
 TiledContentHost::Attach(Layer* aLayer,
-                         Compositor* aCompositor,
+                         TextureSourceProvider* aProvider,
                          AttachFlags aFlags /* = NO_FLAGS */)
 {
-  CompositableHost::Attach(aLayer, aCompositor, aFlags);
+  CompositableHost::Attach(aLayer, aProvider, aFlags);
 }
 
 void
 TiledContentHost::Detach(Layer* aLayer,
                          AttachFlags aFlags /* = NO_FLAGS */)
 {
   if (!mKeepAttached || aLayer == mLayer || aFlags & FORCE_DETACH) {
     // Clear the TiledLayerBuffers, which will take care of releasing the
@@ -163,17 +163,17 @@ UseTileTexture(CompositableTextureHostRe
                Compositor* aCompositor)
 {
   MOZ_ASSERT(aTexture);
   if (!aTexture) {
     return;
   }
 
   if (aCompositor) {
-    aTexture->SetCompositor(aCompositor);
+    aTexture->SetTextureSourceProvider(aCompositor);
   }
 
   if (!aUpdateRect.IsEmpty()) {
     // For !HasIntermediateBuffer() textures, this is likely a no-op.
     nsIntRegion region = aUpdateRect;
     aTexture->Updated(&region);
   }
 
@@ -294,17 +294,17 @@ TiledLayerBufferComposite::UseTiles(cons
         tileDesc.type() == TileDescriptor::TPlaceholderTileDescriptor,
         "Unrecognised tile descriptor type");
       continue;
     }
 
     const TexturedTileDescriptor& texturedDesc = tileDesc.get_TexturedTileDescriptor();
 
     tile.mTextureHost = TextureHost::AsTextureHost(texturedDesc.textureParent());
-    tile.mTextureHost->SetCompositor(aLayerManager->GetCompositor());
+    tile.mTextureHost->SetTextureSourceProvider(aLayerManager->GetCompositor());
     tile.mTextureHost->DeserializeReadLock(texturedDesc.sharedLock(), aAllocator);
 
     if (texturedDesc.textureOnWhite().type() == MaybeTexture::TPTextureParent) {
       tile.mTextureHostOnWhite = TextureHost::AsTextureHost(
         texturedDesc.textureOnWhite().get_PTextureParent()
       );
       tile.mTextureHostOnWhite->DeserializeReadLock(
         texturedDesc.sharedLockOnWhite(), aAllocator
@@ -384,26 +384,26 @@ TiledLayerBufferComposite::Clear()
   mRetainedTiles.Clear();
   mTiles.mFirst = TileIntPoint();
   mTiles.mSize = TileIntSize();
   mValidRegion = nsIntRegion();
   mResolution = 1.0;
 }
 
 void
-TiledContentHost::Composite(LayerComposite* aLayer,
+TiledContentHost::Composite(Compositor* aCompositor,
+                            LayerComposite* aLayer,
                             EffectChain& aEffectChain,
                             float aOpacity,
                             const gfx::Matrix4x4& aTransform,
                             const gfx::SamplingFilter aSamplingFilter,
                             const gfx::IntRect& aClipRect,
                             const nsIntRegion* aVisibleRegion /* = nullptr */,
                             const Maybe<gfx::Polygon>& aGeometry)
 {
-  MOZ_ASSERT(mCompositor);
   // Reduce the opacity of the low-precision buffer to make it a
   // little more subtle and less jarring. In particular, text
   // rendered at low-resolution and scaled tends to look pretty
   // heavy and this helps mitigate that. When we reduce the opacity
   // we also make sure to draw the background color behind the
   // reduced-opacity tile so that content underneath doesn't show
   // through.
   // However, in cases where the background is transparent, or the layer
@@ -433,28 +433,29 @@ TiledContentHost::Composite(LayerComposi
     // entire visible region's bounds, and we should draw it all in one quad
     // to avoid unexpected aliasing.
     tmpRegion = aVisibleRegion->GetBounds();
     renderRegion = &tmpRegion;
   }
 #endif
 
   // Render the low and high precision buffers.
-  RenderLayerBuffer(mLowPrecisionTiledBuffer,
+  RenderLayerBuffer(mLowPrecisionTiledBuffer, aCompositor,
                     lowPrecisionOpacityReduction < 1.0f ? &backgroundColor : nullptr,
                     aEffectChain, lowPrecisionOpacityReduction * aOpacity,
                     aSamplingFilter, aClipRect, *renderRegion, aTransform, aGeometry);
 
-  RenderLayerBuffer(mTiledBuffer, nullptr, aEffectChain, aOpacity, aSamplingFilter,
+  RenderLayerBuffer(mTiledBuffer, aCompositor, nullptr, aEffectChain, aOpacity, aSamplingFilter,
                     aClipRect, *renderRegion, aTransform, aGeometry);
 }
 
 
 void
 TiledContentHost::RenderTile(TileHost& aTile,
+                             Compositor* aCompositor,
                              EffectChain& aEffectChain,
                              float aOpacity,
                              const gfx::Matrix4x4& aTransform,
                              const gfx::SamplingFilter aSamplingFilter,
                              const gfx::IntRect& aClipRect,
                              const nsIntRegion& aScreenRegion,
                              const IntPoint& aTextureOffset,
                              const IntSize& aTextureBounds,
@@ -497,43 +498,40 @@ TiledContentHost::RenderTile(TileHost& a
     Rect textureRect(rect.x - aTextureOffset.x, rect.y - aTextureOffset.y,
                      rect.width, rect.height);
 
     effect->mTextureCoords = Rect(textureRect.x / aTextureBounds.width,
                                   textureRect.y / aTextureBounds.height,
                                   textureRect.width / aTextureBounds.width,
                                   textureRect.height / aTextureBounds.height);
 
-    mCompositor->DrawGeometry(graphicsRect, aClipRect, aEffectChain, opacity,
+    aCompositor->DrawGeometry(graphicsRect, aClipRect, aEffectChain, opacity,
                               aTransform, aVisibleRect, aGeometry);
   }
 
   DiagnosticFlags flags = DiagnosticFlags::CONTENT | DiagnosticFlags::TILE;
   if (aTile.mTextureHostOnWhite) {
     flags |= DiagnosticFlags::COMPONENT_ALPHA;
   }
-  mCompositor->DrawDiagnostics(flags,
+  aCompositor->DrawDiagnostics(flags,
                                aScreenRegion, aClipRect, aTransform, mFlashCounter);
 }
 
 void
 TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
+                                    Compositor* aCompositor,
                                     const Color* aBackgroundColor,
                                     EffectChain& aEffectChain,
                                     float aOpacity,
                                     const gfx::SamplingFilter aSamplingFilter,
                                     const gfx::IntRect& aClipRect,
                                     nsIntRegion aVisibleRegion,
                                     gfx::Matrix4x4 aTransform,
                                     const Maybe<Polygon>& aGeometry)
 {
-  if (!mCompositor) {
-    NS_WARNING("Can't render tiled content host - no compositor");
-    return;
-  }
   float resolution = aLayerBuffer.GetResolution();
   gfx::Size layerScale(1, 1);
 
   // We assume that the current frame resolution is the one used in our high
   // precision layer buffer. Compensate for a changing frame resolution when
   // rendering the low precision buffer.
   if (aLayerBuffer.GetFrameResolution() != mTiledBuffer.GetFrameResolution()) {
     const CSSToParentLayerScale2D& layerResolution = aLayerBuffer.GetFrameResolution();
@@ -574,17 +572,17 @@ TiledContentHost::RenderLayerBuffer(Tile
   if (aBackgroundColor) {
     nsIntRegion backgroundRegion = compositeRegion;
     backgroundRegion.ScaleRoundOut(resolution, resolution);
     EffectChain effect;
     effect.mPrimaryEffect = new EffectSolidColor(*aBackgroundColor);
     for (auto iter = backgroundRegion.RectIter(); !iter.Done(); iter.Next()) {
       const IntRect& rect = iter.Get();
       Rect graphicsRect(rect.x, rect.y, rect.width, rect.height);
-      mCompositor->DrawGeometry(graphicsRect, aClipRect, effect,
+      aCompositor->DrawGeometry(graphicsRect, aClipRect, effect,
                                 1.0, aTransform, aGeometry);
     }
   }
 
   for (size_t i = 0; i < aLayerBuffer.GetTileCount(); ++i) {
     TileHost& tile = aLayerBuffer.GetTile(i);
     if (tile.IsPlaceholderTile()) {
       continue;
@@ -598,32 +596,32 @@ TiledContentHost::RenderLayerBuffer(Tile
     nsIntRegion tileDrawRegion = IntRect(tileOffset, aLayerBuffer.GetScaledTileSize());
     tileDrawRegion.AndWith(compositeRegion);
 
     if (tileDrawRegion.IsEmpty()) {
       continue;
     }
 
     tileDrawRegion.ScaleRoundOut(resolution, resolution);
-    RenderTile(tile, aEffectChain, aOpacity,
+    RenderTile(tile, aCompositor, aEffectChain, aOpacity,
                aTransform, aSamplingFilter, aClipRect, tileDrawRegion,
                tileOffset * resolution, aLayerBuffer.GetTileSize(),
                gfx::Rect(visibleRect.x, visibleRect.y,
                          visibleRect.width, visibleRect.height),
                aGeometry);
 
     if (tile.mTextureHostOnWhite) {
       componentAlphaDiagnostic = DiagnosticFlags::COMPONENT_ALPHA;
     }
   }
 
   gfx::Rect rect(visibleRect.x, visibleRect.y,
                  visibleRect.width, visibleRect.height);
-  GetCompositor()->DrawDiagnostics(DiagnosticFlags::CONTENT | componentAlphaDiagnostic,
-                                   rect, aClipRect, aTransform, mFlashCounter);
+  aCompositor->DrawDiagnostics(DiagnosticFlags::CONTENT | componentAlphaDiagnostic,
+                               rect, aClipRect, aTransform, mFlashCounter);
 }
 
 void
 TiledContentHost::PrintInfo(std::stringstream& aStream, const char* aPrefix)
 {
   aStream << aPrefix;
   aStream << nsPrintfCString("TiledContentHost (0x%p)", this).get();
 
--- a/gfx/layers/composite/TiledContentHost.h
+++ b/gfx/layers/composite/TiledContentHost.h
@@ -131,17 +131,17 @@ public:
   void Clear();
 
   TileHost GetPlaceholderTile() const { return TileHost(); }
 
   // Stores the absolute resolution of the containing frame, calculated
   // by the sum of the resolutions of all parent layers' FrameMetrics.
   const CSSToParentLayerScale2D& GetFrameResolution() { return mFrameResolution; }
 
-  void SetCompositor(Compositor* aCompositor);
+  void SetTextureSourceProvider(TextureSourceProvider* aProvider);
 
   void AddAnimationInvalidation(nsIntRegion& aRegion);
 protected:
 
   CSSToParentLayerScale2D mFrameResolution;
 };
 
 /**
@@ -189,69 +189,71 @@ public:
     return mLowPrecisionTiledBuffer.GetValidRegion();
   }
 
   const nsIntRegion& GetValidRegion() const
   {
     return mTiledBuffer.GetValidRegion();
   }
 
-  virtual void SetCompositor(Compositor* aCompositor) override
+  virtual void SetTextureSourceProvider(TextureSourceProvider* aProvider) override
   {
-    MOZ_ASSERT(aCompositor);
-    CompositableHost::SetCompositor(aCompositor);
-    mTiledBuffer.SetCompositor(aCompositor);
-    mLowPrecisionTiledBuffer.SetCompositor(aCompositor);
+    CompositableHost::SetTextureSourceProvider(aProvider);
+    mTiledBuffer.SetTextureSourceProvider(aProvider);
+    mLowPrecisionTiledBuffer.SetTextureSourceProvider(aProvider);
   }
 
   bool UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
                            const SurfaceDescriptorTiles& aTiledDescriptor);
 
-  virtual void Composite(LayerComposite* aLayer,
+  virtual void Composite(Compositor* aCompositor,
+                         LayerComposite* aLayer,
                          EffectChain& aEffectChain,
                          float aOpacity,
                          const gfx::Matrix4x4& aTransform,
                          const gfx::SamplingFilter aSamplingFilter,
                          const gfx::IntRect& aClipRect,
                          const nsIntRegion* aVisibleRegion = nullptr,
                          const Maybe<gfx::Polygon>& aGeometry = Nothing()) override;
 
   virtual CompositableType GetType() override { return CompositableType::CONTENT_TILED; }
 
   virtual TiledContentHost* AsTiledContentHost() override { return this; }
 
   virtual void Attach(Layer* aLayer,
-                      Compositor* aCompositor,
+                      TextureSourceProvider* aProvider,
                       AttachFlags aFlags = NO_FLAGS) override;
 
   virtual void Detach(Layer* aLayer = nullptr,
                       AttachFlags aFlags = NO_FLAGS) override;
 
   virtual void Dump(std::stringstream& aStream,
                     const char* aPrefix="",
                     bool aDumpHtml=false) override;
 
   virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
 
   virtual void AddAnimationInvalidation(nsIntRegion& aRegion) override;
 
 private:
 
   void RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
+                         Compositor* aCompositor,
                          const gfx::Color* aBackgroundColor,
                          EffectChain& aEffectChain,
                          float aOpacity,
                          const gfx::SamplingFilter aSamplingFilter,
                          const gfx::IntRect& aClipRect,
                          nsIntRegion aMaskRegion,
                          gfx::Matrix4x4 aTransform,
                          const Maybe<gfx::Polygon>& aGeometry);
 
   // Renders a single given tile.
   void RenderTile(TileHost& aTile,
+                  Compositor* aCompositor,
                   EffectChain& aEffectChain,
                   float aOpacity,
                   const gfx::Matrix4x4& aTransform,
                   const gfx::SamplingFilter aSamplingFilter,
                   const gfx::IntRect& aClipRect,
                   const nsIntRegion& aScreenRegion,
                   const gfx::IntPoint& aTextureOffset,
                   const gfx::IntSize& aTextureBounds,
--- a/gfx/layers/composite/X11TextureHost.cpp
+++ b/gfx/layers/composite/X11TextureHost.cpp
@@ -53,21 +53,26 @@ X11TextureHost::Lock()
         return false;
     }
   }
 
   return true;
 }
 
 void
-X11TextureHost::SetCompositor(Compositor* aCompositor)
+X11TextureHost::SetTextureSourceProvider(TextureSourceProvider* aProvider)
 {
-  mCompositor = aCompositor;
+  mProvider = aProvider;
+  if (mProvider) {
+    mCompositor = mProvider->AsCompositor();
+  } else {
+    mCompositor = nullptr;
+  }
   if (mTextureSource) {
-    mTextureSource->SetCompositor(aCompositor);
+    mTextureSource->SetTextureSourceProvider(aProvider);
   }
 }
 
 SurfaceFormat
 X11TextureHost::GetFormat() const
 {
   gfxContentType type = mSurface->GetContentType();
 #ifdef GL_PROVIDER_GLX
--- a/gfx/layers/composite/X11TextureHost.h
+++ b/gfx/layers/composite/X11TextureHost.h
@@ -27,19 +27,17 @@ public:
 
 // TextureHost for Xlib-backed TextureSources.
 class X11TextureHost : public TextureHost
 {
 public:
   X11TextureHost(TextureFlags aFlags,
                  const SurfaceDescriptorX11& aDescriptor);
 
-  virtual void SetCompositor(Compositor* aCompositor) override;
-
-  virtual Compositor* GetCompositor() override { return mCompositor; }
+  virtual void SetTextureSourceProvider(TextureSourceProvider* aProvider) override;
 
   virtual bool Lock() override;
 
   virtual gfx::SurfaceFormat GetFormat() const override;
 
   virtual gfx::IntSize GetSize() const override;
 
   virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -997,18 +997,24 @@ CompositorD3D11::DrawGeometry(const Geom
     }
 
     ID3D11ShaderResourceView* srView = source->GetShaderResourceView();
     mContext->PSSetShaderResources(TexSlot::Mask, 1, &srView);
 
     const gfx::Matrix4x4& maskTransform = maskEffect->mMaskTransform;
     NS_ASSERTION(maskTransform.Is2D(), "How did we end up with a 3D transform here?!");
     Rect bounds = Rect(Point(), Size(maskEffect->mSize));
+    bounds = maskTransform.As2D().TransformBounds(bounds);
 
-    mVSConstants.maskQuad = maskTransform.As2D().TransformBounds(bounds);
+    Matrix4x4 transform;
+    transform._11 = 1.0f / bounds.width;
+    transform._22 = 1.0f / bounds.height;
+    transform._41 = float(-bounds.x) / bounds.width;
+    transform._42 = float(-bounds.y) / bounds.height;
+    memcpy(mVSConstants.maskTransform, &transform._11, 64);
   }
 
   D3D11_RECT scissor;
 
   IntRect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
   if (mCurrentRT == mDefaultRT) {
     clipRect = clipRect.Intersect(mCurrentClip);
   }
--- a/gfx/layers/d3d11/CompositorD3D11.h
+++ b/gfx/layers/d3d11/CompositorD3D11.h
@@ -21,17 +21,17 @@ namespace layers {
 
 struct VertexShaderConstants
 {
   float layerTransform[4][4];
   float projection[4][4];
   float renderTargetOffset[4];
   gfx::Rect textureCoords;
   gfx::Rect layerQuad;
-  gfx::Rect maskQuad;
+  float maskTransform[4][4];
   float backdropTransform[4][4];
 };
 
 struct PixelShaderConstants
 {
   float layerColor[4];
   float layerOpacity[4];
   int blendConfig[4];
@@ -134,16 +134,19 @@ public:
 #endif
 
   virtual LayersBackend GetBackendType() const override {
     return LayersBackend::LAYERS_D3D11;
   }
 
   virtual void ForcePresent();
 
+  // For TextureSourceProvider.
+  ID3D11Device* GetD3D11Device() const override { return mDevice; }
+
   ID3D11Device* GetDevice() { return mDevice; }
 
   ID3D11DeviceContext* GetDC() { return mContext; }
 
 private:
   enum Severity {
     Recoverable,
     DebugAssert,
--- a/gfx/layers/d3d11/CompositorD3D11.hlsl
+++ b/gfx/layers/d3d11/CompositorD3D11.hlsl
@@ -8,18 +8,18 @@
 
 typedef float4 rect;
 
 float4x4 mLayerTransform : register(vs, c0);
 float4x4 mProjection : register(vs, c4);
 float4 vRenderTargetOffset : register(vs, c8);
 rect vTextureCoords : register(vs, c9);
 rect vLayerQuad : register(vs, c10);
-rect vMaskQuad : register(vs, c11);
-float4x4 mBackdropTransform : register(vs, c12);
+float4x4 mMaskTransform : register(vs, c11);
+float4x4 mBackdropTransform : register(vs, c15);
 
 float4 fLayerColor : register(ps, c0);
 float fLayerOpacity : register(ps, c1);
 
 // x = layer type
 // y = mask type
 // z = blend op
 // w = is premultiplied
@@ -139,39 +139,37 @@ VS_OUTPUT LayerQuadVS(const VS_INPUT aVe
   float4 position = TransformedPosition(aVertex.vPosition);
 
   outp.vPosition = VertexPosition(position);
   outp.vTexCoords = TexCoords(aVertex.vPosition.xy);
 
   return outp;
 }
 
-VS_MASK_OUTPUT LayerQuadMaskVS(const VS_INPUT aVertex)
+float3 MaskCoords(float4 aPosition)
 {
-  VS_MASK_OUTPUT outp;
-  float4 position = TransformedPosition(aVertex.vPosition);
-
-  outp.vPosition = VertexPosition(position);
-
-  // calculate the position on the mask texture
-  outp.vMaskCoords.x = (position.x - vMaskQuad.x) / vMaskQuad.z;
-  outp.vMaskCoords.y = (position.y - vMaskQuad.y) / vMaskQuad.w;
   // We use the w coord to do non-perspective correct interpolation:
   // the quad might be transformed in 3D, in which case it will have some
   // perspective. The graphics card will do perspective-correct interpolation
   // of the texture, but our mask is already transformed and so we require
   // linear interpolation. Therefore, we must correct the interpolation
   // ourselves, we do this by multiplying all coords by w here, and dividing by
   // w in the pixel shader (post-interpolation), we pass w in outp.vMaskCoords.z.
   // See http://en.wikipedia.org/wiki/Texture_mapping#Perspective_correctness
-  outp.vMaskCoords.z = 1;
-  outp.vMaskCoords *= position.w;
+  return float3(mul(mMaskTransform, (aPosition / aPosition.w)).xy, 1.0) * aPosition.w;
+}
 
+VS_MASK_OUTPUT LayerQuadMaskVS(const VS_INPUT aVertex)
+{
+  float4 position = TransformedPosition(aVertex.vPosition);
+
+  VS_MASK_OUTPUT outp;
+  outp.vPosition = VertexPosition(position);
+  outp.vMaskCoords = MaskCoords(position);
   outp.vTexCoords = TexCoords(aVertex.vPosition.xy);
-
   return outp;
 }
 
 VS_OUTPUT LayerDynamicVS(const VS_TEX_INPUT aVertex)
 {
   VS_OUTPUT outp;
 
   float4 position = float4(aVertex.vPosition, 0, 1);
@@ -187,23 +185,18 @@ VS_MASK_OUTPUT LayerDynamicMaskVS(const 
 {
   VS_MASK_OUTPUT outp;
 
   float4 position = float4(aVertex.vPosition, 0, 1);
   position = mul(mLayerTransform, position);
   outp.vPosition = VertexPosition(position);
 
   // calculate the position on the mask texture
-  outp.vMaskCoords.x = (position.x - vMaskQuad.x) / vMaskQuad.z;
-  outp.vMaskCoords.y = (position.y - vMaskQuad.y) / vMaskQuad.w;
-  outp.vMaskCoords.z = 1;
-  outp.vMaskCoords *= position.w;
-
+  outp.vMaskCoords = MaskCoords(position);
   outp.vTexCoords = aVertex.vTexCoords;
-
   return outp;
 }
 
 float4 RGBAShaderMask(const VS_MASK_OUTPUT aVertex) : SV_Target
 {
   float2 maskCoords = aVertex.vMaskCoords.xy / aVertex.vMaskCoords.z;
   float mask = tMask.Sample(sSampler, maskCoords).r;
   return tRGB.Sample(sSampler, aVertex.vTexCoords) * fLayerOpacity * mask;
--- a/gfx/layers/d3d11/CompositorD3D11Shaders.h
+++ b/gfx/layers/d3d11/CompositorD3D11Shaders.h
@@ -1,39 +1,39 @@
 struct ShaderBytes { const void* mData; size_t mLength; };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 10.1
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4x4 mLayerTransform;          // Offset:    0 Size:    64
 //   float4x4 mProjection;              // Offset:   64 Size:    64
 //   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]
+//   float4x4 mMaskTransform;           // Offset:  176 Size:    64 [unused]
+//   float4x4 mBackdropTransform;       // Offset:  240 Size:    64 [unused]
+//   float4 fLayerColor;                // Offset:  304 Size:    16 [unused]
+//   float fLayerOpacity;               // Offset:  320 Size:     4 [unused]
+//   uint4 iBlendConfig;                // Offset:  336 Size:    16 [unused]
+//   row_major float3x3 mYuvColorMatrix;// Offset:  352 Size:    44 [unused]
 //
 // }
 //
 //
 // Resource Bindings:
 //
-// Name                                 Type  Format         Dim Slot Elements
-// ------------------------------ ---------- ------- ----------- ---- --------
-// $Globals                          cbuffer      NA          NA    0        1
+// Name                                 Type  Format         Dim      HLSL Bind  Count
+// ------------------------------ ---------- ------- ----------- -------------- ------
+// $Globals                          cbuffer      NA          NA            cb0      1 
 //
 //
 //
 // Input signature:
 //
 // Name                 Index   Mask Register SysValue  Format   Used
 // -------------------- ----- ------ -------- -------- ------- ------
 // POSITION                 0   xy          0     NONE   float   xy  
@@ -79,17 +79,17 @@ struct ShaderBytes { const void* mData; 
     mad r1, c4, r0.x, r1
     mad r1, c6, r0.z, r1
     mad r0, c7, r0.w, r1
     mad oPos.xy, r0.w, c0, r0
     mov oPos.zw, r0
 
 // approximately 15 instruction slots used
 vs_4_0
-dcl_constantbuffer cb0[11], immediateIndexed
+dcl_constantbuffer CB0[11], immediateIndexed
 dcl_input v0.xy
 dcl_output_siv o0.xyzw, position
 dcl_output o1.xy
 dcl_temps 2
 mad r0.xy, v0.xyxx, cb0[10].zwzz, cb0[10].xyxx
 mul r1.xyzw, r0.yyyy, cb0[1].xyzw
 mad r0.xyzw, cb0[0].xyzw, r0.xxxx, r1.xyzw
 add r0.xyzw, r0.xyzw, cb0[3].xyzw
@@ -102,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, 169, 137, 
-    186,  74,  85, 148,   0, 249, 
-    101, 235, 214,  10,  35,  11, 
-    230, 137,   1,   0,   0,   0, 
-     80,   7,   0,   0,   6,   0, 
+     68,  88,  66,  67, 158, 249, 
+    155,   4, 180, 205,  12, 198, 
+     13, 145, 179,  10, 107, 120, 
+    251,  61,   1,   0,   0,   0, 
+     72,   7,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     152,   1,   0,   0, 160,   3, 
       0,   0,  28,   4,   0,   0, 
-    196,   6,   0,   0, 248,   6, 
+    188,   6,   0,   0, 240,   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, 
@@ -278,31 +278,31 @@ 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, 
-    160,   2,   0,   0,   1,   0, 
+    152,   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, 108,   2, 
+      0,   1,   0,   0, 112,   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,  11,   0,   0,   0, 
-     96,   0,   0,   0,  96,   1, 
+     96,   0,   0,   0, 144,   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, 120,   1,   0,   0, 
       0,   0,   0,   0, 136,   1, 
       0,   0,  64,   0,   0,   0, 
      64,   0,   0,   0,   2,   0, 
@@ -316,38 +316,38 @@ const BYTE LayerQuadVS[] =
      16,   0,   0,   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, 200,   1,   0,   0, 
       0,   0,   0,   0, 227,   1, 
       0,   0, 176,   0,   0,   0, 
-     16,   0,   0,   0,   0,   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, 120,   1,   0,   0, 
-      0,   0,   0,   0,   0,   2, 
-      0,   0,   0,   1,   0,   0, 
+      0,   0,   0,   0, 242,   1, 
+      0,   0, 240,   0,   0,   0, 
+     64,   0,   0,   0,   0,   0, 
+      0,   0, 120,   1,   0,   0, 
+      0,   0,   0,   0,   5,   2, 
+      0,   0,  48,   1,   0,   0, 
      16,   0,   0,   0,   0,   0, 
       0,   0, 168,   1,   0,   0, 
-      0,   0,   0,   0,  12,   2, 
-      0,   0,  16,   1,   0,   0, 
+      0,   0,   0,   0,  17,   2, 
+      0,   0,  64,   1,   0,   0, 
       4,   0,   0,   0,   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,  60,   2,   0,   0, 
-      0,   0,   0,   0,  76,   2, 
-      0,   0,  48,   1,   0,   0, 
+      0,   0,  32,   2,   0,   0, 
+      0,   0,   0,   0,  48,   2, 
+      0,   0,  80,   1,   0,   0, 
+     16,   0,   0,   0,   0,   0, 
+      0,   0,  64,   2,   0,   0, 
+      0,   0,   0,   0,  80,   2, 
+      0,   0,  96,   1,   0,   0, 
      44,   0,   0,   0,   0,   0, 
-      0,   0,  92,   2,   0,   0, 
+      0,   0,  96,   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, 
@@ -359,94 +359,93 @@ const BYTE LayerQuadVS[] =
       0,   0,   0,   0,   0,   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, 
-    102,  76,  97, 121, 101, 114, 
-     67, 111, 108, 111, 114,   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, 
-     77, 105,  99, 114, 111, 115, 
-    111, 102, 116,  32,  40,  82, 
-     41,  32,  72,  76,  83,  76, 
-     32,  83, 104,  97, 100, 101, 
-    114,  32,  67, 111, 109, 112, 
-    105, 108, 101, 114,  32,  54, 
-     46,  51,  46,  57,  54,  48, 
-     48,  46,  49,  54,  51,  56, 
-     52,   0, 171, 171,  73,  83, 
-     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, 109,  77,  97, 115, 107, 
+     84, 114,  97, 110, 115, 102, 
+    111, 114, 109,   0, 109,  66, 
+     97,  99, 107, 100, 114, 111, 
+    112,  84, 114,  97, 110, 115, 
+    102, 111, 114, 109,   0, 102, 
+     76,  97, 121, 101, 114,  67, 
+    111, 108, 111, 114,   0, 102, 
+     76,  97, 121, 101, 114,  79, 
+    112,  97,  99, 105, 116, 121, 
+      0, 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,  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, 
-     56,   0,   0,   0,   0,   0, 
-      0,   0,   1,   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,  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,   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
 };
 ShaderBytes sLayerQuadVS = { LayerQuadVS, sizeof(LayerQuadVS) };
 #if 0
 //
-// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384
+// Generated by Microsoft (R) HLSL Shader Compiler 10.1
 //
 //
 // Buffer Definitions: 
 //
 // cbuffer $Globals
 // {
 //
 //   float4x4 mLayerTransform;          // Offset:    0 Size:    64
 //   float4x4 mProjection;              // Offset:   64 Size:    64
 //   float4 vRenderTargetOffset;        // Offset:  128 Size:    16
 //   float4 vTextureCoords;             // Offset:  144 Size:    16 [unused]
 //   float4 vLayerQuad;                 // Offset:  160 Size:    16 [unused]
-//   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]
+//   float4x4 mMaskTransform;           // Offset:  176 Size:    64 [unused]
+//   float4x4 mBackdropTransform;       // Offset:  240 Size:    64 [unused]
+//   float4 fLayerColor;                // Offset:  304 Size:    16 [unused]
+//   float fLayerOpacity;               // Offset:  320 Size:     4 [unused]
+//   uint4 iBlendConfig;                // Offset:  336 Size:    16 [unused]
+//   row_major float3x3 mYuvColorMatrix;// Offset:  352 Size:    44 [unused]
 //
 // }
 //
 //
 // Resource Bindings:
 //
 // Name                                 Type  Format         Dim      HLSL Bind  Count
 // ------------------------------ ---------- ------- ----------- -------------- ------
@@ -525,25 +524,25 @@ mad r1.xyzw, cb0[6].xyzw, r0.zzzz, r1.xy
 mad o0.xyzw, cb0[7].xyzw, r0.wwww, r1.xyzw
 mov o1.xy, v1.xyxx
 ret 
 // Approximately 12 instruction slots used
 #endif
 
 const BYTE LayerDynamicVS[] =
 {
-     68,  88,  66,  67, 139,  89, 
-    202,  51, 215,  17, 235, 234, 
-    105,  39,  39, 230, 117, 232, 
-    111, 184,   1,   0,   0,   0, 
-     28,   7,   0,   0,   6,   0, 
+     68,  88,  66,  67,  11,  85, 
+      4, 119,  93, 228, 195, 201, 
+     22,  72, 173, 198,  47,  25, 
+    227, 199,   1,   0,   0,   0, 
+     32,   7,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     136,   1,   0,   0,  88,   3, 
       0,   0, 212,   3,   0,   0, 
-    112,   6,   0,   0, 196,   6, 
+    116,   6,   0,   0, 200,   6, 
       0,   0,  65, 111, 110,  57, 
      72,   1,   0,   0,  72,   1, 
       0,   0,   0,   2, 254, 255, 
       8,   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, 
@@ -689,31 +688,31 @@ const BYTE LayerDynamicVS[] =
       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, 
-    148,   2,   0,   0,   1,   0, 
+    152,   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, 108,   2, 
+      0,   1,   0,   0, 112,   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,  11,   0,   0,   0, 
-     96,   0,   0,   0,  96,   1, 
+     96,   0,   0,   0, 144,   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, 120,   1,   0,   0, 
       0,   0,   0,   0, 136,   1, 
       0,   0,  64,   0,   0,   0, 
      64,   0,   0,   0,   2,   0, 
@@ -727,38 +726,38 @@ const BYTE LayerDynamicVS[] =
      16,   0,   0,   0,   0,   0, 
       0,   0, 200,   1,   0,   0, 
       0,   0,   0,   0, 216,   1, 
       0,   0, 160,   0,   0,   0, 
      16,   0,   0,   0,   0,   0, 
       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, 200,   1,   0,   0, 
-      0,   0,   0,   0, 237,   1, 
-      0,   0, 192,   0,   0,   0, 
      64,   0,   0,   0,   0,   0, 
       0,   0, 120,   1,   0,   0, 
-      0,   0,   0,   0,   0,   2, 
-      0,   0,   0,   1,   0,   0, 
+      0,   0,   0,   0, 242,   1, 
+      0,   0, 240,   0,   0,   0, 
+     64,   0,   0,   0,   0,   0, 
+      0,   0, 120,   1,   0,   0, 
+      0,   0,   0,   0,   5,   2, 
+      0,   0,  48,   1,   0,   0, 
      16,   0,   0,   0,   0,   0, 
       0,   0, 168,   1,   0,   0, 
-      0,   0,   0,   0,  12,   2, 
-      0,   0,  16,   1,   0,   0, 
+      0,   0,   0,   0,  17,   2, 
+      0,   0,  64,   1,   0,   0, 
       4,   0,   0,   0,   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,  60,   2,   0,   0, 
-      0,   0,   0,   0,  76,   2, 
-      0,   0,  48,   1,   0,   0, 
+      0,   0,  32,   2,   0,   0, 
+      0,   0,   0,   0,  48,   2, 
+      0,   0,  80,   1,   0,   0, 
+     16,   0,   0,   0,   0,   0, 
+      0,   0,  64,   2,   0,   0, 
+      0,   0,   0,   0,  80,   2, 
+      0,   0,  96,   1,   0,   0, 
      44,   0,   0,   0,   0,   0, 
-      0,   0,  92,   2,   0,   0, 
+      0,   0,  96,   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, 
@@ -770,75 +769,75 @@ const BYTE LayerDynamicVS[] =
       0,   0,   0,   0,   0,   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, 
-    102,  76,  97, 121, 101, 114, 
-     67, 111, 108, 111, 114,   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, 
-     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,  76,   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,   3,   3, 
-      0,   0,  65,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   3,   0,   0,   0, 
-      1,   0,   0,   0,   3,   3, 
-      0,   0,  80,  79,  83,  73, 
-     84,  73,  79,  78,   0,  84, 
-     69,  88,  67,  79,  79,  82, 
-     68,   0, 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, 109,  77,  97, 115, 107, 
+     84, 114,  97, 110, 115, 102, 
+    111, 114, 109,   0, 109,  66, 
+     97,  99, 107, 100, 114, 111, 
+    112,  84, 114,  97, 110, 115, 
+    102, 111, 114, 109,   0, 102, 
+     76,  97, 121, 101, 114,  67, 
+    111, 108, 111, 114,   0, 102, 
+     76,  97, 121, 101, 114,  79, 
+    112,  97,  99, 105, 116, 121, 
+      0, 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,  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, 
+     76,   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,   3,   3,   0,   0, 
+     65,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      3,   0,   0,   0,   1,   0, 
+      0,   0,   3,   3,   0,   0, 
+     80,  79,  83,  73,  84,  73, 
+     79,  78,   0,  84,  69,  88, 
+     67,  79,  79,  82,  68,   0, 
+    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
 };
 ShaderBytes sLayerDynamicVS = { LayerDynamicVS, sizeof(LayerDynamicVS) };
 #if 0
 //
 // Generated by Microsoft (R) HLSL Shader Compiler 10.1
 //
 //
 // Buffer Definitions: 
@@ -850,27 +849,27 @@ ShaderBytes sLayerDynamicVS = { LayerDyn
 //   float fLayerOpacity;               // Offset:   16 Size:     4 [unused]
 //   uint4 iBlendConfig;                // Offset:   32 Size:    16 [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]
+//   float4x4 mMaskTransform;           // Offset:  272 Size:    64 [unused]
+//   float4x4 mBackdropTransform;       // Offset:  336 Size:    64 [unused]
 //
 // }
 //
 //
 // Resource Bindings:
 //
-// Name                                 Type  Format         Dim Slot Elements
-// ------------------------------ ---------- ------- ----------- ---- --------
-// $Globals                          cbuffer      NA          NA    0        1
+// Name                                 Type  Format         Dim      HLSL Bind  Count
+// ------------------------------ ---------- ------- ----------- -------------- ------
+// $Globals                          cbuffer      NA          NA            cb0      1 
 //
 //
 //
 // Input signature:
 //
 // Name                 Index   Mask Register SysValue  Format   Used
 // -------------------- ----- ------ -------- -------- ------- ------
 // SV_Position              0   xyzw        0      POS   float       
@@ -893,34 +892,34 @@ ShaderBytes sLayerDynamicVS = { LayerDyn
 //
 // Level9 shader bytecode:
 //
     ps_2_x
     mov oC0, c0
 
 // approximately 1 instruction slot used
 ps_4_0
-dcl_constantbuffer cb0[1], immediateIndexed
+dcl_constantbuffer CB0[1], immediateIndexed
 dcl_output o0.xyzw
 mov o0.xyzw, cb0[0].xyzw
 ret 
 // Approximately 2 instruction slots used
 #endif
 
 const BYTE SolidColorShader[] =
 {
-     68,  88,  66,  67, 156,  36, 
-     85, 115, 249,   2,  97, 236, 
-    182, 204,  98, 136, 164, 213, 
-    133, 234,   1,   0,   0,   0, 
-    124,   4,   0,   0,   6,   0, 
+     68,  88,  66,  67,  31,  16, 
+     81, 179, 243, 141, 148, 255, 
+     60,  11,  92, 171,  28,  14, 
+    237, 203,   1,   0,   0,   0, 
+    120,   4,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     132,   0,   0,   0, 204,   0, 
       0,   0,  72,   1,   0,   0, 
-    240,   3,   0,   0,  72,   4, 
+    236,   3,   0,   0,  68,   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, 
@@ -957,32 +956,32 @@ 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, 160,   2,   0,   0, 
+     69,  70, 156,   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, 
-    108,   2,   0,   0,  60,   0, 
+    113,   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,  11,   0, 
       0,   0,  96,   0,   0,   0, 
-     96,   1,   0,   0,   0,   0, 
+    144,   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, 116,   1, 
       0,   0,   0,   0,   0,   0, 
     132,   1,   0,   0,  16,   0, 
       0,   0,   4,   0,   0,   0, 
       0,   0,   0,   0, 148,   1, 
@@ -1011,20 +1010,20 @@ const BYTE SolidColorShader[] =
       0,   0,  16,   0,   0,   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,  52,   2, 
       0,   0,   0,   0,   0,   0, 
      79,   2,   0,   0,  16,   1, 
-      0,   0,  16,   0,   0,   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, 244,   1, 
+      0,   0,   0,   0,   0,   0, 
+     94,   2,   0,   0,  80,   1, 
       0,   0,  64,   0,   0,   0, 
       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, 
@@ -1056,88 +1055,87 @@ const BYTE SolidColorShader[] =
     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,  54,  46,  51,  46,  57, 
-     54,  48,  48,  46,  49,  54, 
-     51,  56,  52,   0, 171, 171, 
-     73,  83,  71,  78,  80,   0, 
-      0,   0,   2,   0,   0,   0, 
-      8,   0,   0,   0,  56,   0, 
-      0,   0,   0,   0,   0,   0, 
-      1,   0,   0,   0,   3,   0, 
-      0,   0,   0,   0,   0,   0, 
-     15,   0,   0,   0,  68,   0, 
+     97, 100,   0, 109,  77,  97, 
+    115, 107,  84, 114,  97, 110, 
+    115, 102, 111, 114, 109,   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, 171, 
+    171, 171,  73,  83,  71,  78, 
+     80,   0,   0,   0,   2,   0, 
+      0,   0,   8,   0,   0,   0, 
+     56,   0,   0,   0,   0,   0, 
+      0,   0,   1,   0,   0,   0, 
+      3,   0,   0,   0,   0,   0, 
+      0,   0,  15,   0,   0,   0, 
+     68,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   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,   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,   0,   0,   0,   0, 
+     15,   0,   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 6.3.9600.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]
 //   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]
+//   float4x4 mMaskTransform;           // Offset:  272 Size:    64 [unused]
+//   float4x4 mBackdropTransform;       // Offset:  336 Size:    64 [unused]
 //
 // }
 //
 //
 // Resource Bindings:
 //
-// Name                                 Type  Format         Dim Slot Elements
-// ------------------------------ ---------- ------- ----------- ---- --------
-// sSampler                          sampler      NA          NA    0        1
-// tRGB                              texture  float4          2d    0        1
-// $Globals                          cbuffer      NA          NA    0        1
+// Name                                 Type  Format         Dim      HLSL Bind  Count
+// ------------------------------ ---------- ------- ----------- -------------- ------
+// sSampler                          sampler      NA          NA             s0      1 
+// tRGB                              texture  float4          2d             t0      1 
+// $Globals                          cbuffer      NA          NA            cb0      1 
 //
 //
 //
 // Input signature:
 //
 // Name                 Index   Mask Register SysValue  Format   Used
 // -------------------- ----- ------ -------- -------- ------- ------
 // SV_Position              0   xyzw        0      POS   float       
@@ -1172,40 +1170,40 @@ ShaderBytes sSolidColorShader = { SolidC
     dcl_2d s0
     texld r0, t0, s0
     mul r0.xyz, r0, c0.x
     mov r0.w, c0.x
     mov oC0, r0
 
 // approximately 4 instruction slots used (1 texture, 3 arithmetic)
 ps_4_0
-dcl_constantbuffer cb0[2], immediateIndexed
+dcl_constantbuffer CB0[2], immediateIndexed
 dcl_sampler s0, mode_default
 dcl_resource_texture2d (float,float,float,float) t0
 dcl_input_ps linear v1.xy
 dcl_output o0.xyzw
 dcl_temps 1
 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, 160,  15, 
-    174, 178, 100, 241,  44,  13, 
-    161, 155, 205,  21,  72, 246, 
-    233,  55,   1,   0,   0,   0, 
-    132,   5,   0,   0,   6,   0, 
+     68,  88,  66,  67,  26, 170, 
+     86, 163,  31,  89, 148,  91, 
+    161,  88, 174, 193, 214,  13, 
+    132, 225,   1,   0,   0,   0, 
+    128,   5,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     204,   0,   0,   0, 136,   1, 
       0,   0,   4,   2,   0,   0, 
-    248,   4,   0,   0,  80,   5, 
+    244,   4,   0,   0,  76,   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, 
@@ -1273,22 +1271,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, 236,   2, 
+     82,  68,  69,  70, 232,   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, 184,   2,   0,   0, 
+      0,   0, 189,   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, 
@@ -1301,17 +1299,17 @@ const BYTE RGBShader[] =
       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,  11,   0, 
       0,   0, 172,   0,   0,   0, 
-     96,   1,   0,   0,   0,   0, 
+    144,   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, 192,   1, 
       0,   0,   0,   0,   0,   0, 
     208,   1,   0,   0,  16,   0, 
       0,   0,   4,   0,   0,   0, 
       2,   0,   0,   0, 224,   1, 
@@ -1340,20 +1338,20 @@ const BYTE RGBShader[] =
       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, 
+    170,   2,   0,   0,  80,   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, 
@@ -1385,88 +1383,87 @@ const BYTE RGBShader[] =
     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,  54,  46,  51,  46,  57, 
-     54,  48,  48,  46,  49,  54, 
-     51,  56,  52,   0, 171, 171, 
-     73,  83,  71,  78,  80,   0, 
-      0,   0,   2,   0,   0,   0, 
-      8,   0,   0,   0,  56,   0, 
-      0,   0,   0,   0,   0,   0, 
-      1,   0,   0,   0,   3,   0, 
-      0,   0,   0,   0,   0,   0, 
-     15,   0,   0,   0,  68,   0, 
+     97, 100,   0, 109,  77,  97, 
+    115, 107,  84, 114,  97, 110, 
+    115, 102, 111, 114, 109,   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, 171, 
+    171, 171,  73,  83,  71,  78, 
+     80,   0,   0,   0,   2,   0, 
+      0,   0,   8,   0,   0,   0, 
+     56,   0,   0,   0,   0,   0, 
+      0,   0,   1,   0,   0,   0, 
+      3,   0,   0,   0,   0,   0, 
+      0,   0,  15,   0,   0,   0, 
+     68,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   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,   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,   0,   0,   0,   0, 
+     15,   0,   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 6.3.9600.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]
 //   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]
+//   float4x4 mMaskTransform;           // Offset:  272 Size:    64 [unused]
+//   float4x4 mBackdropTransform;       // Offset:  336 Size:    64 [unused]
 //
 // }
 //
 //
 // Resource Bindings:
 //
-// Name                                 Type  Format         Dim Slot Elements
-// ------------------------------ ---------- ------- ----------- ---- --------
-// sSampler                          sampler      NA          NA    0        1
-// tRGB                              texture  float4          2d    0        1
-// $Globals                          cbuffer      NA          NA    0        1
+// Name                                 Type  Format         Dim      HLSL Bind  Count
+// ------------------------------ ---------- ------- ----------- -------------- ------
+// sSampler                          sampler      NA          NA             s0      1 
+// tRGB                              texture  float4          2d             t0      1 
+// $Globals                          cbuffer      NA          NA            cb0      1 
 //
 //
 //
 // Input signature:
 //
 // Name                 Index   Mask Register SysValue  Format   Used
 // -------------------- ----- ------ -------- -------- ------- ------
 // SV_Position              0   xyzw        0      POS   float       
@@ -1500,39 +1497,39 @@ ShaderBytes sRGBShader = { RGBShader, si
     dcl t0.xy
     dcl_2d s0
     texld r0, t0, s0
     mul r0, r0, c0.x
     mov oC0, r0
 
 // approximately 3 instruction slots used (1 texture, 2 arithmetic)
 ps_4_0
-dcl_constantbuffer cb0[2], immediateIndexed
+dcl_constantbuffer CB0[2], immediateIndexed
 dcl_sampler s0, mode_default
 dcl_resource_texture2d (float,float,float,float) t0
 dcl_input_ps linear v1.xy
 dcl_output o0.xyzw
 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, 115, 228, 
-    124, 193, 199, 195, 231, 151, 
-    155,  86, 202, 199, 245, 170, 
-     45, 241,   1,   0,   0,   0, 
-     96,   5,   0,   0,   6,   0, 
+     68,  88,  66,  67,  82, 143, 
+    160,  56, 250, 151,  68,  74, 
+    171, 251, 188, 119, 224, 208, 
+     55, 192,   1,   0,   0,   0, 
+     92,   5,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     192,   0,   0,   0, 100,   1, 
       0,   0, 224,   1,   0,   0, 
-    212,   4,   0,   0,  44,   5, 
+    208,   4,   0,   0,  40,   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, 
@@ -1594,22 +1591,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, 236,   2, 
+     82,  68,  69,  70, 232,   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, 184,   2,   0,   0, 
+      0,   0, 189,   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, 
@@ -1622,17 +1619,17 @@ const BYTE RGBAShader[] =
       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,  11,   0, 
       0,   0, 172,   0,   0,   0, 
-     96,   1,   0,   0,   0,   0, 
+    144,   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, 192,   1, 
       0,   0,   0,   0,   0,   0, 
     208,   1,   0,   0,  16,   0, 
       0,   0,   4,   0,   0,   0, 
       2,   0,   0,   0, 224,   1, 
@@ -1661,20 +1658,20 @@ const BYTE RGBAShader[] =
       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, 
+    170,   2,   0,   0,  80,   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, 
@@ -1706,89 +1703,88 @@ const BYTE RGBAShader[] =
     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,  54,  46,  51,  46,  57, 
-     54,  48,  48,  46,  49,  54, 
-     51,  56,  52,   0, 171, 171, 
-     73,  83,  71,  78,  80,   0, 
-      0,   0,   2,   0,   0,   0, 
-      8,   0,   0,   0,  56,   0, 
-      0,   0,   0,   0,   0,   0, 
-      1,   0,   0,   0,   3,   0, 
-      0,   0,   0,   0,   0,   0, 
-     15,   0,   0,   0,  68,   0, 
+     97, 100,   0, 109,  77,  97, 
+    115, 107,  84, 114,  97, 110, 
+    115, 102, 111, 114, 109,   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, 171, 
+    171, 171,  73,  83,  71,  78, 
+     80,   0,   0,   0,   2,   0, 
+      0,   0,   8,   0,   0,   0, 
+     56,   0,   0,   0,   0,   0, 
+      0,   0,   1,   0,   0,   0, 
+      3,   0,   0,   0,   0,   0, 
+      0,   0,  15,   0,   0,   0, 
+     68,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   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,   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,   0,   0,   0,   0, 
+     15,   0,   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 6.3.9600.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]
 //   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]
+//   float4x4 mMaskTransform;           // Offset:  272 Size:    64 [unused]
+//   float4x4 mBackdropTransform;       // Offset:  336 Size:    64 [unused]
 //
 // }
 //
 //
 // Resource Bindings:
 //
-// Name                                 Type  Format         Dim Slot Elements
-// ------------------------------ ---------- ------- ----------- ---- --------
-// sSampler                          sampler      NA          NA    0        1
-// tRGB                              texture  float4          2d    0        1
-// tRGBWhite                         texture  float4          2d    4        1
-// $Globals                          cbuffer      NA          NA    0        1
+// Name                                 Type  Format         Dim      HLSL Bind  Count
+// ------------------------------ ---------- ------- ----------- -------------- ------
+// sSampler                          sampler      NA          NA             s0      1 
+// tRGB                              texture  float4          2d             t0      1 
+// tRGBWhite                         texture  float4          2d             t4      1 
+// $Globals                          cbuffer      NA          NA            cb0      1 
 //
 //
 //
 // Input signature:
 //
 // Name                 Index   Mask Register SysValue  Format   Used
 // -------------------- ----- ------ -------- -------- ------- ------
 // SV_Position              0   xyzw        0      POS   float       
@@ -1832,17 +1828,17 @@ ShaderBytes sRGBAShader = { RGBAShader, 
     mov r0.w, r1.y
     mul r1, r1, c0.x
     mov oC1, r1
     mul r0, r0, c0.x
     mov oC0, r0
 
 // approximately 9 instruction slots used (2 texture, 7 arithmetic)
 ps_4_0
-dcl_constantbuffer cb0[2], immediateIndexed
+dcl_constantbuffer CB0[2], immediateIndexed
 dcl_sampler s0, mode_default
 dcl_resource_texture2d (float,float,float,float) t0
 dcl_resource_texture2d (float,float,float,float) t4
 dcl_input_ps linear v1.xy
 dcl_output o0.xyzw
 dcl_output o1.xyzw
 dcl_temps 2
 sample r0.xyzw, v1.xyxx, t4.xyzw, s0
@@ -1853,25 +1849,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,  21, 227, 
-    149,  86, 182, 246,  85,  57, 
-    167,  85, 241,  51, 157,  75, 
-     49, 112,   1,   0,   0,   0, 
-    224,   6,   0,   0,   6,   0, 
+     68,  88,  66,  67, 141,  83, 
+    151, 108, 122,  94,  34, 209, 
+     87, 123, 153, 156,  73,  70, 
+    116,  57,   1,   0,   0,   0, 
+    220,   6,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
      64,   1,   0,   0, 160,   2, 
       0,   0,  28,   3,   0,   0, 
-     60,   6,   0,   0, 148,   6, 
+     56,   6,   0,   0, 144,   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, 
@@ -1986,22 +1982,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,  24,   3,   0,   0, 
+     69,  70,  20,   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, 
-    228,   2,   0,   0, 156,   0, 
+    233,   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, 
@@ -2021,17 +2017,17 @@ const BYTE ComponentAlphaShader[] =
     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,  11,   0, 
       0,   0, 216,   0,   0,   0, 
-     96,   1,   0,   0,   0,   0, 
+    144,   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, 236,   1, 
       0,   0,   0,   0,   0,   0, 
     252,   1,   0,   0,  16,   0, 
       0,   0,   4,   0,   0,   0, 
       2,   0,   0,   0,  12,   2, 
@@ -2060,20 +2056,20 @@ const BYTE ComponentAlphaShader[] =
       0,   0,  16,   0,   0,   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, 172,   2, 
       0,   0,   0,   0,   0,   0, 
     199,   2,   0,   0,  16,   1, 
-      0,   0,  16,   0,   0,   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, 108,   2, 
+      0,   0,   0,   0,   0,   0, 
+    214,   2,   0,   0,  80,   1, 
       0,   0,  64,   0,   0,   0, 
       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, 
@@ -2105,94 +2101,93 @@ const BYTE ComponentAlphaShader[] =
     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,  54,  46,  51,  46,  57, 
-     54,  48,  48,  46,  49,  54, 
-     51,  56,  52,   0, 171, 171, 
-     73,  83,  71,  78,  80,   0, 
+     97, 100,   0, 109,  77,  97, 
+    115, 107,  84, 114,  97, 110, 
+    115, 102, 111, 114, 109,   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, 171, 
+    171, 171,  73,  83,  71,  78, 
+     80,   0,   0,   0,   2,   0, 
+      0,   0,   8,   0,   0,   0, 
+     56,   0,   0,   0,   0,   0, 
+      0,   0,   1,   0,   0,   0, 
+      3,   0,   0,   0,   0,   0, 
+      0,   0,  15,   0,   0,   0, 
+     68,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   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,   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, 
-      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
+     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 6.3.9600.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]
 //   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]
+//   float4x4 mMaskTransform;           // Offset:  272 Size:    64 [unused]
+//   float4x4 mBackdropTransform;       // Offset:  336 Size:    64 [unused]
 //
 // }
 //
 //
 // Resource Bindings:
 //
-// Name                                 Type  Format         Dim Slot Elements
-// ------------------------------ ---------- ------- ----------- ---- --------
-// sSampler                          sampler      NA          NA    0        1
-// tY                                texture  float4          2d    1        1
-// tCb                               texture  float4          2d    2        1
-// tCr                               texture  float4          2d    3        1
-// $Globals                          cbuffer      NA          NA    0        1
+// Name                                 Type  Format         Dim      HLSL Bind  Count
+// ------------------------------ ---------- ------- ----------- -------------- ------
+// sSampler                          sampler      NA          NA             s0      1 
+// tY                                texture  float4          2d             t1      1 
+// tCb                               texture  float4          2d             t2      1 
+// tCr                               texture  float4          2d             t3      1 
+// $Globals                          cbuffer      NA          NA            cb0      1 
 //
 //
 //
 // Input signature:
 //
 // Name                 Index   Mask Register SysValue  Format   Used
 // -------------------- ----- ------ -------- -------- ------- ------
 // SV_Position              0   xyzw        0      POS   float       
@@ -2241,17 +2236,17 @@ ShaderBytes sComponentAlphaShader = { Co
     dp3 r0.x, c1, r2
     dp3 r0.y, c2, r2
     dp3 r0.z, c3, r2
     mul r0, r0, c0.x
     mov oC0, r0
 
 // approximately 12 instruction slots used (3 texture, 9 arithmetic)
 ps_4_0
-dcl_constantbuffer cb0[6], 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
 mov r0.w, l(1.000000)
@@ -2266,25 +2261,25 @@ 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 12 instruction slots used
 #endif
 
 const BYTE YCbCrShader[] =
 {
-     68,  88,  66,  67, 239,  64, 
-    176,  25, 191, 201, 146,  39, 
-    143, 201,  64,  49, 208, 121, 
-    166,  95,   1,   0,   0,   0, 
-    168,   7,   0,   0,   6,   0, 
+     68,  88,  66,  67, 144, 145, 
+      3, 115,  79, 221, 206,  93, 
+    244, 174, 182,  75, 160, 248, 
+     95, 149,   1,   0,   0,   0, 
+    164,   7,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
     144,   1,   0,   0, 100,   3, 
       0,   0, 224,   3,   0,   0, 
-     28,   7,   0,   0, 116,   7, 
+     24,   7,   0,   0, 112,   7, 
       0,   0,  65, 111, 110,  57, 
      80,   1,   0,   0,  80,   1, 
       0,   0,   0,   2, 255, 255, 
       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, 
@@ -2432,21 +2427,21 @@ const BYTE YCbCrShader[] =
       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, 
-     52,   3,   0,   0,   1,   0, 
+     48,   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,   1,   0,   0,   5,   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, 
       1,   0,   0,   0, 197,   0, 
       0,   0,   2,   0,   0,   0, 
       5,   0,   0,   0,   4,   0, 
@@ -2471,17 +2466,17 @@ const BYTE YCbCrShader[] =
       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, 144,   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, 
@@ -2510,21 +2505,21 @@ const BYTE YCbCrShader[] =
     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, 
+     16,   1,   0,   0,  64,   0, 
+      0,   0,   0,   0,   0,   0, 
+    136,   2,   0,   0,   0,   0, 
+      0,   0, 242,   2,   0,   0, 
+     80,   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,  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, 
@@ -2555,89 +2550,88 @@ const BYTE YCbCrShader[] =
     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,  54,  46,  51, 
-     46,  57,  54,  48,  48,  46, 
-     49,  54,  51,  56,  52,   0, 
-    171, 171,  73,  83,  71,  78, 
-     80,   0,   0,   0,   2,   0, 
+     81, 117,  97, 100,   0, 109, 
+     77,  97, 115, 107,  84, 114, 
+     97, 110, 115, 102, 111, 114, 
+    109,   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, 171, 171, 171,  73,  83, 
+     71,  78,  80,   0,   0,   0, 
+      2,   0,   0,   0,   8,   0, 
+      0,   0,  56,   0,   0,   0, 
+      0,   0,   0,   0,   1,   0, 
+      0,   0,   3,   0,   0,   0, 
+      0,   0,   0,   0,  15,   0, 
+      0,   0,  68,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      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, 
-     56,   0,   0,   0,   0,   0, 
-      0,   0,   1,   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
+     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 6.3.9600.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]
 //   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]
+//   float4x4 mMaskTransform;           // Offset:  272 Size:    64 [unused]
+//   float4x4 mBackdropTransform;       // Offset:  336 Size:    64 [unused]
 //
 // }
 //
 //
 // Resource Bindings:
 //
-// Name                                 Type  Format         Dim Slot Elements
-// ------------------------------ ---------- ------- ----------- ---- --------
-// sSampler                          sampler      NA          NA    0        1
-// tY                                texture  float4          2d    1        1
-// tCb                               texture  float4          2d    2        1
-// $Globals                          cbuffer      NA          NA    0        1
+// Name                                 Type  Format         Dim      HLSL Bind  Count
+// ------------------------------ ---------- ------- ----------- -------------- ------
+// sSampler                          sampler      NA          NA             s0      1 
+// tY                                texture  float4          2d             t1      1 
+// tCb                               texture  float4          2d             t2      1 
+// $Globals                          cbuffer      NA          NA            cb0      1 
 //
 //
 //
 // Input signature:
 //
 // Name                 Index   Mask Register SysValue  Format   Used
 // -------------------- ----- ------ -------- -------- ------- ------
 // SV_Position              0   xyzw        0      POS   float       
@@ -2682,17 +2676,17 @@ ShaderBytes sYCbCrShader = { YCbCrShader
     dp3 r0.x, c1, r2
     dp3 r0.y, c2, r2
     dp3 r0.z, c3, r2
     mul r0, r0, c0.x
     mov oC0, r0
 
 // approximately 10 instruction slots used (2 texture, 8 arithmetic)
 ps_4_0
-dcl_constantbuffer cb0[6], 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_input_ps linear v1.xy
 dcl_output o0.xyzw
 dcl_temps 3
 mov r0.w, l(1.000000)
 sample r1.xyzw, v1.xyxx, t1.xyzw, s0
@@ -2704,25 +2698,25 @@ 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 10 instruction slots used
 #endif
 
 const BYTE NV12Shader[] =
 {
-     68,  88,  66,  67, 218, 231, 
-     15, 217, 244, 161,  84,  31, 
-     40, 169,  22, 115, 159,  74, 
-      1, 232,   1,   0,   0,   0, 
-     16,   7,   0,   0,   6,   0, 
+     68,  88,  66,  67, 196,  33, 
+    229,  30, 127, 191,  69,  57, 
+    188, 163, 187,  63, 196,  65, 
+     63,  98,   1,   0,   0,   0, 
+     12,   7,   0,   0,   6,   0, 
       0,   0,  56,   0,   0,   0, 
      96,   1,   0,   0, 240,   2, 
       0,   0, 108,   3,   0,   0, 
-    132,   6,   0,   0, 220,   6, 
+    128,   6,   0,   0, 216,   6, 
       0,   0,  65, 111, 110,  57, 
      32,   1,   0,   0,  32,   1, 
       0,   0,   0,   2, 255, 255, 
     220,   0,   0,   0,  68,   0, 
       0,   0,   2,   0,  44,   0,