merge autoland to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Tue, 07 Mar 2017 15:04:48 +0100
changeset 494666 1fb56ba248d5018f8a3314f3d5ff3d9a2c044d83
parent 494263 b7e42143bbbc9dc3e5c05bd1e93b6485ce1d0ad4 (current diff)
parent 494665 bee969ddb83afdc7e4576abd6ee4b2b5d6004d40 (diff)
child 494667 47e5c929a4879384d719568ca002b705b6472b7d
push id48086
push userbsmedberg@mozilla.com
push dateTue, 07 Mar 2017 16:12:47 +0000
reviewersmerge
milestone55.0a1
merge autoland to mozilla-central a=merge
browser/components/extensions/test/browser/browser_ext_url_overrides_all.js
browser/components/extensions/test/browser/browser_ext_url_overrides_home.js
browser/components/sessionstore/SessionHistory.jsm
services/common/stringbundle.js
services/sync/tests/unit/test_utils_lazyStrings.js
xpcom/build/nsXPCOMStrings.cpp
xpcom/string/nsXPCOMStrings.h
--- a/accessible/atk/AccessibleWrap.cpp
+++ b/accessible/atk/AccessibleWrap.cpp
@@ -24,17 +24,16 @@
 #include "mozilla/a11y/Platform.h"
 #include "Relation.h"
 #include "RootAccessible.h"
 #include "States.h"
 #include "nsISimpleEnumerator.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Sprintf.h"
-#include "nsXPCOMStrings.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIPersistentProperties2.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 MaiAtkObject::EAvailableAtkSignals MaiAtkObject::gAvailableAtkSignals =
   eUnknown;
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -164,16 +164,18 @@ pref("extensions.update.interval", 86400
 // Non-symmetric (not shared by extensions) extension-specific [update] preferences
 pref("extensions.dss.enabled", false);          // Dynamic Skin Switching
 pref("extensions.dss.switchPending", false);    // Non-dynamic switch pending after next
                                                 // restart.
 
 pref("extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.name", "chrome://browser/locale/browser.properties");
 pref("extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.description", "chrome://browser/locale/browser.properties");
 
+pref("extensions.webextensions.themes.icons.buttons", "back,forward,reload,stop,bookmark_star,bookmark_menu,downloads,home,app_menu,cut,copy,paste,new_window,new_private_window,save_page,print,history,full_screen,find,options,addons,developer,synced_tabs,open_file,sidebars,share_page,subscribe,text_encoding,email_link,forget,pocket");
+
 pref("lightweightThemes.update.enabled", true);
 pref("lightweightThemes.getMoreURL", "https://addons.mozilla.org/%LOCALE%/firefox/themes");
 pref("lightweightThemes.recommendedThemes", "[{\"id\":\"recommended-1\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/a-web-browser-renaissance/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.header.jpg\",\"footerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.footer.jpg\",\"textcolor\":\"#000000\",\"accentcolor\":\"#f2d9b1\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.icon.jpg\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.preview.jpg\",\"author\":\"Sean.Martell\",\"version\":\"0\"},{\"id\":\"recommended-2\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/space-fantasy/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.header.jpg\",\"footerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.footer.jpg\",\"textcolor\":\"#ffffff\",\"accentcolor\":\"#d9d9d9\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.icon.jpg\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.preview.jpg\",\"author\":\"fx5800p\",\"version\":\"1.0\"},{\"id\":\"recommended-4\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/pastel-gradient/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.header.png\",\"footerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.footer.png\",\"textcolor\":\"#000000\",\"accentcolor\":\"#000000\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.icon.png\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.preview.png\",\"author\":\"darrinhenein\",\"version\":\"1.0\"}]");
 
 #if defined(MOZ_WIDEVINE_EME)
 pref("browser.eme.ui.enabled", true);
 #else
 pref("browser.eme.ui.enabled", false);
@@ -1242,43 +1244,54 @@ pref("security.cert_pinning.enforcement_
 pref("plain_text.wrap_long_lines", true);
 
 // If this turns true, Moz*Gesture events are not called stopPropagation()
 // before content.
 pref("dom.debug.propagate_gesture_events_through_content", false);
 
 // All the Geolocation preferences are here.
 //
-// The request URL of the GeoLocation backend.
-#ifdef RELEASE_OR_BETA
+
+// Geolocation preferences for the RELEASE channel.
+// Some of these prefs are specified even though they are redundant; they are
+// here for clarity and end-user experiments.
+#ifdef RELEASE
 pref("geo.wifi.uri", "https://www.googleapis.com/geolocation/v1/geolocate?key=%GOOGLE_API_KEY%");
-#else
-pref("geo.wifi.uri", "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%");
-#endif
 
 #ifdef XP_MACOSX
-#ifdef RELEASE_OR_BETA
 pref("geo.provider.use_corelocation", false);
-#else
-pref("geo.provider.use_corelocation", true);
-#endif
 #endif
 
 #ifdef XP_WIN
 pref("geo.provider.ms-windows-location", false);
 #endif
 
 #ifdef MOZ_WIDGET_GTK
-#ifdef MOZ_GPSD
-#ifdef RELEASE_OR_BETA
 pref("geo.provider.use_gpsd", false);
+#endif
+
 #else
+
+// Geolocation preferences for Nightly/Aurora/Beta.
+pref("geo.wifi.uri", "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%");
+
+#ifdef XP_MACOSX
+pref("geo.provider.use_corelocation", true);
+#endif
+
+// The native Windows location provider is only enabled in Nightly and likely to
+// be unstable. Set to false if things are really broken.
+#if defined(XP_WIN) && defined(NIGHTLY_BUILD)
+pref("geo.provider.ms-windows-location", true);
+#endif
+
+#if defined(MOZ_WIDGET_GTK) && defined(MOZ_GPSD)
 pref("geo.provider.use_gpsd", true);
 #endif
-#endif
+
 #endif
 
 // We keep allowing non-HTTPS geo requests on all the release
 // channels, for now.
 // TODO: default to false (or remove altogether) for #1072859.
 pref("geo.security.allowinsecure", true);
 
 // Necko IPC security checks only needed for app isolation for cookies/cache/etc:
--- a/browser/base/content/browser-syncui.js
+++ b/browser/base/content/browser-syncui.js
@@ -1,13 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
 
 if (AppConstants.MOZ_SERVICES_CLOUDSYNC) {
   XPCOMUtils.defineLazyModuleGetter(this, "CloudSync",
                                     "resource://gre/modules/CloudSync.jsm");
 }
 
 XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts",
                                   "resource://gre/modules/FxAccounts.jsm");
@@ -35,18 +36,16 @@ var gSyncUI = {
 
   _unloaded: false,
   // The last sync start time. Used to calculate the leftover animation time
   // once syncing completes (bug 1239042).
   _syncStartTime: 0,
   _syncAnimationTimer: 0,
 
   init() {
-    Cu.import("resource://services-common/stringbundle.js");
-
     // Proceed to set up the UI if Sync has already started up.
     // Otherwise we'll do it when Sync is firing up.
     if (this.weaveService.ready) {
       this.initUI();
       return;
     }
 
     // Sync isn't ready yet, but we can still update the UI with an initial
@@ -219,18 +218,19 @@ var gSyncUI = {
     this.updateUI();
   },
 
   onLogout: function SUI_onLogout() {
     this.updateUI();
   },
 
   _getAppName() {
-    let brand = new StringBundle("chrome://branding/locale/brand.properties");
-    return brand.get("brandShortName");
+    let brand = Services.strings.createBundle(
+      "chrome://branding/locale/brand.properties");
+    return brand.GetStringFromName("brandShortName");
   },
 
   // Commands
   // doSync forces a sync - it *does not* return a promise as it is called
   // via the various UI components.
   doSync() {
     this._needsSetup().then(needsSetup => {
       if (!needsSetup) {
@@ -470,19 +470,18 @@ var gSyncUI = {
     Ci.nsIObserver,
     Ci.nsISupportsWeakReference
   ])
 };
 
 XPCOMUtils.defineLazyGetter(gSyncUI, "_stringBundle", function() {
   // XXXzpao these strings should probably be moved from /services to /browser... (bug 583381)
   //        but for now just make it work
-  return Cc["@mozilla.org/intl/stringbundle;1"].
-         getService(Ci.nsIStringBundleService).
-         createBundle("chrome://weave/locale/services/sync.properties");
+  return Services.strings.createBundle(
+    "chrome://weave/locale/services/sync.properties");
 });
 
 XPCOMUtils.defineLazyGetter(gSyncUI, "log", function() {
   return Log.repository.getLogger("browserwindow.syncui");
 });
 
 XPCOMUtils.defineLazyGetter(gSyncUI, "weaveService", function() {
   return Components.classes["@mozilla.org/weave/service;1"]
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -1259,8 +1259,10 @@ toolbarpaletteitem[place="palette"][hidd
   box-shadow: 0 0 2px 2px rgba(255,0,0,0.4);
 }
 
 .dragfeedback-tab {
   -moz-appearance: none;
   opacity: 0.65;
   -moz-window-shadow: none;
 }
+
+%include theme-vars.inc.css
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -824,16 +824,18 @@ function gKeywordURIFixup({ target: brow
   // We get called irrespective of whether we did a keyword search, or
   // whether the original input would be vaguely interpretable as a URL,
   // so figure that out first.
   let alternativeURI = deserializeURI(fixupInfo.fixedURI);
   if (!fixupInfo.keywordProviderName || !alternativeURI || !alternativeURI.host) {
     return;
   }
 
+  let contentPrincipal = browser.contentPrincipal;
+
   // At this point we're still only just about to load this URI.
   // When the async DNS lookup comes back, we may be in any of these states:
   // 1) still on the previous URI, waiting for the preferredURI (keyword
   //    search) to respond;
   // 2) at the keyword search URI (preferredURI)
   // 3) at some other page because the user stopped navigation.
   // We keep track of the currentURI to detect case (1) in the DNS lookup
   // callback.
@@ -926,17 +928,18 @@ function gKeywordURIFixup({ target: brow
     let notification =
       notificationBox.appendNotification(message, "keyword-uri-fixup", null,
                                          notificationBox.PRIORITY_INFO_HIGH,
                                          buttons);
     notification.persistence = 1;
   };
 
   try {
-    gDNSService.asyncResolve(hostName, 0, onLookupComplete, Services.tm.mainThread);
+    gDNSService.asyncResolve(hostName, 0, onLookupComplete, Services.tm.mainThread,
+                             contentPrincipal.originAttributes);
   } catch (ex) {
     // Do nothing if the URL is invalid (we don't want to show a notification in that case).
     if (ex.result != Cr.NS_ERROR_UNKNOWN_HOST) {
       // ... otherwise, report:
       Cu.reportError(ex);
     }
   }
 }
@@ -6716,16 +6719,22 @@ var gIdentityHandler = {
    */
   _sslStatus: null,
 
   /**
    * Bitmask provided by nsIWebProgressListener.onSecurityChange.
    */
   _state: 0,
 
+  /**
+   * This flag gets set if the identity popup was opened by a keypress,
+   * to be able to focus it on the popupshown event.
+   */
+  _popupTriggeredByKeyboard: false,
+
   get _isBroken() {
     return this._state & Ci.nsIWebProgressListener.STATE_IS_BROKEN;
   },
 
   get _isSecure() {
     // If a <browser> is included within a chrome document, then this._state
     // will refer to the security state for the <browser> and not the top level
     // document. In this case, don't upgrade the security state in the UI
@@ -6850,16 +6859,20 @@ var gIdentityHandler = {
   get _permissionEmptyHint() {
     delete this._permissionEmptyHint;
     return this._permissionEmptyHint = document.getElementById("identity-popup-permission-empty-hint");
   },
   get _permissionReloadHint() {
     delete this._permissionReloadHint;
     return this._permissionReloadHint = document.getElementById("identity-popup-permission-reload-hint");
   },
+  get _popupExpander() {
+    delete this._popupExpander;
+    return this._popupExpander = document.getElementById("identity-popup-security-expander");
+  },
   get _permissionAnchors() {
     delete this._permissionAnchors;
     let permissionAnchors = {};
     for (let anchor of document.getElementById("blocked-permissions-container").children) {
       permissionAnchors[anchor.getAttribute("data-permission-id")] = anchor;
     }
     return this._permissionAnchors = permissionAnchors;
   },
@@ -6871,20 +6884,28 @@ var gIdentityHandler = {
   handleMoreInfoClick(event) {
     displaySecurityInfo();
     event.stopPropagation();
     this._identityPopup.hidePopup();
   },
 
   toggleSubView(name, anchor) {
     let view = this._identityPopupMultiView;
+    let id = `identity-popup-${name}View`;
+    let subView = document.getElementById(id);
+
+    // Listen for the subview showing or hiding to change
+    // the tooltip on the expander button.
+    subView.addEventListener("ViewShowing", this);
+    subView.addEventListener("ViewHiding", this);
+
     if (view.showingSubView) {
       view.showMainView();
     } else {
-      view.showSubView(`identity-popup-${name}View`, anchor);
+      view.showSubView(id, anchor);
     }
 
     // If an element is focused that's not the anchor, clear the focus.
     // Elements of hidden views have -moz-user-focus:ignore but setting that
     // per CSS selector doesn't blur a focused element in those hidden views.
     if (Services.focus.focusedElement != anchor) {
       Services.focus.clearFocus(window);
     }
@@ -7183,16 +7204,19 @@ var gIdentityHandler = {
   refreshIdentityPopup() {
     // Update "Learn More" for Mixed Content Blocking and Insecure Login Forms.
     let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL");
     this._identityPopupMixedContentLearnMore
         .setAttribute("href", baseURL + "mixed-content");
     this._identityPopupInsecureLoginFormsLearnMore
         .setAttribute("href", baseURL + "insecure-password");
 
+    // The expander switches its tooltip when toggled, change it to the default.
+    this._popupExpander.tooltipText = gNavigatorBundle.getString("identity.showDetails.tooltip");
+
     // Determine connection security information.
     let connection = "not-secure";
     if (this._isSecureInternalUI) {
       connection = "chrome";
     } else if (this._isURILoadedFromFile) {
       connection = "file";
     } else if (this._isEV) {
       connection = "secure-ev";
@@ -7356,16 +7380,18 @@ var gIdentityHandler = {
       return; // Left click, space or enter only
     }
 
     // Don't allow left click, space or enter if the location has been modified.
     if (gURLBar.getAttribute("pageproxystate") != "valid") {
       return;
     }
 
+    this._popupTriggeredByKeyboard = event.type == "keypress";
+
     // Make sure that the display:none style we set in xul is removed now that
     // the popup is actually needed
     this._identityPopup.hidden = false;
 
     // Remove the reload hint that we show after a user has cleared a permission.
     this._permissionReloadHint.setAttribute("hidden", "true");
 
     // Update the popup strings
@@ -7375,33 +7401,45 @@ var gIdentityHandler = {
     this._identityBox.setAttribute("open", "true");
 
     // Now open the popup, anchored off the primary chrome element
     this._identityPopup.openPopup(this._identityIcon, "bottomcenter topleft");
   },
 
   onPopupShown(event) {
     if (event.target == this._identityPopup) {
-      // Move focus to the next available element in the identity popup.
-      // This is required by role=alertdialog and fixes an issue where
-      // an already open panel would steal focus from the identity popup.
-      document.commandDispatcher.advanceFocusIntoSubtree(this._identityPopup);
+      if (this._popupTriggeredByKeyboard) {
+        // Move focus to the next available element in the identity popup.
+        // This is required by role=alertdialog and fixes an issue where
+        // an already open panel would steal focus from the identity popup.
+        document.commandDispatcher.advanceFocusIntoSubtree(this._identityPopup);
+      }
 
       window.addEventListener("focus", this, true);
     }
   },
 
   onPopupHidden(event) {
     if (event.target == this._identityPopup) {
       window.removeEventListener("focus", this, true);
       this._identityBox.removeAttribute("open");
     }
   },
 
   handleEvent(event) {
+    // If the subview is shown or hidden, change the tooltip on the expander button.
+    if (event.type == "ViewShowing") {
+      this._popupExpander.tooltipText = gNavigatorBundle.getString("identity.hideDetails.tooltip");
+      return;
+    }
+    if (event.type == "ViewHiding") {
+      this._popupExpander.tooltipText = gNavigatorBundle.getString("identity.showDetails.tooltip");
+      return;
+    }
+
     let elem = document.activeElement;
     let position = elem.compareDocumentPosition(this._identityPopup);
 
     if (!(position & (Node.DOCUMENT_POSITION_CONTAINS |
                       Node.DOCUMENT_POSITION_CONTAINED_BY)) &&
         !this._identityPopup.hasAttribute("noautohide")) {
       // Hide the panel when focusing an element that is
       // neither an ancestor nor descendant unless the panel has
--- a/browser/base/content/tabbrowser.css
+++ b/browser/base/content/tabbrowser.css
@@ -92,19 +92,24 @@ tabpanels {
  * memory that to-be-restored tabs would otherwise consume simply by setting
  * their browsers to 'display: none' as that will prevent them from having to
  * create a presentation and the like.
  */
 browser[pending] {
   display: none;
 }
 
+browser[pendingtabchild],
 browser[pendingpaint] {
   opacity: 0;
 }
 
+tabbrowser[pendingtabchild] {
+  background-color: #ffffff !important;
+}
+
 tabbrowser[pendingpaint] {
   background-image: url(chrome://browser/skin/tabbrowser/pendingpaint.png);
   background-repeat: no-repeat;
   background-position: center center;
   background-color: #f9f9f9 !important;
   background-size: 30px;
 }
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -3718,25 +3718,32 @@
 
             // We show this tab in case the requestedTab hasn't loaded yet.
             lastVisibleTab: this.selectedTab,
 
             // Auxilliary state variables:
 
             visibleTab: this.selectedTab,   // Tab that's on screen.
             spinnerTab: null,               // Tab showing a spinner.
+            blankTab: null,                 // Tab showing blank.
             originalTab: this.selectedTab,  // Tab that we started on.
 
             tabbrowser: this,  // Reference to gBrowser.
             loadTimer: null,   // TAB_SWITCH_TIMEOUT nsITimer instance.
             unloadTimer: null, // UNLOAD_DELAY nsITimer instance.
 
             // Map from tabs to STATE_* (below).
             tabState: new Map(),
 
+            // Holds a collection of <xul:browser>'s for this tabbrowser
+            // that we cannot force paint since their TabChild's haven't
+            // been constructed yet. Instead, we show blank tabs for them
+            // when attempting to switch to them.
+            pendingTabChild: new WeakSet(),
+
             // True if we're in the midst of switching tabs.
             switchInProgress: false,
 
             // Keep an exact list of content processes (tabParent) in which
             // we're actively suppressing the display port. This gives a robust
             // way to make sure we don't forget to un-suppress.
             activeSuppressDisplayport: new Set(),
 
@@ -3822,16 +3829,17 @@
 
               window.addEventListener("MozAfterPaint", this);
               window.addEventListener("MozLayerTreeReady", this);
               window.addEventListener("MozLayerTreeCleared", this);
               window.addEventListener("TabRemotenessChange", this);
               window.addEventListener("sizemodechange", this);
               window.addEventListener("SwapDocShells", this, true);
               window.addEventListener("EndSwapDocShells", this, true);
+              window.addEventListener("MozTabChildNotReady", this, true);
               if (!this.minimized) {
                 this.setTabState(this.requestedTab, this.STATE_LOADED);
               }
             },
 
             destroy() {
               if (this.unloadTimer) {
                 this.clearTimer(this.unloadTimer);
@@ -3844,31 +3852,33 @@
 
               window.removeEventListener("MozAfterPaint", this);
               window.removeEventListener("MozLayerTreeReady", this);
               window.removeEventListener("MozLayerTreeCleared", this);
               window.removeEventListener("TabRemotenessChange", this);
               window.removeEventListener("sizemodechange", this);
               window.removeEventListener("SwapDocShells", this, true);
               window.removeEventListener("EndSwapDocShells", this, true);
+              window.removeEventListener("MozTabChildNotReady", this, true);
 
               this.tabbrowser._switcher = null;
 
               this.activeSuppressDisplayport.forEach(function(tabParent) {
                 tabParent.suppressDisplayport(false);
               });
               this.activeSuppressDisplayport.clear();
             },
 
             finish() {
               this.log("FINISH");
 
               this.assert(this.tabbrowser._switcher);
               this.assert(this.tabbrowser._switcher === this);
               this.assert(!this.spinnerTab);
+              this.assert(!this.blankTab);
               this.assert(!this.loadTimer);
               this.assert(!this.loadingTab);
               this.assert(this.lastVisibleTab === this.requestedTab);
               this.assert(this.minimized || this.getTabState(this.requestedTab) == this.STATE_LOADED);
 
               this.destroy();
 
               let toBrowser = this.requestedTab.linkedBrowser;
@@ -3889,30 +3899,55 @@
                 cancelable: true
               });
               this.tabbrowser.dispatchEvent(event);
             },
 
             // This function is called after all the main state changes to
             // make sure we display the right tab.
             updateDisplay() {
+              let requestedTabState = this.getTabState(this.requestedTab);
+
+              let shouldBeBlank =
+                this.pendingTabChild.has(this.requestedTab.linkedBrowser) &&
+                requestedTabState == this.STATE_LOADING;
+
               // Figure out which tab we actually want visible right now.
               let showTab = null;
-              if (this.getTabState(this.requestedTab) != this.STATE_LOADED &&
-                  this.lastVisibleTab && this.loadTimer) {
+              if (requestedTabState != this.STATE_LOADED &&
+                  this.lastVisibleTab && this.loadTimer && !shouldBeBlank) {
                 // If we can't show the requestedTab, and lastVisibleTab is
                 // available, show it.
                 showTab = this.lastVisibleTab;
               } else {
-                // Show the requested tab. If it's not available, we'll show the spinner.
+                // Show the requested tab. If it's not available, we'll show the spinner or a blank tab.
                 showTab = this.requestedTab;
               }
 
+              // First, let's deal with blank tabs, which we show instead
+              // of the spinner when the tab is not currently set up
+              // properly in the content process.
+              if (!shouldBeBlank && this.blankTab) {
+                this.tabbrowser.removeAttribute("pendingtabchild");
+                this.blankTab.linkedBrowser.removeAttribute("pendingtabchild");
+                this.blankTab = null;
+              } else if (shouldBeBlank && this.blankTab !== showTab) {
+                if (this.blankTab) {
+                  this.blankTab.linkedBrowser.removeAttribute("pendingtabchild");
+                }
+                this.blankTab = showTab;
+                this.tabbrowser.setAttribute("pendingtabchild", "true");
+                this.blankTab.linkedBrowser.setAttribute("pendingtabchild", "true");
+              }
+
               // Show or hide the spinner as needed.
-              let needSpinner = this.getTabState(showTab) != this.STATE_LOADED && !this.minimized;
+              let needSpinner = this.getTabState(showTab) != this.STATE_LOADED &&
+                                !this.minimized &&
+                                !shouldBeBlank;
+
               if (!needSpinner && this.spinnerTab) {
                 this.spinnerHidden();
                 this.tabbrowser.removeAttribute("pendingpaint");
                 this.spinnerTab.linkedBrowser.removeAttribute("pendingpaint");
                 this.spinnerTab = null;
               } else if (needSpinner && this.spinnerTab !== showTab) {
                 if (this.spinnerTab) {
                   this.spinnerTab.linkedBrowser.removeAttribute("pendingpaint");
@@ -3987,16 +4022,19 @@
                 if (!tab.linkedBrowser) {
                   this.tabState.delete(tab);
                 }
               }
 
               if (this.lastVisibleTab && !this.lastVisibleTab.linkedBrowser) {
                 this.lastVisibleTab = null;
               }
+              if (this.blankTab && !this.blankTab.linkedBrowser) {
+                this.blankTab = null;
+              }
               if (this.spinnerTab && !this.spinnerTab.linkedBrowser) {
                 this.spinnerHidden();
                 this.spinnerTab = null;
               }
               if (this.loadingTab && !this.loadingTab.linkedBrowser) {
                 this.loadingTab = null;
                 this.clearTimer(this.loadTimer);
                 this.loadTimer = null;
@@ -4099,18 +4137,19 @@
               this.preActions();
               this.loadTimer = null;
               this.loadingTab = null;
               this.postActions();
             },
 
             // Fires when the layers become available for a tab.
             onLayersReady(browser) {
+              this.pendingTabChild.delete(browser);
               let tab = this.tabbrowser.getTabForBrowser(browser);
-              this.logState(`onLayersReady(${tab._tPos})`);
+              this.logState(`onLayersReady(${tab._tPos}, ${browser.isRemoteBrowser})`);
 
               this.assert(this.getTabState(tab) == this.STATE_LOADING ||
                           this.getTabState(tab) == this.STATE_LOADED);
               this.setTabState(tab, this.STATE_LOADED);
 
               this.maybeFinishTabSwitch();
 
               if (this.loadingTab === tab) {
@@ -4125,16 +4164,17 @@
             // around.
             onPaint() {
               this.maybeVisibleTabs.clear();
               this.maybeFinishTabSwitch();
             },
 
             // Called when we're done clearing the layers for a tab.
             onLayersCleared(browser) {
+              this.pendingTabChild.delete(browser);
               let tab = this.tabbrowser.getTabForBrowser(browser);
               if (tab) {
                 this.logState(`onLayersCleared(${tab._tPos})`);
                 this.assert(this.getTabState(tab) == this.STATE_UNLOADING ||
                             this.getTabState(tab) == this.STATE_UNLOADED);
                 this.setTabState(tab, this.STATE_UNLOADED);
               }
             },
@@ -4145,16 +4185,25 @@
             onRemotenessChange(tab) {
               this.logState(`onRemotenessChange(${tab._tPos}, ${tab.linkedBrowser.isRemoteBrowser})`);
               if (!tab.linkedBrowser.isRemoteBrowser) {
                 if (this.getTabState(tab) == this.STATE_LOADING) {
                   this.onLayersReady(tab.linkedBrowser);
                 } else if (this.getTabState(tab) == this.STATE_UNLOADING) {
                   this.onLayersCleared(tab.linkedBrowser);
                 }
+              } else if (this.getTabState(tab) == this.STATE_LOADED) {
+                // A tab just changed from non-remote to remote, which means
+                // that it's gone back into the STATE_LOADING state until
+                // it sends up a layer tree. We also add the browser to
+                // the pendingTabChild set since this browser is unlikely
+                // to have its TabChild set up right away, and we want to
+                // make it appear "blank" instead of showing a spinner for it.
+                this.pendingTabChild.add(tab.linkedBrowser);
+                this.setTabState(tab, this.STATE_LOADING);
               }
             },
 
             // Called when a tab has been removed, and the browser node is
             // about to be removed from the DOM.
             onTabRemoved(tab) {
               if (this.lastVisibleTab == tab) {
                 // The browser that was being presented to the user is
@@ -4191,29 +4240,41 @@
 
             onSwapDocShells(ourBrowser, otherBrowser) {
               // This event fires before the swap. ourBrowser is from
               // our window. We save the state of otherBrowser since ourBrowser
               // needs to take on that state at the end of the swap.
 
               let otherTabbrowser = otherBrowser.ownerGlobal.gBrowser;
               let otherState;
+              let pendingTabChild = false;
               if (otherTabbrowser && otherTabbrowser._switcher) {
                 let otherTab = otherTabbrowser.getTabForBrowser(otherBrowser);
-                otherState = otherTabbrowser._switcher.getTabState(otherTab);
+                let otherSwitcher = otherTabbrowser._switcher;
+                otherState = otherSwitcher.getTabState(otherTab);
+                pendingTabChild = otherSwitcher.pendingTabChild.has(otherBrowser);
+
+                if (pendingTabChild) {
+                  this.assert(otherState == this.STATE_LOADING);
+                }
+
+                otherSwitcher.pendingTabChild.delete(otherBrowser);
               } else {
                 otherState = (otherBrowser.docShellIsActive
                               ? this.STATE_LOADED
                               : this.STATE_UNLOADED);
               }
 
               if (!this.swapMap) {
                 this.swapMap = new WeakMap();
               }
-              this.swapMap.set(otherBrowser, otherState);
+              this.swapMap.set(otherBrowser, {
+                state: otherState,
+                pendingTabChild,
+              });
             },
 
             onEndSwapDocShells(ourBrowser, otherBrowser) {
               // The swap has happened. We reset the loadingTab in
               // case it has been swapped. We also set ourBrowser's state
               // to whatever otherBrowser's state was before the swap.
 
               if (this.loadTimer) {
@@ -4222,36 +4283,63 @@
                 // ready yet. Typically it will already be ready
                 // though. If it's not, we're probably in a new window,
                 // in which case we have no other tabs to display anyway.
                 this.clearTimer(this.loadTimer);
                 this.loadTimer = null;
               }
               this.loadingTab = null;
 
-              let otherState = this.swapMap.get(otherBrowser);
+              let { state: otherState, pendingTabChild } =
+                this.swapMap.get(otherBrowser);
+
               this.swapMap.delete(otherBrowser);
 
               let ourTab = this.tabbrowser.getTabForBrowser(ourBrowser);
               if (ourTab) {
                 this.setTabStateNoAction(ourTab, otherState);
+                if (pendingTabChild) {
+                  this.pendingTabChild.add(ourTab.linkedBrowser);
+                }
               }
             },
 
             shouldActivateDocShell(browser) {
               let tab = this.tabbrowser.getTabForBrowser(browser);
               let state = this.getTabState(tab);
               return state == this.STATE_LOADING || state == this.STATE_LOADED;
             },
 
             activateBrowserForPrintPreview(browser) {
               let tab = this.tabbrowser.getTabForBrowser(browser);
               this.setTabState(tab, this.STATE_LOADING);
             },
 
+            // The tab for this browser isn't currently set
+            // up in the content process, so we have no chance
+            // of painting it right away. We'll paint a blank
+            // tab instead.
+            onTabChildNotReady(browser) {
+              this.assert(browser.isRemoteBrowser);
+
+              let tab = this.tabbrowser.getTabForBrowser(browser);
+
+              this.assert(this.getTabState(tab) == this.STATE_LOADING);
+
+              this.logState(`onTabChildNotReady(${tab._tPos})`);
+              this.pendingTabChild.add(browser);
+              this.maybeFinishTabSwitch();
+
+              if (this.loadingTab === tab) {
+                this.clearTimer(this.loadTimer);
+                this.loadTimer = null;
+                this.loadingTab = null;
+              }
+            },
+
             // Called when the user asks to switch to a given tab.
             requestTab(tab) {
               if (tab === this.requestedTab) {
                 return;
               }
 
               this.logState("requestTab " + this.tinfo(tab));
               this.startTabSwitch();
@@ -4297,16 +4385,18 @@
               } else if (event.type == "TabRemotenessChange") {
                 this.onRemotenessChange(event.target);
               } else if (event.type == "sizemodechange") {
                 this.onSizeModeChange();
               } else if (event.type == "SwapDocShells") {
                 this.onSwapDocShells(event.originalTarget, event.detail);
               } else if (event.type == "EndSwapDocShells") {
                 this.onEndSwapDocShells(event.originalTarget, event.detail);
+              } else if (event.type == "MozTabChildNotReady") {
+                this.onTabChildNotReady(event.originalTarget);
               }
 
               this.postActions();
               this._processing = false;
             },
 
             /*
              * Telemetry and Profiler related helpers for recording tab switch
@@ -4323,17 +4413,18 @@
             /**
              * Something has occurred that might mean that we've completed
              * the tab switch (layers are ready, paints are done, spinners
              * are hidden). This checks to make sure all conditions are
              * satisfied, and then records the tab switch as finished.
              */
             maybeFinishTabSwitch() {
               if (this.switchInProgress && this.requestedTab &&
-                  this.getTabState(this.requestedTab) == this.STATE_LOADED) {
+                  (this.getTabState(this.requestedTab) == this.STATE_LOADED ||
+                   this.requestedTab === this.blankTab)) {
                 // After this point the tab has switched from the content thread's point of view.
                 // The changes will be visible after the next refresh driver tick + composite.
                 let time = TelemetryStopwatch.timeElapsed("FX_TAB_SWITCH_TOTAL_E10S_MS", window);
                 if (time != -1) {
                   TelemetryStopwatch.finish("FX_TAB_SWITCH_TOTAL_E10S_MS", window);
                   this.log("DEBUG: tab switch time = " + time);
                   this.addMarker("AsyncTabSwitch:Finish");
                 }
@@ -4414,16 +4505,17 @@
               for (let i = 0; i < this.tabbrowser.tabs.length; i++) {
                 let tab = this.tabbrowser.tabs[i];
                 let state = this.getTabState(tab);
 
                 accum += i + ":";
                 if (tab === this.lastVisibleTab) accum += "V";
                 if (tab === this.loadingTab) accum += "L";
                 if (tab === this.requestedTab) accum += "R";
+                if (tab === this.blankTab) accum += "B";
                 if (state == this.STATE_LOADED) accum += "(+)";
                 if (state == this.STATE_LOADING) accum += "(+?)";
                 if (state == this.STATE_UNLOADED) accum += "(-)";
                 if (state == this.STATE_UNLOADING) accum += "(-?)";
                 accum += " ";
               }
               if (this._useDumpForLogging) {
                 dump(accum + "\n");
--- a/browser/base/content/test/general/browser_misused_characters_in_strings.js
+++ b/browser/base/content/test/general/browser_misused_characters_in_strings.js
@@ -187,19 +187,21 @@ function* getAllTheFiles(extension) {
 add_task(function* checkAllTheProperties() {
   // This asynchronously produces a list of URLs (sadly, mostly sync on our
   // test infrastructure because it runs against jarfiles there, and
   // our zipreader APIs are all sync)
   let uris = yield getAllTheFiles(".properties");
   ok(uris.length, `Found ${uris.length} .properties files to scan for misused characters`);
 
   for (let uri of uris) {
-    let bundle = new StringBundle(uri.spec);
-    let entities = bundle.getAll();
-    for (let entity of entities) {
+    let bundle = Services.strings.createBundle(uri.spec);
+    let enumerator = bundle.getSimpleEnumeration();
+
+    while (enumerator.hasMoreElements()) {
+      let entity = enumerator.getNext().QueryInterface(Ci.nsIPropertyElement);
       testForErrors(uri.spec, entity.key, entity.value);
     }
   }
 });
 
 var checkDTD = Task.async(function* (aURISpec) {
   let rawContents = yield fetchFile(aURISpec);
   // The regular expression below is adapted from:
--- a/browser/base/content/test/siteIdentity/browser.ini
+++ b/browser/base/content/test/siteIdentity/browser.ini
@@ -42,16 +42,17 @@ support-files =
 [browser_csp_block_all_mixedcontent.js]
 tags = mcb
 support-files =
   file_csp_block_all_mixedcontent.html
   file_csp_block_all_mixedcontent.js
 [browser_identity_UI.js]
 [browser_identityBlock_focus.js]
 support-files = ../general/permissions.html
+[browser_identityPopup_focus.js]
 [browser_insecureLoginForms.js]
 support-files =
   insecure_opener.html
   !/toolkit/components/passwordmgr/test/browser/form_basic.html
   !/toolkit/components/passwordmgr/test/browser/insecure_test.html
   !/toolkit/components/passwordmgr/test/browser/insecure_test_subframe.html
 [browser_mcb_redirect.js]
 tags = mcb
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/siteIdentity/browser_identityPopup_focus.js
@@ -0,0 +1,27 @@
+/* Tests the focus behavior of the identity popup. */
+
+// Access the identity popup via mouseclick. Focus should not be moved inside.
+add_task(function* testIdentityPopupFocusClick() {
+  yield SpecialPowers.pushPrefEnv({"set": [["accessibility.tabfocus", 7]]});
+  yield BrowserTestUtils.withNewTab("https://example.com", function*() {
+    let shown = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popupshown");
+    EventUtils.synthesizeMouseAtCenter(gIdentityHandler._identityBox, {});
+    yield shown;
+    isnot(Services.focus.focusedElement, document.getElementById("identity-popup-security-expander"));
+  });
+});
+
+// Access the identity popup via keyboard. Focus should be moved inside.
+add_task(function* testIdentityPopupFocusKeyboard() {
+  yield SpecialPowers.pushPrefEnv({"set": [["accessibility.tabfocus", 7]]});
+  yield BrowserTestUtils.withNewTab("https://example.com", function*() {
+    let focused = BrowserTestUtils.waitForEvent(gIdentityHandler._identityBox, "focus");
+    gIdentityHandler._identityBox.focus();
+    yield focused;
+    let shown = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popupshown");
+    EventUtils.synthesizeKey(" ", {});
+    yield shown;
+    is(Services.focus.focusedElement, document.getElementById("identity-popup-security-expander"));
+  });
+});
+
--- a/browser/base/content/test/tabs/browser_tabSpinnerProbe.js
+++ b/browser/base/content/test/tabs/browser_tabSpinnerProbe.js
@@ -80,14 +80,22 @@ function* testProbe(aProbe) {
   yield BrowserTestUtils.removeTab(tab2);
   yield BrowserTestUtils.removeTab(tab1);
   ok(sum(snapshot.counts) > 0,
    `Spinner probe should now have a value in some bucket`);
 }
 
 add_task(function* setup() {
   yield SpecialPowers.pushPrefEnv({
-    set: [["dom.ipc.processCount", 1]]
+    set: [
+      ["dom.ipc.processCount", 1],
+      // We can interrupt JS to paint now, which is great for
+      // users, but bad for testing spinners. We temporarily
+      // disable that feature for this test so that we can
+      // easily get ourselves into a predictable tab spinner
+      // state.
+      ["browser.tabs.remote.force-paint", false],
+    ]
   });
 });
 
 add_task(testProbe.bind(null, "FX_TAB_SWITCH_SPINNER_VISIBLE_MS"));
 add_task(testProbe.bind(null, "FX_TAB_SWITCH_SPINNER_VISIBLE_LONG_MS"));
--- a/browser/base/content/test/webextensions/browser_extension_sideloading.js
+++ b/browser/base/content/test/webextensions/browser_extension_sideloading.js
@@ -167,16 +167,18 @@ add_task(function* () {
   yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
 
   registerCleanupFunction(function*() {
     // Return to about:blank when we're done
     gBrowser.selectedBrowser.loadURI("about:blank");
     yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
   });
 
+  hookExtensionsTelemetry();
+
   let changePromise = new Promise(resolve => {
     ExtensionsUI.on("change", function listener() {
       ExtensionsUI.off("change", listener);
       resolve();
     });
   });
   ExtensionsUI._checkForSideloaded();
   yield changePromise;
@@ -322,12 +324,15 @@ add_task(function* () {
   disablePromise = promiseSetDisabled(mock4);
   panel.button.click();
   value = yield disablePromise;
   is(value, false, "userDisabled should be set on addon 4");
 
   addon4 = yield AddonManager.getAddonByID(ID4);
   is(addon4.userDisabled, false, "Addon 4 should be enabled");
 
+  // We should have recorded 1 cancelled followed by 3 accepted sideloads.
+  expectTelemetry(["sideloadRejected", "sideloadAccepted", "sideloadAccepted", "sideloadAccepted"]);
+
   isnot(menuButton.getAttribute("badge-status"), "addon-alert", "Should no longer have addon alert badge");
 
   yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
--- a/browser/base/content/test/webextensions/browser_extension_update_background.js
+++ b/browser/base/content/test/webextensions/browser_extension_update_background.js
@@ -47,16 +47,18 @@ add_task(function* setup() {
 
   registerCleanupFunction(function*() {
     // Return to about:blank when we're done
     gBrowser.selectedBrowser.loadURI("about:blank");
     yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
   });
 });
 
+hookExtensionsTelemetry();
+
 // Helper function to test background updates.
 function* backgroundUpdateTest(url, id, checkIconFn) {
   yield SpecialPowers.pushPrefEnv({set: [
     // Turn on background updates
     ["extensions.update.enabled", true],
 
     // Point updates to the local mochitest server
     ["extensions.update.background.url", `${BASE}/browser_webext_update.json`],
@@ -158,16 +160,19 @@ function* backgroundUpdateTest(url, id, 
 
   addon = yield updatePromise;
   is(addon.version, "2.0", "Should have upgraded to the new version");
 
   yield BrowserTestUtils.removeTab(tab);
 
   is(getBadgeStatus(), "", "Addon alert badge should be gone");
 
+  // Should have recorded 1 canceled followed by 1 accepted update.
+  expectTelemetry(["updateRejected", "updateAccepted"]);
+
   addon.uninstall();
   yield SpecialPowers.popPrefEnv();
 }
 
 function checkDefaultIcon(icon) {
   is(icon, "chrome://mozapps/skin/extensions/extensionGeneric.svg",
      "Popup has the default extension icon");
 }
--- a/browser/base/content/test/webextensions/browser_permissions_addons_search.js
+++ b/browser/base/content/test/webextensions/browser_permissions_addons_search.js
@@ -34,9 +34,9 @@ async function installSearch(filename) {
   // abracadabara XBL
   item.clientTop;
 
   let install = win.document.getAnonymousElementByAttribute(item, "anonid", "install-status");
   let button = win.document.getAnonymousElementByAttribute(install, "anonid", "install-remote-btn");
   EventUtils.synthesizeMouseAtCenter(button, {}, win);
 }
 
-add_task(() => testInstallMethod(installSearch));
+add_task(() => testInstallMethod(installSearch, "installAmo"));
--- a/browser/base/content/test/webextensions/browser_permissions_installTrigger.js
+++ b/browser/base/content/test/webextensions/browser_permissions_installTrigger.js
@@ -6,9 +6,9 @@ async function installTrigger(filename) 
   gBrowser.selectedBrowser.loadURI(INSTALL_PAGE);
   await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
 
   ContentTask.spawn(gBrowser.selectedBrowser, `${BASE}/${filename}`, function*(url) {
     content.wrappedJSObject.installTrigger(url);
   });
 }
 
-add_task(() => testInstallMethod(installTrigger));
+add_task(() => testInstallMethod(installTrigger, "installAmo"));
--- a/browser/base/content/test/webextensions/browser_permissions_local_file.js
+++ b/browser/base/content/test/webextensions/browser_permissions_local_file.js
@@ -15,9 +15,9 @@ async function installFile(filename) {
 
   await BrowserOpenAddonsMgr("addons://list/extension");
   let contentWin = gBrowser.selectedTab.linkedBrowser.contentWindow;
 
   // Do the install...
   contentWin.gViewController.doCommand("cmd_installFromFile");
 }
 
-add_task(() => testInstallMethod(installFile));
+add_task(() => testInstallMethod(installFile, "installLocal"));
--- a/browser/base/content/test/webextensions/browser_permissions_mozAddonManager.js
+++ b/browser/base/content/test/webextensions/browser_permissions_mozAddonManager.js
@@ -6,9 +6,9 @@ async function installMozAM(filename) {
   gBrowser.selectedBrowser.loadURI(INSTALL_PAGE);
   await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
 
   await ContentTask.spawn(gBrowser.selectedBrowser, `${BASE}/${filename}`, function*(url) {
     yield content.wrappedJSObject.installMozAM(url);
   });
 }
 
-add_task(() => testInstallMethod(installMozAM));
+add_task(() => testInstallMethod(installMozAM, "installAmo"));
--- a/browser/base/content/test/webextensions/head.js
+++ b/browser/base/content/test/webextensions/head.js
@@ -1,12 +1,14 @@
 
 const BASE = getRootDirectory(gTestPath)
   .replace("chrome://mochitests/content/", "https://example.com/");
 
+Cu.import("resource:///modules/ExtensionsUI.jsm");
+
 /**
  * Wait for the given PopupNotification to display
  *
  * @param {string} name
  *        The name of the notification to wait for.
  *
  * @returns {Promise}
  *          Resolves with the notification window.
@@ -196,32 +198,39 @@ function checkNotification(panel, checkI
 /**
  * Test that install-time permission prompts work for a given
  * installation method.
  *
  * @param {Function} installFn
  *        Callable that takes the name of an xpi file to install and
  *        starts to install it.  Should return a Promise that resolves
  *        when the install is finished or rejects if the install is canceled.
+ * @param {string} telemetryBase
+ *        If supplied, the base type for telemetry events that should be
+ *        recorded for this install method.
  *
  * @returns {Promise}
  */
-async function testInstallMethod(installFn) {
+async function testInstallMethod(installFn, telemetryBase) {
   const PERMS_XPI = "browser_webext_permissions.xpi";
   const NO_PERMS_XPI = "browser_webext_nopermissions.xpi";
   const ID = "permissions@test.mozilla.org";
 
   await SpecialPowers.pushPrefEnv({set: [
     ["extensions.webapi.testing", true],
     ["extensions.install.requireBuiltInCerts", false],
 
     // XXX remove this when prompts are enabled by default
     ["extensions.webextPermissionPrompts", true],
   ]});
 
+  if (telemetryBase !== undefined) {
+    hookExtensionsTelemetry();
+  }
+
   let testURI = makeURI("https://example.com/");
   Services.perms.add(testURI, "install", Services.perms.ALLOW_ACTION);
   registerCleanupFunction(() => Services.perms.remove(testURI, "install"));
 
   async function runOnce(filename, cancel) {
     let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
 
     let installPromise = new Promise(resolve => {
@@ -311,16 +320,22 @@ async function testInstallMethod(install
   // 2. Same as #1 but with an extension that requests some permissions.
   await runOnce(PERMS_XPI, true);
 
   // 3. Repeat with the same extension from step 2 but this time,
   //    accept the permissions to install the extension.  (Then uninstall
   //    the extension to clean up.)
   await runOnce(PERMS_XPI, false);
 
+  if (telemetryBase !== undefined) {
+    // Should see 2 canceled installs followed by 1 successful install
+    // for this method.
+    expectTelemetry([`${telemetryBase}Rejected`, `${telemetryBase}Rejected`, `${telemetryBase}Accepted`]);
+  }
+
   await SpecialPowers.popPrefEnv();
 }
 
 // The tests in this directory install a bunch of extensions but they
 // need to uninstall them before exiting, as a stray leftover extension
 // after one test can foul up subsequent tests.
 // So, add a task to run before any tests that grabs a list of all the
 // add-ons that are pre-installed in the test environment and then checks
@@ -342,8 +357,26 @@ add_task(async function() {
     for (let addon of await AddonManager.getAllAddons()) {
       if (!existingAddons.has(addon.id)) {
         ok(false, `Addon ${addon.id} was left installed at the end of the test`);
         addon.uninstall();
       }
     }
   });
 });
+
+let collectedTelemetry = [];
+function hookExtensionsTelemetry() {
+  let originalHistogram = ExtensionsUI.histogram;
+  ExtensionsUI.histogram = {
+    add(value) { collectedTelemetry.push(value); },
+  };
+  registerCleanupFunction(() => {
+    is(collectedTelemetry.length, 0, "No unexamined telemetry after test is finished");
+    ExtensionsUI.histogram = originalHistogram;
+  });
+}
+
+function expectTelemetry(values) {
+  Assert.deepEqual(values, collectedTelemetry);
+  collectedTelemetry = [];
+}
+
new file mode 100644
--- /dev/null
+++ b/browser/base/content/theme-vars.inc.css
@@ -0,0 +1,166 @@
+%if 0
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+%endif
+
+:root[lwthemeicons~="--back-icon"] #back-button:-moz-lwtheme {
+  list-style-image: var(--back-icon) !important;
+}
+
+:root[lwthemeicons~="--forward-icon"] #forward-button:-moz-lwtheme {
+  list-style-image: var(--forward-icon) !important;
+}
+
+:root[lwthemeicons~="--reload-icon"] #urlbar-reload-button:-moz-lwtheme {
+  list-style-image: var(--reload-icon) !important;
+}
+
+:root[lwthemeicons~="--stop-icon"] #urlbar-stop-button:-moz-lwtheme {
+  list-style-image: var(--stop-icon) !important;
+}
+
+:root[lwthemeicons~="--bookmark_star-icon"] #bookmarks-menu-button:-moz-lwtheme {
+  list-style-image: var(--bookmark_star-icon) !important;
+}
+
+:root[lwthemeicons~="--bookmark_menu-icon"] #bookmarks-menu-button[cui-areatype='toolbar'] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:-moz-lwtheme {
+  list-style-image: var(--bookmark_menu-icon) !important;
+}
+
+:root[lwthemeicons~="--downloads-icon"] #downloads-button:-moz-lwtheme {
+  list-style-image: var(--downloads-icon) !important;
+}
+
+:root[lwthemeicons~="--home-icon"] #home-button:-moz-lwtheme {
+  list-style-image: var(--home-icon) !important;
+}
+
+:root[lwthemeicons~="--app_menu-icon"] #PanelUI-menu-button:-moz-lwtheme {
+  list-style-image: var(--app_menu-icon) !important;
+}
+
+:root[lwthemeicons~="--cut-icon"] #cut-button:-moz-lwtheme {
+  list-style-image: var(--cut-icon) !important;
+}
+
+:root[lwthemeicons~="--copy-icon"] #copy-button:-moz-lwtheme {
+  list-style-image: var(--copy-icon) !important;
+}
+
+:root[lwthemeicons~="--paste-icon"] #paste-button:-moz-lwtheme {
+  list-style-image: var(--paste-icon) !important;
+}
+
+:root[lwthemeicons~="--new_window-icon"] #new-window-button:-moz-lwtheme {
+  list-style-image: var(--new_window-icon) !important;
+}
+
+:root[lwthemeicons~="--new_private_window-icon"] #privatebrowsing-button:-moz-lwtheme {
+  list-style-image: var(--new_private_window-icon) !important;
+}
+
+:root[lwthemeicons~="--save_page-icon"] #save-page-button:-moz-lwtheme {
+  list-style-image: var(--save_page-icon) !important;
+}
+
+:root[lwthemeicons~="--print-icon"] #print-button:-moz-lwtheme {
+  list-style-image: var(--print-icon) !important;
+}
+
+:root[lwthemeicons~="--history-icon"] #history-panelmenu:-moz-lwtheme {
+  list-style-image: var(--history-icon) !important;
+}
+
+:root[lwthemeicons~="--full_screen-icon"] #fullscreen-button:-moz-lwtheme {
+  list-style-image: var(--full_screen-icon) !important;
+}
+
+:root[lwthemeicons~="--find-icon"] #find-button:-moz-lwtheme {
+  list-style-image: var(--find-icon) !important;
+}
+
+:root[lwthemeicons~="--options-icon"] #preferences-button:-moz-lwtheme {
+  list-style-image: var(--options-icon) !important;
+}
+
+:root[lwthemeicons~="--addons-icon"] #add-ons-button:-moz-lwtheme {
+  list-style-image: var(--addons-icon) !important;
+}
+
+:root[lwthemeicons~="--developer-icon"] #developer-button:-moz-lwtheme {
+  list-style-image: var(--developer-icon) !important;
+}
+
+:root[lwthemeicons~="--synced_tabs-icon"] #sync-button:-moz-lwtheme {
+  list-style-image: var(--synced_tabs-icon) !important;
+}
+
+:root[lwthemeicons~="--open_file-icon"] #open-file-button:-moz-lwtheme {
+  list-style-image: var(--open_file-icon) !important;
+}
+
+:root[lwthemeicons~="--sidebars-icon"] #sidebar-button:-moz-lwtheme {
+  list-style-image: var(--sidebars-icon) !important;
+}
+
+:root[lwthemeicons~="--share_page-icon"] #social-share-button:-moz-lwtheme {
+  list-style-image: var(--share_page-icon) !important;
+}
+
+:root[lwthemeicons~="--subscribe-icon"] #feed-button:-moz-lwtheme {
+  list-style-image: var(--subscribe-icon) !important;
+}
+
+:root[lwthemeicons~="--text_encoding-icon"] #characterencoding-button:-moz-lwtheme {
+  list-style-image: var(--text_encoding-icon) !important;
+}
+
+:root[lwthemeicons~="--email_link-icon"] #email-link-button:-moz-lwtheme {
+  list-style-image: var(--email_link-icon) !important;
+}
+
+:root[lwthemeicons~="--forget-icon"] #panic-button:-moz-lwtheme {
+  list-style-image: var(--forget-icon) !important;
+}
+
+:root[lwthemeicons~="--pocket-icon"] #pocket-button:-moz-lwtheme {
+  list-style-image: var(--pocket-icon) !important;
+}
+
+:root[lwthemeicons~="--back-icon"] #back-button:-moz-lwtheme,
+:root[lwthemeicons~="--forward-icon"] #forward-button:-moz-lwtheme,
+:root[lwthemeicons~="--bookmark_star-icon"] #bookmarks-menu-button:-moz-lwtheme,
+:root[lwthemeicons~="--bookmark_menu-icon"] #bookmarks-menu-button[cui-areatype='toolbar'] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:-moz-lwtheme,
+:root[lwthemeicons~="--downloads-icon"] #downloads-button:-moz-lwtheme,
+:root[lwthemeicons~="--home-icon"] #home-button:-moz-lwtheme,
+:root[lwthemeicons~="--app_menu-icon"] #PanelUI-menu-button:-moz-lwtheme,
+:root[lwthemeicons~="--cut-icon"] #cut-button:-moz-lwtheme,
+:root[lwthemeicons~="--copy-icon"] #copy-button:-moz-lwtheme,
+:root[lwthemeicons~="--paste-icon"] #paste-button:-moz-lwtheme,
+:root[lwthemeicons~="--new_window-icon"] #new-window-button:-moz-lwtheme,
+:root[lwthemeicons~="--new_private_window-icon"] #privatebrowsing-button:-moz-lwtheme,
+:root[lwthemeicons~="--save_page-icon"] #save-page-button:-moz-lwtheme,
+:root[lwthemeicons~="--print-icon"] #print-button:-moz-lwtheme,
+:root[lwthemeicons~="--history-icon"] #history-panelmenu:-moz-lwtheme,
+:root[lwthemeicons~="--full_screen-icon"] #fullscreen-button:-moz-lwtheme,
+:root[lwthemeicons~="--find-icon"] #find-button:-moz-lwtheme,
+:root[lwthemeicons~="--options-icon"] #preferences-button:-moz-lwtheme,
+:root[lwthemeicons~="--addons-icon"] #add-ons-button:-moz-lwtheme,
+:root[lwthemeicons~="--developer-icon"] #developer-button:-moz-lwtheme,
+:root[lwthemeicons~="--synced_tabs-icon"] #sync-button:-moz-lwtheme,
+:root[lwthemeicons~="--open_file-icon"] #open-file-button:-moz-lwtheme,
+:root[lwthemeicons~="--sidebars-icon"] #sidebar-button:-moz-lwtheme,
+:root[lwthemeicons~="--share_page-icon"] #social-share-button:-moz-lwtheme,
+:root[lwthemeicons~="--subscribe-icon"] #feed-button:-moz-lwtheme,
+:root[lwthemeicons~="--text_encoding-icon"] #characterencoding-button:-moz-lwtheme,
+:root[lwthemeicons~="--email_link-icon"] #email-link-button:-moz-lwtheme,
+:root[lwthemeicons~="--forget-icon"] #panic-button:-moz-lwtheme,
+:root[lwthemeicons~="--pocket-icon"] #pocket-button:-moz-lwtheme {
+  -moz-image-region: rect(0, 18px, 18px, 0) !important;
+}
+
+:root[lwthemeicons~="--reload-icon"] #urlbar-reload-button:-moz-lwtheme,
+:root[lwthemeicons~="--stop-icon"] #urlbar-stop-button:-moz-lwtheme {
+  -moz-image-region: rect(0, 14px, 14px, 0) !important;
+}
--- a/browser/components/extensions/ext-url-overrides.js
+++ b/browser/components/extensions/ext-url-overrides.js
@@ -3,102 +3,47 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
                                    "@mozilla.org/browser/aboutnewtab-service;1",
                                    "nsIAboutNewTabService");
-XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
-                                  "resource://gre/modules/Preferences.jsm");
 
 // Bug 1320736 tracks creating a generic precedence manager for handling
 // multiple addons modifying the same properties, and bug 1330494 has been filed
 // to track utilizing this manager for chrome_url_overrides. Until those land,
 // the edge cases surrounding multiple addons using chrome_url_overrides will
 // be ignored and precedence will be first come, first serve.
 let overrides = {
   // A queue of extensions in line to override the newtab page (sorted oldest to newest).
   newtab: [],
-  // A queue of extensions in line to override the home page (sorted oldest to newest).
-  home: [],
 };
 
-/**
- * Resets the specified page to its default value.
- *
- * @param {string} page The page to override. Accepted values are "newtab" and "home".
- */
-function resetPage(page) {
-  switch (page) {
-    case "newtab":
-      aboutNewTabService.resetNewTabURL();
-      break;
-    case "home":
-      Preferences.reset("browser.startup.homepage");
-      break;
-    default:
-      throw new Error("Unrecognized override type");
-  }
-}
-
-/**
- * Overrides the specified page to the specified URL.
- *
- * @param {string} page The page to override. Accepted values are "newtab" and "home".
- * @param {string} url The resolved URL to use for the page override.
- */
-function overridePage(page, url) {
-  switch (page) {
-    case "newtab":
-      aboutNewTabService.newTabURL = url;
-      break;
-    case "home":
-      Preferences.set("browser.startup.homepage", url);
-      break;
-    default:
-      throw new Error("Unrecognized override type");
-  }
-}
-
-/**
- * Updates the page to the URL specified by the extension next in line. If no extensions
- * are in line, the page is reset to its default value.
- *
- * @param {string} page The page to override.
- */
-function updatePage(page) {
-  if (overrides[page].length) {
-    overridePage(page, overrides[page][0].url);
-  } else {
-    resetPage(page);
-  }
-}
-
 /* eslint-disable mozilla/balanced-listeners */
 extensions.on("manifest_chrome_url_overrides", (type, directive, extension, manifest) => {
-  if (Object.keys(overrides).length > 1) {
-    extension.manifestError("Extensions can override only one page.");
-  }
+  if (manifest.chrome_url_overrides.newtab) {
+    let newtab = manifest.chrome_url_overrides.newtab;
+    let url = extension.baseURI.resolve(newtab);
 
-  for (let page of Object.keys(overrides)) {
-    if (manifest.chrome_url_overrides[page]) {
-      let relativeURL = manifest.chrome_url_overrides[page];
-      let url = extension.baseURI.resolve(relativeURL);
-      // Store the extension ID instead of a hard reference to the extension.
-      overrides[page].push({id: extension.id, url});
-      updatePage(page);
-      break;
+    // Only set the newtab URL if no other extension is overriding it.
+    if (!overrides.newtab.length) {
+      aboutNewTabService.newTabURL = url;
     }
+
+    overrides.newtab.push({id: extension.id, url});
   }
 });
 
 extensions.on("shutdown", (type, extension) => {
-  for (let page of Object.keys(overrides)) {
-    let i = overrides[page].findIndex(o => o.id === extension.id);
-    if (i !== -1) {
-      overrides[page].splice(i, 1);
-      updatePage(page);
+  let i = overrides.newtab.findIndex(o => o.id === extension.id);
+  if (i !== -1) {
+    overrides.newtab.splice(i, 1);
+
+    if (overrides.newtab.length) {
+      aboutNewTabService.newTabURL = overrides.newtab[0].url;
+    } else {
+      aboutNewTabService.resetNewTabURL();
     }
   }
 });
 /* eslint-enable mozilla/balanced-listeners */
--- a/browser/components/extensions/schemas/url_overrides.json
+++ b/browser/components/extensions/schemas/url_overrides.json
@@ -9,21 +9,16 @@
             "type": "object",
             "optional": true,
             "properties": {
               "newtab": {
                 "$ref": "ExtensionURL",
                 "optional": true,
                 "preprocess": "localize"
               },
-              "home": {
-                "$ref": "ExtensionURL",
-                "optional": true,
-                "preprocess": "localize"
-              },
               "bookmarks": {
                 "unsupported": true,
                 "$ref": "ExtensionURL",
                 "optional": true,
                 "preprocess": "localize"
               },
               "history": {
                 "unsupported": true,
--- a/browser/components/extensions/test/browser/browser-common.ini
+++ b/browser/components/extensions/test/browser/browser-common.ini
@@ -111,19 +111,18 @@ support-files =
 [browser_ext_tabs_query.js]
 [browser_ext_tabs_reload.js]
 [browser_ext_tabs_reload_bypass_cache.js]
 [browser_ext_tabs_sendMessage.js]
 [browser_ext_tabs_cookieStoreId.js]
 [browser_ext_tabs_update.js]
 [browser_ext_tabs_zoom.js]
 [browser_ext_tabs_update_url.js]
+[browser_ext_themes_icons.js]
 [browser_ext_topwindowid.js]
-[browser_ext_url_overrides_all.js]
-[browser_ext_url_overrides_home.js]
 [browser_ext_url_overrides_newtab.js]
 [browser_ext_webRequest.js]
 [browser_ext_webNavigation_frameId0.js]
 [browser_ext_webNavigation_getFrames.js]
 [browser_ext_webNavigation_onCreatedNavigationTarget.js]
 [browser_ext_webNavigation_onCreatedNavigationTarget_window_open.js]
 [browser_ext_webNavigation_urlbar_transitions.js]
 [browser_ext_windows.js]
--- a/browser/components/extensions/test/browser/browser_ext_contextMenus_icons.js
+++ b/browser/components/extensions/test/browser/browser_ext_contextMenus_icons.js
@@ -2,18 +2,17 @@
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 add_task(function* () {
   let tab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser,
     "http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html");
 
   let encodedImageData = "iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAC4klEQVRYhdWXLWzbQBSADQtDAwsHC1tUhUxqfL67lk2tdn+OJg0ODU0rLByqgqINBY6tmlbn7LMTJ5FaFVVBk1G0oUGjG2jT2Y7jxmmcbU/6iJ+f36fz+e5sGP9riCGm9hB37RG+scd4Yo/wsDXCZyIE2xuXsce4bY+wXkAsQtzYmExrfFgvkJkRbkzo1ehoxx5iXcgI/9iYUGt8WH9MqDXEcmNChmEYrRCf2SHWeYgQx3x0tLNRIeKQLTtEFyJEep4NTuhk8BC+yMrwEE3+iozo42d8gK7FAOkMsRiiN8QhW2ttSK5QTfRRV4QoymVeJMvPvDp7gCZigD613MN6yRFA3SWarow9QB9LCfG+NeF9qCtjAKOSQjCqVKhfVsiHEQ+grgx/lRGqUihAc1uL8EFD+KCRO+GrF4J61phcoRoPoEzkYhZYpykh5sMb7kOdIeY+jHKur4QI4Feh4AFX1nVeLxrAvQchGsBz5ls6wa2QdwcvIcE2863bTH79KOvsz/uUYJsp+J0pSzNlDckVqqVGUAF+n6uS7txcOl6wot4JVy70ufDLy4pWLUQVPE81pRI0mGe9oxLMHSeohHvMs/STUNaUK6vDPCvOyxMFDx4achehRDJmHnydnkPww5OFfLxrGIZBFDyYl4LpMzlTQFIP6AQx86w2UeYBccFpJrcKv5L9eGDtUAU6RIELqsB74uynjy/UBRF1gS5BTFxwQT1wTiXoUg9MH7m/3NZRRoi5IJytUbMgzv4Wc832+oQkiKgEehmyMkkpKsFkQV11QsRJL5rJYBLItQgRaUZEmnoZXsomz3vGiWw+I9KMF9SVFOqZEemZekli1jN3U/UOqhHHvC6oWWGElhfSpGdOk6+O9prdwvtLj5BjRsQxdRnot+Zeifpy/2/0stktKTRNLmbk0mwXyl8253fyojj+8rxOHNAhjjm5n0/5OOCGOKBzkrMO0Z75lvSAzKlrF32Z/3z8BqLAn+yMV7VhAAAAAElFTkSuQmCC";
-  let decodedImageData = atob(encodedImageData);
-  const IMAGE_ARRAYBUFFER = Uint8Array.from(decodedImageData, byte => byte.charCodeAt(0)).buffer;
+  const IMAGE_ARRAYBUFFER = imageBufferFromDataURI(encodedImageData);
 
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
       "permissions": ["contextMenus"],
       "icons": {
         "18": "extension.png",
       },
     },
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_themes_icons.js
@@ -0,0 +1,275 @@
+"use strict";
+
+const ENCODED_IMAGE_DATA = "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2NCA2NCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgNjQgNjQiPjxwYXRoIGQ9Im01NS45IDMyLjFsLTIyLjctMTQuOWMwIDAgMTIuOS0xNy40IDE5LjQtMTQuOSAzLjEgMS4xIDUuNCAyNS4xIDMuMyAyOS44IiBmaWxsPSIjM2U0MzQ3Ii8+PHBhdGggZD0ibTU0LjkgMzMuOWwtOS00LjFjMCAwLTUuMy0xNCA2LjEtMjQuMSAyLjQgMiA1LjEgMjUgMi45IDI4LjIiIGZpbGw9IiNmZmYiLz48cGF0aCBkPSJtOC4xIDMyLjFsMjIuNi0xNC45YzAgMC0xMi45LTE3LjQtMTkuNC0xNC45LTMgMS4xLTUuMyAyNS4xLTMuMiAyOS44IiBmaWxsPSIjM2U0MzQ3Ii8+PHBhdGggZD0ibTkuMSAzMy45bDktNC4xYzAgMCA1LjMtMTQtNi4xLTI0LjEtMi40IDItNS4xIDI1LTIuOSAyOC4yIiBmaWxsPSIjZmZmIi8+PHBhdGggZD0iTTMyLDEzQzE4LjksMTMsMiwzMy42LDIsNDUuNEMyMC41LDQ1LjQsMTkuNyw2MiwzMiw2MnMxMS41LTE2LjYsMzAtMTYuNkM2MiwzMy42LDQ1LjEsMTMsMzIsMTN6IiBmaWxsPSIjZmY4NzM2Ii8+PGcgZmlsbD0iI2ZmZiI+PHBhdGggZD0iTTMyLDU2LjJjMCw1LjEsOS42LDQuMiw5LjUtMi45YzYuNy05LjQsMTkuOS04LjcsMTkuOS04LjdDMzkuNiwzMi40LDMyLDU2LjIsMzIsNTYuMnoiLz48cGF0aCBkPSJNMzIsNTYuMmMwLDUuMS05LjYsNC4yLTkuNS0yLjlDMTUuOCw0NCwyLjYsNDQuNywyLjYsNDQuN0MyNC40LDMyLjQsMzIsNTYuMiwzMiw1Ni4yeiIvPjwvZz48ZyBmaWxsPSIjZmY4NzM2Ij48cGF0aCBkPSJtNTMuNCAxOC41Yy00IC43LTQuOSA2LjMtNC45IDYuM2w2IDUuM2MtMi4zLTUuOS0xLjEtMTEuNi0xLjEtMTEuNiIvPjxwYXRoIGQ9Im01MS4xIDEzLjVjLTQuNCAzLjktNS4xIDguNy01LjEgOC43bDYgNS4zYy0yLjQtNS44LS45LTE0LS45LTE0Ii8+PHBhdGggZD0ibTEwLjYgMTguNWM0IC43IDQuOSA2LjMgNC45IDYuM2wtNiA1LjNjMi4zLTUuOSAxLjEtMTEuNiAxLjEtMTEuNiIvPjxwYXRoIGQ9Im0xMi45IDEzLjVjNC40IDMuOSA1LjEgOC43IDUuMSA4LjdsLTYgNS4zYzIuNC01LjguOS0xNCAuOS0xNCIvPjwvZz48cGF0aCBkPSJtNTIuOCAzMS4xYy01LjctMS44LTEwLjktMy40LTEzLjguOS0yLjQgMy43LjcgOS40LjcgOS40IDExLjIgMS4yIDEzLjEtMTAuMyAxMy4xLTEwLjMiIGZpbGw9IiMzZTQzNDciLz48ZWxsaXBzZSBjeD0iNDMiIGN5PSIzNi4zIiByeD0iNC4yIiByeT0iNC4xIiBmaWxsPSIjZDVmZjgzIi8+PGcgZmlsbD0iIzNlNDM0NyI+PGVsbGlwc2UgY3g9IjQzIiBjeT0iMzYuMyIgcng9IjIuNyIgcnk9IjIuNyIvPjxwYXRoIGQ9Im0xMS4yIDMxLjFjNS43LTEuOCAxMC45LTMuNCAxMy43LjkgMi40IDMuNy0uNyA5LjQtLjcgOS40LTExLjEgMS4yLTEzLTEwLjMtMTMtMTAuMyIvPjwvZz48ZWxsaXBzZSBjeD0iMjEiIGN5PSIzNi4zIiByeD0iNC4yIiByeT0iNC4xIiBmaWxsPSIjZDVmZjgzIi8+PGcgZmlsbD0iIzNlNDM0NyI+PGVsbGlwc2UgY3g9IjIxIiBjeT0iMzYuMyIgcng9IjIuNyIgcnk9IjIuNyIvPjxwYXRoIGQ9Im00MS4yIDQ3LjljLS43LTIuMy0xLjgtNC40LTMtNi41IDEuMSAyLjEgMiA0LjMgMi41IDYuNi41IDIuMy43IDQuNyAwIDYuOC0uNCAxLTEgMi0xLjggMi42LS44LjYtMS44IDEtMi43IDEtLjkgMC0xLjktLjMtMi41LTEtLjYtLjctLjktMS42LS44LTIuNmwtLjkuMmgtLjljMCAxLS4yIDEuOS0uOCAyLjYtLjYuNy0xLjUgMS0yLjUgMS0uOSAwLTEuOS0uNC0yLjctMS0uOC0uNi0xLjQtMS42LTEuOC0yLjYtLjgtMi4xLS42LTQuNiAwLTYuOC41LTIuMyAxLjUtNC41IDIuNS02LjYtMS4yIDItMi4zIDQuMS0zIDYuNS0uNyAyLjMtMS4xIDQuOC0uNCA3LjMuMyAxLjIgMSAyLjQgMS45IDMuMy45LjkgMi4xIDEuNCAzLjQgMS41IDEuMi4xIDIuNi0uMiAzLjctMS4yLjMtLjIuNS0uNS43LS44LjIuMy40LjYuNy44IDEgMSAyLjQgMS4zIDMuNyAxLjIgMS4zLS4xIDIuNC0uNyAzLjQtMS41LjktLjkgMS42LTIgMS45LTMuMy41LTIuNi4xLTUuMi0uNi03LjUiLz48cGF0aCBkPSJtMzcuNiA1MC4zYy0xLjEtMS4xLTQuNS0xLjItNS42LTEuMi0xIDAtNC41LjEtNS42IDEuMi0uOC44LS4yIDIuOCAxLjkgNC41IDEuMyAxLjEgMi42IDEuNCAzLjYgMS40IDEgMCAyLjMtLjMgMy42LTEuNCAyLjMtMS43IDIuOS0zLjcgMi4xLTQuNSIvPjwvZz48L3N2Zz4=";
+
+  /**
+   * Verifies that the button uses the expected icon.
+   *
+   * @param {string} selector The CSS selector used to find the button
+   *   within the DOM.
+   * @param {boolean} shouldHaveCustomStyling True if the button should
+   *   have custom styling, False otherwise.
+   * @param {string} message The message that is printed to the console
+   *   by the verifyFn.
+   */
+function verifyButtonProperties(selector, shouldHaveCustomStyling, message) {
+  try {
+    let element;
+    // This selector is different than the others because it's the only
+    // toolbarbutton that we ship by default that has type="menu-button",
+    // which don't place a unique ID on the associated dropmarker-icon.
+    if (selector == "#bookmarks-menu-button > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon") {
+      if (message.includes("panel")) {
+        // The dropmarker isn't shown in the menupanel.
+        return;
+      }
+      element = document.querySelector("#bookmarks-menu-button");
+      element = document.getAnonymousElementByAttribute(element, "class", "toolbarbutton-menubutton-dropmarker");
+      element = document.getAnonymousElementByAttribute(element, "class", "dropmarker-icon");
+    } else {
+      element = document.querySelector(selector);
+    }
+
+    let listStyleImage = getComputedStyle(element).listStyleImage;
+    info(`listStyleImage for fox.svg is ${listStyleImage}`);
+    is(listStyleImage.includes("fox.svg"), shouldHaveCustomStyling, message);
+  } catch (ex) {
+    ok(false, `Unable to verify ${selector}: ${ex}`);
+  }
+}
+
+  /**
+   * Verifies that the button uses default styling.
+   *
+   * @param {string} selector The CSS selector used to find the button
+   *   within the DOM.
+   * @param {string} message The message that is printed to the console
+   *   by the verifyFn.
+   */
+function verifyButtonWithoutCustomStyling(selector, message) {
+  verifyButtonProperties(selector, false, message);
+}
+
+  /**
+   * Verifies that the button uses non-default styling.
+   *
+   * @param {string} selector The CSS selector used to find the button
+   *   within the DOM.
+   * @param {string} message The message that is printed to the console
+   *   by the verifyFn.
+   */
+function verifyButtonWithCustomStyling(selector, message) {
+  verifyButtonProperties(selector, true, message);
+}
+
+  /**
+   * Loops through all of the buttons to confirm that they are styled
+   * as expected (either with or without custom styling).
+   *
+   * @param {object} icons Array of an array that specifies which buttons should
+   *   have custom icons.
+   * @param {object} iconInfo An array of arrays that maps API names to
+   *   CSS selectors.
+   * @param {string} area The name of the area that the button resides in.
+   */
+function checkButtons(icons, iconInfo, area) {
+  for (let button of iconInfo) {
+    let iconInfo = icons.find(arr => arr[0] == button[0]);
+    if (iconInfo[1]) {
+      verifyButtonWithCustomStyling(button[1],
+        `The ${button[1]} should have it's icon customized in the ${area}`);
+    } else {
+      verifyButtonWithoutCustomStyling(button[1],
+        `The ${button[1]} should not have it's icon customized in the ${area}`);
+    }
+  }
+}
+
+function* runTestWithIcons(icons) {
+  const FRAME_COLOR = [71, 105, 91];
+  const TAB_TEXT_COLOR = [207, 221, 192, .9];
+  let manifest = {
+    "theme": {
+      "images": {
+        "theme_frame": "fox.svg",
+      },
+      "colors": {
+        "frame": FRAME_COLOR,
+        "tab_text": TAB_TEXT_COLOR,
+      },
+      "icons": {},
+    },
+  };
+  let files = {
+    "fox.svg": imageBufferFromDataURI(ENCODED_IMAGE_DATA),
+  };
+
+  // Each item in this array has the following setup:
+  // At position 0: The name that is used in the theme manifest.
+  // At position 1: The CSS selector for the button in the DOM.
+  // At position 2: The CustomizableUI name for the widget, only defined
+  //                if customizable.
+  const ICON_INFO = [
+    ["back", "#back-button"],
+    ["forward", "#forward-button"],
+    ["reload", "#urlbar-reload-button"],
+    ["stop", "#urlbar-stop-button"],
+    ["bookmark_star", "#bookmarks-menu-button", "bookmarks-menu-button"],
+    ["bookmark_menu", "#bookmarks-menu-button > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon"],
+    ["downloads", "#downloads-button", "downloads-button"],
+    ["home", "#home-button", "home-button"],
+    ["app_menu", "#PanelUI-menu-button"],
+    ["cut", "#cut-button", "edit-controls"],
+    ["copy", "#copy-button"],
+    ["paste", "#paste-button"],
+    ["new_window", "#new-window-button", "new-window-button"],
+    ["new_private_window", "#privatebrowsing-button", "privatebrowsing-button"],
+    ["save_page", "#save-page-button", "save-page-button"],
+    ["print", "#print-button", "print-button"],
+    ["history", "#history-panelmenu", "history-panelmenu"],
+    ["full_screen", "#fullscreen-button", "fullscreen-button"],
+    ["find", "#find-button", "find-button"],
+    ["options", "#preferences-button", "preferences-button"],
+    ["addons", "#add-ons-button", "add-ons-button"],
+    ["developer", "#developer-button", "developer-button"],
+    ["synced_tabs", "#sync-button", "sync-button"],
+    ["open_file", "#open-file-button", "open-file-button"],
+    ["sidebars", "#sidebar-button", "sidebar-button"],
+    ["share_page", "#social-share-button", "social-share-button"],
+    ["subscribe", "#feed-button", "feed-button"],
+    ["text_encoding", "#characterencoding-button", "characterencoding-button"],
+    ["email_link", "#email-link-button", "email-link-button"],
+    ["forget", "#panic-button", "panic-button"],
+    ["pocket", "#pocket-button", "pocket-button"],
+  ];
+
+  window.maximize();
+
+  for (let button of ICON_INFO) {
+    if (button[2]) {
+      CustomizableUI.addWidgetToArea(button[2], CustomizableUI.AREA_NAVBAR);
+    }
+
+    verifyButtonWithoutCustomStyling(button[1],
+      `The ${button[1]} should not have it's icon customized when the test starts`);
+
+    let iconInfo = icons.find(arr => arr[0] == button[0]);
+    manifest.theme.icons[button[0]] = iconInfo[1];
+  }
+
+  let extension = ExtensionTestUtils.loadExtension({manifest, files});
+
+  yield extension.startup();
+
+  checkButtons(icons, ICON_INFO, "toolbar");
+
+  for (let button of ICON_INFO) {
+    if (button[2]) {
+      CustomizableUI.addWidgetToArea(button[2], CustomizableUI.AREA_PANEL);
+    }
+  }
+
+  yield PanelUI.show();
+
+  checkButtons(icons, ICON_INFO, "panel");
+
+  yield PanelUI.hide();
+
+  yield extension.unload();
+
+  for (let button of ICON_INFO) {
+    verifyButtonWithoutCustomStyling(button[1],
+      `The ${button[1]} should not have it's icon customized when the theme is unloaded`);
+  }
+}
+
+add_task(function* setup() {
+  yield SpecialPowers.pushPrefEnv({
+    set: [["extensions.webextensions.themes.enabled", true],
+          ["extensions.webextensions.themes.icons.enabled", true]],
+  });
+});
+
+add_task(function* test_all_icons() {
+  let icons = [
+    ["back", "fox.svg"],
+    ["forward", "fox.svg"],
+    ["reload", "fox.svg"],
+    ["stop", "fox.svg"],
+    ["bookmark_star", "fox.svg"],
+    ["bookmark_menu", "fox.svg"],
+    ["downloads", "fox.svg"],
+    ["home", "fox.svg"],
+    ["app_menu", "fox.svg"],
+    ["cut", "fox.svg"],
+    ["copy", "fox.svg"],
+    ["paste", "fox.svg"],
+    ["new_window", "fox.svg"],
+    ["new_private_window", "fox.svg"],
+    ["save_page", "fox.svg"],
+    ["print", "fox.svg"],
+    ["history", "fox.svg"],
+    ["full_screen", "fox.svg"],
+    ["find", "fox.svg"],
+    ["options", "fox.svg"],
+    ["addons", "fox.svg"],
+    ["developer", "fox.svg"],
+    ["synced_tabs", "fox.svg"],
+    ["open_file", "fox.svg"],
+    ["sidebars", "fox.svg"],
+    ["share_page", "fox.svg"],
+    ["subscribe", "fox.svg"],
+    ["text_encoding", "fox.svg"],
+    ["email_link", "fox.svg"],
+    ["forget", "fox.svg"],
+    ["pocket", "fox.svg"],
+  ];
+  yield runTestWithIcons(icons);
+});
+
+add_task(function* teardown() {
+  CustomizableUI.reset();
+  window.restore();
+});
+
+add_task(function* test_some_icons() {
+  let icons = [
+    ["back", ""],
+    ["forward", ""],
+    ["reload", "fox.svg"],
+    ["stop", ""],
+    ["bookmark_star", ""],
+    ["bookmark_menu", ""],
+    ["downloads", ""],
+    ["home", "fox.svg"],
+    ["app_menu", "fox.svg"],
+    ["cut", ""],
+    ["copy", ""],
+    ["paste", ""],
+    ["new_window", ""],
+    ["new_private_window", ""],
+    ["save_page", ""],
+    ["print", ""],
+    ["history", ""],
+    ["full_screen", ""],
+    ["find", ""],
+    ["options", ""],
+    ["addons", ""],
+    ["developer", ""],
+    ["synced_tabs", ""],
+    ["open_file", ""],
+    ["sidebars", ""],
+    ["share_page", ""],
+    ["subscribe", ""],
+    ["text_encoding", ""],
+    ["email_link", ""],
+    ["forget", ""],
+    ["pocket", "fox.svg"],
+  ];
+  yield runTestWithIcons(icons);
+});
+
+add_task(function* teardown() {
+  CustomizableUI.reset();
+  window.restore();
+});
deleted file mode 100644
--- a/browser/components/extensions/test/browser/browser_ext_url_overrides_all.js
+++ /dev/null
@@ -1,97 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-
-"use strict";
-
-XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
-                                   "@mozilla.org/browser/aboutnewtab-service;1",
-                                   "nsIAboutNewTabService");
-
-const NEWTAB_URI = "webext-newtab.html";
-const HOME_URI = "webext-home.html";
-
-add_task(function* test_extensions_overriding_different_pages() {
-  let defaultHomePage = Preferences.get("browser.startup.homepage");
-  let defaultNewtabPage = aboutNewTabService.newTabURL;
-
-  is(Preferences.get("browser.startup.homepage"), defaultHomePage,
-    `Default home url should be ${defaultHomePage}`);
-  is(aboutNewTabService.newTabURL, defaultNewtabPage,
-    `Default newtab url should be ${defaultNewtabPage}`);
-
-  let ext1 = ExtensionTestUtils.loadExtension({
-    manifest: {"chrome_url_overrides": {}},
-  });
-
-  let ext2 = ExtensionTestUtils.loadExtension({
-    manifest: {"chrome_url_overrides": {newtab: NEWTAB_URI}},
-  });
-
-  let ext3 = ExtensionTestUtils.loadExtension({
-    manifest: {"chrome_url_overrides": {home: HOME_URI}},
-  });
-
-  yield ext1.startup();
-
-  is(aboutNewTabService.newTabURL, defaultNewtabPage,
-    `Default newtab url should still be ${defaultNewtabPage}`);
-  is(Preferences.get("browser.startup.homepage"), defaultHomePage,
-    `Default home url should be ${defaultHomePage}`);
-
-  yield ext2.startup();
-
-  ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI),
-    "Newtab url should be overriden by the second extension.");
-  is(Preferences.get("browser.startup.homepage"), defaultHomePage,
-    `Default home url should be ${defaultHomePage}`);
-
-  yield ext1.unload();
-
-  ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI),
-    "Newtab url should still be overriden by the second extension.");
-  is(Preferences.get("browser.startup.homepage"), defaultHomePage,
-    `Default home url should be ${defaultHomePage}`);
-
-  yield ext3.startup();
-
-  ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI),
-    "Newtab url should still be overriden by the second extension.");
-  ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI),
-    "Home url should be overriden by the third extension.");
-
-  yield ext2.unload();
-
-  is(aboutNewTabService.newTabURL, defaultNewtabPage,
-    `Newtab url should be reset to ${defaultNewtabPage}`);
-  ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI),
-    "Home url should still be overriden by the third extension.");
-
-  yield ext3.unload();
-
-  is(aboutNewTabService.newTabURL, defaultNewtabPage,
-    `Newtab url should be reset to ${defaultNewtabPage}`);
-  is(Preferences.get("browser.startup.homepage"), defaultHomePage,
-    `Home url should be reset to ${defaultHomePage}`);
-});
-
-add_task(function* test_extensions_with_multiple_overrides() {
-  let ext = ExtensionTestUtils.loadExtension({
-    manifest: {"chrome_url_overrides": {
-      newtab: NEWTAB_URI,
-      home: HOME_URI,
-    }},
-  });
-
-  SimpleTest.waitForExplicitFinish();
-  let waitForConsole = new Promise(resolve => {
-    SimpleTest.monitorConsole(resolve, [{
-      message: /Extensions can override only one page./,
-    }]);
-  });
-
-  yield ext.startup();
-  yield ext.unload();
-
-  SimpleTest.endMonitorConsole();
-  yield waitForConsole;
-});
deleted file mode 100644
--- a/browser/components/extensions/test/browser/browser_ext_url_overrides_home.js
+++ /dev/null
@@ -1,74 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-
-"use strict";
-
-XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
-                                  "resource://gre/modules/Preferences.jsm");
-
-const HOME_URI_1 = "webext-home-1.html";
-const HOME_URI_2 = "webext-home-2.html";
-const HOME_URI_3 = "webext-home-3.html";
-
-add_task(function* test_multiple_extensions_overriding_newtab_page() {
-  let defaultHomePage = Preferences.get("browser.startup.homepage");
-
-  is(Preferences.get("browser.startup.homepage"), defaultHomePage,
-     `Default home url should be ${defaultHomePage}`);
-
-  let ext1 = ExtensionTestUtils.loadExtension({
-    manifest: {"chrome_url_overrides": {}},
-  });
-
-  let ext2 = ExtensionTestUtils.loadExtension({
-    manifest: {"chrome_url_overrides": {home: HOME_URI_1}},
-  });
-
-  let ext3 = ExtensionTestUtils.loadExtension({
-    manifest: {"chrome_url_overrides": {home: HOME_URI_2}},
-  });
-
-  let ext4 = ExtensionTestUtils.loadExtension({
-    manifest: {"chrome_url_overrides": {home: HOME_URI_3}},
-  });
-
-  yield ext1.startup();
-
-  is(Preferences.get("browser.startup.homepage"), defaultHomePage,
-       `Default home url should still be ${defaultHomePage}`);
-
-  yield ext2.startup();
-
-  ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_1),
-     "Home url should be overriden by the second extension.");
-
-  yield ext1.unload();
-
-  ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_1),
-     "Home url should still be overriden by the second extension.");
-
-  yield ext3.startup();
-
-  ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_1),
-     "Home url should still be overriden by the second extension.");
-
-  yield ext2.unload();
-
-  ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_2),
-     "Home url should be overriden by the third extension.");
-
-  yield ext4.startup();
-
-  ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_2),
-     "Home url should be overriden by the third extension.");
-
-  yield ext4.unload();
-
-  ok(Preferences.get("browser.startup.homepage").endsWith(HOME_URI_2),
-     "Home url should be overriden by the third extension.");
-
-  yield ext3.unload();
-
-  is(Preferences.get("browser.startup.homepage"), defaultHomePage,
-     `Home url should be reset to ${defaultHomePage}`);
-});
--- a/browser/components/extensions/test/browser/browser_ext_url_overrides_newtab.js
+++ b/browser/components/extensions/test/browser/browser_ext_url_overrides_newtab.js
@@ -71,21 +71,21 @@ add_task(function* test_multiple_extensi
   is(aboutNewTabService.newTabURL, "about:newtab",
      "Newtab url should be reset to about:newtab");
 });
 
 add_task(function* test_sending_message_from_newtab_page() {
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
       "chrome_url_overrides": {
-        newtab: NEWTAB_URI_1,
+        newtab: NEWTAB_URI_2,
       },
     },
     files: {
-      [NEWTAB_URI_1]: `
+      [NEWTAB_URI_2]: `
         <!DOCTYPE html>
         <head>
           <meta charset="utf-8"/></head>
         <html>
           <body>
             <script src="newtab.js"></script>
           </body>
         </html>
--- a/browser/components/extensions/test/browser/head.js
+++ b/browser/components/extensions/test/browser/head.js
@@ -7,17 +7,18 @@
  *          clickBrowserAction clickPageAction
  *          getBrowserActionPopup getPageActionPopup
  *          closeBrowserAction closePageAction
  *          promisePopupShown promisePopupHidden
  *          openContextMenu closeContextMenu
  *          openExtensionContextMenu closeExtensionContextMenu
  *          openActionContextMenu openSubmenu closeActionContextMenu
  *          openTabContextMenu closeTabContextMenu
- *          imageBuffer getListStyleImage getPanelForNode
+ *          imageBuffer imageBufferFromDataURI
+ *          getListStyleImage getPanelForNode
  *          awaitExtensionPanel awaitPopupResize
  *          promiseContentDimensions alterContent
  */
 
 const {AppConstants} = Cu.import("resource://gre/modules/AppConstants.jsm", {});
 const {CustomizableUI} = Cu.import("resource:///modules/CustomizableUI.jsm", {});
 
 // We run tests under two different configurations, from browser.ini and
@@ -59,18 +60,23 @@ var focusWindow = Task.async(function* f
       resolve();
     }, {capture: true, once: true});
   });
 
   win.focus();
   yield promise;
 });
 
+function imageBufferFromDataURI(encodedImageData) {
+  let decodedImageData = atob(encodedImageData);
+  return Uint8Array.from(decodedImageData, byte => byte.charCodeAt(0)).buffer;
+}
+
 let img = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==";
-var imageBuffer = Uint8Array.from(atob(img), byte => byte.charCodeAt(0)).buffer;
+var imageBuffer = imageBufferFromDataURI(img);
 
 function getListStyleImage(button) {
   let style = button.ownerGlobal.getComputedStyle(button);
 
   let match = /^url\("(.*)"\)$/.exec(style.listStyleImage);
 
   return match && match[1];
 }
--- a/browser/components/feeds/nsFeedSniffer.cpp
+++ b/browser/components/feeds/nsFeedSniffer.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; 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 "nsFeedSniffer.h"
 
+#include "mozilla/Unused.h"
 
 #include "nsNetCID.h"
 #include "nsXPCOM.h"
 #include "nsCOMPtr.h"
 #include "nsStringStream.h"
 
 #include "nsBrowserCompsCID.h"
 
@@ -52,18 +53,18 @@ nsFeedSniffer::ConvertEncodedData(nsIReq
   nsresult rv = NS_OK;
 
  mDecodedData = "";
  nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(request));
   if (!httpChannel)
     return NS_ERROR_NO_INTERFACE;
 
   nsAutoCString contentEncoding;
-  httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Encoding"), 
-                                 contentEncoding);
+  mozilla::Unused << httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Encoding"),
+                                                    contentEncoding);
   if (!contentEncoding.IsEmpty()) {
     nsCOMPtr<nsIStreamConverterService> converterService(do_GetService(NS_STREAMCONVERTERSERVICE_CONTRACTID));
     if (converterService) {
       ToLowerCase(contentEncoding);
 
       nsCOMPtr<nsIStreamListener> converter;
       rv = converterService->AsyncConvertData(contentEncoding.get(), 
                                               "uncompressed", this, nullptr, 
@@ -208,17 +209,17 @@ nsFeedSniffer::GetMIMETypeFromContent(ns
                                       nsACString& sniffedType)
 {
   nsCOMPtr<nsIHttpChannel> channel(do_QueryInterface(request));
   if (!channel)
     return NS_ERROR_NO_INTERFACE;
 
   // Check that this is a GET request, since you can't subscribe to a POST...
   nsAutoCString method;
-  channel->GetRequestMethod(method);
+  mozilla::Unused << channel->GetRequestMethod(method);
   if (!method.EqualsLiteral("GET")) {
     sniffedType.Truncate();
     return NS_OK;
   }
 
   // We need to find out if this is a load of a view-source document. In this
   // case we do not want to override the content type, since the source display
   // does not need to be converted from feed format to XUL. More importantly, 
@@ -260,18 +261,20 @@ nsFeedSniffer::GetMIMETypeFromContent(ns
     // check for an attachment after we have a likely feed.
     if(HasAttachmentDisposition(channel)) {
       sniffedType.Truncate();
       return NS_OK;
     }
 
     // set the feed header as a response header, since we have good metadata
     // telling us that the feed is supposed to be RSS or Atom
-    channel->SetResponseHeader(NS_LITERAL_CSTRING("X-Moz-Is-Feed"),
-                               NS_LITERAL_CSTRING("1"), false);
+    mozilla::DebugOnly<nsresult> rv =
+      channel->SetResponseHeader(NS_LITERAL_CSTRING("X-Moz-Is-Feed"),
+                                 NS_LITERAL_CSTRING("1"), false);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
     sniffedType.AssignLiteral(TYPE_MAYBE_FEED);
     return NS_OK;
   }
 
   // Don't sniff arbitrary types.  Limit sniffing to situations that
   // we think can reasonably arise.
   if (!contentType.EqualsLiteral(TEXT_HTML) &&
       !contentType.EqualsLiteral(APPLICATION_OCTET_STREAM) &&
--- a/browser/components/places/content/places.js
+++ b/browser/components/places/content/places.js
@@ -308,17 +308,17 @@ var PlacesOrganizer = {
 
     let node = this._places.selectedNode;
     if (node) {
       let middleClick = aEvent.button == 1 && aEvent.detail == 1;
       if (middleClick && PlacesUtils.nodeIsContainer(node)) {
         // The command execution function will take care of seeing if the
         // selection is a folder or a different container type, and will
         // load its contents in tabs.
-        PlacesUIUtils.openContainerNodeInTabs(selectedNode, aEvent, this._places);
+        PlacesUIUtils.openContainerNodeInTabs(node, aEvent, this._places);
       }
     }
   },
 
   /**
    * Handle focus changes on the places list and the current content view.
    */
   updateDetailsPane: function PO_updateDetailsPane() {
--- a/browser/components/places/tests/browser/browser.ini
+++ b/browser/components/places/tests/browser/browser.ini
@@ -34,16 +34,17 @@ support-files =
 [browser_drag_bookmarks_on_toolbar.js]
 [browser_forgetthissite_single.js]
 [browser_history_sidebar_search.js]
 [browser_library_batch_delete.js]
 [browser_library_commands.js]
 [browser_library_downloads.js]
 [browser_library_infoBox.js]
 [browser_library_left_pane_fixnames.js]
+[browser_library_left_pane_middleclick.js]
 [browser_library_left_pane_select_hierarchy.js]
 [browser_library_middleclick.js]
 [browser_library_open_leak.js]
 [browser_library_openFlatContainer.js]
 [browser_library_panel_leak.js]
 [browser_library_search.js]
 [browser_library_views_liveupdate.js]
 [browser_markPageAsFollowedLink.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/places/tests/browser/browser_library_left_pane_middleclick.js
@@ -0,0 +1,196 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+ /**
+ * Tests middle-clicking items in the Library.
+ */
+
+const ENABLE_HISTORY_PREF = "places.history.enabled";
+
+var gLibrary = null;
+var gTests = [];
+var gCurrentTest = null;
+
+// Listener for TabOpen and tabs progress.
+var gTabsListener = {
+  _loadedURIs: [],
+  _openTabsCount: 0,
+
+  handleEvent(aEvent) {
+    if (aEvent.type != "TabOpen")
+      return;
+
+    if (++this._openTabsCount == gCurrentTest.URIs.length) {
+      is(gBrowser.tabs.length, gCurrentTest.URIs.length + 1,
+         "We have opened " + gCurrentTest.URIs.length + " new tab(s)");
+    }
+
+    var tab = aEvent.target;
+    is(tab.ownerGlobal, window,
+       "Tab has been opened in current browser window");
+  },
+
+  onLocationChange(aBrowser, aWebProgress, aRequest, aLocationURI,
+                             aFlags) {
+    var spec = aLocationURI.spec;
+    ok(true, spec);
+    // When a new tab is opened, location is first set to "about:blank", so
+    // we can ignore those calls.
+    // Ignore multiple notifications for the same URI too.
+    if (spec == "about:blank" || this._loadedURIs.includes(spec))
+      return;
+
+    ok(gCurrentTest.URIs.includes(spec),
+       "Opened URI found in list: " + spec);
+
+    if (gCurrentTest.URIs.includes(spec))
+      this._loadedURIs.push(spec);
+
+    if (this._loadedURIs.length == gCurrentTest.URIs.length) {
+      // We have correctly opened all URIs.
+
+      // Reset arrays.
+      this._loadedURIs.length = 0;
+
+      this._openTabsCount = 0;
+
+      executeSoon(function() {
+        // Close all tabs.
+        while (gBrowser.tabs.length > 1)
+          gBrowser.removeCurrentTab();
+
+        // Test finished.  This will move to the next one.
+        waitForFocus(gCurrentTest.finish, gBrowser.ownerGlobal);
+      });
+    }
+  }
+}
+
+// ------------------------------------------------------------------------------
+// Open a folder in tabs.
+
+gTests.push({
+  desc: "Open a folder in tabs.",
+  URIs: ["about:buildconfig", "about:"],
+  _folderId: -1,
+
+  setup() {
+    var bs = PlacesUtils.bookmarks;
+    // Create a new folder.
+    var folderId = bs.createFolder(bs.unfiledBookmarksFolder,
+                                   "Folder",
+                                   bs.DEFAULT_INDEX);
+    this._folderId = folderId;
+
+    // Add bookmarks in folder.
+    this.URIs.forEach(function(aURI) {
+      bs.insertBookmark(folderId,
+                        PlacesUtils._uri(aURI),
+                        bs.DEFAULT_INDEX,
+                        "Title");
+    });
+
+    // Select unsorted bookmarks root in the left pane.
+    gLibrary.PlacesOrganizer.selectLeftPaneQuery("UnfiledBookmarks");
+    isnot(gLibrary.PlacesOrganizer._places.selectedNode, null,
+          "We correctly have selection in the Library left pane");
+    // Get our bookmark in the right pane.
+    var folderNode = gLibrary.ContentTree.view.view.nodeForTreeIndex(0);
+    is(folderNode.title, "Folder", "Found folder in the right pane");
+  },
+
+  finish() {
+    setTimeout(runNextTest, 0);
+  },
+
+  cleanup() {
+    PlacesUtils.bookmarks.removeItem(this._folderId);
+  }
+});
+
+// ------------------------------------------------------------------------------
+
+function test() {
+  waitForExplicitFinish();
+
+  // Sanity checks.
+  ok(PlacesUtils, "PlacesUtils in context");
+  ok(PlacesUIUtils, "PlacesUIUtils in context");
+
+  // Add tabs listeners.
+  gBrowser.tabContainer.addEventListener("TabOpen", gTabsListener);
+  gBrowser.addTabsProgressListener(gTabsListener);
+
+  // Temporary disable history, so we won't record pages navigation.
+  gPrefService.setBoolPref(ENABLE_HISTORY_PREF, false);
+
+  // Open Library window.
+  openLibrary(function(library) {
+    gLibrary = library;
+    // Kick off tests.
+    runNextTest();
+  });
+}
+
+function runNextTest() {
+  // Cleanup from previous test.
+  if (gCurrentTest)
+    gCurrentTest.cleanup();
+
+  if (gTests.length > 0) {
+    // Goto next test.
+    gCurrentTest = gTests.shift();
+    info("Start of test: " + gCurrentTest.desc);
+    // Test setup will set Library so that the bookmark to be opened is the
+    // first node in the content (right pane) tree.
+    gCurrentTest.setup();
+
+    gLibrary.focus();
+    waitForFocus(function() {
+      // Open the "Other Bookmarks" folder.
+      gLibrary.PlacesOrganizer.selectLeftPaneQuery("UnfiledBookmarks");
+      gLibrary.PlacesOrganizer._places.selectedNode.containerOpen = true;
+      // Now middle-click on the bookmark contained with it.
+      let bookmarkedNode = gLibrary.PlacesOrganizer._places.selectedNode.getChild(0);
+      mouseEventOnCell(gLibrary.PlacesOrganizer._places,
+        gLibrary.PlacesOrganizer._places.view.treeIndexForNode(bookmarkedNode),
+        0,
+        { button: 1 });
+    }, gLibrary);
+  } else {
+    // No more tests.
+
+    // We must close "Other Bookmarks" ready for other tests.
+    gLibrary.PlacesOrganizer.selectLeftPaneQuery("UnfiledBookmarks");
+    gLibrary.PlacesOrganizer._places.selectedNode.containerOpen = false;
+
+    // Close Library window.
+    gLibrary.close();
+
+    // Remove tabs listeners.
+    gBrowser.tabContainer.removeEventListener("TabOpen", gTabsListener);
+    gBrowser.removeTabsProgressListener(gTabsListener);
+
+    // Restore history.
+    try {
+      gPrefService.clearUserPref(ENABLE_HISTORY_PREF);
+    } catch (ex) {}
+
+    finish();
+  }
+}
+
+function mouseEventOnCell(aTree, aRowIndex, aColumnIndex, aEventDetails) {
+  var selection = aTree.view.selection;
+  selection.select(aRowIndex);
+  aTree.treeBoxObject.ensureRowIsVisible(aRowIndex);
+  var column = aTree.columns[aColumnIndex];
+
+  // get cell coordinates
+  var rect = aTree.treeBoxObject.getCoordsForCellItem(aRowIndex, column, "text");
+
+  EventUtils.synthesizeMouse(aTree.body, rect.x, rect.y,
+                             aEventDetails, gLibrary);
+}
--- a/browser/components/sessionstore/ContentRestore.jsm
+++ b/browser/components/sessionstore/ContentRestore.jsm
@@ -15,17 +15,17 @@ XPCOMUtils.defineLazyModuleGetter(this, 
   "resource:///modules/sessionstore/DocShellCapabilities.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "FormData",
   "resource://gre/modules/FormData.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PageStyle",
   "resource:///modules/sessionstore/PageStyle.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ScrollPosition",
   "resource://gre/modules/ScrollPosition.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "SessionHistory",
-  "resource:///modules/sessionstore/SessionHistory.jsm");
+  "resource://gre/modules/sessionstore/SessionHistory.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "SessionStorage",
   "resource:///modules/sessionstore/SessionStorage.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Utils",
   "resource://gre/modules/sessionstore/Utils.jsm");
 
 /**
  * This module implements the content side of session restoration. The chrome
  * side is handled by SessionStore.jsm. The functions in this module are called
--- a/browser/components/sessionstore/content/content-sessionStore.js
+++ b/browser/components/sessionstore/content/content-sessionStore.js
@@ -23,17 +23,17 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 
 XPCOMUtils.defineLazyModuleGetter(this, "DocShellCapabilities",
   "resource:///modules/sessionstore/DocShellCapabilities.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PageStyle",
   "resource:///modules/sessionstore/PageStyle.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ScrollPosition",
   "resource://gre/modules/ScrollPosition.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "SessionHistory",
-  "resource:///modules/sessionstore/SessionHistory.jsm");
+  "resource://gre/modules/sessionstore/SessionHistory.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "SessionStorage",
   "resource:///modules/sessionstore/SessionStorage.jsm");
 
 Cu.import("resource:///modules/sessionstore/FrameTree.jsm", this);
 var gFrameTree = new FrameTree(this);
 
 Cu.import("resource:///modules/sessionstore/ContentRestore.jsm", this);
 XPCOMUtils.defineLazyGetter(this, 'gContentRestore',
--- a/browser/components/sessionstore/moz.build
+++ b/browser/components/sessionstore/moz.build
@@ -28,17 +28,16 @@ EXTRA_JS_MODULES.sessionstore = [
     'FrameTree.jsm',
     'GlobalState.jsm',
     'PageStyle.jsm',
     'PrivacyFilter.jsm',
     'RecentlyClosedTabsAndWindowsMenuUtils.jsm',
     'RunState.jsm',
     'SessionCookies.jsm',
     'SessionFile.jsm',
-    'SessionHistory.jsm',
     'SessionMigration.jsm',
     'SessionSaver.jsm',
     'SessionStorage.jsm',
     'SessionStore.jsm',
     'SessionWorker.js',
     'SessionWorker.jsm',
     'StartupPerformance.jsm',
     'TabAttributes.jsm',
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -438,16 +438,18 @@ offlineApps.usage=This website (%S) is n
 offlineApps.manageUsage=Show settings
 offlineApps.manageUsageAccessKey=S
 
 identity.identified.verifier=Verified by: %S
 identity.identified.verified_by_you=You have added a security exception for this site.
 identity.identified.state_and_country=%S, %S
 
 identity.icon.tooltip=Show site information
+identity.showDetails.tooltip=Show connection details
+identity.hideDetails.tooltip=Hide connection details
 
 trackingProtection.intro.title=How Tracking Protection works
 # LOCALIZATION NOTE (trackingProtection.intro.description2):
 # %S is brandShortName. This string should match the one from Step 1 of the tour
 # when it starts from the button shown when a new private window is opened.
 trackingProtection.intro.description2=When you see the shield, %S is blocking some parts of the page that could track your browsing activity.
 # LOCALIZATION NOTE (trackingProtection.intro.step1of3): Indicates that the intro panel is step one of three in a tour.
 trackingProtection.intro.step1of3=1 of 3
--- a/browser/modules/DirectoryLinksProvider.jsm
+++ b/browser/modules/DirectoryLinksProvider.jsm
@@ -190,17 +190,17 @@ var DirectoryLinksProvider = {
   get locale() {
     let matchOS;
     try {
       matchOS = Services.prefs.getBoolPref(PREF_MATCH_OS_LOCALE);
     } catch (e) {}
 
     if (matchOS) {
       return Cc["@mozilla.org/intl/ospreferences;1"].
-             getService(Ci.mozIOSPreferences).getSystemLocale();
+             getService(Ci.mozIOSPreferences).systemLocale;
     }
 
     try {
       let locale = Services.prefs.getComplexValue(PREF_SELECTED_LOCALE,
                                                   Ci.nsIPrefLocalizedString);
       if (locale) {
         return locale.data;
       }
--- a/browser/modules/ExtensionsUI.jsm
+++ b/browser/modules/ExtensionsUI.jsm
@@ -28,18 +28,21 @@ const BROWSER_PROPERTIES = "chrome://bro
 const BRAND_PROPERTIES = "chrome://branding/locale/brand.properties";
 
 const HTML_NS = "http://www.w3.org/1999/xhtml";
 
 this.ExtensionsUI = {
   sideloaded: new Set(),
   updates: new Set(),
   sideloadListener: null,
+  histogram: null,
 
   init() {
+    this.histogram = Services.telemetry.getHistogramById("EXTENSION_INSTALL_PROMPT_RESULT");
+
     Services.obs.addObserver(this, "webextension-permission-prompt", false);
     Services.obs.addObserver(this, "webextension-update-permissions", false);
     Services.obs.addObserver(this, "webextension-install-notify", false);
 
     this._checkForSideloaded();
   },
 
   _checkForSideloaded() {
@@ -83,43 +86,44 @@ this.ExtensionsUI = {
         let win = RecentWindow.getMostRecentBrowserWindow();
         for (let addon of sideloaded) {
           win.openUILinkIn(`about:newaddon?id=${addon.id}`, "tab");
         }
       }
     });
   },
 
-  showAddonsManager(browser, strings, icon) {
+  showAddonsManager(browser, strings, icon, histkey) {
     let global = browser.selectedBrowser.ownerGlobal;
     return global.BrowserOpenAddonsMgr("addons://list/extension").then(aomWin => {
       let aomBrowser = aomWin.QueryInterface(Ci.nsIInterfaceRequestor)
                              .getInterface(Ci.nsIDocShell)
                              .chromeEventHandler;
-      return this.showPermissionsPrompt(aomBrowser, strings, icon);
+      return this.showPermissionsPrompt(aomBrowser, strings, icon, histkey);
     });
   },
 
   showSideloaded(browser, addon) {
     addon.markAsSeen();
     this.sideloaded.delete(addon);
     this.emit("change");
 
     let strings = this._buildStrings({
       addon,
       permissions: addon.userPermissions,
       type: "sideload",
     });
-    this.showAddonsManager(browser, strings, addon.iconURL).then(answer => {
-      addon.userDisabled = !answer;
-    });
+    this.showAddonsManager(browser, strings, addon.iconURL, "sideload")
+        .then(answer => {
+          addon.userDisabled = !answer;
+        });
   },
 
   showUpdate(browser, info) {
-    this.showAddonsManager(browser, info.strings, info.addon.iconURL)
+    this.showAddonsManager(browser, info.strings, info.addon.iconURL, "update")
         .then(answer => {
           if (answer) {
             info.resolve();
           } else {
             info.reject();
           }
           // At the moment, this prompt will re-appear next time we do an update
           // check.  See bug 1332360 for proposal to avoid this.
@@ -142,23 +146,37 @@ this.ExtensionsUI = {
 
       let strings = this._buildStrings(info);
       // If this is an update with no promptable permissions, just apply it
       if (info.type == "update" && strings.msgs.length == 0) {
         info.resolve();
         return;
       }
 
-      this.showPermissionsPrompt(target, strings, info.icon).then(answer => {
-        if (answer) {
-          info.resolve();
-        } else {
-          info.reject();
-        }
-      });
+      let histkey;
+      if (info.type == "sideload") {
+        histkey = "sideload";
+      } else if (info.type == "update") {
+        histkey = "update";
+      } else if (info.source == "AMO") {
+        histkey = "installAmo";
+      } else if (info.source == "local") {
+        histkey = "installLocal";
+      } else {
+        histkey = "installWeb";
+      }
+
+      this.showPermissionsPrompt(target, strings, info.icon, histkey)
+          .then(answer => {
+            if (answer) {
+              info.resolve();
+            } else {
+              info.reject();
+            }
+          });
     } else if (topic == "webextension-update-permissions") {
       let info = subject.wrappedJSObject;
       info.type = "update";
       let strings = this._buildStrings(info);
 
       // If we don't prompt for any new permissions, just apply it
       if (strings.msgs.length == 0) {
         info.resolve();
@@ -302,17 +320,17 @@ this.ExtensionsUI = {
       result.text = bundle.formatStringFromName("webextPerms.updateText", [addonName], 1);
       result.acceptText = bundle.GetStringFromName("webextPerms.updateAccept.label");
       result.acceptKey = bundle.GetStringFromName("webextPerms.updateAccept.accessKey");
     }
 
     return result;
   },
 
-  showPermissionsPrompt(browser, strings, icon) {
+  showPermissionsPrompt(browser, strings, icon, histkey) {
     function eventCallback(topic) {
       if (topic == "showing") {
         let doc = this.browser.ownerDocument;
         doc.getElementById("addon-webext-perm-header").innerHTML = strings.header;
 
         let textEl = doc.getElementById("addon-webext-perm-text");
         textEl.innerHTML = strings.text;
         textEl.hidden = !strings.text;
@@ -344,23 +362,29 @@ this.ExtensionsUI = {
       eventCallback,
     };
 
     let win = browser.ownerGlobal;
     return new Promise(resolve => {
       let action = {
         label: strings.acceptText,
         accessKey: strings.acceptKey,
-        callback: () => resolve(true),
+        callback: () => {
+          this.histogram.add(histkey + "Accepted");
+          resolve(true);
+        },
       };
       let secondaryActions = [
         {
           label: strings.cancelText,
           accessKey: strings.cancelKey,
-          callback: () => resolve(false),
+          callback: () => {
+            this.histogram.add(histkey + "Rejected");
+            resolve(false);
+          },
         },
       ];
 
       win.PopupNotifications.show(browser, "addon-webext-permissions", "",
                                   "addons-notification-icon",
                                   action, secondaryActions, popupOptions);
     });
   },
--- a/browser/themes/shared/customizableui/panelUI.inc.css
+++ b/browser/themes/shared/customizableui/panelUI.inc.css
@@ -799,16 +799,17 @@ toolbarpaletteitem[place="palette"] > to
 
 .PanelUI-remotetabs-notabsforclient-label {
   color: GrayText;
   /* This margin is to line this label up with the labels in toolbarbuttons. */
   margin-left: 28px;
 }
 
 .fxaSyncIllustration {
+  width: 180px;
   height: var(--panel-ui-sync-illustration-height);
 }
 
 .PanelUI-remotetabs-prefs-button > .toolbarbutton-text {
   /* !important to override ".cui-widget-panel toolbarbutton > .toolbarbutton-text" above. */
   text-align: center !important;
   text-shadow: none;
 }
--- a/browser/themes/shared/fxa/sync-illustration.svg
+++ b/browser/themes/shared/fxa/sync-illustration.svg
@@ -1,13 +1,13 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- 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/. -->
-<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid" width="320" height="280" viewBox="0 0 320 280" xmlns:xlink="http://www.w3.org/1999/xlink" >
+<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid" viewBox="0 0 320 280" xmlns:xlink="http://www.w3.org/1999/xlink" >
 <style>
 	#blueFill:target ~ use,
 	#blueFill:target ~ g {
 		fill: #bfcbd3;
 	}
 
 	svg {
 		fill:#cdcdcd;
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -59,17 +59,16 @@
 #include "mozilla/dom/BindingUtils.h"
 #include <stdint.h>
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/StaticPtr.h"
 #include "nsContentUtils.h"
 #include "nsJSUtils.h"
 #include "nsILoadInfo.h"
-#include "nsXPCOMStrings.h"
 
 // This should be probably defined on some other place... but I couldn't find it
 #define WEBAPPS_PERM_NAME "webapps-manage"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsIIOService    *nsScriptSecurityManager::sIOService = nullptr;
--- a/devtools/client/devtools-startup.js
+++ b/devtools/client/devtools-startup.js
@@ -8,17 +8,17 @@
  * core modules like 'devtools-browser.js' that hooks the browser windows
  * and ensure setting up tools.
  *
  * Be careful to lazy load dependencies as much as possible.
  **/
 
 "use strict";
 
-const { interfaces: Ci, utils: Cu } = Components;
+const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 const kDebuggerPrefs = [
   "devtools.debugger.remote-enabled",
   "devtools.chrome.enabled"
 ];
 const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
 XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm");
 
 function DevToolsStartup() {}
@@ -119,19 +119,38 @@ DevToolsStartup.prototype = {
     }
     return remoteDebuggingEnabled;
   },
 
   handleDebuggerFlag: function (cmdLine) {
     if (!this._isRemoteDebuggingEnabled()) {
       return;
     }
+
+    let devtoolsThreadResumed = false;
+    let pauseOnStartup = cmdLine.handleFlag("wait-for-jsdebugger", false);
+    if (pauseOnStartup) {
+      let observe = function (subject, topic, data) {
+        devtoolsThreadResumed = true;
+        Services.obs.removeObserver(observe, "devtools-thread-resumed");
+      };
+      Services.obs.addObserver(observe, "devtools-thread-resumed", false);
+    }
+
     const { BrowserToolboxProcess } = Cu.import("resource://devtools/client/framework/ToolboxProcess.jsm", {});
     BrowserToolboxProcess.init();
 
+    if (pauseOnStartup) {
+      // Spin the event loop until the debugger connects.
+      let thread = Cc["@mozilla.org/thread-manager;1"].getService().currentThread;
+      while (!devtoolsThreadResumed) {
+        thread.processNextEvent(true);
+      }
+    }
+
     if (cmdLine.state == Ci.nsICommandLine.STATE_REMOTE_AUTO) {
       cmdLine.preventDefault = true;
     }
   },
 
   /**
    * Handle the --start-debugger-server command line flag. The options are:
    * --start-debugger-server
@@ -198,16 +217,19 @@ DevToolsStartup.prototype = {
     if (cmdLine.state == Ci.nsICommandLine.STATE_REMOTE_AUTO) {
       cmdLine.preventDefault = true;
     }
   },
 
   /* eslint-disable max-len */
   helpInfo: "  --jsconsole        Open the Browser Console.\n" +
             "  --jsdebugger       Open the Browser Toolbox.\n" +
+            "  --wait-for-jsdebugger Spin event loop until JS debugger connects.\n" +
+            "                     Enables debugging (some) application startup code paths.\n" +
+            "                     Only has an effect when `--jsdebugger` is also supplied.\n" +
             "  --devtools         Open DevTools on initial load.\n" +
             "  --start-debugger-server [ws:][ <port> | <path> ] Start the debugger server on\n" +
             "                     a TCP port or Unix domain socket path. Defaults to TCP port\n" +
             "                     6000. Use WebSocket protocol if ws: prefix is specified.\n",
   /* eslint-disable max-len */
 
   classID: Components.ID("{9e9a9283-0ce9-4e4a-8f1c-ba129a032c32}"),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]),
--- a/devtools/client/shared/components/reps/reps.js
+++ b/devtools/client/shared/components/reps/reps.js
@@ -55,23 +55,25 @@ return /******/ (function(modules) { // 
 /***/ function(module, exports, __webpack_require__) {
 
 	const { MODE } = __webpack_require__(1);
 	const { REPS } = __webpack_require__(2);
 	const {
 	  createFactories,
 	  parseURLEncodedText,
 	  parseURLParams,
-	  getSelectableInInspectorGrips
+	  getSelectableInInspectorGrips,
+	  maybeEscapePropertyName
 	} = __webpack_require__(4);
 	
 	module.exports = {
 	  REPS,
 	  MODE,
 	  createFactories,
+	  maybeEscapePropertyName,
 	  parseURLEncodedText,
 	  parseURLParams,
 	  getSelectableInInspectorGrips
 	};
 
 /***/ },
 /* 1 */
 /***/ function(module, exports) {
@@ -349,16 +351,39 @@ return /******/ (function(modules) { // 
 	      }
 	      // Other surrogate characters are passed through.
 	      return match;
 	    }
 	    return "\\u" + ("0000" + c.toString(16)).substr(-4);
 	  }) + "\"";
 	}
 	
+	/**
+	 * Escape a property name, if needed.  "Escaping" in this context
+	 * means surrounding the property name with quotes.
+	 *
+	 * @param {String}
+	 *        name the property name
+	 * @return {String} either the input, or the input surrounded by
+	 *                  quotes, properly quoted in JS syntax.
+	 */
+	function maybeEscapePropertyName(name) {
+	  // Quote the property name if it needs quoting.  This particular
+	  // test is an approximation; see
+	  // https://mathiasbynens.be/notes/javascript-properties.  However,
+	  // the full solution requires a fair amount of Unicode data, and so
+	  // let's defer that until either it's important, or the \p regexp
+	  // syntax lands, see
+	  // https://github.com/tc39/proposal-regexp-unicode-property-escapes.
+	  if (!/^\w+$/.test(name)) {
+	    name = escapeString(name);
+	  }
+	  return name;
+	}
+	
 	function cropMultipleLines(text, limit) {
 	  return escapeNewLines(cropString(text, limit));
 	}
 	
 	function rawCropString(text, limit, alternativeText) {
 	  if (!alternativeText) {
 	    alternativeText = "\u2026";
 	  }
@@ -582,17 +607,18 @@ return /******/ (function(modules) { // 
 	  sanitizeString,
 	  escapeString,
 	  wrapRender,
 	  cropMultipleLines,
 	  parseURLParams,
 	  parseURLEncodedText,
 	  getFileName,
 	  getURLDisplayString,
-	  getSelectableInInspectorGrips
+	  getSelectableInInspectorGrips,
+	  maybeEscapePropertyName
 	};
 
 /***/ },
 /* 5 */
 /***/ function(module, exports) {
 
 	module.exports = {
 	  ELEMENT_NODE: 1,
@@ -973,19 +999,19 @@ return /******/ (function(modules) { // 
 	    function isInteger(x) {
 	      let y = parseInt(x, 10);
 	      if (isNaN(y)) {
 	        return false;
 	      }
 	      return x === y.toString();
 	    }
 	
-	    let props = Object.getOwnPropertyNames(array);
-	    for (let i = 0; i < props.length; i++) {
-	      let p = props[i];
+	    let propsArray = Object.getOwnPropertyNames(array);
+	    for (let i = 0; i < propsArray.length; i++) {
+	      let p = propsArray[i];
 	
 	      // Valid indexes are skipped
 	      if (isInteger(p)) {
 	        continue;
 	      }
 	
 	      // Ignore standard 'length' property, anything else is custom.
 	      if (p != "length") {
@@ -1263,16 +1289,17 @@ return /******/ (function(modules) { // 
 /***/ },
 /* 14 */
 /***/ function(module, exports, __webpack_require__) {
 
 	// Dependencies
 	const React = __webpack_require__(3);
 	const {
 	  createFactories,
+	  maybeEscapePropertyName,
 	  wrapRender
 	} = __webpack_require__(4);
 	const { MODE } = __webpack_require__(1);
 	// Shortcuts
 	const { span } = React.DOM;
 	
 	/**
 	 * Property for Obj (local JS objects), Grip (remote JS objects)
@@ -1290,34 +1317,42 @@ return /******/ (function(modules) { // 
 	    // Delimiter character used to separate individual properties.
 	    delim: React.PropTypes.string,
 	    // @TODO Change this to Object.values once it's supported in Node's version of V8
 	    mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
 	    objectLink: React.PropTypes.func,
 	    attachedActorIds: React.PropTypes.array,
 	    onDOMNodeMouseOver: React.PropTypes.func,
 	    onDOMNodeMouseOut: React.PropTypes.func,
-	    onInspectIconClick: React.PropTypes.func
+	    onInspectIconClick: React.PropTypes.func,
+	    // Normally a PropRep will quote a property name that isn't valid
+	    // when unquoted; but this flag can be used to suppress the
+	    // quoting.
+	    suppressQuotes: React.PropTypes.bool
 	  },
 	
 	  render: wrapRender(function () {
 	    const Grip = __webpack_require__(15);
 	    let { Rep } = createFactories(__webpack_require__(2));
 	    let {
 	      name,
 	      mode,
 	      equal,
-	      delim
+	      delim,
+	      suppressQuotes
 	    } = this.props;
 	
 	    let key;
 	    // The key can be a simple string, for plain objects,
 	    // or another object for maps and weakmaps.
-	    if (typeof this.props.name === "string") {
-	      key = span({ "className": "nodeName" }, this.props.name);
+	    if (typeof name === "string") {
+	      if (!suppressQuotes) {
+	        name = maybeEscapePropertyName(name);
+	      }
+	      key = span({ "className": "nodeName" }, name);
 	    } else {
 	      key = Rep(Object.assign({}, this.props, {
 	        object: name,
 	        mode: mode || MODE.TINY,
 	        defaultRep: Grip
 	      }));
 	    }
 	
@@ -1419,64 +1454,72 @@ return /******/ (function(modules) { // 
 	    if (indexes.length < max && indexes.length < propertiesLength) {
 	      // There are not enough props yet. Then add uninteresting props to display them.
 	      indexes = indexes.concat(this.getPropIndexes(properties, max - indexes.length, (t, value, name) => {
 	        return !isInterestingProp(t, value, name);
 	      }));
 	    }
 	
 	    const truncate = Object.keys(properties).length > max;
-	    let props = this.getProps(properties, indexes, truncate);
+	    // The server synthesizes some property names for a Proxy, like
+	    // <target> and <handler>; we don't want to quote these because,
+	    // as synthetic properties, they appear more natural when
+	    // unquoted.
+	    const suppressQuotes = object.class === "Proxy";
+	    let propsArray = this.getProps(properties, indexes, truncate, suppressQuotes);
 	    if (truncate) {
 	      // There are some undisplayed props. Then display "more...".
 	      let objectLink = this.props.objectLink || span;
 	
-	      props.push(Caption({
+	      propsArray.push(Caption({
 	        object: objectLink({
 	          object: object
 	        }, `${propertiesLength - max} more…`)
 	      }));
 	    }
 	
-	    return props;
+	    return propsArray;
 	  },
 	
 	  /**
 	   * Get props ordered by index.
 	   *
 	   * @param {Object} properties Props object.
 	   * @param {Array} indexes Indexes of props.
 	   * @param {Boolean} truncate true if the grip will be truncated.
+	   * @param {Boolean} suppressQuotes true if we should suppress quotes
+	   *                  on property names.
 	   * @return {Array} Props.
 	   */
-	  getProps: function (properties, indexes, truncate) {
-	    let props = [];
+	  getProps: function (properties, indexes, truncate, suppressQuotes) {
+	    let propsArray = [];
 	
 	    // Make indexes ordered by ascending.
 	    indexes.sort(function (a, b) {
 	      return a - b;
 	    });
 	
 	    indexes.forEach(i => {
 	      let name = Object.keys(properties)[i];
 	      let value = this.getPropValue(properties[name]);
 	
-	      props.push(PropRep(Object.assign({}, this.props, {
+	      propsArray.push(PropRep(Object.assign({}, this.props, {
 	        mode: MODE.TINY,
 	        name: name,
 	        object: value,
 	        equal: ": ",
 	        delim: i !== indexes.length - 1 || truncate ? ", " : "",
 	        defaultRep: Grip,
 	        // Do not propagate title to properties reps
-	        title: undefined
+	        title: undefined,
+	        suppressQuotes
 	      })));
 	    });
 	
-	    return props;
+	    return propsArray;
 	  },
 	
 	  /**
 	   * Get the indexes of props in the object.
 	   *
 	   * @param {Object} properties Props object.
 	   * @param {Number} max The maximum length of indexes array.
 	   * @param {Function} filter Filter the props you want.
@@ -1525,30 +1568,30 @@ return /******/ (function(modules) { // 
 	        value = property.getterValue;
 	      }
 	    }
 	    return value;
 	  },
 	
 	  render: wrapRender(function () {
 	    let object = this.props.object;
-	    let props = this.safePropIterator(object, this.props.mode === MODE.LONG ? 10 : 3);
+	    let propsArray = this.safePropIterator(object, this.props.mode === MODE.LONG ? 10 : 3);
 	
 	    let objectLink = this.props.objectLink || span;
 	    if (this.props.mode === MODE.TINY) {
 	      return span({ className: "objectBox objectBox-object" }, this.getTitle(object), objectLink({
 	        className: "objectLeftBrace",
 	        object: object
 	      }, ""));
 	    }
 	
 	    return span({ className: "objectBox objectBox-object" }, this.getTitle(object), objectLink({
 	      className: "objectLeftBrace",
 	      object: object
-	    }, " { "), ...props, objectLink({
+	    }, " { "), ...propsArray, objectLink({
 	      className: "objectRightBrace",
 	      object: object
 	    }, " }"));
 	  })
 	});
 	
 	// Registration
 	function supportsObject(object, type) {
@@ -2109,17 +2152,18 @@ return /******/ (function(modules) { // 
 	
 	    return keys.map((key, i) => {
 	      let object = promiseState[key];
 	      return PropRep(Object.assign({}, this.props, {
 	        mode: MODE.TINY,
 	        name: `<${key}>`,
 	        object,
 	        equal: ": ",
-	        delim: i < keys.length - 1 ? ", " : ""
+	        delim: i < keys.length - 1 ? ", " : "",
+	        suppressQuotes: true
 	      }));
 	    });
 	  },
 	
 	  render: wrapRender(function () {
 	    const object = this.props.object;
 	    const { promiseState } = object;
 	    let objectLink = this.props.objectLink || span;
@@ -2131,21 +2175,21 @@ return /******/ (function(modules) { // 
 	        className: "objectLeftBrace",
 	        object: object
 	      }, " { "), Rep({ object: promiseState.state }), objectLink({
 	        className: "objectRightBrace",
 	        object: object
 	      }, " }"));
 	    }
 	
-	    const props = this.getProps(promiseState);
+	    const propsArray = this.getProps(promiseState);
 	    return span({ className: "objectBox objectBox-object" }, this.getTitle(object), objectLink({
 	      className: "objectLeftBrace",
 	      object: object
-	    }, " { "), ...props, objectLink({
+	    }, " { "), ...propsArray, objectLink({
 	      className: "objectRightBrace",
 	      object: object
 	    }, " }"));
 	  })
 	});
 	
 	// Registration
 	function supportsObject(object, type) {
@@ -2451,17 +2495,17 @@ return /******/ (function(modules) { // 
 	      }
 	
 	      if (onInspectIconClick) {
 	        inspectIcon = Svg("open-inspector", {
 	          element: "a",
 	          draggable: false,
 	          // TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands
 	          title: "Click to select the node in the inspector",
-	          onClick: () => onInspectIconClick(object)
+	          onClick: e => onInspectIconClick(object, e)
 	        });
 	      }
 	    }
 	
 	    return span(baseConfig, objectLink({ object }, ...elements), inspectIcon);
 	  })
 	});
 	
@@ -2742,17 +2786,17 @@ return /******/ (function(modules) { // 
 	      }
 	
 	      if (onInspectIconClick) {
 	        inspectIcon = Svg("open-inspector", {
 	          element: "a",
 	          draggable: false,
 	          // TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands
 	          title: "Click to select the node in the inspector",
-	          onClick: () => onInspectIconClick(grip)
+	          onClick: e => onInspectIconClick(grip, e)
 	        });
 	      }
 	    }
 	
 	    if (mode === MODE.TINY) {
 	      return DOM.span(baseConfig, this.getTitle(grip), inspectIcon);
 	    }
 	
@@ -3399,30 +3443,30 @@ return /******/ (function(modules) { // 
 	      }
 	
 	      return indexes;
 	    }, []);
 	  },
 	
 	  render: wrapRender(function () {
 	    let object = this.props.object;
-	    let props = this.safeEntriesIterator(object, this.props.mode === MODE.LONG ? 10 : 3);
+	    let propsArray = this.safeEntriesIterator(object, this.props.mode === MODE.LONG ? 10 : 3);
 	
 	    let objectLink = this.props.objectLink || span;
 	    if (this.props.mode === MODE.TINY) {
 	      return span({ className: "objectBox objectBox-object" }, this.getTitle(object), objectLink({
 	        className: "objectLeftBrace",
 	        object: object
 	      }, ""));
 	    }
 	
 	    return span({ className: "objectBox objectBox-object" }, this.getTitle(object), objectLink({
 	      className: "objectLeftBrace",
 	      object: object
-	    }, " { "), props, objectLink({
+	    }, " { "), propsArray, objectLink({
 	      className: "objectRightBrace",
 	      object: object
 	    }, " }"));
 	  })
 	});
 	
 	function supportsObject(grip, type) {
 	  if (!isGrip(grip)) {
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_array.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_array.html
@@ -9,18 +9,18 @@ Test ArrayRep rep
 <head>
   <meta charset="utf-8">
   <title>Rep test - ArrayRep</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 "use strict";
 /* import-globals-from head.js */
 
 window.onload = Task.async(function* () {
   const { REPS, MODE } = browserRequire("devtools/client/shared/components/reps/reps");
   let { Rep, ArrayRep } = REPS;
 
   let componentUnderTest = ArrayRep;
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_attribute.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_attribute.html
@@ -9,18 +9,18 @@ Test Attribute rep
 <head>
   <meta charset="utf-8">
   <title>Rep test - Attribute</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 window.onload = Task.async(function* () {
   try {
     const { REPS } = browserRequire("devtools/client/shared/components/reps/reps");
     let { Rep, Attribute } = REPS;
 
     let gripStub = {
       "type": "object",
       "class": "Attr",
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_comment-node.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_comment-node.html
@@ -9,18 +9,18 @@ Test comment-node rep
 <head>
   <meta charset="utf-8">
   <title>Rep test - comment-node</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 "use strict";
 
 window.onload = Task.async(function* () {
   try {
     const { REPS, MODE } = browserRequire("devtools/client/shared/components/reps/reps");
     let { Rep, CommentNode } = REPS;
 
     let gripStub = {
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_date-time.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_date-time.html
@@ -9,18 +9,18 @@ Test DateTime rep
 <head>
   <meta charset="utf-8">
   <title>Rep test - DateTime</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 window.onload = Task.async(function* () {
   const { REPS } = browserRequire("devtools/client/shared/components/reps/reps");
   let { Rep, DateTime } = REPS;
 
   try {
     testValid();
     testInvalid();
   } catch(e) {
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_document.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_document.html
@@ -9,18 +9,18 @@ Test Document rep
 <head>
   <meta charset="utf-8">
   <title>Rep test - Document</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 window.onload = Task.async(function* () {
   const { REPS } = browserRequire("devtools/client/shared/components/reps/reps");
   let { Rep, Document } = REPS;
 
   try {
     let gripStub = {
       "type": "object",
       "class": "HTMLDocument",
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_element-node.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_element-node.html
@@ -9,18 +9,18 @@ Test Element node rep
 <head>
   <meta charset="utf-8">
   <title>Rep test - Element node</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 "use strict";
 
 window.onload = Task.async(function* () {
   const {
     REPS,
     MODE,
     getSelectableInInspectorGrips,
   } = browserRequire("devtools/client/shared/components/reps/reps");
@@ -228,18 +228,21 @@ window.onload = Task.async(function* () 
   function testOnInspectIconClick() {
     const stub = getGripStub("testNode");
     const grips = getSelectableInInspectorGrips(stub);
     is(grips.length, 1, "the stub has one node grip");
 
     const attachedActorIds = getStubAttachedActorIds(grips);
 
     let inspectIconClickedValue = null;
-    let onInspectIconClick = (object) => {
+    let inspectIconClickedEvent = null;
+
+    let onInspectIconClick = (object, event) => {
       inspectIconClickedValue = object;
+      inspectIconClickedEvent = event;
     };
 
     const renderedComponentWithoutInspectIcon = renderComponent(ElementNode.rep, {
       object: stub,
       onInspectIconClick,
       attachedActorIds: ["someOtherId"]
     });
     is(renderedComponentWithoutInspectIcon.querySelector(".open-inspector"), null,
@@ -260,16 +263,18 @@ window.onload = Task.async(function* () 
     });
 
     inspectIconNode = renderedComponent.querySelector(".open-inspector");
     ok(inspectIconNode !== null, "There is an inspect icon as expected");
     TestUtils.Simulate.click(inspectIconNode);
 
     is(inspectIconClickedValue, grips[0],
       "onInspectIconClick is called with expected value when inspect icon is clicked");
+    ok(inspectIconClickedEvent !== null && inspectIconClickedEvent.type === "click",
+      "onInspectIconClick forwarded the original event to the callback");
   }
 
   function getGripStub(name) {
     switch (name) {
       case "testBodyNode":
         return {
           "type": "object",
           "actor": "server1.conn1.child1/obj30",
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_error.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_error.html
@@ -9,18 +9,18 @@ Test Error rep
 <head>
   <meta charset="utf-8">
   <title>Rep test - Error</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 "use strict";
 
 window.onload = Task.async(function* () {
   const { REPS, MODE } = browserRequire("devtools/client/shared/components/reps/reps");
   let { Rep, ErrorRep } = REPS;
 
   try {
     // Test errors with different properties
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_event.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_event.html
@@ -9,18 +9,18 @@ Test Event rep
 <head>
   <meta charset="utf-8">
   <title>Rep test - Event</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 window.onload = Task.async(function* () {
   const {
     REPS,
     MODE,
     getSelectableInInspectorGrips,
   } = browserRequire("devtools/client/shared/components/reps/reps");
   let { Rep, Event } = REPS;
 
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_failure.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_failure.html
@@ -9,18 +9,18 @@ Test fallback for rep rendering when a r
 <head>
   <meta charset="utf-8">
   <title>Rep test - Failure</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 window.onload = Task.async(function* () {
   try {
     const { REPS } = browserRequire("devtools/client/shared/components/reps/reps");
     let { Rep, ArrayRep, RegExp } = REPS;
 
     // Force the RegExp rep to crash by creating RegExp grip that throws when accessing
     // the displayString property
     let gripStub = {
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_function.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_function.html
@@ -9,18 +9,18 @@ Test Func rep
 <head>
   <meta charset="utf-8">
   <title>Rep test - Func</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 window.onload = Task.async(function* () {
   const { REPS, MODE } = browserRequire("devtools/client/shared/components/reps/reps");
   let { Rep, Func } = REPS;
 
   const componentUnderTest = Func;
 
   try {
     // Test that correct rep is chosen
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_grip-array.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_grip-array.html
@@ -9,18 +9,18 @@ Test GripArray rep
 <head>
   <meta charset="utf-8">
   <title>Rep test - GripArray</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 window.onload = Task.async(function* () {
   const {
     REPS,
     MODE,
     getSelectableInInspectorGrips,
   } = browserRequire("devtools/client/shared/components/reps/reps");
   let { Rep, GripArray } = REPS;
 
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_grip-map.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_grip-map.html
@@ -9,18 +9,18 @@ Test GripMap rep
 <head>
   <meta charset="utf-8">
   <title>Rep test - GripMap</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 "use strict";
 
 window.onload = Task.async(function* () {
   const {
     REPS,
     MODE,
     getSelectableInInspectorGrips,
   } = browserRequire("devtools/client/shared/components/reps/reps");
@@ -151,17 +151,17 @@ window.onload = Task.async(function* () 
     testRepRenderModes(modeTests, testName, componentUnderTest, getGripStub(testName));
   }
 
   function testMaxEntries() {
     // Test object:
     // `new Map([["key-a","value-a"], ["key-b","value-b"], ["key-c","value-c"]])`
     const testName = "testMaxEntries";
 
-    const defaultOutput = `Map { key-a: "value-a", key-b: "value-b", key-c: "value-c" }`;
+    const defaultOutput = `Map { "key-a": "value-a", "key-b": "value-b", "key-c": "value-c" }`;
 
     const modeTests = [
       {
         mode: undefined,
         expectedOutput: defaultOutput,
       },
       {
         mode: MODE.TINY,
@@ -181,20 +181,20 @@ window.onload = Task.async(function* () 
   }
 
   function testMoreThanMaxEntries() {
     // Test object = `new Map(
     //   [["key-0", "value-0"], ["key-1", "value-1"]], …, ["key-100", "value-100"]]}`
     const testName = "testMoreThanMaxEntries";
 
     const defaultOutput =
-      `Map { key-0: "value-0", key-1: "value-1", key-2: "value-2", 98 more… }`;
+      `Map { "key-0": "value-0", "key-1": "value-1", "key-2": "value-2", 98 more… }`;
 
     // Generate string with 101 entries, which is the max limit for 'long' mode.
-    let longString = Array.from({length: 10}).map((_, i) => `key-${i}: "value-${i}"`);
+    let longString = Array.from({length: 10}).map((_, i) => `"key-${i}": "value-${i}"`);
     const longOutput = `Map { ${longString.join(", ")}, 91 more… }`;
 
     const modeTests = [
       {
         mode: undefined,
         expectedOutput: defaultOutput,
       },
       {
@@ -215,19 +215,19 @@ window.onload = Task.async(function* () 
   }
 
   function testUninterestingEntries() {
     // Test object:
     // `new Map([["key-a",null], ["key-b",undefined], ["key-c","value-c"], ["key-d",4]])`
     const testName = "testUninterestingEntries";
 
     const defaultOutput =
-      `Map { key-a: null, key-c: "value-c", key-d: 4, 1 more… }`;
+      `Map { "key-a": null, "key-c": "value-c", "key-d": 4, 1 more… }`;
     const longOutput =
-      `Map { key-a: null, key-b: undefined, key-c: "value-c", key-d: 4 }`;
+      `Map { "key-a": null, "key-b": undefined, "key-c": "value-c", "key-d": 4 }`;
 
     const modeTests = [
       {
         mode: undefined,
         expectedOutput: defaultOutput,
       },
       {
         mode: MODE.TINY,
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_grip.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_grip.html
@@ -9,18 +9,18 @@ Test grip rep
 <head>
   <meta charset="utf-8">
   <title>Rep test - grip</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 window.onload = Task.async(function* () {
   const {
     REPS,
     MODE,
     getSelectableInInspectorGrips,
   } = browserRequire("devtools/client/shared/components/reps/reps");
   let { Rep, Grip } = REPS;
 
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_infinity.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_infinity.html
@@ -9,18 +9,18 @@ Test Infinity rep
 <head>
   <meta charset="utf-8">
   <title>Rep test - Infinity</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 "use strict";
 
 window.onload = Task.async(function* () {
   const { REPS } = browserRequire("devtools/client/shared/components/reps/reps");
   let { Rep, InfinityRep } = REPS;
 
   try {
     yield testInfinity();
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_long-string.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_long-string.html
@@ -9,18 +9,18 @@ Test LongString rep
 <head>
   <meta charset="utf-8">
   <title>Rep test - LongString</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 window.onload = Task.async(function* () {
   const { REPS } = browserRequire("devtools/client/shared/components/reps/reps");
   let { Rep, LongStringRep } = REPS;
 
   try {
     // Test that correct rep is chosen
     const renderedRep = shallowRenderComponent(Rep, { object: getGripStub("testMultiline") });
     is(renderedRep.type, LongStringRep.rep,
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_nan.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_nan.html
@@ -9,18 +9,18 @@ Test NaN rep
 <head>
   <meta charset="utf-8">
   <title>Rep test - NaN</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 "use strict";
 
 window.onload = Task.async(function* () {
   const { REPS } = browserRequire("devtools/client/shared/components/reps/reps");
   let { Rep, NaNRep } = REPS;
 
   try {
     yield testNaN();
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_null.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_null.html
@@ -9,18 +9,18 @@ Test Null rep
 <head>
   <meta charset="utf-8">
   <title>Rep test - Null</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 window.onload = Task.async(function* () {
   try {
     const { REPS } = browserRequire("devtools/client/shared/components/reps/reps");
     let { Rep, Null } = REPS;
 
     let gripStub = {
       "type": "null"
     };
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_number.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_number.html
@@ -9,18 +9,18 @@ Test Number rep
 <head>
   <meta charset="utf-8">
   <title>Rep test - Number</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 window.onload = Task.async(function* () {
   const { REPS } = browserRequire("devtools/client/shared/components/reps/reps");
   let { Rep, Number } = REPS;
 
   try {
     yield testInt();
     yield testBoolean();
     yield testNegativeZero();
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_object-with-text.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_object-with-text.html
@@ -9,18 +9,18 @@ Test ObjectWithText rep
 <head>
   <meta charset="utf-8">
   <title>Rep test - ObjectWithText</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 window.onload = Task.async(function* () {
   try {
     const { REPS } = browserRequire("devtools/client/shared/components/reps/reps");
     let { Rep, ObjectWithText } = REPS;
 
     let gripStub = {
       "type": "object",
       "class": "CSSStyleRule",
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_object-with-url.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_object-with-url.html
@@ -9,18 +9,18 @@ Test ObjectWithURL rep
 <head>
   <meta charset="utf-8">
   <title>Rep test - ObjectWithURL</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 window.onload = Task.async(function* () {
   try {
     let ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
     let React = browserRequire("devtools/client/shared/vendor/react");
 
     const { REPS } = browserRequire("devtools/client/shared/components/reps/reps");
     let { Rep, ObjectWithURL } = REPS;
 
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_object.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_object.html
@@ -9,32 +9,35 @@ Test Obj rep
 <head>
   <meta charset="utf-8">
   <title>Rep test - Obj</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 window.onload = Task.async(function* () {
   const { REPS, MODE } = browserRequire("devtools/client/shared/components/reps/reps");
   let { Rep, Obj } = REPS;
 
   const componentUnderTest = Obj;
 
   try {
     yield testBasic();
 
     // Test property iterator
     yield testMaxProps();
     yield testMoreThanMaxProps();
     yield testUninterestingProps();
 
+    // Test that unusual property names are escaped.
+    yield testEscapedPropertyNames();
+
     // Test that properties are rendered as expected by PropRep
     yield testNested();
 
     // Test that 'more' property doesn't clobber the caption.
     yield testMoreProp();
 
     // Test that you can pass a custom title to the Rep
     yield testCustomTitle();
@@ -154,16 +157,42 @@ window.onload = Task.async(function* () 
         mode: MODE.LONG,
         expectedOutput: defaultOutput,
       }
     ];
 
     testRepRenderModes(modeTests, "testUninterestingProps", componentUnderTest, stub);
   }
 
+  function testEscapedPropertyNames() {
+    const stub = {"":1, "quote-this":2, noquotes:3};
+    const defaultOutput = `Object { "": 1, "quote-this": 2, noquotes: 3 }`;
+
+    const modeTests = [
+      {
+        mode: undefined,
+        expectedOutput: defaultOutput,
+      },
+      {
+        mode: MODE.TINY,
+        expectedOutput: `Object`,
+      },
+      {
+        mode: MODE.SHORT,
+        expectedOutput: defaultOutput,
+      },
+      {
+        mode: MODE.LONG,
+        expectedOutput: defaultOutput,
+      }
+    ];
+
+    testRepRenderModes(modeTests, "testEscapedPropertyNames", componentUnderTest, stub);
+  }
+
   function testNested() {
     const stub = {
       objProp: {
         id: 1,
         arr: [2]
       },
       strProp: "test string",
       arrProp: [1]
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_promise.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_promise.html
@@ -9,18 +9,18 @@ Test Promise rep
 <head>
   <meta charset="utf-8">
   <title>Rep test - Promise</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 "use strict";
 
 window.onload = Task.async(function* () {
   const {
     REPS,
     MODE,
     getSelectableInInspectorGrips,
   } = browserRequire("devtools/client/shared/components/reps/reps");
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_regexp.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_regexp.html
@@ -9,18 +9,18 @@ Test RegExp rep
 <head>
   <meta charset="utf-8">
   <title>Rep test - RegExp</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 window.onload = Task.async(function* () {
   try {
     const { REPS } = browserRequire("devtools/client/shared/components/reps/reps");
     let { Rep, RegExp } = REPS;
 
     let gripStub = {
       "type": "object",
       "class": "RegExp",
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_string.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_string.html
@@ -9,18 +9,18 @@ Test String rep
 <head>
   <meta charset="utf-8">
   <title>Rep test - String</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 window.onload = Task.async(function* () {
   const { REPS } = browserRequire("devtools/client/shared/components/reps/reps");
   let { Rep, StringRep } = REPS;
 
   const test_cases = [{
     name: "testMultiline",
     props: {
       object: "aaaaaaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbb\ncccccccccccccccc\n",
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_stylesheet.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_stylesheet.html
@@ -9,18 +9,18 @@ Test Stylesheet rep
 <head>
   <meta charset="utf-8">
   <title>Rep test - Stylesheet</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 window.onload = Task.async(function* () {
   try {
     const { REPS } = browserRequire("devtools/client/shared/components/reps/reps");
     let { Rep, StyleSheet } = REPS;
 
     let gripStub = {
       "type": "object",
       "class": "CSSStyleSheet",
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_symbol.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_symbol.html
@@ -9,18 +9,18 @@ Test Symbol rep
 <head>
   <meta charset="utf-8">
   <title>Rep test - String</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 "use strict";
 /* import-globals-from head.js */
 
 window.onload = Task.async(function* () {
   const { REPS } = browserRequire("devtools/client/shared/components/reps/reps");
   let { Rep, SymbolRep } = REPS;
 
   let gripStubs = new Map();
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_text-node.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_text-node.html
@@ -9,18 +9,18 @@ Test text-node rep
 <head>
   <meta charset="utf-8">
   <title>Rep test - text-node</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 "use strict";
 
 window.onload = Task.async(function* () {
   const {
     REPS,
     MODE,
     getSelectableInInspectorGrips,
   } = browserRequire("devtools/client/shared/components/reps/reps");
@@ -167,18 +167,21 @@ window.onload = Task.async(function* () 
   function testOnInspectIconClick() {
     const stub = gripStubs.get("testRendering");
 
     const grips = getSelectableInInspectorGrips(stub);
     is(grips.length, 1, "the stub has one text node grip");
     const attachedActorIds = getStubAttachedActorIds(grips);
 
     let inspectIconClickedValue = null;
-    let onInspectIconClick = (object) => {
+    let inspectIconClickedEvent = null;
+
+    let onInspectIconClick = (object, event) => {
       inspectIconClickedValue = object;
+      inspectIconClickedEvent = event;
     };
 
     const renderedComponentWithoutInspectIcon = renderComponent(TextNode.rep, {
       object: stub,
       onInspectIconClick,
       attachedActorIds: ["someOtherId"]
     });
     is(renderedComponentWithoutInspectIcon.querySelector(".open-inspector"), null,
@@ -191,14 +194,16 @@ window.onload = Task.async(function* () 
     });
 
     const inspectIconNode = renderedComponent.querySelector(".open-inspector");
     ok(inspectIconNode !== null, "There is an inspect icon as expected");
     TestUtils.Simulate.click(inspectIconNode);
 
     is(inspectIconClickedValue, grips[0],
       "onInspectIconClick is called with expected value when inspect icon is clicked");
+    ok(inspectIconClickedEvent !== null && inspectIconClickedEvent.type === "click",
+      "onInspectIconClick forwarded the original event to the callback");
   }
 });
 </script>
 </pre>
 </body>
 </html>
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_undefined.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_undefined.html
@@ -9,18 +9,18 @@ Test undefined rep
 <head>
   <meta charset="utf-8">
   <title>Rep test - undefined</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 window.onload = Task.async(function* () {
   try {
     let ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
     let React = browserRequire("devtools/client/shared/vendor/react");
     const { REPS } = browserRequire("devtools/client/shared/components/reps/reps");
     let { Rep, Undefined } = REPS;
 
     let gripStub = {
--- a/devtools/client/shared/components/reps/test/mochitest/test_reps_window.html
+++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_window.html
@@ -9,18 +9,18 @@ Test window rep
 <head>
   <meta charset="utf-8">
   <title>Rep tests - window</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
-<script src="head.js" type="application/javascript"></script>
-<script type="application/javascript">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
 window.onload = Task.async(function* () {
   try {
     let ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
     let React = browserRequire("devtools/client/shared/vendor/react");
 
     const { REPS, MODE } = browserRequire("devtools/client/shared/components/reps/reps");
     let { Rep, Window } = REPS;
 
--- a/devtools/server/actors/chrome.js
+++ b/devtools/server/actors/chrome.js
@@ -45,17 +45,28 @@ function ChromeActor(connection) {
   // Defines the default docshell selected for the tab actor
   let window = Services.wm.getMostRecentWindow(DebuggerServer.chromeWindowType);
 
   // Default to any available top level window if there is no expected window
   // (for example when we open firefox with -webide argument)
   if (!window) {
     window = Services.wm.getMostRecentWindow(null);
   }
-  // On xpcshell, there is no window/docshell
+
+  // We really want _some_ window at least, so fallback to the hidden window if
+  // there's nothing else (such as during early startup).
+  if (!window) {
+    try {
+      window = Services.appShell.hiddenDOMWindow;
+    } catch (e) {
+      // On XPCShell, the above line will throw.
+    }
+  }
+
+  // On XPCShell, there is no window/docshell
   let docShell = window ? window.QueryInterface(Ci.nsIInterfaceRequestor)
                                 .getInterface(Ci.nsIDocShell)
                         : null;
   Object.defineProperty(this, "docShell", {
     value: docShell,
     configurable: true
   });
 }
--- a/devtools/server/actors/script.js
+++ b/devtools/server/actors/script.js
@@ -1015,18 +1015,18 @@ const ThreadActor = ActorClassWithSpec(t
         this._options.pauseOnExceptions = aRequest.pauseOnExceptions;
         this._options.ignoreCaughtExceptions = aRequest.ignoreCaughtExceptions;
         this.maybePauseOnExceptions();
         this._maybeListenToEvents(aRequest);
       }
 
       let packet = this._resumed();
       this._popThreadPause();
-      // Tell anyone who cares of the resume (as of now, that's the xpcshell
-      // harness)
+      // Tell anyone who cares of the resume (as of now, that's the xpcshell harness and
+      // devtools-startup.js when handling the --wait-for-jsdebugger flag)
       if (Services.obs) {
         Services.obs.notifyObservers(this, "devtools-thread-resumed", null);
       }
       return packet;
     }, error => {
       return error instanceof Error
         ? { error: "unknownError",
             message: DevToolsUtils.safeErrorString(error) }
--- a/devtools/shared/css/generated/properties-db.js
+++ b/devtools/shared/css/generated/properties-db.js
@@ -3218,16 +3218,17 @@ exports.CSS_PROPERTIES = {
       "cubic-bezier",
       "currentColor",
       "darken",
       "dashed",
       "default",
       "dialog",
       "difference",
       "disabled",
+      "distribute",
       "dotted",
       "double",
       "drag",
       "dualbutton",
       "ease",
       "ease-in",
       "ease-in-out",
       "ease-out",
@@ -3278,16 +3279,18 @@ exports.CSS_PROPERTIES = {
       "inline-block",
       "inline-end",
       "inline-flex",
       "inline-grid",
       "inline-start",
       "inline-table",
       "inset",
       "inside",
+      "inter-character",
+      "inter-word",
       "intersect",
       "isolate",
       "italic",
       "justify",
       "keep-all",
       "large",
       "larger",
       "last baseline",
@@ -8807,16 +8810,33 @@ exports.CSS_PROPERTIES = {
     ],
     "values": [
       "calc",
       "inherit",
       "initial",
       "unset"
     ]
   },
+  "text-justify": {
+    "isInherited": true,
+    "subproperties": [
+      "text-justify"
+    ],
+    "supports": [],
+    "values": [
+      "auto",
+      "distribute",
+      "inherit",
+      "initial",
+      "inter-character",
+      "inter-word",
+      "none",
+      "unset"
+    ]
+  },
   "text-orientation": {
     "isInherited": true,
     "subproperties": [
       "text-orientation"
     ],
     "supports": [],
     "values": [
       "inherit",
--- a/docshell/base/nsDSURIContentListener.cpp
+++ b/docshell/base/nsDSURIContentListener.cpp
@@ -423,18 +423,18 @@ nsDSURIContentListener::CheckFrameOption
     }
   }
 
   if (!httpChannel) {
     return true;
   }
 
   nsAutoCString xfoHeaderCValue;
-  httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("X-Frame-Options"),
-                                 xfoHeaderCValue);
+  Unused << httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("X-Frame-Options"),
+                                           xfoHeaderCValue);
   NS_ConvertUTF8toUTF16 xfoHeaderValue(xfoHeaderCValue);
 
   // if no header value, there's nothing to do.
   if (xfoHeaderValue.IsEmpty()) {
     return true;
   }
 
   // iterate through all the header values (usually there's only one, but can
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -537,67 +537,76 @@ SendPing(void* aClosure, nsIContent* aCo
 
   nsCOMPtr<nsIHttpChannel> httpChan = do_QueryInterface(chan);
   if (!httpChan) {
     return;
   }
 
   // This is needed in order for 3rd-party cookie blocking to work.
   nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(httpChan);
+  nsresult rv;
   if (httpInternal) {
-    httpInternal->SetDocumentURI(doc->GetDocumentURI());
-  }
-
-  httpChan->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
+    rv = httpInternal->SetDocumentURI(doc->GetDocumentURI());
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
+  }
+
+  rv = httpChan->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
 
   // Remove extraneous request headers (to reduce request size)
-  httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept"),
-                             EmptyCString(), false);
-  httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-language"),
-                             EmptyCString(), false);
-  httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-encoding"),
-                             EmptyCString(), false);
+  rv = httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept"),
+                                  EmptyCString(), false);
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
+  rv = httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-language"),
+                                  EmptyCString(), false);
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
+  rv = httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-encoding"),
+                                  EmptyCString(), false);
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
 
   // Always send a Ping-To header.
   nsAutoCString pingTo;
   if (NS_SUCCEEDED(info->target->GetSpec(pingTo))) {
-    httpChan->SetRequestHeader(NS_LITERAL_CSTRING("Ping-To"), pingTo, false);
+    rv = httpChan->SetRequestHeader(NS_LITERAL_CSTRING("Ping-To"), pingTo, false);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
   }
 
   nsCOMPtr<nsIScriptSecurityManager> sm =
     do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
 
   if (sm && info->referrer) {
     bool referrerIsSecure;
     uint32_t flags = nsIProtocolHandler::URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT;
-    nsresult rv = NS_URIChainHasFlags(info->referrer, flags, &referrerIsSecure);
+    rv = NS_URIChainHasFlags(info->referrer, flags, &referrerIsSecure);
 
     // Default to sending less data if NS_URIChainHasFlags() fails.
     referrerIsSecure = NS_FAILED(rv) || referrerIsSecure;
 
     bool sameOrigin =
       NS_SUCCEEDED(sm->CheckSameOriginURI(info->referrer, aURI, false));
 
     // If both the address of the document containing the hyperlink being
     // audited and "ping URL" have the same origin or the document containing
     // the hyperlink being audited was not retrieved over an encrypted
     // connection, send a Ping-From header.
     if (sameOrigin || !referrerIsSecure) {
       nsAutoCString pingFrom;
       if (NS_SUCCEEDED(info->referrer->GetSpec(pingFrom))) {
-        httpChan->SetRequestHeader(NS_LITERAL_CSTRING("Ping-From"), pingFrom,
-                                   false);
+        rv = httpChan->SetRequestHeader(NS_LITERAL_CSTRING("Ping-From"),
+                                        pingFrom, false);
+        MOZ_ASSERT(NS_SUCCEEDED(rv));
       }
     }
 
     // If the document containing the hyperlink being audited was not retrieved
     // over an encrypted connection and its address does not have the same
     // origin as "ping URL", send a referrer.
     if (!sameOrigin && !referrerIsSecure) {
-      httpChan->SetReferrerWithPolicy(info->referrer, info->referrerPolicy);
+      rv = httpChan->SetReferrerWithPolicy(info->referrer, info->referrerPolicy);
+      MOZ_ASSERT(NS_SUCCEEDED(rv));
     }
   }
 
   nsCOMPtr<nsIUploadChannel2> uploadChan = do_QueryInterface(httpChan);
   if (!uploadChan) {
     return;
   }
 
@@ -7501,17 +7510,17 @@ nsDocShell::OnRedirectStateChange(nsICha
     nsCOMPtr<nsIURI> referrer;
     // Treat referrer as null if there is an error getting it.
     (void)NS_GetReferrerFromChannel(aOldChannel, getter_AddRefs(referrer));
 
     // Get the HTTP response code, if available.
     uint32_t responseStatus = 0;
     nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aOldChannel);
     if (httpChannel) {
-      (void)httpChannel->GetResponseStatus(&responseStatus);
+      Unused << httpChannel->GetResponseStatus(&responseStatus);
     }
 
     // Add visit N -1 => N
     AddURIVisit(oldURI, referrer, previousURI, previousFlags, responseStatus);
 
     // Since N + 1 could be the final destination, we will not save N => N + 1
     // here.  OnNewURI will do that, so we will cache it.
     SaveLastVisit(aNewChannel, oldURI, aRedirectFlags);
@@ -11145,26 +11154,30 @@ nsDocShell::DoURILoad(nsIURI* aURI,
   }
 
   // hack
   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
   nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal(
     do_QueryInterface(channel));
   if (httpChannelInternal) {
     if (aForceAllowCookies) {
-      httpChannelInternal->SetThirdPartyFlags(
+      rv = httpChannelInternal->SetThirdPartyFlags(
         nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW);
+      MOZ_ASSERT(NS_SUCCEEDED(rv));
     }
     if (aFirstParty) {
-      httpChannelInternal->SetDocumentURI(aURI);
+      rv = httpChannelInternal->SetDocumentURI(aURI);
+      MOZ_ASSERT(NS_SUCCEEDED(rv));
     } else {
-      httpChannelInternal->SetDocumentURI(aReferrerURI);
-    }
-    httpChannelInternal->SetRedirectMode(
+      rv = httpChannelInternal->SetDocumentURI(aReferrerURI);
+      MOZ_ASSERT(NS_SUCCEEDED(rv));
+    }
+    rv = httpChannelInternal->SetRedirectMode(
       nsIHttpChannelInternal::REDIRECT_MODE_MANUAL);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
   }
 
   nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(channel));
   if (props) {
     // save true referrer for those who need it (e.g. xpinstall whitelisting)
     // Currently only http and ftp channels support this.
     props->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"),
                                   aReferrerURI);
@@ -11235,17 +11248,18 @@ nsDocShell::DoURILoad(nsIURI* aURI,
 
   if (httpChannel) {
     if (aHeadersData) {
       rv = AddHeadersToChannel(aHeadersData, httpChannel);
     }
     // Set the referrer explicitly
     if (aReferrerURI && aSendReferrer) {
       // Referrer is currenly only set for link clicks here.
-      httpChannel->SetReferrerWithPolicy(aReferrerURI, aReferrerPolicy);
+      rv = httpChannel->SetReferrerWithPolicy(aReferrerURI, aReferrerPolicy);
+      MOZ_ASSERT(NS_SUCCEEDED(rv));
     }
   }
 
   nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(channel);
   if (scriptChannel) {
     // Allow execution against our context if the principals match
     scriptChannel->SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
   }
@@ -12327,18 +12341,20 @@ nsDocShell::AddToSessionHistory(nsIURI* 
       nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
       if (uploadChannel) {
         uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
       }
       httpChannel->GetOriginalURI(getter_AddRefs(originalURI));
       uint32_t loadFlags;
       aChannel->GetLoadFlags(&loadFlags);
       loadReplace = loadFlags & nsIChannel::LOAD_REPLACE;
-      httpChannel->GetReferrer(getter_AddRefs(referrerURI));
-      httpChannel->GetReferrerPolicy(&referrerPolicy);
+      rv = httpChannel->GetReferrer(getter_AddRefs(referrerURI));
+      MOZ_ASSERT(NS_SUCCEEDED(rv));
+      rv = httpChannel->GetReferrerPolicy(&referrerPolicy);
+      MOZ_ASSERT(NS_SUCCEEDED(rv));
 
       discardLayoutState = ShouldDiscardLayoutState(httpChannel);
     }
 
     // XXX Bug 1286838: Replace channel owner with loadInfo triggeringPrincipal
     nsCOMPtr<nsISupports> owner;
     aChannel->GetOwner(getter_AddRefs(owner));
     triggeringPrincipal = do_QueryInterface(owner);
@@ -12971,17 +12987,17 @@ nsDocShell::ShouldDiscardLayoutState(nsI
 {
   // By default layout State will be saved.
   if (!aChannel) {
     return false;
   }
 
   // figure out if SH should be saving layout state
   bool noStore = false;
-  aChannel->IsNoStoreResponse(&noStore);
+  Unused << aChannel->IsNoStoreResponse(&noStore);
   return noStore;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetEditor(nsIEditor** aEditor)
 {
   NS_ENSURE_ARG_POINTER(aEditor);
 
@@ -13043,17 +13059,17 @@ bool
 nsDocShell::ChannelIsPost(nsIChannel* aChannel)
 {
   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
   if (!httpChannel) {
     return false;
   }
 
   nsAutoCString method;
-  httpChannel->GetRequestMethod(method);
+  Unused << httpChannel->GetRequestMethod(method);
   return method.EqualsLiteral("POST");
 }
 
 void
 nsDocShell::ExtractLastVisit(nsIChannel* aChannel,
                              nsIURI** aURI,
                              uint32_t* aChannelRedirectFlags)
 {
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -219,17 +219,17 @@ Element::UpdateLinkState(EventStates aSt
     (mState & ~(NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED)) |
     aState;
 }
 
 void
 Element::UpdateState(bool aNotify)
 {
   EventStates oldState = mState;
-  mState = IntrinsicState() | (oldState & ESM_MANAGED_STATES);
+  mState = IntrinsicState() | (oldState & EXTERNALLY_MANAGED_STATES);
   if (aNotify) {
     EventStates changedStates = oldState ^ mState;
     if (!changedStates.IsEmpty()) {
       nsIDocument* doc = GetComposedDoc();
       if (doc) {
         nsAutoScriptBlocker scriptBlocker;
         doc->ContentStateChanged(this, changedStates);
       }
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -510,34 +510,49 @@ private:
   void NotifyStateChange(EventStates aStates);
 
   void NotifyStyleStateChange(EventStates aStates);
 
   // Style state computed from element's state and style locks.
   EventStates StyleStateFromLocks() const;
 
 protected:
-  // Methods for the ESM to manage state bits.  These will handle
-  // setting up script blockers when they notify, so no need to do it
-  // in the callers unless desired.
+  // Methods for the ESM, nsGlobalWindow and focus manager to manage state bits.
+  // These will handle setting up script blockers when they notify, so no need
+  // to do it in the callers unless desired.  States passed here must only be
+  // those in EXTERNALLY_MANAGED_STATES.
   virtual void AddStates(EventStates aStates)
   {
     NS_PRECONDITION(!aStates.HasAtLeastOneOfStates(INTRINSIC_STATES),
-                    "Should only be adding ESM-managed states here");
+                    "Should only be adding externally-managed states here");
     AddStatesSilently(aStates);
     NotifyStateChange(aStates);
   }
   virtual void RemoveStates(EventStates aStates)
   {
     NS_PRECONDITION(!aStates.HasAtLeastOneOfStates(INTRINSIC_STATES),
-                    "Should only be removing ESM-managed states here");
+                    "Should only be removing externally-managed states here");
     RemoveStatesSilently(aStates);
     NotifyStateChange(aStates);
   }
 public:
+  // Public methods to manage state bits in MANUALLY_MANAGED_STATES.
+  void AddManuallyManagedStates(EventStates aStates)
+  {
+    MOZ_ASSERT(MANUALLY_MANAGED_STATES.HasAllStates(aStates),
+               "Should only be adding manually-managed states here");
+    AddStates(aStates);
+  }
+  void RemoveManuallyManagedStates(EventStates aStates)
+  {
+    MOZ_ASSERT(MANUALLY_MANAGED_STATES.HasAllStates(aStates),
+               "Should only be removing manually-managed states here");
+    RemoveStates(aStates);
+  }
+
   virtual void UpdateEditableState(bool aNotify) override;
 
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers) override;
   virtual void UnbindFromTree(bool aDeep = true,
                               bool aNullParent = true) override;
 
--- a/dom/base/EventSource.cpp
+++ b/dom/base/EventSource.cpp
@@ -990,28 +990,32 @@ EventSourceImpl::GetBaseURI(nsIURI** aBa
   return NS_OK;
 }
 
 void
 EventSourceImpl::SetupHttpChannel()
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(!IsShutDown());
-  mHttpChannel->SetRequestMethod(NS_LITERAL_CSTRING("GET"));
+  DebugOnly<nsresult> rv =
+    mHttpChannel->SetRequestMethod(NS_LITERAL_CSTRING("GET"));
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
 
   /* set the http request headers */
 
-  mHttpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
+  rv = mHttpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
     NS_LITERAL_CSTRING(TEXT_EVENT_STREAM), false);
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
 
   // LOAD_BYPASS_CACHE already adds the Cache-Control: no-cache header
 
   if (!mLastEventID.IsEmpty()) {
-    mHttpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Last-Event-ID"),
+    rv = mHttpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Last-Event-ID"),
       NS_ConvertUTF16toUTF8(mLastEventID), false);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
   }
 }
 
 nsresult
 EventSourceImpl::SetupReferrerPolicy()
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(!IsShutDown());
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1344,17 +1344,18 @@ Navigator::SendBeaconInternal(const nsAS
   }
 
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
   if (!httpChannel) {
     // Beacon spec only supports HTTP requests at this time
     aRv.Throw(NS_ERROR_DOM_BAD_URI);
     return false;
   }
-  httpChannel->SetReferrer(documentURI);
+  rv = httpChannel->SetReferrer(documentURI);
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
 
   nsCOMPtr<nsIInputStream> in;
   nsAutoCString contentTypeWithCharset;
   nsAutoCString charset;
   uint64_t length = 0;
 
   if (aBody) {
     aRv = aBody->GetAsStream(getter_AddRefs(in), &length,
@@ -1374,17 +1375,18 @@ Navigator::SendBeaconInternal(const nsAS
       aRv.Throw(NS_ERROR_FAILURE);
       return false;
     }
 
     uploadChannel->ExplicitSetUploadStream(in, contentTypeWithCharset, length,
                                            NS_LITERAL_CSTRING("POST"),
                                            false);
   } else {
-    httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
+    rv = httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
   }
 
   nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(channel);
   if (p) {
     p->SetPriority(nsISupportsPriority::PRIORITY_LOWEST);
   }
 
   nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
--- a/dom/base/nsContentSink.cpp
+++ b/dom/base/nsContentSink.cpp
@@ -889,17 +889,18 @@ nsContentSink::PrefetchDNS(const nsAStri
     if (NS_SUCCEEDED(rv) && !isLocalResource) {
       nsAutoCString host;
       uri->GetHost(host);
       CopyUTF8toUTF16(host, hostname);
     }
   }
 
   if (!hostname.IsEmpty() && nsHTMLDNSPrefetch::IsAllowed(mDocument)) {
-    nsHTMLDNSPrefetch::PrefetchLow(hostname);
+    nsHTMLDNSPrefetch::PrefetchLow(hostname,
+                                   mDocument->NodePrincipal()->OriginAttributesRef());
   }
 }
 
 void
 nsContentSink::Preconnect(const nsAString& aHref, const nsAString& aCrossOrigin)
 {
   // construct URI using document charset
   const nsACString& charset = mDocument->GetDocumentCharacterSet();
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -4090,16 +4090,80 @@ nsDOMWindowUtils::IsTimeoutTracking(uint
   NS_ENSURE_STATE(window);
   nsCOMPtr<nsPIDOMWindowInner> innerWindow = window->GetCurrentInnerWindow();
   NS_ENSURE_STATE(innerWindow);
 
   *aResult = innerWindow->TimeoutManager().IsTimeoutTracking(aTimeoutId);
   return NS_OK;
 }
 
+struct StateTableEntry
+{
+  const char* mStateString;
+  EventStates mState;
+};
+
+static constexpr StateTableEntry kManuallyManagedStates[] = {
+  // none yet; but for example: { "highlight", NS_EVENT_STATE_HIGHLIGHT },
+  { nullptr, EventStates() },
+};
+
+static_assert(!kManuallyManagedStates[ArrayLength(kManuallyManagedStates) - 1]
+               .mStateString,
+              "last kManuallyManagedStates entry must be a sentinel with "
+              "mStateString == nullptr");
+
+static EventStates
+GetEventStateForString(const nsAString& aStateString)
+{
+  for (const StateTableEntry* entry = kManuallyManagedStates;
+       entry->mStateString; ++entry) {
+    if (aStateString.EqualsASCII(entry->mStateString)) {
+      return entry->mState;
+    }
+  }
+  return EventStates();
+}
+
+NS_IMETHODIMP
+nsDOMWindowUtils::AddManuallyManagedState(nsIDOMElement* aElement,
+                                          const nsAString& aStateString)
+{
+  nsCOMPtr<Element> element = do_QueryInterface(aElement);
+  if (!element) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  EventStates state = GetEventStateForString(aStateString);
+  if (state.IsEmpty()) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  element->AddManuallyManagedStates(state);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMWindowUtils::RemoveManuallyManagedState(nsIDOMElement* aElement,
+                                             const nsAString& aStateString)
+{
+  nsCOMPtr<Element> element = do_QueryInterface(aElement);
+  if (!element) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  EventStates state = GetEventStateForString(aStateString);
+  if (state.IsEmpty()) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  element->RemoveManuallyManagedStates(state);
+  return NS_OK;
+}
+
 NS_INTERFACE_MAP_BEGIN(nsTranslationNodeList)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsITranslationNodeList)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(nsTranslationNodeList)
 NS_IMPL_RELEASE(nsTranslationNodeList)
 
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -2633,21 +2633,21 @@ nsDocument::InitCSP(nsIChannel* aChannel
 
   nsCOMPtr<nsIHttpChannel> httpChannel;
   nsresult rv = GetHttpChannelHelper(aChannel, getter_AddRefs(httpChannel));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   if (httpChannel) {
-    httpChannel->GetResponseHeader(
+    Unused << httpChannel->GetResponseHeader(
         NS_LITERAL_CSTRING("content-security-policy"),
         tCspHeaderValue);
 
-    httpChannel->GetResponseHeader(
+    Unused << httpChannel->GetResponseHeader(
         NS_LITERAL_CSTRING("content-security-policy-report-only"),
         tCspROHeaderValue);
   }
   NS_ConvertASCIItoUTF16 cspHeaderValue(tCspHeaderValue);
   NS_ConvertASCIItoUTF16 cspROHeaderValue(tCspROHeaderValue);
 
   // Check if this is a document from a WebExtension.
   nsString addonId;
@@ -4791,17 +4791,18 @@ nsDocument::SetScriptGlobalObject(nsIScr
   if (csp) {
     static_cast<nsCSPContext*>(csp.get())->flushConsoleMessages();
   }
 
   nsCOMPtr<nsIHttpChannelInternal> internalChannel =
     do_QueryInterface(GetChannel());
   if (internalChannel) {
     nsCOMArray<nsISecurityConsoleMessage> messages;
-    internalChannel->TakeAllSecurityMessages(messages);
+    DebugOnly<nsresult> rv = internalChannel->TakeAllSecurityMessages(messages);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
     SendToConsole(messages);
   }
 
   // Set our visibility state, but do not fire the event.  This is correct
   // because either we're coming out of bfcache (in which case IsVisible() will
   // still test false at this point and no state change will happen) or we're
   // doing the initial document load and don't want to fire the event for this
   // change.
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -1127,16 +1127,17 @@ GK_ATOM(scrollbar, "scrollbar")
 GK_ATOM(scrollbarbutton, "scrollbarbutton")
 GK_ATOM(scrollbarDownBottom, "scrollbar-down-bottom")
 GK_ATOM(scrollbarDownTop, "scrollbar-down-top")
 GK_ATOM(scrollbarUpBottom, "scrollbar-up-bottom")
 GK_ATOM(scrollbarUpTop, "scrollbar-up-top")
 GK_ATOM(scrollbox, "scrollbox")
 GK_ATOM(scrollcorner, "scrollcorner")
 GK_ATOM(scrolling, "scrolling")
+GK_ATOM(scrollPosition, "scroll-position")
 GK_ATOM(section, "section")
 GK_ATOM(select, "select")
 GK_ATOM(selectable, "selectable")
 GK_ATOM(selected, "selected")
 GK_ATOM(selectedIndex, "selectedIndex")
 GK_ATOM(selectedindex, "selectedindex")
 GK_ATOM(self, "self")
 GK_ATOM(seltype, "seltype")
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -2594,18 +2594,19 @@ nsObjectLoadingContent::OpenChannel()
     nsCOMPtr<nsILoadInfo> loadinfo = chan->GetLoadInfo();
     NS_ENSURE_STATE(loadinfo);
     loadinfo->SetPrincipalToInherit(thisContent->NodePrincipal());
   }
 
   // Referrer
   nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan));
   if (httpChan) {
-    httpChan->SetReferrerWithPolicy(doc->GetDocumentURI(),
-                                    doc->GetReferrerPolicy());
+    rv = httpChan->SetReferrerWithPolicy(doc->GetDocumentURI(),
+                                         doc->GetReferrerPolicy());
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
 
     // Set the initiator type
     nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(httpChan));
     if (timedChannel) {
       timedChannel->SetInitiatorType(thisContent->LocalName());
     }
   }
 
--- a/dom/base/nsScriptLoader.cpp
+++ b/dom/base/nsScriptLoader.cpp
@@ -1293,25 +1293,28 @@ nsScriptLoader::StartLoad(nsScriptLoadRe
       // other scripts are neither blocked nor prioritized unless marked deferred
       cos->AddClassFlags(nsIClassOfService::Unblocked);
     }
   }
 
   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
   if (httpChannel) {
     // HTTP content negotation has little value in this context.
-    httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
-                                  NS_LITERAL_CSTRING("*/*"),
-                                  false);
-    httpChannel->SetReferrerWithPolicy(mDocument->GetDocumentURI(),
-                                       aRequest->mReferrerPolicy);
+    rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
+                                       NS_LITERAL_CSTRING("*/*"),
+                                       false);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
+    rv = httpChannel->SetReferrerWithPolicy(mDocument->GetDocumentURI(),
+                                            aRequest->mReferrerPolicy);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
 
     nsCOMPtr<nsIHttpChannelInternal> internalChannel(do_QueryInterface(httpChannel));
     if (internalChannel) {
-      internalChannel->SetIntegrityMetadata(aRequest->mIntegrity.GetIntegrityString());
+      rv = internalChannel->SetIntegrityMetadata(aRequest->mIntegrity.GetIntegrityString());
+      MOZ_ASSERT(NS_SUCCEEDED(rv));
     }
   }
 
   OriginAttributes attrs;
   attrs.Inherit(mDocument->NodePrincipal()->OriginAttributesRef());
 
   mozilla::net::PredictorLearn(aRequest->mURI, mDocument->GetDocumentURI(),
       nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE, attrs);
--- a/dom/base/nsSyncLoadService.cpp
+++ b/dom/base/nsSyncLoadService.cpp
@@ -138,25 +138,27 @@ nsSyncLoader::LoadDocument(nsIChannel* a
     NS_ENSURE_ARG(aChannel);
     NS_ENSURE_ARG_POINTER(aResult);
     *aResult = nullptr;
     nsresult rv = NS_OK;
 
     mChannel = aChannel;
     nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(mChannel);
     if (http) {
-        http->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
-                               NS_LITERAL_CSTRING("text/xml,application/xml,application/xhtml+xml,*/*;q=0.1"),
-                               false);
+        rv = http->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
+                                    NS_LITERAL_CSTRING("text/xml,application/xml,application/xhtml+xml,*/*;q=0.1"),
+                                    false);
+        MOZ_ASSERT(NS_SUCCEEDED(rv));
         nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
         if (loadInfo) {
             nsCOMPtr<nsIURI> loaderUri;
             loadInfo->TriggeringPrincipal()->GetURI(getter_AddRefs(loaderUri));
             if (loaderUri) {
-              http->SetReferrerWithPolicy(loaderUri, aReferrerPolicy);
+                rv = http->SetReferrerWithPolicy(loaderUri, aReferrerPolicy);
+                MOZ_ASSERT(NS_SUCCEEDED(rv));
             }
         }
     }
 
     // Hook us up to listen to redirects and the like.
     // Do this before setting up the cross-site proxy since
     // that installs its own proxies.
     mChannel->SetNotificationCallbacks(this);
--- a/dom/events/EventStates.h
+++ b/dom/events/EventStates.h
@@ -309,17 +309,39 @@ private:
 #define NS_EVENT_STATE_IGNORE NS_DEFINE_EVENT_STATE_MACRO(63)
 
 /**
  * NOTE: do not go over 63 without updating EventStates::InternalType!
  */
 
 #define DIRECTION_STATES (NS_EVENT_STATE_LTR | NS_EVENT_STATE_RTL)
 
-#define ESM_MANAGED_STATES (NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_FOCUS |  \
-                            NS_EVENT_STATE_HOVER | NS_EVENT_STATE_DRAGOVER |   \
-                            NS_EVENT_STATE_URLTARGET | NS_EVENT_STATE_FOCUSRING | \
-                            NS_EVENT_STATE_FULL_SCREEN | NS_EVENT_STATE_UNRESOLVED | \
-                            NS_EVENT_STATE_FOCUS_WITHIN)
+// Event states that can be added and removed through
+// Element::{Add,Remove}ManuallyManagedStates.
+//
+// Take care when manually managing state bits.  You are responsible for
+// setting or clearing the bit when an Element is added or removed from a
+// document (e.g. in BindToTree and UnbindFromTree), if that is an
+// appropriate thing to do for your state bit.
+#define MANUALLY_MANAGED_STATES (             \
+  mozilla::EventStates() /* none so far */    \
+)
 
-#define INTRINSIC_STATES (~ESM_MANAGED_STATES)
+// Event states that are managed externally to an element (by the
+// EventStateManager, or by other code).  As opposed to those in
+// INTRINSIC_STATES, which are are computed by the element itself
+// and returned from Element::IntrinsicState.
+#define EXTERNALLY_MANAGED_STATES (           \
+  MANUALLY_MANAGED_STATES |                   \
+  NS_EVENT_STATE_ACTIVE |                     \
+  NS_EVENT_STATE_DRAGOVER |                   \
+  NS_EVENT_STATE_FOCUS |                      \
+  NS_EVENT_STATE_FOCUSRING |                  \
+  NS_EVENT_STATE_FOCUS_WITHIN |               \
+  NS_EVENT_STATE_FULL_SCREEN |                \
+  NS_EVENT_STATE_HOVER |                      \
+  NS_EVENT_STATE_UNRESOLVED |                 \
+  NS_EVENT_STATE_URLTARGET                    \
+)
+
+#define INTRINSIC_STATES (~EXTERNALLY_MANAGED_STATES)
 
 #endif // mozilla_EventStates_h_
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -293,21 +293,25 @@ FetchDriver::HttpFetch()
     // Auth may require prompting, we don't support it yet.
     // The next patch in this same bug prevents this from aborting the request.
     // Credentials checks for CORS are handled by nsCORSListenerProxy,
 
     nsCOMPtr<nsIHttpChannelInternal> internalChan = do_QueryInterface(httpChan);
 
     // Conversion between enumerations is safe due to static asserts in
     // dom/workers/ServiceWorkerManager.cpp
-    internalChan->SetCorsMode(static_cast<uint32_t>(mRequest->Mode()));
-    internalChan->SetRedirectMode(static_cast<uint32_t>(mRequest->GetRedirectMode()));
+    rv = internalChan->SetCorsMode(static_cast<uint32_t>(mRequest->Mode()));
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
+    rv = internalChan->SetRedirectMode(static_cast<uint32_t>(mRequest->GetRedirectMode()));
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
     mRequest->MaybeSkipCacheIfPerformingRevalidation();
-    internalChan->SetFetchCacheMode(static_cast<uint32_t>(mRequest->GetCacheMode()));
-    internalChan->SetIntegrityMetadata(mRequest->GetIntegrity());
+    rv = internalChan->SetFetchCacheMode(static_cast<uint32_t>(mRequest->GetCacheMode()));
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
+    rv = internalChan->SetIntegrityMetadata(mRequest->GetIntegrity());
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
   }
 
   // Step 5. Proxy authentication will be handled by Necko.
 
   // Continue setting up 'HTTPRequest'. Content-Type and body data.
   nsCOMPtr<nsIUploadChannel2> uploadChan = do_QueryInterface(chan);
   if (uploadChan) {
     nsAutoCString contentType;
@@ -446,30 +450,32 @@ FetchDriver::OnStartRequest(nsIRequest* 
   bool foundOpaqueRedirect = false;
 
   int64_t contentLength = InternalResponse::UNKNOWN_BODY_SIZE;
   rv = channel->GetContentLength(&contentLength);
   MOZ_ASSERT_IF(NS_FAILED(rv), contentLength == InternalResponse::UNKNOWN_BODY_SIZE);
 
   if (httpChannel) {
     uint32_t responseStatus;
-    httpChannel->GetResponseStatus(&responseStatus);
+    rv = httpChannel->GetResponseStatus(&responseStatus);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
 
     if (mozilla::net::nsHttpChannel::IsRedirectStatus(responseStatus)) {
       if (mRequest->GetRedirectMode() == RequestRedirect::Error) {
         FailWithNetworkError();
         return NS_BINDING_FAILED;
       }
       if (mRequest->GetRedirectMode() == RequestRedirect::Manual) {
         foundOpaqueRedirect = true;
       }
     }
 
     nsAutoCString statusText;
-    httpChannel->GetResponseStatusText(statusText);
+    rv = httpChannel->GetResponseStatusText(statusText);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
 
     response = new InternalResponse(responseStatus, statusText);
 
     response->Headers()->FillResponseHeaders(httpChannel);
 
     // If Content-Encoding or Transfer-Encoding headers are set, then the actual
     // Content-Length (which refer to the decoded data) is obscured behind the encodings.
     ErrorResult result;
@@ -734,18 +740,18 @@ FetchDriver::AsyncOnChannelRedirect(nsIC
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aNewChannel);
   if (httpChannel) {
     SetRequestHeaders(httpChannel);
   }
 
   nsCOMPtr<nsIHttpChannel> oldHttpChannel = do_QueryInterface(aOldChannel);
   nsAutoCString tRPHeaderCValue;
   if (oldHttpChannel) {
-    oldHttpChannel->GetResponseHeader(NS_LITERAL_CSTRING("referrer-policy"),
-                                      tRPHeaderCValue);
+    Unused << oldHttpChannel->GetResponseHeader(NS_LITERAL_CSTRING("referrer-policy"),
+                                                tRPHeaderCValue);
   }
 
   // "HTTP-redirect fetch": step 14 "Append locationURL to request's URL list."
   nsCOMPtr<nsIURI> uri;
   MOZ_ALWAYS_SUCCEEDS(aNewChannel->GetURI(getter_AddRefs(uri)));
 
   nsCOMPtr<nsIURI> uriClone;
   nsresult rv = uri->CloneIgnoringRef(getter_AddRefs(uriClone));
@@ -831,32 +837,40 @@ FetchDriver::SetRequestHeaders(nsIHttpCh
   AutoTArray<InternalHeaders::Entry, 5> headers;
   mRequest->Headers()->GetEntries(headers);
   bool hasAccept = false;
   for (uint32_t i = 0; i < headers.Length(); ++i) {
     if (!hasAccept && headers[i].mName.EqualsLiteral("accept")) {
       hasAccept = true;
     }
     if (headers[i].mValue.IsEmpty()) {
-      aChannel->SetEmptyRequestHeader(headers[i].mName);
+      DebugOnly<nsresult> rv = aChannel->SetEmptyRequestHeader(headers[i].mName);
+      MOZ_ASSERT(NS_SUCCEEDED(rv));
     } else {
-      aChannel->SetRequestHeader(headers[i].mName, headers[i].mValue, false /* merge */);
+      DebugOnly<nsresult> rv =
+        aChannel->SetRequestHeader(headers[i].mName, headers[i].mValue,
+                                   false /* merge */);
+      MOZ_ASSERT(NS_SUCCEEDED(rv));
     }
   }
 
   if (!hasAccept) {
-    aChannel->SetRequestHeader(NS_LITERAL_CSTRING("accept"),
-                               NS_LITERAL_CSTRING("*/*"),
-                               false /* merge */);
+    DebugOnly<nsresult> rv =
+      aChannel->SetRequestHeader(NS_LITERAL_CSTRING("accept"),
+                                 NS_LITERAL_CSTRING("*/*"),
+                                 false /* merge */);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
   }
 
   if (mRequest->ForceOriginHeader()) {
     nsAutoString origin;
     if (NS_SUCCEEDED(nsContentUtils::GetUTFOrigin(mPrincipal, origin))) {
-      aChannel->SetRequestHeader(NS_LITERAL_CSTRING("origin"),
-                                 NS_ConvertUTF16toUTF8(origin),
-                                 false /* merge */);
+      DebugOnly<nsresult> rv =
+        aChannel->SetRequestHeader(NS_LITERAL_CSTRING("origin"),
+                                   NS_ConvertUTF16toUTF8(origin),
+                                   false /* merge */);
+      MOZ_ASSERT(NS_SUCCEEDED(rv));
     }
   }
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/fetch/FetchUtil.cpp
+++ b/dom/fetch/FetchUtil.cpp
@@ -143,17 +143,17 @@ FetchUtil::SetRequestReferrer(nsIPrincip
     rv = NS_NewURI(getter_AddRefs(referrerURI), referrer, nullptr, nullptr);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = aChannel->SetReferrerWithPolicy(referrerURI, policy);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsCOMPtr<nsIURI> referrerURI;
-  aChannel->GetReferrer(getter_AddRefs(referrerURI));
+  Unused << aChannel->GetReferrer(getter_AddRefs(referrerURI));
 
   // Step 8 https://fetch.spec.whatwg.org/#main-fetch
   // If request’s referrer is not "no-referrer", set request’s referrer to
   // the result of invoking determine request’s referrer.
   if (referrerURI) {
     nsAutoCString spec;
     rv = referrerURI->GetSpec(spec);
     NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/fetch/InternalHeaders.cpp
+++ b/dom/fetch/InternalHeaders.cpp
@@ -350,17 +350,20 @@ void
 InternalHeaders::FillResponseHeaders(nsIRequest* aRequest)
 {
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest);
   if (!httpChannel) {
     return;
   }
 
   RefPtr<FillHeaders> visitor = new FillHeaders(this);
-  httpChannel->VisitResponseHeaders(visitor);
+  nsresult rv = httpChannel->VisitResponseHeaders(visitor);
+  if (NS_FAILED(rv)) {
+    NS_WARNING("failed to fill headers");
+  }
 }
 
 bool
 InternalHeaders::HasOnlySimpleHeaders() const
 {
   for (uint32_t i = 0; i < mList.Length(); ++i) {
     if (!IsSimpleHeader(mList[i].mName, mList[i].mValue)) {
       return false;
--- a/dom/flyweb/HttpServer.cpp
+++ b/dom/flyweb/HttpServer.cpp
@@ -286,17 +286,19 @@ HttpServer::TransportProvider::SetTransp
 
 void
 HttpServer::TransportProvider::MaybeNotify()
 {
   if (mTransport && mListener) {
     RefPtr<TransportProvider> self = this;
     nsCOMPtr<nsIRunnable> event = NS_NewRunnableFunction([self, this] ()
     {
-      mListener->OnTransportAvailable(mTransport, mInput, mOutput);
+      DebugOnly<nsresult> rv = mListener->OnTransportAvailable(mTransport,
+                                                               mInput, mOutput);
+      MOZ_ASSERT(NS_SUCCEEDED(rv));
     });
     NS_DispatchToCurrentThread(event);
   }
 }
 
 NS_IMPL_ISUPPORTS(HttpServer::Connection,
                   nsIInputStreamCallback,
                   nsIOutputStreamCallback)
--- a/dom/geolocation/nsGeolocation.cpp
+++ b/dom/geolocation/nsGeolocation.cpp
@@ -688,25 +688,16 @@ nsresult nsGeolocationService::Init()
   }
 
   obs->AddObserver(this, "xpcom-shutdown", false);
 
 #ifdef MOZ_WIDGET_ANDROID
   mProvider = new AndroidLocationProvider();
 #endif
 
-#ifdef MOZ_WIDGET_GONK
-  // GonkGPSGeolocationProvider can be started at boot up time for initialization reasons.
-  // do_getService gets hold of the already initialized component and starts
-  // processing location requests immediately.
-  // do_Createinstance will create multiple instances of the provider which is not right.
-  // bug 993041
-  mProvider = do_GetService(GONK_GPS_GEOLOCATION_PROVIDER_CONTRACTID);
-#endif
-
 #ifdef MOZ_WIDGET_GTK
 #ifdef MOZ_GPSD
   if (Preferences::GetBool("geo.provider.use_gpsd", false)) {
     mProvider = new GpsdLocationProvider();
   }
 #endif
 #endif
 
@@ -728,21 +719,21 @@ nsresult nsGeolocationService::Init()
   }
 
   // Override platform-specific providers with the default (network)
   // provider while testing. Our tests are currently not meant to exercise
   // the provider, and some tests rely on the network provider being used.
   // "geo.provider.testing" is always set for all plain and browser chrome
   // mochitests, and also for xpcshell tests.
   if (!mProvider || Preferences::GetBool("geo.provider.testing", false)) {
-    nsCOMPtr<nsIGeolocationProvider> geo_net_provider =
+    nsCOMPtr<nsIGeolocationProvider> geoTestProvider =
       do_GetService(NS_GEOLOCATION_PROVIDER_CONTRACTID);
 
-    if (geo_net_provider) {
-      mProvider = geo_net_provider;
+    if (geoTestProvider) {
+      mProvider = geoTestProvider;
     }
   }
 
   return NS_OK;
 }
 
 nsGeolocationService::~nsGeolocationService() = default;
 
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -27,17 +27,16 @@
 #include "nsSize.h"
 #include "nsIFrame.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsIDocShell.h"
 #include "nsError.h"
 #include "nsNodeInfoManager.h"
 #include "nsNetUtil.h"
-#include "nsXPCOMStrings.h"
 #include "xpcpublic.h"
 #include "nsThreadUtils.h"
 #include "nsIThreadInternal.h"
 #include "nsContentUtils.h"
 #include "nsIRequest.h"
 #include "nsQueryObject.h"
 #include "nsIObserverService.h"
 #include "nsISupportsPrimitives.h"
@@ -512,17 +511,17 @@ HTMLMediaElement::MediaLoadListener::OnS
     return status;
   }
 
   nsCOMPtr<nsIHttpChannel> hc = do_QueryInterface(aRequest);
   bool succeeded;
   if (hc && NS_SUCCEEDED(hc->GetRequestSucceeded(&succeeded)) && !succeeded) {
     element->NotifyLoadError();
     uint32_t responseStatus = 0;
-    hc->GetResponseStatus(&responseStatus);
+    Unused << hc->GetResponseStatus(&responseStatus);
     nsAutoString code;
     code.AppendInt(responseStatus);
     nsAutoString src;
     element->GetCurrentSrc(src);
     const char16_t* params[] = { code.get(), src.get() };
     element->ReportLoadError("MediaLoadHttpError", params, ArrayLength(params));
     return NS_BINDING_ABORTED;
   }
@@ -1164,19 +1163,20 @@ public:
 
     channel->SetNotificationCallbacks(loadListener);
 
     nsCOMPtr<nsIHttpChannel> hc = do_QueryInterface(channel);
     if (hc) {
       // Use a byte range request from the start of the resource.
       // This enables us to detect if the stream supports byte range
       // requests, and therefore seeking, early.
-      hc->SetRequestHeader(NS_LITERAL_CSTRING("Range"),
-                           NS_LITERAL_CSTRING("bytes=0-"),
-                           false);
+      rv = hc->SetRequestHeader(NS_LITERAL_CSTRING("Range"),
+                                NS_LITERAL_CSTRING("bytes=0-"),
+                                false);
+      MOZ_ASSERT(NS_SUCCEEDED(rv));
       aElement->SetRequestHeaders(hc);
     }
 
     rv = channel->AsyncOpen2(loadListener);
     if (NS_FAILED(rv)) {
       // Notify load error so the element will try next resource candidate.
       aElement->NotifyLoadError();
       return;
@@ -6450,22 +6450,25 @@ void HTMLMediaElement::SetRequestHeaders
   // Send Accept header for video and audio types only (Bug 489071)
   SetAcceptHeader(aChannel);
 
   // Apache doesn't send Content-Length when gzip transfer encoding is used,
   // which prevents us from estimating the video length (if explicit Content-Duration
   // and a length spec in the container are not present either) and from seeking.
   // So, disable the standard "Accept-Encoding: gzip,deflate" that we usually send.
   // See bug 614760.
-  aChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept-Encoding"),
-                             EmptyCString(), false);
+  DebugOnly<nsresult> rv =
+    aChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept-Encoding"),
+                               EmptyCString(), false);
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
 
   // Set the Referer header
-  aChannel->SetReferrerWithPolicy(OwnerDoc()->GetDocumentURI(),
-                                  OwnerDoc()->GetReferrerPolicy());
+  rv = aChannel->SetReferrerWithPolicy(OwnerDoc()->GetDocumentURI(),
+                                       OwnerDoc()->GetReferrerPolicy());
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
 }
 
 void HTMLMediaElement::FireTimeUpdate(bool aPeriodic)
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
 
   TimeStamp now = TimeStamp::Now();
   double time = CurrentTime();
--- a/dom/html/HTMLVideoElement.cpp
+++ b/dom/html/HTMLVideoElement.cpp
@@ -8,17 +8,16 @@
 #include "mozilla/dom/HTMLVideoElement.h"
 #include "mozilla/dom/HTMLVideoElementBinding.h"
 #include "nsGenericHTMLElement.h"
 #include "nsGkAtoms.h"
 #include "nsSize.h"
 #include "nsError.h"
 #include "nsNodeInfoManager.h"
 #include "plbase64.h"
-#include "nsXPCOMStrings.h"
 #include "prlock.h"
 #include "nsThreadUtils.h"
 #include "ImageContainer.h"
 #include "VideoFrameContainer.h"
 
 #include "nsIScriptSecurityManager.h"
 #include "nsIXPConnect.h"
 
--- a/dom/html/nsHTMLDNSPrefetch.cpp
+++ b/dom/html/nsHTMLDNSPrefetch.cpp
@@ -124,113 +124,131 @@ nsHTMLDNSPrefetch::PrefetchMedium(Link *
 
 nsresult
 nsHTMLDNSPrefetch::PrefetchHigh(Link *aElement)
 {
   return Prefetch(aElement, 0);
 }
 
 nsresult
-nsHTMLDNSPrefetch::Prefetch(const nsAString &hostname, uint16_t flags)
+nsHTMLDNSPrefetch::Prefetch(const nsAString &hostname,
+                            const OriginAttributes &aOriginAttributes,
+                            uint16_t flags)
 {
   if (IsNeckoChild()) {
     // We need to check IsEmpty() because net_IsValidHostName()
     // considers empty strings to be valid hostnames
     if (!hostname.IsEmpty() &&
         net_IsValidHostName(NS_ConvertUTF16toUTF8(hostname))) {
       // during shutdown gNeckoChild might be null
       if (gNeckoChild) {
-        gNeckoChild->SendHTMLDNSPrefetch(nsAutoString(hostname), flags);
+        gNeckoChild->SendHTMLDNSPrefetch(nsString(hostname),
+                                         aOriginAttributes, flags);
       }
     }
     return NS_OK;
   }
 
   if (!(sInitialized && sDNSService && sPrefetches && sDNSListener))
     return NS_ERROR_NOT_AVAILABLE;
 
   nsCOMPtr<nsICancelable> tmpOutstanding;
-  return sDNSService->AsyncResolve(NS_ConvertUTF16toUTF8(hostname),
-                                   flags | nsIDNSService::RESOLVE_SPECULATE,
-                                   sDNSListener, nullptr, 
-                                   getter_AddRefs(tmpOutstanding));
+  return sDNSService->AsyncResolveNative(NS_ConvertUTF16toUTF8(hostname),
+                                         flags | nsIDNSService::RESOLVE_SPECULATE,
+                                         sDNSListener, nullptr, aOriginAttributes,
+                                         getter_AddRefs(tmpOutstanding));
 }
 
 nsresult
-nsHTMLDNSPrefetch::PrefetchLow(const nsAString &hostname)
+nsHTMLDNSPrefetch::PrefetchLow(const nsAString &hostname,
+                               const OriginAttributes &aOriginAttributes)
 {
-  return Prefetch(hostname, nsIDNSService::RESOLVE_PRIORITY_LOW);
+  return Prefetch(hostname, aOriginAttributes, nsIDNSService::RESOLVE_PRIORITY_LOW);
 }
 
 nsresult
-nsHTMLDNSPrefetch::PrefetchMedium(const nsAString &hostname)
+nsHTMLDNSPrefetch::PrefetchMedium(const nsAString &hostname,
+                                  const OriginAttributes &aOriginAttributes)
 {
-  return Prefetch(hostname, nsIDNSService::RESOLVE_PRIORITY_MEDIUM);
+  return Prefetch(hostname, aOriginAttributes, nsIDNSService::RESOLVE_PRIORITY_MEDIUM);
 }
 
 nsresult
-nsHTMLDNSPrefetch::PrefetchHigh(const nsAString &hostname)
+nsHTMLDNSPrefetch::PrefetchHigh(const nsAString &hostname,
+                                const OriginAttributes &aOriginAttributes)
 {
-  return Prefetch(hostname, 0);
+  return Prefetch(hostname, aOriginAttributes, 0);
 }
 
 nsresult
 nsHTMLDNSPrefetch::CancelPrefetch(Link *aElement,
                                   uint16_t flags,
                                   nsresult aReason)
 {
   if (!(sInitialized && sPrefetches && sDNSService && sDNSListener))
     return NS_ERROR_NOT_AVAILABLE;
 
   nsAutoString hostname;
   aElement->GetHostname(hostname);
-  return CancelPrefetch(hostname, flags, aReason);
+
+  Element* element = aElement->GetElement();
+  NS_ENSURE_TRUE(element, NS_ERROR_FAILURE);
+
+  return CancelPrefetch(hostname,
+                        element->NodePrincipal()
+                               ->OriginAttributesRef(),
+                        flags, aReason);
 }
 
 nsresult
 nsHTMLDNSPrefetch::CancelPrefetch(const nsAString &hostname,
+                                  const OriginAttributes &aOriginAttributes,
                                   uint16_t flags,
                                   nsresult aReason)
 {
   // Forward this request to Necko Parent if we're a child process
   if (IsNeckoChild()) {
     // We need to check IsEmpty() because net_IsValidHostName()
     // considers empty strings to be valid hostnames
     if (!hostname.IsEmpty() &&
         net_IsValidHostName(NS_ConvertUTF16toUTF8(hostname))) {
       // during shutdown gNeckoChild might be null
       if (gNeckoChild) {
-        gNeckoChild->SendCancelHTMLDNSPrefetch(nsString(hostname), flags,
+        gNeckoChild->SendCancelHTMLDNSPrefetch(nsString(hostname),
+                                               aOriginAttributes,
+                                               flags,
                                                aReason);
       }
     }
     return NS_OK;
   }
 
   if (!(sInitialized && sDNSService && sPrefetches && sDNSListener))
     return NS_ERROR_NOT_AVAILABLE;
 
   // Forward cancellation to DNS service
-  return sDNSService->CancelAsyncResolve(NS_ConvertUTF16toUTF8(hostname),
-                                         flags
-                                         | nsIDNSService::RESOLVE_SPECULATE,
-                                         sDNSListener, aReason);
+  return sDNSService->CancelAsyncResolveNative(NS_ConvertUTF16toUTF8(hostname),
+                                               flags
+                                               | nsIDNSService::RESOLVE_SPECULATE,
+                                               sDNSListener, aReason, aOriginAttributes);
 }
 
 nsresult
 nsHTMLDNSPrefetch::CancelPrefetchLow(Link *aElement, nsresult aReason)
 {
   return CancelPrefetch(aElement, nsIDNSService::RESOLVE_PRIORITY_LOW,
                         aReason);
 }
 
 nsresult
-nsHTMLDNSPrefetch::CancelPrefetchLow(const nsAString &hostname, nsresult aReason)
+nsHTMLDNSPrefetch::CancelPrefetchLow(const nsAString &hostname,
+                                     const OriginAttributes &aOriginAttributes,
+                                     nsresult aReason)
 {
-  return CancelPrefetch(hostname, nsIDNSService::RESOLVE_PRIORITY_LOW,
+  return CancelPrefetch(hostname, aOriginAttributes, nsIDNSService::RESOLVE_PRIORITY_LOW,
                         aReason);
 }
 
 
 /////////////////////////////////////////////////////////////////////////////////////////////////////////
 
 NS_IMPL_ISUPPORTS(nsHTMLDNSPrefetch::nsListener,
                   nsIDNSListener)
@@ -313,52 +331,58 @@ nsHTMLDNSPrefetch::nsDeferrals::SubmitQu
     nsCOMPtr<nsIContent> content = do_QueryReferent(mEntries[mTail].mElement);
     if (content) {
       nsCOMPtr<Link> link = do_QueryInterface(content);
       // Only prefetch here if request was deferred and deferral not cancelled
       if (link && link->HasDeferredDNSPrefetchRequest()) {
         nsCOMPtr<nsIURI> hrefURI(link ? link->GetURI() : nullptr);
         bool isLocalResource = false;
         nsresult rv = NS_OK;
+        Element* element = link->GetElement();
 
         hostName.Truncate();
         if (hrefURI) {
           hrefURI->GetAsciiHost(hostName);
           rv = NS_URIChainHasFlags(hrefURI,
                                    nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
                                    &isLocalResource);
         }
 
-        if (!hostName.IsEmpty() && NS_SUCCEEDED(rv) && !isLocalResource) {
+        if (!hostName.IsEmpty() && NS_SUCCEEDED(rv) && !isLocalResource &&
+            element) {
           if (IsNeckoChild()) {
             // during shutdown gNeckoChild might be null
             if (gNeckoChild) {
               gNeckoChild->SendHTMLDNSPrefetch(NS_ConvertUTF8toUTF16(hostName),
+                                               element->NodePrincipal()
+                                                      ->OriginAttributesRef(),
                                                mEntries[mTail].mFlags);
             }
           } else {
             nsCOMPtr<nsICancelable> tmpOutstanding;
 
-            rv = sDNSService->AsyncResolve(hostName,
-                                           mEntries[mTail].mFlags
-                                           | nsIDNSService::RESOLVE_SPECULATE,
-                                           sDNSListener, nullptr,
-                                           getter_AddRefs(tmpOutstanding));
+            rv = sDNSService->AsyncResolveNative(hostName,
+                                                 mEntries[mTail].mFlags
+                                                 | nsIDNSService::RESOLVE_SPECULATE,
+                                                 sDNSListener, nullptr,
+                                                 element->NodePrincipal()
+                                                        ->OriginAttributesRef(),
+                                                 getter_AddRefs(tmpOutstanding));
             // Tell link that deferred prefetch was requested
             if (NS_SUCCEEDED(rv))
               link->OnDNSPrefetchRequested();
           }
         }
       }
     }
-    
+
     mEntries[mTail].mElement = nullptr;
     mTail = (mTail + 1) & sMaxDeferredMask;
   }
-  
+
   if (mTimerArmed) {
     mTimerArmed = false;
     mTimer->Cancel();
   }
 }
 
 void
 nsHTMLDNSPrefetch::nsDeferrals::Activate()
--- a/dom/html/nsHTMLDNSPrefetch.h
+++ b/dom/html/nsHTMLDNSPrefetch.h
@@ -46,27 +46,35 @@ public:
   // complete, while the string versions submit the lookup to 
   // the DNS system immediately. The URI version is somewhat lighter
   // weight, but its request is also more likely to be dropped due to a 
   // full queue and it may only be used from the main thread.
 
   static nsresult PrefetchHigh(mozilla::dom::Link *aElement);
   static nsresult PrefetchMedium(mozilla::dom::Link *aElement);
   static nsresult PrefetchLow(mozilla::dom::Link *aElement);
-  static nsresult PrefetchHigh(const nsAString &host);
-  static nsresult PrefetchMedium(const nsAString &host);
-  static nsresult PrefetchLow(const nsAString &host);
-  static nsresult CancelPrefetchLow(const nsAString &host, nsresult aReason);
+  static nsresult PrefetchHigh(const nsAString &host,
+                               const mozilla::OriginAttributes &aOriginAttributes);
+  static nsresult PrefetchMedium(const nsAString &host,
+                                 const mozilla::OriginAttributes &aOriginAttributes);
+  static nsresult PrefetchLow(const nsAString &host,
+                              const mozilla::OriginAttributes &aOriginAttributes);
+  static nsresult CancelPrefetchLow(const nsAString &host,
+                                    const mozilla::OriginAttributes &aOriginAttributes,
+                                    nsresult aReason);
   static nsresult CancelPrefetchLow(mozilla::dom::Link *aElement,
                                     nsresult aReason);
 
 private:
-  static nsresult Prefetch(const nsAString &host, uint16_t flags);
+  static nsresult Prefetch(const nsAString &host,
+                           const mozilla::OriginAttributes &aOriginAttributes,
+                           uint16_t flags);
   static nsresult Prefetch(mozilla::dom::Link *aElement, uint16_t flags);
   static nsresult CancelPrefetch(const nsAString &hostname,
+                                 const mozilla::OriginAttributes &aOriginAttributes,
                                  uint16_t flags,
                                  nsresult aReason);
   static nsresult CancelPrefetch(mozilla::dom::Link *aElement,
                                  uint16_t flags,
                                  nsresult aReason);
   
 public:
   class nsListener final : public nsIDNSListener
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -1971,16 +1971,36 @@ interface nsIDOMWindowUtils : nsISupport
   readonly attribute int32_t gpuProcessPid;
 
   /**
    * Returns true if the given timeout ID is in the list of tracking
    * timeouts.
    */
   boolean isTimeoutTracking(in unsigned long timeoutId);
 
+  /**
+   * Adds an EventStates bit to the element.
+   *
+   * The state string must be one of the following:
+   *   * (none yet; but for example "higlighted" for NS_EVENT_STATE_HIGHLIGHTED)
+   *
+   * The supported state strings are defined in kManuallyManagedStates
+   * in nsDOMWindowUtils.cpp.
+   */
+  void addManuallyManagedState(in nsIDOMElement element,
+                               in AString state);
+
+  /**
+   * Removes the specified EventStates bits from the element.
+   *
+   * See above for the strings that can be passed for |state|.
+   */
+  void removeManuallyManagedState(in nsIDOMElement element,
+                                  in AString state);
+
   // These consts are only for testing purposes.
   const long DEFAULT_MOUSE_POINTER_ID = 0;
   const long DEFAULT_PEN_POINTER_ID   = 1;
   const long DEFAULT_TOUCH_POINTER_ID = 2;
 
   // Match WidgetMouseEventBase::buttonType.
   const long MOUSE_BUTTON_LEFT_BUTTON   = 0;
   const long MOUSE_BUTTON_MIDDLE_BUTTON = 1;
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -4245,16 +4245,33 @@ ContentParent::RecvDeallocateTabId(const
 mozilla::ipc::IPCResult
 ContentParent::RecvNotifyTabDestroying(const TabId& aTabId,
                                        const ContentParentId& aCpId)
 {
   NotifyTabDestroying(aTabId, aCpId);
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult
+ContentParent::RecvTabChildNotReady(const TabId& aTabId)
+{
+  ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
+  RefPtr<TabParent> tp =
+    cpm->GetTopLevelTabParentByProcessAndTabId(this->ChildID(), aTabId);
+
+  if (!tp) {
+    NS_WARNING("Couldn't find TabParent for TabChildNotReady message.");
+    return IPC_OK();
+  }
+
+  tp->DispatchTabChildNotReadyEvent();
+
+  return IPC_OK();
+}
+
 nsTArray<TabContext>
 ContentParent::GetManagedTabContext()
 {
   return Move(ContentProcessManager::GetSingleton()->
           GetTabContextByContentProcess(this->ChildID()));
 }
 
 mozilla::docshell::POfflineCacheUpdateParent*
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -486,16 +486,18 @@ public:
 
   virtual mozilla::ipc::IPCResult RecvDeallocateTabId(const TabId& aTabId,
                                                       const ContentParentId& aCpId,
                                                       const bool& aMarkedDestroying) override;
 
   virtual mozilla::ipc::IPCResult RecvNotifyTabDestroying(const TabId& aTabId,
                                                           const ContentParentId& aCpId) override;
 
+  virtual mozilla::ipc::IPCResult RecvTabChildNotReady(const TabId& aTabId) override;
+
   nsTArray<TabContext> GetManagedTabContext();
 
   virtual POfflineCacheUpdateParent*
   AllocPOfflineCacheUpdateParent(const URIParams& aManifestURI,
                                  const URIParams& aDocumentURI,
                                  const PrincipalInfo& aLoadingPrincipalInfo,
                                  const bool& aStickDocument) override;
 
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -1017,16 +1017,19 @@ parent:
                           ContentParentId cpId,
                           bool aMarkedDestroying);
 
     /**
      * Tell the chrome process there is a destruction of PBrowser(Tab)
      */
     async NotifyTabDestroying(TabId tabId,
                               ContentParentId cpId);
+
+    async TabChildNotReady(TabId tabId);
+
     /**
      * Starts an offline application cache update.
      * @param manifestURI
      *   URI of the manifest to fetch, the application cache group ID
      * @param documentURI
      *   URI of the document that referred the manifest
      * @param loadingPrincipal
      *   Principal of the document that referred the manifest
--- a/dom/ipc/PProcessHangMonitor.ipdl
+++ b/dom/ipc/PProcessHangMonitor.ipdl
@@ -29,16 +29,17 @@ union HangData
   PluginHangData;
 };
 
 protocol PProcessHangMonitor
 {
 parent:
   async HangEvidence(HangData data);
   async ClearHang();
+  async Ready();
 
 child:
   async TerminateScript();
 
   async BeginStartingDebugger();
   async EndStartingDebugger();
 
   async ForcePaint(TabId tabId, uint64_t aLayerObserverEpoch);
--- a/dom/ipc/ProcessHangMonitor.cpp
+++ b/dom/ipc/ProcessHangMonitor.cpp
@@ -7,21 +7,23 @@
 #include "mozilla/ProcessHangMonitor.h"
 #include "mozilla/ProcessHangMonitorIPC.h"
 
 #include "jsapi.h"
 #include "js/GCAPI.h"
 
 #include "mozilla/Atomics.h"
 #include "mozilla/BackgroundHangMonitor.h"
+#include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/TabParent.h"
+#include "mozilla/ipc/TaskFactory.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/plugins/PluginBridge.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Unused.h"
 
 #include "nsIFrameLoader.h"
 #include "nsIHangReport.h"
 #include "nsITabParent.h"
@@ -189,16 +191,18 @@ public:
     mDumpId = aDumpId;
   }
 
   void ClearHang() {
     mHangData = HangData();
     mDumpId.Truncate();
   }
 
+  void DispatchTabChildNotReady(TabId aTabId);
+
 private:
   ~HangMonitoredProcess() = default;
 
   // Everything here is main thread-only.
   HangMonitorParent* mActor;
   ContentParent* mContentParent;
   HangData mHangData;
   nsAutoString mDumpId;
@@ -208,16 +212,17 @@ class HangMonitorParent
   : public PProcessHangMonitorParent
 {
 public:
   explicit HangMonitorParent(ProcessHangMonitor* aMonitor);
   ~HangMonitorParent() override;
 
   void Bind(Endpoint<PProcessHangMonitorParent>&& aEndpoint);
 
+  mozilla::ipc::IPCResult RecvReady() override;
   mozilla::ipc::IPCResult RecvHangEvidence(const HangData& aHangData) override;
   mozilla::ipc::IPCResult RecvClearHang() override;
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
   void SetProcess(HangMonitoredProcess* aProcess) { mProcess = aProcess; }
 
   void Shutdown();
@@ -236,38 +241,51 @@ public:
    */
   void UpdateMinidump(uint32_t aPluginId, const nsString& aDumpId);
 
   MessageLoop* MonitorLoop() { return mHangMonitor->MonitorLoop(); }
 
 private:
   bool TakeBrowserMinidump(const PluginHangData& aPhd, nsString& aCrashId);
 
+  void DispatchTabChildNotReady(TabId aTabId);
+
   void ForcePaintOnThread(TabId aTabId, uint64_t aLayerObserverEpoch);
 
   void ShutdownOnThread();
 
   const RefPtr<ProcessHangMonitor> mHangMonitor;
 
   // This field is read-only after construction.
   bool mReportHangs;
 
+  // This field is only accessed on the hang thread. Inits to
+  // false, and will flip to true once the HangMonitorChild is
+  // constructed in the child process, and sends a message saying
+  // so.
+  bool mReady;
+
   // This field is only accessed on the hang thread.
   bool mIPCOpen;
 
   Monitor mMonitor;
 
   // Must be accessed with mMonitor held.
   RefPtr<HangMonitoredProcess> mProcess;
   bool mShutdownDone;
   // Map from plugin ID to crash dump ID. Protected by mBrowserCrashDumpHashLock.
   nsDataHashtable<nsUint32HashKey, nsString> mBrowserCrashDumpIds;
   Mutex mBrowserCrashDumpHashLock;
+  mozilla::ipc::TaskFactory<HangMonitorParent> mMainThreadTaskFactory;
+
+  static bool sShouldForcePaint;
 };
 
+bool HangMonitorParent::sShouldForcePaint = true;
+
 } // namespace
 
 /* HangMonitorChild implementation */
 
 HangMonitorChild::HangMonitorChild(ProcessHangMonitor* aMonitor)
  : mHangMonitor(aMonitor),
    mMonitor("HangMonitorChild lock"),
    mSentReport(false),
@@ -313,16 +331,21 @@ HangMonitorChild::InterruptCallback()
     mForcePaint = false;
   }
 
   if (forcePaint) {
     RefPtr<TabChild> tabChild = TabChild::FindTabChild(forcePaintTab);
     if (tabChild) {
       js::AutoAssertNoContentJS nojs(mContext);
       tabChild->ForcePaint(forcePaintEpoch);
+    } else {
+      auto cc = ContentChild::GetSingleton();
+      if (cc) {
+        cc->SendTabChildNotReady(forcePaintTab);
+      }
     }
   }
 }
 
 void
 HangMonitorChild::Shutdown()
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
@@ -418,16 +441,18 @@ HangMonitorChild::Bind(Endpoint<PProcess
 {
   MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
 
   MOZ_ASSERT(!sInstance);
   sInstance = this;
 
   DebugOnly<bool> ok = aEndpoint.Bind(this);
   MOZ_ASSERT(ok);
+
+  Unused << SendReady();
 }
 
 void
 HangMonitorChild::NotifySlowScriptAsync(TabId aTabId,
                                         const nsCString& aFileName,
                                         unsigned aLineNo)
 {
   if (mIPCOpen) {
@@ -540,23 +565,32 @@ HangMonitorChild::ClearHangAsync()
     Unused << SendClearHang();
   }
 }
 
 /* HangMonitorParent implementation */
 
 HangMonitorParent::HangMonitorParent(ProcessHangMonitor* aMonitor)
  : mHangMonitor(aMonitor),
+   mReady(false),
    mIPCOpen(true),
    mMonitor("HangMonitorParent lock"),
    mShutdownDone(false),
-   mBrowserCrashDumpHashLock("mBrowserCrashDumpIds lock")
+   mBrowserCrashDumpHashLock("mBrowserCrashDumpIds lock"),
+   mMainThreadTaskFactory(this)
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   mReportHangs = mozilla::Preferences::GetBool("dom.ipc.reportProcessHangs", false);
+
+  static bool sInited = false;
+  if (!sInited) {
+    sInited = true;
+    Preferences::AddBoolVarCache(&sShouldForcePaint,
+                                 "browser.tabs.remote.force-paint", true);
+  }
 }
 
 HangMonitorParent::~HangMonitorParent()
 {
 #ifdef MOZ_CRASHREPORTER
   MutexAutoLock lock(mBrowserCrashDumpHashLock);
 
   for (auto iter = mBrowserCrashDumpIds.Iter(); !iter.Done(); iter.Next()) {
@@ -604,28 +638,55 @@ HangMonitorParent::ShutdownOnThread()
   mShutdownDone = true;
   mMonitor.Notify();
 }
 
 void
 HangMonitorParent::ForcePaint(dom::TabParent* aTab, uint64_t aLayerObserverEpoch)
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
-  TabId id = aTab->GetTabId();
-  MonitorLoop()->PostTask(NewNonOwningRunnableMethod<TabId, uint64_t>(
-                            this, &HangMonitorParent::ForcePaintOnThread, id, aLayerObserverEpoch));
+  if (sShouldForcePaint) {
+    TabId id = aTab->GetTabId();
+    MonitorLoop()->PostTask(NewNonOwningRunnableMethod<TabId, uint64_t>(
+                              this, &HangMonitorParent::ForcePaintOnThread, id, aLayerObserverEpoch));
+  }
+}
+
+void
+HangMonitorParent::DispatchTabChildNotReady(TabId aTabId)
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+  if (!mProcess) {
+    return;
+  }
+
+  mProcess->DispatchTabChildNotReady(aTabId);
 }
 
 void
 HangMonitorParent::ForcePaintOnThread(TabId aTabId, uint64_t aLayerObserverEpoch)
 {
   MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
 
   if (mIPCOpen) {
-    Unused << SendForcePaint(aTabId, aLayerObserverEpoch);
+    if (mReady) {
+      Unused << SendForcePaint(aTabId, aLayerObserverEpoch);
+    } else {
+      // We've never heard from the HangMonitorChild before, so
+      // it's either not finished setting up, or has only recently
+      // finished setting up. In either case, we're dealing with
+      // a new content process that probably hasn't had time to
+      // get the ContentChild, let alone the TabChild for aTabId,
+      // set up, and so attempting to force paint on the non-existant
+      // TabChild is not going to work. Instead, we tell the main
+      // thread that we're waiting on a TabChild to be created.
+      NS_DispatchToMainThread(
+        mMainThreadTaskFactory.NewRunnableMethod(
+          &HangMonitorParent::DispatchTabChildNotReady, aTabId));
+    }
   }
 }
 
 void
 HangMonitorParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
   mIPCOpen = false;
@@ -714,16 +775,24 @@ HangMonitorParent::TakeBrowserMinidump(c
     }
   }
 #endif // MOZ_CRASHREPORTER
 
   return false;
 }
 
 mozilla::ipc::IPCResult
+HangMonitorParent::RecvReady()
+{
+  MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
+  mReady = true;
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
 HangMonitorParent::RecvHangEvidence(const HangData& aHangData)
 {
   // chrome process, background thread
   MOZ_RELEASE_ASSERT(MessageLoop::current() == MonitorLoop());
 
   if (!mReportHangs) {
     return IPC_OK();
   }
@@ -1053,16 +1122,27 @@ HangMonitoredProcess::UserCanceled()
 
   if (mActor) {
     uint32_t id = mHangData.get_PluginHangData().pluginId();
     mActor->CleanupPluginHang(id, true);
   }
   return NS_OK;
 }
 
+void
+HangMonitoredProcess::DispatchTabChildNotReady(TabId aTabId)
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+  if (!mContentParent) {
+    return;
+  }
+
+  Unused << mContentParent->RecvTabChildNotReady(aTabId);
+}
+
 static bool
 InterruptCallback(JSContext* cx)
 {
   if (HangMonitorChild* child = HangMonitorChild::Get()) {
     child->InterruptCallback();
   }
 
   return true;
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -162,16 +162,17 @@ TabParent::TabParent(nsIContentParent* a
   , mCursor(nsCursor(-1))
   , mTabSetsCursor(false)
   , mHasContentOpener(false)
 #ifdef DEBUG
   , mActiveSupressDisplayportCount(0)
 #endif
   , mLayerTreeEpoch(0)
   , mPreserveLayers(false)
+  , mHasPresented(false)
 {
   MOZ_ASSERT(aManager);
 }
 
 TabParent::~TabParent()
 {
 }
 
@@ -2848,16 +2849,17 @@ TabParent::LayerTreeUpdate(uint64_t aEpo
   nsCOMPtr<mozilla::dom::EventTarget> target = do_QueryInterface(mFrameElement);
   if (!target) {
     NS_WARNING("Could not locate target for layer tree message.");
     return;
   }
 
   RefPtr<Event> event = NS_NewDOMEvent(mFrameElement, nullptr, nullptr);
   if (aActive) {
+    mHasPresented = true;
     event->InitEvent(NS_LITERAL_STRING("MozLayerTreeReady"), true, false);
   } else {
     event->InitEvent(NS_LITERAL_STRING("MozLayerTreeCleared"), true, false);
   }
   event->SetTrusted(true);
   event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
   bool dummy;
   mFrameElement->DispatchEvent(event, &dummy);
@@ -3327,16 +3329,62 @@ TabParent::LiveResizeStarted()
 }
 
 void
 TabParent::LiveResizeStopped()
 {
   SuppressDisplayport(false);
 }
 
+void
+TabParent::DispatchTabChildNotReadyEvent()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsCOMPtr<mozilla::dom::EventTarget> target = do_QueryInterface(mFrameElement);
+  if (!target) {
+    NS_WARNING("Could not locate target for tab child not ready event.");
+    return;
+  }
+
+  if (mHasPresented) {
+    // We shouldn't dispatch this event because clearly the
+    // TabChild _became_ ready by the time we were told to
+    // dispatch.
+    return;
+  }
+
+  if (!mDocShellIsActive) {
+    return;
+  }
+
+  RefPtr<nsFrameLoader> frameLoader = GetFrameLoader(true);
+  if (!frameLoader) {
+    return;
+  }
+
+  nsCOMPtr<Element> frameElement(mFrameElement);
+  nsCOMPtr<nsIFrameLoaderOwner> owner = do_QueryInterface(frameElement);
+  if (!owner) {
+    return;
+  }
+
+  RefPtr<nsFrameLoader> currentFrameLoader = owner->GetFrameLoader();
+  if (currentFrameLoader != frameLoader) {
+    return;
+  }
+
+  RefPtr<Event> event = NS_NewDOMEvent(mFrameElement, nullptr, nullptr);
+  event->InitEvent(NS_LITERAL_STRING("MozTabChildNotReady"), true, false);
+  event->SetTrusted(true);
+  event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
+  bool dummy;
+  mFrameElement->DispatchEvent(event, &dummy);
+}
+
 NS_IMETHODIMP
 FakeChannel::OnAuthAvailable(nsISupports *aContext, nsIAuthInformation *aAuthInfo)
 {
   nsAuthInformationHolder* holder =
     static_cast<nsAuthInformationHolder*>(aAuthInfo);
 
   if (!net::gNeckoChild->SendOnAuthAvailable(mCallbackId,
                                              holder->User(),
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -594,16 +594,18 @@ public:
                           uint64_t* aLayersId);
 
   mozilla::ipc::IPCResult RecvEnsureLayersConnected() override;
 
   // LiveResizeListener implementation
   void LiveResizeStarted() override;
   void LiveResizeStopped() override;
 
+  void DispatchTabChildNotReadyEvent();
+
 protected:
   bool ReceiveMessage(const nsString& aMessage,
                       bool aSync,
                       ipc::StructuredCloneData* aData,
                       mozilla::jsipc::CpowHolder* aCpows,
                       nsIPrincipal* aPrincipal,
                       nsTArray<ipc::StructuredCloneData>* aJSONRetVal = nullptr);
 
@@ -773,16 +775,20 @@ private:
   static void RemoveTabParentFromTable(uint64_t aLayersId);
 
   uint64_t mLayerTreeEpoch;
 
   // If this flag is set, then the tab's layers will be preserved even when
   // the tab's docshell is inactive.
   bool mPreserveLayers;
 
+  // True if this TabParent has had its layer tree sent to the compositor
+  // at least once.
+  bool mHasPresented;
+
 public:
   static TabParent* GetTabParentFromLayersId(uint64_t aLayersId);
 };
 
 struct MOZ_STACK_CLASS TabParent::AutoUseNewTab final
 {
 public:
   AutoUseNewTab(TabParent* aNewTab, bool* aWindowIsNew, nsCString* aURLToLoad)
--- a/dom/json/nsJSON.cpp
+++ b/dom/json/nsJSON.cpp
@@ -10,17 +10,16 @@
 #include "nsIXPConnect.h"
 #include "nsIXPCScriptable.h"
 #include "nsStreamUtils.h"
 #include "nsIInputStream.h"
 #include "nsStringStream.h"
 #include "mozilla/dom/EncodingUtils.h"
 #include "nsIUnicodeEncoder.h"
 #include "nsIUnicodeDecoder.h"
-#include "nsXPCOMStrings.h"
 #include "nsNetUtil.h"
 #include "nsIURI.h"
 #include "nsComponentManagerUtils.h"
 #include "nsContentUtils.h"
 #include "nsIScriptError.h"
 #include "nsCRTGlue.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsNullPrincipal.h"
@@ -358,18 +357,18 @@ nsJSONWriter::WriteToStream(nsIOutputStr
 NS_IMETHODIMP
 nsJSON::Decode(const nsAString& json, JSContext* cx,
                JS::MutableHandle<JS::Value> aRetval)
 {
   nsresult rv = WarnDeprecatedMethod(DecodeWarning);
   if (NS_FAILED(rv))
     return rv;
 
-  const char16_t *data;
-  uint32_t len = NS_StringGetData(json, &data);
+  const char16_t *data = json.BeginReading();
+  uint32_t len = json.Length();
   nsCOMPtr<nsIInputStream> stream;
   rv = NS_NewByteInputStream(getter_AddRefs(stream),
                              reinterpret_cast<const char*>(data),
                              len * sizeof(char16_t),
                              NS_ASSIGNMENT_DEPEND);
   NS_ENSURE_SUCCESS(rv, rv);
   return DecodeInternal(cx, stream, len, false, aRetval);
 }
--- a/dom/media/MediaResource.cpp
+++ b/dom/media/MediaResource.cpp
@@ -49,18 +49,21 @@ namespace mozilla {
 void
 MediaResource::Destroy()
 {
   // Ensures we only delete the MediaResource on the main thread.
   if (NS_IsMainThread()) {
     delete this;
     return;
   }
-  MOZ_ALWAYS_SUCCEEDS(
-    NS_DispatchToMainThread(NewNonOwningRunnableMethod(this, &MediaResource::Destroy)));
+  nsresult rv =
+    SystemGroup::Dispatch("MediaResource::Destroy",
+                          TaskCategory::Other,
+                          NewNonOwningRunnableMethod(this, &MediaResource::Destroy));
+  MOZ_ALWAYS_SUCCEEDS(rv);
 }
 
 NS_IMPL_ADDREF(MediaResource)
 NS_IMPL_RELEASE_WITH_DESTROY(MediaResource, Destroy())
 NS_IMPL_QUERY_INTERFACE0(MediaResource)
 
 ChannelMediaResource::ChannelMediaResource(MediaResourceCallback* aCallback,
                                            nsIChannel* aChannel,
@@ -180,19 +183,19 @@ ChannelMediaResource::OnStartRequest(nsI
       return NS_ERROR_DOM_BAD_URI;
     }
   }
 
   nsCOMPtr<nsIHttpChannel> hc = do_QueryInterface(aRequest);
   bool seekable = false;
   if (hc) {
     uint32_t responseStatus = 0;
-    hc->GetResponseStatus(&responseStatus);
+    Unused << hc->GetResponseStatus(&responseStatus);
     bool succeeded = false;
-    hc->GetRequestSucceeded(&succeeded);
+    Unused << hc->GetRequestSucceeded(&succeeded);
 
     if (!succeeded && NS_SUCCEEDED(status)) {
       // HTTP-level error (e.g. 4xx); treat this as a fatal network-level error.
       // We might get this on a seek.
       // (Note that lower-level errors indicated by NS_FAILED(status) are
       // handled in OnStopRequest.)
       // A 416 error should treated as EOF here... it's possible
       // that we don't get Content-Length, we read N bytes, then we
@@ -209,18 +212,18 @@ ChannelMediaResource::OnStartRequest(nsI
 
       // This disconnects our listener so we don't get any more data. We
       // certainly don't want an error page to end up in our cache!
       CloseChannel();
       return NS_OK;
     }
 
     nsAutoCString ranges;
-    hc->GetResponseHeader(NS_LITERAL_CSTRING("Accept-Ranges"),
-                          ranges);
+    Unused << hc->GetResponseHeader(NS_LITERAL_CSTRING("Accept-Ranges"),
+                                    ranges);
     bool acceptsRanges = ranges.EqualsLiteral("bytes");
     // True if this channel will not return an unbounded amount of data
     bool dataIsBounded = false;
 
     int64_t contentLength = -1;
     hc->GetContentLength(&contentLength);
     if (contentLength >= 0 &&
         (responseStatus == HTTP_OK_CODE ||
@@ -861,17 +864,20 @@ ChannelMediaResource::CacheClientNotifyD
   // block or do anything which might try to acquire a lock!
 
   if (mDataReceivedEvent.IsPending())
     return;
 
   mDataReceivedEvent =
     NewNonOwningRunnableMethod("ChannelMediaResource::DoNotifyDataReceived",
                                this, &ChannelMediaResource::DoNotifyDataReceived);
-  NS_DispatchToMainThread(mDataReceivedEvent.get());
+
+  nsCOMPtr<nsIRunnable> event = mDataReceivedEvent.get();
+
+  SystemGroup::AbstractMainThreadFor(TaskCategory::Other)->Dispatch(event.forget());
 }
 
 void
 ChannelMediaResource::CacheClientNotifyDataEnded(nsresult aStatus)
 {
   MOZ_ASSERT(NS_IsMainThread());
   mCallback->NotifyDataEnded(aStatus);
 }
--- a/dom/media/android/AndroidMediaPluginHost.cpp
+++ b/dom/media/android/AndroidMediaPluginHost.cpp
@@ -5,17 +5,16 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 #include "mozilla/Preferences.h"
 #include "MediaContainerType.h"
 #include "MediaResource.h"
 #include "mozilla/dom/HTMLMediaElement.h"
 #include "mozilla/Services.h"
 #include "AndroidMediaPluginHost.h"
 #include "nsAutoPtr.h"
-#include "nsXPCOMStrings.h"
 #include "nsISeekableStream.h"
 #include "nsIGfxInfo.h"
 #include "gfxCrashReporterUtils.h"
 #include "prmem.h"
 #include "prlink.h"
 #include "AndroidMediaResourceServer.h"
 #include "nsServiceManagerUtils.h"
 
@@ -225,18 +224,18 @@ AndroidMediaPluginHost::AndroidMediaPlug
 AndroidMediaPluginHost::~AndroidMediaPluginHost() {
   mResourceServer->Stop();
   MOZ_COUNT_DTOR(AndroidMediaPluginHost);
 }
 
 bool AndroidMediaPluginHost::FindDecoder(const MediaContainerType& aMimeType,
                                          MediaCodecs* aCodecs)
 {
-  const char *chars;
-  size_t len = NS_CStringGetData(aMimeType.Type().AsString(), &chars, nullptr);
+  const char *chars = aMimeType.Type().AsString().BeginReading();
+  size_t len = aMimeType.Type().AsString().Length();
   for (size_t n = 0; n < mPlugins.Length(); ++n) {
     Manifest *plugin = mPlugins[n];
     const char* const *codecs;
     if (plugin->CanDecode(chars, len, &codecs)) {
       if (aCodecs) {
         nsString codecsString;
         for (const char* const* codec = codecs; *codec; ++codec) {
           if (codecsString.IsEmpty()) {
@@ -257,18 +256,18 @@ MPAPI::Decoder *AndroidMediaPluginHost::
 {
   NS_ENSURE_TRUE(aResource, nullptr);
 
   nsAutoPtr<Decoder> decoder(new Decoder());
   if (!decoder) {
     return nullptr;
   }
 
-  const char *chars;
-  size_t len = NS_CStringGetData(aMimeType.Type().AsString(), &chars, nullptr);
+  const char *chars = aMimeType.Type().AsString().BeginReading();
+  size_t len = aMimeType.Type().AsString().Length();
   for (size_t n = 0; n < mPlugins.Length(); ++n) {
     Manifest *plugin = mPlugins[n];
     const char* const *codecs;
     if (!plugin->CanDecode(chars, len, &codecs)) {
       continue;
     }
 
     nsCString url;
--- a/dom/media/gmp/GMPPlatform.cpp
+++ b/dom/media/gmp/GMPPlatform.cpp
@@ -5,16 +5,17 @@
 
 #include "GMPPlatform.h"
 #include "GMPStorageChild.h"
 #include "GMPTimerChild.h"
 #include "mozilla/Monitor.h"
 #include "GMPChild.h"
 #include "mozilla/Mutex.h"
 #include "base/thread.h"
+#include "base/time.h"
 #include "mozilla/ReentrantMonitor.h"
 
 #include <ctime>
 
 namespace mozilla {
 namespace gmp {
 
 static MessageLoop* sMainLoop = nullptr;
@@ -215,18 +216,21 @@ SetTimerOnMainThread(GMPTask* aTask, int
   GMPTimerChild* timers = sChild->GetGMPTimers();
   NS_ENSURE_TRUE(timers, GMPGenericErr);
   return timers->SetTimer(aTask, aTimeoutMS);
 }
 
 GMPErr
 GetClock(GMPTimestamp* aOutTime)
 {
-  *aOutTime = time(0) * 1000;
-  return GMPNoErr;
+  if (!aOutTime) {
+    return GMPGenericErr;
+  }
+  *aOutTime = base::Time::Now().ToDoubleT() * 1000.0;
+ return GMPNoErr;
 }
 
 void
 InitPlatformAPI(GMPPlatformAPI& aPlatformAPI, GMPChild* aChild)
 {
   if (!sMainLoop) {
     sMainLoop = MessageLoop::current();
   }
--- a/dom/media/platforms/wrappers/H264Converter.cpp
+++ b/dom/media/platforms/wrappers/H264Converter.cpp
@@ -313,35 +313,34 @@ H264Converter::CheckForSPSChange(MediaRa
   RefPtr<MediaByteBuffer> extra_data =
     mp4_demuxer::AnnexB::ExtractExtraData(aSample);
   if (!mp4_demuxer::AnnexB::HasSPS(extra_data)
       || mp4_demuxer::AnnexB::CompareExtraData(extra_data,
                                                mCurrentConfig.mExtraData)) {
         return NS_OK;
       }
 
-  mPendingSample = aSample;
+  RefPtr<MediaRawData> sample = aSample;
 
   if (CanRecycleDecoder()) {
     // Do not recreate the decoder, reuse it.
     UpdateConfigFromExtraData(extra_data);
     // Ideally we would want to drain the decoder instead of flushing it.
     // However the draining operation requires calling Drain and looping several
     // times which isn't possible from within the H264Converter. So instead we
     // flush the decoder. In practice, this is a no-op as SPS change will only
     // be used with MSE. And with MSE, the MediaFormatReader would have drained
     // the decoder already.
     RefPtr<H264Converter> self = this;
     mDecoder->Flush()
       ->Then(AbstractThread::GetCurrent()->AsTaskQueue(),
              __func__,
-             [self, this]() {
+             [self, sample, this]() {
                mFlushRequest.Complete();
-               DecodeFirstSample(mPendingSample);
-               mPendingSample = nullptr;
+               DecodeFirstSample(sample);
              },
              [self, this](const MediaResult& aError) {
                mFlushRequest.Complete();
                mDecodePromise.Reject(aError, __func__);
              })
       ->Track(mFlushRequest);
     mNeedKeyframe = true;
     // This is not really initializing the decoder, but it will do as it
@@ -350,27 +349,26 @@ H264Converter::CheckForSPSChange(MediaRa
   }
 
   // The SPS has changed, signal to flush the current decoder and create a
   // new one.
   RefPtr<H264Converter> self = this;
   mDecoder->Flush()
     ->Then(AbstractThread::GetCurrent()->AsTaskQueue(),
            __func__,
-           [self, this]() {
+           [self, sample, this]() {
              mFlushRequest.Complete();
              mShutdownPromise = Shutdown();
              mShutdownPromise
                ->Then(AbstractThread::GetCurrent()->AsTaskQueue(),
                       __func__,
-                      [self, this]() {
+                      [self, sample, this]() {
                         mShutdownRequest.Complete();
                         mShutdownPromise = nullptr;
                         mNeedAVCC.reset();
-                        RefPtr<MediaRawData> sample = mPendingSample.forget();
                         nsresult rv = CreateDecoderAndInit(sample);
                         if (rv == NS_ERROR_DOM_MEDIA_INITIALIZING_DECODER) {
                           // All good so far, will continue later.
                           return;
                         }
                         MOZ_ASSERT(NS_FAILED(rv));
                         mDecodePromise.Reject(rv, __func__);
                         return;
--- a/dom/media/test/manifest.js
+++ b/dom/media/test/manifest.js
@@ -88,22 +88,21 @@ var gPlayedTests = [
   // See bug 1110922 comment 26.
   //{ name:"vbr.mp3", type:"audio/mpeg", duration:10.0 },
   { name:"bug495794.ogg", type:"audio/ogg", duration:0.3 },
 ];
 
 // Used by test_mozLoadFrom.  Need one test file per decoder backend, plus
 // anything for testing clone-specific bugs.
 var cloneKey = Math.floor(Math.random()*100000000);
-var gCloneTests = gSmallTests.concat([
-  { name:"bug520908.ogv", type:"video/ogg", duration:0.2 },
+var gCloneTests = [
   // short-video is more like 1s, so if you load this twice you'll get an unexpected duration
   { name:"dynamic_resource.sjs?key=" + cloneKey + "&res1=320x240.ogv&res2=short-video.ogv",
     type:"video/ogg", duration:0.266 },
-]);
+];
 
 // Used by test_play_twice.  Need one test file per decoder backend, plus
 // anything for testing bugs that occur when replying a played file.
 var gReplayTests = gSmallTests.concat([
   { name:"bug533822.ogg", type:"audio/ogg" },
 ]);
 
 // Used by test_paused_after_ended. Need one test file per decoder backend, plus
@@ -1607,16 +1606,22 @@ const DEBUG_TEST_LOOP_FOREVER = false;
 //      MediaTestManager.start(token) if it starts a test. The test object is
 //      guaranteed to be playable by our supported decoders; you don't need to
 //      check canPlayType.
 //   3. When your tests finishes, call MediaTestManager.finished(), passing
 //      the token back to the manager. The manager may either start the next run
 //      or end the mochitest if all the tests are done.
 function MediaTestManager() {
 
+  // Set a very large timeout to prevent Mochitest timeout.
+  // Instead MediaTestManager will manage timeout of each test.
+  SimpleTest.requestLongerTimeout(1000);
+
+  this.hasTimeout = false;
+
   // Return how many seconds elapsed since |begin|.
   function elapsedTime(begin) {
     var end = new Date();
     return (end.getTime() - begin.getTime()) / 1000;
   }
   // Sets up a MediaTestManager to runs through the 'tests' array, which needs
   // to be one of, or have the same fields as, the g*Test arrays of tests. Uses
   // the user supplied 'startTest' function to initialize the test. This
@@ -1630,16 +1635,17 @@ function MediaTestManager() {
     SimpleTest.info("Started " + this.startTime + " (" + this.startTime.getTime()/1000 + "s)");
     this.testNum = 0;
     this.tests = tests;
     this.startTest = startTest;
     this.tokens = [];
     this.isShutdown = false;
     this.numTestsRunning = 0;
     this.handlers = {};
+    this.timers = {};
 
     // Always wait for explicit finish.
     SimpleTest.waitForExplicitFinish();
     SpecialPowers.pushPrefEnv({'set': gTestPrefs}, (function() {
       this.nextTest();
     }).bind(this));
 
     SimpleTest.registerCleanupFunction(function() {
@@ -1656,31 +1662,46 @@ function MediaTestManager() {
   }
 
   // Registers that the test corresponding to 'token' has been started.
   // Don't call more than once per token.
   this.started = function(token, handler) {
     this.tokens.push(token);
     this.numTestsRunning++;
     this.handlers[token] = handler;
+
+    var onTimeout = function() {
+      this.hasTimeout = true;
+      ok(false, `${token} timed out!`);
+      this.finished(token);
+    }.bind(this);
+    // Default timeout to 180s for each test.
+    this.timers[token] = setTimeout(onTimeout, 180000);
+
     is(this.numTestsRunning, this.tokens.length,
        "[started " + token + " t=" + elapsedTime(this.startTime) + "] Length of array should match number of running tests");
   }
 
   // Registers that the test corresponding to 'token' has finished. Call when
   // you've finished your test. If all tests are complete this will finish the
   // run, otherwise it may start up the next run. It's ok to call multiple times
   // per token.
   this.finished = function(token) {
     var i = this.tokens.indexOf(token);
     if (i != -1) {
       // Remove the element from the list of running tests.
       this.tokens.splice(i, 1);
     }
 
+    if (this.timers[token]) {
+      // Cancel the timer when the test finishes.
+      clearTimeout(this.timers[token]);
+      this.timers[token] = null;
+    }
+
     info("[finished " + token + "] remaining= " + this.tokens);
     this.numTestsRunning--;
     is(this.numTestsRunning, this.tokens.length,
        "[finished " + token + " t=" + elapsedTime(this.startTime) + "] Length of array should match number of running tests");
     if (this.tokens.length < PARALLEL_TESTS) {
       this.nextTest();
     }
   }
@@ -1709,16 +1730,19 @@ function MediaTestManager() {
         !DEBUG_TEST_LOOP_FOREVER &&
         this.tokens.length == 0 &&
         !this.isShutdown)
     {
       this.isShutdown = true;
       if (this.onFinished) {
         this.onFinished();
       }
+      if (this.hasTimeout) {
+        dumpDebugInfo();
+      }
       var onCleanup = function() {
         var end = new Date();
         SimpleTest.info("Finished at " + end + " (" + (end.getTime() / 1000) + "s)");
         SimpleTest.info("Running time: " + elapsedTime(this.startTime) + "s");
         SimpleTest.finish();
       }.bind(this);
       mediaTestCleanup(onCleanup);
       return;
@@ -1743,23 +1767,25 @@ function mediaTestCleanup(callback) {
     SpecialPowers.exactGC(callback);
 }
 
 // B2G emulator and Android 2.3 are condidered slow platforms
 function isSlowPlatform() {
   return SpecialPowers.Services.appinfo.name == "B2G" || getAndroidVersion() == 10;
 }
 
+function dumpDebugInfo() {
+  for (var v of document.getElementsByTagName("video")) {
+    v.mozDumpDebugInfo();
+  }
+  for (var a of document.getElementsByTagName("audio")) {
+    a.mozDumpDebugInfo();
+  }
+}
+
 // Could be undefined in a page opened by the parent test page
 // like file_access_controls.html.
 if ("SimpleTest" in window) {
   SimpleTest.requestFlakyTimeout("untriaged");
 
   // Register timeout function to dump debugging logs.
-  SimpleTest.registerTimeoutFunction(function() {
-    for (var v of document.getElementsByTagName("video")) {
-      v.mozDumpDebugInfo();
-    }
-    for (var a of document.getElementsByTagName("audio")) {
-      a.mozDumpDebugInfo();
-    }
-  });
+  SimpleTest.registerTimeoutFunction(dumpDebugInfo);
 }
--- a/dom/media/test/test_bug495145.html
+++ b/dom/media/test/test_bug495145.html
@@ -10,20 +10,16 @@ https://bugzilla.mozilla.org/show_bug.cg
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
   <script type="text/javascript" src="manifest.js"></script>
 
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=495145">Mozilla Bug 495145</a>
 <pre id="test">
 <script class="testbody" type="text/javascript">
-//longer timeout for slow platforms
-if (isSlowPlatform()) {
-  SimpleTest.requestLongerTimeout(1.5);
-}
 
 var manager = new MediaTestManager;
 
 function start(e) {
   e.target.play();
 }
 
 function ended1(e) {
--- a/dom/media/test/test_bug879717.html
+++ b/dom/media/test/test_bug879717.html
@@ -4,20 +4,16 @@
   <title>Test for bug 879717, check that a video element can be drawn into a canvas at various states of playback</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
   <script type="text/javascript" src="manifest.js"></script>
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
-//longer timeout for slow platforms
-if (isSlowPlatform()) {
-  SimpleTest.requestLongerTimeout(1.5);
-}
 
 var manager = new MediaTestManager;
 
 var canvas = document.createElement('canvas');
 document.body.appendChild(canvas);
 
 var checkDrawImage = function(eventName, videoElement) {
   var exception = null;
--- a/dom/media/test/test_fragment_noplay.html
+++ b/dom/media/test/test_fragment_noplay.html
@@ -7,21 +7,16 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
   <script type="text/javascript" src="manifest.js"></script>
   <script type="text/javascript" src="fragment_noplay.js"></script>
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
-//longer timeout for slow platforms
-if (isSlowPlatform()) {
-  SimpleTest.requestLongerTimeout(1.5);
-}
-
 var manager = new MediaTestManager;
 
 // Fragment parameters to try
 var gFragmentParams = [
   // W3C Media fragment tests
   // http://www.w3.org/2008/WebVideo/Fragments/TC/ua-test-cases
   { fragment: "#t=banana", start: null, end: null }, // TC0027-UA
   { fragment: "#t=3,banana", start: null, end: null }, // TC0028-UA
--- a/dom/media/test/test_load_same_resource.html
+++ b/dom/media/test/test_load_same_resource.html
@@ -9,92 +9,84 @@
 <body>
 
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 SimpleTest.requestCompleteLog();
 var manager = new MediaTestManager;
 
-function cloneLoaded(event) {
-  ok(true, "Clone loaded OK");
-  var e = event.target;
+function checkDuration(actual, expected, name) {
+  ok(Math.abs(actual - expected) < 0.1,
+     `${name} duration: ${actual} expected: ${expected}`);
+}
 
-  if (e._expectedDuration) {
-    ok(Math.abs(e.duration - e._expectedDuration) < 0.1,
-       "Clone " + e.currentSrc + " duration: " + e.duration + " expected: " + e._expectedDuration);
-  }
-
-  e.removeEventListener("loadeddata", cloneLoaded);
+function cloneLoaded(event) {
+  var e = event.target;
+  ok(true, `${e.token} loaded OK`);
+  checkDuration(e.duration, e._expectedDuration, e.token);
   removeNodeAndSource(e);
   manager.finished(e.token);
 }
 
 function tryClone(event) {
   var e = event.target;
   var clone = e.cloneNode(false);
-  clone.token = e.token;
+  clone.token = `${e.token}(cloned)`;
+  manager.started(clone.token);
+  manager.finished(e.token);
 
   // Log events for debugging.
   var events = ["suspend", "play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
                 "loadeddata", "playing", "ended", "error", "stalled", "emptied", "abort",
                 "waiting", "pause"];
   function logEvent(evt) {
     var e = evt.target;
-    info(e.token + ": got " + evt.type);
+    info(`${e.token} got ${evt.type}`);
   }
   events.forEach(function(e) {
     clone.addEventListener(e, logEvent);
   });
 
 
-  if (e._expectedDuration) {
-    ok(Math.abs(e.duration - e._expectedDuration) < 0.1,
-       e.currentSrc + " duration: " + e.duration + " expected: " + e._expectedDuration);
-    clone._expectedDuration = e._expectedDuration;
-  }
+  checkDuration(e.duration, e._expectedDuration, e.token);
+  clone._expectedDuration = e._expectedDuration;
 
-  clone.addEventListener("loadeddata", cloneLoaded);
-  clone.onloadstart = function(evt) {
-    info("cloned " + evt.target.token + " start loading.");
-    evt.target.onloadstart = null;
+  clone.addEventListener("loadeddata", cloneLoaded, {once: true});
+  clone.addEventListener("loadstart", function(evt) {
+    info(`${evt.target.token} starts loading.`);
     // Since there is only one H264 decoder instance, we have to delete the
     // decoder of the original element for the cloned element to load. However,
     // we can't delete the decoder too early otherwise cloning decoder will
     // fail to kick in. We wait for 'loadstart' event of the cloned element to
     // know when the decoder is already cloned and we can delete the decoder of
     // the original element.
     removeNodeAndSource(e);
-  }
-
-  e.removeEventListener("loadeddata", tryClone);
+  }, {once: true});
 }
 
 // This test checks that loading the same URI twice in different elements at the same time
 // uses the same resource without doing another network fetch. One of the gCloneTests
 // uses dynamic_resource.sjs to return one resource on the first fetch and a different resource
 // on the second fetch. These resources have different lengths, so if the cloned element
 // does a network fetch it will get a resource with the wrong length and we get a test
 // failure.
 
 function initTest(test, token) {
-  var elemType = /^audio/.test(test.type) ? "audio" : "video";
-  var e = document.createElement(elemType);
+  var e = document.createElement("video");
   e.preload = "auto";
-  if (e.canPlayType(test.type)) {
-    e.src = test.name;
-    if (test.duration) {
-      e._expectedDuration = test.duration;
-    }
-    ok(true, "Trying to load " + test.name);
-    e.addEventListener("loadeddata", tryClone);
-    e.load();
-    e.token = token;
-    manager.started(token);
-  }
+  e.src = test.name;
+  e._expectedDuration = test.duration;
+  ok(true, `Trying to load ${test.name}, duration=${test.duration}`);
+  e.addEventListener("loadeddata", tryClone, {once: true});
+  e.token = token;
+  manager.started(token);
 }
 
-manager.runTests(gCloneTests, initTest);
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv(
+  {"set": [["logging.MediaDecoder", "Debug"]]},
+  manager.runTests.bind(manager, gCloneTests, initTest));
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/test/test_loop.html
+++ b/dom/media/test/test_loop.html
@@ -4,20 +4,16 @@
   <title>Test looping support</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
   <script type="text/javascript" src="manifest.js"></script>
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
-//longer timeout for slow platforms
-if (isSlowPlatform()) {
-  SimpleTest.requestLongerTimeout(2);
-}
 
 var manager = new MediaTestManager;
 
 function startTest(test, token) {
   manager.started(token);
   var v = document.createElement('video');
   v.token = token;
   v.src = test.name;
--- a/dom/media/test/test_media_selection.html
+++ b/dom/media/test/test_media_selection.html
@@ -4,20 +4,16 @@
   <title>Media test: media selection</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
   <script type="application/javascript" src="manifest.js"></script>
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
-//longer timeout for sometimes B2G emulator runs very slowly
-if (SpecialPowers.Services.appinfo.name == "B2G") {
-  SimpleTest.requestLongerTimeout(3);
-}
 
 var manager = new MediaTestManager;
 
 function maketest(attach_media, name, type, check_metadata) {
   return function (token) {
     var e = document.createElement('video');
     e.preload = "metadata";
     token = name + "-" + token;
--- a/dom/media/test/test_playback.html
+++ b/dom/media/test/test_playback.html
@@ -5,22 +5,16 @@
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
   <script type="text/javascript" src="manifest.js"></script>
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
-// longer timeout for slow platforms
-if (isSlowPlatform()) {
-  SimpleTest.requestLongerTimeout(3);
-  SimpleTest.requestCompleteLog();
-}
-
 var manager = new MediaTestManager;
 
 function startTest(test, token) {
   var v = document.createElement('video');
   v.preload = "metadata";
   v.token = token;
   v.prevTime = 0;
   v.seenEnded = false;
--- a/dom/media/test/test_playback_reactivate.html
+++ b/dom/media/test/test_playback_reactivate.html
@@ -12,22 +12,16 @@
 
 /* This testcase wants to test a video element's playback is not break
    by dormant.
    When the metadata is loaded, we remove the video element to trigger dormant.
    Then set a timer to append the video element back and play it.
    Test pass if the video plays to the end.
 */
 
-// longer timeout for slow platforms
-if (isSlowPlatform()) {
-  SimpleTest.requestLongerTimeout(1.5);
-  SimpleTest.requestCompleteLog();
-}
-
 var manager = new MediaTestManager;
 
 function startTest(test, token) {
   var v = document.createElement('video');
   v.preload = "metadata";
   v.token = token;
 
   var handler = {
--- a/dom/media/test/test_played.html
+++ b/dom/media/test/test_played.html
@@ -5,22 +5,17 @@
 <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 <script type="text/javascript" src="manifest.js"></script>
 </head>
 <body>
 <pre id='test'>
 <script class="testbody" type='application/javascript'>
-//longer timeout for sometimes B2G emulator runs very slowly
-if (SpecialPowers.Services.appinfo.name == "B2G") {
-  SimpleTest.requestLongerTimeout(3);
-}
 
-SimpleTest.requestCompleteLog();
 let manager = new MediaTestManager;
 
 function finish_test(element) {
   removeNodeAndSource(element);
   manager.finished(element.token);
 }
 
 // Check that a file has been played in its entirety.
--- a/dom/media/tests/mochitest/pc.js
+++ b/dom/media/tests/mochitest/pc.js
@@ -1884,16 +1884,17 @@ PeerConnectionWrapper.prototype = {
   }
 };
 
 // haxx to prevent SimpleTest from failing at window.onload
 function addLoadEvent() {}
 
 var scriptsReady = Promise.all([
   "/tests/SimpleTest/SimpleTest.js",
+  "../../test/manifest.js",
   "head.js",
   "templates.js",
   "turnConfig.js",
   "dataChannel.js",
   "network.js",
   "sdpUtils.js"
 ].map(script  => {
   var el = document.createElement("script");
--- a/dom/media/tests/mochitest/test_peerConnection_capturedVideo.html
+++ b/dom/media/tests/mochitest/test_peerConnection_capturedVideo.html
@@ -1,39 +1,39 @@
-<!DOCTYPE HTML>
+<!DOCTYPE HTML>
 <html>
 <head>
   <script type="application/javascript" src="pc.js"></script>
-  <script type="text/javascript" src="../../test/manifest.js"></script>
 </head>
 <body>
 <pre id="test">
 <script type="application/javascript">
-var manager = new MediaTestManager;
 
 createHTML({
   bug: "1081409",
   title: "Captured video-only over peer connection",
   visible: true
 }).then(() => new Promise(resolve => {
+  // Run tests in sequence for log readability.
+  PARALLEL_TESTS = 1;
+  let manager = new MediaTestManager;
+  window.mediaTestManager = manager;
   manager.runTests(getPlayableVideos(gLongerTests), startTest);
   manager.onFinished = () => {
     // Tear down before SimpleTest.finish.
     if ("nsINetworkInterfaceListService" in SpecialPowers.Ci) {
       getNetworkUtils().tearDownNetwork();
     }
     resolve();
   };
 }))
 .catch(e => ok(false, "Unexpected " + e + ":\n" + e.stack));
 
-// Run tests in sequence for log readability.
-PARALLEL_TESTS = 1;
-
 function startTest(media, token) {
+  let manager = window.mediaTestManager;
   manager.started(token);
   var video = document.createElement('video');
   video.id = "id_" + media.name;
   video.width = 160;
   video.height = 120;
   video.muted = true;
   video.loop = true;
   video.preload = "metadata";
--- a/dom/media/webspeech/recognition/SpeechGrammarList.cpp
+++ b/dom/media/webspeech/recognition/SpeechGrammarList.cpp
@@ -4,17 +4,16 @@
  * 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 "SpeechGrammarList.h"
 
 #include "mozilla/dom/SpeechGrammarListBinding.h"
 #include "mozilla/ErrorResult.h"
 #include "nsCOMPtr.h"
-#include "nsXPCOMStrings.h"
 #include "SpeechRecognition.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SpeechGrammarList, mParent, mItems)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechGrammarList)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechGrammarList)
--- a/dom/performance/PerformanceMainThread.cpp
+++ b/dom/performance/PerformanceMainThread.cpp
@@ -149,40 +149,41 @@ PerformanceMainThread::AddEntry(nsIHttpC
             0);
 
     // The PerformanceResourceTiming object will use the PerformanceTiming
     // object to get all the required timings.
     RefPtr<PerformanceResourceTiming> performanceEntry =
       new PerformanceResourceTiming(performanceTiming, this, entryName);
 
     nsAutoCString protocol;
-    channel->GetProtocolVersion(protocol);
+    // Can be an empty string.
+    Unused << channel->GetProtocolVersion(protocol);
 
     // If this is a local fetch, nextHopProtocol should be set to empty string.
     nsCOMPtr<nsICacheInfoChannel> cachedChannel = do_QueryInterface(channel);
     if (cachedChannel) {
       bool isFromCache;
       if (NS_SUCCEEDED(cachedChannel->IsFromCache(&isFromCache))
           && isFromCache) {
         protocol.Truncate();
       }
     }
 
     performanceEntry->SetNextHopProtocol(NS_ConvertUTF8toUTF16(protocol));
 
     uint64_t encodedBodySize = 0;
-    channel->GetEncodedBodySize(&encodedBodySize);
+    Unused << channel->GetEncodedBodySize(&encodedBodySize);
     performanceEntry->SetEncodedBodySize(encodedBodySize);
 
     uint64_t transferSize = 0;
-    channel->GetTransferSize(&transferSize);
+    Unused << channel->GetTransferSize(&transferSize);
     performanceEntry->SetTransferSize(transferSize);
 
     uint64_t decodedBodySize = 0;
-    channel->GetDecodedBodySize(&decodedBodySize);
+    Unused << channel->GetDecodedBodySize(&decodedBodySize);
     if (decodedBodySize == 0) {
       decodedBodySize = encodedBodySize;
     }
     performanceEntry->SetDecodedBodySize(decodedBodySize);
 
     // If the initiator type had no valid value, then set it to the default
     // ("other") value.
     if (initiatorType.IsEmpty()) {
--- a/dom/plugins/base/nsPluginStreamListenerPeer.cpp
+++ b/dom/plugins/base/nsPluginStreamListenerPeer.cpp
@@ -772,17 +772,18 @@ nsPluginStreamListenerPeer::RequestRead(
 
   if (NS_FAILED(rv))
     return rv;
 
   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
   if (!httpChannel)
     return NS_ERROR_FAILURE;
 
-  httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Range"), rangeString, false);
+  rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Range"), rangeString, false);
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
 
   mAbort = true; // instruct old stream listener to cancel
   // the request on the next ODA.
 
   nsCOMPtr<nsIStreamListener> converter;
 
   if (numRequests == 1) {
     converter = this;
@@ -1169,17 +1170,18 @@ nsresult nsPluginStreamListenerPeer::Set
 
       // Assemble everything and pass to listener.
       nsPrintfCString status("HTTP%s %" PRIu32 " %s", ver.get(), statusNum,
                              statusText.get());
       static_cast<nsIHTTPHeaderListener*>(mPStreamListener)->StatusLine(status.get());
     }
 
     // Also provide all HTTP response headers to our listener.
-    httpChannel->VisitResponseHeaders(this);
+    rv = httpChannel->VisitResponseHeaders(this);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
 
     mSeekable = false;
     // first we look for a content-encoding header. If we find one, we tell the
     // plugin that stream is not seekable, because the plugin always sees
     // uncompressed data, so it can't make meaningful range requests on a
     // compressed entity.  Also, we force the plugin to use
     // nsPluginStreamType_AsFile stream type and we have to save decompressed
     // file into local plugin cache, because necko cache contains original
--- a/dom/security/nsCSPContext.cpp
+++ b/dom/security/nsCSPContext.cpp
@@ -995,17 +995,18 @@ nsCSPContext::SendReports(nsISupports* a
     }
 
     rv = uploadChannel->SetUploadStream(sis, NS_LITERAL_CSTRING("application/csp-report"), -1);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // if this is an HTTP channel, set the request method to post
     nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(reportChannel));
     if (httpChannel) {
-      httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
+      rv = httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
+      MOZ_ASSERT(NS_SUCCEEDED(rv));
     }
 
     RefPtr<CSPViolationReportListener> listener = new CSPViolationReportListener();
     rv = reportChannel->AsyncOpen2(listener);
 
     // AsyncOpen should not fail, but could if there's no load group (like if
     // SetRequestContext is not given a channel).  This should fail quietly and
     // not return an error since it's really ok if reports don't go out, but
--- a/dom/security/nsContentSecurityManager.cpp
+++ b/dom/security/nsContentSecurityManager.cpp
@@ -320,17 +320,18 @@ DoContentSecurityChecks(nsIChannel* aCha
 
     case nsIContentPolicy::TYPE_WEBSOCKET: {
       // Websockets have to use the proxied URI:
       // ws:// instead of http:// for CSP checks
       nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal
         = do_QueryInterface(aChannel);
       MOZ_ASSERT(httpChannelInternal);
       if (httpChannelInternal) {
-        httpChannelInternal->GetProxyURI(getter_AddRefs(uri));
+        rv = httpChannelInternal->GetProxyURI(getter_AddRefs(uri));
+        MOZ_ASSERT(NS_SUCCEEDED(rv));
       }
       mimeTypeGuess = EmptyCString();
       requestingContext = aLoadInfo->LoadingNode();
       break;
     }
 
     case nsIContentPolicy::TYPE_CSP_REPORT: {
       mimeTypeGuess = EmptyCString();
--- a/dom/system/gonk/NetworkManager.js
+++ b/dom/system/gonk/NetworkManager.js
@@ -955,17 +955,18 @@ NetworkManager.prototype = {
           aResolve(retval);
         };
 
         debug('Calling gDNSService.asyncResolveExtended: ' + aNetId + ', ' + aHostname);
         gDNSService.asyncResolveExtended(aHostname,
                                          0,
                                          aNetId,
                                          onLookupComplete,
-                                         Services.tm.mainThread);
+                                         Services.tm.mainThread,
+                                         {});
       });
     };
 
     // TODO: |getNetId| will be implemented as a sync call in nsINetworkManager
     //       once Bug 1141903 is landed.
     return gNetworkService.getNetId(aNetworkInfo.name)
       .then(aNetId => hostResolveWrapper(aNetId));
   },
--- a/dom/u2f/U2F.cpp
+++ b/dom/u2f/U2F.cpp
@@ -530,19 +530,17 @@ U2FRegisterRunnable::U2FRegisterRunnable
   // U2FRegisterCallback does not support threadsafe refcounting, and must be
   // used and destroyed on main.
   , mCallback(new nsMainThreadPtrHolder<U2FRegisterCallback>(aCallback))
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // The WebIDL dictionary types RegisterRequest and RegisteredKey cannot
   // be copied to this thread, so store them serialized.
-  for (size_t i = 0; i < aRegisterRequests.Length(); ++i) {
-    RegisterRequest req(aRegisterRequests[i]);
-
+  for (const RegisterRequest& req : aRegisterRequests) {
     // Check for required attributes
     if (!req.mChallenge.WasPassed() || !req.mVersion.WasPassed()) {
       continue;
     }
 
     LocalRegisterRequest localReq;
     localReq.mVersion = req.mVersion.Value();
     localReq.mChallenge = req.mChallenge.Value();
@@ -551,19 +549,17 @@ U2FRegisterRunnable::U2FRegisterRunnable
                                      localReq.mChallenge, localReq.mClientData);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       continue;
     }
 
     mRegisterRequests.AppendElement(localReq);
   }
 
-  for (size_t i = 0; i < aRegisteredKeys.Length(); ++i) {
-    RegisteredKey key(aRegisteredKeys[i]);
-
+  for (const RegisteredKey& key : aRegisteredKeys) {
     // Check for required attributes
     if (!key.mVersion.WasPassed() || !key.mKeyHandle.WasPassed()) {
       continue;
     }
 
     LocalRegisteredKey localKey;
     localKey.mVersion = key.mVersion.Value();
     localKey.mKeyHandle = key.mKeyHandle.Value();
@@ -619,20 +615,19 @@ U2FRegisterRunnable::Run()
   // Evaluate the AppID
   ErrorCode appIdResult = EvaluateAppID();
   if (appIdResult != ErrorCode::OK) {
     status->Stop(appIdResult);
   }
 
   // First, we must determine if any of the RegisteredKeys are already
   // registered, e.g., in the whitelist.
-  for (LocalRegisteredKey key: mRegisteredKeys) {
+  for (LocalRegisteredKey key : mRegisteredKeys) {
     nsTArray<RefPtr<U2FPrepPromise>> prepPromiseList;
-    for (size_t a = 0; a < mAuthenticators.Length(); ++a) {
-      Authenticator token(mAuthenticators[a]);
+    for (const Authenticator& token : mAuthenticators) {
       RefPtr<U2FIsRegisteredTask> compTask =
         new U2FIsRegisteredTask(token, key, mAbstractMainThread);
       prepPromiseList.AppendElement(compTask->Execute());
     }
 
     // Treat each call to Promise::All as a work unit, as it completes together
     status->WaitGroupAdd();
 
@@ -699,33 +694,32 @@ U2FRegisterRunnable::Run()
     }
 
     srv = PK11_HashBuf(SEC_OID_SHA256, challengeParam.Elements(),
                        req.mClientData.Elements(), req.mClientData.Length());
     if (srv != SECSuccess) {
       continue;
     }
 
-    for (size_t a = 0; a < mAuthenticators.Length(); ++a) {
-      Authenticator token(mAuthenticators[a]);
+    for (const Authenticator& token : mAuthenticators) {
       RefPtr<U2FRegisterTask> registerTask = new U2FRegisterTask(mOrigin, mAppId,
                                                                  token, appParam,
                                                                  challengeParam,
                                                                  req,
                                                                  mAbstractMainThread);
       status->WaitGroupAdd();
 
       registerTask->Execute()->Then(mAbstractMainThread, __func__,
-        [&status, this] (nsString aResponse) {
+        [&status] (nsString aResponse) {
           if (!status->IsStopped()) {
             status->Stop(ErrorCode::OK, aResponse);
           }
           status->WaitGroupDone();
         },
-        [&status, this] (ErrorCode aErrorCode) {
+        [&status] (ErrorCode aErrorCode) {
           // Ignore the failing error code, as we only want the first success.
           // U2F devices don't provide much for error codes anyway, so if
           // they all fail we'll return DEVICE_INELIGIBLE.
           status->WaitGroupDone();
      });
     }
   }
 
@@ -769,19 +763,17 @@ U2FSignRunnable::U2FSignRunnable(const n
   , mAuthenticators(aAuthenticators)
   // U2FSignCallback does not support threadsafe refcounting, and must be used
   // and destroyed on main.
   , mCallback(new nsMainThreadPtrHolder<U2FSignCallback>(aCallback))
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // Convert WebIDL objects to generic structs to pass between threads
-  for (size_t i = 0; i < aRegisteredKeys.Length(); ++i) {
-    RegisteredKey key(aRegisteredKeys[i]);
-
+  for (const RegisteredKey& key : aRegisteredKeys) {
     // Check for required attributes
     if (!key.mVersion.WasPassed() || !key.mKeyHandle.WasPassed()) {
       continue;
     }
 
     LocalRegisteredKey localKey;
     localKey.mVersion = key.mVersion.Value();
     localKey.mKeyHandle = key.mKeyHandle.Value();
@@ -884,34 +876,32 @@ U2FSignRunnable::Run()
     nsresult rv = keyHandle.FromJwkBase64(key.mKeyHandle);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       continue;
     }
 
     // We ignore mTransports, as it is intended to be used for sorting the
     // available devices by preference, but is not an exclusion factor.
 
-    for (size_t a = 0; a < mAuthenticators.Length() ; ++a) {
-      Authenticator token(mAuthenticators[a]);
-
+    for (const Authenticator& token : mAuthenticators) {
       RefPtr<U2FSignTask> signTask = new U2FSignTask(mOrigin, mAppId,
                                                      key.mVersion, token,
                                                      appParam, challengeParam,
                                                      mClientData, keyHandle,
                                                      mAbstractMainThread);
       status->WaitGroupAdd();
 
       signTask->Execute()->Then(mAbstractMainThread, __func__,
-        [&status, this] (nsString aResponse) {
+        [&status] (nsString aResponse) {
           if (!status->IsStopped()) {
             status->Stop(ErrorCode::OK, aResponse);
           }
           status->WaitGroupDone();
         },
-        [&status, this] (ErrorCode aErrorCode) {
+        [&status] (ErrorCode aErrorCode) {
           // Ignore the failing error code, as we only want the first success.
           // U2F devices don't provide much for error codes anyway, so if
           // they all fail we'll return DEVICE_INELIGIBLE.
           status->WaitGroupDone();
       });
     }
   }
 
--- a/dom/webbrowserpersist/nsWebBrowserPersist.cpp
+++ b/dom/webbrowserpersist/nsWebBrowserPersist.cpp
@@ -1381,28 +1381,31 @@ nsresult nsWebBrowserPersist::SaveURIInt
             encodedChannel->SetApplyConversion(false);
         }
     }
 
     if (mPersistFlags & PERSIST_FLAGS_FORCE_ALLOW_COOKIES)
     {
         nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal =
                 do_QueryInterface(inputChannel);
-        if (httpChannelInternal)
-            httpChannelInternal->SetThirdPartyFlags(nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW);
+        if (httpChannelInternal) {
+            rv = httpChannelInternal->SetThirdPartyFlags(nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW);
+            MOZ_ASSERT(NS_SUCCEEDED(rv));
+        }
     }
 
     // Set the referrer, post data and headers if any
     nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(inputChannel));
     if (httpChannel)
     {
         // Referrer
         if (aReferrer)
         {
-            httpChannel->SetReferrerWithPolicy(aReferrer, aReferrerPolicy);
+            rv = httpChannel->SetReferrerWithPolicy(aReferrer, aReferrerPolicy);
+            MOZ_ASSERT(NS_SUCCEEDED(rv));
         }
 
         // Post data
         if (aPostData)
         {
             nsCOMPtr<nsISeekableStream> stream(do_QueryInterface(aPostData));
             if (stream)
             {
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -1057,25 +1057,25 @@ private:
       bool requestSucceeded;
       rv = httpChannel->GetRequestSucceeded(&requestSucceeded);
       NS_ENSURE_SUCCESS(rv, rv);
 
       if (!requestSucceeded) {
         return NS_ERROR_NOT_AVAILABLE;
       }
 
-      httpChannel->GetResponseHeader(
+      Unused << httpChannel->GetResponseHeader(
         NS_LITERAL_CSTRING("content-security-policy"),
         tCspHeaderValue);
 
-      httpChannel->GetResponseHeader(
+      Unused << httpChannel->GetResponseHeader(
         NS_LITERAL_CSTRING("content-security-policy-report-only"),
         tCspROHeaderValue);
 
-      httpChannel->GetResponseHeader(
+      Unused << httpChannel->GetResponseHeader(
         NS_LITERAL_CSTRING("referrer-policy"),
         tRPHeaderCValue);
     }
 
     // May be null.
     nsIDocument* parentDoc = mWorkerPrivate->GetDocument();
 
     // Use the regular nsScriptLoader for this grunt work! Should be just fine
--- a/dom/workers/ServiceWorkerPrivate.cpp
+++ b/dom/workers/ServiceWorkerPrivate.cpp
@@ -1379,17 +1379,18 @@ public:
     mContentPolicyType = loadInfo->InternalContentPolicyType();
 
 
     nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
     MOZ_ASSERT(httpChannel, "How come we don't have an HTTP channel?");
 
     nsAutoCString referrer;
     // Ignore the return value since the Referer header may not exist.
-    httpChannel->GetRequestHeader(NS_LITERAL_CSTRING("Referer"), referrer);
+    Unused << httpChannel->GetRequestHeader(NS_LITERAL_CSTRING("Referer"),
+                                            referrer);
     if (!referrer.IsEmpty()) {
       mReferrer = referrer;
     } else {
       // If there's no referrer Header, means the header was omitted for
       // security/privacy reason.
       mReferrer = EmptyCString();
     }
 
@@ -1434,25 +1435,28 @@ public:
 
     nsCOMPtr<nsIHttpChannelInternal> internalChannel = do_QueryInterface(httpChannel);
     NS_ENSURE_TRUE(internalChannel, NS_ERROR_NOT_AVAILABLE);
 
     mRequestMode = InternalRequest::MapChannelToRequestMode(channel);
 
     // This is safe due to static_asserts in ServiceWorkerManager.cpp.
     uint32_t redirectMode;
-    internalChannel->GetRedirectMode(&redirectMode);
+    rv = internalChannel->GetRedirectMode(&redirectMode);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
     mRequestRedirect = static_cast<RequestRedirect>(redirectMode);
 
     // This is safe due to static_asserts in ServiceWorkerManager.cpp.
     uint32_t cacheMode;
-    internalChannel->GetFetchCacheMode(&cacheMode);
+    rv = internalChannel->GetFetchCacheMode(&cacheMode);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
     mCacheMode = static_cast<RequestCache>(cacheMode);
 
-    internalChannel->GetIntegrityMetadata(mIntegrity);
+    rv = internalChannel->GetIntegrityMetadata(mIntegrity);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
 
     mRequestCredentials = InternalRequest::MapChannelToRequestCredentials(channel);
 
     rv = httpChannel->VisitNonDefaultRequestHeaders(this);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(httpChannel);
     if (uploadChannel) {
--- a/dom/workers/ServiceWorkerScriptCache.cpp
+++ b/dom/workers/ServiceWorkerScriptCache.cpp
@@ -666,21 +666,23 @@ CompareNetwork::Initialize(nsIPrincipal*
                      flags);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel);
   if (httpChannel) {
     // Spec says no redirects allowed for SW scripts.
-    httpChannel->SetRedirectionLimit(0);
+    rv = httpChannel->SetRedirectionLimit(0);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
 
-    httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Service-Worker"),
-                                  NS_LITERAL_CSTRING("script"),
-                                  /* merge */ false);
+    rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Service-Worker"),
+                                       NS_LITERAL_CSTRING("script"),
+                                       /* merge */ false);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
   }
 
   nsCOMPtr<nsIStreamLoader> loader;
   rv = NS_NewStreamLoader(getter_AddRefs(loader), this, this);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
@@ -760,17 +762,17 @@ CompareNetwork::OnStreamComplete(nsIStre
     mManager->NetworkFinished(rv);
     return NS_OK;
   }
 
   if (NS_WARN_IF(!requestSucceeded)) {
     // Get the stringified numeric status code, not statusText which could be
     // something misleading like OK for a 404.
     uint32_t status = 0;
-    httpChannel->GetResponseStatus(&status); // don't care if this fails, use 0.
+    Unused << httpChannel->GetResponseStatus(&status); // don't care if this fails, use 0.
     nsAutoString statusAsText;
     statusAsText.AppendInt(status);
 
     RefPtr<ServiceWorkerRegistrationInfo> registration = mManager->GetRegistration();
     ServiceWorkerManager::LocalizeAndReportToAllClients(
       registration->mScope, "ServiceWorkerRegisterNetworkError",
       nsTArray<nsString> { NS_ConvertUTF8toUTF16(registration->mScope),
         statusAsText, mManager->URL() });
--- a/dom/xhr/XMLHttpRequestMainThread.cpp
+++ b/dom/xhr/XMLHttpRequestMainThread.cpp
@@ -1003,17 +1003,17 @@ XMLHttpRequestMainThread::GetStatusText(
   }
 
   if (mErrorLoad) {
     return;
   }
 
   nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel();
   if (httpChannel) {
-    httpChannel->GetResponseStatusText(aStatusText);
+    Unused << httpChannel->GetResponseStatusText(aStatusText);
   } else {
     aStatusText.AssignLiteral("OK");
   }
 }
 
 void
 XMLHttpRequestMainThread::CloseRequest()
 {
@@ -1174,17 +1174,17 @@ XMLHttpRequestMainThread::IsSafeHeader(c
   for (uint32_t i = 0; i < ArrayLength(kCrossOriginSafeHeaders); ++i) {
     if (aHeader.LowerCaseEqualsASCII(kCrossOriginSafeHeaders[i])) {
       return true;
     }
   }
   nsAutoCString headerVal;
   // The "Access-Control-Expose-Headers" header contains a comma separated
   // list of method names.
-  aHttpChannel->
+  Unused << aHttpChannel->
       GetResponseHeader(NS_LITERAL_CSTRING("Access-Control-Expose-Headers"),
                         headerVal);
   nsCCharSeparatedTokenizer exposeTokens(headerVal, ',');
   bool isSafe = false;
   while (exposeTokens.hasMoreTokens()) {
     const nsDependentCSubstring& token = exposeTokens.nextToken();
     if (token.IsEmpty()) {
       continue;
@@ -1626,17 +1626,18 @@ XMLHttpRequestMainThread::PopulateNetwor
 {
   if (mNetworkInterfaceId.IsEmpty()) {
     return;
   }
   nsCOMPtr<nsIHttpChannelInternal> channel(do_QueryInterface(mChannel));
   if (!channel) {
     return;
   }
-  channel->SetNetworkInterfaceId(mNetworkInterfaceId);
+  DebugOnly<nsresult> rv = channel->SetNetworkInterfaceId(mNetworkInterfaceId);
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
 }
 
 /*
  * "Copy" from a stream.
  */
 nsresult
 XMLHttpRequestMainThread::StreamReaderFunc(nsIInputStream* in,
                                            void* closure,
@@ -2019,17 +2020,18 @@ XMLHttpRequestMainThread::OnStartRequest
   }
 
   // Set up responseXML
   bool parseBody = mResponseType == XMLHttpRequestResponseType::_empty ||
                    mResponseType == XMLHttpRequestResponseType::Document;
   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel));
   if (parseBody && httpChannel) {
     nsAutoCString method;
-    httpChannel->GetRequestMethod(method);
+    rv = httpChannel->GetRequestMethod(method);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
     parseBody = !method.EqualsLiteral("HEAD");
   }
 
   mIsHtml = false;
   mWarnAboutSyncHtml = false;
   if (parseBody && NS_SUCCEEDED(status)) {
     // We can gain a huge performance win by not even trying to
     // parse non-XML data. This also protects us from the situation
@@ -2622,17 +2624,18 @@ XMLHttpRequestMainThread::InitiateFetch(
         if (aUploadContentType.IsEmpty()) {
           aUploadContentType.AssignLiteral("application/octet-stream");
         }
         nsCOMPtr<nsIUploadChannel> uploadChannel =
           do_QueryInterface(httpChannel);
         uploadChannel->SetUploadStream(aUploadStream, aUploadContentType,
                                        mUploadTotal);
         // Reset the method to its original value
-        httpChannel->SetRequestMethod(mRequestMethod);
+        rv = httpChannel->SetRequestMethod(mRequestMethod);
+        MOZ_ASSERT(NS_SUCCEEDED(rv));
       }
     }
   }
 
   // Due to the chrome-only XHR.channel API, we need a hacky way to set the
   // SEC_COOKIES_INCLUDE *after* the channel has been has been created, since
   // .withCredentials can be called after open() is called.
   // Not doing this for privileged system XHRs since those don't use CORS.
@@ -2649,17 +2652,18 @@ XMLHttpRequestMainThread::InitiateFetch(
   if (cos) {
     cos->AddClassFlags(nsIClassOfService::Unblocked);
   }
 
   // Disable Necko-internal response timeouts.
   nsCOMPtr<nsIHttpChannelInternal>
     internalHttpChannel(do_QueryInterface(mChannel));
   if (internalHttpChannel) {
-    internalHttpChannel->SetResponseTimeoutEnabled(false);
+    rv = internalHttpChannel->SetResponseTimeoutEnabled(false);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
   }
 
   if (!mIsAnon) {
     AddLoadFlags(mChannel, nsIChannel::LOAD_EXPLICIT_CREDENTIALS);
   }
 
   // Bypass the network cache in cases where it makes no sense:
   // POST responses are always unique, and we provide no API that would
@@ -4107,19 +4111,23 @@ RequestHeaders::Clear()
   mHeaders.Clear();
 }
 
 void
 RequestHeaders::ApplyToChannel(nsIHttpChannel* aHttpChannel) const
 {
   for (const RequestHeader& header : mHeaders) {
     if (header.mValue.IsEmpty()) {
-      aHttpChannel->SetEmptyRequestHeader(header.mName);
+      DebugOnly<nsresult> rv =
+        aHttpChannel->SetEmptyRequestHeader(header.mName);
+      MOZ_ASSERT(NS_SUCCEEDED(rv));
     } else {
-      aHttpChannel->SetRequestHeader(header.mName, header.mValue, false);
+      DebugOnly<nsresult> rv =
+        aHttpChannel->SetRequestHeader(header.mName, header.mValue, false);
+      MOZ_ASSERT(NS_SUCCEEDED(rv));
     }
   }
 }
 
 void
 RequestHeaders::GetCORSUnsafeHeaders(nsTArray<nsCString>& aArray) const
 {
   static const char *kCrossOriginSafeHeaders[] = {
--- a/dom/xml/XMLDocument.cpp
+++ b/dom/xml/XMLDocument.cpp
@@ -422,17 +422,18 @@ XMLDocument::Load(const nsAString& aUrl,
     return false;
   }
 
   // TODO Bug 1189945: Remove nsIChannel CorsMode flag and set Request.mode
   // based on nsILoadInfo securityFlags instead. This block will be removed
   // when Request.mode set correctly.
   nsCOMPtr<nsIHttpChannelInternal> httpChannel = do_QueryInterface(channel);
   if (httpChannel) {
-    httpChannel->SetCorsMode(nsIHttpChannelInternal::CORS_MODE_SAME_ORIGIN);
+    rv = httpChannel->SetCorsMode(nsIHttpChannelInternal::CORS_MODE_SAME_ORIGIN);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
   }
 
   // StartDocumentLoad asserts that readyState is uninitialized, so
   // uninitialize it. SetReadyStateInternal make this transition invisible to
   // Web content. But before doing that, assert that the current readyState
   // is complete as it should be after the call to ResetToURI() above.
   MOZ_ASSERT(GetReadyStateEnum() == nsIDocument::READYSTATE_COMPLETE,
              "Bad readyState");
--- a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
+++ b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
@@ -303,17 +303,17 @@ txStylesheetSink::OnStartRequest(nsIRequ
 NS_IMETHODIMP
 txStylesheetSink::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext,
                                 nsresult aStatusCode)
 {
     bool success = true;
 
     nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest);
     if (httpChannel) {
-        httpChannel->GetRequestSucceeded(&success);
+        Unused << httpChannel->GetRequestSucceeded(&success);
     }
 
     nsresult result = aStatusCode;
     if (!success) {
         // XXX We sometimes want to use aStatusCode here, but the parser resets
         //     it to NS_ERROR_NOINTERFACE because we don't implement
         //     nsIHTMLContentSink.
         result = NS_ERROR_XSLT_NETWORK_ERROR;
@@ -457,24 +457,27 @@ txCompileObserver::startLoad(nsIURI* aUr
                     loadGroup);
 
     NS_ENSURE_SUCCESS(rv, rv);
 
     channel->SetContentType(NS_LITERAL_CSTRING("text/xml"));
 
     nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
     if (httpChannel) {
-        httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
-                                      NS_LITERAL_CSTRING("*/*"),
-                                      false);
+        DebugOnly<nsresult> rv;
+        rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
+                                           NS_LITERAL_CSTRING("*/*"),
+                                           false);
+        MOZ_ASSERT(NS_SUCCEEDED(rv));
 
         nsCOMPtr<nsIURI> referrerURI;
         aReferrerPrincipal->GetURI(getter_AddRefs(referrerURI));
         if (referrerURI) {
-            httpChannel->SetReferrerWithPolicy(referrerURI, aReferrerPolicy);
+            rv = httpChannel->SetReferrerWithPolicy(referrerURI, aReferrerPolicy);
+            MOZ_ASSERT(NS_SUCCEEDED(rv));
         }
     }
 
     nsCOMPtr<nsIParser> parser = do_CreateInstance(kCParserCID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
     RefPtr<txStylesheetSink> sink = new txStylesheetSink(aCompiler, parser);
     NS_ENSURE_TRUE(sink, NS_ERROR_OUT_OF_MEMORY);
--- a/dom/xul/nsXULPrototypeCache.cpp
+++ b/dom/xul/nsXULPrototypeCache.cpp
@@ -184,27 +184,36 @@ nsXULPrototypeCache::PutPrototype(nsXULP
     aDocument->GetURI()->CloneIgnoringRef(getter_AddRefs(uri));
 
     // Put() releases any old value and addrefs the new one
     mPrototypeTable.Put(uri, aDocument);
 
     return NS_OK;
 }
 
+mozilla::StyleSheet*
+nsXULPrototypeCache::GetStyleSheet(nsIURI* aURI,
+                                   StyleBackendType aType)
+{
+    StyleSheetTable& table = TableForBackendType(aType);
+    return table.GetWeak(aURI);
+}
+
 nsresult
-nsXULPrototypeCache::PutStyleSheet(StyleSheet* aStyleSheet)
+nsXULPrototypeCache::PutStyleSheet(StyleSheet* aStyleSheet,
+                                   StyleBackendType aType)
 {
     nsIURI* uri = aStyleSheet->GetSheetURI();
 
-    mStyleSheetTable.Put(uri, aStyleSheet);
+    StyleSheetTable& table = TableForBackendType(aType);
+    table.Put(uri, aStyleSheet);
 
     return NS_OK;
 }
 
-
 JSScript*
 nsXULPrototypeCache::GetScript(nsIURI* aURI)
 {
     return mScriptTable.Get(aURI);
 }
 
 nsresult
 nsXULPrototypeCache::PutScript(nsIURI* aURI,
@@ -249,21 +258,26 @@ nsXULPrototypeCache::FlushSkinFiles()
     nsAutoCString str;
     iter.Key()->GetPath(str);
     if (strncmp(str.get(), "/skin", 5) == 0) {
       iter.Remove();
     }
   }
 
   // Now flush out our skin stylesheets from the cache.
-  for (auto iter = mStyleSheetTable.Iter(); !iter.Done(); iter.Next()) {
-    nsAutoCString str;
-    iter.Data()->GetSheetURI()->GetPath(str);
-    if (strncmp(str.get(), "/skin", 5) == 0) {
-      iter.Remove();
+  mozilla::StyleBackendType tableTypes[] = { StyleBackendType::Gecko,
+                                             StyleBackendType::Servo };
+  for (auto tableType : tableTypes) {
+    StyleSheetTable& table = TableForBackendType(tableType);
+    for (auto iter = table.Iter(); !iter.Done(); iter.Next()) {
+      nsAutoCString str;
+      iter.Data()->GetSheetURI()->GetPath(str);
+      if (strncmp(str.get(), "/skin", 5) == 0) {
+        iter.Remove();
+      }
     }
   }
 
   // Iterate over all the remaining XBL and make sure cached
   // scoped skin stylesheets are flushed and refetched by the
   // prototype bindings.
   for (auto iter = mXBLDocTable.Iter(); !iter.Done(); iter.Next()) {
     iter.Data()->FlushSkinStylesheets();
@@ -276,17 +290,18 @@ nsXULPrototypeCache::FlushScripts()
     mScriptTable.Clear();
 }
 
 void
 nsXULPrototypeCache::Flush()
 {
     mPrototypeTable.Clear();
     mScriptTable.Clear();
-    mStyleSheetTable.Clear();
+    mGeckoStyleSheetTable.Clear();
+    mServoStyleSheetTable.Clear();
     mXBLDocTable.Clear();
 }
 
 
 bool
 nsXULPrototypeCache::IsEnabled()
 {
     return !gDisableXULCache;
--- a/dom/xul/nsXULPrototypeCache.h
+++ b/dom/xul/nsXULPrototypeCache.h
@@ -69,25 +69,25 @@ public:
         return mXBLDocTable.GetWeak(aURL);
     }
     nsresult PutXBLDocumentInfo(nsXBLDocumentInfo* aDocumentInfo);
 
     /**
      * Get a style sheet by URI. If the style sheet is not in the cache,
      * returns nullptr.
      */
-    mozilla::StyleSheet* GetStyleSheet(nsIURI* aURI) {
-        return mStyleSheetTable.GetWeak(aURI);
-    }
+    mozilla::StyleSheet* GetStyleSheet(nsIURI* aURI,
+                                       mozilla::StyleBackendType aType);
 
     /**
      * Store a style sheet in the cache. The key, style sheet's URI is obtained
      * from the style sheet itself.
      */
-    nsresult PutStyleSheet(mozilla::StyleSheet* aStyleSheet);
+    nsresult PutStyleSheet(mozilla::StyleSheet* aStyleSheet,
+                           mozilla::StyleBackendType aType);
 
     /**
      * Write the XUL prototype document to a cache file. The proto must be
      * fully loaded.
      */
     nsresult WritePrototype(nsXULPrototypeDocument* aPrototypeDocument);
 
     /**
@@ -117,18 +117,25 @@ protected:
 
     nsXULPrototypeCache();
     virtual ~nsXULPrototypeCache();
 
     static nsXULPrototypeCache* sInstance;
 
     void FlushSkinFiles();
 
+    typedef nsRefPtrHashtable<nsURIHashKey, mozilla::StyleSheet> StyleSheetTable;
+    StyleSheetTable& TableForBackendType(mozilla::StyleBackendType aType) {
+      return aType == mozilla::StyleBackendType::Gecko ? mGeckoStyleSheetTable
+                                                       : mServoStyleSheetTable;
+    }
+
     nsRefPtrHashtable<nsURIHashKey,nsXULPrototypeDocument>   mPrototypeTable; // owns the prototypes
-    nsRefPtrHashtable<nsURIHashKey,mozilla::StyleSheet>      mStyleSheetTable;
+    StyleSheetTable                                          mGeckoStyleSheetTable;
+    StyleSheetTable                                          mServoStyleSheetTable;
     nsJSThingHashtable<nsURIHashKey, JSScript*>              mScriptTable;
     nsRefPtrHashtable<nsURIHashKey,nsXBLDocumentInfo>        mXBLDocTable;
 
     // URIs already written to the startup cache, to prevent double-caching.
     nsTHashtable<nsURIHashKey>                               mStartupCacheURITable;
 
     nsInterfaceHashtable<nsURIHashKey, nsIStorageStream>     mOutputStreamTable;
     nsInterfaceHashtable<nsURIHashKey, nsIObjectInputStream> mInputStreamTable;
--- a/extensions/auth/nsAuthSSPI.cpp
+++ b/extensions/auth/nsAuthSSPI.cpp
@@ -114,19 +114,21 @@ MakeSN(const char *principal, nsCString 
     // However, we should have at least hit the OS resolver once prior to
     // reaching this code, so provided the OS resolver has this information
     // cached, we should not have to worry about blocking on this function call
     // for very long.  NOTE: because we ask for the canonical hostname, we
     // might end up requiring extra network activity in cases where the OS
     // resolver might not have enough information to satisfy the request from
     // its cache.  This is not an issue in versions of Windows up to WinXP.
     nsCOMPtr<nsIDNSRecord> record;
-    rv = dns->Resolve(Substring(buf, index + 1),
-                      nsIDNSService::RESOLVE_CANONICAL_NAME,
-                      getter_AddRefs(record));
+    mozilla::OriginAttributes attrs;
+    rv = dns->ResolveNative(Substring(buf, index + 1),
+                            nsIDNSService::RESOLVE_CANONICAL_NAME,
+                            attrs,
+                            getter_AddRefs(record));
     if (NS_FAILED(rv))
         return rv;
 
     nsAutoCString cname;
     rv = record->GetCanonicalName(cname);
     if (NS_SUCCEEDED(rv)) {
         result = StringHead(buf, index) + NS_LITERAL_CSTRING("/") + cname;
         LOG(("Using SPN of [%s]\n", result.get()));
--- a/extensions/pref/autoconfig/src/nsAutoConfig.cpp
+++ b/extensions/pref/autoconfig/src/nsAutoConfig.cpp
@@ -131,18 +131,18 @@ nsAutoConfig::OnStopRequest(nsIRequest *
                                        static_cast<uint32_t>(aStatus)));
         return readOfflineFile();
     }
 
     // Checking for the http response, if failure go read the failover file.
     nsCOMPtr<nsIHttpChannel> pHTTPCon(do_QueryInterface(request));
     if (pHTTPCon) {
         uint32_t httpStatus;
-        pHTTPCon->GetResponseStatus(&httpStatus);
-        if (httpStatus != 200) 
+        rv = pHTTPCon->GetResponseStatus(&httpStatus);
+        if (NS_FAILED(rv) || httpStatus != 200)
         {
             MOZ_LOG(MCD, LogLevel::Debug, ("mcd http request failed with status %x\n", httpStatus));
             return readOfflineFile();
         }
     }
     
     // Send the autoconfig.jsc to javascript engine.
     
--- a/gfx/layers/Compositor.cpp
+++ b/gfx/layers/Compositor.cpp
@@ -306,53 +306,86 @@ Compositor::DrawTriangles(const nsTArray
                           const gfx::Rect& aVisibleRect)
 {
   for (const gfx::TexturedTriangle& triangle : aTriangles) {
     DrawTriangle(triangle, aClipRect, aEffectChain,
                  aOpacity, aTransform, aVisibleRect);
   }
 }
 
+static nsTArray<gfx::TexturedTriangle>
+GenerateTexturedTriangles(const gfx::Polygon& aPolygon,
+                          const gfx::Rect& aRect,
+                          const gfx::Rect& aTexRect)
+{
+  nsTArray<gfx::TexturedTriangle> texturedTriangles;
+
+  gfx::Rect layerRects[4];
+  gfx::Rect textureRects[4];
+  size_t rects = DecomposeIntoNoRepeatRects(aRect, aTexRect,
+                                            &layerRects, &textureRects);
+  for (size_t i = 0; i < rects; ++i) {
+    const gfx::Rect& rect = layerRects[i];
+    const gfx::Rect& texRect = textureRects[i];
+    const gfx::Polygon clipped = aPolygon.ClipPolygon(rect);
+
+    if (clipped.IsEmpty()) {
+      continue;
+    }
+
+    for (const gfx::Triangle& triangle : clipped.ToTriangles()) {
+      const gfx::Rect intersection = rect.Intersect(triangle.BoundingBox());
+
+      // Cull completely invisible triangles.
+      if (intersection.IsEmpty()) {
+        continue;
+      }
+
+      MOZ_ASSERT(rect.width > 0.0f && rect.height > 0.0f);
+      MOZ_ASSERT(intersection.width > 0.0f && intersection.height > 0.0f);
+
+      // Since the texture was created for non-split geometry, we need to
+      // update the texture coordinates to account for the split.
+      gfx::TexturedTriangle t(triangle);
+      t.width = rect.width;
+      t.height = rect.height;
+      UpdateTextureCoordinates(t, rect, intersection, texRect);
+      texturedTriangles.AppendElement(Move(t));
+    }
+  }
+
+  return texturedTriangles;
+}
+
 void
 Compositor::DrawPolygon(const gfx::Polygon& aPolygon,
                         const gfx::Rect& aRect,
                         const gfx::IntRect& aClipRect,
                         const EffectChain& aEffectChain,
                         gfx::Float aOpacity,
                         const gfx::Matrix4x4& aTransform,
                         const gfx::Rect& aVisibleRect)
 {
   nsTArray<gfx::TexturedTriangle> texturedTriangles;
 
-  for (gfx::Triangle& triangle : aPolygon.ToTriangles()) {
-    const gfx::Rect intersection = aRect.Intersect(triangle.BoundingBox());
-
-    // Cull invisible triangles.
-    if (intersection.IsEmpty()) {
-      continue;
-    }
-
-    MOZ_ASSERT(aRect.width > 0.0f && aRect.height > 0.0f);
-    MOZ_ASSERT(intersection.width > 0.0f && intersection.height > 0.0f);
+  TexturedEffect* texturedEffect =
+    aEffectChain.mPrimaryEffect->AsTexturedEffect();
 
-    gfx::TexturedTriangle texturedTriangle(Move(triangle));
-    texturedTriangle.width = aRect.width;
-    texturedTriangle.height = aRect.height;
+  if (texturedEffect) {
+    texturedTriangles =
+      GenerateTexturedTriangles(aPolygon, aRect, texturedEffect->mTextureCoords);
+  } else {
+    for (const gfx::Triangle& triangle : aPolygon.ToTriangles()) {
+      texturedTriangles.AppendElement(gfx::TexturedTriangle(triangle));
+    }
+  }
 
-    // Since the texture was created for non-split geometry, we need to
-    // update the texture coordinates to account for the split.
-    TexturedEffect* texturedEffect =
-      aEffectChain.mPrimaryEffect->AsTexturedEffect();
-
-    if (texturedEffect) {
-      UpdateTextureCoordinates(texturedTriangle, aRect, intersection,
-                               texturedEffect->mTextureCoords);
-    }
-
-    texturedTriangles.AppendElement(Move(texturedTriangle));
+  if (texturedTriangles.IsEmpty()) {
+    // Nothing to render.
+    return;
   }
 
   DrawTriangles(texturedTriangles, aRect, aClipRect, aEffectChain,
                 aOpacity, aTransform, aVisibleRect);
 }
 
 void
 Compositor::SlowDrawRect(const gfx::Rect& aRect, const gfx::Color& aColor,
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -42,25 +42,33 @@ namespace layers {
 
 static bool CanUsePartialPresents(ID3D11Device* aDevice);
 
 struct Vertex
 {
     float position[2];
 };
 
+struct TexturedVertex
+{
+    float position[2];
+    float texCoords[2];
+};
+
 // {1E4D7BEB-D8EC-4A0B-BF0A-63E6DE129425}
 static const GUID sDeviceAttachmentsD3D11 =
 { 0x1e4d7beb, 0xd8ec, 0x4a0b, { 0xbf, 0xa, 0x63, 0xe6, 0xde, 0x12, 0x94, 0x25 } };
 // {88041664-C835-4AA8-ACB8-7EC832357ED8}
 static const GUID sLayerManagerCount =
 { 0x88041664, 0xc835, 0x4aa8, { 0xac, 0xb8, 0x7e, 0xc8, 0x32, 0x35, 0x7e, 0xd8 } };
 
 const FLOAT sBlendFactor[] = { 0, 0, 0, 0 };
 
+static const size_t kInitialMaximumTriangles = 64;
+
 namespace TexSlot {
   static const int RGB = 0;
   static const int Y = 1;
   static const int Cb = 2;
   static const int Cr = 3;
   static const int RGBWhite = 4;
   static const int Mask = 5;
   static const int Backdrop = 6;
@@ -79,31 +87,39 @@ struct DeviceAttachmentsD3D11
   bool InitSyncObject();
 
   typedef EnumeratedArray<MaskType, MaskType::NumMaskTypes, RefPtr<ID3D11VertexShader>>
           VertexShaderArray;
   typedef EnumeratedArray<MaskType, MaskType::NumMaskTypes, RefPtr<ID3D11PixelShader>>
           PixelShaderArray;
 
   RefPtr<ID3D11InputLayout> mInputLayout;
+  RefPtr<ID3D11InputLayout> mDynamicInputLayout;
+
   RefPtr<ID3D11Buffer> mVertexBuffer;
+  RefPtr<ID3D11Buffer> mDynamicVertexBuffer;
 
   VertexShaderArray mVSQuadShader;
   VertexShaderArray mVSQuadBlendShader;
+
+  VertexShaderArray mVSDynamicShader;
+  VertexShaderArray mVSDynamicBlendShader;
+
   PixelShaderArray mSolidColorShader;
   PixelShaderArray mRGBAShader;
   PixelShaderArray mRGBShader;
   PixelShaderArray mYCbCrShader;
   PixelShaderArray mComponentAlphaShader;
   PixelShaderArray mBlendShader;
   RefPtr<ID3D11Buffer> mPSConstantBuffer;
   RefPtr<ID3D11Buffer> mVSConstantBuffer;
   RefPtr<ID3D11RasterizerState> mRasterizerState;
   RefPtr<ID3D11SamplerState> mLinearSamplerState;
   RefPtr<ID3D11SamplerState> mPointSamplerState;
+
   RefPtr<ID3D11BlendState> mPremulBlendState;
   RefPtr<ID3D11BlendState> mNonPremulBlendState;
   RefPtr<ID3D11BlendState> mComponentBlendState;
   RefPtr<ID3D11BlendState> mDisabledBlendState;
   RefPtr<IDXGIResource> mSyncTexture;
   HANDLE mSyncHandle;
 
 private:
@@ -145,16 +161,17 @@ private:
 
 CompositorD3D11::CompositorD3D11(CompositorBridgeParent* aParent, widget::CompositorWidget* aWidget)
   : Compositor(aWidget, aParent)
   , mAttachments(nullptr)
   , mHwnd(nullptr)
   , mDisableSequenceForNextFrame(false)
   , mAllowPartialPresents(false)
   , mVerifyBuffersFailed(false)
+  , mMaximumTriangles(kInitialMaximumTriangles)
 {
 }
 
 CompositorD3D11::~CompositorD3D11()
 {
   if (mDevice) {
     int referenceCount = 0;
     UINT size = sizeof(referenceCount);
@@ -173,16 +190,84 @@ CompositorD3D11::~CompositorD3D11()
       // which hold a reference to the device.
       mDevice->SetPrivateData(sDeviceAttachmentsD3D11, 0, nullptr);
 
       delete attachments;
     }
   }
 }
 
+
+template<typename VertexType>
+void
+CompositorD3D11::SetVertexBuffer(ID3D11Buffer* aBuffer)
+{
+  UINT size = sizeof(VertexType);
+  UINT offset = 0;
+  mContext->IASetVertexBuffers(0, 1, &aBuffer, &size, &offset);
+}
+
+bool
+CompositorD3D11::SupportsLayerGeometry() const
+{
+  return gfxPrefs::D3D11LayerGeometry();
+}
+
+bool
+CompositorD3D11::UpdateDynamicVertexBuffer(const nsTArray<gfx::TexturedTriangle>& aTriangles)
+{
+  HRESULT hr;
+
+  // Resize the dynamic vertex buffer if needed.
+  if (aTriangles.Length() > mMaximumTriangles) {
+    CD3D11_BUFFER_DESC bufferDesc(sizeof(TexturedVertex) * aTriangles.Length() * 3,
+                                  D3D11_BIND_VERTEX_BUFFER,
+                                  D3D11_USAGE_DYNAMIC,
+                                  D3D11_CPU_ACCESS_WRITE);
+
+    hr = mDevice->CreateBuffer(&bufferDesc, nullptr,
+                               getter_AddRefs(mAttachments->mDynamicVertexBuffer));
+
+    if (Failed(hr, "resize dynamic vertex buffer")) {
+      return false;
+    }
+
+    mMaximumTriangles = aTriangles.Length();
+  }
+
+  MOZ_ASSERT(mMaximumTriangles >= aTriangles.Length());
+
+  D3D11_MAPPED_SUBRESOURCE resource {};
+  hr = mContext->Map(mAttachments->mDynamicVertexBuffer, 0,
+                     D3D11_MAP_WRITE_DISCARD, 0, &resource);
+
+  if (Failed(hr, "map dynamic vertex buffer")) {
+    return false;
+  }
+
+  const auto vertexFromPoints = [](const gfx::Point& p, const gfx::Point& t) {
+    return TexturedVertex { { p.x, p.y }, { t.x, t.y } };
+  };
+
+  nsTArray<TexturedVertex> vertices;
+
+  for (const gfx::TexturedTriangle& t : aTriangles) {
+    vertices.AppendElement(vertexFromPoints(t.p1, t.textureCoords.p1));
+    vertices.AppendElement(vertexFromPoints(t.p2, t.textureCoords.p2));
+    vertices.AppendElement(vertexFromPoints(t.p3, t.textureCoords.p3));
+  }
+
+  memcpy(resource.pData, vertices.Elements(),
+         vertices.Length() * sizeof(TexturedVertex));
+
+  mContext->Unmap(mAttachments->mDynamicVertexBuffer, 0);
+
+  return true;
+}
+
 bool
 CompositorD3D11::Initialize(nsCString* const out_failureReason)
 {
   ScopedGfxFeatureReporter reporter("D3D11 Layers");
 
   HRESULT hr;
 
   mDevice = DeviceManagerDx::Get()->GetCompositorDevice();
@@ -240,18 +325,47 @@ CompositorD3D11::Initialize(nsCString* c
     }
 
     Vertex vertices[] = { {{0.0, 0.0}}, {{1.0, 0.0}}, {{0.0, 1.0}}, {{1.0, 1.0}} };
     CD3D11_BUFFER_DESC bufferDesc(sizeof(vertices), D3D11_BIND_VERTEX_BUFFER);
     D3D11_SUBRESOURCE_DATA data;
     data.pSysMem = (void*)vertices;
 
     hr = mDevice->CreateBuffer(&bufferDesc, &data, getter_AddRefs(mAttachments->mVertexBuffer));
+    if (Failed(hr, "create vertex buffer")) {
+      *out_failureReason = "FEATURE_FAILURE_D3D11_VERTEX_BUFFER";
+      return false;
+    }
 
-    if (Failed(hr, "create vertex buffer")) {
+    // Create a second input layout for layers with dynamic geometry.
+    D3D11_INPUT_ELEMENT_DESC dynamicLayout[] =
+    {
+      { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
+      { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 },
+    };
+
+    hr = mDevice->CreateInputLayout(dynamicLayout,
+                                    sizeof(dynamicLayout) / sizeof(D3D11_INPUT_ELEMENT_DESC),
+                                    LayerDynamicVS,
+                                    sizeof(LayerDynamicVS),
+                                    getter_AddRefs(mAttachments->mDynamicInputLayout));
+
+    if (Failed(hr, "CreateInputLayout")) {
+      *out_failureReason = "FEATURE_FAILURE_D3D11_INPUT_LAYOUT";
+      return false;
+    }
+
+    // Allocate memory for the dynamic vertex buffer.
+    bufferDesc = CD3D11_BUFFER_DESC(sizeof(TexturedVertex) * mMaximumTriangles * 3,
+                                    D3D11_BIND_VERTEX_BUFFER,
+                                    D3D11_USAGE_DYNAMIC,
+                                    D3D11_CPU_ACCESS_WRITE);
+
+    hr = mDevice->CreateBuffer(&bufferDesc, nullptr, getter_AddRefs(mAttachments->mDynamicVertexBuffer));
+    if (Failed(hr, "create dynamic vertex buffer")) {
       *out_failureReason = "FEATURE_FAILURE_D3D11_VERTEX_BUFFER";
       return false;
     }
 
     if (!mAttachments->CreateShaders()) {
       *out_failureReason = "FEATURE_FAILURE_D3D11_CREATE_SHADERS";
       return false;
     }
@@ -628,18 +742,24 @@ CompositorD3D11::SetRenderTarget(Composi
     newRT->GetProjection(projection, depthEnable, zNear, zFar);
     PrepareViewport(newRT->GetSize(), projection, zNear, zFar);
   } else {
     PrepareViewport(newRT->GetSize());
   }
 }
 
 ID3D11PixelShader*
-CompositorD3D11::GetPSForEffect(Effect* aEffect, MaskType aMaskType)
+CompositorD3D11::GetPSForEffect(Effect* aEffect,
+                                const bool aUseBlendShader,
+                                const MaskType aMaskType)
 {
+  if (aUseBlendShader) {
+    return mAttachments->mBlendShader[MaskType::MaskNone];
+  }
+
   switch (aEffect->mType) {
   case EffectTypes::SOLID_COLOR:
     return mAttachments->mSolidColorShader[aMaskType];
   case EffectTypes::RENDER_TARGET:
     return mAttachments->mRGBAShader[aMaskType];
   case EffectTypes::RGB: {
     SurfaceFormat format = static_cast<TexturedEffect*>(aEffect)->mTexture->GetFormat();
     return (format == SurfaceFormat::B8G8R8A8 || format == SurfaceFormat::R8G8B8A8)
@@ -728,16 +848,126 @@ EffectToBlendLayerType(Effect* aEffect)
 void
 CompositorD3D11::DrawQuad(const gfx::Rect& aRect,
                           const gfx::IntRect& aClipRect,
                           const EffectChain& aEffectChain,
                           gfx::Float aOpacity,
                           const gfx::Matrix4x4& aTransform,
                           const gfx::Rect& aVisibleRect)
 {
+  DrawGeometry(aRect, aRect, aClipRect, aEffectChain,
+               aOpacity, aTransform, aVisibleRect);
+}
+
+void
+CompositorD3D11::DrawTriangles(const nsTArray<gfx::TexturedTriangle>& aTriangles,
+                               const gfx::Rect& aRect,
+                               const gfx::IntRect& aClipRect,
+                               const EffectChain& aEffectChain,
+                               gfx::Float aOpacity,
+                               const gfx::Matrix4x4& aTransform,
+                               const gfx::Rect& aVisibleRect)
+{
+  DrawGeometry(aTriangles, aRect, aClipRect, aEffectChain,
+               aOpacity, aTransform, aVisibleRect);
+}
+
+void
+CompositorD3D11::PrepareDynamicVertexBuffer()
+{
+  mContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+  mContext->IASetInputLayout(mAttachments->mDynamicInputLayout);
+  SetVertexBuffer<TexturedVertex>(mAttachments->mDynamicVertexBuffer);
+}
+
+void
+CompositorD3D11::PrepareStaticVertexBuffer()
+{
+  mContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+  mContext->IASetInputLayout(mAttachments->mInputLayout);
+  SetVertexBuffer<Vertex>(mAttachments->mVertexBuffer);
+}
+
+void
+CompositorD3D11::Draw(const nsTArray<gfx::TexturedTriangle>& aTriangles,
+                      const gfx::Rect*)
+{
+  if (!UpdateConstantBuffers()) {
+    NS_WARNING("Failed to update shader constant buffers");
+    return;
+  }
+
+  PrepareDynamicVertexBuffer();
+
+  if (!UpdateDynamicVertexBuffer(aTriangles)) {
+    NS_WARNING("Failed to update shader dynamic buffers");
+    return;
+  }
+
+  mContext->Draw(3 * aTriangles.Length(), 0);
+
+  PrepareStaticVertexBuffer();
+}
+
+void
+CompositorD3D11::Draw(const gfx::Rect& aRect,
+                      const gfx::Rect* aTexCoords)
+{
+  Rect layerRects[4] = { aRect };
+  Rect textureRects[4] = { };
+  size_t rects = 1;
+
+  if (aTexCoords) {
+    rects = DecomposeIntoNoRepeatRects(aRect, *aTexCoords,
+                                       &layerRects, &textureRects);
+  }
+
+  for (size_t i = 0; i < rects; i++) {
+    mVSConstants.layerQuad = layerRects[i];
+    mVSConstants.textureCoords = textureRects[i];
+
+    if (!UpdateConstantBuffers()) {
+      NS_WARNING("Failed to update shader constant buffers");
+      break;
+    }
+
+    mContext->Draw(4, 0);
+  }
+}
+
+ID3D11VertexShader*
+CompositorD3D11::GetVSForGeometry(const nsTArray<gfx::TexturedTriangle>& aTriangles,
+                                  const bool aUseBlendShaders,
+                                  const MaskType aMaskType)
+{
+  return aUseBlendShaders
+    ? mAttachments->mVSDynamicBlendShader[aMaskType]
+    : mAttachments->mVSDynamicShader[aMaskType];
+}
+
+ID3D11VertexShader*
+CompositorD3D11::GetVSForGeometry(const gfx::Rect& aRect,
+                                  const bool aUseBlendShaders,
+                                  const MaskType aMaskType)
+{
+  return aUseBlendShaders
+    ? mAttachments->mVSQuadBlendShader[aMaskType]
+    : mAttachments->mVSQuadShader[aMaskType];
+}
+
+template<typename Geometry>
+void
+CompositorD3D11::DrawGeometry(const Geometry& aGeometry,
+                              const gfx::Rect& aRect,
+                              const gfx::IntRect& aClipRect,
+                              const EffectChain& aEffectChain,
+                              gfx::Float aOpacity,
+                              const gfx::Matrix4x4& aTransform,
+                              const gfx::Rect& aVisibleRect)
+{
   if (mCurrentClip.IsEmpty()) {
     return;
   }
 
   MOZ_ASSERT(mCurrentRT, "No render target");
 
   memcpy(&mVSConstants.layerTransform, &aTransform._11, 64);
   IntPoint origin = mCurrentRT->GetOrigin();
@@ -783,19 +1013,17 @@ CompositorD3D11::DrawQuad(const gfx::Rec
     return;
   }
 
   scissor.left = clipRect.x;
   scissor.right = clipRect.XMost();
   scissor.top = clipRect.y;
   scissor.bottom = clipRect.YMost();
 
-  RefPtr<ID3D11VertexShader> vertexShader = mAttachments->mVSQuadShader[maskType];
-  RefPtr<ID3D11PixelShader> pixelShader = GetPSForEffect(aEffectChain.mPrimaryEffect, maskType);
-
+  bool useBlendShaders = false;
   RefPtr<ID3D11Texture2D> mixBlendBackdrop;
   gfx::CompositionOp blendMode = gfx::CompositionOp::OP_OVER;
   if (aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE]) {
     EffectBlendMode *blendEffect =
       static_cast<EffectBlendMode*>(aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE].get());
     blendMode = blendEffect->mBlendMode;
 
     // If the blend operation needs to read from the backdrop, copy the
@@ -803,34 +1031,39 @@ CompositorD3D11::DrawQuad(const gfx::Rec
     if (BlendOpIsMixBlendMode(blendMode)) {
       gfx::Matrix4x4 backdropTransform;
       gfx::IntRect rect = ComputeBackdropCopyRect(aRect, aClipRect, aTransform, &backdropTransform);
 
       RefPtr<ID3D11ShaderResourceView> srv;
       if (CopyBackdrop(rect, &mixBlendBackdrop, &srv) &&
           mAttachments->InitBlendShaders())
       {
-        vertexShader = mAttachments->mVSQuadBlendShader[maskType];
-        pixelShader = mAttachments->mBlendShader[MaskType::MaskNone];
+        useBlendShaders = true;
 
         ID3D11ShaderResourceView* srView = srv.get();
         mContext->PSSetShaderResources(TexSlot::Backdrop, 1, &srView);
 
         memcpy(&mVSConstants.backdropTransform, &backdropTransform._11, 64);
 
         mPSConstants.blendConfig[0] = EffectToBlendLayerType(aEffectChain.mPrimaryEffect);
         mPSConstants.blendConfig[1] = int(maskType);
         mPSConstants.blendConfig[2] = BlendOpToShaderConstant(blendMode);
         mPSConstants.blendConfig[3] = EffectHasPremultipliedAlpha(aEffectChain.mPrimaryEffect);
       }
     }
   }
 
   mContext->RSSetScissorRects(1, &scissor);
-  mContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+
+  RefPtr<ID3D11VertexShader> vertexShader =
+    GetVSForGeometry(aGeometry, useBlendShaders, maskType);
+
+  RefPtr<ID3D11PixelShader> pixelShader =
+    GetPSForEffect(aEffectChain.mPrimaryEffect, useBlendShaders, maskType);
+
   mContext->VSSetShader(vertexShader, nullptr, 0);
   mContext->PSSetShader(pixelShader, nullptr, 0);
 
   const Rect* pTexCoordRect = nullptr;
 
   switch (aEffectChain.mPrimaryEffect->mType) {
   case EffectTypes::SOLID_COLOR: {
       Color color =
@@ -930,42 +1163,17 @@ CompositorD3D11::DrawQuad(const gfx::Rec
       restoreBlendMode = true;
     }
     break;
   default:
     NS_WARNING("Unknown shader type");
     return;
   }
 
-  if (pTexCoordRect) {
-    Rect layerRects[4];
-    Rect textureRects[4];
-    size_t rects = DecomposeIntoNoRepeatRects(aRect,
-                                              *pTexCoordRect,
-                                              &layerRects,
-                                              &textureRects);
-    for (size_t i = 0; i < rects; i++) {
-      mVSConstants.layerQuad = layerRects[i];
-      mVSConstants.textureCoords = textureRects[i];
-
-      if (!UpdateConstantBuffers()) {
-        NS_WARNING("Failed to update shader constant buffers");
-        break;
-      }
-      mContext->Draw(4, 0);
-    }
-  } else {
-    mVSConstants.layerQuad = aRect;
-
-    if (!UpdateConstantBuffers()) {
-      NS_WARNING("Failed to update shader constant buffers");
-    } else {
-      mContext->Draw(4, 0);
-    }
-  }
+  Draw(aGeometry, pTexCoordRect);
 
   if (restoreBlendMode) {
     mContext->OMSetBlendState(mAttachments->mPremulBlendState, sBlendFactor, 0xFFFFFFFF);
   }
 }
 
 void
 CompositorD3D11::BeginFrame(const nsIntRegion& aInvalidRegion,
@@ -1029,22 +1237,17 @@ CompositorD3D11::BeginFrame(const nsIntR
   }
 
   if (clipRect.IsEmpty()) {
     CancelFrame();
     *aRenderBoundsOut = IntRect();
     return;
   }
 
-  mContext->IASetInputLayout(mAttachments->mInputLayout);
-
-  ID3D11Buffer* buffer = mAttachments->mVertexBuffer;
-  UINT size = sizeof(Vertex);
-  UINT offset = 0;
-  mContext->IASetVertexBuffers(0, 1, &buffer, &size, &offset);
+  PrepareStaticVertexBuffer();
 
   mInvalidRect = IntRect(invalidRect.x, invalidRect.y, invalidRect.width, invalidRect.height);
   mInvalidRegion = invalidRegionSafe;
 
   if (aClipRectOut) {
     *aClipRectOut = IntRect(0, 0, mSize.width, mSize.height);
   }
   if (aRenderBoundsOut) {
@@ -1399,28 +1602,37 @@ DeviceAttachmentsD3D11::InitSyncObject()
 
 bool
 DeviceAttachmentsD3D11::InitBlendShaders()
 {
   if (!mVSQuadBlendShader[MaskType::MaskNone]) {
     InitVertexShader(sLayerQuadBlendVS, mVSQuadBlendShader, MaskType::MaskNone);
     InitVertexShader(sLayerQuadBlendMaskVS, mVSQuadBlendShader, MaskType::Mask);
   }
+
+  if (!mVSDynamicBlendShader[MaskType::MaskNone]) {
+    InitVertexShader(sLayerDynamicBlendVS, mVSDynamicBlendShader, MaskType::MaskNone);
+    InitVertexShader(sLayerDynamicBlendMaskVS, mVSDynamicBlendShader, MaskType::Mask);
+  }
+
   if (!mBlendShader[MaskType::MaskNone]) {
     InitPixelShader(sBlendShader, mBlendShader, MaskType::MaskNone);
   }
   return mInitOkay;
 }
 
 bool
 DeviceAttachmentsD3D11::CreateShaders()
 {
   InitVertexShader(sLayerQuadVS, mVSQuadShader, MaskType::MaskNone);
   InitVertexShader(sLayerQuadMaskVS, mVSQuadShader, MaskType::Mask);
 
+  InitVertexShader(sLayerDynamicVS, mVSDynamicShader, MaskType::MaskNone);
+  InitVertexShader(sLayerDynamicMaskVS, mVSDynamicShader, MaskType::Mask);
+
   InitPixelShader(sSolidColorShader, mSolidColorShader, MaskType::MaskNone);
   InitPixelShader(sSolidColorShaderMask, mSolidColorShader, MaskType::Mask);
   InitPixelShader(sRGBShader, mRGBShader, MaskType::MaskNone);
   InitPixelShader(sRGBShaderMask, mRGBShader, MaskType::Mask);
   InitPixelShader(sRGBAShader, mRGBAShader, MaskType::MaskNone);
   InitPixelShader(sRGBAShaderMask, mRGBAShader, MaskType::Mask);
   InitPixelShader(sYCbCrShader, mYCbCrShader, MaskType::MaskNone);
   InitPixelShader(sYCbCrShaderMask, mYCbCrShader, MaskType::Mask);
--- a/gfx/layers/d3d11/CompositorD3D11.h
+++ b/gfx/layers/d3d11/CompositorD3D11.h
@@ -96,17 +96,17 @@ public:
                         const gfx::IntRect &aClipRect,
                         const EffectChain &aEffectChain,
                         gfx::Float aOpacity,
                         const gfx::Matrix4x4& aTransform,
                         const gfx::Rect& aVisibleRect) override;
 
   /**
    * Start a new frame. If aClipRectIn is null, sets *aClipRectOut to the
-   * screen dimensions. 
+   * screen dimensions.
    */
   virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
                           const gfx::IntRect *aClipRectIn,
                           const gfx::IntRect& aRenderBounds,
                           const nsIntRegion& aOpaqueRegion,
                           gfx::IntRect *aClipRectOut = nullptr,
                           gfx::IntRect *aRenderBoundsOut = nullptr) override;
 
@@ -122,16 +122,18 @@ public:
    * to a window of the given dimensions.
    */
   virtual void PrepareViewport(const gfx::IntSize& aSize);
   virtual void PrepareViewport(const gfx::IntSize& aSize, const gfx::Matrix4x4& aProjection,
                                float aZNear, float aZFar);
 
   virtual bool SupportsPartialTextureUpdate() override { return true; }
 
+  virtual bool SupportsLayerGeometry() const override;
+
 #ifdef MOZ_DUMP_PAINTING
   virtual const char* Name() const override { return "Direct3D 11"; }
 #endif
 
   virtual LayersBackend GetBackendType() const override {
     return LayersBackend::LAYERS_D3D11;
   }
 
@@ -155,25 +157,68 @@ private:
   bool Failed(HRESULT hr, const char* aContext);
 
   // ensure mSize is up to date with respect to mWidget
   void EnsureSize();
   bool VerifyBufferSize();
   bool UpdateRenderTarget();
   bool UpdateConstantBuffers();
   void SetSamplerForSamplingFilter(gfx::SamplingFilter aSamplingFilter);
-  ID3D11PixelShader* GetPSForEffect(Effect *aEffect, MaskType aMaskType);
+
+  ID3D11PixelShader* GetPSForEffect(Effect* aEffect,
+                                    const bool aUseBlendShader,
+                                    const MaskType aMaskType);
   void PaintToTarget();
   RefPtr<ID3D11Texture2D> CreateTexture(const gfx::IntRect& aRect,
                                         const CompositingRenderTarget* aSource,
                                         const gfx::IntPoint& aSourcePoint);
   bool CopyBackdrop(const gfx::IntRect& aRect,
                     RefPtr<ID3D11Texture2D>* aOutTexture,
                     RefPtr<ID3D11ShaderResourceView>* aOutView);
 
+  virtual void DrawTriangles(const nsTArray<gfx::TexturedTriangle>& aTriangles,
+                             const gfx::Rect& aRect,
+                             const gfx::IntRect& aClipRect,
+                             const EffectChain& aEffectChain,
+                             gfx::Float aOpacity,
+                             const gfx::Matrix4x4& aTransform,
+                             const gfx::Rect& aVisibleRect) override;
+
+  template<typename Geometry>
+  void DrawGeometry(const Geometry& aGeometry,
+                    const gfx::Rect& aRect,
+                    const gfx::IntRect& aClipRect,
+                    const EffectChain& aEffectChain,
+                    gfx::Float aOpacity,
+                    const gfx::Matrix4x4& aTransform,
+                    const gfx::Rect& aVisibleRect);
+
+  bool UpdateDynamicVertexBuffer(const nsTArray<gfx::TexturedTriangle>& aTriangles);
+
+  void PrepareDynamicVertexBuffer();
+  void PrepareStaticVertexBuffer();
+
+  // Overloads for rendering both rects and triangles with same rendering path
+  void Draw(const nsTArray<gfx::TexturedTriangle>& aGeometry,
+            const gfx::Rect* aTexCoords);
+
+  void Draw(const gfx::Rect& aGeometry,
+            const gfx::Rect* aTexCoords);
+
+  ID3D11VertexShader* GetVSForGeometry(const nsTArray<gfx::TexturedTriangle>& aTriangles,
+                                       const bool aUseBlendShader,
+                                       const MaskType aMaskType);
+
+  ID3D11VertexShader* GetVSForGeometry(const gfx::Rect& aRect,
+                                       const bool aUseBlendShader,
+                                       const MaskType aMaskType);
+
+  template<typename VertexType>
+  void SetVertexBuffer(ID3D11Buffer* aBuffer);
+
   RefPtr<ID3D11DeviceContext> mContext;
   RefPtr<ID3D11Device> mDevice;
   RefPtr<IDXGISwapChain> mSwapChain;
   RefPtr<CompositingRenderTargetD3D11> mDefaultRT;
   RefPtr<CompositingRenderTargetD3D11> mCurrentRT;
 
   RefPtr<ID3D11Query> mQuery;
 
@@ -191,14 +236,16 @@ private:
   bool mAllowPartialPresents;
 
   gfx::IntRect mInvalidRect;
   // This is the clip rect applied to the default DrawTarget (i.e. the window)
   gfx::IntRect mCurrentClip;
   nsIntRegion mInvalidRegion;
 
   bool mVerifyBuffersFailed;
+
+  size_t mMaximumTriangles;
 };
 
 }
 }
 
 #endif
--- a/gfx/layers/d3d11/CompositorD3D11.hlsl
+++ b/gfx/layers/d3d11/CompositorD3D11.hlsl
@@ -38,16 +38,21 @@ Texture2D tCr : register(ps, t3);
 Texture2D tRGBWhite : register(ps, t4);
 Texture2D tMask : register(ps, t5);
 Texture2D tBackdrop : register(ps, t6);
 
 struct VS_INPUT {
   float2 vPosition : POSITION;
 };
 
+struct VS_TEX_INPUT {
+  float2 vPosition : POSITION;
+  float2 vTexCoords : TEXCOORD0;
+};
+
 struct VS_OUTPUT {
   float4 vPosition : SV_Position;
   float2 vTexCoords : TEXCOORD0;
 };
 
 struct VS_MASK_OUTPUT {
   float4 vPosition : SV_Position;
   float2 vTexCoords : TEXCOORD0;
@@ -160,16 +165,48 @@ VS_MASK_OUTPUT LayerQuadMaskVS(const VS_
   outp.vMaskCoords.z = 1;
   outp.vMaskCoords *= position.w;
 
   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);
+  position = mul(mLayerTransform, position);
+  outp.vPosition = VertexPosition(position);
+
+  outp.vTexCoords = aVertex.vTexCoords;
+
+  return outp;
+}
+
+VS_MASK_OUTPUT LayerDynamicMaskVS(const VS_TEX_INPUT aVertex)
+{
+  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.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;
 }
 
 float4 RGBShaderMask(const VS_MASK_OUTPUT aVertex) : SV_Target
@@ -308,16 +345,40 @@ VS_BLEND_OUTPUT LayerQuadBlendMaskVS(con
   VS_BLEND_OUTPUT o;
   o.vPosition = v.vPosition;
   o.vTexCoords = v.vTexCoords;
   o.vMaskCoords = v.vMaskCoords;
   o.vBackdropCoords = BackdropPosition(v.vPosition);
   return o;
 }
 
+VS_BLEND_OUTPUT LayerDynamicBlendVS(const VS_TEX_INPUT aVertex)
+{
+  VS_OUTPUT v = LayerDynamicVS(aVertex);
+
+  VS_BLEND_OUTPUT o;
+  o.vPosition = v.vPosition;
+  o.vTexCoords = v.vTexCoords;
+  o.vMaskCoords = float3(0, 0, 0);
+  o.vBackdropCoords = BackdropPosition(v.vPosition);
+  return o;
+}
+
+VS_BLEND_OUTPUT LayerDynamicBlendMaskVS(const VS_TEX_INPUT aVertex)
+{
+  VS_MASK_OUTPUT v = LayerDynamicMaskVS(aVertex);
+
+  VS_BLEND_OUTPUT o;
+  o.vPosition = v.vPosition;
+  o.vTexCoords = v.vTexCoords;
+  o.vMaskCoords = v.vMaskCoords;
+  o.vBackdropCoords = BackdropPosition(v.vPosition);
+  return o;
+}
+
 // The layer type and mask type are specified as constants. We use these to
 // call the correct pixel shader to determine the source color for blending.
 // Unfortunately this also requires some boilerplate to convert VS_BLEND_OUTPUT
 // to a compatible pixel shader input.
 float4 ComputeBlendSourceColor(const VS_BLEND_OUTPUT aVertex)
 {
   if (iBlendConfig.y == PS_MASK_NONE) {
     VS_OUTPUT tmp;
--- a/gfx/layers/d3d11/CompositorD3D11Shaders.h
+++ b/gfx/layers/d3d11/CompositorD3D11Shaders.h
@@ -1,9434 +1,11413 @@
 struct ShaderBytes { const void* mData; size_t mLength; };
-#if 0
-//
-// 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]
-//
-// }
-//
-//
-// Resource Bindings:
-//
-// 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  
-//
-//
-// Output signature:
-//
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Position              0   xyzw        0      POS   float   xyzw
-// TEXCOORD                 0   xy          1     NONE   float   xy  
-//
-//
-// Constant buffer to DX9 shader constant mappings:
-//
-// Target Reg Buffer  Start Reg # of Regs        Data Conversion
-// ---------- ------- --------- --------- ----------------------
-// c1         cb0             0         2  ( FLT, FLT, FLT, FLT)
-// c3         cb0             3         8  ( FLT, FLT, FLT, FLT)
-//
-//
-// Runtime generated constant mappings:
-//
-// Target Reg                               Constant Description
-// ---------- --------------------------------------------------
-// c0                              Vertex Shader position offset
-//
-//
-// Level9 shader bytecode:
-//
-    vs_2_x
-    dcl_texcoord v0
-    mad oT0.xy, v0, c9.zwzw, c9
-    mad r0.xy, v0, c10.zwzw, c10
-    mul r1, r0.y, c2
-    mad r0, c1, r0.x, r1
-    add r0, r0, c3
-    rcp r1.x, r0.w
-    mul r0.xyz, r0, r1.x
-    add r0, r0, -c8
-    mul r0.xyz, r0.w, r0
-    mul r1, r0.y, c5
-    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_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
-div r0.xyz, r0.xyzx, r0.wwww
-add r0.xyzw, r0.xyzw, -cb0[8].xyzw
-mul r0.xyz, r0.wwww, r0.xyzx
-mul r1.xyzw, r0.yyyy, cb0[5].xyzw
-mad r1.xyzw, cb0[4].xyzw, r0.xxxx, r1.xyzw
-mad r1.xyzw, cb0[6].xyzw, r0.zzzz, r1.xyzw
-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, 250,  65, 
-     94, 205, 254, 155,  52,  90, 
-     43, 147, 203, 201, 141,  74, 
-     80, 143,   1,   0,   0,   0, 
-     68,   7,   0,   0,   6,   0, 
-      0,   0,  56,   0,   0,   0, 
-    152,   1,   0,   0, 160,   3, 
-      0,   0,  28,   4,   0,   0, 
-    184,   6,   0,   0, 236,   6, 
-      0,   0,  65, 111, 110,  57, 
-     88,   1,   0,   0,  88,   1, 
-      0,   0,   0,   2, 254, 255, 
-     24,   1,   0,   0,  64,   0, 
-      0,   0,   2,   0,  36,   0, 
-      0,   0,  60,   0,   0,   0, 
-     60,   0,   0,   0,  36,   0, 
-      1,   0,  60,   0,   0,   0, 
-      0,   0,   2,   0,   1,   0, 
-      0,   0,   0,   0,   0,   0, 
-      3,   0,   8,   0,   3,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   1,   2, 254, 255, 
-     31,   0,   0,   2,   5,   0, 
-      0, 128,   0,   0,  15, 144, 
-      4,   0,   0,   4,   0,   0, 
-      3, 224,   0,   0, 228, 144, 
-      9,   0, 238, 160,   9,   0, 
-    228, 160,   4,   0,   0,   4, 
-      0,   0,   3, 128,   0,   0, 
-    228, 144,  10,   0, 238, 160, 
-     10,   0, 228, 160,   5,   0, 
-      0,   3,   1,   0,  15, 128, 
-      0,   0,  85, 128,   2,   0, 
-    228, 160,   4,   0,   0,   4, 
-      0,   0,  15, 128,   1,   0, 
-    228, 160,   0,   0,   0, 128, 
-      1,   0, 228, 128,   2,   0, 
-      0,   3,   0,   0,  15, 128, 
-      0,   0, 228, 128,   3,   0, 
-    228, 160,   6,   0,   0,   2, 
-      1,   0,   1, 128,   0,   0, 
-    255, 128,   5,   0,   0,   3, 
-      0,   0,   7, 128,   0,   0, 
-    228, 128,   1,   0,   0, 128, 
-      2,   0,   0,   3,   0,   0, 
-     15, 128,   0,   0, 228, 128, 
-      8,   0, 228, 161,   5,   0, 
-      0,   3,   0,   0,   7, 128, 
-      0,   0, 255, 128,   0,   0, 
-    228, 128,   5,   0,   0,   3, 
-      1,   0,  15, 128,   0,   0, 
-     85, 128,   5,   0, 228, 160, 
-      4,   0,   0,   4,   1,   0, 
-     15, 128,   4,   0, 228, 160, 
-      0,   0,   0, 128,   1,   0, 
-    228, 128,   4,   0,   0,   4, 
-      1,   0,  15, 128,   6,   0, 
-    228, 160,   0,   0, 170, 128, 
-      1,   0, 228, 128,   4,   0, 
-      0,   4,   0,   0,  15, 128, 
-      7,   0, 228, 160,   0,   0, 
-    255, 128,   1,   0, 228, 128, 
-      4,   0,   0,   4,   0,   0, 
-      3, 192,   0,   0, 255, 128, 
-      0,   0, 228, 160,   0,   0, 
-    228, 128,   1,   0,   0,   2, 
-      0,   0,  12, 192,   0,   0, 
-    228, 128, 255, 255,   0,   0, 
-     83,  72,  68,  82,   0,   2, 
-      0,   0,  64,   0,   1,   0, 
-    128,   0,   0,   0,  89,   0, 
-      0,   4,  70, 142,  32,   0, 
-      0,   0,   0,   0,  11,   0, 
-      0,   0,  95,   0,   0,   3, 
-     50,  16,  16,   0,   0,   0, 
-      0,   0, 103,   0,   0,   4, 
-    242,  32,  16,   0,   0,   0, 
-      0,   0,   1,   0,   0,   0, 
-    101,   0,   0,   3,  50,  32, 
-     16,   0,   1,   0,   0,   0, 
-    104,   0,   0,   2,   2,   0, 
-      0,   0,  50,   0,   0,  11, 
-     50,   0,  16,   0,   0,   0, 
-      0,   0,  70,  16,  16,   0, 
-      0,   0,   0,   0, 230, 138, 
-     32,   0,   0,   0,   0,   0, 
-     10,   0,   0,   0,  70, 128, 
-     32,   0,   0,   0,   0,   0, 
-     10,   0,   0,   0,  56,   0, 
-      0,   8, 242,   0,  16,   0, 
-      1,   0,   0,   0,  86,   5, 
-     16,   0,   0,   0,   0,   0, 
-     70, 142,  32,   0,   0,   0, 
-      0,   0,   1,   0,   0,   0, 
-     50,   0,   0,  10, 242,   0, 
-     16,   0,   0,   0,   0,   0, 
-     70, 142,  32,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      6,   0,  16,   0,   0,   0, 
-      0,   0,  70,  14,  16,   0, 
-      1,   0,   0,   0,   0,   0, 
-      0,   8, 242,   0,  16,   0, 
-      0,   0,   0,   0,  70,  14, 
-     16,   0,   0,   0,   0,   0, 
-     70, 142,  32,   0,   0,   0, 
-      0,   0,   3,   0,   0,   0, 
-     14,   0,   0,   7, 114,   0, 
-     16,   0,   0,   0,   0,   0, 
-     70,   2,  16,   0,   0,   0, 
-      0,   0, 246,  15,  16,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   9, 242,   0,  16,   0, 
-      0,   0,   0,   0,  70,  14, 
-     16,   0,   0,   0,   0,   0, 
-     70, 142,  32, 128,  65,   0, 
-      0,   0,   0,   0,   0,   0, 
-      8,   0,   0,   0,  56,   0, 
-      0,   7, 114,   0,  16,   0, 
-      0,   0,   0,   0, 246,  15, 
-     16,   0,   0,   0,   0,   0, 
-     70,   2,  16,   0,   0,   0, 
-      0,   0,  56,   0,   0,   8, 
-    242,   0,  16,   0,   1,   0, 
-      0,   0,  86,   5,  16,   0, 
-      0,   0,   0,   0,  70, 142, 
-     32,   0,   0,   0,   0,   0, 
-      5,   0,   0,   0,  50,   0, 
-      0,  10, 242,   0,  16,   0, 
-      1,   0,   0,   0,  70, 142, 
-     32,   0,   0,   0,   0,   0, 
-      4,   0,   0,   0,   6,   0, 
-     16,   0,   0,   0,   0,   0, 
-     70,  14,  16,   0,   1,   0, 
-      0,   0,  50,   0,   0,  10, 
-    242,   0,  16,   0,   1,   0, 
-      0,   0,  70, 142,  32,   0, 
-      0,   0,   0,   0,   6,   0, 
-      0,   0, 166,  10,  16,   0, 
-      0,   0,   0,   0,  70,  14, 
-     16,   0,   1,   0,   0,   0, 
-     50,   0,   0,  10, 242,  32, 
-     16,   0,   0,   0,   0,   0, 
-     70, 142,  32,   0,   0,   0, 
-      0,   0,   7,   0,   0,   0, 
-    246,  15,  16,   0,   0,   0, 
-      0,   0,  70,  14,  16,   0, 
-      1,   0,   0,   0,  50,   0, 
-      0,  11,  50,  32,  16,   0, 
-      1,   0,   0,   0,  70,  16, 
-     16,   0,   0,   0,   0,   0, 
-    230, 138,  32,   0,   0,   0, 
-      0,   0,   9,   0,   0,   0, 
-     70, 128,  32,   0,   0,   0, 
-      0,   0,   9,   0,   0,   0, 
-     62,   0,   0,   1,  83,  84, 
-     65,  84, 116,   0,   0,   0, 
-     13,   0,   0,   0,   2,   0, 
-      0,   0,   0,   0,   0,   0, 
-      3,   0,   0,   0,  12,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   1,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   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, 
-      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,   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,   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, 
-      0,   0, 120,   1,   0,   0, 
-      0,   0,   0,   0, 148,   1, 
-      0,   0, 128,   0,   0,   0, 
-     16,   0,   0,   0,   2,   0, 
-      0,   0, 168,   1,   0,   0, 
-      0,   0,   0,   0, 184,   1, 
-      0,   0, 144,   0,   0,   0, 
-     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, 
-     16,   0,   0,   0,   0,   0, 
-      0,   0, 168,   1,   0,   0, 
-      0,   0,   0,   0,  12,   2, 
-      0,   0,  16,   1,   0,   0, 
-      4,   0,   0,   0,   0,   0, 
-      0,   0,  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, 
-     44,   0,   0,   0,   0,   0, 
-      0,   0,  92,   2,   0,   0, 
-      0,   0,   0,   0, 109,  76, 
-     97, 121, 101, 114,  84, 114, 
-     97, 110, 115, 102, 111, 114, 
-    109,   0,   3,   0,   3,   0, 
-      4,   0,   4,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-    109,  80, 114, 111, 106, 101, 
-     99, 116, 105, 111, 110,   0, 
-    118,  82, 101, 110, 100, 101, 
-    114,  84,  97, 114, 103, 101, 
-    116,  79, 102, 102, 115, 101, 
-    116,   0,   1,   0,   3,   0, 
-      1,   0,   4,   0,   0,   0, 
-      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,  44,   0,   0,   0, 
-      1,   0,   0,   0,   8,   0, 
-      0,   0,  32,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   3,   0,   0,   0, 
-      0,   0,   0,   0,   3,   3, 
-      0,   0,  80,  79,  83,  73, 
-     84,  73,  79,  78,   0, 171, 
-    171, 171,  79,  83,  71,  78, 
-     80,   0,   0,   0,   2,   0, 
-      0,   0,   8,   0,   0,   0, 
-     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
-};
+#if 0
+//
+// 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]
+//
+// }
+//
+//
+// Resource Bindings:
+//
+// 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  
+//
+//
+// Output signature:
+//
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Position              0   xyzw        0      POS   float   xyzw
+// TEXCOORD                 0   xy          1     NONE   float   xy  
+//
+//
+// Constant buffer to DX9 shader constant mappings:
+//
+// Target Reg Buffer  Start Reg # of Regs        Data Conversion
+// ---------- ------- --------- --------- ----------------------
+// c1         cb0             0         2  ( FLT, FLT, FLT, FLT)
+// c3         cb0             3         8  ( FLT, FLT, FLT, FLT)
+//
+//
+// Runtime generated constant mappings:
+//
+// Target Reg                               Constant Description
+// ---------- --------------------------------------------------
+// c0                              Vertex Shader position offset
+//
+//
+// Level9 shader bytecode:
+//
+    vs_2_x
+    dcl_texcoord v0
+    mad oT0.xy, v0, c9.zwzw, c9
+    mad r0.xy, v0, c10.zwzw, c10
+    mul r1, r0.y, c2
+    mad r0, c1, r0.x, r1
+    add r0, r0, c3
+    rcp r1.x, r0.w
+    mul r0.xyz, r0, r1.x
+    add r0, r0, -c8
+    mul r0.xyz, r0.w, r0
+    mul r1, r0.y, c5
+    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_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
+div r0.xyz, r0.xyzx, r0.wwww
+add r0.xyzw, r0.xyzw, -cb0[8].xyzw
+mul r0.xyz, r0.wwww, r0.xyzx
+mul r1.xyzw, r0.yyyy, cb0[5].xyzw
+mad r1.xyzw, cb0[4].xyzw, r0.xxxx, r1.xyzw
+mad r1.xyzw, cb0[6].xyzw, r0.zzzz, r1.xyzw
+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, 250,  65, 
+     94, 205, 254, 155,  52,  90, 
+     43, 147, 203, 201, 141,  74, 
+     80, 143,   1,   0,   0,   0, 
+     68,   7,   0,   0,   6,   0, 
+      0,   0,  56,   0,   0,   0, 
+    152,   1,   0,   0, 160,   3, 
+      0,   0,  28,   4,   0,   0, 
+    184,   6,   0,   0, 236,   6, 
+      0,   0,  65, 111, 110,  57, 
+     88,   1,   0,   0,  88,   1, 
+      0,   0,   0,   2, 254, 255, 
+     24,   1,   0,   0,  64,   0, 
+      0,   0,   2,   0,  36,   0, 
+      0,   0,  60,   0,   0,   0, 
+     60,   0,   0,   0,  36,   0, 
+      1,   0,  60,   0,   0,   0, 
+      0,   0,   2,   0,   1,   0, 
+      0,   0,   0,   0,   0,   0, 
+      3,   0,   8,   0,   3,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   1,   2, 254, 255, 
+     31,   0,   0,   2,   5,   0, 
+      0, 128,   0,   0,  15, 144, 
+      4,   0,   0,   4,   0,   0, 
+      3, 224,   0,   0, 228, 144, 
+      9,   0, 238, 160,   9,   0, 
+    228, 160,   4,   0,   0,   4, 
+      0,   0,   3, 128,   0,   0, 
+    228, 144,  10,   0, 238, 160, 
+     10,   0, 228, 160,   5,   0, 
+      0,   3,   1,   0,  15, 128, 
+      0,   0,  85, 128,   2,   0, 
+    228, 160,   4,   0,   0,   4, 
+      0,   0,  15, 128,   1,   0, 
+    228, 160,   0,   0,   0, 128, 
+      1,   0, 228, 128,   2,   0, 
+      0,   3,   0,   0,  15, 128, 
+      0,   0, 228, 128,   3,   0, 
+    228, 160,   6,   0,   0,   2, 
+      1,   0,   1, 128,   0,   0, 
+    255, 128,   5,   0,   0,   3, 
+      0,   0,   7, 128,   0,   0, 
+    228, 128,   1,   0,   0, 128, 
+      2,   0,   0,   3,   0,   0, 
+     15, 128,   0,   0, 228, 128, 
+      8,   0, 228, 161,   5,   0, 
+      0,   3,   0,   0,   7, 128, 
+      0,   0, 255, 128,   0,   0, 
+    228, 128,   5,   0,   0,   3, 
+      1,   0,  15, 128,   0,   0, 
+     85, 128,   5,   0, 228, 160, 
+      4,   0,   0,   4,   1,   0, 
+     15, 128,   4,   0, 228, 160, 
+      0,   0,   0, 128,   1,   0, 
+    228, 128,   4,   0,   0,   4, 
+      1,   0,  15, 128,   6,   0, 
+    228, 160,   0,   0, 170, 128, 
+      1,   0, 228, 128,   4,   0, 
+      0,   4,   0,   0,  15, 128, 
+      7,   0, 228, 160,   0,   0, 
+    255, 128,   1,   0, 228, 128, 
+      4,   0,   0,   4,   0,   0, 
+      3, 192,   0,   0, 255, 128, 
+      0,   0, 228, 160,   0,   0, 
+    228, 128,   1,   0,   0,   2, 
+      0,   0,  12, 192,   0,   0, 
+    228, 128, 255, 255,   0,   0, 
+     83,  72,  68,  82,   0,   2, 
+      0,   0,  64,   0,   1,   0, 
+    128,   0,   0,   0,  89,   0, 
+      0,   4,  70, 142,  32,   0, 
+      0,   0,   0,   0,  11,   0, 
+      0,   0,  95,   0,   0,   3, 
+     50,  16,  16,   0,   0,   0, 
+      0,   0, 103,   0,   0,   4, 
+    242,  32,  16,   0,   0,   0, 
+      0,   0,   1,   0,   0,   0, 
+    101,   0,   0,   3,  50,  32, 
+     16,   0,   1,   0,   0,   0, 
+    104,   0,   0,   2,   2,   0, 
+      0,   0,  50,   0,   0,  11, 
+     50,   0,  16,   0,   0,   0, 
+      0,   0,  70,  16,  16,   0, 
+      0,   0,   0,   0, 230, 138, 
+     32,   0,   0,   0,   0,   0, 
+     10,   0,   0,   0,  70, 128, 
+     32,   0,   0,   0,   0,   0, 
+     10,   0,   0,   0,  56,   0, 
+      0,   8, 242,   0,  16,   0, 
+      1,   0,   0,   0,  86,   5, 
+     16,   0,   0,   0,   0,   0, 
+     70, 142,  32,   0,   0,   0, 
+      0,   0,   1,   0,   0,   0, 
+     50,   0,   0,  10, 242,   0, 
+     16,   0,   0,   0,   0,   0, 
+     70, 142,  32,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      6,   0,  16,   0,   0,   0, 
+      0,   0,  70,  14,  16,   0, 
+      1,   0,   0,   0,   0,   0, 
+      0,   8, 242,   0,  16,   0, 
+      0,   0,   0,   0,  70,  14, 
+     16,   0,   0,   0,   0,   0, 
+     70, 142,  32,   0,   0,   0, 
+      0,   0,   3,   0,   0,   0, 
+     14,   0,   0,   7, 114,   0, 
+     16,   0,   0,   0,   0,   0, 
+     70,   2,  16,   0,   0,   0, 
+      0,   0, 246,  15,  16,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   9, 242,   0,  16,   0, 
+      0,   0,   0,   0,  70,  14, 
+     16,   0,   0,   0,   0,   0, 
+     70, 142,  32, 128,  65,   0, 
+      0,   0,   0,   0,   0,   0, 
+      8,   0,   0,   0,  56,   0, 
+      0,   7, 114,   0,  16,   0, 
+      0,   0,   0,   0, 246,  15, 
+     16,   0,   0,   0,   0,   0, 
+     70,   2,  16,   0,   0,   0, 
+      0,   0,  56,   0,   0,   8, 
+    242,   0,  16,   0,   1,   0, 
+      0,   0,  86,   5,  16,   0, 
+      0,   0,   0,   0,  70, 142, 
+     32,   0,   0,   0,   0,   0, 
+      5,   0,   0,   0,  50,   0, 
+      0,  10, 242,   0,  16,   0, 
+      1,   0,   0,   0,  70, 142, 
+     32,   0,   0,   0,   0,   0, 
+      4,   0,   0,   0,   6,   0, 
+     16,   0,   0,   0,   0,   0, 
+     70,  14,  16,   0,   1,   0, 
+      0,   0,  50,   0,   0,  10, 
+    242,   0,  16,   0,   1,   0, 
+      0,   0,  70, 142,  32,   0, 
+      0,   0,   0,   0,   6,   0, 
+      0,   0, 166,  10,  16,   0, 
+      0,   0,   0,   0,  70,  14, 
+     16,   0,   1,   0,   0,   0, 
+     50,   0,   0,  10, 242,  32, 
+     16,   0,   0,   0,   0,   0, 
+     70, 142,  32,   0,   0,   0, 
+      0,   0,   7,   0,   0,   0, 
+    246,  15,  16,   0,   0,   0, 
+      0,   0,  70,  14,  16,   0, 
+      1,   0,   0,   0,  50,   0, 
+      0,  11,  50,  32,  16,   0, 
+      1,   0,   0,   0,  70,  16, 
+     16,   0,   0,   0,   0,   0, 
+    230, 138,  32,   0,   0,   0, 
+      0,   0,   9,   0,   0,   0, 
+     70, 128,  32,   0,   0,   0, 
+      0,   0,   9,   0,   0,   0, 
+     62,   0,   0,   1,  83,  84, 
+     65,  84, 116,   0,   0,   0, 
+     13,   0,   0,   0,   2,   0, 
+      0,   0,   0,   0,   0,   0, 
+      3,   0,   0,   0,  12,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   1,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   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, 
+      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,   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,   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, 
+      0,   0, 120,   1,   0,   0, 
+      0,   0,   0,   0, 148,   1, 
+      0,   0, 128,   0,   0,   0, 
+     16,   0,   0,   0,   2,   0, 
+      0,   0, 168,   1,   0,   0, 
+      0,   0,   0,   0, 184,   1, 
+      0,   0, 144,   0,   0,   0, 
+     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, 
+     16,   0,   0,   0,   0,   0, 
+      0,   0, 168,   1,   0,   0, 
+      0,   0,   0,   0,  12,   2, 
+      0,   0,  16,   1,   0,   0, 
+      4,   0,   0,   0,   0,   0, 
+      0,   0,  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, 
+     44,   0,   0,   0,   0,   0, 
+      0,   0,  92,   2,   0,   0, 
+      0,   0,   0,   0, 109,  76, 
+     97, 121, 101, 114,  84, 114, 
+     97, 110, 115, 102, 111, 114, 
+    109,   0,   3,   0,   3,   0, 
+      4,   0,   4,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+    109,  80, 114, 111, 106, 101, 
+     99, 116, 105, 111, 110,   0, 
+    118,  82, 101, 110, 100, 101, 
+    114,  84,  97, 114, 103, 101, 
+    116,  79, 102, 102, 115, 101, 
+    116,   0,   1,   0,   3,   0, 
+      1,   0,   4,   0,   0,   0, 
+      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,  44,   0,   0,   0, 
+      1,   0,   0,   0,   8,   0, 
+      0,   0,  32,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   3,   0,   0,   0, 
+      0,   0,   0,   0,   3,   3, 
+      0,   0,  80,  79,  83,  73, 
+     84,  73,  79,  78,   0, 171, 
+    171, 171,  79,  83,  71,  78, 
+     80,   0,   0,   0,   2,   0, 
+      0,   0,   8,   0,   0,   0, 
+     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 10.1
-//
-//
-// Buffer Definitions: 
-//
-// cbuffer $Globals
-// {
-//
-//   float4 fLayerColor;                // Offset:    0 Size:    16
-//   float fLayerOpacity;               // Offset:   16 Size:     4 [unused]
-//   uint4 iBlendConfig;                // Offset:   32 Size:    16 [unused]
-//   row_major float3x3 mYuvColorMatrix;// Offset:   48 Size:    44 [unused]
-//   float4x4 mLayerTransform;          // Offset:   96 Size:    64 [unused]
-//   float4x4 mProjection;              // Offset:  160 Size:    64 [unused]
-//   float4 vRenderTargetOffset;        // Offset:  224 Size:    16 [unused]
-//   float4 vTextureCoords;             // Offset:  240 Size:    16 [unused]
-//   float4 vLayerQuad;                 // Offset:  256 Size:    16 [unused]
-//   float4 vMaskQuad;                  // Offset:  272 Size:    16 [unused]
-//   float4x4 mBackdropTransform;       // Offset:  288 Size:    64 [unused]
-//
-// }
-//
-//
-// Resource Bindings:
-//
-// Name                                 Type  Format         Dim      HLSL Bind  Count
-// ------------------------------ ---------- ------- ----------- -------------- ------
-// $Globals                          cbuffer      NA          NA            cb0      1 
-//
-//
-//
-// Input signature:
-//
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Position              0   xyzw        0      POS   float       
-// TEXCOORD                 0   xy          1     NONE   float       
-//
-//
-// Output signature:
-//
-// Name                 Index   Mask Register SysValue  Format   Used
-// -------------------- ----- ------ -------- -------- ------- ------
-// SV_Target                0   xyzw        0   TARGET   float   xyzw
-//
-//
-// Constant buffer to DX9 shader constant mappings:
-//
-// Target Reg Buffer  Start Reg # of Regs        Data Conversion
-// ---------- ------- --------- --------- ----------------------
-// c0         cb0             0         1  ( FLT, FLT, FLT, FLT)
-//
-//
-// Level9 shader bytecode:
-//
-    ps_2_x
-    mov oC0, c0
-
-// approximately 1 instruction slot used
-ps_4_0
-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, 181,   3, 
-     20,   0, 202,  78, 164,  59, 
-    210, 171, 118, 253, 118, 104, 
-    133, 184,   1,   0,   0,   0, 
-    112,   4,   0,   0,   6,   0, 
-      0,   0,  56,   0,   0,   0, 
-    132,   0,   0,   0, 204,   0, 
-      0,   0,  72,   1,   0,   0, 
-    228,   3,   0,   0,  60,   4, 
-      0,   0,  65, 111, 110,  57, 
-     68,   0,   0,   0,  68,   0, 
-      0,   0,   0,   2, 255, 255, 
-     20,   0,   0,   0,  48,   0, 
-      0,   0,   1,   0,  36,   0, 
-      0,   0,  48,   0,   0,   0, 
-     48,   0,   0,   0,  36,   0, 
-      0,   0,  48,   0,   0,   0, 
-      0,   0,   1,   0,   0,   0, 
-      0,   0,   0,   0,   1,   2, 
-    255, 255,   1,   0,   0,   2, 
-      0,   8,  15, 128,   0,   0, 
-    228, 160, 255, 255,   0,   0, 
-     83,  72,  68,  82,  64,   0, 
-      0,   0,  64,   0,   0,   0, 
-     16,   0,   0,   0,  89,   0, 
-      0,   4,  70, 142,  32,   0, 
-      0,   0,   0,   0,   1,   0, 
-      0,   0, 101,   0,   0,   3, 
-    242,  32,  16,   0,   0,   0, 
-      0,   0,  54,   0,   0,   6, 
-    242,  32,  16,   0,   0,   0, 
-      0,   0,  70, 142,  32,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,  62,   0,   0,   1, 
-     83,  84,  65,  84, 116,   0, 
-      0,   0,   2,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   1,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      1,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      1,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   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,   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, 
-      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, 
-      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, 
-      0,   0,   0,   0,   0,   0, 
-    164,   1,   0,   0,  32,   0, 
-      0,   0,  16,   0,   0,   0, 
-      0,   0,   0,   0, 180,   1, 
-      0,   0,   0,   0,   0,   0, 
-    196,   1,   0,   0,  48,   0, 
-      0,   0,  44,   0,   0,   0, 
-      0,   0,   0,   0, 212,   1, 
-      0,   0,   0,   0,   0,   0, 
-    228,   1,   0,   0,  96,   0, 
-      0,   0,  64,   0,   0,   0, 
-      0,   0,   0,   0, 244,   1, 
-      0,   0,   0,   0,   0,   0, 
-      4,   2,   0,   0, 160,   0, 
-      0,   0,  64,   0,   0,   0, 
-      0,   0,   0,   0, 244,   1, 
-      0,   0,   0,   0,   0,   0, 
-     16,   2,   0,   0, 224,   0, 
-      0,   0,  16,   0,   0,   0, 
-      0,   0,   0,   0, 116,   1, 
-      0,   0,   0,   0,   0,   0, 
-     36,   2,   0,   0, 240,   0, 
-      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, 
-    102,  76,  97, 121, 101, 114, 
-     67, 111, 108, 111, 114,   0, 
-      1,   0,   3,   0,   1,   0, 
-      4,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0, 102,  76, 
-     97, 121, 101, 114,  79, 112, 
-     97,  99, 105, 116, 121,   0, 
-    171, 171,   0,   0,   3,   0, 
-      1,   0,   1,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-    105,  66, 108, 101, 110, 100, 
-     67, 111, 110, 102, 105, 103, 
-      0, 171, 171, 171,   1,   0, 
-     19,   0,   1,   0,   4,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0, 109,  89, 117, 118, 
-     67, 111, 108, 111, 114,  77, 
-     97, 116, 114, 105, 120,   0, 
-      2,   0,   3,   0,   3,   0, 
-      3,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0, 109,  76, 
-     97, 121, 101, 114,  84, 114, 
-     97, 110, 115, 102, 111, 114, 
-    109,   0,   3,   0,   3,   0, 
-      4,   0,   4,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-    109,  80, 114, 111, 106, 101, 
-     99, 116, 105, 111, 110,   0, 
-    118,  82, 101, 110, 100, 101, 
-    114,  84,  97, 114, 103, 101, 
-    116,  79, 102, 102, 115, 101, 
-    116,   0, 118,  84, 101, 120, 
-    116, 117, 114, 101,  67, 111, 
-    111, 114, 100, 115,   0, 171, 
-      1,   0,   3,   0,   1,   0, 
-      4,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0, 118,  76, 
-     97, 121, 101, 114,  81, 117, 
-     97, 100,   0, 118,  77,  97, 
-    115, 107,  81, 117,  97, 100, 
-      0, 109,  66,  97,  99, 107, 
-    100, 114, 111, 112,  84, 114, 
-     97, 110, 115, 102, 111, 114, 
-    109,   0,  77, 105,  99, 114, 
-    111, 115, 111, 102, 116,  32, 
-     40,  82,  41,  32,  72,  76, 
-     83,  76,  32,  83, 104,  97, 
-    100, 101, 114,  32,  67, 111, 
-    109, 112, 105, 108, 101, 114, 
-     32,  49,  48,  46,  49,   0, 
-     73,  83,  71,  78,  80,   0, 
-      0,   0,   2,   0,   0,   0, 
-      8,   0,   0,   0,  56,   0, 
-      0,   0,   0,   0,   0,   0, 
-      1,   0,   0,   0,   3,   0, 
-      0,   0,   0,   0,   0,   0, 
-     15,   0,   0,   0,  68,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   0,   0,   3,   0, 
-      0,   0,   1,   0,   0,   0, 
-      3,   0,   0,   0,  83,  86, 
-     95,  80, 111, 115, 105, 116, 
-    105, 111, 110,   0,  84,  69, 
-     88,  67,  79,  79,  82,  68, 
-      0, 171, 171, 171,  79,  83, 
-     71,  78,  44,   0,   0,   0, 
-      1,   0,   0,   0,   8,   0, 
-      0,   0,  32,   0,   0,   0, 
-      0,   0,   0,   0,   0,   0, 
-      0,   0,   3,   0,   0,   0, 
-      0,   0,   0,   0,  15,   0, 
-      0,   0,  83,  86,  95,  84, 
-     97, 114, 103, 101, 116,   0, 
-    171, 171
-};
+#if 0
+//
+// 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]
+//
+// }
+//
+//
+// Resource Bindings:
+//
+// 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  
+// TEXCOORD                 0   xy          1     NONE   float   xy  
+//
+//
+// Output signature:
+//
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Position              0   xyzw        0      POS   float   xyzw
+// TEXCOORD                 0   xy          1     NONE   float   xy  
+//
+//
+// Constant buffer to DX9 shader constant mappings:
+//
+// Target Reg Buffer  Start Reg # of Regs        Data Conversion
+// ---------- ------- --------- --------- ----------------------
+// c1         cb0             0         2  ( FLT, FLT, FLT, FLT)
+// c3         cb0             3         6  ( FLT, FLT, FLT, FLT)
+//
+//
+// Runtime generated constant mappings:
+//
+// Target Reg                               Constant Description
+// ---------- --------------------------------------------------
+// c0                              Vertex Shader position offset
+//
+//
+// Level9 shader bytecode:
+//
+    vs_2_x
+    dcl_texcoord v0
+    dcl_texcoord1 v1
+    mul r0, v0.y, c2
+    mad r0, c1, v0.x, r0
+    add r0, r0, c3
+    rcp r1.x, r0.w
+    mul r0.xyz, r0, r1.x
+    add r0, r0, -c8
+    mul r0.xyz, r0.w, r0
+    mul r1, r0.y, c5
+    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
+    mov oT0.xy, v1
+
+// approximately 14 instruction slots used
+vs_4_0
+dcl_constantbuffer CB0[9], immediateIndexed
+dcl_input v0.xy
+dcl_input v1.xy
+dcl_output_siv o0.xyzw, position
+dcl_output o1.xy
+dcl_temps 2
+mul r0.xyzw, v0.yyyy, cb0[1].xyzw
+mad r0.xyzw, cb0[0].xyzw, v0.xxxx, r0.xyzw
+add r0.xyzw, r0.xyzw, cb0[3].xyzw
+div r0.xyz, r0.xyzx, r0.wwww
+add r0.xyzw, r0.xyzw, -cb0[8].xyzw
+mul r0.xyz, r0.wwww, r0.xyzx
+mul r1.xyzw, r0.yyyy, cb0[5].xyzw
+mad r1.xyzw, cb0[4].xyzw, r0.xxxx, r1.xyzw
+mad r1.xyzw, cb0[6].xyzw, r0.zzzz, r1.xyzw
+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, 
+      0,   0,  56,   0,   0,   0, 
+    136,   1,   0,   0,  88,   3, 
+      0,   0, 212,   3,   0,   0, 
+    112,   6,   0,   0, 196,   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, 
+      0,   0,   2,   0,   1,   0, 
+      0,   0,   0,   0,   0,   0, 
+      3,   0,   6,   0,   3,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   1,   2, 254, 255, 
+     31,   0,   0,   2,   5,   0, 
+      0, 128,   0,   0,  15, 144, 
+     31,   0,   0,   2,   5,   0, 
+      1, 128,   1,   0,  15, 144, 
+      5,   0,   0,   3,   0,   0, 
+     15, 128,   0,   0,  85, 144, 
+      2,   0, 228, 160,   4,   0, 
+      0,   4,   0,   0,  15, 128, 
+      1,   0, 228, 160,   0,   0, 
+      0, 144,   0,   0, 228, 128, 
+      2,   0,   0,   3,   0,   0, 
+     15, 128,   0,   0, 228, 128, 
+      3,   0, 228, 160,   6,   0, 
+      0,   2,   1,   0,   1, 128, 
+      0,   0, 255, 128,   5,   0, 
+      0,   3,   0,   0,   7, 128, 
+      0,   0, 228, 128,   1,   0, 
+      0, 128,   2,   0,   0,   3, 
+      0,   0,  15, 128,   0,   0, 
+    228, 128,   8,   0, 228, 161, 
+      5,   0,   0,   3,   0,   0, 
+      7, 128,   0,   0, 255, 128, 
+      0,   0, 228, 128,   5,   0, 
+      0,   3,   1,   0,  15, 128, 
+      0,   0,  85, 128,   5,   0, 
+    228, 160,   4,   0,   0,   4, 
+      1,   0,  15, 128,   4,   0, 
+    228, 160,   0,   0,   0, 128, 
+      1,   0, 228, 128,   4,   0, 
+      0,   4,   1,   0,  15, 128, 
+      6,   0, 228, 160,   0,   0, 
+    170, 128,   1,   0, 228, 128, 
+      4,   0,   0,   4,   0,   0, 
+     15, 128,   7,   0, 228, 160, 
+      0,   0, 255, 128,   1,   0, 
+    228, 128,   4,   0,   0,   4, 
+      0,   0,   3, 192,   0,   0, 
+    255, 128,   0,   0, 228, 160, 
+      0,   0, 228, 128,   1,   0, 
+      0,   2,   0,   0,  12, 192, 
+      0,   0, 228, 128,   1,   0, 
+      0,   2,   0,   0,   3, 224, 
+      1,   0, 228, 144, 255, 255, 
+      0,   0,  83,  72,  68,  82, 
+    200,   1,   0,   0,  64,   0, 
+      1,   0, 114,   0,   0,   0, 
+     89,   0,   0,   4,  70, 142, 
+     32,   0,   0,   0,   0,   0, 
+      9,   0,   0,   0,  95,   0, 
+      0,   3,  50,  16,  16,   0, 
+      0,   0,   0,   0,  95,   0, 
+      0,   3,  50,  16,  16,   0, 
+      1,   0,   0,   0, 103,   0, 
+      0,   4, 242,  32,  16,   0, 
+      0,   0,   0,   0,   1,   0, 
+      0,   0, 101,   0,   0,   3, 
+     50,  32,  16,   0,   1,   0, 
+      0,   0, 104,   0,   0,   2, 
+      2,   0,   0,   0,  56,   0, 
+      0,   8, 242,   0,  16,   0, 
+      0,   0,   0,   0,  86,  21, 
+     16,   0,   0,   0,   0,   0, 
+     70, 142,  32,   0,   0,   0, 
+      0,   0,   1,   0,   0,   0, 
+     50,   0,   0,  10, 242,   0, 
+     16,   0,   0,   0,   0,   0, 
+     70, 142,  32,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      6,  16,  16,   0,   0,   0, 
+      0,   0,  70,  14,  16,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   8, 242,   0,  16,   0, 
+      0,   0,   0,   0,  70,  14, 
+     16,   0,   0,   0,   0,   0, 
+     70, 142,  32,   0,   0,   0, 
+      0,   0,   3,   0,   0,   0, 
+     14,   0,   0,   7, 114,   0, 
+     16,   0,   0,   0,   0,   0, 
+     70,   2,  16,   0,   0,   0, 
+      0,   0, 246,  15,  16,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   9, 242,   0,  16,   0, 
+      0,   0,   0,   0,  70,  14, 
+     16,   0,   0,   0,   0,   0, 
+     70, 142,  32, 128,  65,   0, 
+      0,   0,   0,   0,   0,   0, 
+      8,   0,   0,   0,  56,   0, 
+      0,   7, 114,   0,  16,   0, 
+      0,   0,   0,   0, 246,  15, 
+     16,   0,   0,   0,   0,   0, 
+     70,   2,  16,   0,   0,   0, 
+      0,   0,  56,   0,   0,   8, 
+    242,   0,  16,   0,   1,   0, 
+      0,   0,  86,   5,  16,   0, 
+      0,   0,   0,   0,  70, 142, 
+     32,   0,   0,   0,   0,   0, 
+      5,   0,   0,   0,  50,   0, 
+      0,  10, 242,   0,  16,   0, 
+      1,   0,   0,   0,  70, 142, 
+     32,   0,   0,   0,   0,   0, 
+      4,   0,   0,   0,   6,   0, 
+     16,   0,   0,   0,   0,   0, 
+     70,  14,  16,   0,   1,   0, 
+      0,   0,  50,   0,   0,  10, 
+    242,   0,  16,   0,   1,   0, 
+      0,   0,  70, 142,  32,   0, 
+      0,   0,   0,   0,   6,   0, 
+      0,   0, 166,  10,  16,   0, 
+      0,   0,   0,   0,  70,  14, 
+     16,   0,   1,   0,   0,   0, 
+     50,   0,   0,  10, 242,  32, 
+     16,   0,   0,   0,   0,   0, 
+     70, 142,  32,   0,   0,   0, 
+      0,   0,   7,   0,   0,   0, 
+    246,  15,  16,   0,   0,   0, 
+      0,   0,  70,  14,  16,   0, 
+      1,   0,   0,   0,  54,   0, 
+      0,   5,  50,  32,  16,   0, 
+      1,   0,   0,   0,  70,  16, 
+     16,   0,   1,   0,   0,   0, 
+     62,   0,   0,   1,  83,  84, 
+     65,  84, 116,   0,   0,   0, 
+     12,   0,   0,   0,   2,   0, 
+      0,   0,   0,   0,   0,   0, 
+      4,   0,   0,   0,  10,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   1,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   1,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,  82,  68,  69,  70, 
+    148,   2,   0,   0,   1,   0, 
+      0,   0,  72,   0,   0,   0, 
+      1,   0,   0,   0,  28,   0, 
+      0,   0,   0,   4, 254, 255, 
+      0,   1,   0,   0, 108,   2, 
+      0,   0,  60,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   1,   0,   0,   0, 
+      0,   0,   0,   0,  36,  71, 
+    108, 111,  98,  97, 108, 115, 
+      0, 171, 171, 171,  60,   0, 
+      0,   0,  11,   0,   0,   0, 
+     96,   0,   0,   0,  96,   1, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0, 104,   1, 
+      0,   0,   0,   0,   0,   0, 
+     64,   0,   0,   0,   2,   0, 
+      0,   0, 120,   1,   0,   0, 
+      0,   0,   0,   0, 136,   1, 
+      0,   0,  64,   0,   0,   0, 
+     64,   0,   0,   0,   2,   0, 
+      0,   0, 120,   1,   0,   0, 
+      0,   0,   0,   0, 148,   1, 
+      0,   0, 128,   0,   0,   0, 
+     16,   0,   0,   0,   2,   0, 
+      0,   0, 168,   1,   0,   0, 
+      0,   0,   0,   0, 184,   1, 
+      0,   0, 144,   0,   0,   0, 
+     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, 
+     16,   0,   0,   0,   0,   0, 
+      0,   0, 168,   1,   0,   0, 
+      0,   0,   0,   0,  12,   2, 
+      0,   0,  16,   1,   0,   0, 
+      4,   0,   0,   0,   0,   0, 
+      0,   0,  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, 
+     44,   0,   0,   0,   0,   0, 
+      0,   0,  92,   2,   0,   0, 
+      0,   0,   0,   0, 109,  76, 
+     97, 121, 101, 114,  84, 114, 
+     97, 110, 115, 102, 111, 114, 
+    109,   0,   3,   0,   3,   0, 
+      4,   0,   4,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+    109,  80, 114, 111, 106, 101, 
+     99, 116, 105, 111, 110,   0, 
+    118,  82, 101, 110, 100, 101, 
+    114,  84,  97, 114, 103, 101, 
+    116,  79, 102, 102, 115, 101, 
+    116,   0,   1,   0,   3,   0, 
+      1,   0,   4,   0,   0,   0, 
+      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
+};
+ShaderBytes sLayerDynamicVS = { LayerDynamicVS, sizeof(LayerDynamicVS) };
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 10.1
+//
+//
+// Buffer Definitions: 
+//
+// cbuffer $Globals
+// {
+//
+//   float4 fLayerColor;                // Offset:    0 Size:    16
+//   float fLayerOpacity;               // Offset:   16 Size:     4 [unused]
+//   uint4 iBlendConfig;                // Offset:   32 Size:    16 [unused]
+//   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]