Merge m-i to m-c, a=merge
authorPhil Ringnalda <philringnalda@gmail.com>
Sat, 14 Jan 2017 09:38:58 -0800
changeset 374460 5ce3882eec21be3a70e4afc050959ca2f76bfa76
parent 374404 a5fd4e171cf7db1851a9a4d7b26995aaceb25b2d (current diff)
parent 374459 c78097a585e0335fa82555aa9595ff2fa6e4f204 (diff)
child 374461 cab8337789bcbd783c263262f3a8cb5f10a67812
child 374464 426109521b9a0fa5bdac77ce9c21da19b1c51b95
child 374489 383b301471d8f069cd799bb8f5a7c12bc73b1c6f
push id6996
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 20:48:21 +0000
treeherdermozilla-beta@d89512dab048 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone53.0a1
first release with
nightly linux32
5ce3882eec21 / 53.0a1 / 20170115030210 / files
nightly linux64
5ce3882eec21 / 53.0a1 / 20170115030210 / files
nightly mac
5ce3882eec21 / 53.0a1 / 20170115030210 / files
nightly win32
5ce3882eec21 / 53.0a1 / 20170115030210 / files
nightly win64
5ce3882eec21 / 53.0a1 / 20170115030210 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-i to m-c, a=merge MozReview-Commit-ID: 1NtOkt6oQ7d
browser/app/profile/firefox.js
browser/base/content/browser-devedition.js
browser/base/content/defaultthemes/devedition.header.png
browser/base/content/defaultthemes/devedition.icon.png
browser/base/content/test/general/browser_devedition.js
browser/themes/linux/devedition.css
browser/themes/linux/social/share-button-active.png
browser/themes/linux/social/share-button.png
browser/themes/osx/devedition.css
browser/themes/shared/devedition.inc.css
browser/themes/windows/devedition.css
layout/style/moz.build
testing/mochitest/runtests.py
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1128,17 +1128,17 @@ pref("services.sync.prefs.sync.xpinstall
 // fetching these icons to show remote tabs may leak information about that
 // user's tabs and bookmarks. Note this pref is also synced.
 pref("services.sync.syncedTabs.showRemoteIcons", true);
 
 pref("services.sync.sendTabToDevice.enabled", true);
 
 // Developer edition preferences
 #ifdef MOZ_DEV_EDITION
-sticky_pref("lightweightThemes.selectedThemeID", "firefox-devedition@mozilla.org");
+sticky_pref("lightweightThemes.selectedThemeID", "firefox-compact-dark@mozilla.org");
 #else
 sticky_pref("lightweightThemes.selectedThemeID", "");
 #endif
 
 // Whether the character encoding menu is under the main Firefox button. This
 // preference is a string so that localizers can alter it.
 pref("browser.menu.showCharacterEncoding", "chrome://browser/locale/browser.properties");
 
rename from browser/base/content/browser-devedition.js
rename to browser/base/content/browser-compacttheme.js
--- a/browser/base/content/browser-devedition.js
+++ b/browser/base/content/browser-compacttheme.js
@@ -1,37 +1,35 @@
 /* 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/. */
 
 /**
- * Listeners for the DevEdition theme.  This adds an extra stylesheet
+ * Listeners for the compact theme.  This adds an extra stylesheet
  * to browser.xul if a pref is set and no other themes are applied.
  */
-var DevEdition = {
-  _devtoolsThemePrefName: "devtools.theme",
-  styleSheetLocation: "chrome://browser/skin/devedition.css",
+var CompactTheme = {
+  styleSheetLocation: "chrome://browser/skin/compacttheme.css",
   styleSheet: null,
   initialized: false,
 
   get isStyleSheetEnabled() {
     return this.styleSheet && !this.styleSheet.sheet.disabled;
   },
 
   get isThemeCurrentlyApplied() {
     let theme = LightweightThemeManager.currentTheme;
-    return theme && theme.id == "firefox-devedition@mozilla.org";
+    return theme && (
+           theme.id == "firefox-compact-dark@mozilla.org" ||
+           theme.id == "firefox-compact-light@mozilla.org");
   },
 
   init() {
     this.initialized = true;
-    Services.prefs.addObserver(this._devtoolsThemePrefName, this, false);
     Services.obs.addObserver(this, "lightweight-theme-styling-update", false);
-    Services.obs.addObserver(this, "lightweight-theme-window-updated", false);
-    this._updateDevtoolsThemeAttribute();
 
     if (this.isThemeCurrentlyApplied) {
       this._toggleStyleSheet(true);
     }
   },
 
   createStyleSheet() {
     let styleSheetAttr = `href="${this.styleSheetLocation}" type="text/css"`;
@@ -40,103 +38,68 @@ var DevEdition = {
     this.styleSheet.addEventListener("load", this);
     document.insertBefore(this.styleSheet, document.documentElement);
     this.styleSheet.sheet.disabled = true;
   },
 
   observe(subject, topic, data) {
     if (topic == "lightweight-theme-styling-update") {
       let newTheme = JSON.parse(data);
-      if (newTheme && newTheme.id == "firefox-devedition@mozilla.org") {
+      if (newTheme && (
+          newTheme.id == "firefox-compact-light@mozilla.org" ||
+          newTheme.id == "firefox-compact-dark@mozilla.org")) {
+        // We are using the theme ID on this object instead of always referencing
+        // LightweightThemeManager.currentTheme in case this is a preview
         this._toggleStyleSheet(true);
       } else {
         this._toggleStyleSheet(false);
       }
-    } else if (topic == "lightweight-theme-window-updated" && subject == window) {
-      this._updateLWTBrightness();
-    }
 
-    if (topic == "nsPref:changed" && data == this._devtoolsThemePrefName) {
-      this._updateDevtoolsThemeAttribute();
-    }
-  },
-
-  _inferBrightness() {
-    ToolbarIconColor.inferFromText();
-    // Get an inverted full screen button if the dark theme is applied.
-    if (this.isStyleSheetEnabled &&
-        document.documentElement.getAttribute("devtoolstheme") == "dark") {
-      document.documentElement.setAttribute("brighttitlebarforeground", "true");
-    } else {
-      document.documentElement.removeAttribute("brighttitlebarforeground");
     }
   },
 
-  _updateLWTBrightness() {
-    if (this.isThemeCurrentlyApplied) {
-      let devtoolsTheme = Services.prefs.getCharPref(this._devtoolsThemePrefName);
-      let textColor = devtoolsTheme == "dark" ? "bright" : "dark";
-      document.documentElement.setAttribute("lwthemetextcolor", textColor);
-    }
-  },
-
-  _updateDevtoolsThemeAttribute() {
-    // Set an attribute on root element to make it possible
-    // to change colors based on the selected devtools theme.
-    let devtoolsTheme = Services.prefs.getCharPref(this._devtoolsThemePrefName);
-    if (devtoolsTheme != "dark") {
-      devtoolsTheme = "light";
-    }
-    document.documentElement.setAttribute("devtoolstheme", devtoolsTheme);
-    this._updateLWTBrightness();
-    this._inferBrightness();
-  },
-
   handleEvent(e) {
     if (e.type === "load") {
       this.styleSheet.removeEventListener("load", this);
       this.refreshBrowserDisplay();
     }
   },
 
   refreshBrowserDisplay() {
     // Don't touch things on the browser if gBrowserInit.onLoad hasn't
     // yet fired.
     if (this.initialized) {
       gBrowser.tabContainer._positionPinnedTabs();
-      this._inferBrightness();
     }
   },
 
-  _toggleStyleSheet(deveditionThemeEnabled) {
+  _toggleStyleSheet(enabled) {
     let wasEnabled = this.isStyleSheetEnabled;
-    if (deveditionThemeEnabled && !wasEnabled) {
+    if (enabled) {
       // The stylesheet may not have been created yet if it wasn't
       // needed on initial load.  Make it now.
       if (!this.styleSheet) {
         this.createStyleSheet();
       }
       this.styleSheet.sheet.disabled = false;
       this.refreshBrowserDisplay();
-    } else if (!deveditionThemeEnabled && wasEnabled) {
+    } else if (!enabled && wasEnabled) {
       this.styleSheet.sheet.disabled = true;
       this.refreshBrowserDisplay();
     }
   },
 
   uninit() {
-    Services.prefs.removeObserver(this._devtoolsThemePrefName, this);
     Services.obs.removeObserver(this, "lightweight-theme-styling-update");
-    Services.obs.removeObserver(this, "lightweight-theme-window-updated");
     if (this.styleSheet) {
       this.styleSheet.removeEventListener("load", this);
     }
     this.styleSheet = null;
   }
 };
 
-// If the DevEdition theme is going to be applied in gBrowserInit.onLoad,
+// If the compact theme is going to be applied in gBrowserInit.onLoad,
 // then preload it now.  This prevents a flash of unstyled content where the
-// normal theme is applied while the DevEdition stylesheet is loading.
-if (!AppConstants.RELEASE_OR_BETA &&
-    this != Services.appShell.hiddenDOMWindow && DevEdition.isThemeCurrentlyApplied) {
-  DevEdition.createStyleSheet();
+// normal theme is applied while the compact theme stylesheet is loading.
+if (AppConstants.INSTALL_COMPACT_THEMES &&
+    this != Services.appShell.hiddenDOMWindow && CompactTheme.isThemeCurrentlyApplied) {
+  CompactTheme.createStyleSheet();
 }
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -993,17 +993,17 @@ var gBrowserInit = {
     // loading the frame script to ensure that we don't miss any
     // message sent between when the frame script is loaded and when
     // the listener is registered.
     DOMLinkHandler.init();
     gPageStyleMenu.init();
     LanguageDetectionListener.init();
     BrowserOnClick.init();
     FeedHandler.init();
-    DevEdition.init();
+    CompactTheme.init();
     AboutPrivateBrowsingListener.init();
     TrackingProtection.init();
     RefreshBlocker.init();
 
     let mm = window.getGroupMessageManager("browsers");
     mm.loadFrameScript("chrome://browser/content/tab-content.js", true);
     mm.loadFrameScript("chrome://browser/content/content.js", true);
     mm.loadFrameScript("chrome://browser/content/content-UITour.js", true);
@@ -1510,17 +1510,17 @@ var gBrowserInit = {
     TabletModeUpdater.uninit();
 
     gTabletModePageCounter.finish();
 
     BrowserOnClick.uninit();
 
     FeedHandler.uninit();
 
-    DevEdition.uninit();
+    CompactTheme.uninit();
 
     TrackingProtection.uninit();
 
     RefreshBlocker.uninit();
 
     gMenuButtonUpdateBadge.uninit();
 
     gMenuButtonBadgeManager.uninit();
rename from browser/base/content/defaultthemes/devedition.header.png
rename to browser/base/content/defaultthemes/compact.header.png
new file mode 100644
--- /dev/null
+++ b/browser/base/content/defaultthemes/compactdark.icon.svg
@@ -0,0 +1,16 @@
+<?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" width="32" height="32">
+    <rect fill="#727780" x="1" y="1" width="30" height="30" rx="2" ry="2"/>
+    <path fill="#393f4c" d="M3 1h26a2 2 0 0 1 2 2v14H1V3a2 2 0 0 1 2-2z"/>
+    <rect fill="#171b1f" x="3.5" y="3.5" width="25" height="11" rx="1" ry="1"/>
+    <path fill="#252c33" d="M4.5 3.5h12v11h-12a1 1 0 0 1-1-1v-9a1 1 0 0 1 1-1z"/>
+    <rect stroke="#1d2328" fill="none" stroke-width="2" x="1" y="1" width="30" height="30" rx="2" ry="2"/>
+    <path class="icon-line-2px" d="M10 6L7 9l3 3M7.5 9H13"/>
+    <path stroke="#1d2328" d="M1.5 16.5h29"/>
+    <path class="separator-toolbar-items" d="M16.5 3.5v11"/>
+    <rect fill="none" stroke="#171b1f" x="3.5" y="3.5" width="25" height="11" rx="1" ry="1"/>
+    <path fill="#f0f1f2" d="M13 8H9.4l1.3-1.3a1 1 0 0 0-1.4-1.4l-3 3a1 1 0 0 0 0 1.4l3 3a1 1 0 0 0 1.4-1.4L9.4 10H13a1 1 0 0 0 0-2z"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/defaultthemes/compactlight.icon.svg
@@ -0,0 +1,15 @@
+<?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" width="32" height="32">
+    <rect fill="#fff" x="1" y="1" width="30" height="30" rx="2" ry="2"/>
+    <path fill="#e3e3e3" d="M3 1h26a2 2 0 0 1 2 2v14H1V3a2 2 0 0 1 2-2z"/>
+    <rect fill="#fff" x="3.5" y="3.5" width="25" height="11" rx="1" ry="1"/>
+    <path fill="#fcfcfc" d="M4.5 3.5h12v11h-12a1 1 0 0 1-1-1v-9a1 1 0 0 1 1-1z"/>
+    <rect fill="none" stroke="#999" stroke-width="2" x="1" y="1" width="30" height="30" rx="2" ry="2"/>
+    <path stroke="#999" d="M1.5 16.5h29"/>
+    <path stroke="#b3b3b3" d="M16.5 3.5v11"/>
+    <rect fill="none" stroke="#b3b3b3" x="3.5" y="3.5" width="25" height="11" rx="1" ry="1"/>
+    <path fill="#595959" d="M13 8H9.4l1.3-1.3a1 1 0 0 0-1.4-1.4l-3 3a1 1 0 0 0 0 1.4l3 3a1 1 0 0 0 1.4-1.4L9.4 10H13a1 1 0 0 0 0-2z"/>
+</svg>
deleted file mode 100644
index 04cfba796dc6aa0bac6b3b368e929009bf01af52..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/browser/base/content/global-scripts.inc
+++ b/browser/base/content/global-scripts.inc
@@ -8,17 +8,17 @@
 <script type="application/javascript" src="chrome://browser/content/places/browserPlacesViews.js"/>
 <script type="application/javascript" src="chrome://browser/content/browser.js"/>
 <script type="application/javascript" src="chrome://browser/content/customizableui/panelUI.js"/>
 <script type="application/javascript" src="chrome://global/content/viewSourceUtils.js"/>
 
 <script type="application/javascript" src="chrome://browser/content/browser-addons.js"/>
 <script type="application/javascript" src="chrome://browser/content/browser-ctrlTab.js"/>
 <script type="application/javascript" src="chrome://browser/content/browser-customization.js"/>
-<script type="application/javascript" src="chrome://browser/content/browser-devedition.js"/>
+<script type="application/javascript" src="chrome://browser/content/browser-compacttheme.js"/>
 <script type="application/javascript" src="chrome://browser/content/browser-feeds.js"/>
 <script type="application/javascript" src="chrome://browser/content/browser-fullScreenAndPointerLock.js"/>
 <script type="application/javascript" src="chrome://browser/content/browser-fullZoom.js"/>
 <script type="application/javascript" src="chrome://browser/content/browser-gestureSupport.js"/>
 <script type="application/javascript" src="chrome://browser/content/browser-media.js"/>
 <script type="application/javascript" src="chrome://browser/content/browser-places.js"/>
 <script type="application/javascript" src="chrome://browser/content/browser-plugins.js"/>
 <script type="application/javascript" src="chrome://browser/content/browser-refreshblocker.js"/>
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -275,31 +275,31 @@ tags = mcb
 [browser_bug970746.js]
 [browser_bug1015721.js]
 skip-if = os == 'win'
 [browser_accesskeys.js]
 [browser_clipboard.js]
 subsuite = clipboard
 [browser_clipboard_pastefile.js]
 skip-if = true # Disabled due to the clipboard not supporting real file types yet (bug 1288773)
+[browser_compacttheme.js]
 [browser_contentAreaClick.js]
 skip-if = e10s # Clicks in content don't go through contentAreaClick with e10s.
 [browser_contentAltClick.js]
 [browser_contextmenu.js]
 subsuite = clipboard
 tags = fullscreen
 skip-if = toolkit == "gtk2" || toolkit == "gtk3" # disabled on Linux due to bug 513558
 [browser_contextmenu_input.js]
 skip-if = toolkit == "gtk2" || toolkit == "gtk3" # disabled on Linux due to bug 513558
 [browser_ctrlTab.js]
 [browser_datachoices_notification.js]
 skip-if = !datareporting
 [browser_decoderDoctor.js]
 skip-if = os == "mac" # decoder doctor isn't implemented on osx
-[browser_devedition.js]
 [browser_discovery.js]
 [browser_double_close_tab.js]
 [browser_documentnavigation.js]
 [browser_duplicateIDs.js]
 [browser_drag.js]
 skip-if = true # browser_drag.js is disabled, as it needs to be updated for the new behavior from bug 320638.
 [browser_extension_permissions.js]
 [browser_favicon_change.js]
rename from browser/base/content/test/general/browser_devedition.js
rename to browser/base/content/test/general/browser_compacttheme.js
--- a/browser/base/content/test/general/browser_devedition.js
+++ b/browser/base/content/test/general/browser_compacttheme.js
@@ -1,129 +1,90 @@
 /*
- * Testing changes for Developer Edition theme.
+ * Testing changes for compact themes.
  * A special stylesheet should be added to the browser.xul document
- * when the firefox-devedition@mozilla.org lightweight theme
- * is applied.
+ * when the firefox-compact-light and firefox-compact-dark lightweight
+ * themes are applied.
  */
 
 const PREF_LWTHEME_USED_THEMES = "lightweightThemes.usedThemes";
-const PREF_DEVTOOLS_THEME = "devtools.theme";
+const COMPACT_LIGHT_ID = "firefox-compact-light@mozilla.org";
+const COMPACT_DARK_ID = "firefox-compact-dark@mozilla.org";
+const SKIP_TEST = !AppConstants.INSTALL_COMPACT_THEMES;
 const {LightweightThemeManager} = Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm", {});
 
-LightweightThemeManager.clearBuiltInThemes();
-LightweightThemeManager.addBuiltInTheme(dummyLightweightTheme("firefox-devedition@mozilla.org"));
-
 registerCleanupFunction(() => {
   // Set preferences back to their original values
   LightweightThemeManager.currentTheme = null;
-  Services.prefs.clearUserPref(PREF_DEVTOOLS_THEME);
   Services.prefs.clearUserPref(PREF_LWTHEME_USED_THEMES);
-
-  LightweightThemeManager.currentTheme = null;
-  LightweightThemeManager.clearBuiltInThemes();
 });
 
 add_task(function* startTests() {
-  Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "dark");
+  if (SKIP_TEST) {
+    ok(true, "No need to run this test since themes aren't installed");
+    return;
+  }
 
   info("Setting the current theme to null");
   LightweightThemeManager.currentTheme = null;
-  ok(!DevEdition.isStyleSheetEnabled, "There is no devedition style sheet when no lw theme is applied.");
+  ok(!CompactTheme.isStyleSheetEnabled, "There is no compact style sheet when no lw theme is applied.");
 
   info("Adding a lightweight theme.");
   LightweightThemeManager.currentTheme = dummyLightweightTheme("preview0");
-  ok(!DevEdition.isStyleSheetEnabled, "The devedition stylesheet has been removed when a lightweight theme is applied.");
+  ok(!CompactTheme.isStyleSheetEnabled, "The compact stylesheet has been removed when a lightweight theme is applied.");
+
+  info("Applying the dark compact theme.");
+  LightweightThemeManager.currentTheme = LightweightThemeManager.getUsedTheme(COMPACT_DARK_ID);
+  ok(CompactTheme.isStyleSheetEnabled, "The compact stylesheet has been added when the compact lightweight theme is applied");
 
-  info("Applying the devedition lightweight theme.");
-  let onAttributeAdded = waitForBrightTitlebarAttribute();
-  LightweightThemeManager.currentTheme = LightweightThemeManager.getUsedTheme("firefox-devedition@mozilla.org");
-  ok(DevEdition.isStyleSheetEnabled, "The devedition stylesheet has been added when the devedition lightweight theme is applied");
-  yield onAttributeAdded;
-  is(document.documentElement.getAttribute("brighttitlebarforeground"), "true",
-     "The brighttitlebarforeground attribute is set on the window.");
+  info("Applying the light compact theme.");
+  LightweightThemeManager.currentTheme = LightweightThemeManager.getUsedTheme(COMPACT_LIGHT_ID);
+  ok(CompactTheme.isStyleSheetEnabled, "The compact stylesheet has been added when the compact lightweight theme is applied");
+
+  info("Adding a different lightweight theme.");
+  LightweightThemeManager.currentTheme = dummyLightweightTheme("preview1");
+  ok(!CompactTheme.isStyleSheetEnabled, "The compact stylesheet has been removed when a lightweight theme is applied.");
 
   info("Unapplying all themes.");
   LightweightThemeManager.currentTheme = null;
-  ok(!DevEdition.isStyleSheetEnabled, "There is no devedition style sheet when no lw theme is applied.");
-
-  info("Applying the devedition lightweight theme.");
-  onAttributeAdded = waitForBrightTitlebarAttribute();
-  LightweightThemeManager.currentTheme = LightweightThemeManager.getUsedTheme("firefox-devedition@mozilla.org");
-  ok(DevEdition.isStyleSheetEnabled, "The devedition stylesheet has been added when the devedition lightweight theme is applied");
-  yield onAttributeAdded;
-  ok(document.documentElement.hasAttribute("brighttitlebarforeground"),
-     "The brighttitlebarforeground attribute is set on the window with dark devtools theme.");
-});
-
-add_task(function* testDevtoolsTheme() {
-  info("Checking stylesheet and :root attributes based on devtools theme.");
-  Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "light");
-  is(document.documentElement.getAttribute("devtoolstheme"), "light",
-    "The documentElement has an attribute based on devtools theme.");
-  ok(DevEdition.isStyleSheetEnabled, "The devedition stylesheet is still there with the light devtools theme.");
-  ok(!document.documentElement.hasAttribute("brighttitlebarforeground"),
-     "The brighttitlebarforeground attribute is not set on the window with light devtools theme.");
-
-  Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "dark");
-  is(document.documentElement.getAttribute("devtoolstheme"), "dark",
-    "The documentElement has an attribute based on devtools theme.");
-  ok(DevEdition.isStyleSheetEnabled, "The devedition stylesheet is still there with the dark devtools theme.");
-  is(document.documentElement.getAttribute("brighttitlebarforeground"), "true",
-     "The brighttitlebarforeground attribute is set on the window with dark devtools theme.");
-
-  Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "foobar");
-  is(document.documentElement.getAttribute("devtoolstheme"), "light",
-    "The documentElement has 'light' as a default for the devtoolstheme attribute");
-  ok(DevEdition.isStyleSheetEnabled, "The devedition stylesheet is still there with the foobar devtools theme.");
-  ok(!document.documentElement.hasAttribute("brighttitlebarforeground"),
-     "The brighttitlebarforeground attribute is not set on the window with light devtools theme.");
+  ok(!CompactTheme.isStyleSheetEnabled, "There is no compact style sheet when no lw theme is applied.");
 });
 
 function dummyLightweightTheme(id) {
   return {
     id,
     name: id,
-    headerURL: "resource:///chrome/browser/content/browser/defaultthemes/devedition.header.png",
-    iconURL: "resource:///chrome/browser/content/browser/defaultthemes/devedition.icon.png",
+    headerURL: "resource:///chrome/browser/content/browser/defaultthemes/compact.header.png",
+    iconURL: "resource:///chrome/browser/content/browser/defaultthemes/compactlight.icon.svg",
     textcolor: "red",
     accentcolor: "blue"
   };
 }
 
 add_task(function* testLightweightThemePreview() {
-  info("Setting devedition to current and the previewing others");
-  LightweightThemeManager.currentTheme = LightweightThemeManager.getUsedTheme("firefox-devedition@mozilla.org");
-  ok(DevEdition.isStyleSheetEnabled, "The devedition stylesheet is enabled.");
+  if (SKIP_TEST) {
+    ok(true, "No need to run this test since themes aren't installed");
+    return;
+  }
+  info("Setting compact to current and previewing others");
+  LightweightThemeManager.currentTheme = LightweightThemeManager.getUsedTheme(COMPACT_LIGHT_ID);
+  ok(CompactTheme.isStyleSheetEnabled, "The compact stylesheet is enabled.");
   LightweightThemeManager.previewTheme(dummyLightweightTheme("preview0"));
-  ok(!DevEdition.isStyleSheetEnabled, "The devedition stylesheet is not enabled after a lightweight theme preview.");
+  ok(!CompactTheme.isStyleSheetEnabled, "The compact stylesheet is not enabled after a lightweight theme preview.");
   LightweightThemeManager.resetPreview();
   LightweightThemeManager.previewTheme(dummyLightweightTheme("preview1"));
-  ok(!DevEdition.isStyleSheetEnabled, "The devedition stylesheet is not enabled after a second lightweight theme preview.");
+  ok(!CompactTheme.isStyleSheetEnabled, "The compact stylesheet is not enabled after a second lightweight theme preview.");
   LightweightThemeManager.resetPreview();
-  ok(DevEdition.isStyleSheetEnabled, "The devedition stylesheet is enabled again after resetting the preview.");
+  ok(CompactTheme.isStyleSheetEnabled, "The compact stylesheet is enabled again after resetting the preview.");
   LightweightThemeManager.currentTheme = null;
-  ok(!DevEdition.isStyleSheetEnabled, "The devedition stylesheet is gone after removing the current theme.");
-
-  info("Previewing the devedition theme");
-  LightweightThemeManager.previewTheme(LightweightThemeManager.getUsedTheme("firefox-devedition@mozilla.org"));
-  ok(DevEdition.isStyleSheetEnabled, "The devedition stylesheet is enabled.");
-  LightweightThemeManager.previewTheme(dummyLightweightTheme("preview2"));
-  LightweightThemeManager.resetPreview();
-  ok(!DevEdition.isStyleSheetEnabled, "The devedition stylesheet is now disabled after resetting the preview.");
-});
+  ok(!CompactTheme.isStyleSheetEnabled, "The compact stylesheet is gone after removing the current theme.");
 
-// Use a mutation observer to wait for the brighttitlebarforeground
-// attribute to change.  Using this instead of waiting for the load
-// event on the DevEdition styleSheet.
-function waitForBrightTitlebarAttribute() {
-  return new Promise((resolve, reject) => {
-    let mutationObserver = new MutationObserver(function(mutations) {
-      for (let mutation of mutations) {
-        if (mutation.attributeName == "brighttitlebarforeground") {
-          mutationObserver.disconnect();
-          resolve();
-        }
-      }
-    });
-    mutationObserver.observe(document.documentElement, { attributes: true });
-  });
-}
+  info("Previewing the compact theme");
+  LightweightThemeManager.previewTheme(LightweightThemeManager.getUsedTheme(COMPACT_LIGHT_ID));
+  ok(CompactTheme.isStyleSheetEnabled, "The compact stylesheet is enabled.");
+  LightweightThemeManager.previewTheme(LightweightThemeManager.getUsedTheme(COMPACT_DARK_ID));
+  ok(CompactTheme.isStyleSheetEnabled, "The compact stylesheet is enabled.");
+
+  LightweightThemeManager.previewTheme(dummyLightweightTheme("preview2"));
+  ok(!CompactTheme.isStyleSheetEnabled, "The compact stylesheet is now disabled after previewing a new sheet.");
+  LightweightThemeManager.resetPreview();
+  ok(!CompactTheme.isStyleSheetEnabled, "The compact stylesheet is now disabled after resetting the preview.");
+});
--- a/browser/base/content/test/tabPrompts/browser_openPromptInBackgroundTab.js
+++ b/browser/base/content/test/tabPrompts/browser_openPromptInBackgroundTab.js
@@ -1,15 +1,15 @@
 "use strict";
 
 const ROOT = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://example.com/");
 let pageWithAlert = ROOT + "openPromptOffTimeout.html";
 
 registerCleanupFunction(function() {
-  Services.perms.removeAll(makeURI(pageWithAlert));
+  Services.perms.removeAll();
 });
 
 /*
  * This test opens a tab that alerts when it is hidden. We then switch away
  * from the tab, and check that by default the tab is not automatically
  * re-selected. We also check that a checkbox appears in the alert that allows
  * the user to enable this automatically re-selecting. We then check that
  * checking the checkbox does actually enable that behaviour.
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -64,17 +64,17 @@ browser.jar:
         content/browser/aboutTabCrashed.xhtml         (content/aboutTabCrashed.xhtml)
 *       content/browser/browser.css                   (content/browser.css)
         content/browser/browser.js                    (content/browser.js)
 *       content/browser/browser.xul                   (content/browser.xul)
         content/browser/browser-addons.js             (content/browser-addons.js)
         content/browser/browser-ctrlTab.js            (content/browser-ctrlTab.js)
         content/browser/browser-customization.js      (content/browser-customization.js)
         content/browser/browser-data-submission-info-bar.js (content/browser-data-submission-info-bar.js)
-        content/browser/browser-devedition.js         (content/browser-devedition.js)
+        content/browser/browser-compacttheme.js       (content/browser-compacttheme.js)
         content/browser/browser-feeds.js              (content/browser-feeds.js)
         content/browser/browser-fullScreenAndPointerLock.js  (content/browser-fullScreenAndPointerLock.js)
         content/browser/browser-fullZoom.js           (content/browser-fullZoom.js)
         content/browser/browser-fxaccounts.js         (content/browser-fxaccounts.js)
         content/browser/browser-gestureSupport.js     (content/browser-gestureSupport.js)
         content/browser/browser-media.js              (content/browser-media.js)
         content/browser/browser-places.js             (content/browser-places.js)
         content/browser/browser-plugins.js            (content/browser-plugins.js)
@@ -110,18 +110,19 @@ browser.jar:
         content/browser/defaultthemes/4.footer.png    (content/defaultthemes/4.footer.png)
         content/browser/defaultthemes/4.header.png    (content/defaultthemes/4.header.png)
         content/browser/defaultthemes/4.icon.png      (content/defaultthemes/4.icon.png)
         content/browser/defaultthemes/4.preview.png   (content/defaultthemes/4.preview.png)
         content/browser/defaultthemes/5.footer.png    (content/defaultthemes/5.footer.png)
         content/browser/defaultthemes/5.header.png    (content/defaultthemes/5.header.png)
         content/browser/defaultthemes/5.icon.jpg      (content/defaultthemes/5.icon.jpg)
         content/browser/defaultthemes/5.preview.jpg   (content/defaultthemes/5.preview.jpg)
-        content/browser/defaultthemes/devedition.header.png   (content/defaultthemes/devedition.header.png)
-        content/browser/defaultthemes/devedition.icon.png     (content/defaultthemes/devedition.icon.png)
+        content/browser/defaultthemes/compact.header.png    (content/defaultthemes/compact.header.png)
+        content/browser/defaultthemes/compactdark.icon.svg  (content/defaultthemes/compactdark.icon.svg)
+        content/browser/defaultthemes/compactlight.icon.svg (content/defaultthemes/compactlight.icon.svg)
         content/browser/gcli_sec_bad.svg              (content/gcli_sec_bad.svg)
         content/browser/gcli_sec_good.svg             (content/gcli_sec_good.svg)
         content/browser/gcli_sec_moderate.svg         (content/gcli_sec_moderate.svg)
         content/browser/newtab/newTab.xhtml           (content/newtab/newTab.xhtml)
 *       content/browser/newtab/newTab.js              (content/newtab/newTab.js)
         content/browser/newtab/newTab.css             (content/newtab/newTab.css)
         content/browser/newtab/newTab.inadjacent.json         (content/newtab/newTab.inadjacent.json)
         content/browser/newtab/alternativeDefaultSites.json   (content/newtab/alternativeDefaultSites.json)
--- a/browser/components/newtab/aboutNewTabService.js
+++ b/browser/components/newtab/aboutNewTabService.js
@@ -167,17 +167,17 @@ AboutNewTabService.prototype = {
    * Generate a default url based on remote mode, version, locale and update channel
    */
   generateRemoteURL() {
     let releaseName = this.releaseFromUpdateChannel(UpdateUtils.UpdateChannel);
     let path = REMOTE_NEWTAB_PATH
       .replace("%VERSION%", this.remoteVersion)
       .replace("%LOCALE%", Locale.getLocale())
       .replace("%CHANNEL%", releaseName);
-    let mode = Services.prefs.getCharPref(PREF_REMOTE_MODE, "production");
+    let mode = Services.prefs.getCharPref(PREF_REMOTE_MODE);
     if (!(mode in NewTabRemoteResources.MODE_CHANNEL_MAP)) {
       mode = "production";
     }
     return NewTabRemoteResources.MODE_CHANNEL_MAP[mode].origin + path;
   },
 
   /*
    * Returns the default URL.
@@ -224,17 +224,17 @@ AboutNewTabService.prototype = {
     return VALID_CHANNELS.has(channelName) ? channelName : "nightly";
   },
 
   get newTabURL() {
     return this._newTabURL;
   },
 
   get remoteVersion() {
-    return Services.prefs.getCharPref(PREF_REMOTE_VERSION, "1");
+    return Services.prefs.getCharPref(PREF_REMOTE_VERSION);
   },
 
   get remoteReleaseName() {
     return this.releaseFromUpdateChannel(UpdateUtils.UpdateChannel);
   },
 
   set newTabURL(aNewTabURL) {
     let csTest = Services.prefs.getBoolPref(PREF_REMOTE_CS_TEST);
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -646,25 +646,37 @@ BrowserGlue.prototype = {
     ReaderParent.init();
     URLBarZoom.init();
 
     SelfSupportBackend.init();
 
     // Ensure we keep track of places/pw-mananager undo by init'ing this early.
     Cu.import("resource:///modules/AutoMigrate.jsm");
 
-    if (!AppConstants.RELEASE_OR_BETA) {
-      let themeName = gBrowserBundle.GetStringFromName("deveditionTheme.name");
+    if (AppConstants.INSTALL_COMPACT_THEMES) {
       let vendorShortName = gBrandBundle.GetStringFromName("vendorShortName");
 
       LightweightThemeManager.addBuiltInTheme({
-        id: "firefox-devedition@mozilla.org",
-        name: themeName,
-        headerURL: "resource:///chrome/browser/content/browser/defaultthemes/devedition.header.png",
-        iconURL: "resource:///chrome/browser/content/browser/defaultthemes/devedition.icon.png",
+        id: "firefox-compact-light@mozilla.org",
+        name: gBrowserBundle.GetStringFromName("compactLightTheme.name"),
+        description: gBrowserBundle.GetStringFromName("compactLightTheme.description"),
+        headerURL: "resource:///chrome/browser/content/browser/defaultthemes/compact.header.png",
+        iconURL: "resource:///chrome/browser/content/browser/defaultthemes/compactlight.icon.svg",
+        textcolor: "black",
+        accentcolor: "white",
+        author: vendorShortName,
+      });
+      LightweightThemeManager.addBuiltInTheme({
+        id: "firefox-compact-dark@mozilla.org",
+        name: gBrowserBundle.GetStringFromName("compactDarkTheme.name"),
+        description: gBrowserBundle.GetStringFromName("compactDarkTheme.description"),
+        headerURL: "resource:///chrome/browser/content/browser/defaultthemes/compact.header.png",
+        iconURL: "resource:///chrome/browser/content/browser/defaultthemes/compactdark.icon.svg",
+        textcolor: "white",
+        accentcolor: "black",
         author: vendorShortName,
       });
     }
 
     TabCrashHandler.init();
     if (AppConstants.MOZ_CRASHREPORTER) {
       PluginCrashReporter.init();
       UnsubmittedCrashHandler.init();
@@ -1713,17 +1725,17 @@ BrowserGlue.prototype = {
       if (topic != "alertclickcallback")
         return;
       this._openPreferences("sync");
     }
     AlertsService.showAlertNotification(null, title, body, true, null, clickCallback);
   },
 
   _migrateUI: function BG__migrateUI() {
-    const UI_VERSION = 42;
+    const UI_VERSION = 43;
     const BROWSER_DOCURL = "chrome://browser/content/browser.xul";
 
     let currentUIVersion;
     if (Services.prefs.prefHasUserValue("browser.migration.version")) {
       currentUIVersion = Services.prefs.getIntPref("browser.migration.version");
     } else {
       // This is a new profile, nothing to migrate.
       Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
@@ -2046,16 +2058,28 @@ BrowserGlue.prototype = {
     }
 
     if (currentUIVersion < 42) {
       let backupFile = Services.dirsvc.get("ProfD", Ci.nsIFile);
       backupFile.append("tabgroups-session-backup.json");
       OS.File.remove(backupFile.path, {ignoreAbsent: true}).catch(ex => Cu.reportError(ex));
     }
 
+    if (currentUIVersion < 43) {
+      let currentTheme = null;
+      try {
+        currentTheme = Services.prefs.getCharPref("lightweightThemes.selectedThemeID");
+      } catch (e) {}
+      if (currentTheme == "firefox-devedition@mozilla.org") {
+        let newTheme = Services.prefs.getCharPref("devtools.theme") == "dark" ?
+          "firefox-compact-dark@mozilla.org" : "firefox-compact-light@mozilla.org";
+        Services.prefs.setCharPref("lightweightThemes.selectedThemeID", newTheme);
+      }
+    }
+
     // Update the migration version.
     Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
   },
 
   _hasExistingNotificationPermission: function BG__hasExistingNotificationPermission() {
     let enumerator = Services.perms.enumerator;
     while (enumerator.hasMoreElements()) {
       let permission = enumerator.getNext().QueryInterface(Ci.nsIPermission);
--- a/browser/installer/allowed-dupes.mn
+++ b/browser/installer/allowed-dupes.mn
@@ -213,11 +213,10 @@ modules/commonjs/sdk/ui/state/events.js
 plugin-container.app/Contents/PkgInfo
 res/table-remove-column-active.gif
 res/table-remove-column-hover.gif
 res/table-remove-column.gif
 res/table-remove-row-active.gif
 res/table-remove-row-hover.gif
 res/table-remove-row.gif
 # Aurora branding
-browser/chrome/browser/content/browser/defaultthemes/devedition.icon.png
 browser/chrome/browser/content/branding/icon64.png
 browser/chrome/devtools/content/framework/dev-edition-promo/dev-edition-logo.png
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -101,19 +101,23 @@ addonInstallErrorIncompatible=%3$S could
 
 # LOCALIZATION NOTE (addonInstallErrorBlocklisted): %S is add-on name
 addonInstallErrorBlocklisted=%S could not be installed because it has a high risk of causing stability or security problems.
 
 unsignedAddonsDisabled.message=One or more installed add-ons cannot be verified and have been disabled.
 unsignedAddonsDisabled.learnMore.label=Learn More
 unsignedAddonsDisabled.learnMore.accesskey=L
 
-# LOCALIZATION NOTE (deveditionTheme.name): This should be nearly the brand name for aurora.
-# See browser/branding/aurora/locales/*/brand.properties
-deveditionTheme.name=Developer Edition
+# LOCALIZATION NOTE (compactLightTheme.name): This is displayed in about:addons -> Appearance
+compactLightTheme.name=Compact Light
+compactLightTheme.description=A compact theme with a light color scheme.
+
+# LOCALIZATION NOTE (compactDarkTheme.name): This is displayed in about:addons -> Appearance
+compactDarkTheme.name=Compact Dark
+compactDarkTheme.description=A compact theme with a dark color scheme.
 
 # LOCALIZATION NOTE (lwthemeInstallRequest.message): %S will be replaced with
 # the host name of the site.
 lwthemeInstallRequest.message=This site (%S) attempted to install a theme.
 lwthemeInstallRequest.allowButton=Allow
 lwthemeInstallRequest.allowButton.accesskey=a
 
 lwthemePostInstallNotification.message=A new theme has been installed.
--- a/browser/modules/ContentCrashHandlers.jsm
+++ b/browser/modules/ContentCrashHandlers.jsm
@@ -466,17 +466,17 @@ this.TabCrashHandler = {
       sendReport,
       includeURL,
       emailMe,
       requestAutoSubmit,
       requestEmail,
     };
 
     if (emailMe) {
-      data.email = this.prefs.getCharPref("email", "");
+      data.email = this.prefs.getCharPref("email");
     }
 
     // Make sure to only count once even if there are multiple windows
     // that will all show about:tabcrashed.
     if (this._crashedTabCount == 1) {
       Services.telemetry.getHistogramById("FX_CONTENT_CRASH_PRESENTED").add(1);
     }
 
--- a/browser/modules/test/browser_UsageTelemetry_urlbar.js
+++ b/browser/modules/test/browser_UsageTelemetry_urlbar.js
@@ -84,17 +84,17 @@ add_task(function* setup() {
   // Enable event recording for the events tested here.
   Services.telemetry.setEventRecordingEnabled("navigation", true);
 
   // Make sure to restore the engine once we're done.
   registerCleanupFunction(function* () {
     Services.telemetry.canRecordExtended = oldCanRecord;
     Services.search.currentEngine = originalEngine;
     Services.search.removeEngine(engine);
-    Services.prefs.clearUserPref(SUGGEST_URLBAR_PREF, true);
+    Services.prefs.clearUserPref(SUGGEST_URLBAR_PREF);
     Services.prefs.clearUserPref(ONEOFF_URLBAR_PREF);
     yield PlacesTestUtils.clearHistory();
     Services.telemetry.setEventRecordingEnabled("navigation", false);
   });
 });
 
 add_task(function* test_simpleQuery() {
   // Let's reset the counts.
rename from browser/themes/linux/devedition.css
rename to browser/themes/linux/compacttheme.css
--- a/browser/themes/linux/devedition.css
+++ b/browser/themes/linux/compacttheme.css
@@ -1,31 +1,31 @@
 % 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 ../shared/devedition.inc.css
+%include ../shared/compacttheme.inc.css
 
 :root {
   --forwardbutton-width: 29px;
 }
 
-:root[devtoolstheme="light"] {
+:root:-moz-lwtheme-darktext {
   --urlbar-dropmarker-url: url("chrome://browser/skin/devedition/urlbar-history-dropmarker.svg");
   --urlbar-dropmarker-region: rect(0px, 11px, 14px, 0px);
   --urlbar-dropmarker-hover-region: rect(0, 22px, 14px, 11px);
   --urlbar-dropmarker-active-region: rect(0px, 33px, 14px, 22px);
   --urlbar-dropmarker-2x-url: url("chrome://browser/skin/devedition/urlbar-history-dropmarker.svg");
   --urlbar-dropmarker-2x-region: rect(0px, 11px, 14px, 0px);
   --urlbar-dropmarker-hover-2x-region: rect(0, 22px, 14px, 11px);
   --urlbar-dropmarker-active-2x-region: rect(0px, 33px, 14px, 22px);
 }
 
-:root[devtoolstheme="dark"] .findbar-closebutton:not(:hover),
-:root[devtoolstheme="dark"] #sidebar-header > .close-icon:not(:hover),
+.findbar-closebutton:-moz-lwtheme-brighttext:not(:hover),
+#sidebar-header > .close-icon:-moz-lwtheme-brighttext:not(:hover),
 .tab-close-button[selected]:not(:hover) {
   background-image: -moz-image-rect(url("chrome://global/skin/icons/close.svg"), 0, 80, 16, 64);
 }
 
 /* The menubar and tabs toolbar should match the devedition theme */
 #TabsToolbar,
 #toolbar-menubar {
   -moz-appearance: none !important;
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -6,17 +6,17 @@ browser.jar:
 % skin browser classic/1.0 %skin/classic/browser/
 % override chrome://global/skin/icons/warning-16.png moz-icon://stock/gtk-dialog-warning?size=menu
 #include ../shared/jar.inc.mn
   skin/classic/browser/sanitizeDialog.css
   skin/classic/browser/aboutSessionRestore-window-icon.png
   skin/classic/browser/aboutSyncTabs.css
 * skin/classic/browser/syncedtabs/sidebar.css     (syncedtabs/sidebar.css)
 * skin/classic/browser/browser.css
-* skin/classic/browser/devedition.css
+* skin/classic/browser/compacttheme.css
 * skin/classic/browser/browser-lightweightTheme.css
   skin/classic/browser/click-to-play-warning-stripes.png
   skin/classic/browser/Info.png
   skin/classic/browser/menuPanel-customize.png
   skin/classic/browser/menuPanel-customize@2x.png
   skin/classic/browser/menuPanel-exit.png
   skin/classic/browser/menuPanel-exit@2x.png
   skin/classic/browser/menuPanel-help.png
@@ -74,18 +74,16 @@ browser.jar:
   skin/classic/browser/places/downloads.png           (places/downloads.png)
   skin/classic/browser/preferences/alwaysAsk.png      (preferences/alwaysAsk.png)
   skin/classic/browser/preferences/preferences.css    (preferences/preferences.css)
 * skin/classic/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css)
 * skin/classic/browser/preferences/in-content/dialog.css      (preferences/in-content/dialog.css)
   skin/classic/browser/preferences/applications.css   (preferences/applications.css)
   skin/classic/browser/social/services-16.png         (social/services-16.png)
   skin/classic/browser/social/services-64.png         (social/services-64.png)
-  skin/classic/browser/social/share-button.png        (social/share-button.png)
-  skin/classic/browser/social/share-button-active.png (social/share-button-active.png)
   skin/classic/browser/tabbrowser/alltabs.png         (tabbrowser/alltabs.png)
   skin/classic/browser/tabbrowser/alltabs-inverted.png (tabbrowser/alltabs-inverted.png)
   skin/classic/browser/tabbrowser/newtab.svg                (tabbrowser/newtab.svg)
   skin/classic/browser/tabbrowser/newtab-inverted.svg       (tabbrowser/newtab-inverted.svg)
   skin/classic/browser/tabbrowser/tab-active-middle.png     (tabbrowser/tab-active-middle.png)
   skin/classic/browser/tabbrowser/tab-active-middle@2x.png  (tabbrowser/tab-active-middle@2x.png)
   skin/classic/browser/tabbrowser/tab-arrow-left.png        (tabbrowser/tab-arrow-left.png)
   skin/classic/browser/tabbrowser/tab-arrow-left-inverted.png (tabbrowser/tab-arrow-left-inverted.png)
deleted file mode 100644
index 7df438db014c265c35da304c4a846f5e34c46e4b..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index c5298c143eaaa74773f5066766f923ef076a74ca..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
rename from browser/themes/osx/devedition.css
rename to browser/themes/osx/compacttheme.css
--- a/browser/themes/osx/devedition.css
+++ b/browser/themes/osx/compacttheme.css
@@ -1,13 +1,13 @@
 % This Source Code Form is subject to the terms of the Mozilla Public
 % License, v. 2.0. If a copy of the MPL was not distributed with this
 % file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-%include ../shared/devedition.inc.css
+%include ../shared/compacttheme.inc.css
 
 :root {
   --forwardbutton-width: 32px;
 }
 
 /* Use only 1px separator between nav toolbox and page content */
 #navigator-toolbox::after {
   border-top-style: none;
@@ -101,24 +101,24 @@
   padding-bottom: 3px !important;
 }
 
 #PanelUI-button {
   margin-top: 0;
   margin-bottom: 0;
 }
 
-:root[devtoolstheme="dark"] .findbar-closebutton:not(:hover),
+.findbar-closebutton:-moz-lwtheme-brighttext:not(:hover),
 /* Tab styling - make sure to use an inverted icon for the selected tab
    (brighttext only covers the unselected tabs) */
 .tab-close-button[selected=true]:not(:hover) {
   -moz-image-region: rect(0, 64px, 16px, 48px);
 }
 @media (min-resolution: 2dppx) {
-  :root[devtoolstheme="dark"] .findbar-closebutton:not(:hover),
+  .findbar-closebutton:-moz-lwtheme-brighttext :not(:hover),
   .tab-close-button[selected=true]:not(:hover) {
     -moz-image-region: rect(0, 128px, 32px, 96px);
   }
 }
 
 .ac-type-icon {
   /* Left-align the type icon in awesomebar popup results with the icon in the
      urlbar. */
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -5,17 +5,17 @@
 browser.jar:
 % skin browser classic/1.0 %skin/classic/browser/
 #include ../shared/jar.inc.mn
   skin/classic/browser/sanitizeDialog.css
   skin/classic/browser/aboutSessionRestore-window-icon.png
   skin/classic/browser/aboutSyncTabs.css
 * skin/classic/browser/syncedtabs/sidebar.css          (syncedtabs/sidebar.css)
 * skin/classic/browser/browser.css
-* skin/classic/browser/devedition.css
+* skin/classic/browser/compacttheme.css
 * skin/classic/browser/browser-lightweightTheme.css
   skin/classic/browser/click-to-play-warning-stripes.png
   skin/classic/browser/Info.png
   skin/classic/browser/keyhole-circle.png
   skin/classic/browser/keyhole-circle@2x.png
   skin/classic/browser/subtle-pattern.png
   skin/classic/browser/menu-back.png
   skin/classic/browser/menu-forward.png
rename from browser/themes/shared/devedition.inc.css
rename to browser/themes/shared/compacttheme.inc.css
--- a/browser/themes/shared/devedition.inc.css
+++ b/browser/themes/shared/compacttheme.inc.css
@@ -1,25 +1,25 @@
 % 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/.
 
-/* devedition.css is loaded in browser.xul after browser.css when it is
+/* compacttheme.css is loaded in browser.xul after browser.css when it is
    preffed on.  The bulk of the styling is here in the shared file, but
-   there are overrides for each platform in their devedition.css files. */
+   there are overrides for each platform in their compacttheme.css files. */
 
 :root {
   --tab-toolbar-navbar-overlap: 0px;
   --navbar-tab-toolbar-highlight-overlap: 0px;
   --space-above-tabbar: 0px;
   --toolbarbutton-text-shadow: none;
   --backbutton-urlbar-overlap: 0px;
 }
 
-:root[devtoolstheme="dark"] {
+:root:-moz-lwtheme-brighttext {
   /* Chrome */
   --chrome-background-color: #272b35;
   --chrome-color: #F5F7FA;
   --chrome-secondary-background-color: #393F4C;
   --chrome-navigator-toolbox-separator-color: rgba(0,0,0,.2);
   --chrome-nav-bar-separator-color: rgba(0,0,0,.2);
   --chrome-nav-buttons-background: #252C33;
   --chrome-nav-buttons-hover-background: #1B2127;
@@ -45,29 +45,29 @@
   --urlbar-dropmarker-active-region: rect(0px, 33px, 14px, 22px);
   --urlbar-dropmarker-2x-url: url("chrome://browser/skin/devedition/urlbar-history-dropmarker.svg");
   --urlbar-dropmarker-2x-region: rect(0px, 11px, 14px, 0px);
   --urlbar-dropmarker-hover-2x-region: rect(0, 22px, 14px, 11px);
   --urlbar-dropmarker-active-2x-region: rect(0px, 33px, 14px, 22px);
 }
 
 /* Override the lwtheme-specific styling for toolbar buttons */
-:root[devtoolstheme="dark"],
-:root[devtoolstheme="dark"] toolbar:-moz-lwtheme {
+:root:-moz-lwtheme-brighttext,
+toolbar:-moz-lwtheme-brighttext  {
   --toolbarbutton-hover-background: rgba(25,33, 38,.6) linear-gradient(rgba(25,33,38,.6), rgba(25,33,38,.6)) padding-box;
   --toolbarbutton-hover-boxshadow: none;
   --toolbarbutton-hover-bordercolor: rgba(25,33,38,.6);
   --toolbarbutton-active-background: rgba(25,33,38,1) linear-gradient(rgba(25,33,38,1), rgba(25,33,38,1)) border-box;
   --toolbarbutton-active-boxshadow: none;
   --toolbarbutton-active-bordercolor: rgba(25,33,38,.8);
   --toolbarbutton-checkedhover-backgroundcolor: #3C5283;
 
 }
 
-:root[devtoolstheme="light"] {
+:root:-moz-lwtheme-darktext {
   --url-and-searchbar-background-color: #fff;
 
   --chrome-background-color: #E3E4E6;
   --chrome-color: #18191a;
   --chrome-secondary-background-color: #f5f6f7;
   --chrome-navigator-toolbox-separator-color: #cccccc;
   --chrome-nav-bar-separator-color: #B6B6B8;
   --chrome-nav-buttons-background: #ffffff; /* --theme-body-background */
@@ -80,18 +80,18 @@
   --tab-hover-background-color: #D7D8DA;
   --tab-selection-color: #f5f7fa;
   --tab-selection-background-color: #4c9ed9;
   --tab-selection-box-shadow: none;
   --pinned-tab-glow: radial-gradient(22px at center calc(100% - 2px), rgba(76,158,217,0.9) 13%, transparent 16%);
 }
 
 /* Override the lwtheme-specific styling for toolbar buttons */
-:root[devtoolstheme="light"],
-:root[devtoolstheme="light"] toolbar:-moz-lwtheme {
+:root:-moz-lwtheme-darktext,
+toolbar:-moz-lwtheme-darktext {
   --toolbarbutton-hover-background: #eaeaea;
   --toolbarbutton-hover-boxshadow: none;
   --toolbarbutton-hover-bordercolor: rgba(0,0,0,0.1);
   --toolbarbutton-active-background: #d7d7d8 border-box;
   --toolbarbutton-active-boxshadow: none;
   --toolbarbutton-active-bordercolor: rgba(0,0,0,0.15);
   --toolbarbutton-checkedhover-backgroundcolor: #d7d7d8;
 }
@@ -192,37 +192,36 @@ toolbar[brighttext] #downloads-indicator
   background-color: var(--url-and-searchbar-background-color) !important;
   background-image: none !important;
   color: inherit !important;
   border: 1px solid var(--chrome-nav-bar-controls-border-color) !important;
   box-shadow: none !important;
 }
 
 %filter substitution
-%define selectorPrefix :root[devtoolstheme="dark"] 
-%define selectorSuffix :-moz-lwtheme
+%define selectorSuffix :-moz-lwtheme-brighttext
 %define iconVariant -white
 %include identity-block/icons.inc.css
 
 #urlbar {
   border-inline-start: none !important;
   opacity: 1 !important;
 }
 
 window:not([chromehidden~="toolbar"]) #urlbar-wrapper {
   overflow: -moz-hidden-unscrollable;
   clip-path: none;
   margin-inline-start: 0;
 }
 
-:root[devtoolstheme="dark"] #urlbar-zoom-button:hover {
+#urlbar-zoom-button:-moz-lwtheme-brighttext:hover {
   background-color: rgba(255,255,255,.2);
 }
 
-:root[devtoolstheme="dark"] #urlbar-zoom-button:hover:active {
+#urlbar-zoom-button:-moz-lwtheme-brighttext:hover:active {
   background-color: rgba(255,255,255,.3);
 }
 
 /* Nav bar specific stuff */
 #nav-bar {
   margin-top: 0 !important;
   border-top: none !important;
   border-bottom: none !important;
--- a/browser/themes/shared/identity-block/icons.inc.css
+++ b/browser/themes/shared/identity-block/icons.inc.css
@@ -1,62 +1,62 @@
 %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
 
-@selectorPrefix@#identity-icon@selectorSuffix@ {
+#identity-icon@selectorSuffix@ {
   list-style-image: url(chrome://browser/skin/identity-icon.svg#normal@iconVariant@);
 }
 
-@selectorPrefix@#identity-box:hover > #identity-icon:not(.no-hover)@selectorSuffix@,
-@selectorPrefix@#identity-box[open=true] > #identity-icon@selectorSuffix@ {
+#identity-box:hover > #identity-icon:not(.no-hover)@selectorSuffix@,
+#identity-box[open=true] > #identity-icon@selectorSuffix@ {
   list-style-image: url(chrome://browser/skin/identity-icon.svg#hover@iconVariant@);
 }
 
-@selectorPrefix@#identity-box.grantedPermissions > #identity-icon@selectorSuffix@ {
+#identity-box.grantedPermissions > #identity-icon@selectorSuffix@ {
   list-style-image: url(chrome://browser/skin/identity-icon.svg#notice@iconVariant@);
 }
 
-@selectorPrefix@#identity-box.grantedPermissions:hover > #identity-icon:not(.no-hover)@selectorSuffix@,
-@selectorPrefix@#identity-box.grantedPermissions[open=true] > #identity-icon@selectorSuffix@ {
+#identity-box.grantedPermissions:hover > #identity-icon:not(.no-hover)@selectorSuffix@,
+#identity-box.grantedPermissions[open=true] > #identity-icon@selectorSuffix@ {
   list-style-image: url(chrome://browser/skin/identity-icon.svg#notice-hover@iconVariant@);
 }
 
-@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.chromeUI > #identity-icon@selectorSuffix@ {
+#urlbar[pageproxystate="valid"] > #identity-box.chromeUI > #identity-icon@selectorSuffix@ {
   list-style-image: url(chrome://branding/content/identity-icons-brand.svg);
 }
 
 
-@selectorPrefix@#tracking-protection-icon@selectorSuffix@ {
+#tracking-protection-icon@selectorSuffix@ {
   list-style-image: url(chrome://browser/skin/tracking-protection-16.svg#enabled@iconVariant@);
 }
 
-@selectorPrefix@#tracking-protection-icon[state="loaded-tracking-content"]@selectorSuffix@ {
+#tracking-protection-icon[state="loaded-tracking-content"]@selectorSuffix@ {
   list-style-image: url(chrome://browser/skin/tracking-protection-16.svg#disabled@iconVariant@);
 }
 
 
-@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.verifiedDomain > #connection-icon@selectorSuffix@,
-@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity > #connection-icon@selectorSuffix@,
-@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.mixedActiveBlocked > #connection-icon@selectorSuffix@ {
+#urlbar[pageproxystate="valid"] > #identity-box.verifiedDomain > #connection-icon@selectorSuffix@,
+#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity > #connection-icon@selectorSuffix@,
+#urlbar[pageproxystate="valid"] > #identity-box.mixedActiveBlocked > #connection-icon@selectorSuffix@ {
   list-style-image: url(chrome://browser/skin/connection-secure.svg);
   visibility: visible;
 }
 
-@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.certUserOverridden > #connection-icon@selectorSuffix@ {
+#urlbar[pageproxystate="valid"] > #identity-box.certUserOverridden > #connection-icon@selectorSuffix@ {
   list-style-image: url(chrome://browser/skin/connection-mixed-passive-loaded.svg#icon@iconVariant@);
   visibility: visible;
 }
 
-@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.insecureLoginForms > #connection-icon@selectorSuffix@,
-@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.mixedActiveContent > #connection-icon@selectorSuffix@ {
+#urlbar[pageproxystate="valid"] > #identity-box.insecureLoginForms > #connection-icon@selectorSuffix@,
+#urlbar[pageproxystate="valid"] > #identity-box.mixedActiveContent > #connection-icon@selectorSuffix@ {
   list-style-image: url(chrome://browser/skin/connection-mixed-active-loaded.svg#icon@iconVariant@);
   visibility: visible;
 }
 
-@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.weakCipher > #connection-icon@selectorSuffix@,
-@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.mixedDisplayContent > #connection-icon@selectorSuffix@,
-@selectorPrefix@#urlbar[pageproxystate="valid"] > #identity-box.mixedDisplayContentLoadedActiveBlocked > #connection-icon@selectorSuffix@ {
+#urlbar[pageproxystate="valid"] > #identity-box.weakCipher > #connection-icon@selectorSuffix@,
+#urlbar[pageproxystate="valid"] > #identity-box.mixedDisplayContent > #connection-icon@selectorSuffix@,
+#urlbar[pageproxystate="valid"] > #identity-box.mixedDisplayContentLoadedActiveBlocked > #connection-icon@selectorSuffix@ {
   list-style-image: url(chrome://browser/skin/connection-mixed-passive-loaded.svg#icon@iconVariant@);
   visibility: visible;
 }
--- a/browser/themes/shared/identity-block/identity-block.inc.css
+++ b/browser/themes/shared/identity-block/identity-block.inc.css
@@ -1,22 +1,20 @@
 %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
 
 %filter substitution
 
-%define selectorPrefix
 %define selectorSuffix
 %define iconVariant
 %include icons.inc.css
 
-%define selectorPrefix
 %define selectorSuffix :-moz-lwtheme
 %define iconVariant -black
 %include icons.inc.css
 
 #identity-box {
   font-size: .9em;
   padding: 3px 5px;
   overflow: hidden;
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -182,17 +182,17 @@ toolbar:-moz-lwtheme {
   min-height: 0.1px;
   max-height: 0;
   transition: min-height 170ms ease-out, max-height 170ms ease-out, visibility 170ms linear;
 }
 
 @media (-moz-windows-compositor: 0),
        (-moz-windows-default-theme: 0) {
   /* Please keep the menu text colors in this media block in sync with
-   * devedition.css, minus the :not(:-moz-lwtheme) condition - see Bug 1165718.
+   * compacttheme.css, minus the :not(:-moz-lwtheme) condition - see Bug 1165718.
    */
   #main-window[tabsintitlebar]:not([inFullscreen]) #toolbar-menubar:not(:-moz-lwtheme),
   #main-window[tabsintitlebar]:not([inFullscreen]) #TabsToolbar:not(:-moz-lwtheme) {
     color: CaptionText;
   }
 
   #main-window[tabsintitlebar]:not([inFullscreen]) #toolbar-menubar:not(:-moz-lwtheme):-moz-window-inactive,
   #main-window[tabsintitlebar]:not([inFullscreen]) #TabsToolbar:not(:-moz-lwtheme):-moz-window-inactive {
rename from browser/themes/windows/devedition.css
rename to browser/themes/windows/compacttheme.css
--- a/browser/themes/windows/devedition.css
+++ b/browser/themes/windows/compacttheme.css
@@ -1,20 +1,16 @@
 % This Source Code Form is subject to the terms of the Mozilla Public
 % License, v. 2.0. If a copy of the MPL was not distributed with this
 % file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-%include ../shared/devedition.inc.css
+%include ../shared/compacttheme.inc.css
 
 :root {
   --forwardbutton-width: 29px;
-}
-
-:root[devtoolstheme="dark"],
-:root[devtoolstheme="light"] {
    /* Matches the #browser-border-start, #browser-border-end color */
   --chrome-nav-bar-separator-color: rgba(10, 31, 51, 0.35);
 }
 
 /* The window background is white due to no accentcolor in the lightweight
    theme. It can't be changed to transparent when there is no compositor
    (Win 7 in classic / basic theme), or else dragging and focus become
    broken. So instead just show the normal titlebar in that case, and override
@@ -95,27 +91,27 @@
 .tabbrowser-tab {
   background-color: var(--tab-background-color);
 }
 
 #toolbar-menubar {
   text-shadow: none !important;
 }
 
-:root[devtoolstheme="dark"] .findbar-closebutton,
-:root[devtoolstheme="dark"] #sidebar-header > .close-icon,
+.findbar-closebutton:-moz-lwtheme-brighttext,
+#sidebar-header > .close-icon:-moz-lwtheme-brighttext,
 /* Tab styling - make sure to use an inverted icon for the selected tab
    (brighttext only covers the unselected tabs) */
 .tab-close-button[selected=true] {
   list-style-image: url("chrome://global/skin/icons/close-inverted.png");
 }
 
 @media (min-resolution: 1.1dppx) {
-  :root[devtoolstheme="dark"] .findbar-closebutton,
-  :root[devtoolstheme="dark"] #sidebar-header > .close-icon,
+  .findbar-closebutton:-moz-lwtheme-brighttext,
+  #sidebar-header > .close-icon:-moz-lwtheme-brighttext,
   .tab-close-button[selected=true] {
     list-style-image: url("chrome://global/skin/icons/close-inverted@2x.png");
   }
 }
 
 @media (-moz-os-version: windows-win7),
        (-moz-os-version: windows-win8) {
   :root {
@@ -274,44 +270,43 @@
 @media (-moz-os-version: windows-win10) {
   /* Always keep draggable space on the sides of tabs since there is no top margin on Win10 */
   #main-window .tabbrowser-arrowscrollbox > .arrowscrollbox-scrollbox {
     padding-left: 15px;
     padding-right: 15px;
   }
 
   /* Force white caption buttons for the dark theme on Windows 10 */
-  :root[devtoolstheme="dark"] #titlebar-min {
+  #titlebar-min:-moz-lwtheme-brighttext {
     list-style-image: url(chrome://browser/skin/caption-buttons.svg#minimize-white);
   }
-  :root[devtoolstheme="dark"] #titlebar-max {
+  #titlebar-max:-moz-lwtheme-brighttext {
     list-style-image: url(chrome://browser/skin/caption-buttons.svg#maximize-white);
   }
-  #main-window[devtoolstheme="dark"][sizemode="maximized"] #titlebar-max {
+  #main-window[sizemode="maximized"] #titlebar-max:-moz-lwtheme-brighttext {
     list-style-image: url(chrome://browser/skin/caption-buttons.svg#restore-white);
   }
-  :root[devtoolstheme="dark"] #titlebar-close {
+  #titlebar-close:-moz-lwtheme-brighttext {
     list-style-image: url(chrome://browser/skin/caption-buttons.svg#close-white);
   }
 
   /* ... and normal ones for the light theme on Windows 10 */
-  :root[devtoolstheme="light"] #titlebar-min {
+  #titlebar-min:-moz-lwtheme-darktext {
     list-style-image: url(chrome://browser/skin/caption-buttons.svg#minimize);
   }
-  :root[devtoolstheme="light"] #titlebar-max {
+  #titlebar-max:-moz-lwtheme-darktext {
     list-style-image: url(chrome://browser/skin/caption-buttons.svg#maximize);
   }
-  #main-window[devtoolstheme="light"][sizemode="maximized"] #titlebar-max {
+  #main-window[sizemode="maximized"] #titlebar-max:-moz-lwtheme-darktext {
     list-style-image: url(chrome://browser/skin/caption-buttons.svg#restore);
   }
-  :root[devtoolstheme="light"] #titlebar-close {
+  #titlebar-close:-moz-lwtheme-darktext {
     list-style-image: url(chrome://browser/skin/caption-buttons.svg#close);
   }
-
-  :root[devtoolstheme="light"] #titlebar-close:hover {
+  #titlebar-close:-moz-lwtheme-darktext:hover {
     list-style-image: url(chrome://browser/skin/caption-buttons.svg#close-white);
   }
 }
 
 .ac-type-icon {
   /* Left-align the type icon in awesomebar popup results with the icon in the
      urlbar. */
   margin-inline-start: 13px;
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -5,17 +5,17 @@
 browser.jar:
 % skin browser classic/1.0 %skin/classic/browser/
 #include ../shared/jar.inc.mn
   skin/classic/browser/sanitizeDialog.css
   skin/classic/browser/aboutSessionRestore-window-icon.png
   skin/classic/browser/aboutSyncTabs.css
 * skin/classic/browser/syncedtabs/sidebar.css     (syncedtabs/sidebar.css)
 * skin/classic/browser/browser.css
-* skin/classic/browser/devedition.css
+* skin/classic/browser/compacttheme.css
 * skin/classic/browser/browser-lightweightTheme.css
   skin/classic/browser/caption-buttons.svg
   skin/classic/browser/click-to-play-warning-stripes.png
   skin/classic/browser/Info.png
   skin/classic/browser/livemark-folder.png
   skin/classic/browser/menu-back.png
   skin/classic/browser/menu-forward.png
   skin/classic/browser/menuPanel-customize.png
--- a/devtools/client/framework/devtools-browser.js
+++ b/devtools/client/framework/devtools-browser.js
@@ -24,25 +24,29 @@ loader.lazyRequireGetter(this, "TargetFa
 loader.lazyRequireGetter(this, "Toolbox", "devtools/client/framework/toolbox", true);
 loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true);
 loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/main", true);
 loader.lazyRequireGetter(this, "BrowserMenus", "devtools/client/framework/browser-menus");
 loader.lazyRequireGetter(this, "findCssSelector", "devtools/shared/inspector/css-logic", true);
 
 loader.lazyImporter(this, "CustomizableUI", "resource:///modules/CustomizableUI.jsm");
 loader.lazyImporter(this, "AppConstants", "resource://gre/modules/AppConstants.jsm");
+loader.lazyImporter(this, "LightweightThemeManager", "resource://gre/modules/LightweightThemeManager.jsm");
 
 const {LocalizationHelper} = require("devtools/shared/l10n");
 const L10N = new LocalizationHelper("devtools/client/locales/toolbox.properties");
 
 const TABS_OPEN_PEAK_HISTOGRAM = "DEVTOOLS_TABS_OPEN_PEAK_LINEAR";
 const TABS_OPEN_AVG_HISTOGRAM = "DEVTOOLS_TABS_OPEN_AVERAGE_LINEAR";
 const TABS_PINNED_PEAK_HISTOGRAM = "DEVTOOLS_TABS_PINNED_PEAK_LINEAR";
 const TABS_PINNED_AVG_HISTOGRAM = "DEVTOOLS_TABS_PINNED_AVERAGE_LINEAR";
 
+const COMPACT_LIGHT_ID = "firefox-compact-light@mozilla.org";
+const COMPACT_DARK_ID = "firefox-compact-dark@mozilla.org";
+
 /**
  * gDevToolsBrowser exposes functions to connect the gDevTools instance with a
  * Firefox instance.
  */
 var gDevToolsBrowser = exports.gDevToolsBrowser = {
   /**
    * A record of the windows whose menus we altered, so we can undo the changes
    * as the window is closed
@@ -124,38 +128,89 @@ var gDevToolsBrowser = exports.gDevTools
     let remoteEnabled = chromeEnabled && devtoolsRemoteEnabled;
     toggleMenuItem("menu_browserToolbox", remoteEnabled);
     toggleMenuItem("menu_browserContentToolbox", remoteEnabled && win.gMultiProcessBrowser);
 
     // Enable DevTools connection screen, if the preference allows this.
     toggleMenuItem("menu_devtools_connect", devtoolsRemoteEnabled);
   },
 
+  /**
+   * This function makes sure that the "devtoolstheme" attribute is set on the browser
+   * window to make it possible to change colors on elements in the browser (like gcli,
+   * or the splitter between the toolbox and web content).
+   */
+  updateDevtoolsThemeAttribute: function(win) {
+    // Set an attribute on root element of each window to make it possible
+    // to change colors based on the selected devtools theme.
+    let devtoolsTheme = Services.prefs.getCharPref("devtools.theme");
+    if (devtoolsTheme != "dark") {
+      devtoolsTheme = "light";
+    }
+
+    win.document.documentElement.setAttribute("devtoolstheme", devtoolsTheme);
+
+    // If the toolbox color changes and we have the opposite compact theme applied,
+    // change it to match.  For example:
+    // 1) toolbox changes to dark, and the light compact theme was applied.
+    //    Switch to the dark compact theme.
+    // 2) toolbox changes to light or firebug, and the dark compact theme was applied.
+    //    Switch to the light compact theme.
+    // 3) No compact theme was applied. Do nothing.
+    let currentTheme = LightweightThemeManager.currentTheme;
+    let currentThemeID = currentTheme && currentTheme.id;
+    if (currentThemeID == COMPACT_LIGHT_ID && devtoolsTheme == "dark") {
+      LightweightThemeManager.currentTheme = LightweightThemeManager.getUsedTheme(COMPACT_DARK_ID);
+    }
+    if (currentThemeID == COMPACT_DARK_ID && devtoolsTheme == "light") {
+      LightweightThemeManager.currentTheme = LightweightThemeManager.getUsedTheme(COMPACT_LIGHT_ID);
+    }
+  },
+
   observe: function (subject, topic, prefName) {
     switch (topic) {
       case "browser-delayed-startup-finished":
         this._registerBrowserWindow(subject);
         break;
       case "nsPref:changed":
         if (prefName.endsWith("enabled")) {
           for (let win of this._trackedBrowserWindows) {
             this.updateCommandAvailability(win);
           }
         }
+        if (prefName === "devtools.theme") {
+          for (let win of this._trackedBrowserWindows) {
+            this.updateDevtoolsThemeAttribute(win);
+          }
+        }
         break;
       case "quit-application":
         gDevToolsBrowser.destroy({ shuttingDown: true });
         break;
       case "sdk:loader:destroy":
         // This event is fired when the devtools loader unloads, which happens
         // only when the add-on workflow ask devtools to be reloaded.
         if (subject.wrappedJSObject == require('@loader/unload')) {
           gDevToolsBrowser.destroy({ shuttingDown: false });
         }
         break;
+      case "lightweight-theme-changed":
+        let currentTheme = LightweightThemeManager.currentTheme;
+        let currentThemeID = currentTheme && currentTheme.id;
+        let devtoolsTheme = Services.prefs.getCharPref("devtools.theme");
+
+        // If the current lightweight theme changes to one of the compact themes, then
+        // keep the devtools color in sync.
+        if (currentThemeID == COMPACT_LIGHT_ID && devtoolsTheme == "dark") {
+          Services.prefs.setCharPref("devtools.theme", "light");
+        }
+        if (currentThemeID == COMPACT_DARK_ID && devtoolsTheme == "light") {
+            Services.prefs.setCharPref("devtools.theme", "dark");
+        }
+        break;
     }
   },
 
   _prefObserverRegistered: false,
 
   ensurePrefObserver: function () {
     if (!this._prefObserverRegistered) {
       this._prefObserverRegistered = true;
@@ -456,16 +511,17 @@ var gDevToolsBrowser = exports.gDevTools
 
     // Inject lazily DeveloperToolbar on the chrome window
     loader.lazyGetter(win, "DeveloperToolbar", function () {
       let { DeveloperToolbar } = require("devtools/client/shared/developer-toolbar");
       return new DeveloperToolbar(win);
     });
 
     this.updateCommandAvailability(win);
+    this.updateDevtoolsThemeAttribute(win);
     this.ensurePrefObserver();
     win.addEventListener("unload", this);
 
     let tabContainer = win.gBrowser.tabContainer;
     tabContainer.addEventListener("TabSelect", this, false);
     tabContainer.addEventListener("TabOpen", this, false);
     tabContainer.addEventListener("TabClose", this, false);
     tabContainer.addEventListener("TabPinned", this, false);
@@ -744,16 +800,17 @@ var gDevToolsBrowser = exports.gDevTools
 
    * @param {boolean} shuttingDown
    *        True if firefox is currently shutting down. We may prevent doing
    *        some cleanups to speed it up. Otherwise everything need to be
    *        cleaned up in order to be able to load devtools again.
    */
   destroy: function ({ shuttingDown }) {
     Services.prefs.removeObserver("devtools.", gDevToolsBrowser);
+    Services.obs.removeObserver(gDevToolsBrowser, "lightweight-theme-changed", false);
     Services.obs.removeObserver(gDevToolsBrowser, "browser-delayed-startup-finished");
     Services.obs.removeObserver(gDevToolsBrowser, "quit-application");
     Services.obs.removeObserver(gDevToolsBrowser, "sdk:loader:destroy");
 
     gDevToolsBrowser._pingTelemetry();
     gDevToolsBrowser._telemetry = null;
 
     for (let win of gDevToolsBrowser._trackedBrowserWindows) {
@@ -783,16 +840,17 @@ gDevTools.on("tool-unregistered", functi
 
 gDevTools.on("toolbox-ready", gDevToolsBrowser._updateMenuCheckbox);
 gDevTools.on("toolbox-destroyed", gDevToolsBrowser._updateMenuCheckbox);
 
 Services.obs.addObserver(gDevToolsBrowser, "quit-application", false);
 Services.obs.addObserver(gDevToolsBrowser, "browser-delayed-startup-finished", false);
 // Watch for module loader unload. Fires when the tools are reloaded.
 Services.obs.addObserver(gDevToolsBrowser, "sdk:loader:destroy", false);
+Services.obs.addObserver(gDevToolsBrowser, "lightweight-theme-changed", false);
 
 // Fake end of browser window load event for all already opened windows
 // that is already fully loaded.
 let enumerator = Services.wm.getEnumerator(gDevTools.chromeWindowType);
 while (enumerator.hasMoreElements()) {
   let win = enumerator.getNext();
   if (win.gBrowserInit && win.gBrowserInit.delayedStartupFinished) {
     gDevToolsBrowser._registerBrowserWindow(win);
--- a/devtools/client/framework/test/browser.ini
+++ b/devtools/client/framework/test/browser.ini
@@ -70,16 +70,17 @@ skip-if = e10s # Bug 1069044 - destroyIn
 [browser_toolbox_sidebar.js]
 [browser_toolbox_sidebar_events.js]
 [browser_toolbox_sidebar_existing_tabs.js]
 [browser_toolbox_sidebar_overflow_menu.js]
 [browser_toolbox_split_console.js]
 [browser_toolbox_target.js]
 [browser_toolbox_tabsswitch_shortcuts.js]
 [browser_toolbox_textbox_context_menu.js]
+[browser_toolbox_theme.js]
 [browser_toolbox_theme_registration.js]
 [browser_toolbox_toggle.js]
 [browser_toolbox_tool_ready.js]
 [browser_toolbox_tool_remote_reopen.js]
 [browser_toolbox_tools_per_toolbox_registration.js]
 [browser_toolbox_transport_events.js]
 [browser_toolbox_view_source_01.js]
 [browser_toolbox_view_source_02.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/framework/test/browser_toolbox_theme.js
@@ -0,0 +1,76 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const COMPACT_LIGHT_ID = "firefox-compact-light@mozilla.org";
+const COMPACT_DARK_ID = "firefox-compact-dark@mozilla.org";
+const PREF_DEVTOOLS_THEME = "devtools.theme";
+const {LightweightThemeManager} = Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm", {});
+
+registerCleanupFunction(() => {
+  // Set preferences back to their original values
+  Services.prefs.clearUserPref(PREF_DEVTOOLS_THEME);
+  LightweightThemeManager.currentTheme = null;
+});
+
+add_task(function* testDevtoolsTheme() {
+  info("Checking stylesheet and :root attributes based on devtools theme.");
+  Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "light");
+  is(document.documentElement.getAttribute("devtoolstheme"), "light",
+    "The documentElement has an attribute based on devtools theme.");
+
+  Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "dark");
+  is(document.documentElement.getAttribute("devtoolstheme"), "dark",
+    "The documentElement has an attribute based on devtools theme.");
+
+  Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "firebug");
+  is(document.documentElement.getAttribute("devtoolstheme"), "light",
+    "The documentElement has 'light' as a default for the devtoolstheme attribute");
+});
+
+add_task(function* testDevtoolsAndCompactThemeSyncing() {
+  if (!AppConstants.INSTALL_COMPACT_THEMES) {
+    ok(true, "No need to run this test since themes aren't installed");
+    return;
+  }
+
+  info("Devtools theme light -> dark when dark compact applied");
+  Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "light");
+  LightweightThemeManager.currentTheme = LightweightThemeManager.getUsedTheme(COMPACT_DARK_ID);
+  is(Services.prefs.getCharPref(PREF_DEVTOOLS_THEME), "dark");
+
+  info("Devtools theme dark -> light when light compact applied");
+  Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "dark");
+  LightweightThemeManager.currentTheme = LightweightThemeManager.getUsedTheme(COMPACT_LIGHT_ID);
+  is(Services.prefs.getCharPref(PREF_DEVTOOLS_THEME), "light");
+
+  info("Devtools theme shouldn't change if it wasn't light or dark during lwt change");
+  Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "firebug");
+  LightweightThemeManager.currentTheme = LightweightThemeManager.getUsedTheme(COMPACT_DARK_ID);
+  is(Services.prefs.getCharPref(PREF_DEVTOOLS_THEME), "firebug");
+
+  info("Compact theme dark -> light when devtools changes dark -> light");
+  LightweightThemeManager.currentTheme = LightweightThemeManager.getUsedTheme(COMPACT_DARK_ID);
+  Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "dark");
+  Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "light");
+  is(LightweightThemeManager.currentTheme, LightweightThemeManager.getUsedTheme(COMPACT_LIGHT_ID));
+
+  info("Compact theme dark -> light when devtools changes dark -> firebug");
+  LightweightThemeManager.currentTheme = LightweightThemeManager.getUsedTheme(COMPACT_DARK_ID);
+  Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "dark");
+  Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "firebug");
+  is(LightweightThemeManager.currentTheme, LightweightThemeManager.getUsedTheme(COMPACT_LIGHT_ID));
+
+  info("Compact theme light -> dark when devtools changes light -> dark");
+  LightweightThemeManager.currentTheme = LightweightThemeManager.getUsedTheme(COMPACT_LIGHT_ID);
+  Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "light");
+  Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "dark");
+  is(LightweightThemeManager.currentTheme, LightweightThemeManager.getUsedTheme(COMPACT_DARK_ID));
+
+  info("Compact theme shouldn't change if it wasn't set during devtools change");
+  LightweightThemeManager.currentTheme = null;
+  Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "light");
+  Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "dark");
+  is(LightweightThemeManager.currentTheme, null);
+});
--- a/devtools/client/webconsole/net/test/mochitest/head.js
+++ b/devtools/client/webconsole/net/test/mochitest/head.js
@@ -16,18 +16,18 @@ const FRAME_SCRIPT_UTILS_URL =
 const NET_INFO_PREF = "devtools.webconsole.filter.networkinfo";
 const NET_XHR_PREF = "devtools.webconsole.filter.netxhr";
 
 // Enable XHR logging for the test
 Services.prefs.setBoolPref(NET_INFO_PREF, true);
 Services.prefs.setBoolPref(NET_XHR_PREF, true);
 
 registerCleanupFunction(() => {
-  Services.prefs.clearUserPref(NET_INFO_PREF, true);
-  Services.prefs.clearUserPref(NET_XHR_PREF, true);
+  Services.prefs.clearUserPref(NET_INFO_PREF);
+  Services.prefs.clearUserPref(NET_XHR_PREF);
 });
 
 // Use the old webconsole since the new one doesn't yet support
 // XHR spy. See Bug 1304794.
 Services.prefs.setBoolPref("devtools.webconsole.new-frontend-enabled", false);
 registerCleanupFunction(function* () {
   Services.prefs.clearUserPref("devtools.webconsole.new-frontend-enabled");
 });
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -64,31 +64,20 @@
 #include "nsIDOMXULButtonElement.h"
 #include "nsIDOMXULCheckboxElement.h"
 #include "nsIDOMXULPopupElement.h"
 
 // Event related includes
 #include "nsIDOMEventTarget.h"
 
 // CSS related includes
-#include "nsCSSRules.h"
 #include "nsIDOMCSSRule.h"
 #include "nsMemory.h"
 
 // includes needed for the prototype chain interfaces
-#include "nsIDOMCSSKeyframeRule.h"
-#include "nsIDOMCSSKeyframesRule.h"
-#include "nsIDOMCSSImportRule.h"
-#include "nsIDOMCSSMediaRule.h"
-#include "nsIDOMCSSFontFaceRule.h"
-#include "nsIDOMCSSMozDocumentRule.h"
-#include "nsIDOMCSSSupportsRule.h"
-#include "nsIDOMCSSCounterStyleRule.h"
-#include "nsIDOMCSSPageRule.h"
-#include "nsIDOMCSSStyleRule.h"
 #include "nsIDOMXULCommandDispatcher.h"
 #include "nsIControllers.h"
 #ifdef MOZ_XUL
 #include "nsITreeSelection.h"
 #include "nsITreeContentView.h"
 #include "nsITreeView.h"
 #include "nsIXULTemplateBuilder.h"
 #endif
@@ -184,26 +173,16 @@ static nsDOMClassInfoData sClassInfoData
                            nsIXPCScriptable::WANT_RESOLVE |
                            nsIXPCScriptable::WANT_HASINSTANCE |
                            nsIXPCScriptable::WANT_CALL |
                            nsIXPCScriptable::WANT_CONSTRUCT |
                            nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE)
 
   // Misc Core related classes
 
-  // CSS classes
-  NS_DEFINE_CLASSINFO_DATA(CSSStyleRule, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(CSSImportRule, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(CSSMediaRule, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(CSSNameSpaceRule, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
-
   // XUL classes
 #ifdef MOZ_XUL
   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULCommandDispatcher, nsDOMGenericSH,
                                       DOM_DEFAULT_SCRIPTABLE_FLAGS)
 #endif
   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULControllers, nsNonDOMObjectSH,
                                       DEFAULT_SCRIPTABLE_FLAGS)
 #ifdef MOZ_XUL
@@ -216,55 +195,32 @@ static nsDOMClassInfoData sClassInfoData
 #ifdef MOZ_XUL
   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULTemplateBuilder, nsDOMGenericSH,
                                       DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULTreeBuilder, nsDOMGenericSH,
                                       DEFAULT_SCRIPTABLE_FLAGS)
 #endif
 
-  NS_DEFINE_CLASSINFO_DATA(CSSMozDocumentRule, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
-
-  NS_DEFINE_CLASSINFO_DATA(CSSSupportsRule, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
-
-  NS_DEFINE_CLASSINFO_DATA(CSSFontFaceRule, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
-
   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ContentFrameMessageManager,
                                        nsMessageManagerSH<nsEventTargetSH>,
                                        DOM_DEFAULT_SCRIPTABLE_FLAGS |
                                        nsIXPCScriptable::WANT_ENUMERATE |
                                        nsIXPCScriptable::IS_GLOBAL_OBJECT)
   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ContentProcessMessageManager,
                                        nsMessageManagerSH<nsDOMGenericSH>,
                                        DOM_DEFAULT_SCRIPTABLE_FLAGS |
                                        nsIXPCScriptable::WANT_ENUMERATE |
                                        nsIXPCScriptable::IS_GLOBAL_OBJECT)
   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ChromeMessageBroadcaster, nsDOMGenericSH,
                                        DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ChromeMessageSender, nsDOMGenericSH,
                                        DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
 
-  NS_DEFINE_CLASSINFO_DATA(CSSKeyframeRule, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(CSSKeyframesRule, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
-
-  NS_DEFINE_CLASSINFO_DATA(CSSCounterStyleRule, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
-
-  NS_DEFINE_CLASSINFO_DATA(CSSPageRule, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
-
-  NS_DEFINE_CLASSINFO_DATA(CSSFontFeatureValuesRule, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
-
   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULControlElement, nsDOMGenericSH,
                                       DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULLabeledControlElement, nsDOMGenericSH,
                                       DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULButtonElement, nsDOMGenericSH,
                                       DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULCheckboxElement, nsDOMGenericSH,
                                       DOM_DEFAULT_SCRIPTABLE_FLAGS)
@@ -507,32 +463,16 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(DOMPrototype, nsIDOMDOMConstructor)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMConstructor)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(DOMConstructor, nsIDOMDOMConstructor)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMConstructor)
   DOM_CLASSINFO_MAP_END
 
-  DOM_CLASSINFO_MAP_BEGIN(CSSStyleRule, nsIDOMCSSStyleRule)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSStyleRule)
-  DOM_CLASSINFO_MAP_END
-
-  DOM_CLASSINFO_MAP_BEGIN(CSSImportRule, nsIDOMCSSImportRule)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSImportRule)
-  DOM_CLASSINFO_MAP_END
-
-  DOM_CLASSINFO_MAP_BEGIN(CSSMediaRule, nsIDOMCSSMediaRule)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSMediaRule)
-  DOM_CLASSINFO_MAP_END
-
-  DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(CSSNameSpaceRule, nsIDOMCSSRule)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSRule)
-  DOM_CLASSINFO_MAP_END
-
 #ifdef MOZ_XUL
   DOM_CLASSINFO_MAP_BEGIN(XULCommandDispatcher, nsIDOMXULCommandDispatcher)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULCommandDispatcher)
   DOM_CLASSINFO_MAP_END
 #endif
 
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULControllers, nsIControllers)
     DOM_CLASSINFO_MAP_ENTRY(nsIControllers)
@@ -556,28 +496,16 @@ nsDOMClassInfo::Init()
 
   DOM_CLASSINFO_MAP_BEGIN(XULTreeBuilder, nsIXULTreeBuilder)
     DOM_CLASSINFO_MAP_ENTRY(nsIXULTreeBuilder)
     DOM_CLASSINFO_MAP_ENTRY(nsIXULTemplateBuilder)
     DOM_CLASSINFO_MAP_ENTRY(nsITreeView)
   DOM_CLASSINFO_MAP_END
 #endif
 
-  DOM_CLASSINFO_MAP_BEGIN(CSSMozDocumentRule, nsIDOMCSSMozDocumentRule)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSMozDocumentRule)
-  DOM_CLASSINFO_MAP_END
-
-  DOM_CLASSINFO_MAP_BEGIN(CSSSupportsRule, nsIDOMCSSSupportsRule)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSSupportsRule)
-  DOM_CLASSINFO_MAP_END
-
-  DOM_CLASSINFO_MAP_BEGIN(CSSFontFaceRule, nsIDOMCSSFontFaceRule)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSFontFaceRule)
-  DOM_CLASSINFO_MAP_END
-
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ContentFrameMessageManager, nsISupports)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
     DOM_CLASSINFO_MAP_ENTRY(nsIMessageListenerManager)
     DOM_CLASSINFO_MAP_ENTRY(nsIMessageSender)
     DOM_CLASSINFO_MAP_ENTRY(nsISyncMessageSender)
     DOM_CLASSINFO_MAP_ENTRY(nsIContentFrameMessageManager)
   DOM_CLASSINFO_MAP_END
 
@@ -598,36 +526,16 @@ nsDOMClassInfo::Init()
 
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ChromeMessageSender, nsISupports)
     DOM_CLASSINFO_MAP_ENTRY(nsIFrameScriptLoader)
     DOM_CLASSINFO_MAP_ENTRY(nsIProcessScriptLoader)
     DOM_CLASSINFO_MAP_ENTRY(nsIMessageListenerManager)
     DOM_CLASSINFO_MAP_ENTRY(nsIMessageSender)
   DOM_CLASSINFO_MAP_END
 
-  DOM_CLASSINFO_MAP_BEGIN(CSSKeyframeRule, nsIDOMCSSKeyframeRule)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSKeyframeRule)
-  DOM_CLASSINFO_MAP_END
-
-  DOM_CLASSINFO_MAP_BEGIN(CSSKeyframesRule, nsIDOMCSSKeyframesRule)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSKeyframesRule)
-  DOM_CLASSINFO_MAP_END
-
-  DOM_CLASSINFO_MAP_BEGIN(CSSCounterStyleRule, nsIDOMCSSCounterStyleRule)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSCounterStyleRule)
-  DOM_CLASSINFO_MAP_END
-
-  DOM_CLASSINFO_MAP_BEGIN(CSSPageRule, nsIDOMCSSPageRule)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSPageRule)
-  DOM_CLASSINFO_MAP_END
-
-  DOM_CLASSINFO_MAP_BEGIN(CSSFontFeatureValuesRule, nsIDOMCSSFontFeatureValuesRule)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSFontFeatureValuesRule)
-  DOM_CLASSINFO_MAP_END
-
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULControlElement, nsIDOMXULControlElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULControlElement)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULLabeledControlElement, nsIDOMXULLabeledControlElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULLabeledControlElement)
   DOM_CLASSINFO_MAP_END
 
--- a/dom/base/nsDOMClassInfoID.h
+++ b/dom/base/nsDOMClassInfoID.h
@@ -14,58 +14,36 @@
 
 #include "nsIXPCScriptable.h"
 
 enum nsDOMClassInfoID
 {
   eDOMClassInfo_DOMPrototype_id,
   eDOMClassInfo_DOMConstructor_id,
 
-  // CSS classes
-  eDOMClassInfo_CSSStyleRule_id,
-  eDOMClassInfo_CSSImportRule_id,
-  eDOMClassInfo_CSSMediaRule_id,
-  eDOMClassInfo_CSSNameSpaceRule_id,
-
   // XUL classes
 #ifdef MOZ_XUL
   eDOMClassInfo_XULCommandDispatcher_id,
 #endif
   eDOMClassInfo_XULControllers_id,
 #ifdef MOZ_XUL
   eDOMClassInfo_TreeSelection_id,
   eDOMClassInfo_TreeContentView_id,
 #endif
 
 #ifdef MOZ_XUL
   eDOMClassInfo_XULTemplateBuilder_id,
   eDOMClassInfo_XULTreeBuilder_id,
 #endif
 
-  eDOMClassInfo_CSSMozDocumentRule_id,
-  eDOMClassInfo_CSSSupportsRule_id,
-
-  // @font-face in CSS
-  eDOMClassInfo_CSSFontFaceRule_id,
-
   eDOMClassInfo_ContentFrameMessageManager_id,
   eDOMClassInfo_ContentProcessMessageManager_id,
   eDOMClassInfo_ChromeMessageBroadcaster_id,
   eDOMClassInfo_ChromeMessageSender_id,
 
-  eDOMClassInfo_CSSKeyframeRule_id,
-  eDOMClassInfo_CSSKeyframesRule_id,
-
-  // @counter-style in CSS
-  eDOMClassInfo_CSSCounterStyleRule_id,
-
-  eDOMClassInfo_CSSPageRule_id,
-
-  eDOMClassInfo_CSSFontFeatureValuesRule_id,
-
   eDOMClassInfo_XULControlElement_id,
   eDOMClassInfo_XULLabeledControlElement_id,
   eDOMClassInfo_XULButtonElement_id,
   eDOMClassInfo_XULCheckboxElement_id,
   eDOMClassInfo_XULPopupElement_id,
 
   // This one better be the last one in this list
   eDOMClassInfoIDCount
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -5175,47 +5175,45 @@ nsDocument::StyleRuleChanged(StyleSheet*
                              css::Rule* aStyleRule)
 {
   NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleChanged, (aSheet));
 
   if (StyleSheetChangeEventsEnabled()) {
     DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent,
                                "StyleRuleChanged",
                                mRule,
-                               aStyleRule ? aStyleRule->GetDOMRule() : nullptr);
+                               aStyleRule);
   }
 }
 
 void
 nsDocument::StyleRuleAdded(StyleSheet* aSheet,
                            css::Rule* aStyleRule)
 {
   NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleAdded, (aSheet));
 
   if (StyleSheetChangeEventsEnabled()) {
     DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent,
                                "StyleRuleAdded",
                                mRule,
-                               aStyleRule ? aStyleRule->GetDOMRule()
-                                          : nullptr);
+                               aStyleRule);
   }
 }
 
 void
 nsDocument::StyleRuleRemoved(StyleSheet* aSheet,
                              css::Rule* aStyleRule)
 {
   NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleRemoved, (aSheet));
 
   if (StyleSheetChangeEventsEnabled()) {
     DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent,
                                "StyleRuleRemoved",
                                mRule,
-                               aStyleRule ? aStyleRule->GetDOMRule()
-                                          : nullptr);
+                               aStyleRule);
   }
 }
 
 #undef DO_STYLESHEET_NOTIFICATION
 
 already_AddRefed<AnonymousContent>
 nsIDocument::InsertAnonymousContent(Element& aElement, ErrorResult& aRv)
 {
--- a/dom/base/nsWrapperCache.h
+++ b/dom/base/nsWrapperCache.h
@@ -267,16 +267,19 @@ protected:
     if (mWrapper) {
       // Set the pointer to a value that will cause a crash if it is
       // dereferenced.
       mWrapper = reinterpret_cast<JSObject*>(1);
     }
   }
 
 private:
+  // Friend declarations for things that need to be able to call
+  // SetIsNotDOMBinding().  The goal is to get rid of all of these, and
+  // SetIsNotDOMBinding() too.
   friend class mozilla::dom::TabChildGlobal;
   friend class mozilla::dom::ProcessGlobal;
   friend class SandboxPrivate;
   friend class nsInProcessTabChildGlobal;
   friend class nsWindowRoot;
   void SetIsNotDOMBinding()
   {
     MOZ_ASSERT(!mWrapper && !(GetWrapperFlags() & ~WRAPPER_IS_NOT_DOM_BINDING),
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -191,33 +191,106 @@ DOMInterfaces = {
 'CSS': {
     'concrete': False,
 },
 
 'CSS2Properties': {
     'nativeType': 'nsDOMCSSDeclaration'
 },
 
+'CSSConditionRule': {
+    'concrete': False,
+    'nativeType': 'mozilla::css::ConditionRule',
+    'headerFile': 'mozilla/css/GroupRule.h',
+},
+
+'CSSCounterStyleRule': {
+    'nativeType': 'nsCSSCounterStyleRule',
+    'headerFile': 'nsCSSRules.h',
+},
+
+'CSSFontFaceRule': {
+    'nativeType': 'nsCSSFontFaceRule',
+    'headerFile': 'nsCSSRules.h',
+},
+
+'CSSFontFeatureValuesRule': {
+    'nativeType': 'nsCSSFontFeatureValuesRule',
+    'headerFile': 'nsCSSRules.h',
+},
+
+'CSSGroupingRule': {
+    'concrete': False,
+    'nativeType': 'mozilla::css::GroupRule',
+},
+
+'CSSImportRule': {
+    'nativeType': 'mozilla::css::ImportRule',
+},
+
+'CSSKeyframeRule': {
+    'nativeType': 'nsCSSKeyframeRule',
+    'headerFile': 'nsCSSRules.h',
+},
+
+'CSSKeyframesRule': {
+    'nativeType': 'nsCSSKeyframesRule',
+    'headerFile': 'nsCSSRules.h',
+},
+
 'CSSLexer': {
     'wrapperCache': False
 },
 
+'CSSMediaRule': {
+    'nativeType': 'mozilla::css::MediaRule',
+    'headerFile': 'nsCSSRules.h',
+},
+
+'CSSMozDocumentRule': {
+    'nativeType': 'mozilla::css::DocumentRule',
+    'headerFile': 'nsCSSRules.h',
+},
+
+'CSSNamespaceRule': {
+    'nativeType': 'mozilla::css::NameSpaceRule',
+},
+
+'CSSPageRule': {
+    'nativeType': 'nsCSSPageRule',
+    'headerFile': 'nsCSSRules.h',
+},
+
 'CSSPrimitiveValue': {
     'nativeType': 'nsROCSSPrimitiveValue',
 },
 
+'CSSRule': {
+    'concrete': False,
+    'nativeType': 'mozilla::css::Rule'
+},
+
 'CSSStyleDeclaration': {
     'nativeType': 'nsICSSDeclaration'
 },
 
+'CSSStyleRule': {
+    'nativeType': 'mozilla::BindingStyleRule',
+},
+
 'CSSStyleSheet': {
     'nativeType': 'mozilla::StyleSheet',
     'binaryNames': { 'ownerRule': 'DOMOwnerRule' },
 },
 
+'CSSSupportsRule': {
+    'nativeType': 'mozilla::CSSSupportsRule',
+    'headerFile': 'nsCSSRules.h',
+},
+
 'CSSValue': {
     'concrete': False
 },
 
 'CSSValueList': {
     'nativeType': 'nsDOMCSSValueList'
 },
 
@@ -1655,17 +1728,16 @@ def addExternalIface(iface, nativeType=N
         domInterface['nativeType'] = nativeType
     if not headerFile is None:
         domInterface['headerFile'] = headerFile
     domInterface['notflattened'] = notflattened
     DOMInterfaces[iface] = domInterface
 
 addExternalIface('ApplicationCache', nativeType='nsIDOMOfflineResourceList')
 addExternalIface('Counter')
-addExternalIface('CSSRule')
 addExternalIface('RTCDataChannel', nativeType='nsIDOMDataChannel')
 addExternalIface('HitRegionOptions', nativeType='nsISupports')
 addExternalIface('imgINotificationObserver', nativeType='imgINotificationObserver')
 addExternalIface('imgIRequest', nativeType='imgIRequest', notflattened=True)
 addExternalIface('MenuBuilder', nativeType='nsIMenuBuilder', notflattened=True)
 addExternalIface('MozControllers', nativeType='nsIControllers')
 addExternalIface('MozFrameLoader', nativeType='nsIFrameLoader', notflattened=True)
 addExternalIface('MozObserver', nativeType='nsIObserver', notflattened=True)
--- a/dom/events/DataTransferItem.cpp
+++ b/dom/events/DataTransferItem.cpp
@@ -472,49 +472,50 @@ DataTransferItem::Data(nsIPrincipal* aPr
      mDataTransfer->GetEventMessage() != ePaste);
 
   // Check if the caller is allowed to access the drag data. Callers with
   // chrome privileges can always read the data. During the
   // drop event, allow retrieving the data except in the case where the
   // source of the drag is in a child frame of the caller. In that case,
   // we only allow access to data of the same principal. During other events,
   // only allow access to the data with the same principal.
+  //
+  // We don't want to fail with an exception in this siutation, rather we want
+  // to just pretend as though the stored data is "nullptr". This is consistent
+  // with Chrome's behavior and is less surprising for web applications which
+  // don't expect execptions to be raised when performing certain operations.
   if (Principal() && checkItemPrincipal &&
       !aPrincipal->Subsumes(Principal())) {
-    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return nullptr;
   }
 
   if (!variant) {
     return nullptr;
   }
 
   nsCOMPtr<nsISupports> data;
   nsresult rv = variant->GetAsISupports(getter_AddRefs(data));
   if (NS_SUCCEEDED(rv) && data) {
     nsCOMPtr<EventTarget> pt = do_QueryInterface(data);
     if (pt) {
       nsIScriptContext* c = pt->GetContextForEventHandlers(&rv);
       if (NS_WARN_IF(NS_FAILED(rv) || !c)) {
-        aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
         return nullptr;
       }
 
       nsIGlobalObject* go = c->GetGlobalObject();
       if (NS_WARN_IF(!go)) {
-        aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
         return nullptr;
       }
 
       nsCOMPtr<nsIScriptObjectPrincipal> sp = do_QueryInterface(go);
       MOZ_ASSERT(sp, "This cannot fail on the main thread.");
 
       nsIPrincipal* dataPrincipal = sp->GetPrincipal();
       if (NS_WARN_IF(!dataPrincipal || !aPrincipal->Equals(dataPrincipal))) {
-        aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
         return nullptr;
       }
     }
   }
 
   return variant.forget();
 }
 
--- a/dom/interfaces/css/nsIDOMCSSCounterStyleRule.idl
+++ b/dom/interfaces/css/nsIDOMCSSCounterStyleRule.idl
@@ -1,18 +1,18 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "nsIDOMCSSRule.idl"
+#include "nsISupports.idl"
 
 [scriptable, uuid(9b5e48ce-d84c-4e31-aff5-34e9f4141313)]
-interface nsIDOMCSSCounterStyleRule : nsIDOMCSSRule
+interface nsIDOMCSSCounterStyleRule : nsISupports
 {
   attribute DOMString name;
   attribute DOMString system;
   attribute DOMString symbols;
   attribute DOMString additiveSymbols;
   attribute DOMString negative;
   attribute DOMString prefix;
   attribute DOMString suffix;
--- a/dom/interfaces/css/nsIDOMCSSFontFaceRule.idl
+++ b/dom/interfaces/css/nsIDOMCSSFontFaceRule.idl
@@ -1,12 +1,14 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "nsIDOMCSSRule.idl"
+#include "nsISupports.idl"
+
+interface nsIDOMCSSStyleDeclaration;
 
 [scriptable, uuid(db971017-fe0c-4529-972c-8217f2fee217)]
-interface nsIDOMCSSFontFaceRule : nsIDOMCSSRule
+interface nsIDOMCSSFontFaceRule : nsISupports
 {
   readonly attribute nsIDOMCSSStyleDeclaration  style;
 };
--- a/dom/interfaces/css/nsIDOMCSSFontFeatureValuesRule.idl
+++ b/dom/interfaces/css/nsIDOMCSSFontFeatureValuesRule.idl
@@ -1,16 +1,16 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "nsIDOMCSSRule.idl"
+#include "nsISupports.idl"
 
 [scriptable, uuid(a343d27f-1da6-4fc3-9355-d4ca434f958e)]
-interface nsIDOMCSSFontFeatureValuesRule : nsIDOMCSSRule
+interface nsIDOMCSSFontFeatureValuesRule : nsISupports
 {
   attribute DOMString fontFamily;
                       // raises(DOMException) on setting
 
   attribute DOMString valueText;
                       // raises(DOMException) on setting
 };
--- a/dom/interfaces/css/nsIDOMCSSGroupingRule.idl
+++ b/dom/interfaces/css/nsIDOMCSSGroupingRule.idl
@@ -1,20 +1,22 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "nsIDOMCSSRule.idl"
+#include "nsISupports.idl"
+
+interface nsIDOMCSSRuleList;
 
 /**
  * Interface for at-rules that have child rules in the CSS OM.
  */
 [scriptable, uuid(a0e3324a-f911-4baf-9591-5322c76cbb0d)]
-interface nsIDOMCSSGroupingRule : nsIDOMCSSRule
+interface nsIDOMCSSGroupingRule : nsISupports
 {
   readonly attribute nsIDOMCSSRuleList cssRules;
 
   unsigned long      insertRule(in DOMString rule,
                                 in unsigned long index)
                                         raises(DOMException);
   void               deleteRule(in unsigned long index)
                                         raises(DOMException);
--- a/dom/interfaces/css/nsIDOMCSSImportRule.idl
+++ b/dom/interfaces/css/nsIDOMCSSImportRule.idl
@@ -1,14 +1,17 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "nsIDOMCSSRule.idl"
+#include "nsISupports.idl"
+
+interface nsIDOMMediaList;
+interface nsIDOMCSSStyleSheet;
 
 [scriptable, uuid(d3b2b914-01ef-4663-beda-a6475a26f491)]
-interface nsIDOMCSSImportRule : nsIDOMCSSRule
+interface nsIDOMCSSImportRule : nsISupports
 {
   readonly attribute DOMString           href;
   readonly attribute nsIDOMMediaList     media;
   readonly attribute nsIDOMCSSStyleSheet styleSheet;
 };
--- a/dom/interfaces/css/nsIDOMCSSKeyframeRule.idl
+++ b/dom/interfaces/css/nsIDOMCSSKeyframeRule.idl
@@ -1,13 +1,15 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "nsIDOMCSSRule.idl"
+#include "nsISupports.idl"
+
+interface nsIDOMCSSStyleDeclaration;
 
 [scriptable, uuid(a281a8b4-eaa2-49a8-8b97-acc2814a57c9)]
-interface nsIDOMCSSKeyframeRule : nsIDOMCSSRule
+interface nsIDOMCSSKeyframeRule : nsISupports
 {
            attribute DOMString                 keyText;
   readonly attribute nsIDOMCSSStyleDeclaration style;
 };
--- a/dom/interfaces/css/nsIDOMCSSKeyframesRule.idl
+++ b/dom/interfaces/css/nsIDOMCSSKeyframesRule.idl
@@ -1,17 +1,20 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "nsIDOMCSSRule.idl"
+#include "nsISupports.idl"
+
+interface nsIDOMCSSRuleList;
+interface nsIDOMCSSKeyframeRule;
 
 [scriptable, uuid(400f4b70-ad0a-4047-aba4-ee8019f6b907)]
-interface nsIDOMCSSKeyframesRule : nsIDOMCSSRule
+interface nsIDOMCSSKeyframesRule : nsISupports
 {
            attribute DOMString         name;
   readonly attribute nsIDOMCSSRuleList cssRules;
 
   void                     appendRule(in DOMString rule);
   void                     deleteRule(in DOMString key);
   nsIDOMCSSKeyframeRule    findRule(in DOMString key);
 };
--- a/dom/interfaces/css/nsIDOMCSSMediaRule.idl
+++ b/dom/interfaces/css/nsIDOMCSSMediaRule.idl
@@ -1,15 +1,17 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIDOMCSSConditionRule.idl"
 
+interface nsIDOMMediaList;
+
 /**
  * Interface for @media rules in the CSS OM.
  */
 [scriptable, uuid(6cf9c5b2-fa0f-43c0-aa50-ef85b4756e3a)]
 interface nsIDOMCSSMediaRule : nsIDOMCSSConditionRule
 {
   readonly attribute nsIDOMMediaList   media;
 };
--- a/dom/interfaces/css/nsIDOMCSSPageRule.idl
+++ b/dom/interfaces/css/nsIDOMCSSPageRule.idl
@@ -1,15 +1,17 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "nsIDOMCSSRule.idl"
+#include "nsISupports.idl"
+
+interface nsIDOMCSSStyleDeclaration;
 
 [scriptable, uuid(c119072b-7d2f-4aeb-a90d-e2d6b606c32a)]
-interface nsIDOMCSSPageRule : nsIDOMCSSRule
+interface nsIDOMCSSPageRule : nsISupports
 {
            //attribute DOMString        selectorText;
                                         // raises(DOMException) on setting
 
   readonly attribute nsIDOMCSSStyleDeclaration  style;
 };
--- a/dom/interfaces/css/nsIDOMCSSStyleRule.idl
+++ b/dom/interfaces/css/nsIDOMCSSStyleRule.idl
@@ -1,15 +1,17 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "nsIDOMCSSRule.idl"
+#include "nsISupports.idl"
+
+interface nsIDOMCSSStyleDeclaration;
 
 [scriptable, uuid(b5e9af48-a7c2-4f88-aae3-58307af4b5a5)]
-interface nsIDOMCSSStyleRule : nsIDOMCSSRule
+interface nsIDOMCSSStyleRule : nsISupports
 {
            attribute DOMString        selectorText;
                                         // raises(DOMException) on setting
 
   readonly attribute nsIDOMCSSStyleDeclaration  style;
 };
--- a/dom/interfaces/css/nsIDOMCSSUnknownRule.idl
+++ b/dom/interfaces/css/nsIDOMCSSUnknownRule.idl
@@ -1,11 +1,11 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "nsIDOMCSSRule.idl"
+#include "nsISupports.idl"
 
 [scriptable, uuid(98f4c27b-fb35-4355-8fd9-546c4697d71a)]
-interface nsIDOMCSSUnknownRule : nsIDOMCSSRule
+interface nsIDOMCSSUnknownRule : nsISupports
 {
 };
--- a/dom/media/MediaStreamGraph.cpp
+++ b/dom/media/MediaStreamGraph.cpp
@@ -1712,16 +1712,20 @@ MediaStreamGraphImpl::RunInStableState(b
         // take locks, and we don't want to deadlock.
         LIFECYCLE_LOG("Starting a graph (%p) ! %s\n",
                       this,
                       CurrentDriver()->AsAudioCallbackDriver() ? "AudioDriver" :
                                                                  "SystemDriver");
         RefPtr<GraphDriver> driver = CurrentDriver();
         MonitorAutoUnlock unlock(mMonitor);
         driver->Start();
+        // It's not safe to Shutdown() a thread from StableState, and
+        // releasing this may shutdown a SystemClockDriver thread.
+        // Proxy the release to outside of StableState.
+        NS_ReleaseOnMainThread(driver.forget(), true); // always proxy
       }
     }
 
     if ((mForceShutDown || !mRealtime) &&
         mLifecycleState == LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP) {
       // Defer calls to RunDuringShutdown() to happen while mMonitor is not held.
       for (uint32_t i = 0; i < mBackMessageQueue.Length(); ++i) {
         MessageBlock& mb = mBackMessageQueue[i];
--- a/dom/media/webaudio/AudioBuffer.h
+++ b/dom/media/webaudio/AudioBuffer.h
@@ -10,16 +10,17 @@
 #include "nsWrapperCache.h"
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/StaticMutex.h"
 #include "nsTArray.h"
 #include "js/TypeDecls.h"
 #include "mozilla/MemoryReporting.h"
+#include "mozilla/dom/TypedArray.h"
 
 namespace mozilla {
 
 class ErrorResult;
 class ThreadSharedFloatArrayBufferList;
 
 namespace dom {
 
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -244,17 +244,17 @@ var interfaceNamesInGlobalScope =
     "CSSKeyframeRule",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "CSSKeyframesRule",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "CSSMediaRule",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "CSSMozDocumentRule",
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    "CSSNameSpaceRule",
+    "CSSNamespaceRule",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "CSSPageRule",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "CSSPrimitiveValue",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "CSSPseudoElement", release: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "CSSRule",
new file mode 100644
--- /dev/null
+++ b/dom/webidl/CSSConditionRule.webidl
@@ -0,0 +1,14 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://drafts.csswg.org/css-conditional/#the-cssconditionrule-interface
+ */
+
+// https://drafts.csswg.org/css-conditional/#the-cssconditionrule-interface
+interface CSSConditionRule : CSSGroupingRule {
+  [SetterThrows]
+  attribute DOMString conditionText;
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/CSSCounterStyleRule.webidl
@@ -0,0 +1,23 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://drafts.csswg.org/css-counter-styles-3/#the-csscounterstylerule-interface
+ */
+
+// https://drafts.csswg.org/css-counter-styles-3/#the-csscounterstylerule-interface
+interface CSSCounterStyleRule : CSSRule {
+  attribute DOMString name;
+  attribute DOMString system;
+  attribute DOMString symbols;
+  attribute DOMString additiveSymbols;
+  attribute DOMString negative;
+  attribute DOMString prefix;
+  attribute DOMString suffix;
+  attribute DOMString range;
+  attribute DOMString pad;
+  attribute DOMString speakAs;
+  attribute DOMString fallback;
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/CSSFontFaceRule.webidl
@@ -0,0 +1,15 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://drafts.csswg.org/css-fonts/#om-fontface
+ */
+
+// https://drafts.csswg.org/css-fonts/#om-fontface
+// But we implement a very old draft, apparently....
+// See bug 1058408 for implementing the current spec.
+interface CSSFontFaceRule : CSSRule {
+  [SameObject] readonly attribute CSSStyleDeclaration style;
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/CSSFontFeatureValuesRule.webidl
@@ -0,0 +1,29 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://drafts.csswg.org/css-fonts/#om-fontfeaturevalues
+ */
+
+// https://drafts.csswg.org/css-fonts/#om-fontfeaturevalues
+// but we don't implement anything remotely resembling the spec.
+interface CSSFontFeatureValuesRule : CSSRule {
+  [SetterThrows]
+  attribute DOMString fontFamily;
+
+  // Not yet implemented
+  //  readonly attribute CSSFontFeatureValuesMap annotation;
+  //  readonly attribute CSSFontFeatureValuesMap ornaments;
+  //  readonly attribute CSSFontFeatureValuesMap stylistic;
+  //  readonly attribute CSSFontFeatureValuesMap swash;
+  //  readonly attribute CSSFontFeatureValuesMap characterVariant;
+  //  readonly attribute CSSFontFeatureValuesMap styleset;
+};
+
+partial interface CSSFontFeatureValuesRule {
+  // Gecko addition?
+  [SetterThrows]
+  attribute DOMString valueText;
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/CSSGroupingRule.webidl
@@ -0,0 +1,17 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://drafts.csswg.org/cssom/#cssgroupingrule
+ */
+
+// https://drafts.csswg.org/cssom/#cssgroupingrule
+interface CSSGroupingRule : CSSRule {
+  [SameObject] readonly attribute CSSRuleList cssRules;
+  [Throws]
+  unsigned long insertRule(DOMString rule, unsigned long index);
+  [Throws]
+  void deleteRule(unsigned long index);
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/CSSImportRule.webidl
@@ -0,0 +1,17 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://drafts.csswg.org/cssom/#cssimportrule
+ */
+
+// https://drafts.csswg.org/cssom/#cssimportrule
+interface CSSImportRule : CSSRule {
+  readonly attribute DOMString href;
+  [SameObject, PutForwards=mediaText] readonly attribute MediaList media;
+  // Per spec, the .styleSheet is never null, but in our implementation it can
+  // be.  See <https://bugzilla.mozilla.org/show_bug.cgi?id=1326509>.
+  [SameObject] readonly attribute CSSStyleSheet? styleSheet;
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/CSSKeyframeRule.webidl
@@ -0,0 +1,14 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://drafts.csswg.org/css-animations/#interface-csskeyframerule
+ */
+
+// https://drafts.csswg.org/css-animations/#interface-csskeyframerule
+interface CSSKeyframeRule : CSSRule {
+           attribute DOMString           keyText;
+  readonly attribute CSSStyleDeclaration style;
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/CSSKeyframesRule.webidl
@@ -0,0 +1,18 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://drafts.csswg.org/css-animations/#interface-csskeyframesrule
+ */
+
+// https://drafts.csswg.org/css-animations/#interface-csskeyframesrule
+interface CSSKeyframesRule : CSSRule {
+           attribute DOMString   name;
+  readonly attribute CSSRuleList cssRules;
+
+  void            appendRule(DOMString rule);
+  void            deleteRule(DOMString select);
+  CSSKeyframeRule? findRule(DOMString select);
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/CSSMediaRule.webidl
@@ -0,0 +1,17 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://drafts.csswg.org/cssom/#the-cssmediarule-interface
+ * https://drafts.csswg.org/css-conditional/#the-cssmediarule-interface
+ */
+
+// https://drafts.csswg.org/cssom/#the-cssmediarule-interface and
+// https://drafts.csswg.org/css-conditional/#the-cssmediarule-interface
+// except they disagree with each other.  We're taking the inheritance from
+// css-conditional and the PutForwards behavior from cssom.
+interface CSSMediaRule : CSSConditionRule {
+  [SameObject, PutForwards=mediaText] readonly attribute MediaList media;
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/CSSMozDocumentRule.webidl
@@ -0,0 +1,10 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+// This is a non-standard interface for @-moz-document rules
+interface CSSMozDocumentRule : CSSConditionRule {
+  // XXX Add access to the URL list.
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/CSSNamespaceRule.webidl
@@ -0,0 +1,16 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://drafts.csswg.org/cssom/#cssnamespacerule
+ */
+
+// https://drafts.csswg.org/cssom/#cssnamespacerule
+interface CSSNamespaceRule : CSSRule {
+  // Not implemented yet.  <See
+  // https://bugzilla.mozilla.org/show_bug.cgi?id=1326514>.
+  //  readonly attribute DOMString namespaceURI;
+  //  readonly attribute DOMString prefix;
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/CSSPageRule.webidl
@@ -0,0 +1,17 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://drafts.csswg.org/cssom/#the-csspagerule-interface
+ */
+
+// https://drafts.csswg.org/cssom/#the-csspagerule-interface
+// Per spec, this should inherit from CSSGroupingRule, but we don't
+// implement this yet.
+interface CSSPageRule : CSSRule {
+  // selectorText not implemented yet
+  //         attribute DOMString selectorText;
+  [SameObject, PutForwards=cssText] readonly attribute CSSStyleDeclaration style;
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/CSSRule.webidl
@@ -0,0 +1,52 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://drafts.csswg.org/cssom/#the-cssrule-interface
+ * https://drafts.csswg.org/css-animations/#interface-cssrule
+ * https://drafts.csswg.org/css-counter-styles-3/#extentions-to-cssrule-interface
+ * https://drafts.csswg.org/css-conditional-3/#extentions-to-cssrule-interface
+ * https://drafts.csswg.org/css-fonts-3/#om-fontfeaturevalues
+ */
+
+// https://drafts.csswg.org/cssom/#the-cssrule-interface
+interface CSSRule {
+
+  const unsigned short STYLE_RULE = 1;
+  const unsigned short CHARSET_RULE = 2; // historical
+  const unsigned short IMPORT_RULE = 3;
+  const unsigned short MEDIA_RULE = 4;
+  const unsigned short FONT_FACE_RULE = 5;
+  const unsigned short PAGE_RULE = 6;
+  // FIXME: We don't support MARGIN_RULE yet.
+  // XXXbz Should we expose the constant anyway?
+  // const unsigned short MARGIN_RULE = 9;
+  const unsigned short NAMESPACE_RULE = 10;
+  readonly attribute unsigned short type;
+  attribute DOMString cssText;
+  readonly attribute CSSRule? parentRule;
+  readonly attribute CSSStyleSheet? parentStyleSheet;
+};
+
+// https://drafts.csswg.org/css-animations/#interface-cssrule
+partial interface CSSRule {
+    const unsigned short KEYFRAMES_RULE = 7;
+    const unsigned short KEYFRAME_RULE = 8;
+};
+
+// https://drafts.csswg.org/css-counter-styles-3/#extentions-to-cssrule-interface
+partial interface CSSRule {
+    const unsigned short COUNTER_STYLE_RULE = 11;
+};
+
+// https://drafts.csswg.org/css-conditional-3/#extentions-to-cssrule-interface
+partial interface CSSRule {
+    const unsigned short SUPPORTS_RULE = 12;
+};
+
+// https://drafts.csswg.org/css-fonts-3/#om-fontfeaturevalues
+partial interface CSSRule {
+  const unsigned short FONT_FEATURE_VALUES_RULE = 14;
+};
--- a/dom/webidl/CSSStyleDeclaration.webidl
+++ b/dom/webidl/CSSStyleDeclaration.webidl
@@ -2,18 +2,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * The origin of this IDL file is
  * http://dev.w3.org/csswg/cssom/
  */
 
-interface CSSRule;
-
 interface CSSStyleDeclaration {
   [SetterThrows]
   attribute DOMString cssText;
 
   readonly attribute unsigned long length;
   getter DOMString item(unsigned long index);
 
   [Throws]
new file mode 100644
--- /dev/null
+++ b/dom/webidl/CSSStyleRule.webidl
@@ -0,0 +1,14 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://drafts.csswg.org/cssom/#the-cssstylerule-interface
+ */
+
+// https://drafts.csswg.org/cssom/#the-cssstylerule-interface
+interface CSSStyleRule : CSSRule {
+  attribute DOMString selectorText;
+  [SameObject, PutForwards=cssText] readonly attribute CSSStyleDeclaration style;
+};
--- a/dom/webidl/CSSStyleSheet.webidl
+++ b/dom/webidl/CSSStyleSheet.webidl
@@ -2,18 +2,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * The origin of this IDL file is
  * http://dev.w3.org/csswg/cssom/
  */
 
-interface CSSRule;
-
 enum CSSStyleSheetParsingMode {
   "author",
   "user",
   "agent"
 };
 
 interface CSSStyleSheet : StyleSheet {
   [Pure]
new file mode 100644
--- /dev/null
+++ b/dom/webidl/CSSSupportsRule.webidl
@@ -0,0 +1,12 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://drafts.csswg.org/css-conditional/#the-csssupportsrule-interface
+ */
+
+// https://drafts.csswg.org/css-conditional/#the-csssupportsrule-interface
+interface CSSSupportsRule : CSSConditionRule {
+};
--- a/dom/webidl/LegacyQueryInterface.webidl
+++ b/dom/webidl/LegacyQueryInterface.webidl
@@ -19,18 +19,20 @@ interface LegacyQueryInterface {
 };
 
 Attr implements LegacyQueryInterface;
 BarProp implements LegacyQueryInterface;
 BoxObject implements LegacyQueryInterface;
 CaretPosition implements LegacyQueryInterface;
 Comment implements LegacyQueryInterface;
 Crypto implements LegacyQueryInterface;
+CSSMozDocumentRule implements LegacyQueryInterface;
 CSSPrimitiveValue implements LegacyQueryInterface;
 CSSStyleDeclaration implements LegacyQueryInterface;
+CSSStyleRule implements LegacyQueryInterface;
 CSSValueList implements LegacyQueryInterface;
 DOMImplementation implements LegacyQueryInterface;
 DOMParser implements LegacyQueryInterface;
 DOMStringMap implements LegacyQueryInterface;
 DOMTokenList implements LegacyQueryInterface;
 Document implements LegacyQueryInterface;
 DocumentFragment implements LegacyQueryInterface;
 DocumentType implements LegacyQueryInterface;
--- a/dom/webidl/StyleRuleChangeEvent.webidl
+++ b/dom/webidl/StyleRuleChangeEvent.webidl
@@ -1,15 +1,13 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
-interface CSSRule;
-
 [ChromeOnly, Constructor(DOMString type, optional StyleRuleChangeEventInit eventInitDict)]
 interface StyleRuleChangeEvent : Event
 {
   readonly attribute CSSStyleSheet? stylesheet;
   readonly attribute CSSRule? rule;
 };
 
 dictionary StyleRuleChangeEventInit : EventInit
--- a/dom/webidl/StyleSheet.webidl
+++ b/dom/webidl/StyleSheet.webidl
@@ -2,18 +2,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * The origin of this IDL file is
  * http://dev.w3.org/csswg/cssom/
  */
 
-interface CSSRule;
-
 interface StyleSheet {
   [Constant]
   readonly attribute DOMString type;
   [Constant]
   readonly attribute DOMString? href;
   // Spec says "Node", but it can go null when the node gets a new
   // sheet.  That's also why it's not [Constant]
   [Pure]
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -84,22 +84,37 @@ WEBIDL_FILES = [
     'ConvolverNode.webidl',
     'Coordinates.webidl',
     'CreateOfferRequest.webidl',
     'Crypto.webidl',
     'CSPDictionaries.webidl',
     'CSPReport.webidl',
     'CSS.webidl',
     'CSSAnimation.webidl',
+    'CSSConditionRule.webidl',
+    'CSSCounterStyleRule.webidl',
+    'CSSFontFaceRule.webidl',
+    'CSSFontFeatureValuesRule.webidl',
+    'CSSGroupingRule.webidl',
+    'CSSImportRule.webidl',
+    'CSSKeyframeRule.webidl',
+    'CSSKeyframesRule.webidl',
     'CSSLexer.webidl',
+    'CSSMediaRule.webidl',
+    'CSSMozDocumentRule.webidl',
+    'CSSNamespaceRule.webidl',
+    'CSSPageRule.webidl',
     'CSSPrimitiveValue.webidl',
     'CSSPseudoElement.webidl',
+    'CSSRule.webidl',
     'CSSRuleList.webidl',
     'CSSStyleDeclaration.webidl',
+    'CSSStyleRule.webidl',
     'CSSStyleSheet.webidl',
+    'CSSSupportsRule.webidl',
     'CSSTransition.webidl',
     'CSSValue.webidl',
     'CSSValueList.webidl',
     'CustomElementRegistry.webidl',
     'DataContainerEvent.webidl',
     'DataTransfer.webidl',
     'DataTransferItem.webidl',
     'DataTransferItemList.webidl',
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -31,16 +31,17 @@
 
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/ErrorNames.h"
 #include "mozilla/LoadContext.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/DOMError.h"
 #include "mozilla/dom/ErrorEvent.h"
 #include "mozilla/dom/Headers.h"
 #include "mozilla/dom/InternalHeaders.h"
 #include "mozilla/dom/Navigator.h"
 #include "mozilla/dom/NotificationEvent.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/Request.h"
@@ -673,16 +674,27 @@ ServiceWorkerManager::Register(mozIDOMWi
     new ServiceWorkerRegisterJob(documentPrincipal, cleanedScope, spec,
                                  loadGroup, aLoadFlags);
   job->AppendResultCallback(cb);
   queue->ScheduleJob(job);
 
   AssertIsOnMainThread();
   Telemetry::Accumulate(Telemetry::SERVICE_WORKER_REGISTRATIONS, 1);
 
+  ContentChild* contentChild = ContentChild::GetSingleton();
+  if (contentChild &&
+      contentChild->GetRemoteType().EqualsLiteral(FILE_REMOTE_TYPE)) {
+    nsString message(NS_LITERAL_STRING("ServiceWorker registered by document "
+                                       "embedded in a file:/// URI.  This may "
+                                       "result in unexpected behavior."));
+    ReportToAllClients(cleanedScope, message, EmptyString(),
+                       EmptyString(), 0, 0, nsIScriptError::warningFlag);
+    Telemetry::Accumulate(Telemetry::FILE_EMBEDDED_SERVICEWORKERS, 1);
+  }
+
   promise.forget(aPromise);
   return NS_OK;
 }
 
 void
 ServiceWorkerManager::AppendPendingOperation(nsIRunnable* aRunnable)
 {
   MOZ_ASSERT(!mActor);
--- a/gfx/layers/ImageContainer.cpp
+++ b/gfx/layers/ImageContainer.cpp
@@ -92,30 +92,57 @@ BufferRecycleBin::ClearRecycledBuffers()
 {
   MutexAutoLock lock(mLock);
   if (!mRecycledBuffers.IsEmpty()) {
     mRecycledBuffers.Clear();
   }
   mRecycledBufferSize = 0;
 }
 
+ImageContainerListener::ImageContainerListener(ImageContainer* aImageContainer)
+  : mLock("mozilla.layers.ImageContainerListener.mLock")
+  , mImageContainer(aImageContainer)
+{
+}
+
+ImageContainerListener::~ImageContainerListener()
+{
+}
+
+void
+ImageContainerListener::NotifyComposite(const ImageCompositeNotification& aNotification)
+{
+  MutexAutoLock lock(mLock);
+  if (mImageContainer) {
+    mImageContainer->NotifyComposite(aNotification);
+  }
+}
+
+void
+ImageContainerListener::ClearImageContainer()
+{
+  MutexAutoLock lock(mLock);
+  mImageContainer = nullptr;
+}
+
 void
 ImageContainer::EnsureImageClient(bool aCreate)
 {
   // If we're not forcing a new ImageClient, then we can skip this if we don't have an existing
   // ImageClient, or if the existing one belongs to an IPC actor that is still open.
   if (!aCreate && (!mImageClient || mImageClient->GetForwarder()->GetLayersIPCActor()->IPCOpen())) {
     return;
   }
 
   RefPtr<ImageBridgeChild> imageBridge = ImageBridgeChild::GetSingleton();
   if (imageBridge) {
     mImageClient = imageBridge->CreateImageClient(CompositableType::IMAGE, this);
     if (mImageClient) {
       mAsyncContainerID = mImageClient->GetAsyncID();
+      mNotifyCompositeListener = new ImageContainerListener(this);
     }
   }
 }
 
 ImageContainer::ImageContainer(Mode flag)
 : mReentrantMonitor("ImageContainer.mReentrantMonitor"),
   mGenerationCounter(++sGenerationCounter),
   mPaintCount(0),
@@ -141,16 +168,19 @@ ImageContainer::ImageContainer(uint64_t 
   mAsyncContainerID(aAsyncContainerID),
   mCurrentProducerID(-1)
 {
   MOZ_ASSERT(mAsyncContainerID != sInvalidAsyncContainerId);
 }
 
 ImageContainer::~ImageContainer()
 {
+  if (mNotifyCompositeListener) {
+    mNotifyCompositeListener->ClearImageContainer();
+  }
   if (mAsyncContainerID) {
     if (RefPtr<ImageBridgeChild> imageBridge = ImageBridgeChild::GetSingleton()) {
       imageBridge->ForgetImageContainer(mAsyncContainerID);
     }
   }
 }
 
 RefPtr<PlanarYCbCrImage>
--- a/gfx/layers/ImageContainer.h
+++ b/gfx/layers/ImageContainer.h
@@ -140,16 +140,17 @@ typedef void* HANDLE;
 
 namespace mozilla {
 
 
 namespace layers {
 
 class ImageClient;
 class ImageCompositeNotification;
+class ImageContainer;
 class ImageContainerChild;
 class PImageContainerChild;
 class SharedPlanarYCbCrImage;
 class PlanarYCbCrImage;
 class TextureClient;
 class KnowsCompositor;
 class NVImage;
 
@@ -318,16 +319,34 @@ protected:
 
   ImageFactory() {}
   virtual ~ImageFactory() {}
 
   virtual RefPtr<PlanarYCbCrImage> CreatePlanarYCbCrImage(
     const gfx::IntSize& aScaleHint,
     BufferRecycleBin *aRecycleBin);
 };
+
+// Used to notify ImageContainer::NotifyComposite()
+class ImageContainerListener final {
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageContainerListener)
+
+public:
+  explicit ImageContainerListener(ImageContainer* aImageContainer);
+
+  void NotifyComposite(const ImageCompositeNotification& aNotification);
+  void ClearImageContainer();
+private:
+  typedef mozilla::Mutex Mutex;
+
+  ~ImageContainerListener();
+
+  Mutex mLock;
+  ImageContainer* mImageContainer;
+};
  
 /**
  * A class that manages Images for an ImageLayer. The only reason
  * we need a separate class here is that ImageLayers aren't threadsafe
  * (because layers can only be used on the main thread) and we want to
  * be able to set the current Image from any thread, to facilitate
  * video playback without involving the main thread, for example.
  *
@@ -561,16 +580,21 @@ public:
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     return mDroppedImageCount;
   }
 
   void NotifyComposite(const ImageCompositeNotification& aNotification);
 
   PImageContainerChild* GetPImageContainerChild();
 
+  ImageContainerListener* GetImageContainerListener()
+  {
+    return mNotifyCompositeListener;
+  }
+
   /**
    * Main thread only.
    */
   static ProducerID AllocateProducerID();
 
 private:
   typedef mozilla::ReentrantMonitor ReentrantMonitor;
 
@@ -627,16 +651,18 @@ private:
 
   uint64_t mAsyncContainerID;
 
   nsTArray<FrameID> mFrameIDsNotYetComposited;
   // ProducerID for last current image(s), including the frames in
   // mFrameIDsNotYetComposited
   ProducerID mCurrentProducerID;
 
+  RefPtr<ImageContainerListener> mNotifyCompositeListener;
+
   static mozilla::Atomic<uint32_t> sGenerationCounter;
 };
 
 class AutoLockImage
 {
 public:
   explicit AutoLockImage(ImageContainer *aContainer)
   {
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -1100,23 +1100,27 @@ ImageBridgeChild::RecvParentAsyncMessage
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 ImageBridgeChild::RecvDidComposite(InfallibleTArray<ImageCompositeNotification>&& aNotifications)
 {
   for (auto& n : aNotifications) {
-    RefPtr<ImageContainer> imageContainer;
+    RefPtr<ImageContainerListener> listener;
     {
       MutexAutoLock lock(mContainerMapLock);
+      ImageContainer* imageContainer;
       imageContainer = mImageContainers.Get(n.asyncCompositableID());
+      if (imageContainer) {
+        listener = imageContainer->GetImageContainerListener();
+      }
     }
-    if (imageContainer) {
-      imageContainer->NotifyComposite(n);
+    if (listener) {
+      listener->NotifyComposite(n);
     }
   }
   return IPC_OK();
 }
 
 PTextureChild*
 ImageBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData,
                                 LayersBackend aLayersBackend,
--- a/ipc/chromium/src/base/process_util_win.cc
+++ b/ipc/chromium/src/base/process_util_win.cc
@@ -14,19 +14,16 @@
 #include <winternl.h>
 #include <psapi.h>
 
 #include "base/histogram.h"
 #include "base/logging.h"
 #include "base/win_util.h"
 
 #include <algorithm>
-#include "prenv.h"
-
-#include "mozilla/WindowsVersion.h"
 
 namespace {
 
 // System pagesize. This value remains constant on x86/64 architectures.
 const int PAGESIZE_KB = 4;
 
 // HeapSetInformation function pointer.
 typedef BOOL (WINAPI* HeapSetFn)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T);
@@ -275,72 +272,59 @@ void FreeThreadAttributeList(LPPROC_THRE
 }
 
 bool LaunchApp(const std::wstring& cmdline,
                bool wait, bool start_hidden, ProcessHandle* process_handle) {
 
   // We want to inherit the std handles so dump() statements and assertion
   // messages in the child process can be seen - but we *do not* want to
   // blindly have all handles inherited.  Vista and later has a technique
-  // where only specified handles are inherited - so we use this technique if
-  // we can.  If that technique isn't available (or it fails), we just don't
-  // inherit anything.  This can cause us a problem for Windows XP testing,
-  // because we sometimes need the handles to get inherited for test logging to
-  // work. So we also inherit when a specific environment variable is set.
+  // where only specified handles are inherited - so we use this technique.
+  // If that fails we just don't inherit anything.
   DWORD dwCreationFlags = 0;
   BOOL bInheritHandles = FALSE;
+
   // We use a STARTUPINFOEX, but if we can't do the thread attribute thing, we
   // just pass the size of a STARTUPINFO.
   STARTUPINFOEX startup_info_ex;
   ZeroMemory(&startup_info_ex, sizeof(startup_info_ex));
   STARTUPINFO &startup_info = startup_info_ex.StartupInfo;
   startup_info.cb = sizeof(startup_info);
   startup_info.dwFlags = STARTF_USESHOWWINDOW;
   startup_info.wShowWindow = start_hidden ? SW_HIDE : SW_SHOW;
 
   // Per the comment in CreateThreadAttributeList, lpAttributeList will contain
   // a pointer to handlesToInherit, so make sure they have the same lifetime.
   LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList = NULL;
   HANDLE handlesToInherit[2];
   int handleCount = 0;
 
-  // Don't even bother trying pre-Vista...
-  if (mozilla::IsVistaOrLater()) {
-    // setup our handle array first - if we end up with no handles that can
-    // be inherited we can avoid trying to do the ThreadAttributeList dance...
-    HANDLE stdOut = ::GetStdHandle(STD_OUTPUT_HANDLE);
-    HANDLE stdErr = ::GetStdHandle(STD_ERROR_HANDLE);
+  // setup our handle array first - if we end up with no handles that can
+  // be inherited we can avoid trying to do the ThreadAttributeList dance...
+  HANDLE stdOut = ::GetStdHandle(STD_OUTPUT_HANDLE);
+  HANDLE stdErr = ::GetStdHandle(STD_ERROR_HANDLE);
 
-    if (IsInheritableHandle(stdOut))
-      handlesToInherit[handleCount++] = stdOut;
-    if (stdErr != stdOut && IsInheritableHandle(stdErr))
-      handlesToInherit[handleCount++] = stdErr;
+  if (IsInheritableHandle(stdOut))
+    handlesToInherit[handleCount++] = stdOut;
+  if (stdErr != stdOut && IsInheritableHandle(stdErr))
+    handlesToInherit[handleCount++] = stdErr;
 
-    if (handleCount) {
-      lpAttributeList = CreateThreadAttributeList(handlesToInherit, handleCount);
-      if (lpAttributeList) {
-        // it's safe to inherit handles, so arrange for that...
-        startup_info.cb = sizeof(startup_info_ex);
-        startup_info.dwFlags |= STARTF_USESTDHANDLES;
-        startup_info.hStdOutput = stdOut;
-        startup_info.hStdError = stdErr;
-        startup_info.hStdInput = INVALID_HANDLE_VALUE;
-        startup_info_ex.lpAttributeList = lpAttributeList;
-        dwCreationFlags |= EXTENDED_STARTUPINFO_PRESENT;
-        bInheritHandles = TRUE;
-      }
+  if (handleCount) {
+    lpAttributeList = CreateThreadAttributeList(handlesToInherit, handleCount);
+    if (lpAttributeList) {
+      // it's safe to inherit handles, so arrange for that...
+      startup_info.cb = sizeof(startup_info_ex);
+      startup_info.dwFlags |= STARTF_USESTDHANDLES;
+      startup_info.hStdOutput = stdOut;
+      startup_info.hStdError = stdErr;
+      startup_info.hStdInput = INVALID_HANDLE_VALUE;
+      startup_info_ex.lpAttributeList = lpAttributeList;
+      dwCreationFlags |= EXTENDED_STARTUPINFO_PRESENT;
+      bInheritHandles = TRUE;
     }
-  } else if (PR_GetEnv("MOZ_WIN_INHERIT_STD_HANDLES_PRE_VISTA")) {
-    // Even if we can't limit what gets inherited, we sometimes want to inherit
-    // stdout/err for testing purposes.
-    startup_info.dwFlags |= STARTF_USESTDHANDLES;
-    startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
-    startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
-    startup_info.hStdInput = INVALID_HANDLE_VALUE;
-    bInheritHandles = TRUE;
   }
 
   PROCESS_INFORMATION process_info;
   BOOL createdOK = CreateProcess(NULL,
                      const_cast<wchar_t*>(cmdline.c_str()), NULL, NULL,
                      bInheritHandles, dwCreationFlags, NULL, NULL,
                      &startup_info, &process_info);
   if (lpAttributeList)
--- a/ipc/glue/WindowsMessageLoop.cpp
+++ b/ipc/glue/WindowsMessageLoop.cpp
@@ -14,17 +14,16 @@
 #include "nsServiceManagerUtils.h"
 #include "nsString.h"
 #include "nsIXULAppInfo.h"
 #include "WinUtils.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/ipc/ProtocolUtils.h"
 #include "mozilla/PaintTracker.h"
-#include "mozilla/WindowsVersion.h"
 
 using namespace mozilla;
 using namespace mozilla::ipc;
 using namespace mozilla::ipc::windows;
 
 /**
  * The Windows-only code below exists to solve a general problem with deadlocks
  * that we experience when sending synchronous IPC messages to processes that
@@ -1017,17 +1016,17 @@ MessageChannel::WaitForSyncNotifyWithA11
 bool
 MessageChannel::WaitForSyncNotify(bool aHandleWindowsMessages)
 {
   mMonitor->AssertCurrentThreadOwns();
 
   MOZ_ASSERT(gUIThreadId, "InitUIThread was not called!");
 
 #if defined(ACCESSIBILITY)
-  if (IsVistaOrLater() && (mFlags & REQUIRE_A11Y_REENTRY)) {
+  if ((mFlags & REQUIRE_A11Y_REENTRY)) {
     MOZ_ASSERT(!(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION));
     return WaitForSyncNotifyWithA11yReentry();
   }
 #endif
 
   // Use a blocking wait if this channel does not require
   // Windows message deferral behavior.
   if (!(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION) || !aHandleWindowsMessages) {
--- a/ipc/mscom/MainThreadRuntime.cpp
+++ b/ipc/mscom/MainThreadRuntime.cpp
@@ -5,17 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/mscom/MainThreadRuntime.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/UniquePtr.h"
-#include "mozilla/WindowsVersion.h"
 #include "nsDebug.h"
 #include "nsWindowsHelpers.h"
 
 #include <accctrl.h>
 #include <aclapi.h>
 #include <objbase.h>
 #include <objidl.h>
 
@@ -39,45 +38,34 @@ MainThreadRuntime::MainThreadRuntime()
 {
   // We must be the outermost COM initialization on this thread. The COM runtime
   // cannot be configured once we start manipulating objects
   MOZ_ASSERT(mStaRegion.IsValidOutermost());
   if (NS_WARN_IF(!mStaRegion.IsValidOutermost())) {
     return;
   }
 
-  // Windows XP doesn't support setting of the COM exception policy, so we'll
-  // just stop here in that case.
-  if (!IsVistaOrLater()) {
-    mInitResult = S_OK;
-    return;
-  }
-
   // We are required to initialize security in order to configure global options.
   mInitResult = InitializeSecurity();
   MOZ_ASSERT(SUCCEEDED(mInitResult));
   if (FAILED(mInitResult)) {
     return;
   }
 
   RefPtr<IGlobalOptions> globalOpts;
   mInitResult = ::CoCreateInstance(CLSID_GlobalOptions, nullptr,
                                    CLSCTX_INPROC_SERVER, IID_IGlobalOptions,
                                    (void**)getter_AddRefs(globalOpts));
   MOZ_ASSERT(SUCCEEDED(mInitResult));
   if (FAILED(mInitResult)) {
     return;
   }
 
-  // Windows 7 has a policy that is even more strict. We should use that one
-  // whenever possible.
-  ULONG_PTR exceptionSetting = IsWin7OrLater() ?
-                               COMGLB_EXCEPTION_DONOT_HANDLE_ANY :
-                               COMGLB_EXCEPTION_DONOT_HANDLE;
-  mInitResult = globalOpts->Set(COMGLB_EXCEPTION_HANDLING, exceptionSetting);
+  mInitResult = globalOpts->Set(COMGLB_EXCEPTION_HANDLING,
+                                COMGLB_EXCEPTION_DONOT_HANDLE_ANY);
   MOZ_ASSERT(SUCCEEDED(mInitResult));
 }
 
 HRESULT
 MainThreadRuntime::InitializeSecurity()
 {
   HANDLE rawToken = nullptr;
   BOOL ok = ::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &rawToken);
@@ -172,9 +160,8 @@ MainThreadRuntime::InitializeSecurity()
   return ::CoInitializeSecurity(&sd, -1, nullptr, nullptr,
                                 RPC_C_AUTHN_LEVEL_DEFAULT,
                                 RPC_C_IMP_LEVEL_IDENTIFY, nullptr, EOAC_NONE,
                                 nullptr);
 }
 
 } // namespace mscom
 } // namespace mozilla
-
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -1136,19 +1136,21 @@ IonBuilder::initEnvironmentChain(MDefini
             MCallee* calleeIns = MCallee::New(alloc());
             current->add(calleeIns);
             callee = calleeIns;
         }
         env = MFunctionEnvironment::New(alloc(), callee);
         current->add(env);
 
         // This reproduce what is done in CallObject::createForFunction. Skip
-        // this for analyses, as the script might not have a baseline script
-        // with template objects yet.
-        if (fun->needsSomeEnvironmentObject() && !info().isAnalysis()) {
+        // this for the arguments analysis, as the script might not have a
+        // baseline script with template objects yet.
+        if (fun->needsSomeEnvironmentObject() &&
+            info().analysisMode() != Analysis_ArgumentsUsage)
+        {
             if (fun->needsNamedLambdaEnvironment())
                 env = createNamedLambdaObject(callee, env);
 
             // TODO: Parameter expression-induced extra var environment not
             // yet handled.
             if (fun->needsExtraBodyVarEnvironment())
                 return abort(AbortReason::Disable, "Extra var environment unsupported");
 
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -82,20 +82,16 @@ js::SetFakeCPUCount(size_t count)
     HelperThreadState().threadCount = ThreadCountForCPUCount(count);
 }
 
 bool
 js::StartOffThreadWasmCompile(wasm::CompileTask* task)
 {
     AutoLockHelperThreadState lock;
 
-    // Don't append this task if another failed.
-    if (HelperThreadState().wasmFailed(lock))
-        return false;
-
     if (!HelperThreadState().wasmWorklist(lock).append(task))
         return false;
 
     HelperThreadState().notifyOne(GlobalHelperThreadState::PRODUCER, lock);
     return true;
 }
 
 bool
--- a/js/src/vm/HelperThreads.h
+++ b/js/src/vm/HelperThreads.h
@@ -224,17 +224,17 @@ class GlobalHelperThreadState
         return Move(firstWasmError);
     }
     void noteWasmFailure(const AutoLockHelperThreadState&) {
         // Be mindful to signal the main thread after calling this function.
         numWasmFailedJobs++;
     }
     void setWasmError(const AutoLockHelperThreadState&, UniqueChars error) {
         if (!firstWasmError)
-          firstWasmError = Move(error);
+            firstWasmError = Move(error);
     }
     bool wasmFailed(const AutoLockHelperThreadState&) {
         return bool(numWasmFailedJobs);
     }
 
     JSScript* finishParseTask(JSContext* cx, ParseTaskKind kind, void* token);
     void cancelParseTask(JSContext* cx, ParseTaskKind kind, void* token);
 
--- a/js/src/wasm/WasmGenerator.cpp
+++ b/js/src/wasm/WasmGenerator.cpp
@@ -242,18 +242,18 @@ ModuleGenerator::finishOutstandingTask()
     CompileTask* task = nullptr;
     {
         AutoLockHelperThreadState lock;
         while (true) {
             MOZ_ASSERT(outstanding_ > 0);
 
             if (HelperThreadState().wasmFailed(lock)) {
                 if (error_) {
-                  MOZ_ASSERT(!*error_, "Should have stopped earlier");
-                  *error_ = Move(HelperThreadState().harvestWasmError(lock));
+                    MOZ_ASSERT(!*error_, "Should have stopped earlier");
+                    *error_ = Move(HelperThreadState().harvestWasmError(lock));
                 }
                 return false;
             }
 
             if (!HelperThreadState().wasmFinishedList(lock).empty()) {
                 outstanding_--;
                 task = HelperThreadState().wasmFinishedList(lock).popCopy();
                 break;
--- a/js/src/wasm/WasmIonCompile.cpp
+++ b/js/src/wasm/WasmIonCompile.cpp
@@ -3662,17 +3662,17 @@ wasm::IonCompileFunction(CompileTask* ta
     const FuncBytes& func = unit->func();
     const ModuleEnvironment& env = task->env();
     uint32_t bodySize = func.bytes().length();
 
     Decoder d(func.bytes(), error);
 
     if (!env.isAsmJS()) {
         if (!ValidateFunctionBody(task->env(), func.index(), bodySize, d))
-          return false;
+            return false;
 
         d.rollbackPosition(d.begin());
     }
 
     // Build the local types vector.
 
     ValTypeVector locals;
     if (!locals.appendAll(func.sig().args()))
--- a/js/xpconnect/tests/chrome/test_weakmaps.xul
+++ b/js/xpconnect/tests/chrome/test_weakmaps.xul
@@ -209,38 +209,18 @@ https://bugzilla.mozilla.org/show_bug.cg
   let make_live_map = function () {
     let live = get_live_dom();
     wn_live_map.set(live, {});
     ok(wn_live_map.has(get_live_dom()), "Live map should have live DOM node before GC.");
   }
 
   make_live_map();
 
-  let unpreservable_native_key = function () {
-    // We only allow natives that support wrapper preservation to be used as weak
-    // map keys.  We should be able to try to add unpreservable natives as keys without
-    // crashing (bug 711616), but we should throw an error (bug 761620).
-
-    let dummy_test_map = new WeakMap;
-
-    let rule_fail = false;
-    let got_rule = false;
-    try {
-      var rule = document.styleSheets[0].cssRules[0];
-      got_rule = true;
-      dummy_test_map.set(rule, 1);
-    } catch (e) {
-      rule_fail = true;
-    }
-    ok(got_rule, "Got the CSS rule");
-    ok(rule_fail, "Using a CSS rule as a weak map key should produce an exception because it can't be wrapper preserved.");
-
-  }
-
-  unpreservable_native_key();
+  // We're out of ideas for unpreservable natives, now that just about
+  // everything is on webidl, so just don't test those.
 
   /* set up for running precise GC/CC then checking the results */
 
   SimpleTest.waitForExplicitFinish();
 
   Cu.schedulePreciseGC(function () {
     SpecialPowers.DOMWindowUtils.cycleCollect();
     SpecialPowers.DOMWindowUtils.garbageCollect();
--- a/js/xpconnect/tests/mochitest/file_crosscompartment_weakmap.html
+++ b/js/xpconnect/tests/mochitest/file_crosscompartment_weakmap.html
@@ -1,9 +1,8 @@
 <!DOCTYPE HTML>
 <html>
 <head>
-  <link rel="stylesheet" href="data:text/css,div {}">
   <title>Test Cross-Compartment DOM WeakMaps</title>
 </head>
 <body>
 </body>
 </html>
--- a/js/xpconnect/tests/mochitest/test_crosscompartment_weakmap.html
+++ b/js/xpconnect/tests/mochitest/test_crosscompartment_weakmap.html
@@ -10,24 +10,16 @@
 <script type="application/javascript">
 
 var my_map = new WeakMap();
 
 function setup() {
   var item = window.frames[0].document.querySelector("body");
 
   my_map.set(item, "success_string");
-
-  var rule_fail = false;
-  try {
-    my_map.set(window.frames[0].document.styleSheets[0].cssRules[0], 1);
-  } catch (e) {
-    rule_fail = true;
-  }
-  ok(rule_fail, "Using rule as a weak map key across compartments should produce an exception because it can't be wrapper preserved.");
 }
 
 function runTest() {
   setup();
   SpecialPowers.forceGC();
   SpecialPowers.forceCC();
   SpecialPowers.forceGC();
   SpecialPowers.forceCC();
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -3673,16 +3673,17 @@ nsGridContainerFrame::Tracks::Initialize
 /**
  * Reflow aChild in the given aAvailableSize.
  */
 static nscoord
 MeasuringReflow(nsIFrame*           aChild,
                 const ReflowInput*  aReflowInput,
                 nsRenderingContext* aRC,
                 const LogicalSize&  aAvailableSize,
+                const LogicalSize&  aCBSize,
                 nscoord             aIMinSizeClamp = NS_MAXSIZE,
                 nscoord             aBMinSizeClamp = NS_MAXSIZE)
 {
   nsContainerFrame* parent = aChild->GetParent();
   nsPresContext* pc = aChild->PresContext();
   Maybe<ReflowInput> dummyParentState;
   const ReflowInput* rs = aReflowInput;
   if (!aReflowInput) {
@@ -3705,17 +3706,17 @@ MeasuringReflow(nsIFrame*           aChi
   }
   if (aBMinSizeClamp != NS_MAXSIZE) {
     riFlags |= ReflowInput::B_CLAMP_MARGIN_BOX_MIN_SIZE;
     aChild->Properties().Set(nsIFrame::BClampMarginBoxMinSizeProperty(),
                              aBMinSizeClamp);
   } else {
     aChild->Properties().Delete(nsIFrame::BClampMarginBoxMinSizeProperty());
   }
-  ReflowInput childRI(pc, *rs, aChild, aAvailableSize, nullptr, riFlags);
+  ReflowInput childRI(pc, *rs, aChild, aAvailableSize, &aCBSize, riFlags);
   ReflowOutput childSize(childRI);
   nsReflowStatus childStatus;
   const uint32_t flags = NS_FRAME_NO_MOVE_FRAME | NS_FRAME_NO_SIZE_VIEW;
   WritingMode wm = childRI.GetWritingMode();
   parent->ReflowChild(aChild, pc, childSize, childRI, wm,
                       LogicalPoint(wm), nsSize(), flags, childStatus);
   parent->FinishReflowChild(aChild, pc, childSize, &childRI, wm,
                             LogicalPoint(wm), nsSize(), flags);
@@ -3743,52 +3744,54 @@ ContentContribution(const GridItemInfo& 
   PhysicalAxis axis(aCBWM.PhysicalAxis(aAxis));
   nscoord size = nsLayoutUtils::IntrinsicForAxis(axis, aRC, child, aConstraint,
                    aFlags | nsLayoutUtils::BAIL_IF_REFLOW_NEEDED |
                             nsLayoutUtils::ADD_PERCENTS,
                    aMinSizeClamp);
   if (size == NS_INTRINSIC_WIDTH_UNKNOWN) {
     // We need to reflow the child to find its BSize contribution.
     // XXX this will give mostly correct results for now (until bug 1174569).
-    nscoord cbISize = INFINITE_ISIZE_COORD;
-    nscoord cbBSize = NS_UNCONSTRAINEDSIZE;
+    nscoord availISize = INFINITE_ISIZE_COORD;
+    nscoord availBSize = NS_UNCONSTRAINEDSIZE;
     auto childWM = child->GetWritingMode();
     const bool isOrthogonal = childWM.IsOrthogonalTo(aCBWM);
     // The next two variables are MinSizeClamp values in the child's axes.
     nscoord iMinSizeClamp = NS_MAXSIZE;
     nscoord bMinSizeClamp = NS_MAXSIZE;
+    LogicalSize cbSize(childWM, 0, 0);
     if (aState.mCols.mCanResolveLineRangeSize) {
       nscoord sz = aState.mCols.ResolveSize(aGridItem.mArea.mCols);
       if (isOrthogonal) {
-        cbBSize = sz;
+        availBSize = sz;
+        cbSize.BSize(childWM) = sz;
         if (aGridItem.mState[aAxis] & ItemState::eClampMarginBoxMinSize) {
           bMinSizeClamp = sz;
         }
       } else {
-        cbISize = sz;
+        availISize = sz;
+        cbSize.ISize(childWM) = sz;
         if (aGridItem.mState[aAxis] & ItemState::eClampMarginBoxMinSize) {
           iMinSizeClamp = sz;
         }
       }
     }
     if (isOrthogonal == (aAxis == eLogicalAxisInline)) {
       bMinSizeClamp = aMinSizeClamp;
     } else {
       iMinSizeClamp = aMinSizeClamp;
     }
-    LogicalSize availableSize(childWM, cbISize, cbBSize);
+    LogicalSize availableSize(childWM, availISize, availBSize);
     size = ::MeasuringReflow(child, aState.mReflowInput, aRC, availableSize,
-                             iMinSizeClamp, bMinSizeClamp);
+                             cbSize, iMinSizeClamp, bMinSizeClamp);
     nsIFrame::IntrinsicISizeOffsetData offsets = child->IntrinsicBSizeOffsets();
     size += offsets.hMargin;
     auto percent = offsets.hPctMargin;
-    if (!aState.mReflowInput) {
-      // We always want to add in percent padding too, but during Reflow we
-      // always have a definite percentage basis (the grid area) so any percent
-      // padding is already resolved and baked in to 'size' at this point.
+    if (availBSize == NS_UNCONSTRAINEDSIZE) {
+      // We always want to add in percent padding too, unless we already did so
+      // using a resolved column size above.
       percent += offsets.hPctPadding;
     }
     size = nsLayoutUtils::AddPercents(size, percent);
     nscoord overflow = size - aMinSizeClamp;
     if (MOZ_UNLIKELY(overflow > 0)) {
       nscoord contentSize = child->ContentBSize(childWM);
       nscoord newContentSize = std::max(nscoord(0), contentSize - overflow);
       // XXXmats deal with percentages better, see bug 1300369 comment 27.
@@ -4194,17 +4197,25 @@ nsGridContainerFrame::Tracks::Initialize
     }
 
     if (state & ItemState::eIsBaselineAligned) {
       // XXX available size issue
       LogicalSize avail(childWM, INFINITE_ISIZE_COORD, NS_UNCONSTRAINEDSIZE);
       auto* rc = &aState.mRenderingContext;
       // XXX figure out if we can avoid/merge this reflow with the main reflow.
       // XXX (after bug 1174569 is sorted out)
-      ::MeasuringReflow(child, aState.mReflowInput, rc, avail);
+      //
+      // XXX How should we handle percentage padding here? (bug 1330866)
+      // XXX (see ::ContentContribution and how it deals with percentages)
+      // XXX What if the true baseline after line-breaking differs from this
+      // XXX hypothetical baseline based on an infinite inline size?
+      // XXX Maybe we should just call ::ContentContribution here instead?
+      // XXX For now we just pass a zero-sized CB:
+      LogicalSize cbSize(childWM, 0, 0);
+      ::MeasuringReflow(child, aState.mReflowInput, rc, avail, cbSize);
       nscoord baseline;
       nsGridContainerFrame* grid = do_QueryFrame(child);
       if (state & ItemState::eFirstBaseline) {
         if (grid) {
           if (isOrthogonal == isInlineAxis) {
             grid->GetBBaseline(BaselineSharingGroup::eFirst, &baseline);
           } else {
             grid->GetIBaseline(BaselineSharingGroup::eFirst, &baseline);
--- a/layout/inspector/inCSSValueSearch.cpp
+++ b/layout/inspector/inCSSValueSearch.cpp
@@ -13,16 +13,17 @@
 #include "nsIDOMStyleSheetList.h"
 #include "nsIDOMCSSStyleSheet.h"
 #include "nsIDOMCSSRuleList.h"
 #include "nsIDOMCSSStyleRule.h"
 #include "nsIDOMCSSStyleDeclaration.h"
 #include "nsIDOMCSSImportRule.h"
 #include "nsIDOMCSSMediaRule.h"
 #include "nsIDOMCSSSupportsRule.h"
+#include "nsIDOMCSSRule.h"
 #include "nsIURI.h"
 #include "nsIDocument.h"
 #include "nsNetUtil.h"
 
 using namespace mozilla;
 
 ///////////////////////////////////////////////////////////////////////////////
 inCSSValueSearch::inCSSValueSearch()
--- a/layout/inspector/inDOMUtils.cpp
+++ b/layout/inspector/inDOMUtils.cpp
@@ -248,23 +248,19 @@ inDOMUtils::GetCSSStyleRules(nsIDOMEleme
     ruleNodes.AppendElement(ruleNode);
     ruleNode = ruleNode->GetParent();
   }
 
   nsCOMPtr<nsIMutableArray> rules = nsArray::Create();
   for (nsRuleNode* ruleNode : Reversed(ruleNodes)) {
     RefPtr<Declaration> decl = do_QueryObject(ruleNode->GetRule());
     if (decl) {
-      RefPtr<mozilla::css::StyleRule> styleRule =
-        do_QueryObject(decl->GetOwningRule());
-      if (styleRule) {
-        nsCOMPtr<nsIDOMCSSRule> domRule = styleRule->GetDOMRule();
-        if (domRule) {
-          rules->AppendElement(domRule, /*weak =*/ false);
-        }
+      css::Rule* owningRule = decl->GetOwningRule();
+      if (owningRule) {
+        rules->AppendElement(owningRule, /*weak =*/ false);
       }
     }
   }
 
   rules.forget(_retval);
 
   return NS_OK;
 }
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-grid/grid-item-sizing-percent-002-ref.html
@@ -0,0 +1,136 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <title>Reference: Testing grid item percent sizes</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1330380">
+  <meta charset="utf-8">
+  <style type="text/css">
+body,html { color:black; background:white; font:16px/1 monospace; padding:0; margin:0; }
+* { vertical-align:top; line-height:4px; }
+
+.grid {
+  display: grid;
+  position: relative;
+  float: left;
+  background-color: grey;
+  grid-template-columns: 50px 100px;
+  justify-items: start;
+  align-items: start;
+  clear: both;
+}
+
+.item {
+  background: pink;
+  grid-area: 1 / 1 / 2 / 2;
+  background-clip: content-box;
+  min-width: 0;
+  min-height: 0;
+  z-index: 1;
+}
+.c1 {
+  width: 60px;
+  height: 60%;
+  grid-area: 1 / 1 / 3 / 3;
+}
+.c2 {
+  grid-area: 1 / 1 / 3 / 3;
+}
+.pbox {
+  box-sizing: border-box;
+}
+
+.maxw .item { max-width: 25px; }
+.minw .item { min-width: 25px; }
+.maxw .c1.item { max-width: 75px; }
+.minw .c1.item { min-width: 75px; }
+.maxw .c2.item { max-width: 75px; }
+.minw .c2.item { min-width: 75px; }
+
+.p { padding:3px 5px 10% 10px; }
+.c1.p, .c2.p { padding:3px 5px 10% 30px; }
+.m { margin:3px 5px 10% 5px; }
+.c1.m, .c2.m { margin:3px 5px 10% 15px; }
+.b { border:solid black; }
+
+x { display:inline-block; width:10px; height:4px; background: silver; }
+
+a {
+  grid-area: 1 / 1 / 2 / 2;
+  width:100%; height:100%;
+  background: blue;
+}
+</style>
+</head>
+<body>
+
+<div style="float:left">
+<div class="grid" style="grid-template-rows:calc(4px)"><div class="item"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(7px/.9)"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(7px/.9)"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(11px/.9)"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(7px/.9)"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(10px)"><div class="item pbox b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(17px/.9)"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(21px/.9)"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(13px/.9)"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<div style="float:left" class="maxw">
+<div class="grid" style="grid-template-rows:calc(8px)"><div class="item"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(15px/.9)"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(7px/.9)"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(11px/.9)"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(7px/.9)"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(18px)"><div class="item pbox b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(21px/.9)"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(21px/.9)"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(13px/.9)"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<div style="float:left" class="minw">
+<div class="grid" style="grid-template-rows:calc(4px)"><div class="item"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(7px/.9)"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(7px/.9)"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(7px/.9)"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(7px/.9)"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(10px)"><div class="item pbox b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(17px/.9)"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(13px/.9)"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(13px/.9)"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<div style="float:left">
+<div class="grid" style="grid-template-rows:calc(7px/.9)"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(7px/.9)"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(7px/.9)"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(17.5px)"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(30px)"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(20px)"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<br clear="all">
+
+<div style="float:left" class="maxw">
+<div class="grid" style="grid-template-rows:calc(11px/.9)"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(7px/.9)"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(7px/.9)"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(22.5px)"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(30px)"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(20px)"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<div style="float:left" class="minw">
+<div class="grid" style="grid-template-rows:calc(7px/.9)"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(7px/.9)"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(7px/.9)"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(17.5px)"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(30px)"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(20px)"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-grid/grid-item-sizing-percent-002.html
@@ -0,0 +1,138 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <title>CSS Test: Testing grid item percent sizes</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1330380">
+  <link rel="help" href="http://dev.w3.org/csswg/css-grid/">
+  <link rel="match" href="grid-item-sizing-percent-002-ref.html">
+  <meta charset="utf-8">
+  <style type="text/css">
+body,html { color:black; background:white; font:16px/1 monospace; padding:0; margin:0; }
+* { vertical-align:top; line-height:4px; }
+
+.grid {
+  display: grid;
+  position: relative;
+  float: left;
+  background-color: grey;
+  grid-template-columns: 50px 100px;
+  justify-items: start;
+  align-items: start;
+  clear: both;
+}
+
+.item {
+  background: pink;
+  grid-area: 1 / 1 / 2 / 2;
+  background-clip: content-box;
+  min-width: 0;
+  min-height: 0;
+  z-index: 1;
+}
+.c1 {
+  width: 40%;
+  height: 60%;
+  grid-area: 1 / 1 / 3 / 3;
+}
+.c2 {
+  grid-area: 1 / 1 / 3 / 3;
+}
+.pbox {
+  box-sizing: border-box;
+}
+
+.maxw .item { max-width: 50%; }
+.minw .item { min-width: 50%; }
+
+.p { padding:3px 5px 10% 20%; }
+.m { margin:3px 5px 10% 10%; }
+.b { border:solid black; }
+
+x { display:inline-block; width:10px; height:4px; background: silver; }
+
+a {
+  grid-area: 1 / 1 / 2 / 2;
+  width:100%; height:100%;
+  background: blue;
+}
+</style>
+</head>
+<body>
+
+<div style="float:left">
+<div class="grid"><div class="item"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<div style="float:left" class="maxw">
+<div class="grid"><div class="item"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<div style="float:left" class="minw">
+<div class="grid"><div class="item"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<div style="float:left">
+<div class="grid"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<br clear="all">
+
+<div style="float:left" class="maxw">
+<div class="grid"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<div style="float:left" class="minw">
+<div class="grid"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<script>
+var grids = [].slice.call(document.querySelectorAll('.grid'));
+grids.forEach((grid) => {
+  console.log(window.getComputedStyle(grid).gridTemplateRows);
+});
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-grid/grid-item-sizing-percent-003-ref.html
@@ -0,0 +1,137 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <title>Reference: Testing grid item percent sizes</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1330380">
+  <meta charset="utf-8">
+  <style type="text/css">
+body,html { color:black; background:white; font:16px/1 monospace; padding:0; margin:0; }
+* { vertical-align:top; line-height:4px; }
+
+.grid {
+  display: grid;
+  position: relative;
+  float: left;
+  background-color: grey;
+  grid-template-columns: 50px 100px;
+  justify-items: start;
+  align-items: start;
+  clear: both;
+}
+
+.item {
+  background: pink;
+  grid-area: 1 / 1 / 2 / 2;
+  background-clip: content-box;
+  min-width: 0;
+  min-height: 0;
+  z-index: 1;
+  writing-mode: vertical-rl;
+}
+.c1 {
+  width: 40%;
+  height: 60%;
+  grid-area: 1 / 1 / 3 / 3;
+}
+.c2 {
+  grid-area: 1 / 1 / 3 / 3;
+}
+.pbox {
+  box-sizing: border-box;
+}
+
+.maxw .item { max-width: 25px; }
+.minw .item { min-width: 25px; }
+.maxw .c1.item { max-width: 75px; }
+.minw .c1.item { min-width: 75px; }
+.maxw .c2.item { max-width: 75px; }
+.minw .c2.item { min-width: 75px; }
+
+.p { padding:3px 5px 10% 10px; }
+.c1.p, .c2.p { padding:3px 5px 10% 30px; }
+.m { margin:3px 5px 10% 5px; }
+.c1.m, .c2.m { margin:3px 5px 10% 15px; }
+.b { border:solid black; }
+
+x { display:inline-block; width:10px; height:4px; background: silver; }
+
+a {
+  grid-area: 1 / 1 / 2 / 2;
+  width:100%; height:100%;
+  background: blue;
+}
+</style>
+</head>
+<body>
+
+<div style="float:left">
+<div class="grid" style="grid-template-rows:calc(12px)"><div class="item"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(15px/.9)"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(18px)"><div class="item pbox b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(21px/0.9)"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(21px/.9)"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(21px/.9)"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<div style="float:left" class="maxw">
+<div class="grid" style="grid-template-rows:calc(12px)"><div class="item"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(15px/.9)"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(18px)"><div class="item pbox b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(21px/.9)"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(21px/.9)"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(21px/.9)"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<div style="float:left" class="minw">
+<div class="grid" style="grid-template-rows:calc(12px)"><div class="item"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(15px/.9)"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(18px)"><div class="item pbox b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(21px/.9)"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(21px/.9)"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(21px/.9)"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<div style="float:left">
+<div class="grid" style="grid-template-rows:calc(15px/.9)"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(22.5px)"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(30px)"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(30px)"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<br clear="all">
+
+<div style="float:left" class="maxw">
+<div class="grid" style="grid-template-rows:calc(15px/.9)"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(22.5px)"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(30px)"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(30px)"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<div style="float:left" class="minw">
+<div class="grid" style="grid-template-rows:calc(15px/.9)"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(15px/.9)"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(22.5px)"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:calc(30px)"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-rows:0 calc(30px)"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-grid/grid-item-sizing-percent-003.html
@@ -0,0 +1,139 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <title>CSS Test: Testing grid item percent sizes</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1330380">
+  <link rel="help" href="http://dev.w3.org/csswg/css-grid/">
+  <link rel="match" href="grid-item-sizing-percent-003-ref.html">
+  <meta charset="utf-8">
+  <style type="text/css">
+body,html { color:black; background:white; font:16px/1 monospace; padding:0; margin:0; }
+* { vertical-align:top; line-height:4px; }
+
+.grid {
+  display: grid;
+  position: relative;
+  float: left;
+  background-color: grey;
+  grid-template-columns: 50px 100px;
+  justify-items: start;
+  align-items: start;
+  clear: both;
+}
+
+.item {
+  background: pink;
+  grid-area: 1 / 1 / 2 / 2;
+  background-clip: content-box;
+  min-width: 0;
+  min-height: 0;
+  z-index: 1;
+  writing-mode: vertical-rl;
+}
+.c1 {
+  width: 40%;
+  height: 60%;
+  grid-area: 1 / 1 / 3 / 3;
+}
+.c2 {
+  grid-area: 1 / 1 / 3 / 3;
+}
+.pbox {
+  box-sizing: border-box;
+}
+
+.maxw .item { max-width: 50%; }
+.minw .item { min-width: 50%; }
+
+.p { padding:3px 5px 10% 20%; }
+.m { margin:3px 5px 10% 10%; }
+.b { border:solid black; }
+
+x { display:inline-block; width:10px; height:4px; background: silver; }
+
+a {
+  grid-area: 1 / 1 / 2 / 2;
+  width:100%; height:100%;
+  background: blue;
+}
+</style>
+</head>
+<body>
+
+<div style="float:left">
+<div class="grid"><div class="item"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<div style="float:left" class="maxw">
+<div class="grid"><div class="item"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<div style="float:left" class="minw">
+<div class="grid"><div class="item"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<div style="float:left">
+<div class="grid"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<br clear="all">
+
+<div style="float:left" class="maxw">
+<div class="grid"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<div style="float:left" class="minw">
+<div class="grid"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<script>
+var grids = [].slice.call(document.querySelectorAll('.grid'));
+grids.forEach((grid) => {
+  console.log(window.getComputedStyle(grid).gridTemplateRows);
+});
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-grid/grid-item-sizing-percent-004-ref.html
@@ -0,0 +1,134 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <title>Reference: Testing grid item percent sizes</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1330380">
+  <meta charset="utf-8">
+  <style type="text/css">
+body,html { color:black; background:white; font:16px/1 monospace; padding:0; margin:0; }
+* { vertical-align:top; line-height:4px; }
+
+.grid {
+  display: inline-grid;
+  position: relative;
+  background-color: grey;
+  grid-template-rows: 50px 100px;
+  justify-items: start;
+  align-items: start;
+  clear: both;
+}
+
+.item {
+  background: pink;
+  grid-area: 1 / 1 / 2 / 2;
+  background-clip: content-box;
+  min-width: 0;
+  min-height: 0;
+  z-index: 1;
+  writing-mode: vertical-rl;
+}
+.c1 {
+  width: 40%;
+  height: 90px;
+  grid-area: 1 / 1 / 3 / 3;
+}
+.c2 {
+  grid-area: 1 / 1 / 3 / 3;
+}
+.pbox {
+  box-sizing: border-box;
+}
+
+.maxw .item { max-height: 50%; }
+.minw .item { min-height: 50%; }
+
+.p { padding:3px 5px 10% 20%; }
+.m { margin:3px 5px 10% 10%; }
+.b { border:solid black; }
+
+x { display:inline-block; width:10px; height:4px; background: silver; }
+
+a {
+  grid-area: 1 / 1 / 2 / 2;
+  width:100%; height:100%;
+  background: blue;
+}
+</style>
+</head>
+<body>
+
+<div style="float:left">
+<div class="grid" style="grid-template-columns:calc(10px)"><div class="item"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:calc(18.75px)"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:0 calc(43.75px)"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:0 calc(43.75px)"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:0 calc(18.75px)"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:calc(16px)"><div class="item pbox b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:calc(26.25px)"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:0 calc(51.25px)"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:0 calc(26.25px)"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<br clear="all">
+
+<div style="float:left" class="maxw">
+<div class="grid" style="grid-template-columns:calc(30px)"><div class="item"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:calc(43.75px)"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:0 calc(43.75px)"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:0 calc(43.75px)"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:0 calc(43.75px)"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:calc(36px)"><div class="item pbox b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:calc(51.25px)"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:0 calc(51.25px)"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:0 calc(51.25px)"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<br clear="all">
+
+<div style="float:left" class="minw">
+<div class="grid" style="grid-template-columns:calc(10px)"><div class="item"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:calc(18.75px)"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:0 calc(43.75px)"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:0 calc(43.75px)"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:0 calc(18.75px)"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:calc(16px)"><div class="item pbox b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:calc(26.25px)"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:0 calc(51.25px)"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:0 calc(26.25px)"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<div style="float:left">
+<div class="grid" style="grid-template-columns:calc(15px/.9)"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:0 calc(35px/.9)"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:0 calc(15px/.9)"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:calc(20px/.7)"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:calc(37.15px)"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:0 calc(37.15px)"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<br clear="all">
+
+<div style="float:left" class="maxw">
+<div class="grid" style="grid-template-columns:calc(35px/.9)"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:0 calc(35px/.9)"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:0 calc(35px/.9)"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:calc(57.15px)"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:calc(46px/.7)"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:0 calc(46px/.7)"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<div style="float:left" class="minw">
+<div class="grid" style="grid-template-columns:calc(15px/.9)"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:0 calc(35px/.9)"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:0 calc(15px/.9)"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:calc(20px/.7)"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:calc(37.15px)"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid" style="grid-template-columns:0 calc(37.15px)"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-grid/grid-item-sizing-percent-004.html
@@ -0,0 +1,142 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <title>CSS Test: Testing grid item percent sizes</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1330380">
+  <link rel="help" href="http://dev.w3.org/csswg/css-grid/">
+  <link rel="match" href="grid-item-sizing-percent-004-ref.html">
+  <meta charset="utf-8">
+  <style type="text/css">
+body,html { color:black; background:white; font:16px/1 monospace; padding:0; margin:0; }
+* { vertical-align:top; line-height:4px; }
+
+.grid {
+  display: inline-grid;
+  position: relative;
+  background-color: grey;
+  grid-template-rows: 50px 100px;
+  justify-items: start;
+  align-items: start;
+  clear: both;
+}
+
+.item {
+  background: pink;
+  grid-area: 1 / 1 / 2 / 2;
+  background-clip: content-box;
+  min-width: 0;
+  min-height: 0;
+  z-index: 1;
+  writing-mode: vertical-rl;
+}
+.c1 {
+  width: 40%;
+  height: 60%;
+  grid-area: 1 / 1 / 3 / 3;
+}
+.c2 {
+  grid-area: 1 / 1 / 3 / 3;
+}
+.pbox {
+  box-sizing: border-box;
+}
+
+.maxw .item { max-height: 50%; }
+.minw .item { min-height: 50%; }
+
+.p { padding:3px 5px 10% 20%; }
+.m { margin:3px 5px 10% 10%; }
+.b { border:solid black; }
+
+x { display:inline-block; width:10px; height:4px; background: silver; }
+
+a {
+  grid-area: 1 / 1 / 2 / 2;
+  width:100%; height:100%;
+  background: blue;
+}
+</style>
+</head>
+<body>
+
+<div style="float:left">
+<div class="grid"><div class="item"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<br clear="all">
+
+<div style="float:left" class="maxw">
+<div class="grid"><div class="item"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<br clear="all">
+
+<div style="float:left" class="minw">
+<div class="grid"><div class="item"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox p"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox p b"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<div style="float:left">
+<div class="grid"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<br clear="all">
+
+<div style="float:left" class="maxw">
+<div class="grid"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<div style="float:left" class="minw">
+<div class="grid"><div class="item pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c1 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+<div class="grid"><div class="item c2 pbox p b m"><x></x><x></x><x></x></div><a></a></div>
+</div>
+
+<script>
+var grids = [].slice.call(document.querySelectorAll('.grid'));
+grids.forEach((grid) => {
+  console.log(window.getComputedStyle(grid).gridTemplateColumns);
+});
+</script>
+
+</body>
+</html>
--- a/layout/reftests/css-grid/reftest.list
+++ b/layout/reftests/css-grid/reftest.list
@@ -40,16 +40,19 @@ skip-if(Android) == grid-placement-defin
 skip-if(Android) fuzzy-if(winWidget,1,32) == grid-placement-auto-implicit-001.html grid-placement-auto-implicit-001-ref.html
 == grid-placement-abspos-implicit-001.html grid-placement-abspos-implicit-001-ref.html
 == rtl-grid-placement-definite-001.html rtl-grid-placement-definite-001-ref.html
 == rtl-grid-placement-auto-row-sparse-001.html rtl-grid-placement-auto-row-sparse-001-ref.html
 == vlr-grid-placement-auto-row-sparse-001.html vlr-grid-placement-auto-row-sparse-001-ref.html
 == vrl-grid-placement-auto-row-sparse-001.html vrl-grid-placement-auto-row-sparse-001-ref.html
 == grid-relpos-items-001.html grid-relpos-items-001-ref.html
 == grid-item-sizing-percent-001.html grid-item-sizing-percent-001-ref.html
+== grid-item-sizing-percent-002.html grid-item-sizing-percent-002-ref.html
+== grid-item-sizing-percent-003.html grid-item-sizing-percent-003-ref.html
+== grid-item-sizing-percent-004.html grid-item-sizing-percent-004-ref.html
 == grid-item-sizing-px-001.html grid-item-sizing-percent-001-ref.html
 == grid-item-dir-001.html grid-item-dir-001-ref.html
 fuzzy-if(winWidget,70,130) fuzzy-if(cocoaWidget,85,180) == grid-col-max-sizing-max-content-001.html grid-col-max-sizing-max-content-001-ref.html
 fuzzy-if(winWidget,70,130) fuzzy-if(cocoaWidget,85,180) == grid-col-max-sizing-max-content-002.html grid-col-max-sizing-max-content-002-ref.html
 == grid-min-max-content-sizing-001.html grid-min-max-content-sizing-001-ref.html
 == grid-min-max-content-sizing-002.html grid-min-max-content-sizing-002-ref.html
 fuzzy-if(winWidget,1,36) == grid-auto-min-sizing-definite-001.html grid-auto-min-sizing-definite-001-ref.html
 == grid-auto-min-sizing-intrinsic-001.html grid-auto-min-sizing-intrinsic-001-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/style/BindingStyleRule.cpp
@@ -0,0 +1,18 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/BindingStyleRule.h"
+#include "mozilla/dom/CSSStyleRuleBinding.h"
+
+namespace mozilla {
+
+/* virtual */ JSObject*
+BindingStyleRule::WrapObject(JSContext* aCx,
+			     JS::Handle<JSObject*> aGivenProto)
+{
+  return dom::CSSStyleRuleBinding::Wrap(aCx, this, aGivenProto);
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/layout/style/BindingStyleRule.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_BindingStyleRule_h__
+#define mozilla_BindingStyleRule_h__
+
+#include "nscore.h"
+#include "nsStringGlue.h"
+#include "mozilla/css/Rule.h"
+
+/**
+ * Shared superclass for mozilla::css::StyleRule and mozilla::ServoStyleRule,
+ * for use from bindings code.
+ */
+
+class nsICSSDeclaration;
+
+namespace mozilla {
+
+class BindingStyleRule : public css::Rule
+{
+protected:
+  BindingStyleRule(uint32_t aLineNumber, uint32_t aColumnNumber)
+    : css::Rule(aLineNumber, aColumnNumber)
+  {
+  }
+  BindingStyleRule(const BindingStyleRule& aCopy)
+    : css::Rule(aCopy)
+  {
+  }
+  virtual ~BindingStyleRule() {}
+
+public:
+  // This is pure virtual because we have no members, and are an abstract class
+  // to start with.  The fact that we have to have this declaration at all is
+  // kinda dumb.  :(
+  virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
+    const override MOZ_MUST_OVERRIDE = 0;
+
+  // WebIDL API
+  // For GetSelectorText/SetSelectorText, we purposefully use a signature that
+  // matches the nsIDOMCSSStyleRule one for now, so subclasses can just
+  // implement both at once.  The actual implementations must never return
+  // anything other than NS_OK;
+  NS_IMETHOD GetSelectorText(nsAString& aSelectorText) = 0;
+  NS_IMETHOD SetSelectorText(const nsAString& aSelectorText) = 0;
+  virtual nsICSSDeclaration* Style() = 0;
+
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aGivenProto) override;
+};
+
+} // namespace mozilla
+
+#endif // mozilla_BindingStyleRule_h__
--- a/layout/style/CSSRuleList.h
+++ b/layout/style/CSSRuleList.h
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_CSSRuleList_h
 #define mozilla_dom_CSSRuleList_h
 
 #include "mozilla/StyleSheetInlines.h"
+#include "mozilla/css/Rule.h"
 #include "nsIDOMCSSRule.h"
 #include "nsIDOMCSSRuleList.h"
 #include "nsWrapperCache.h"
 
 namespace mozilla {
 namespace dom {
 
 // IID for the CSSRuleList interface
@@ -40,23 +41,23 @@ public:
   NS_IMETHOD
   Item(uint32_t aIndex, nsIDOMCSSRule** aReturn) override final
   {
     NS_IF_ADDREF(*aReturn = Item(aIndex));
     return NS_OK;
   }
 
   // WebIDL API
-  nsIDOMCSSRule* Item(uint32_t aIndex)
+  css::Rule* Item(uint32_t aIndex)
   {
     bool unused;
     return IndexedGetter(aIndex, unused);
   }
 
-  virtual nsIDOMCSSRule* IndexedGetter(uint32_t aIndex, bool& aFound) = 0;
+  virtual css::Rule* IndexedGetter(uint32_t aIndex, bool& aFound) = 0;
   virtual uint32_t Length() = 0;
 
 protected:
   virtual ~CSSRuleList() {}
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(CSSRuleList, NS_ICSSRULELIST_IID)
 
--- a/layout/style/CSSStyleSheet.cpp
+++ b/layout/style/CSSStyleSheet.cpp
@@ -56,17 +56,17 @@ using namespace mozilla::dom;
 //
 class CSSRuleListImpl final : public CSSRuleList
 {
 public:
   explicit CSSRuleListImpl(CSSStyleSheet *aStyleSheet);
 
   virtual CSSStyleSheet* GetParentObject() override;
 
-  virtual nsIDOMCSSRule*
+  virtual css::Rule*
   IndexedGetter(uint32_t aIndex, bool& aFound) override;
   virtual uint32_t
   Length() override;
 
   void DropReference() { mStyleSheet = nullptr; }
 
 protected:
   virtual ~CSSRuleListImpl();
@@ -96,28 +96,28 @@ CSSRuleListImpl::Length()
 {
   if (!mStyleSheet) {
     return 0;
   }
 
   return AssertedCast<uint32_t>(mStyleSheet->StyleRuleCount());
 }
 
-nsIDOMCSSRule*    
+css::Rule*
 CSSRuleListImpl::IndexedGetter(uint32_t aIndex, bool& aFound)
 {
   aFound = false;
 
   if (mStyleSheet) {
     // ensure rules have correct parent
     mStyleSheet->EnsureUniqueInner();
     css::Rule* rule = mStyleSheet->GetStyleRuleAt(aIndex);
     if (rule) {
       aFound = true;
-      return rule->GetDOMRule();
+      return rule;
     }
   }
 
   // Per spec: "Return Value ... null if ... not a valid index."
   return nullptr;
 }
 
 namespace mozilla {
@@ -503,17 +503,17 @@ CSSStyleSheet::TraverseInner(nsCycleColl
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "child sheet");
     cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMCSSStyleSheet*, childSheetSlot->get()));
     childSheetSlot = &(*childSheetSlot)->mNext;
   }
 
   const nsCOMArray<css::Rule>& rules = mInner->mOrderedRules;
   for (int32_t i = 0, count = rules.Count(); i < count; ++i) {
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mOrderedRules[i]");
-    cb.NoteXPCOMChild(rules[i]->GetExistingDOMRule());
+    cb.NoteXPCOMChild(rules[i]);
   }
 }
 
 // QueryInterface implementation for CSSStyleSheet
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(CSSStyleSheet)
   NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, StyleSheet)
   if (aIID.Equals(NS_GET_IID(CSSStyleSheet)))
@@ -860,20 +860,20 @@ CSSStyleSheet::RegisterNamespaceRule(css
     nsresult rv = mInner->CreateNamespaceMap();
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   AddNamespaceRuleToMap(aRule, mInner->mNameSpaceMap);
   return NS_OK;
 }
 
-nsIDOMCSSRule*
+css::Rule*
 CSSStyleSheet::GetDOMOwnerRule() const
 {
-  return mOwnerRule ? mOwnerRule->GetDOMRule() : nullptr;
+  return mOwnerRule;
 }
 
 CSSRuleList*
 CSSStyleSheet::GetCssRulesInternal(ErrorResult& aRv)
 {
   if (!mRuleCollection) {
     mRuleCollection = new CSSRuleListImpl(this);
   }
@@ -1026,21 +1026,16 @@ CSSStyleSheet::DeleteRuleInternal(uint32
 
   NS_ASSERTION(uint32_t(mInner->mOrderedRules.Count()) <= INT32_MAX,
                "Too many style rules!");
 
   // Hold a strong ref to the rule so it doesn't die when we RemoveObjectAt
   RefPtr<css::Rule> rule = mInner->mOrderedRules.ObjectAt(aIndex);
   if (rule) {
     mInner->mOrderedRules.RemoveObjectAt(aIndex);
-    if (mDocument && mDocument->StyleSheetChangeEventsEnabled()) {
-      // Force creation of the DOM rule, so that it can be put on the
-      // StyleRuleRemoved event object.
-      rule->GetDOMRule();
-    }
     rule->SetStyleSheet(nullptr);
     DidDirty();
 
     if (mDocument) {
       mDocument->StyleRuleRemoved(this, rule);
     }
   }
 }
--- a/layout/style/CSSStyleSheet.h
+++ b/layout/style/CSSStyleSheet.h
@@ -189,17 +189,17 @@ public:
   {
     mScopeElement = aScopeElement;
   }
 
   // WebIDL CSSStyleSheet API
   // Can't be inline because we can't include ImportRule here.  And can't be
   // called GetOwnerRule because that would be ambiguous with the ImportRule
   // version.
-  nsIDOMCSSRule* GetDOMOwnerRule() const final;
+  css::Rule* GetDOMOwnerRule() const final;
 
   void WillDirty();
   void DidDirty();
 
 private:
   CSSStyleSheet(const CSSStyleSheet& aCopy,
                 CSSStyleSheet* aParentToUse,
                 css::ImportRule* aOwnerRuleToUse,
--- a/layout/style/GroupRule.h
+++ b/layout/style/GroupRule.h
@@ -7,47 +7,50 @@
  * internal interface representing CSS style rules that contain other
  * rules, such as @media rules
  */
 
 #ifndef mozilla_css_GroupRule_h__
 #define mozilla_css_GroupRule_h__
 
 #include "mozilla/Attributes.h"
+#include "mozilla/ErrorResult.h"
 #include "mozilla/IncrementalClearCOMRuleArray.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/css/Rule.h"
 #include "nsCycleCollectionParticipant.h"
 
 class nsPresContext;
 class nsMediaQueryResultCacheKey;
 
 namespace mozilla {
 
 class StyleSheet;
 
+namespace dom {
+class CSSRuleList;
+} // namespace dom
+
 namespace css {
 
 class GroupRuleRuleList;
 
 // inherits from Rule so it can be shared between
 // MediaRule and DocumentRule
 class GroupRule : public Rule
 {
 protected:
   GroupRule(uint32_t aLineNumber, uint32_t aColumnNumber);
   GroupRule(const GroupRule& aCopy);
   virtual ~GroupRule();
 public:
 
-  NS_DECL_CYCLE_COLLECTION_CLASS(GroupRule)
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(GroupRule, Rule)
+  NS_DECL_ISUPPORTS_INHERITED
 
-  // implement part of Rule
-  DECL_STYLE_RULE_INHERIT_NO_DOMRULE
 #ifdef DEBUG
   virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
 #endif
   virtual void SetStyleSheet(StyleSheet* aSheet) override;
 
 public:
   void AppendStyleRule(Rule* aRule);
 
@@ -75,27 +78,51 @@ public:
   static bool
   CloneRuleInto(Rule* aRule, void* aArray)
   {
     RefPtr<Rule> clone = aRule->Clone();
     static_cast<IncrementalClearCOMRuleArray*>(aArray)->AppendObject(clone);
     return true;
   }
 
+  // WebIDL API
+  dom::CSSRuleList* CssRules();
+  uint32_t InsertRule(const nsAString& aRule, uint32_t aIndex,
+                      ErrorResult& aRv);
+  void DeleteRule(uint32_t aIndex, ErrorResult& aRv);
+
 protected:
   // to help implement nsIDOMCSSRule
-  void AppendRulesToCssText(nsAString& aCssText);
+  void AppendRulesToCssText(nsAString& aCssText) const;
 
   // to implement common methods on nsIDOMCSSMediaRule and
   // nsIDOMCSSMozDocumentRule
   nsresult GetCssRules(nsIDOMCSSRuleList* *aRuleList);
   nsresult InsertRule(const nsAString & aRule, uint32_t aIndex,
                       uint32_t* _retval);
   nsresult DeleteRule(uint32_t aIndex);
 
   IncrementalClearCOMRuleArray mRules;
   RefPtr<GroupRuleRuleList> mRuleCollection; // lazily constructed
 };
 
+// Implementation of WebIDL CSSConditionRule.
+class ConditionRule : public GroupRule
+{
+protected:
+  ConditionRule(uint32_t aLineNumber, uint32_t aColumnNumber);
+  ConditionRule(const ConditionRule& aCopy);
+  virtual ~ConditionRule();
+
+public:
+
+  // GetConditionText signature matches nsIDOMCSSConditionRule, so subclasses
+  // can implement this easily.  The implementations should never return
+  // anything other than NS_OK.
+  NS_IMETHOD GetConditionText(nsAString& aConditionText) = 0;
+  virtual void SetConditionText(const nsAString& aConditionText,
+                                ErrorResult& aRv) = 0;
+};
+
 } // namespace css
 } // namespace mozilla
 
 #endif /* mozilla_css_GroupRule_h__ */
--- a/layout/style/ImportRule.h
+++ b/layout/style/ImportRule.h
@@ -15,54 +15,61 @@
 #include "nsIDOMCSSImportRule.h"
 
 class nsMediaList;
 class nsString;
 
 namespace mozilla {
 
 class CSSStyleSheet;
+class StyleSheet;
 
 namespace css {
 
 class ImportRule final : public Rule,
                          public nsIDOMCSSImportRule
 {
 public:
   ImportRule(nsMediaList* aMedia, const nsString& aURLSpec,
              uint32_t aLineNumber, uint32_t aColumnNumber);
 private:
   // for |Clone|
   ImportRule(const ImportRule& aCopy);
   ~ImportRule();
 public:
-  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ImportRule, mozilla::css::Rule)
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-
-  DECL_STYLE_RULE_INHERIT
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ImportRule, Rule)
+  NS_DECL_ISUPPORTS_INHERITED
 
   using Rule::GetStyleSheet; // unhide since nsIDOMCSSImportRule has its own GetStyleSheet
 
   // Rule methods
 #ifdef DEBUG
   virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
 #endif
   virtual int32_t GetType() const override;
+  using Rule::GetType;
   virtual already_AddRefed<Rule> Clone() const override;
 
   void SetSheet(CSSStyleSheet*);
 
   virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
 
-  // nsIDOMCSSRule interface
-  NS_DECL_NSIDOMCSSRULE
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aGivenProto) override;
 
   // nsIDOMCSSImportRule interface
   NS_DECL_NSIDOMCSSIMPORTRULE
 
+  // WebIDL interface
+  uint16_t Type() const override;
+  void GetCssTextImpl(nsAString& aCssText) const override;
+  // The XPCOM GetHref is fine, since it never fails.
+  nsMediaList* Media() const { return mMedia; }
+  StyleSheet* GetStyleSheet() const;
+
 private:
   nsString  mURLSpec;
   RefPtr<nsMediaList> mMedia;
   RefPtr<CSSStyleSheet> mChildSheet;
 };
 
 } // namespace css
 } // namespace mozilla
--- a/layout/style/NameSpaceRule.h
+++ b/layout/style/NameSpaceRule.h
@@ -19,48 +19,50 @@ class nsIAtom;
 // IID for the NameSpaceRule class {f0b0dbe1-5031-4a21-b06a-dc141ef2af98}
 #define NS_CSS_NAMESPACE_RULE_IMPL_CID     \
 {0xf0b0dbe1, 0x5031, 0x4a21, {0xb0, 0x6a, 0xdc, 0x14, 0x1e, 0xf2, 0xaf, 0x98}}
 
 
 namespace mozilla {
 namespace css {
 
-class NameSpaceRule final : public Rule,
-                            public nsIDOMCSSRule
+class NameSpaceRule final : public Rule
 {
 public:
   NameSpaceRule(nsIAtom* aPrefix, const nsString& aURLSpec,
                 uint32_t aLineNumber, uint32_t aColumnNumber);
 private:
   // for |Clone|
   NameSpaceRule(const NameSpaceRule& aCopy);
   ~NameSpaceRule();
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_CSS_NAMESPACE_RULE_IMPL_CID)
 
-  NS_DECL_ISUPPORTS
+  NS_DECL_ISUPPORTS_INHERITED
 
-  // Rule methods
-  DECL_STYLE_RULE_INHERIT
 #ifdef DEBUG
   virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
 #endif
   virtual int32_t GetType() const override;
+  using Rule::GetType;
   virtual already_AddRefed<Rule> Clone() const override;
 
   nsIAtom* GetPrefix() const { return mPrefix; }
 
   void GetURLSpec(nsString& aURLSpec) const { aURLSpec = mURLSpec; }
 
+  // WebIDL interface
+  uint16_t Type() const override;
+  void GetCssTextImpl(nsAString& aCssText) const override;
+
   virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
     override MOZ_MUST_OVERRIDE;
 
-  // nsIDOMCSSRule interface
-  NS_DECL_NSIDOMCSSRULE
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aGivenProto) override;
 
 private:
   nsCOMPtr<nsIAtom> mPrefix;
   nsString          mURLSpec;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(NameSpaceRule, NS_CSS_NAMESPACE_RULE_IMPL_CID)
 
--- a/layout/style/Rule.h
+++ b/layout/style/Rule.h
@@ -7,35 +7,30 @@
 
 #ifndef mozilla_css_Rule_h___
 #define mozilla_css_Rule_h___
 
 #include "mozilla/StyleSheetInlines.h"
 #include "mozilla/MemoryReporting.h"
 #include "nsISupports.h"
 #include "nsIDOMCSSRule.h"
+#include "nsWrapperCache.h"
 
 class nsIDocument;
 struct nsRuleData;
 template<class T> struct already_AddRefed;
 class nsHTMLCSSStyleSheet;
 
 namespace mozilla {
 namespace css {
 class GroupRule;
 
-#define DECL_STYLE_RULE_INHERIT_NO_DOMRULE  \
- /* nothing */
-
-#define DECL_STYLE_RULE_INHERIT                            \
-  DECL_STYLE_RULE_INHERIT_NO_DOMRULE                       \
-  virtual nsIDOMCSSRule* GetDOMRule() override;        \
-  virtual nsIDOMCSSRule* GetExistingDOMRule() override;
-
-class Rule : public nsISupports {
+class Rule : public nsIDOMCSSRule
+           , public nsWrapperCache
+{
 protected:
   Rule(uint32_t aLineNumber, uint32_t aColumnNumber)
     : mSheet(nullptr),
       mParentRule(nullptr),
       mLineNumber(aLineNumber),
       mColumnNumber(aColumnNumber)
   {
   }
@@ -47,16 +42,22 @@ protected:
       mColumnNumber(aCopy.mColumnNumber)
   {
   }
 
   virtual ~Rule() {}
 
 public:
 
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Rule)
+
+  // nsIDOMCSSRule interface
+  NS_DECL_NSIDOMCSSRULE
+
 #ifdef DEBUG
   virtual void List(FILE* out = stdout, int32_t aIndent = 0) const = 0;
 #endif
 
   // The constants in this list must maintain the following invariants:
   //   If a rule of type N must appear before a rule of type M in stylesheets
   //   then N < M
   // Note that CSSStyleSheet::RebuildChildList assumes that no other kinds of
@@ -101,33 +102,30 @@ public:
   uint32_t GetLineNumber() const { return mLineNumber; }
   uint32_t GetColumnNumber() const { return mColumnNumber; }
 
   /**
    * Clones |this|. Never returns nullptr.
    */
   virtual already_AddRefed<Rule> Clone() const = 0;
 
-  // Note that this returns null for inline style rules since they aren't
-  // supposed to have a DOM rule representation (and our code wouldn't work).
-  virtual nsIDOMCSSRule* GetDOMRule() = 0;
-
-  // Like GetDOMRule(), but won't create one if we don't have one yet
-  virtual nsIDOMCSSRule* GetExistingDOMRule() = 0;
-
-  // to implement methods on nsIDOMCSSRule
-  nsresult GetParentRule(nsIDOMCSSRule** aParentRule);
-  nsresult GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet);
-  Rule* GetCSSRule();
-
   // This is pure virtual because all of Rule's data members are non-owning and
   // thus measured elsewhere.
   virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
     const MOZ_MUST_OVERRIDE = 0;
 
+  // WebIDL interface, aka helpers for nsIDOMCSSRule implementation.
+  virtual uint16_t Type() const = 0;
+  virtual void GetCssTextImpl(nsAString& aCssText) const = 0;
+  // XPCOM GetCssText is OK, since it never throws.
+  // XPCOM SetCssText is OK, since it never throws.
+  Rule* GetParentRule() const;
+  StyleSheet* GetParentStyleSheet() const { return GetStyleSheet(); }
+  nsIDocument* GetParentObject() const { return GetDocument(); }
+
 protected:
   // This is sometimes null (e.g., for style attributes).
   StyleSheet* mSheet;
   // When the parent GroupRule is destroyed, it will call SetParentRule(nullptr)
   // on this object. (Through SetParentRuleReference);
   GroupRule* MOZ_NON_OWNING_REF mParentRule;
 
   // Keep the same type so that MSVC packs them.
--- a/layout/style/ServoCSSRuleList.cpp
+++ b/layout/style/ServoCSSRuleList.cpp
@@ -42,17 +42,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Se
       rule = 0;
     }
   }
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(dom::CSSRuleList)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ServoCSSRuleList,
                                                   dom::CSSRuleList)
   tmp->EnumerateInstantiatedRules([&](css::Rule* aRule) {
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mRules[i]");
-    cb.NoteXPCOMChild(aRule->GetExistingDOMRule());
+    cb.NoteXPCOMChild(aRule);
   });
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 css::Rule*
 ServoCSSRuleList::GetRule(uint32_t aIndex)
 {
   uintptr_t rule = mRules[aIndex];
   if (rule <= kMaxRuleType) {
@@ -74,28 +74,25 @@ ServoCSSRuleList::GetRule(uint32_t aInde
     }
     ruleObj->SetStyleSheet(mStyleSheet);
     rule = CastToUint(ruleObj.forget().take());
     mRules[aIndex] = rule;
   }
   return CastToPtr(rule);
 }
 
-nsIDOMCSSRule*
+css::Rule*
 ServoCSSRuleList::IndexedGetter(uint32_t aIndex, bool& aFound)
 {
   if (aIndex >= mRules.Length()) {
     aFound = false;
     return nullptr;
   }
   aFound = true;
-  if (css::Rule* rule = GetRule(aIndex)) {
-    return rule->GetDOMRule();
-  }
-  return nullptr;
+  return GetRule(aIndex);
 }
 
 template<typename Func>
 void
 ServoCSSRuleList::EnumerateInstantiatedRules(Func aCallback)
 {
   for (uintptr_t rule : mRules) {
     if (rule > kMaxRuleType) {
--- a/layout/style/ServoCSSRuleList.h
+++ b/layout/style/ServoCSSRuleList.h
@@ -25,17 +25,17 @@ public:
   ServoCSSRuleList(ServoStyleSheet* aStyleSheet,
                    already_AddRefed<ServoCssRules> aRawRules);
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServoCSSRuleList, dom::CSSRuleList)
 
   ServoStyleSheet* GetParentObject() final { return mStyleSheet; }
 
-  nsIDOMCSSRule* IndexedGetter(uint32_t aIndex, bool& aFound) final;
+  css::Rule* IndexedGetter(uint32_t aIndex, bool& aFound) final;
   uint32_t Length() final { return mRules.Length(); }
 
   void DropReference();
 
   css::Rule* GetRule(uint32_t aIndex);
   nsresult InsertRule(const nsAString& aRule, uint32_t aIndex);
   nsresult DeleteRule(uint32_t aIndex);
 
--- a/layout/style/ServoStyleRule.cpp
+++ b/layout/style/ServoStyleRule.cpp
@@ -6,18 +6,18 @@
 
 /* representation of CSSStyleRule for stylo */
 
 #include "mozilla/ServoStyleRule.h"
 
 #include "mozilla/DeclarationBlockInlines.h"
 #include "mozilla/ServoBindings.h"
 #include "mozilla/ServoDeclarationBlock.h"
+#include "mozilla/dom/CSSStyleRuleBinding.h"
 
-#include "nsDOMClassInfoID.h"
 #include "mozAutoDocUpdate.h"
 
 namespace mozilla {
 
 // -- ServoStyleRuleDeclaration ---------------------------------------
 
 ServoStyleRuleDeclaration::ServoStyleRuleDeclaration(
   already_AddRefed<RawServoDeclarationBlock> aDecls)
@@ -95,50 +95,47 @@ ServoStyleRuleDeclaration::GetCSSParsing
   CSSParsingEnvironment& aCSSParseEnv)
 {
   GetCSSParsingEnvironmentForRule(Rule(), aCSSParseEnv);
 }
 
 // -- ServoStyleRule --------------------------------------------------
 
 ServoStyleRule::ServoStyleRule(already_AddRefed<RawServoStyleRule> aRawRule)
-  : css::Rule(0, 0)
+  : BindingStyleRule(0, 0)
   , mRawRule(aRawRule)
   , mDecls(Servo_StyleRule_GetStyle(mRawRule).Consume())
 {
 }
 
 // QueryInterface implementation for ServoStyleRule
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServoStyleRule)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ServoStyleRule)
   NS_INTERFACE_MAP_ENTRY(nsIDOMCSSStyleRule)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, css::Rule)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSStyleRule)
-NS_INTERFACE_MAP_END
+NS_INTERFACE_MAP_END_INHERITING(css::Rule)
 
-NS_IMPL_CYCLE_COLLECTING_ADDREF(ServoStyleRule)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(ServoStyleRule)
+NS_IMPL_ADDREF_INHERITED(ServoStyleRule, css::Rule)
+NS_IMPL_RELEASE_INHERITED(ServoStyleRule, css::Rule)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(ServoStyleRule)
 
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ServoStyleRule)
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ServoStyleRule, css::Rule)
   // Trace the wrapper for our declaration.  This just expands out
   // NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER which we can't use
   // directly because the wrapper is on the declaration, not on us.
   tmp->mDecls.TraceWrapper(aCallbacks, aClosure);
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ServoStyleRule)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ServoStyleRule, css::Rule)
   // Unlink the wrapper for our declaraton.  This just expands out
   // NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER which we can't use
   // directly because the wrapper is on the declaration, not on us.
   tmp->mDecls.ReleaseWrapper(static_cast<nsISupports*>(p));
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ServoStyleRule)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ServoStyleRule, css::Rule)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 already_AddRefed<css::Rule>
 ServoStyleRule::Clone() const
 {
   // Rule::Clone is only used when CSSStyleSheetInner is cloned in
   // preparation of being mutated. However, ServoStyleSheet never clones
   // anything, so this method should never be called.
@@ -163,53 +160,32 @@ ServoStyleRule::List(FILE* out, int32_t 
   }
   Servo_StyleRule_Debug(mRawRule, &str);
   fprintf_stderr(out, "%s\n", str.get());
 }
 #endif
 
 /* CSSRule implementation */
 
-NS_IMETHODIMP
-ServoStyleRule::GetType(uint16_t* aType)
+uint16_t
+ServoStyleRule::Type() const
 {
-  *aType = nsIDOMCSSRule::STYLE_RULE;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-ServoStyleRule::GetCssText(nsAString& aCssText)
-{
-  Servo_StyleRule_GetCssText(mRawRule, &aCssText);
-  return NS_OK;
+  return nsIDOMCSSRule::STYLE_RULE;
 }
 
-NS_IMETHODIMP
-ServoStyleRule::SetCssText(const nsAString& aCssText)
+void
+ServoStyleRule::GetCssTextImpl(nsAString& aCssText) const
 {
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-ServoStyleRule::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet)
-{
-  return css::Rule::GetParentStyleSheet(aSheet);
+  Servo_StyleRule_GetCssText(mRawRule, &aCssText);
 }
 
-NS_IMETHODIMP
-ServoStyleRule::GetParentRule(nsIDOMCSSRule** aParentRule)
+nsICSSDeclaration*
+ServoStyleRule::Style()
 {
-  *aParentRule = nullptr;
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-css::Rule*
-ServoStyleRule::GetCSSRule()
-{
-  return this;
+  return &mDecls;
 }
 
 /* CSSStyleRule implementation */
 
 NS_IMETHODIMP
 ServoStyleRule::GetSelectorText(nsAString& aSelectorText)
 {
   Servo_StyleRule_GetSelectorText(mRawRule, &aSelectorText);
--- a/layout/style/ServoStyleRule.h
+++ b/layout/style/ServoStyleRule.h
@@ -4,17 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* representation of CSSStyleRule for stylo */
 
 #ifndef mozilla_ServoStyleRule_h
 #define mozilla_ServoStyleRule_h
 
-#include "mozilla/css/Rule.h"
+#include "mozilla/BindingStyleRule.h"
 #include "mozilla/ServoBindingTypes.h"
 
 #include "nsIDOMCSSStyleRule.h"
 #include "nsDOMCSSDeclaration.h"
 
 namespace mozilla {
 
 class ServoDeclarationBlock;
@@ -42,35 +42,38 @@ private:
     already_AddRefed<RawServoDeclarationBlock> aDecls);
   ~ServoStyleRuleDeclaration();
 
   inline ServoStyleRule* Rule();
 
   RefPtr<ServoDeclarationBlock> mDecls;
 };
 
-class ServoStyleRule final : public css::Rule
+class ServoStyleRule final : public BindingStyleRule
                            , public nsIDOMCSSStyleRule
 {
 public:
   explicit ServoStyleRule(already_AddRefed<RawServoStyleRule> aRawRule);
 
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(ServoStyleRule,
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(ServoStyleRule,
                                                          css::Rule)
-  NS_DECL_NSIDOMCSSRULE
   NS_DECL_NSIDOMCSSSTYLERULE
 
+  // WebIDL interface
+  uint16_t Type() const override;
+  void GetCssTextImpl(nsAString& aCssText) const override;
+  virtual nsICSSDeclaration* Style() override;
+
   RawServoStyleRule* Raw() const { return mRawRule; }
 
   // Methods of mozilla::css::Rule
   int32_t GetType() const final { return css::Rule::STYLE_RULE; }
+  using Rule::GetType;
   already_AddRefed<Rule> Clone() const final;
-  nsIDOMCSSRule* GetDOMRule() final { return this; }
-  nsIDOMCSSRule* GetExistingDOMRule() final { return this; }
   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const final;
 #ifdef DEBUG
   void List(FILE* out = stdout, int32_t aIndent = 0) const final;
 #endif
 
 private:
   ~ServoStyleRule() {}
 
--- a/layout/style/ServoStyleSheet.cpp
+++ b/layout/style/ServoStyleSheet.cpp
@@ -140,19 +140,20 @@ ServoStyleSheet::SizeOfIncludingThis(Mal
 #ifdef DEBUG
 void
 ServoStyleSheet::List(FILE* aOut, int32_t aIndex) const
 {
   MOZ_CRASH("stylo: not implemented");
 }
 #endif
 
-nsIDOMCSSRule*
+css::Rule*
 ServoStyleSheet::GetDOMOwnerRule() const
 {
+  NS_ERROR("stylo: Don't know how to get DOM owner rule for ServoStyleSheet");
   return nullptr;
 }
 
 CSSRuleList*
 ServoStyleSheet::GetCssRulesInternal(ErrorResult& aRv)
 {
   if (!mRuleList) {
     RefPtr<ServoCssRules> rawRules = Servo_StyleSheet_GetRules(mSheet).Consume();
--- a/layout/style/ServoStyleSheet.h
+++ b/layout/style/ServoStyleSheet.h
@@ -15,16 +15,17 @@
 #include "nsStringFwd.h"
 
 namespace mozilla {
 
 class ServoCSSRuleList;
 
 namespace css {
 class Loader;
+class Rule;
 }
 
 /**
  * CSS style sheet object that is a wrapper for a Servo Stylesheet.
  */
 class ServoStyleSheet : public StyleSheet
 {
 public:
@@ -68,17 +69,17 @@ public:
     MOZ_ASSERT(!mSheet);
     mSheet = aSheet;
   }
 
   // WebIDL CSSStyleSheet API
   // Can't be inline because we can't include ImportRule here.  And can't be
   // called GetOwnerRule because that would be ambiguous with the ImportRule
   // version.
-  nsIDOMCSSRule* GetDOMOwnerRule() const final;
+  css::Rule* GetDOMOwnerRule() const final;
 
   void WillDirty() {}
   void DidDirty() {}
 
 protected:
   virtual ~ServoStyleSheet();
 
   // Internal methods which do not have security check and completeness check.
--- a/layout/style/StyleRule.cpp
+++ b/layout/style/StyleRule.cpp
@@ -11,28 +11,27 @@
 
 #include "mozilla/css/StyleRule.h"
 
 #include "mozilla/DeclarationBlockInlines.h"
 #include "mozilla/StyleSheetInlines.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/css/GroupRule.h"
 #include "mozilla/css/Declaration.h"
+#include "mozilla/dom/CSSStyleRuleBinding.h"
 #include "nsIDocument.h"
 #include "nsIAtom.h"
 #include "nsString.h"
 #include "nsStyleUtil.h"
-#include "nsICSSStyleRuleDOMWrapper.h"
 #include "nsDOMCSSDeclaration.h"
 #include "nsNameSpaceManager.h"
 #include "nsXMLNameSpaceMap.h"
 #include "nsCSSPseudoClasses.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsTArray.h"
-#include "nsDOMClassInfoID.h"
 #include "nsContentUtils.h"
 #include "nsError.h"
 #include "mozAutoDocUpdate.h"
 
 class nsIDOMCSSStyleDeclaration;
 class nsIDOMCSSStyleSheet;
 
 using namespace mozilla;
@@ -1042,166 +1041,96 @@ nsCSSSelectorList::SizeOfIncludingThis(m
     n += s->mSelectors ? s->mSelectors->SizeOfIncludingThis(aMallocSizeOf) : 0;
     s = s->mNext;
   }
   return n;
 }
 
 // --------------------------------------------------------
 
-namespace mozilla {
-namespace css {
-class DOMCSSStyleRule;
-} // namespace css
-} // namespace mozilla
-
 class DOMCSSDeclarationImpl : public nsDOMCSSDeclaration
 {
 protected:
+  // Needs to be protected so we can use NS_IMPL_ADDREF_USING_AGGREGATOR.
   virtual ~DOMCSSDeclarationImpl(void);
 
+  // But we need to allow UniquePtr to delete us.
+  friend class mozilla::DefaultDelete<DOMCSSDeclarationImpl>;
+
 public:
   explicit DOMCSSDeclarationImpl(css::StyleRule *aRule);
 
   NS_IMETHOD GetParentRule(nsIDOMCSSRule **aParent) override;
-  void DropReference(void);
   virtual DeclarationBlock* GetCSSDeclaration(Operation aOperation) override;
   virtual nsresult SetCSSDeclaration(DeclarationBlock* aDecl) override;
   virtual void GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv) override;
   virtual nsIDocument* DocToUpdate() override;
 
-  // Override |AddRef| and |Release| for being a member of
-  // |DOMCSSStyleRule|.  Also, we need to forward QI for cycle
-  // collection things to DOMCSSStyleRule.
+  // Override |AddRef| and |Release| for being owned by StyleRule.  Also, we
+  // need to forward QI for cycle collection things to StyleRule.
   NS_DECL_ISUPPORTS_INHERITED
 
   virtual nsINode *GetParentObject() override
   {
     return mRule ? mRule->GetDocument() : nullptr;
   }
 
-  friend class css::DOMCSSStyleRule;
-
 protected:
-  // This reference is not reference-counted. The rule object tells us
-  // when it's about to go away.
+  // This reference is not reference-counted. The rule object owns us and we go
+  // away when it does.
   css::StyleRule *mRule;
-
-  inline css::DOMCSSStyleRule* DomRule();
-
-private:
-  // NOT TO BE IMPLEMENTED
-  // This object cannot be allocated on its own.  It must be a member of
-  // DOMCSSStyleRule.
-  void* operator new(size_t size) CPP_THROW_NEW;
 };
 
-namespace mozilla {
-namespace css {
-
-class DOMCSSStyleRule : public nsICSSStyleRuleDOMWrapper
-{
-public:
-  explicit DOMCSSStyleRule(StyleRule *aRule);
-
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMCSSStyleRule)
-  NS_DECL_NSIDOMCSSRULE
-  NS_DECL_NSIDOMCSSSTYLERULE
-
-  // nsICSSStyleRuleDOMWrapper
-  NS_IMETHOD GetCSSStyleRule(StyleRule **aResult) override;
-
-  DOMCSSDeclarationImpl* DOMDeclaration() { return &mDOMDeclaration; }
-
-  friend class ::DOMCSSDeclarationImpl;
-
-protected:
-  virtual ~DOMCSSStyleRule();
-
-  DOMCSSDeclarationImpl mDOMDeclaration;
-
-  StyleRule* Rule() {
-    return mDOMDeclaration.mRule;
-  }
-};
-
-} // namespace css
-} // namespace mozilla
-
 DOMCSSDeclarationImpl::DOMCSSDeclarationImpl(css::StyleRule *aRule)
   : mRule(aRule)
 {
 }
 
 DOMCSSDeclarationImpl::~DOMCSSDeclarationImpl(void)
 {
-  NS_ASSERTION(!mRule, "DropReference not called.");
 }
 
-inline css::DOMCSSStyleRule* DOMCSSDeclarationImpl::DomRule()
-{
-  return reinterpret_cast<css::DOMCSSStyleRule*>
-                         (reinterpret_cast<char*>(this) -
-           offsetof(css::DOMCSSStyleRule, mDOMDeclaration));
-}
-
-NS_IMPL_ADDREF_USING_AGGREGATOR(DOMCSSDeclarationImpl, DomRule())
-NS_IMPL_RELEASE_USING_AGGREGATOR(DOMCSSDeclarationImpl, DomRule())
+NS_IMPL_ADDREF_USING_AGGREGATOR(DOMCSSDeclarationImpl, mRule)
+NS_IMPL_RELEASE_USING_AGGREGATOR(DOMCSSDeclarationImpl, mRule)
 
 NS_INTERFACE_MAP_BEGIN(DOMCSSDeclarationImpl)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-  // We forward the cycle collection interfaces to DomRule(), which is
-  // never null (in fact, we're part of that object!)
+  // We forward the cycle collection interfaces to mRule, which is
+  // never null.
   if (aIID.Equals(NS_GET_IID(nsCycleCollectionISupports)) ||
       aIID.Equals(NS_GET_IID(nsXPCOMCycleCollectionParticipant))) {
-    return DomRule()->QueryInterface(aIID, aInstancePtr);
+    return mRule->QueryInterface(aIID, aInstancePtr);
   }
   else
 NS_IMPL_QUERY_TAIL_INHERITING(nsDOMCSSDeclaration)
 
-void
-DOMCSSDeclarationImpl::DropReference(void)
-{
-  mRule = nullptr;
-}
-
 DeclarationBlock*
 DOMCSSDeclarationImpl::GetCSSDeclaration(Operation aOperation)
 {
-  if (mRule) {
-    if (aOperation != eOperation_Read) {
-      RefPtr<CSSStyleSheet> sheet = mRule->GetStyleSheet();
-      if (sheet) {
-        sheet->WillDirty();
-      }
+  if (aOperation != eOperation_Read) {
+    RefPtr<CSSStyleSheet> sheet = mRule->GetStyleSheet();
+    if (sheet) {
+      sheet->WillDirty();
     }
-    return mRule->GetDeclaration();
-  } else {
-    return nullptr;
   }
+  return mRule->GetDeclaration();
 }
 
 void
 DOMCSSDeclarationImpl::GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv)
 {
   GetCSSParsingEnvironmentForRule(mRule, aCSSParseEnv);
 }
 
 NS_IMETHODIMP
 DOMCSSDeclarationImpl::GetParentRule(nsIDOMCSSRule **aParent)
 {
   NS_ENSURE_ARG_POINTER(aParent);
 
-  if (!mRule) {
-    *aParent = nullptr;
-    return NS_OK;
-  }
-
-  NS_IF_ADDREF(*aParent = mRule->GetDOMRule());
+  NS_IF_ADDREF(*aParent = mRule);
   return NS_OK;
 }
 
 nsresult
 DOMCSSDeclarationImpl::SetCSSDeclaration(DeclarationBlock* aDecl)
 {
   NS_PRECONDITION(mRule,
          "can only be called when |GetCSSDeclaration| returned a declaration");
@@ -1227,239 +1156,139 @@ DOMCSSDeclarationImpl::SetCSSDeclaration
 }
 
 nsIDocument*
 DOMCSSDeclarationImpl::DocToUpdate()
 {
   return nullptr;
 }
 
-namespace mozilla {
-namespace css {
-
-DOMCSSStyleRule::DOMCSSStyleRule(StyleRule* aRule)
-  : mDOMDeclaration(aRule)
-{
-}
-
-DOMCSSStyleRule::~DOMCSSStyleRule()
-{
-}
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMCSSStyleRule)
-  NS_INTERFACE_MAP_ENTRY(nsICSSStyleRuleDOMWrapper)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMCSSStyleRule)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule)
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSStyleRule)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMCSSStyleRule)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMCSSStyleRule)
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(DOMCSSStyleRule)
-
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMCSSStyleRule)
-  // Trace the wrapper for our declaration.  This just expands out
-  // NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER which we can't use
-  // directly because the wrapper is on the declaration, not on us.
-  tmp->DOMDeclaration()->TraceWrapper(aCallbacks, aClosure);
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMCSSStyleRule)
-  // Unlink the wrapper for our declaraton.  This just expands out
-  // NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER which we can't use
-  // directly because the wrapper is on the declaration, not on us.
-  tmp->DOMDeclaration()->ReleaseWrapper(static_cast<nsISupports*>(p));
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMCSSStyleRule)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMETHODIMP
-DOMCSSStyleRule::GetType(uint16_t* aType)
-{
-  *aType = nsIDOMCSSRule::STYLE_RULE;
-  
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-DOMCSSStyleRule::GetCssText(nsAString& aCssText)
-{
-  if (!Rule()) {
-    aCssText.Truncate();
-  } else {
-    Rule()->GetCssText(aCssText);
-  }
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-DOMCSSStyleRule::SetCssText(const nsAString& aCssText)
-{
-  if (Rule()) {
-    Rule()->SetCssText(aCssText);
-  }
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-DOMCSSStyleRule::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet)
-{
-  if (!Rule()) {
-    *aSheet = nullptr;
-    return NS_OK;
-  }
-  return Rule()->GetParentStyleSheet(aSheet);
-}
-
-NS_IMETHODIMP
-DOMCSSStyleRule::GetParentRule(nsIDOMCSSRule** aParentRule)
-{
-  if (!Rule()) {
-    *aParentRule = nullptr;
-    return NS_OK;
-  }
-  return Rule()->GetParentRule(aParentRule);
-}
-
-css::Rule*
-DOMCSSStyleRule::GetCSSRule()
-{
-  return Rule();
-}
-
-NS_IMETHODIMP
-DOMCSSStyleRule::GetSelectorText(nsAString& aSelectorText)
-{
-  if (!Rule()) {
-    aSelectorText.Truncate();
-  } else {
-    Rule()->GetSelectorText(aSelectorText);
-  }
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-DOMCSSStyleRule::SetSelectorText(const nsAString& aSelectorText)
-{
-  if (Rule()) {
-    Rule()->SetSelectorText(aSelectorText);
-  }
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-DOMCSSStyleRule::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
-{
-  *aStyle = &mDOMDeclaration;
-  NS_ADDREF(*aStyle);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-DOMCSSStyleRule::GetCSSStyleRule(StyleRule **aResult)
-{
-  *aResult = Rule();
-  NS_IF_ADDREF(*aResult);
-  return NS_OK;
-}
-
-} // namespace css
-} // namespace mozilla
-
 // -- StyleRule ------------------------------------
 
 namespace mozilla {
 namespace css {
 
+uint16_t
+StyleRule::Type() const
+{
+  return nsIDOMCSSRule::STYLE_RULE;
+}
+
+NS_IMETHODIMP
+StyleRule::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
+{
+  NS_ADDREF(*aStyle = Style());
+  return NS_OK;
+}
+
+nsICSSDeclaration*
+StyleRule::Style()
+{
+  if (!mDOMDeclaration) {
+    mDOMDeclaration.reset(new DOMCSSDeclarationImpl(this));
+  }
+  return mDOMDeclaration.get();
+}
+
+NS_IMETHODIMP
+StyleRule::GetCSSStyleRule(StyleRule **aResult)
+{
+  *aResult = this;
+  NS_ADDREF(*aResult);
+  return NS_OK;
+}
+
 StyleRule::StyleRule(nsCSSSelectorList* aSelector,
                      Declaration* aDeclaration,
                      uint32_t aLineNumber,
                      uint32_t aColumnNumber)
-  : Rule(aLineNumber, aColumnNumber),
+  : BindingStyleRule(aLineNumber, aColumnNumber),
     mSelector(aSelector),
     mDeclaration(aDeclaration)
 {
   NS_PRECONDITION(aDeclaration, "must have a declaration");
 
   mDeclaration->SetOwningRule(this);
 }
 
 // for |Clone|
 StyleRule::StyleRule(const StyleRule& aCopy)
-  : Rule(aCopy),
+  : BindingStyleRule(aCopy),
     mSelector(aCopy.mSelector ? aCopy.mSelector->Clone() : nullptr),
     mDeclaration(new Declaration(*aCopy.mDeclaration))
 {
   mDeclaration->SetOwningRule(this);
   // rest is constructed lazily on existing data
 }
 
 StyleRule::~StyleRule()
 {
   delete mSelector;
-  if (mDOMRule) {
-    mDOMRule->DOMDeclaration()->DropReference();
-  }
+  DropReferences();
+}
 
+void
+StyleRule::DropReferences()
+{
   if (mDeclaration) {
     mDeclaration->SetOwningRule(nullptr);
+    mDeclaration = nullptr;
   }
 }
 
 // QueryInterface implementation for StyleRule
-NS_INTERFACE_MAP_BEGIN(StyleRule)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(StyleRule)
   if (aIID.Equals(NS_GET_IID(mozilla::css::StyleRule))) {
     *aInstancePtr = this;
     NS_ADDREF_THIS();
     return NS_OK;
   }
   else
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozilla::css::Rule)
-NS_INTERFACE_MAP_END
+  NS_INTERFACE_MAP_ENTRY(nsICSSStyleRuleDOMWrapper)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMCSSStyleRule)
+NS_INTERFACE_MAP_END_INHERITING(Rule)
+
+NS_IMPL_ADDREF_INHERITED(StyleRule, Rule)
+NS_IMPL_RELEASE_INHERITED(StyleRule, Rule)
 
-NS_IMPL_ADDREF(StyleRule)
-NS_IMPL_RELEASE(StyleRule)
+NS_IMPL_CYCLE_COLLECTION_CLASS(StyleRule)
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(StyleRule, Rule)
+  // Trace the wrapper for our declaration.  This just expands out
+  // NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER which we can't use
+  // directly because the wrapper is on the declaration, not on us.
+  if (tmp->mDOMDeclaration) {
+    tmp->mDOMDeclaration->TraceWrapper(aCallbacks, aClosure);
+  }
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(StyleRule, Rule)
+  // Unlink the wrapper for our declaraton.  This just expands out
+  // NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER which we can't use
+  // directly because the wrapper is on the declaration, not on us.
+  if (tmp->mDOMDeclaration) {
+    tmp->mDOMDeclaration->ReleaseWrapper(static_cast<nsISupports*>(p));
+  }
+  tmp->DropReferences();
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(StyleRule, Rule)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDeclaration)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 /* virtual */ int32_t
 StyleRule::GetType() const
 {
   return Rule::STYLE_RULE;
 }
 
 /* virtual */ already_AddRefed<Rule>
 StyleRule::Clone() const
 {
   RefPtr<Rule> clone = new StyleRule(*this);
   return clone.forget();
 }
 
-/* virtual */ nsIDOMCSSRule*
-StyleRule::GetDOMRule()
-{
-  if (!mDOMRule) {
-    if (!GetStyleSheet()) {
-      // Inline style rules aren't supposed to have a DOM rule object, only
-      // a declaration.  But if we do have one already, from a style sheet
-      // rule that used to be in a document, we still want to return it.
-      return nullptr;
-    }
-    mDOMRule = new DOMCSSStyleRule(this);
-  }
-  return mDOMRule;
-}
-
-/* virtual */ nsIDOMCSSRule*
-StyleRule::GetExistingDOMRule()
-{
-  return mDOMRule;
-}
-
 void
 StyleRule::SetDeclaration(Declaration* aDecl)
 {
   if (aDecl == mDeclaration) {
     return;
   }
   mDeclaration->SetOwningRule(nullptr);
   mDeclaration = aDecl;
@@ -1505,17 +1334,17 @@ StyleRule::List(FILE* out, int32_t aInde
     str.AppendLiteral("{ null declaration }");
   }
   str.Append('\n');
   fprintf_stderr(out, "%s", str.get());
 }
 #endif
 
 void
-StyleRule::GetCssText(nsAString& aCssText)
+StyleRule::GetCssTextImpl(nsAString& aCssText) const
 {
   if (mSelector) {
     mSelector->ToString(aCssText, GetStyleSheet());
     aCssText.Append(char16_t(' '));
   }
   aCssText.Append(char16_t('{'));
   aCssText.Append(char16_t(' '));
   if (mDeclaration)
@@ -1523,48 +1352,43 @@ StyleRule::GetCssText(nsAString& aCssTex
     nsAutoString   tempString;
     mDeclaration->ToString( tempString );
     aCssText.Append( tempString );
   }
   aCssText.Append(char16_t(' '));
   aCssText.Append(char16_t('}'));
 }
 
-void
-StyleRule::SetCssText(const nsAString& aCssText)
-{
-  // XXX TBI - need to re-parse rule & declaration
-}
-
-void
+NS_IMETHODIMP
 StyleRule::GetSelectorText(nsAString& aSelectorText)
 {
   if (mSelector)
     mSelector->ToString(aSelectorText, GetStyleSheet());
   else
     aSelectorText.Truncate();
+  return NS_OK;
 }
 
-void
+NS_IMETHODIMP
 StyleRule::SetSelectorText(const nsAString& aSelectorText)
 {
   // XXX TBI - get a parser and re-parse the selectors,
   // XXX then need to re-compute the cascade
   // XXX and dirty sheet
+  return NS_OK;
 }
 
 /* virtual */ size_t
 StyleRule::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
 {
   size_t n = aMallocSizeOf(this);
   n += mSelector ? mSelector->SizeOfIncludingThis(aMallocSizeOf) : 0;
   n += mDeclaration ? mDeclaration->SizeOfIncludingThis(aMallocSizeOf) : 0;
 
   // Measurement of the following members may be added later if DMD finds it is
   // worthwhile:
   // - mDOMRule;
 
   return n;
 }
 
-
 } // namespace css
 } // namespace mozilla
--- a/layout/style/StyleRule.h
+++ b/layout/style/StyleRule.h
@@ -8,22 +8,24 @@
  * selectors
  */
 
 #ifndef mozilla_css_StyleRule_h__
 #define mozilla_css_StyleRule_h__
 
 #include "mozilla/Attributes.h"
 #include "mozilla/MemoryReporting.h"
-#include "mozilla/css/Rule.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/BindingStyleRule.h"
 
 #include "nsString.h"
 #include "nsCOMPtr.h"
 #include "nsCSSPseudoElements.h"
 #include "nsIStyleRule.h"
+#include "nsICSSStyleRuleDOMWrapper.h"
 
 class nsIAtom;
 struct nsCSSSelectorList;
 
 namespace mozilla {
 enum class CSSPseudoClassType : uint8_t;
 class CSSStyleSheet;
 } // namespace mozilla
@@ -297,76 +299,85 @@ private:
   nsCSSSelectorList& operator=(const nsCSSSelectorList& aCopy) = delete;
 };
 
 // 464bab7a-2fce-4f30-ab44-b7a5f3aae57d
 #define NS_CSS_STYLE_RULE_IMPL_CID \
 { 0x464bab7a, 0x2fce, 0x4f30, \
   { 0xab, 0x44, 0xb7, 0xa5, 0xf3, 0xaa, 0xe5, 0x7d } }
 
+class DOMCSSDeclarationImpl;
+
 namespace mozilla {
 namespace css {
 
 class Declaration;
-class DOMCSSStyleRule;
 
-class StyleRule final : public Rule
+class StyleRule final : public BindingStyleRule
+                      , public nsICSSStyleRuleDOMWrapper
 {
  public:
   StyleRule(nsCSSSelectorList* aSelector,
             Declaration *aDeclaration,
             uint32_t aLineNumber, uint32_t aColumnNumber);
 private:
   // for |Clone|
   StyleRule(const StyleRule& aCopy);
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_CSS_STYLE_RULE_IMPL_CID)
 
-  NS_DECL_ISUPPORTS
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(StyleRule, Rule)
+  NS_DECL_NSIDOMCSSSTYLERULE
+
+  // nsICSSStyleRuleDOMWrapper
+  NS_IMETHOD GetCSSStyleRule(StyleRule **aResult) override;
+
+  // WebIDL interface
+  uint16_t Type() const override;
+  void GetCssTextImpl(nsAString& aCssText) const override;
+  virtual nsICSSDeclaration* Style() override;
 
   // null for style attribute
   nsCSSSelectorList* Selector() { return mSelector; }
 
   Declaration* GetDeclaration() const { return mDeclaration; }
 
   void SetDeclaration(Declaration* aDecl);
 
-  // hooks for DOM rule
-  void GetCssText(nsAString& aCssText);
-  void SetCssText(const nsAString& aCssText);
-  void GetSelectorText(nsAString& aSelectorText);
-  void SetSelectorText(const nsAString& aSelectorText);
-
   virtual int32_t GetType() const override;
+  using Rule::GetType;
 
   CSSStyleSheet* GetStyleSheet() const
   {
     StyleSheet* sheet = Rule::GetStyleSheet();
     return sheet ? sheet->AsGecko() : nullptr;
   }
 
   virtual already_AddRefed<Rule> Clone() const override;
 
-  virtual nsIDOMCSSRule* GetDOMRule() override;
-
-  virtual nsIDOMCSSRule* GetExistingDOMRule() override;
-
 #ifdef DEBUG
   virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
 #endif
 
   virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
 
 private:
   ~StyleRule();
 
+  // Drop our references to mDeclaration and mRule, and let them know we're
+  // doing that.
+  void DropReferences();
+
 private:
   nsCSSSelectorList*      mSelector; // null for style attribute
   RefPtr<Declaration>     mDeclaration;
-  RefPtr<DOMCSSStyleRule> mDOMRule;
+
+  // We own it, and it aggregates its refcount with us.
+  UniquePtr<DOMCSSDeclarationImpl> mDOMDeclaration;
 
 private:
   StyleRule& operator=(const StyleRule& aCopy) = delete;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(StyleRule, NS_CSS_STYLE_RULE_IMPL_CID)
 
 } // namespace css
--- a/layout/style/StyleSheet.h
+++ b/layout/style/StyleSheet.h
@@ -28,16 +28,20 @@ class CSSStyleSheet;
 class ServoStyleSheet;
 struct StyleSheetInfo;
 
 namespace dom {
 class CSSRuleList;
 class SRIMetadata;
 } // namespace dom
 
+namespace css {
+class Rule;
+}
+
 /**
  * Superclass for data common to CSSStyleSheet and ServoStyleSheet.
  */
 class StyleSheet : public nsIDOMCSSStyleSheet
                  , public nsWrapperCache
 {
 protected:
   StyleSheet(StyleBackendType aType, css::SheetParsingMode aParsingMode);
@@ -143,17 +147,17 @@ public:
   // GetOwnerNode is defined above.
   inline StyleSheet* GetParentStyleSheet() const;
   // The XPCOM GetTitle is fine for WebIDL.
   nsMediaList* Media();
   bool Disabled() const { return mDisabled; }
   // The XPCOM SetDisabled is fine for WebIDL.
 
   // WebIDL CSSStyleSheet API
-  virtual nsIDOMCSSRule* GetDOMOwnerRule() const = 0;
+  virtual css::Rule* GetDOMOwnerRule() const = 0;
   dom::CSSRuleList* GetCssRules(nsIPrincipal& aSubjectPrincipal,
                                 ErrorResult& aRv);
   uint32_t InsertRule(const nsAString& aRule, uint32_t aIndex,
                       nsIPrincipal& aSubjectPrincipal,
                       ErrorResult& aRv);
   void DeleteRule(uint32_t aIndex,
                   nsIPrincipal& aSubjectPrincipal,
                   ErrorResult& aRv);
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -76,16 +76,17 @@ EXPORTS += [
     'nsStyleStructFwd.h',
     'nsStyleStructInlines.h',
     'nsStyleTransformMatrix.h',
     'nsStyleUtil.h',
 ]
 
 EXPORTS.mozilla += [
     'AnimationCollection.h',
+    'BindingStyleRule.h',
     'CSSEnabledState.h',
     'CSSStyleSheet.h',
     'CSSVariableDeclarations.h',
     'CSSVariableResolver.h',
     'CSSVariableValues.h',
     'DeclarationBlock.h',
     'DeclarationBlockInlines.h',
     'DocumentStyleRootIterator.h',
@@ -211,20 +212,28 @@ UNIFIED_SOURCES += [
     'ServoStyleSet.cpp',
     'ServoStyleSheet.cpp',
     'StyleAnimationValue.cpp',
     'StyleRule.cpp',
     'StyleSheet.cpp',
     'SVGAttrAnimationRuleProcessor.cpp',
 ]
 
-# nsCSSRuleProcessor.cpp needs to be built separately because it uses plarena.h.
-# nsLayoutStylesheetCache.cpp needs to be built separately because it uses
+# - BindingStyleRule.cpp doesn't _really_ needs to be built separately,
+# except insofar as it shifts unified build boundaries, causing
+# Unified_cpp_layout_style4.cpp to include nsStyleCoord.cpp, which
+# includes, via nsStyleCoord.h, <type_traits>, which ends up including
+# <xutility>, which fails in much the way described in
+# <https://bugzilla.mozilla.org/show_bug.cgi?id=1331102>.
+# - nsCSSRuleProcessor.cpp needs to be built separately because it uses
+# plarena.h.
+# - nsLayoutStylesheetCache.cpp needs to be built separately because it uses
 # nsExceptionHandler.h, which includes windows.h.
 SOURCES += [
+    'BindingStyleRule.cpp',
     'nsCSSRuleProcessor.cpp',
     'nsLayoutStylesheetCache.cpp',
 ]
 
 EXTRA_COMPONENTS += [
     'CSSUnprefixingService.js',
     'CSSUnprefixingService.manifest',
 ]
--- a/layout/style/nsCSSRules.cpp
+++ b/layout/style/nsCSSRules.cpp
@@ -28,85 +28,122 @@
 
 #include "nsContentUtils.h"
 #include "nsError.h"
 #include "nsStyleUtil.h"
 #include "mozilla/DeclarationBlockInlines.h"
 #include "nsCSSParser.h"
 #include "nsDOMClassInfoID.h"
 #include "mozilla/dom/CSSStyleDeclarationBinding.h"
+#include "mozilla/dom/CSSNamespaceRuleBinding.h"
+#include "mozilla/dom/CSSImportRuleBinding.h"
+#include "mozilla/dom/CSSMediaRuleBinding.h"
+#include "mozilla/dom/CSSSupportsRuleBinding.h"
+#include "mozilla/dom/CSSMozDocumentRuleBinding.h"
+#include "mozilla/dom/CSSPageRuleBinding.h"
+#include "mozilla/dom/CSSFontFaceRuleBinding.h"
+#include "mozilla/dom/CSSFontFeatureValuesRuleBinding.h"
+#include "mozilla/dom/CSSKeyframeRuleBinding.h"
+#include "mozilla/dom/CSSKeyframesRuleBinding.h"
+#include "mozilla/dom/CSSCounterStyleRuleBinding.h"
 #include "StyleRule.h"
 #include "nsFont.h"
 #include "nsIURI.h"
 #include "mozAutoDocUpdate.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-#define IMPL_STYLE_RULE_INHERIT_GET_DOM_RULE_WEAK(class_, super_) \
-  /* virtual */ nsIDOMCSSRule* class_::GetDOMRule()               \
-  { return this; }                                                \
-  /* virtual */ nsIDOMCSSRule* class_::GetExistingDOMRule()       \
-  { return this; }
-
-#define IMPL_STYLE_RULE_INHERIT(class_, super_) \
-IMPL_STYLE_RULE_INHERIT_GET_DOM_RULE_WEAK(class_, super_)
-
 // base class for all rule types in a CSS style sheet
 
 namespace mozilla {
 namespace css {
 
+NS_IMPL_CYCLE_COLLECTING_ADDREF(Rule)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(Rule)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Rule)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule)
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(Rule)
+
 /* virtual */ void
 Rule::SetStyleSheet(StyleSheet* aSheet)
 {
   // We don't reference count this up reference. The style sheet
   // will tell us when it's going away or when we're detached from
   // it.
   mSheet = aSheet;
 }
 
-nsresult
+NS_IMETHODIMP
 Rule::GetParentRule(nsIDOMCSSRule** aParentRule)
 {
-  if (mParentRule) {
-    NS_IF_ADDREF(*aParentRule = mParentRule->GetDOMRule());
-  } else {
-    *aParentRule = nullptr;
-  }
+  NS_IF_ADDREF(*aParentRule = mParentRule);
   return NS_OK;
 }
 
-nsresult
+NS_IMETHODIMP
 Rule::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet)
 {
   NS_ENSURE_ARG_POINTER(aSheet);
 
   NS_IF_ADDREF(*aSheet = GetStyleSheet());
   return NS_OK;
 }
 
-css::Rule*
+/* virtual */ css::Rule*
 Rule::GetCSSRule()
 {
   return this;
 }
 
+NS_IMETHODIMP
+Rule::GetType(uint16_t* aType)
+{
+  *aType = Type();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+Rule::SetCssText(const nsAString& aCssText)
+{
+  // We used to throw for some rule types, but not all.  Specifically, we did
+  // not throw for StyleRule.  Let's just always not throw.
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+Rule::GetCssText(nsAString& aCssText)
+{
+  GetCssTextImpl(aCssText);
+  return NS_OK;
+}
+
+Rule*
+Rule::GetParentRule() const
+{
+  return mParentRule;
+}
+
 // -------------------------------
 // Style Rule List for group rules
 //
 
 class GroupRuleRuleList final : public dom::CSSRuleList
 {
 public:
   explicit GroupRuleRuleList(GroupRule *aGroupRule);
 
   virtual CSSStyleSheet* GetParentObject() override;
 
-  virtual nsIDOMCSSRule*
+  virtual Rule*
   IndexedGetter(uint32_t aIndex, bool& aFound) override;
   virtual uint32_t
   Length() override;
 
   void DropReference() { mGroupRule = nullptr; }
 
 private:
   ~GroupRuleRuleList();
@@ -141,42 +178,43 @@ GroupRuleRuleList::Length()
 {
   if (!mGroupRule) {
     return 0;
   }
 
   return AssertedCast<uint32_t>(mGroupRule->StyleRuleCount());
 }
 
-nsIDOMCSSRule*
+Rule*
 GroupRuleRuleList::IndexedGetter(uint32_t aIndex, bool& aFound)
 {
   aFound = false;
 
   if (mGroupRule) {
     RefPtr<Rule> rule = mGroupRule->GetStyleRuleAt(aIndex);
     if (rule) {
       aFound = true;
-      return rule->GetDOMRule();
+      return rule;
     }
   }
 
   return nullptr;
 }
 
 // -------------------------------------------
 // ImportRule
 //
 
 ImportRule::ImportRule(nsMediaList* aMedia, const nsString& aURLSpec,
                        uint32_t aLineNumber, uint32_t aColumnNumber)
   : Rule(aLineNumber, aColumnNumber)
   , mURLSpec(aURLSpec)
   , mMedia(aMedia)
 {
+  MOZ_ASSERT(aMedia);
   // XXXbz This is really silly.... the mMedia here will be replaced
   // with itself if we manage to load a sheet.  Which should really
   // never fail nowadays, in sane cases.
 }
 
 ImportRule::ImportRule(const ImportRule& aCopy)
   : Rule(aCopy),
     mURLSpec(aCopy.mURLSpec)
@@ -194,30 +232,25 @@ ImportRule::ImportRule(const ImportRule&
 
 ImportRule::~ImportRule()
 {
   if (mChildSheet) {
     mChildSheet->SetOwnerRule(nullptr);
   }
 }
 
-NS_IMPL_CYCLE_COLLECTING_ADDREF(ImportRule)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(ImportRule)
-
-NS_IMPL_CYCLE_COLLECTION(ImportRule, mMedia, mChildSheet)
+NS_IMPL_ADDREF_INHERITED(ImportRule, Rule)
+NS_IMPL_RELEASE_INHERITED(ImportRule, Rule)
+
+NS_IMPL_CYCLE_COLLECTION_INHERITED(ImportRule, Rule, mMedia, mChildSheet)
 
 // QueryInterface implementation for ImportRule
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ImportRule)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ImportRule)
   NS_INTERFACE_MAP_ENTRY(nsIDOMCSSImportRule)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozilla::css::Rule)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSImportRule)
-NS_INTERFACE_MAP_END
-
-IMPL_STYLE_RULE_INHERIT(ImportRule, Rule)
+NS_INTERFACE_MAP_END_INHERITING(Rule)
 
 #ifdef DEBUG
 /* virtual */ void
 ImportRule::List(FILE* out, int32_t aIndent) const
 {
   nsAutoCString str;
   // Indent
   for (int32_t indent = aIndent; --indent >= 0; ) {
@@ -257,79 +290,58 @@ ImportRule::SetSheet(CSSStyleSheet* aShe
   // set the new sheet
   mChildSheet = aSheet;
   aSheet->SetOwnerRule(this);
 
   // set our medialist to be the same as the sheet's medialist
   mMedia = mChildSheet->Media();
 }
 
-NS_IMETHODIMP
-ImportRule::GetType(uint16_t* aType)
+uint16_t
+ImportRule::Type() const
 {
-  NS_ENSURE_ARG_POINTER(aType);
-  *aType = nsIDOMCSSRule::IMPORT_RULE;
-  return NS_OK;
+  return nsIDOMCSSRule::IMPORT_RULE;
 }
 
-NS_IMETHODIMP
-ImportRule::GetCssText(nsAString& aCssText)
+void
+ImportRule::GetCssTextImpl(nsAString& aCssText) const
 {
   aCssText.AssignLiteral("@import url(");
   nsStyleUtil::AppendEscapedCSSString(mURLSpec, aCssText);
   aCssText.Append(')');
   if (mMedia) {
     nsAutoString mediaText;
     mMedia->GetText(mediaText);
     if (!mediaText.IsEmpty()) {
       aCssText.Append(' ');
       aCssText.Append(mediaText);
     }
   }
   aCssText.Append(';');
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-ImportRule::SetCssText(const nsAString& aCssText)
-{
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-ImportRule::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet)
+StyleSheet*
+ImportRule::GetStyleSheet() const
 {
-  return Rule::GetParentStyleSheet(aSheet);
-}
-
-NS_IMETHODIMP
-ImportRule::GetParentRule(nsIDOMCSSRule** aParentRule)
-{
-  return Rule::GetParentRule(aParentRule);
-}
-
-css::Rule*
-ImportRule::GetCSSRule()
-{
-  return Rule::GetCSSRule();
+  return mChildSheet;
 }
 
 NS_IMETHODIMP
 ImportRule::GetHref(nsAString & aHref)
 {
   aHref = mURLSpec;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 ImportRule::GetMedia(nsIDOMMediaList * *aMedia)
 {
   NS_ENSURE_ARG_POINTER(aMedia);
 
-  NS_IF_ADDREF(*aMedia = mMedia);
+  NS_ADDREF(*aMedia = mMedia);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 ImportRule::GetStyleSheet(nsIDOMCSSStyleSheet * *aStyleSheet)
 {
   NS_ENSURE_ARG_POINTER(aStyleSheet);
 
@@ -346,16 +358,23 @@ ImportRule::SizeOfIncludingThis(MallocSi
   // worthwhile:
   // - mURLSpec
   //
   // The following members are not measured:
   // - mMedia, because it is measured via CSSStyleSheet::mMedia
   // - mChildSheet, because it is measured via CSSStyleSheetInner::mSheets
 }
 
+/* virtual */ JSObject*
+ImportRule::WrapObject(JSContext* aCx,
+                       JS::Handle<JSObject*> aGivenProto)
+{
+  return CSSImportRuleBinding::Wrap(aCx, this, aGivenProto);
+}
+
 GroupRule::GroupRule(uint32_t aLineNumber, uint32_t aColumnNumber)
   : Rule(aLineNumber, aColumnNumber)
 {
 }
 
 static bool
 SetParentRuleReference(Rule* aRule, void* aParentRule)
 {
@@ -375,32 +394,32 @@ GroupRule::~GroupRule()
 {
   MOZ_ASSERT(!mSheet, "SetStyleSheet should have been called");
   mRules.EnumerateForwards(SetParentRuleReference, nullptr);
   if (mRuleCollection) {
     mRuleCollection->DropReference();
   }
 }
 
-NS_IMPL_CYCLE_COLLECTING_ADDREF(GroupRule)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(GroupRule)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(GroupRule)
-NS_INTERFACE_MAP_END
+NS_IMPL_ADDREF_INHERITED(GroupRule, Rule)
+NS_IMPL_RELEASE_INHERITED(GroupRule, Rule)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(GroupRule)
+NS_INTERFACE_MAP_END_INHERITING(Rule)
 
 static bool
 SetStyleSheetReference(Rule* aRule, void* aSheet)
 {
   aRule->SetStyleSheet(reinterpret_cast<StyleSheet*>(aSheet));
   return true;
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(GroupRule)
 
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(GroupRule)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(GroupRule, Rule)
   tmp->mRules.EnumerateForwards(SetParentRuleReference, nullptr);
   // If tmp does not have a stylesheet, neither do its descendants.  In that
   // case, don't try to null out their stylesheet, to avoid O(N^2) behavior in
   // depth of group rule nesting.  But if tmp _does_ have a stylesheet (which
   // can happen if it gets unlinked earlier than its owning stylesheet), then we
   // need to null out the stylesheet pointer on descendants now, before we clear
   // tmp->mRules.
   if (tmp->GetStyleSheet()) {
@@ -408,21 +427,21 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Gr
   }
   tmp->mRules.Clear();
   if (tmp->mRuleCollection) {
     tmp->mRuleCollection->DropReference();
     tmp->mRuleCollection = nullptr;
   }
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(GroupRule)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(GroupRule, Rule)
   const nsCOMArray<Rule>& rules = tmp->mRules;
   for (int32_t i = 0, count = rules.Count(); i < count; ++i) {
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mRules[i]");
-    cb.NoteXPCOMChild(rules[i]->GetExistingDOMRule());
+    cb.NoteXPCOMChild(rules[i]);
   }
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRuleCollection)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 /* virtual */ void
 GroupRule::SetStyleSheet(StyleSheet* aSheet)
 {
   // Don't set the sheet on the kids if it's already the same as the sheet we
@@ -494,130 +513,182 @@ GroupRule::InsertStyleRuleAt(uint32_t aI
   aRule->SetParentRule(this);
   if (! mRules.InsertObjectAt(aRule, aIndex)) {
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
 void
-GroupRule::AppendRulesToCssText(nsAString& aCssText)
+GroupRule::AppendRulesToCssText(nsAString& aCssText) const
 {
   aCssText.AppendLiteral(" {\n");
 
   // get all the rules
   for (int32_t index = 0, count = mRules.Count(); index < count; ++index) {
     Rule* rule = mRules.ObjectAt(index);
-    nsIDOMCSSRule* domRule = rule->GetDOMRule();
-    if (domRule) {
-      nsAutoString cssText;
-      domRule->GetCssText(cssText);
-      aCssText.AppendLiteral("  ");
-      aCssText.Append(cssText);
-      aCssText.Append('\n');
-    }
+    nsAutoString cssText;
+    rule->GetCssText(cssText);
+    aCssText.AppendLiteral("  ");
+    aCssText.Append(cssText);
+    aCssText.Append('\n');
   }
 
   aCssText.Append('}');
 }
 
 // nsIDOMCSSMediaRule or nsIDOMCSSMozDocumentRule methods
 nsresult
 GroupRule::GetCssRules(nsIDOMCSSRuleList* *aRuleList)
 {
+  NS_ADDREF(*aRuleList = CssRules());
+  return NS_OK;
+}
+
+CSSRuleList*
+GroupRule::CssRules()
+{
   if (!mRuleCollection) {
     mRuleCollection = new css::GroupRuleRuleList(this);
   }
 
-  NS_ADDREF(*aRuleList = mRuleCollection);
-  return NS_OK;
+  return mRuleCollection;
 }
 
 nsresult
 GroupRule::InsertRule(const nsAString & aRule, uint32_t aIndex, uint32_t* _retval)
 {
+  ErrorResult rv;
+  *_retval = InsertRule(aRule, aIndex, rv);
+  return rv.StealNSResult();
+}
+
+uint32_t
+GroupRule::InsertRule(const nsAString& aRule, uint32_t aIndex, ErrorResult& aRv)
+{
   StyleSheet* sheet = GetStyleSheet();
-  NS_ENSURE_TRUE(sheet, NS_ERROR_FAILURE);
-  
-  if (aIndex > uint32_t(mRules.Count()))
-    return NS_ERROR_DOM_INDEX_SIZE_ERR;
+  if (NS_WARN_IF(!sheet)) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return 0;
+  }
+
+  if (aIndex > uint32_t(mRules.Count())) {
+    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+    return 0;
+  }
 
   NS_ASSERTION(uint32_t(mRules.Count()) <= INT32_MAX,
                "Too many style rules!");
 
-  return sheet->AsGecko()->InsertRuleIntoGroup(aRule, this, aIndex, _retval);
+  uint32_t retval;
+  nsresult rv =
+    sheet->AsGecko()->InsertRuleIntoGroup(aRule, this, aIndex, &retval);
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+    return 0;
+  }
+  return retval;
 }
 
 nsresult
 GroupRule::DeleteRule(uint32_t aIndex)
 {
+  ErrorResult rv;
+  DeleteRule(aIndex, rv);
+  return rv.StealNSResult();
+}
+
+void
+GroupRule::DeleteRule(uint32_t aIndex, ErrorResult& aRv)
+{
   StyleSheet* sheet = GetStyleSheet();
-  NS_ENSURE_TRUE(sheet, NS_ERROR_FAILURE);
-
-  if (aIndex >= uint32_t(mRules.Count()))
-    return NS_ERROR_DOM_INDEX_SIZE_ERR;
+  if (NS_WARN_IF(!sheet)) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
+
+  if (aIndex >= uint32_t(mRules.Count())) {
+    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+    return;
+  }
 
   NS_ASSERTION(uint32_t(mRules.Count()) <= INT32_MAX,
                "Too many style rules!");
 
-  return sheet->AsGecko()->DeleteRuleFromGroup(this, aIndex);
+  nsresult rv = sheet->AsGecko()->DeleteRuleFromGroup(this, aIndex);
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+  }
 }
 
 /* virtual */ size_t
 GroupRule::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
 {
   size_t n = mRules.ShallowSizeOfExcludingThis(aMallocSizeOf);
   for (size_t i = 0; i < mRules.Length(); i++) {
     n += mRules[i]->SizeOfIncludingThis(aMallocSizeOf);
   }
 
   // Measurement of the following members may be added later if DMD finds it is
   // worthwhile:
   // - mRuleCollection
   return n;
 }
 
+ConditionRule::ConditionRule(uint32_t aLineNumber, uint32_t aColumnNumber)
+  : GroupRule(aLineNumber, aColumnNumber)
+{
+}
+
+ConditionRule::ConditionRule(const ConditionRule& aCopy)
+  : GroupRule(aCopy)
+{
+}
+
+ConditionRule::~ConditionRule()
+{
+}
 
 // -------------------------------------------
 // nsICSSMediaRule
 //
 MediaRule::MediaRule(uint32_t aLineNumber, uint32_t aColumnNumber)
-  : GroupRule(aLineNumber, aColumnNumber)
+  : ConditionRule(aLineNumber, aColumnNumber)
 {
 }
 
 MediaRule::MediaRule(const MediaRule& aCopy)
-  : GroupRule(aCopy)
+  : ConditionRule(aCopy)
 {
   if (aCopy.mMedia) {
     mMedia = aCopy.mMedia->Clone();
     // XXXldb This doesn't really make sense.
     mMedia->SetStyleSheet(aCopy.GetStyleSheet());
   }
 }
 
 MediaRule::~MediaRule()
 {
   if (mMedia) {
     mMedia->SetStyleSheet(nullptr);
   }
 }
 
-NS_IMPL_ADDREF_INHERITED(MediaRule, GroupRule)
-NS_IMPL_RELEASE_INHERITED(MediaRule, GroupRule)
+NS_IMPL_ADDREF_INHERITED(MediaRule, ConditionRule)
+NS_IMPL_RELEASE_INHERITED(MediaRule, ConditionRule)
 
 // QueryInterface implementation for MediaRule
-NS_INTERFACE_MAP_BEGIN(MediaRule)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MediaRule)
   NS_INTERFACE_MAP_ENTRY(nsIDOMCSSGroupingRule)
   NS_INTERFACE_MAP_ENTRY(nsIDOMCSSConditionRule)
   NS_INTERFACE_MAP_ENTRY(nsIDOMCSSMediaRule)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozilla::css::Rule)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSMediaRule)
-NS_INTERFACE_MAP_END_INHERITING(GroupRule)
+NS_INTERFACE_MAP_END_INHERITING(ConditionRule)
+
+NS_IMPL_CYCLE_COLLECTION_INHERITED(MediaRule, ConditionRule,
+                                   mMedia)
 
 /* virtual */ void
 MediaRule::SetStyleSheet(StyleSheet* aSheet)
 {
   if (mMedia) {
     // Set to null so it knows it's leaving one sheet and joining another.
     mMedia->SetStyleSheet(nullptr);
     if (aSheet) {
@@ -672,55 +743,36 @@ nsresult
 MediaRule::SetMedia(nsMediaList* aMedia)
 {
   mMedia = aMedia;
   if (aMedia)
     mMedia->SetStyleSheet(GetStyleSheet());
   return NS_OK;
 }
 
-// nsIDOMCSSRule methods
-NS_IMETHODIMP
-MediaRule::GetType(uint16_t* aType)
+uint16_t
+MediaRule::Type() const
 {
-  *aType = nsIDOMCSSRule::MEDIA_RULE;
-  return NS_OK;
+  return nsIDOMCSSRule::MEDIA_RULE;
 }
 
-NS_IMETHODIMP
-MediaRule::GetCssText(nsAString& aCssText)
+nsMediaList*
+MediaRule::Media() const
+{
+  // In practice, if we end up being parsed at all, we have non-null mMedia.  So
+  // it's OK to claim we don't return null here.
+  return mMedia;
+}
+
+void
+MediaRule::GetCssTextImpl(nsAString& aCssText) const
 {
   aCssText.AssignLiteral("@media ");
   AppendConditionText(aCssText);
   GroupRule::AppendRulesToCssText(aCssText);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-MediaRule::SetCssText(const nsAString& aCssText)
-{
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-MediaRule::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet)
-{
-  return GroupRule::GetParentStyleSheet(aSheet);
-}
-
-NS_IMETHODIMP
-MediaRule::GetParentRule(nsIDOMCSSRule** aParentRule)
-{
-  return GroupRule::GetParentRule(aParentRule);
-}
-
-css::Rule*
-MediaRule::GetCSSRule()
-{
-  return Rule::GetCSSRule();
 }
 
 // nsIDOMCSSGroupingRule methods
 NS_IMETHODIMP
 MediaRule::GetCssRules(nsIDOMCSSRuleList* *aRuleList)
 {
   return GroupRule::GetCssRules(aRuleList);
 }
@@ -744,27 +796,41 @@ MediaRule::GetConditionText(nsAString& a
   aConditionText.Truncate(0);
   AppendConditionText(aConditionText);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 MediaRule::SetConditionText(const nsAString& aConditionText)
 {
+  ErrorResult rv;
+  SetConditionText(aConditionText, rv);
+  return rv.StealNSResult();
+}
+
+void
+MediaRule::SetConditionText(const nsAString& aConditionText,
+                            ErrorResult& aRv)
+{
   if (!mMedia) {
     RefPtr<nsMediaList> media = new nsMediaList();
     media->SetStyleSheet(GetStyleSheet());
     nsresult rv = media->SetMediaText(aConditionText);
     if (NS_SUCCEEDED(rv)) {
       mMedia = media;
+    } else {
+      aRv.Throw(rv);
     }
-    return rv;
+    return;
   }
 
-  return mMedia->SetMediaText(aConditionText);
+  nsresult rv = mMedia->SetMediaText(aConditionText);
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+  }
 }
 
 // nsIDOMCSSMediaRule methods
 NS_IMETHODIMP
 MediaRule::GetMedia(nsIDOMMediaList* *aMedia)
 {
   NS_ENSURE_ARG_POINTER(aMedia);
   NS_IF_ADDREF(*aMedia = mMedia);
@@ -790,53 +856,57 @@ MediaRule::SizeOfIncludingThis(MallocSiz
 
   // Measurement of the following members may be added later if DMD finds it is
   // worthwhile:
   // - mMedia
 
   return n;
 }
 
+/* virtual */ JSObject*
+MediaRule::WrapObject(JSContext* aCx,
+                      JS::Handle<JSObject*> aGivenProto)
+{
+  return CSSMediaRuleBinding::Wrap(aCx, this, aGivenProto);
+}
+
 void
-MediaRule::AppendConditionText(nsAString& aOutput)
+MediaRule::AppendConditionText(nsAString& aOutput) const
 {
   if (mMedia) {
     nsAutoString mediaText;
     mMedia->GetText(mediaText);
     aOutput.Append(mediaText);
   }
 }
 
 DocumentRule::DocumentRule(uint32_t aLineNumber, uint32_t aColumnNumber)
-  : GroupRule(aLineNumber, aColumnNumber)
+  : ConditionRule(aLineNumber, aColumnNumber)
 {
 }
 
 DocumentRule::DocumentRule(const DocumentRule& aCopy)
-  : GroupRule(aCopy)
+  : ConditionRule(aCopy)
   , mURLs(new URL(*aCopy.mURLs))
 {
 }
 
 DocumentRule::~DocumentRule()
 {
 }
 
-NS_IMPL_ADDREF_INHERITED(DocumentRule, GroupRule)
-NS_IMPL_RELEASE_INHERITED(DocumentRule, GroupRule)
+NS_IMPL_ADDREF_INHERITED(DocumentRule, ConditionRule)
+NS_IMPL_RELEASE_INHERITED(DocumentRule, ConditionRule)
 
 // QueryInterface implementation for DocumentRule
 NS_INTERFACE_MAP_BEGIN(DocumentRule)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule)
   NS_INTERFACE_MAP_ENTRY(nsIDOMCSSGroupingRule)
   NS_INTERFACE_MAP_ENTRY(nsIDOMCSSConditionRule)
   NS_INTERFACE_MAP_ENTRY(nsIDOMCSSMozDocumentRule)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozilla::css::Rule)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSMozDocumentRule)
-NS_INTERFACE_MAP_END_INHERITING(GroupRule)
+NS_INTERFACE_MAP_END_INHERITING(ConditionRule)
 
 #ifdef DEBUG
 /* virtual */ void
 DocumentRule::List(FILE* out, int32_t aIndent) const
 {
   nsAutoCString indentStr;
   for (int32_t indent = aIndent; --indent >= 0; ) {
     indentStr.AppendLiteral("  ");
@@ -881,56 +951,29 @@ DocumentRule::GetType() const
 
 /* virtual */ already_AddRefed<Rule>
 DocumentRule::Clone() const
 {
   RefPtr<Rule> clone = new DocumentRule(*this);
   return clone.forget();
 }
 
-// nsIDOMCSSRule methods
-NS_IMETHODIMP
-DocumentRule::GetType(uint16_t* aType)
+uint16_t
+DocumentRule::Type() const
 {
   // XXX What should really happen here?
-  *aType = nsIDOMCSSRule::UNKNOWN_RULE;
-  return NS_OK;
+  return nsIDOMCSSRule::UNKNOWN_RULE;
 }
 
-NS_IMETHODIMP
-DocumentRule::GetCssText(nsAString& aCssText)
+void
+DocumentRule::GetCssTextImpl(nsAString& aCssText) const
 {
   aCssText.AssignLiteral("@-moz-document ");
   AppendConditionText(aCssText);
   GroupRule::AppendRulesToCssText(aCssText);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-DocumentRule::SetCssText(const nsAString& aCssText)
-{
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-DocumentRule::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet)
-{
-  return GroupRule::GetParentStyleSheet(aSheet);
-}
-
-NS_IMETHODIMP
-DocumentRule::GetParentRule(nsIDOMCSSRule** aParentRule)
-{
-  return GroupRule::GetParentRule(aParentRule);
-}
-
-css::Rule*
-DocumentRule::GetCSSRule()
-{
-  return Rule::GetCSSRule();
 }
 
 // nsIDOMCSSGroupingRule methods
 NS_IMETHODIMP
 DocumentRule::GetCssRules(nsIDOMCSSRuleList* *aRuleList)
 {
   return GroupRule::GetCssRules(aRuleList);
 }
@@ -957,16 +1000,23 @@ DocumentRule::GetConditionText(nsAString
 }
 
 NS_IMETHODIMP
 DocumentRule::SetConditionText(const nsAString& aConditionText)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
+void
+DocumentRule::SetConditionText(const nsAString& aConditionText,
+                               ErrorResult& aRv)
+{
+  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
+}
+
 // GroupRule interface
 /* virtual */ bool
 DocumentRule::UseForPresentation(nsPresContext* aPresContext,
                                  nsMediaQueryResultCacheKey& aKey)
 {
   return UseForPresentation(aPresContext);
 }
 
@@ -1032,18 +1082,25 @@ DocumentRule::SizeOfIncludingThis(Malloc
 
   // Measurement of the following members may be added later if DMD finds it is
   // worthwhile:
   // - mURLs
 
   return n;
 }
 
+/* virtual */ JSObject*
+DocumentRule::WrapObject(JSContext* aCx,
+                         JS::Handle<JSObject*> aGivenProto)
+{
+  return CSSMozDocumentRuleBinding::Wrap(aCx, this, aGivenProto);
+}
+
 void
-DocumentRule::AppendConditionText(nsAString& aCssText)
+DocumentRule::AppendConditionText(nsAString& aCssText) const
 {
   for (URL *url = mURLs; url; url = url->next) {
     switch (url->func) {
       case eURL:
         aCssText.AppendLiteral("url(");
         break;
       case eURLPrefix:
         aCssText.AppendLiteral("url-prefix(");
@@ -1080,33 +1137,28 @@ NameSpaceRule::NameSpaceRule(const NameS
     mURLSpec(aCopy.mURLSpec)
 {
 }
 
 NameSpaceRule::~NameSpaceRule()
 {
 }
 
-NS_IMPL_ADDREF(NameSpaceRule)
-NS_IMPL_RELEASE(NameSpaceRule)
+NS_IMPL_ADDREF_INHERITED(NameSpaceRule, Rule)
+NS_IMPL_RELEASE_INHERITED(NameSpaceRule, Rule)
 
 // QueryInterface implementation for NameSpaceRule
 NS_INTERFACE_MAP_BEGIN(NameSpaceRule)
   if (aIID.Equals(NS_GET_IID(css::NameSpaceRule))) {
     *aInstancePtr = this;
     NS_ADDREF_THIS();
     return NS_OK;
   }
   else
-  NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozilla::css::Rule)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSNameSpaceRule)
-NS_INTERFACE_MAP_END
-
-IMPL_STYLE_RULE_INHERIT(NameSpaceRule, Rule)
+NS_INTERFACE_MAP_END_INHERITING(Rule)
 
 #ifdef DEBUG
 /* virtual */ void
 NameSpaceRule::List(FILE* out, int32_t aIndent) const
 {
   nsAutoCString str;
   for (int32_t indent = aIndent; --indent >= 0; ) {
     str.AppendLiteral("  ");
@@ -1137,71 +1189,51 @@ NameSpaceRule::GetType() const
 
 /* virtual */ already_AddRefed<Rule>
 NameSpaceRule::Clone() const
 {
   RefPtr<Rule> clone = new NameSpaceRule(*this);
   return clone.forget();
 }
 
-NS_IMETHODIMP
-NameSpaceRule::GetType(uint16_t* aType)
+uint16_t
+NameSpaceRule::Type() const
 {
-  *aType = nsIDOMCSSRule::NAMESPACE_RULE;
-  return NS_OK;
+  return nsIDOMCSSRule::NAMESPACE_RULE;
 }
 
-NS_IMETHODIMP
-NameSpaceRule::GetCssText(nsAString& aCssText)
+void
+NameSpaceRule::GetCssTextImpl(nsAString& aCssText) const
 {
   aCssText.AssignLiteral("@namespace ");
   if (mPrefix) {
     aCssText.Append(nsDependentAtomString(mPrefix) + NS_LITERAL_STRING(" "));
   }
   aCssText.AppendLiteral("url(");
   nsStyleUtil::AppendEscapedCSSString(mURLSpec, aCssText);
   aCssText.AppendLiteral(");");
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-NameSpaceRule::SetCssText(const nsAString& aCssText)
-{
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-NameSpaceRule::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet)
-{
-  return Rule::GetParentStyleSheet(aSheet);
-}
-
-NS_IMETHODIMP
-NameSpaceRule::GetParentRule(nsIDOMCSSRule** aParentRule)
-{
-  return Rule::GetParentRule(aParentRule);
-}
-
-css::Rule*
-NameSpaceRule::GetCSSRule()
-{
-  return Rule::GetCSSRule();
 }
 
 /* virtual */ size_t
 NameSpaceRule::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
 {
   return aMallocSizeOf(this);
 
   // Measurement of the following members may be added later if DMD finds it is
   // worthwhile:
   // - mPrefix
   // - mURLSpec
 }
 
+/* virtual */ JSObject*
+NameSpaceRule::WrapObject(JSContext* aCx,
+                          JS::Handle<JSObject*> aGivenProto)
+{
+  return CSSNamespaceRuleBinding::Wrap(aCx, this, aGivenProto);
+}
 
 } // namespace css
 } // namespace mozilla
 
 // -------------------------------------------
 // nsCSSFontFaceStyleDecl and related routines
 //
 
@@ -1324,16 +1356,23 @@ nsCSSFontFaceStyleDecl::GetPropertyValue
                 "out-of-range value got to the switch");
   return NS_ERROR_INVALID_ARG;
 }
 
 
 NS_IMETHODIMP
 nsCSSFontFaceStyleDecl::GetCssText(nsAString & aCssText)
 {
+  GetCssTextImpl(aCssText);
+  return NS_OK;
+}
+
+void
+nsCSSFontFaceStyleDecl::GetCssTextImpl(nsAString& aCssText) const
+{
   nsAutoString descStr;
 
   aCssText.Truncate();
   for (nsCSSFontDesc id = nsCSSFontDesc(eCSSFontDesc_UNKNOWN + 1);
        id < eCSSFontDesc_COUNT;
        id = nsCSSFontDesc(id + 1)) {
     if (mDescriptors.Get(id).GetUnit() != eCSSUnit_Null &&
         NS_SUCCEEDED(GetPropertyValue(id, descStr))) {
@@ -1341,17 +1380,16 @@ nsCSSFontFaceStyleDecl::GetCssText(nsASt
                    "GetCssText: non-null unit, empty property value");
       aCssText.AppendLiteral("  ");
       aCssText.AppendASCII(nsCSSProps::GetStringValue(id).get());
       aCssText.AppendLiteral(": ");
       aCssText.Append(descStr);
       aCssText.AppendLiteral(";\n");
     }
   }
-  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCSSFontFaceStyleDecl::SetCssText(const nsAString & aCssText)
 {
   return NS_ERROR_NOT_IMPLEMENTED; // bug 443978
 }
 
@@ -1458,17 +1496,17 @@ nsCSSFontFaceStyleDecl::IndexedGetter(ui
     }
   }
   aFound = false;
 }
 
 NS_IMETHODIMP
 nsCSSFontFaceStyleDecl::GetParentRule(nsIDOMCSSRule** aParentRule)
 {
-  NS_IF_ADDREF(*aParentRule = ContainingRule()->GetDOMRule());
+  NS_IF_ADDREF(*aParentRule = ContainingRule());
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCSSFontFaceStyleDecl::GetPropertyValue(const nsCSSPropertyID aPropID,
                                          nsAString& aValue)
 {
   return
@@ -1502,47 +1540,45 @@ nsCSSFontFaceStyleDecl::WrapObject(JSCon
 
 /* virtual */ already_AddRefed<css::Rule>
 nsCSSFontFaceRule::Clone() const
 {
   RefPtr<css::Rule> clone = new nsCSSFontFaceRule(*this);
   return clone.forget();
 }
 
-NS_IMPL_CYCLE_COLLECTING_ADDREF(nsCSSFontFaceRule)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(nsCSSFontFaceRule)
+NS_IMPL_ADDREF_INHERITED(nsCSSFontFaceRule, mozilla::css::Rule)
+NS_IMPL_RELEASE_INHERITED(nsCSSFontFaceRule, mozilla::css::Rule)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsCSSFontFaceRule)
 
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsCSSFontFaceRule)
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(nsCSSFontFaceRule,
+                                               mozilla::css::Rule)
   // Trace the wrapper for our declaration.  This just expands out
   // NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER which we can't use
   // directly because the wrapper is on the declaration, not on us.
   tmp->mDecl.TraceWrapper(aCallbacks, aClosure);
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsCSSFontFaceRule)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsCSSFontFaceRule,
+                                                mozilla::css::Rule)
   // Unlink the wrapper for our declaraton.  This just expands out
   // NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER which we can't use
   // directly because the wrapper is on the declaration, not on us.
   tmp->mDecl.ReleaseWrapper(static_cast<nsISupports*>(p));
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsCSSFontFaceRule)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsCSSFontFaceRule,
+                                                  mozilla::css::Rule)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 // QueryInterface implementation for nsCSSFontFaceRule
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsCSSFontFaceRule)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsCSSFontFaceRule)
   NS_INTERFACE_MAP_ENTRY(nsIDOMCSSFontFaceRule)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozilla::css::Rule)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSFontFaceRule)
-NS_INTERFACE_MAP_END
-
-IMPL_STYLE_RULE_INHERIT(nsCSSFontFaceRule, Rule)
+NS_INTERFACE_MAP_END_INHERITING(Rule)
 
 #ifdef DEBUG
 void
 nsCSSFontFaceRule::List(FILE* out, int32_t aIndent) const
 {
   nsCString baseInd, descInd;
   for (int32_t indent = aIndent; --indent >= 0; ) {
     baseInd.AppendLiteral("  ");
@@ -1570,57 +1606,37 @@ nsCSSFontFaceRule::List(FILE* out, int32
 #endif
 
 /* virtual */ int32_t
 nsCSSFontFaceRule::GetType() const
 {
   return Rule::FONT_FACE_RULE;
 }
 
-NS_IMETHODIMP
-nsCSSFontFaceRule::GetType(uint16_t* aType)
+uint16_t
+nsCSSFontFaceRule::Type() const
 {
-  *aType = nsIDOMCSSRule::FONT_FACE_RULE;
-  return NS_OK;
+  return nsIDOMCSSRule::FONT_FACE_RULE;
 }
 
-NS_IMETHODIMP
-nsCSSFontFaceRule::GetCssText(nsAString& aCssText)
+void
+nsCSSFontFaceRule::GetCssTextImpl(nsAString& aCssText) const
 {
   nsAutoString propText;
-  mDecl.GetCssText(propText);
+  mDecl.GetCssTextImpl(propText);
 
   aCssText.AssignLiteral("@font-face {\n");
   aCssText.Append(propText);
   aCssText.Append('}');
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsCSSFontFaceRule::SetCssText(const nsAString& aCssText)
-{
-  return NS_ERROR_NOT_IMPLEMENTED; // bug 443978
-}
-
-NS_IMETHODIMP
-nsCSSFontFaceRule::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet)
+nsICSSDeclaration*
+nsCSSFontFaceRule::Style()
 {
-  return Rule::GetParentStyleSheet(aSheet);
-}
-
-NS_IMETHODIMP
-nsCSSFontFaceRule::GetParentRule(nsIDOMCSSRule** aParentRule)
-{
-  return Rule::GetParentRule(aParentRule);
-}
-
-css::Rule*
-nsCSSFontFaceRule::GetCSSRule()
-{
-  return Rule::GetCSSRule();
+  return &mDecl;
 }
 
 NS_IMETHODIMP
 nsCSSFontFaceRule::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
 {
   NS_IF_ADDREF(*aStyle = &mDecl);
   return NS_OK;
 }
@@ -1653,40 +1669,41 @@ nsCSSFontFaceRule::SizeOfIncludingThis(M
 {
   return aMallocSizeOf(this);
 
   // Measurement of the following members may be added later if DMD finds it is
   // worthwhile:
   // - mDecl
 }
 
+/* virtual */ JSObject*
+nsCSSFontFaceRule::WrapObject(JSContext* aCx,
+                              JS::Handle<JSObject*> aGivenProto)
+{
+  return CSSFontFaceRuleBinding::Wrap(aCx, this, aGivenProto);
+}
 
 // -----------------------------------
 // nsCSSFontFeatureValuesRule
 //
 
 /* virtual */ already_AddRefed<css::Rule>
 nsCSSFontFeatureValuesRule::Clone() const
 {
   RefPtr<css::Rule> clone = new nsCSSFontFeatureValuesRule(*this);
   return clone.forget();
 }
 
-NS_IMPL_ADDREF(nsCSSFontFeatureValuesRule)
-NS_IMPL_RELEASE(nsCSSFontFeatureValuesRule)
+NS_IMPL_ADDREF_INHERITED(nsCSSFontFeatureValuesRule, mozilla::css::Rule)
+NS_IMPL_RELEASE_INHERITED(nsCSSFontFeatureValuesRule, mozilla::css::Rule)
 
 // QueryInterface implementation for nsCSSFontFeatureValuesRule
 NS_INTERFACE_MAP_BEGIN(nsCSSFontFeatureValuesRule)
   NS_INTERFACE_MAP_ENTRY(nsIDOMCSSFontFeatureValuesRule)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozilla::css::Rule)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSFontFeatureValuesRule)
-NS_INTERFACE_MAP_END
-
-IMPL_STYLE_RULE_INHERIT(nsCSSFontFeatureValuesRule, Rule)
+NS_INTERFACE_MAP_END_INHERITING(mozilla::css::Rule)
 
 static void
 FeatureValuesToString(
   const nsTArray<gfxFontFeatureValueSet::FeatureValues>& aFeatureValues,
   nsAString& aOutStr)
 {
   uint32_t i, n;
 
@@ -1766,53 +1783,40 @@ nsCSSFontFeatureValuesRule::List(FILE* o
 #endif
 
 /* virtual */ int32_t
 nsCSSFontFeatureValuesRule::GetType() const
 {
   return Rule::FONT_FEATURE_VALUES_RULE;
 }
 
-NS_IMETHODIMP
-nsCSSFontFeatureValuesRule::GetType(uint16_t* aType)
+uint16_t
+nsCSSFontFeatureValuesRule::Type() const
 {
-  *aType = nsIDOMCSSRule::FONT_FEATURE_VALUES_RULE;
-  return NS_OK;
+  return nsIDOMCSSRule::FONT_FEATURE_VALUES_RULE;
 }
 
-NS_IMETHODIMP
-nsCSSFontFeatureValuesRule::GetCssText(nsAString& aCssText)
+void
+nsCSSFontFeatureValuesRule::GetCssTextImpl(nsAString& aCssText) const
 {
   FontFeatureValuesRuleToString(mFamilyList, mFeatureValues, aCssText);
-  return NS_OK;
 }
 
-NS_IMETHODIMP
-nsCSSFontFeatureValuesRule::SetCssText(const nsAString& aCssText)
-{
-  // FIXME: implement???
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsCSSFontFeatureValuesRule::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet)
+void
+nsCSSFontFeatureValuesRule::SetFontFamily(const nsAString& aFamily,
+                                          ErrorResult& aRv)
 {
-  return Rule::GetParentStyleSheet(aSheet);
+  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
 }
 
-NS_IMETHODIMP
-nsCSSFontFeatureValuesRule::GetParentRule(nsIDOMCSSRule** aParentRule)
+void
+nsCSSFontFeatureValuesRule::SetValueText(const nsAString& aFamily,
+                                         ErrorResult& aRv)
 {
-  return Rule::GetParentRule(aParentRule);
-}
-
-css::Rule*
-nsCSSFontFeatureValuesRule::GetCSSRule()
-{
-  return Rule::GetCSSRule();
+  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
 }
 
 NS_IMETHODIMP
 nsCSSFontFeatureValuesRule::GetFontFamily(nsAString& aFamilyListStr)
 {
   nsStyleUtil::AppendEscapedCSSFontFamilyList(mFamilyList, aFamilyListStr);
   return NS_OK;
 }
@@ -1893,16 +1897,23 @@ nsCSSFontFeatureValuesRule::AddValueList
 
 size_t
 nsCSSFontFeatureValuesRule::SizeOfIncludingThis(
   MallocSizeOf aMallocSizeOf) const
 {
   return aMallocSizeOf(this);
 }
 
+/* virtual */ JSObject*
+nsCSSFontFeatureValuesRule::WrapObject(JSContext* aCx,
+                                       JS::Handle<JSObject*> aGivenProto)
+{
+  return CSSFontFeatureValuesRuleBinding::Wrap(aCx, this, aGivenProto);
+}
+
 // -------------------------------------------
 // nsCSSKeyframeStyleDeclaration
 //
 
 nsCSSKeyframeStyleDeclaration::nsCSSKeyframeStyleDeclaration(nsCSSKeyframeRule *aRule)
   : mRule(aRule)
 {
 }
@@ -1989,40 +2000,37 @@ nsCSSKeyframeRule::~nsCSSKeyframeRule()
 
 /* virtual */ already_AddRefed<css::Rule>
 nsCSSKeyframeRule::Clone() const
 {
   RefPtr<css::Rule> clone = new nsCSSKeyframeRule(*this);
   return clone.forget();
 }
 
-NS_IMPL_CYCLE_COLLECTING_ADDREF(nsCSSKeyframeRule)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(nsCSSKeyframeRule)
+NS_IMPL_ADDREF_INHERITED(nsCSSKeyframeRule, mozilla::css::Rule)
+NS_IMPL_RELEASE_INHERITED(nsCSSKeyframeRule, mozilla::css::Rule)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsCSSKeyframeRule)
 
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsCSSKeyframeRule)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsCSSKeyframeRule,
+                                                mozilla::css::Rule)
   if (tmp->mDOMDeclaration) {
     tmp->mDOMDeclaration->DropReference();
     tmp->mDOMDeclaration = nullptr;
   }
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsCSSKeyframeRule)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsCSSKeyframeRule,
+                                                  mozilla::css::Rule)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMDeclaration)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 // QueryInterface implementation for nsCSSKeyframeRule
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsCSSKeyframeRule)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsCSSKeyframeRule)
   NS_INTERFACE_MAP_ENTRY(nsIDOMCSSKeyframeRule)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozilla::css::Rule)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSKeyframeRule)
-NS_INTERFACE_MAP_END
-
-IMPL_STYLE_RULE_INHERIT_GET_DOM_RULE_WEAK(nsCSSKeyframeRule, Rule)
+NS_INTERFACE_MAP_END_INHERITING(mozilla::css::Rule)
 
 #ifdef DEBUG
 void
 nsCSSKeyframeRule::List(FILE* out, int32_t aIndent) const
 {
   nsAutoCString str;
   for (int32_t index = aIndent; --index >= 0; ) {
     str.AppendLiteral("  ");
@@ -2040,58 +2048,31 @@ nsCSSKeyframeRule::List(FILE* out, int32
 #endif
 
 /* virtual */ int32_t
 nsCSSKeyframeRule::GetType() const
 {
   return Rule::KEYFRAME_RULE;
 }
 
-NS_IMETHODIMP
-nsCSSKeyframeRule::GetType(uint16_t* aType)
+uint16_t
+nsCSSKeyframeRule::Type() const
 {
-  *aType = nsIDOMCSSRule::KEYFRAME_RULE;
-  return NS_OK;
+  return nsIDOMCSSRule::KEYFRAME_RULE;
 }
 
-NS_IMETHODIMP
-nsCSSKeyframeRule::GetCssText(nsAString& aCssText)
+void
+nsCSSKeyframeRule::GetCssTextImpl(nsAString& aCssText) const
 {
   DoGetKeyText(aCssText);
   aCssText.AppendLiteral(" { ");
   nsAutoString tmp;
   mDeclaration->ToString(tmp);
   aCssText.Append(tmp);
   aCssText.AppendLiteral(" }");
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsCSSKeyframeRule::SetCssText(const nsAString& aCssText)
-{
-  // FIXME: implement???
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsCSSKeyframeRule::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet)
-{
-  return Rule::GetParentStyleSheet(aSheet);
-}
-
-NS_IMETHODIMP
-nsCSSKeyframeRule::GetParentRule(nsIDOMCSSRule** aParentRule)
-{
-  return Rule::GetParentRule(aParentRule);
-}
-
-css::Rule*
-nsCSSKeyframeRule::GetCSSRule()
-{
-  return Rule::GetCSSRule();
 }
 
 NS_IMETHODIMP
 nsCSSKeyframeRule::GetKeyText(nsAString& aKeyText)
 {
   DoGetKeyText(aKeyText);
   return NS_OK;
 }
@@ -2137,21 +2118,27 @@ nsCSSKeyframeRule::SetKeyText(const nsAS
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCSSKeyframeRule::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
 {
+  NS_ADDREF(*aStyle = Style());
+  return NS_OK;
+}
+
+nsICSSDeclaration*
+nsCSSKeyframeRule::Style()
+{
   if (!mDOMDeclaration) {
     mDOMDeclaration = new nsCSSKeyframeStyleDeclaration(this);
   }
-  NS_ADDREF(*aStyle = mDOMDeclaration);
-  return NS_OK;
+  return mDOMDeclaration;
 }
 
 void
 nsCSSKeyframeRule::ChangeDeclaration(css::Declaration* aDeclaration)
 {
   // Our caller already did a BeginUpdate/EndUpdate, but with
   // UPDATE_CONTENT, and we need UPDATE_STYLE to trigger work in
   // PresShell::EndUpdate.
@@ -2179,16 +2166,22 @@ nsCSSKeyframeRule::SizeOfIncludingThis(M
 
   // Measurement of the following members may be added later if DMD finds it is
   // worthwhile:
   // - mKeys
   // - mDeclaration
   // - mDOMDeclaration
 }
 
+/* virtual */ JSObject*
+nsCSSKeyframeRule::WrapObject(JSContext* aCx,
+                              JS::Handle<JSObject*> aGivenProto)
+{
+  return CSSKeyframeRuleBinding::Wrap(aCx, this, aGivenProto);
+}
 
 // -------------------------------------------
 // nsCSSKeyframesRule
 //
 
 nsCSSKeyframesRule::nsCSSKeyframesRule(const nsCSSKeyframesRule& aCopy)
   // copy everything except our reference count.  GroupRule's copy
   // constructor also doesn't copy the lazily-constructed
@@ -2209,20 +2202,17 @@ nsCSSKeyframesRule::Clone() const
   return clone.forget();
 }
 
 NS_IMPL_ADDREF_INHERITED(nsCSSKeyframesRule, css::GroupRule)
 NS_IMPL_RELEASE_INHERITED(nsCSSKeyframesRule, css::GroupRule)
 
 // QueryInterface implementation for nsCSSKeyframesRule
 NS_INTERFACE_MAP_BEGIN(nsCSSKeyframesRule)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule)
   NS_INTERFACE_MAP_ENTRY(nsIDOMCSSKeyframesRule)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozilla::css::Rule)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSKeyframesRule)
 NS_INTERFACE_MAP_END_INHERITING(GroupRule)
 
 #ifdef DEBUG
 void
 nsCSSKeyframesRule::List(FILE* out, int32_t aIndent) const
 {
   nsAutoCString indentStr;
   for (int32_t indent = aIndent; --indent >= 0; ) {
@@ -2239,62 +2229,35 @@ nsCSSKeyframesRule::List(FILE* out, int3
 #endif
 
 /* virtual */ int32_t
 nsCSSKeyframesRule::GetType() const
 {
   return Rule::KEYFRAMES_RULE;
 }
 
-NS_IMETHODIMP
-nsCSSKeyframesRule::GetType(uint16_t* aType)
+uint16_t
+nsCSSKeyframesRule::Type() const
 {
-  *aType = nsIDOMCSSRule::KEYFRAMES_RULE;
-  return NS_OK;
+  return nsIDOMCSSRule::KEYFRAMES_RULE;
 }
 
-NS_IMETHODIMP
-nsCSSKeyframesRule::GetCssText(nsAString& aCssText)
+void
+nsCSSKeyframesRule::GetCssTextImpl(nsAString& aCssText) const
 {
   aCssText.AssignLiteral("@keyframes ");
   aCssText.Append(mName);
   aCssText.AppendLiteral(" {\n");
   nsAutoString tmp;
   for (uint32_t i = 0, i_end = mRules.Count(); i != i_end; ++i) {
     static_cast<nsCSSKeyframeRule*>(mRules[i])->GetCssText(tmp);
     aCssText.Append(tmp);
     aCssText.Append('\n');
   }
   aCssText.Append('}');
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsCSSKeyframesRule::SetCssText(const nsAString& aCssText)
-{
-  // FIXME: implement???
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsCSSKeyframesRule::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet)
-{
-  return GroupRule::GetParentStyleSheet(aSheet);
-}
-
-NS_IMETHODIMP
-nsCSSKeyframesRule::GetParentRule(nsIDOMCSSRule** aParentRule)
-{
-  return GroupRule::GetParentRule(aParentRule);
-}
-
-css::Rule*
-nsCSSKeyframesRule::GetCSSRule()
-{
-  return GroupRule::GetCSSRule();
 }
 
 NS_IMETHODIMP
 nsCSSKeyframesRule::GetName(nsAString& aName)
 {
   aName = mName;
   return NS_OK;
 }
@@ -2400,23 +2363,28 @@ nsCSSKeyframesRule::DeleteRule(const nsA
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCSSKeyframesRule::FindRule(const nsAString& aKey,
                              nsIDOMCSSKeyframeRule** aResult)
 {
+  NS_IF_ADDREF(*aResult = FindRule(aKey));
+  return NS_OK;
+}
+
+nsCSSKeyframeRule*
+nsCSSKeyframesRule::FindRule(const nsAString& aKey)
+{
   uint32_t index = FindRuleIndexForKey(aKey);
   if (index == RULE_NOT_FOUND) {
-    *aResult = nullptr;
-  } else {
-    NS_ADDREF(*aResult = static_cast<nsCSSKeyframeRule*>(mRules[index]));
+    return nullptr;
   }
-  return NS_OK;
+  return static_cast<nsCSSKeyframeRule*>(mRules[index]);
 }
 
 // GroupRule interface
 /* virtual */ bool
 nsCSSKeyframesRule::UseForPresentation(nsPresContext* aPresContext,
                                        nsMediaQueryResultCacheKey& aKey)
 {
   MOZ_ASSERT(false, "should not be called");
@@ -2431,16 +2399,23 @@ nsCSSKeyframesRule::SizeOfIncludingThis(
 
   // Measurement of the following members may be added later if DMD finds it is
   // worthwhile:
   // - mName
 
   return n;
 }
 
+/* virtual */ JSObject*
+nsCSSKeyframesRule::WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aGivenProto)
+{
+  return CSSKeyframesRuleBinding::Wrap(aCx, this, aGivenProto);
+}
+
 // -------------------------------------------
 // nsCSSPageStyleDeclaration
 //
 
 nsCSSPageStyleDeclaration::nsCSSPageStyleDeclaration(nsCSSPageRule* aRule)
   : mRule(aRule)
 {
 }
@@ -2526,40 +2501,37 @@ nsCSSPageRule::~nsCSSPageRule()
 
 /* virtual */ already_AddRefed<css::Rule>
 nsCSSPageRule::Clone() const
 {
   RefPtr<css::Rule> clone = new nsCSSPageRule(*this);
   return clone.forget();
 }
 
-NS_IMPL_CYCLE_COLLECTING_ADDREF(nsCSSPageRule)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(nsCSSPageRule)
+NS_IMPL_ADDREF_INHERITED(nsCSSPageRule, mozilla::css::Rule)
+NS_IMPL_RELEASE_INHERITED(nsCSSPageRule, mozilla::css::Rule)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsCSSPageRule)
 
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsCSSPageRule)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsCSSPageRule,
+                                                mozilla::css::Rule)
   if (tmp->mDOMDeclaration) {
     tmp->mDOMDeclaration->DropReference();
     tmp->mDOMDeclaration = nullptr;
   }
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsCSSPageRule)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsCSSPageRule,
+                                                  mozilla::css::Rule)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMDeclaration)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 // QueryInterface implementation for nsCSSPageRule
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsCSSPageRule)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsCSSPageRule)
   NS_INTERFACE_MAP_ENTRY(nsIDOMCSSPageRule)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozilla::css::Rule)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSPageRule)
-NS_INTERFACE_MAP_END
-
-IMPL_STYLE_RULE_INHERIT_GET_DOM_RULE_WEAK(nsCSSPageRule, Rule)
+NS_INTERFACE_MAP_END_INHERITING(mozilla::css::Rule)
 
 #ifdef DEBUG
 void
 nsCSSPageRule::List(FILE* out, int32_t aIndent) const
 {
   nsAutoCString str;
   for (int32_t indent = aIndent; --indent >= 0; ) {
     str.AppendLiteral("  ");
@@ -2575,67 +2547,46 @@ nsCSSPageRule::List(FILE* out, int32_t a
 #endif
 
 /* virtual */ int32_t
 nsCSSPageRule::GetType() const
 {
   return Rule::PAGE_RULE;
 }
 
-NS_IMETHODIMP
-nsCSSPageRule::GetType(uint16_t* aType)
+uint16_t
+nsCSSPageRule::Type() const
 {
-  *aType = nsIDOMCSSRule::PAGE_RULE;
-  return NS_OK;
+  return nsIDOMCSSRule::PAGE_RULE;
 }
 
-NS_IMETHODIMP
-nsCSSPageRule::GetCssText(nsAString& aCssText)
+void
+nsCSSPageRule::GetCssTextImpl(nsAString& aCssText) const
 {
   aCssText.AppendLiteral("@page { ");
   nsAutoString tmp;
   mDeclaration->ToString(tmp);
   aCssText.Append(tmp);
   aCssText.AppendLiteral(" }");
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsCSSPageRule::SetCssText(const nsAString& aCssText)
-{
-  // FIXME: implement???
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsCSSPageRule::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet)
-{
-  return Rule::GetParentStyleSheet(aSheet);
-}
-
-NS_IMETHODIMP
-nsCSSPageRule::GetParentRule(nsIDOMCSSRule** aParentRule)
-{
-  return Rule::GetParentRule(aParentRule);
-}
-
-css::Rule*
-nsCSSPageRule::GetCSSRule()
-{
-  return Rule::GetCSSRule();
 }
 
 NS_IMETHODIMP
 nsCSSPageRule::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
 {
+  NS_ADDREF(*aStyle = Style());
+  return NS_OK;
+}
+
+nsICSSDeclaration*
+nsCSSPageRule::Style()
+{
   if (!mDOMDeclaration) {
     mDOMDeclaration = new nsCSSPageStyleDeclaration(this);
   }
-  NS_ADDREF(*aStyle = mDOMDeclaration);
-  return NS_OK;
+  return mDOMDeclaration;
 }
 
 void
 nsCSSPageRule::ChangeDeclaration(css::Declaration* aDeclaration)
 {
   if (aDeclaration != mDeclaration) {
     mDeclaration->SetOwningRule(nullptr);
     mDeclaration = aDeclaration;
@@ -2648,33 +2599,40 @@ nsCSSPageRule::ChangeDeclaration(css::De
 }
 
 /* virtual */ size_t
 nsCSSPageRule::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
 {
   return aMallocSizeOf(this);
 }
 
+/* virtual */ JSObject*
+nsCSSPageRule::WrapObject(JSContext* aCx,
+                          JS::Handle<JSObject*> aGivenProto)
+{
+  return CSSPageRuleBinding::Wrap(aCx, this, aGivenProto);
+}
+
 namespace mozilla {
 
 CSSSupportsRule::CSSSupportsRule(bool aConditionMet,
                                  const nsString& aCondition,
                                  uint32_t aLineNumber, uint32_t aColumnNumber)
-  : css::GroupRule(aLineNumber, aColumnNumber)
+  : css::ConditionRule(aLineNumber, aColumnNumber)
   , mUseGroup(aConditionMet)
   , mCondition(aCondition)
 {
 }
 
 CSSSupportsRule::~CSSSupportsRule()
 {
 }
 
 CSSSupportsRule::CSSSupportsRule(const CSSSupportsRule& aCopy)
-  : css::GroupRule(aCopy),
+  : css::ConditionRule(aCopy),
     mUseGroup(aCopy.mUseGroup),
     mCondition(aCopy.mCondition)
 {
 }
 
 #ifdef DEBUG
 /* virtual */ void
 CSSSupportsRule::List(FILE* out, int32_t aIndent) const
@@ -2708,68 +2666,38 @@ CSSSupportsRule::Clone() const
 
 /* virtual */ bool
 CSSSupportsRule::UseForPresentation(nsPresContext* aPresContext,
                                    nsMediaQueryResultCacheKey& aKey)
 {
   return mUseGroup;
 }
 
-NS_IMPL_ADDREF_INHERITED(CSSSupportsRule, css::GroupRule)
-NS_IMPL_RELEASE_INHERITED(CSSSupportsRule, css::GroupRule)
+NS_IMPL_ADDREF_INHERITED(CSSSupportsRule, css::ConditionRule)
+NS_IMPL_RELEASE_INHERITED(CSSSupportsRule, css::ConditionRule)
 
 // QueryInterface implementation for CSSSupportsRule
 NS_INTERFACE_MAP_BEGIN(CSSSupportsRule)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule)
   NS_INTERFACE_MAP_ENTRY(nsIDOMCSSGroupingRule)
   NS_INTERFACE_MAP_ENTRY(nsIDOMCSSConditionRule)
   NS_INTERFACE_MAP_ENTRY(nsIDOMCSSSupportsRule)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozilla::css::Rule)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSSupportsRule)
-NS_INTERFACE_MAP_END_INHERITING(GroupRule)
-
-// nsIDOMCSSRule methods
-NS_IMETHODIMP
-CSSSupportsRule::GetType(uint16_t* aType)
+NS_INTERFACE_MAP_END_INHERITING(ConditionRule)
+
+uint16_t
+CSSSupportsRule::Type() const
 {
-  *aType = nsIDOMCSSRule::SUPPORTS_RULE;
-  return NS_OK;
+  return nsIDOMCSSRule::SUPPORTS_RULE;
 }
 
-NS_IMETHODIMP
-CSSSupportsRule::GetCssText(nsAString& aCssText)
+void
+CSSSupportsRule::GetCssTextImpl(nsAString& aCssText) const
 {
   aCssText.AssignLiteral("@supports ");
   aCssText.Append(mCondition);
   css::GroupRule::AppendRulesToCssText(aCssText);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-CSSSupportsRule::SetCssText(const nsAString& aCssText)
-{
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-CSSSupportsRule::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet)
-{
-  return css::GroupRule::GetParentStyleSheet(aSheet);
-}
-
-NS_IMETHODIMP
-CSSSupportsRule::GetParentRule(nsIDOMCSSRule** aParentRule)
-{
-  return css::GroupRule::GetParentRule(aParentRule);
-}
-
-css::Rule*
-CSSSupportsRule::GetCSSRule()
-{
-  return css::GroupRule::GetCSSRule();
 }
 
 // nsIDOMCSSGroupingRule methods
 NS_IMETHODIMP
 CSSSupportsRule::GetCssRules(nsIDOMCSSRuleList* *aRuleList)
 {
   return css::GroupRule::GetCssRules(aRuleList);
 }
@@ -2795,25 +2723,39 @@ CSSSupportsRule::GetConditionText(nsAStr
 }
 
 NS_IMETHODIMP
 CSSSupportsRule::SetConditionText(const nsAString& aConditionText)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
+void
+CSSSupportsRule::SetConditionText(const nsAString& aConditionText,
+                                  ErrorResult& aRv)
+{
+  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
+}
+
 /* virtual */ size_t
 CSSSupportsRule::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
 {
   size_t n = aMallocSizeOf(this);
   n += css::GroupRule::SizeOfExcludingThis(aMallocSizeOf);
   n += mCondition.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
   return n;
 }
 
+/* virtual */ JSObject*
+CSSSupportsRule::WrapObject(JSContext* aCx,
+                            JS::Handle<JSObject*> aGivenProto)
+{
+  return CSSSupportsRuleBinding::Wrap(aCx, this, aGivenProto);
+}
+
 } // namespace mozilla
 
 // -------------------------------------------
 // nsCSSCounterStyleRule
 //
 
 nsCSSCounterStyleRule::nsCSSCounterStyleRule(const nsCSSCounterStyleRule& aCopy)
   : Rule(aCopy)
@@ -2838,28 +2780,23 @@ nsCSSCounterStyleRule::Clone() const
 
 nsCSSCounterStyleRule::Getter const
 nsCSSCounterStyleRule::kGetters[] = {
 #define CSS_COUNTER_DESC(name_, method_) &nsCSSCounterStyleRule::Get##method_,
 #include "nsCSSCounterDescList.h"
 #undef CSS_COUNTER_DESC
 };
 
-NS_IMPL_ADDREF(nsCSSCounterStyleRule)
-NS_IMPL_RELEASE(nsCSSCounterStyleRule)
+NS_IMPL_ADDREF_INHERITED(nsCSSCounterStyleRule, mozilla::css::Rule)
+NS_IMPL_RELEASE_INHERITED(nsCSSCounterStyleRule, mozilla::css::Rule)
 
 // QueryInterface implementation for nsCSSCounterStyleRule
 NS_INTERFACE_MAP_BEGIN(nsCSSCounterStyleRule)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule)
   NS_INTERFACE_MAP_ENTRY(nsIDOMCSSCounterStyleRule)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozilla::css::Rule)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSCounterStyleRule)
-NS_INTERFACE_MAP_END
-
-IMPL_STYLE_RULE_INHERIT(nsCSSCounterStyleRule, css::Rule)
+NS_INTERFACE_MAP_END_INHERITING(mozilla::css::Rule)
 
 #ifdef DEBUG
 void
 nsCSSCounterStyleRule::List(FILE* out, int32_t aIndent) const
 {
   nsCString baseInd, descInd;
   for (int32_t indent = aIndent; --indent >= 0; ) {
     baseInd.AppendLiteral("  ");
@@ -2876,70 +2813,45 @@ nsCSSCounterStyleRule::List(FILE* out, i
 #endif
 
 /* virtual */ int32_t
 nsCSSCounterStyleRule::GetType() const
 {
   return Rule::COUNTER_STYLE_RULE;
 }
 
-// nsIDOMCSSRule methods
-NS_IMETHODIMP
-nsCSSCounterStyleRule::GetType(uint16_t* aType)
+uint16_t
+nsCSSCounterStyleRule::Type() const
 {
-  *aType = nsIDOMCSSRule::COUNTER_STYLE_RULE;
-  return NS_OK;
+  return nsIDOMCSSRule::COUNTER_STYLE_RULE;
 }
 
-NS_IMETHODIMP
-nsCSSCounterStyleRule::GetCssText(nsAString& aCssText)
+void
+nsCSSCounterStyleRule::GetCssTextImpl(nsAString& aCssText) const
 {
   aCssText.AssignLiteral(u"@counter-style ");
   nsStyleUtil::AppendEscapedCSSIdent(mName, aCssText);
   aCssText.AppendLiteral(u" {\n");
   for (nsCSSCounterDesc id = nsCSSCounterDesc(0);
        id < eCSSCounterDesc_COUNT;
        id = nsCSSCounterDesc(id + 1)) {
     if (mValues[id].GetUnit() != eCSSUnit_Null) {
       nsAutoString tmp;
-      (this->*kGetters[id])(tmp);
+      // This is annoying.  We want to be a const method, but kGetters stores
+      // XPCOM method pointers, which aren't const methods.  The thing is,
+      // none of those mutate "this".  So it's OK to cast away const here.
+      (const_cast<nsCSSCounterStyleRule*>(this)->*kGetters[id])(tmp);
       aCssText.AppendLiteral(u"  ");
       AppendASCIItoUTF16(nsCSSProps::GetStringValue(id), aCssText);
       aCssText.AppendLiteral(u": ");
       aCssText.Append(tmp);
       aCssText.AppendLiteral(u";\n");
     }
   }
   aCssText.AppendLiteral(u"}");
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsCSSCounterStyleRule::SetCssText(const nsAString& aCssText)
-{
-  // FIXME: implement???
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsCSSCounterStyleRule::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet)
-{
-  return Rule::GetParentStyleSheet(aSheet);
-}
-
-NS_IMETHODIMP
-nsCSSCounterStyleRule::GetParentRule(nsIDOMCSSRule** aParentRule)
-{
-  return Rule::GetParentRule(aParentRule);
-}
-
-css::Rule*
-nsCSSCounterStyleRule::GetCSSRule()
-{
-  return Rule::GetCSSRule();
 }
 
 // nsIDOMCSSCounterStyleRule methods
 NS_IMETHODIMP
 nsCSSCounterStyleRule::GetName(nsAString& aName)
 {
   aName.Truncate();
   nsStyleUtil::AppendEscapedCSSIdent(mName, aName);
@@ -3264,8 +3176,15 @@ CSS_COUNTER_DESC_SETTER(Fallback)
 CSS_COUNTER_DESC_SETTER(SpeakAs)
 #undef CSS_COUNTER_DESC_SETTER
 
 /* virtual */ size_t
 nsCSSCounterStyleRule::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
 {
   return aMallocSizeOf(this);
 }
+
+/* virtual */ JSObject*
+nsCSSCounterStyleRule::WrapObject(JSContext* aCx,
+                                  JS::Handle<JSObject*> aGivenProto)
+{
+  return CSSCounterStyleRuleBinding::Wrap(aCx, this, aGivenProto);
+}
--- a/layout/style/nsCSSRules.h
+++ b/layout/style/nsCSSRules.h
@@ -38,106 +38,98 @@
 class nsMediaList;
 
 namespace mozilla {
 
 class ErrorResult;
 
 namespace css {
 
-class MediaRule final : public GroupRule,
+class MediaRule final : public ConditionRule,
                         public nsIDOMCSSMediaRule
 {
 public:
   MediaRule(uint32_t aLineNumber, uint32_t aColumnNumber);
 private:
   MediaRule(const MediaRule& aCopy);
   ~MediaRule();
 public:
 
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaRule, ConditionRule)
   NS_DECL_ISUPPORTS_INHERITED
 
   // Rule methods
 #ifdef DEBUG
   virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
 #endif
   virtual void SetStyleSheet(mozilla::StyleSheet* aSheet) override; //override GroupRule
   mozilla::CSSStyleSheet* GetStyleSheet() const
   {
     mozilla::StyleSheet* sheet = GroupRule::GetStyleSheet();
     return sheet ? sheet->AsGecko() : nullptr;
   }
   virtual int32_t GetType() const override;
+  using Rule::GetType;
   virtual already_AddRefed<Rule> Clone() const override;
-  virtual nsIDOMCSSRule* GetDOMRule() override
-  {
-    return this;
-  }
-  virtual nsIDOMCSSRule* GetExistingDOMRule() override
-  {
-    return this;
-  }
-
-  // nsIDOMCSSRule interface
-  NS_DECL_NSIDOMCSSRULE
 
   // nsIDOMCSSGroupingRule interface
   NS_DECL_NSIDOMCSSGROUPINGRULE
 
   // nsIDOMCSSConditionRule interface
   NS_DECL_NSIDOMCSSCONDITIONRULE
 
   // nsIDOMCSSMediaRule interface
   NS_DECL_NSIDOMCSSMEDIARULE
 
   // rest of GroupRule
   virtual bool UseForPresentation(nsPresContext* aPresContext,
                                     nsMediaQueryResultCacheKey& aKey) override;
 
   // @media rule methods
   nsresult SetMedia(nsMediaList* aMedia);
+
+  // WebIDL interface
+  uint16_t Type() const override;
+  void GetCssTextImpl(nsAString& aCssText) const override;
+  // Our XPCOM GetConditionText is OK
+  virtual void SetConditionText(const nsAString& aConditionText,
+                                ErrorResult& aRv) override;
+  nsMediaList* Media() const;
   
   virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
     const override MOZ_MUST_OVERRIDE;
 
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aGivenProto) override;
+
 protected:
-  void AppendConditionText(nsAString& aOutput);
+  void AppendConditionText(nsAString& aOutput) const;
 
   RefPtr<nsMediaList> mMedia;
 };
 
-class DocumentRule final : public GroupRule,
+class DocumentRule final : public ConditionRule,
                            public nsIDOMCSSMozDocumentRule
 {
 public:
   DocumentRule(uint32_t aLineNumber, uint32_t aColumnNumber);
 private:
   DocumentRule(const DocumentRule& aCopy);
   ~DocumentRule();
 public:
 
   NS_DECL_ISUPPORTS_INHERITED
 
   // Rule methods
 #ifdef DEBUG
   virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
 #endif
   virtual int32_t GetType() const override;
+  using Rule::GetType;
   virtual already_AddRefed<Rule> Clone() const override;
-  virtual nsIDOMCSSRule* GetDOMRule() override
-  {
-    return this;
-  }
-  virtual nsIDOMCSSRule* GetExistingDOMRule() override
-  {
-    return this;
-  }
-
-  // nsIDOMCSSRule interface
-  NS_DECL_NSIDOMCSSRULE
 
   // nsIDOMCSSGroupingRule interface
   NS_DECL_NSIDOMCSSGROUPINGRULE
 
   // nsIDOMCSSConditionRule interface
   NS_DECL_NSIDOMCSSCONDITIONRULE
 
   // nsIDOMCSSMozDocumentRule interface
@@ -168,21 +160,31 @@ public:
       , next(aOther.next ? new URL(*aOther.next) : nullptr)
     {
     }
     ~URL();
   };
 
   void SetURLs(URL *aURLs) { mURLs = aURLs; }
 
+  // WebIDL interface
+  uint16_t Type() const override;
+  void GetCssTextImpl(nsAString& aCssText) const override;
+  // Our XPCOM GetConditionText is OK
+  virtual void SetConditionText(const nsAString& aConditionText,
+                                ErrorResult& aRv) override;
+
   virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
     const override MOZ_MUST_OVERRIDE;
 
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aGivenProto) override;
+
 protected:
-  void AppendConditionText(nsAString& aOutput);
+  void AppendConditionText(nsAString& aOutput) const;
 
   nsAutoPtr<URL> mURLs; // linked list of |struct URL| above.
 };
 
 } // namespace css
 
 struct CSSFontFaceDescriptors
 {
@@ -225,57 +227,68 @@ protected:
 
   friend class nsCSSFontFaceRule;
 
   inline nsCSSFontFaceRule* ContainingRule();
   inline const nsCSSFontFaceRule* ContainingRule() const;
 
   mozilla::CSSFontFaceDescriptors mDescriptors;
 
+  // The actual implementation of GetCssText, so we can make it const.
+  void GetCssTextImpl(nsAString& aCssText) const;
+
 private:
   // NOT TO BE IMPLEMENTED
   // This object cannot be allocated on its own, only as part of
   // nsCSSFontFaceRule.
   void* operator new(size_t size) CPP_THROW_NEW;
 };
 
 class nsCSSFontFaceRule final : public mozilla::css::Rule,
                                 public nsIDOMCSSFontFaceRule
 {
 public:
   nsCSSFontFaceRule(uint32_t aLineNumber, uint32_t aColumnNumber)
-    : mozilla::css::Rule(aLineNumber, aColumnNumber) {}
+    : mozilla::css::Rule(aLineNumber, aColumnNumber)
+  {
+  }
 
   nsCSSFontFaceRule(const nsCSSFontFaceRule& aCopy)
     // copy everything except our reference count
-    : mozilla::css::Rule(aCopy), mDecl(aCopy.mDecl) {}
+    : mozilla::css::Rule(aCopy), mDecl(aCopy.mDecl)
+  {
+  }
 
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsCSSFontFaceRule,
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(nsCSSFontFaceRule,
                                                          mozilla::css::Rule)
 
-  // Rule methods
-  DECL_STYLE_RULE_INHERIT
 #ifdef DEBUG
   virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
 #endif
   virtual int32_t GetType() const override;
+  using Rule::GetType;
   virtual already_AddRefed<mozilla::css::Rule> Clone() const override;
 
-  // nsIDOMCSSRule interface
-  NS_DECL_NSIDOMCSSRULE
-
   // nsIDOMCSSFontFaceRule interface
   NS_DECL_NSIDOMCSSFONTFACERULE
 
   void SetDesc(nsCSSFontDesc aDescID, nsCSSValue const & aValue);
   void GetDesc(nsCSSFontDesc aDescID, nsCSSValue & aValue);
 
+  // WebIDL interface
+  uint16_t Type() const override;
+  void GetCssTextImpl(nsAString& aCssText) const override;
+  nsICSSDeclaration* Style();
+
   virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
 
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aGivenProto) override;
+
   void GetDescriptors(mozilla::CSSFontFaceDescriptors& aDescriptors) const
     { aDescriptors = mDecl.mDescriptors; }
 
 protected:
   ~nsCSSFontFaceRule() {}
 
   friend class nsCSSFontFaceStyleDecl;
   nsCSSFontFaceStyleDecl mDecl;
@@ -302,53 +315,64 @@ nsCSSFontFaceStyleDecl::ContainingRule()
     (reinterpret_cast<const char*>(this) - offsetof(nsCSSFontFaceRule, mDecl));
 }
 
 class nsCSSFontFeatureValuesRule final : public mozilla::css::Rule,
                                          public nsIDOMCSSFontFeatureValuesRule
 {
 public:
   nsCSSFontFeatureValuesRule(uint32_t aLineNumber, uint32_t aColumnNumber)
-    : mozilla::css::Rule(aLineNumber, aColumnNumber) {}
+    : mozilla::css::Rule(aLineNumber, aColumnNumber)
+  {
+  }
 
   nsCSSFontFeatureValuesRule(const nsCSSFontFeatureValuesRule& aCopy)
     // copy everything except our reference count
     : mozilla::css::Rule(aCopy),
       mFamilyList(aCopy.mFamilyList),
-      mFeatureValues(aCopy.mFeatureValues) {}
+      mFeatureValues(aCopy.mFeatureValues)
+  {
+  }
 
-  NS_DECL_ISUPPORTS
+  NS_DECL_ISUPPORTS_INHERITED
 
-  // Rule methods
-  DECL_STYLE_RULE_INHERIT
 #ifdef DEBUG
   virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
 #endif
   virtual int32_t GetType() const override;
+  using Rule::GetType;
   virtual already_AddRefed<mozilla::css::Rule> Clone() const override;
 
-  // nsIDOMCSSRule interface
-  NS_DECL_NSIDOMCSSRULE
-
   // nsIDOMCSSFontFaceRule interface
   NS_DECL_NSIDOMCSSFONTFEATUREVALUESRULE
 
+  // WebIDL interface
+  uint16_t Type() const override;
+  void GetCssTextImpl(nsAString& aCssText) const override;
+  // The XPCOM GetFontFamily is fine
+  void SetFontFamily(const nsAString& aFamily, mozilla::ErrorResult& aRv);
+  // The XPCOM GetValueText is fine
+  void SetValueText(const nsAString& aFamily, mozilla::ErrorResult& aRv);
+
   const mozilla::FontFamilyList& GetFamilyList() { return mFamilyList; }
   void SetFamilyList(const mozilla::FontFamilyList& aFamilyList);
 
   void AddValueList(int32_t aVariantAlternate,
                     nsTArray<gfxFontFeatureValueSet::ValueList>& aValueList);
 
   const nsTArray<gfxFontFeatureValueSet::FeatureValues>& GetFeatureValues()
   {
     return mFeatureValues;
   }
 
   virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
 
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aGivenProto) override;
+
 protected:
   ~nsCSSFontFeatureValuesRule() {}
 
   mozilla::FontFamilyList mFamilyList;
   nsTArray<gfxFontFeatureValueSet::FeatureValues> mFeatureValues;
 };
 
 class nsCSSKeyframeRule;
@@ -392,40 +416,46 @@ public:
     , mDeclaration(mozilla::Move(aDeclaration))
   {
     mDeclaration->SetOwningRule(this);
   }
 private:
   nsCSSKeyframeRule(const nsCSSKeyframeRule& aCopy);
   ~nsCSSKeyframeRule();
 public:
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsCSSKeyframeRule, mozilla::css::Rule)
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsCSSKeyframeRule, mozilla::css::Rule)
 
-  // Rule methods
-  DECL_STYLE_RULE_INHERIT
 #ifdef DEBUG
   virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
 #endif
   virtual int32_t GetType() const override;
+  using Rule::GetType;
   virtual already_AddRefed<mozilla::css::Rule> Clone() const override;
 
-  // nsIDOMCSSRule interface
-  NS_DECL_NSIDOMCSSRULE
-
   // nsIDOMCSSKeyframeRule interface
   NS_DECL_NSIDOMCSSKEYFRAMERULE
 
+  // WebIDL interface
+  uint16_t Type() const override;
+  void GetCssTextImpl(nsAString& aCssText) const override;
+  // The XPCOM GetKeyText is fine.
+  // The XPCOM SetKeyText is fine.
+  nsICSSDeclaration* Style();
+
   const nsTArray<float>& GetKeys() const     { return mKeys; }
   mozilla::css::Declaration* Declaration()   { return mDeclaration; }
 
   void ChangeDeclaration(mozilla::css::Declaration* aDeclaration);
 
   virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
 
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aGivenProto) override;
+
   void DoGetKeyText(nsAString &aKeyText) const;
 
 private:
   nsTArray<float>                            mKeys;
   RefPtr<mozilla::css::Declaration>          mDeclaration;
   // lazily created when needed:
   RefPtr<nsCSSKeyframeStyleDeclaration>    mDOMDeclaration;
 };
@@ -446,40 +476,43 @@ private:
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
   // Rule methods
 #ifdef DEBUG
   virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
 #endif
   virtual int32_t GetType() const override;
+  using Rule::GetType;
   virtual already_AddRefed<mozilla::css::Rule> Clone() const override;
-  virtual nsIDOMCSSRule* GetDOMRule() override
-  {
-    return this;
-  }
-  virtual nsIDOMCSSRule* GetExistingDOMRule() override
-  {
-    return this;
-  }
-
-  // nsIDOMCSSRule interface
-  NS_DECL_NSIDOMCSSRULE
 
   // nsIDOMCSSKeyframesRule interface
   NS_DECL_NSIDOMCSSKEYFRAMESRULE
 
+  // WebIDL interface
+  uint16_t Type() const override;
+  void GetCssTextImpl(nsAString& aCssText) const override;
+  // The XPCOM GetName is OK
+  // The XPCOM SetName is OK
+  using mozilla::css::GroupRule::CssRules;
+  // The XPCOM appendRule is OK, since it never throws
+  // The XPCOM deleteRule is OK, since it never throws
+  nsCSSKeyframeRule* FindRule(const nsAString& aKey);
+
   // rest of GroupRule
   virtual bool UseForPresentation(nsPresContext* aPresContext,
                                     nsMediaQueryResultCacheKey& aKey) override;
 
   const nsString& GetName() { return mName; }
 
   virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
 
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aGivenProto) override;
+
 private:
   uint32_t FindRuleIndexForKey(const nsAString& aKey);
 
   nsString                                   mName;
 };
 
 class nsCSSPageRule;
 
@@ -519,87 +552,92 @@ public:
     , mDeclaration(aDeclaration)
   {
     mDeclaration->SetOwningRule(this);
   }
 private:
   nsCSSPageRule(const nsCSSPageRule& aCopy);
   ~nsCSSPageRule();
 public:
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsCSSPageRule, nsIDOMCSSPageRule)
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsCSSPageRule, mozilla::css::Rule)
 
-  // Rule methods
-  DECL_STYLE_RULE_INHERIT
 #ifdef DEBUG
   virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
 #endif
   virtual int32_t GetType() const override;
+  using Rule::GetType;
   virtual already_AddRefed<mozilla::css::Rule> Clone() const override;
 
-  // nsIDOMCSSRule interface
-  NS_DECL_NSIDOMCSSRULE
-
   // nsIDOMCSSPageRule interface
   NS_DECL_NSIDOMCSSPAGERULE
 
+  // WebIDL interface
+  uint16_t Type() const override;
+  void GetCssTextImpl(nsAString& aCssText) const override;
+  nsICSSDeclaration* Style();
+
   mozilla::css::Declaration* Declaration()   { return mDeclaration; }
 
   void ChangeDeclaration(mozilla::css::Declaration* aDeclaration);
 
   virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
+
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aGivenProto) override;
+
 private:
   RefPtr<mozilla::css::Declaration>     mDeclaration;
   // lazily created when needed:
   RefPtr<nsCSSPageStyleDeclaration>     mDOMDeclaration;
 };
 
 namespace mozilla {
 
-class CSSSupportsRule : public css::GroupRule,
-                        public nsIDOMCSSSupportsRule
+class CSSSupportsRule final : public css::ConditionRule,
+                              public nsIDOMCSSSupportsRule
 {
 public:
   CSSSupportsRule(bool aConditionMet, const nsString& aCondition,
                   uint32_t aLineNumber, uint32_t aColumnNumber);
   CSSSupportsRule(const CSSSupportsRule& aCopy);
 
   // Rule methods
 #ifdef DEBUG
   virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
 #endif
   virtual int32_t GetType() const override;
+  using Rule::GetType;
   virtual already_AddRefed<mozilla::css::Rule> Clone() const override;
   virtual bool UseForPresentation(nsPresContext* aPresContext,
                                   nsMediaQueryResultCacheKey& aKey) override;
-  virtual nsIDOMCSSRule* GetDOMRule() override
-  {
-    return this;
-  }
-  virtual nsIDOMCSSRule* GetExistingDOMRule() override
-  {
-    return this;
-  }
 
   NS_DECL_ISUPPORTS_INHERITED
 
-  // nsIDOMCSSRule interface
-  NS_DECL_NSIDOMCSSRULE
-
   // nsIDOMCSSGroupingRule interface
   NS_DECL_NSIDOMCSSGROUPINGRULE
 
   // nsIDOMCSSConditionRule interface
   NS_DECL_NSIDOMCSSCONDITIONRULE
 
   // nsIDOMCSSSupportsRule interface
   NS_DECL_NSIDOMCSSSUPPORTSRULE
 
+  // WebIDL interface
+  uint16_t Type() const override;
+  void GetCssTextImpl(nsAString& aCssText) const override;
+  // Our XPCOM GetConditionText is OK
+  virtual void SetConditionText(const nsAString& aConditionText,
+                                ErrorResult& aRv) override;
+
   virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
 
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aGivenProto) override;
+
 protected:
   virtual ~CSSSupportsRule();
 
   bool mUseGroup;
   nsString mCondition;
 };
 
 } // namespace mozilla
@@ -616,32 +654,54 @@ public:
   {
   }
 
 private:
   nsCSSCounterStyleRule(const nsCSSCounterStyleRule& aCopy);
   ~nsCSSCounterStyleRule();
 
 public:
-  NS_DECL_ISUPPORTS
+  NS_DECL_ISUPPORTS_INHERITED
 
-  // Rule methods
-  DECL_STYLE_RULE_INHERIT
 #ifdef DEBUG
   virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
 #endif
   virtual int32_t GetType() const override;
+  using Rule::GetType;
   virtual already_AddRefed<mozilla::css::Rule> Clone() const override;
 
-  // nsIDOMCSSRule interface
-  NS_DECL_NSIDOMCSSRULE
-
   // nsIDOMCSSCounterStyleRule
   NS_DECL_NSIDOMCSSCOUNTERSTYLERULE
 
+  // WebIDL interface
+  uint16_t Type() const override;
+  void GetCssTextImpl(nsAString& aCssText) const override;
+  // The XPCOM GetName is OK
+  // The XPCOM SetName is OK
+  // The XPCOM GetSystem is OK
+  // The XPCOM SetSystem is OK
+  // The XPCOM GetSymbols is OK
+  // The XPCOM SetSymbols is OK
+  // The XPCOM GetAdditiveSymbols is OK
+  // The XPCOM SetAdditiveSymbols is OK
+  // The XPCOM GetNegative is OK
+  // The XPCOM SetNegative is OK
+  // The XPCOM GetPrefix is OK
+  // The XPCOM SetPrefix is OK
+  // The XPCOM GetSuffix is OK
+  // The XPCOM SetSuffix is OK
+  // The XPCOM GetRange is OK
+  // The XPCOM SetRange is OK
+  // The XPCOM GetPad is OK
+  // The XPCOM SetPad is OK
+  // The XPCOM GetSpeakAs is OK
+  // The XPCOM SetSpeakAs is OK
+  // The XPCOM GetFallback is OK
+  // The XPCOM SetFallback is OK
+
   // This function is only used to check whether a non-empty value, which has
   // been accepted by parser, is valid for the given system and descriptor.
   static bool CheckDescValue(int32_t aSystem,
                              nsCSSCounterDesc aDescID,
                              const nsCSSValue& aValue);
 
   const nsString& GetName() const { return mName; }
 
@@ -656,16 +716,19 @@ public:
                "descriptor ID out of range");
     return mValues[aDescID];
   }
 
   void SetDesc(nsCSSCounterDesc aDescID, const nsCSSValue& aValue);
 
   virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
 
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aGivenProto) override;
+
 private:
   typedef NS_STDCALL_FUNCPROTO(nsresult, Getter, nsCSSCounterStyleRule,
                                GetSymbols, (nsAString&));
   static const Getter kGetters[];
 
   nsresult GetDescriptor(nsCSSCounterDesc aDescID, nsAString& aValue);
   nsresult SetDescriptor(nsCSSCounterDesc aDescID, const nsAString& aValue);
 
--- a/layout/style/nsICSSStyleRuleDOMWrapper.h
+++ b/layout/style/nsICSSStyleRuleDOMWrapper.h
@@ -13,16 +13,21 @@
 
 #include "nsIDOMCSSStyleRule.h"
 
 // IID for the nsICSSStyleRuleDOMWrapper interface
 // {cee1bbb6-0a32-4cf3-8d42-ba3938e9ecaa}
 #define NS_ICSS_STYLE_RULE_DOM_WRAPPER_IID \
 {0xcee1bbb6, 0x0a32, 0x4cf3, {0x8d, 0x42, 0xba, 0x39, 0x38, 0xe9, 0xec, 0xaa}}
 
+namespace mozilla {
+namespace css {
+class StyleRule;
+} // namespace css
+} // namespace mozilla
 
 class nsICSSStyleRuleDOMWrapper : public nsIDOMCSSStyleRule {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICSS_STYLE_RULE_DOM_WRAPPER_IID)
 
   NS_IMETHOD GetCSSStyleRule(mozilla::css::StyleRule** aResult) = 0;
 };
 
--- a/layout/style/test/mochitest.ini
+++ b/layout/style/test/mochitest.ini
@@ -155,17 +155,17 @@ support-files = file_bug1089417_iframe.h
 [test_bug1203766.html]
 [test_bug1232829.html]
 [test_bug1292447.html]
 [test_cascade.html]
 [test_ch_ex_no_infloops.html]
 [test_change_hint_optimizations.html]
 [test_clip-path_polygon.html]
 [test_compute_data_with_start_struct.html]
-skip-if = toolkit == 'android' || stylo # bug 1330824 for stylo
+skip-if = toolkit == 'android'
 [test_computed_style.html]
 [test_computed_style_min_size_auto.html]
 [test_computed_style_no_pseudo.html]
 [test_computed_style_prefs.html]
 [test_condition_text.html]
 [test_condition_text_assignment.html]
 [test_contain_formatting_context.html]
 [test_counter_descriptor_storage.html]
@@ -267,17 +267,16 @@ skip-if = toolkit == 'android' #bug 7752
 [test_text_decoration_shorthands.html]
 [test_transitions_and_reframes.html]
 [test_transitions_and_restyles.html]
 [test_transitions_and_zoom.html]
 skip-if = stylo # timeout bug 1328499
 [test_transitions_cancel_near_end.html]
 skip-if = stylo # timeout bug 1328499
 [test_transitions_computed_values.html]
-skip-if = stylo # bug 1330825
 [test_transitions_computed_value_combinations.html]
 [test_transitions_events.html]
 skip-if = stylo # timeout bug 1328499
 [test_transitions.html]
 skip-if = (android_version == '18' && debug) # bug 1159532
 [test_transitions_bug537151.html]
 skip-if = stylo # timeout bug 1328499
 [test_transitions_dynamic_changes.html]
@@ -297,21 +296,20 @@ support-files = ../../reftests/fonts/mar
 [test_units_frequency.html]
 [test_units_length.html]
 [test_units_time.html]
 [test_unprefixing_service.html]
 support-files = unprefixing_service_iframe.html unprefixing_service_utils.js
 [test_unprefixing_service_prefs.html]
 support-files = unprefixing_service_iframe.html unprefixing_service_utils.js
 [test_value_cloning.html]
-skip-if = toolkit == 'android' || stylo # bug 775227 for android, bug 1330824 for stylo
+skip-if = toolkit == 'android' # bug 775227 for android
 [test_value_computation.html]
-skip-if = toolkit == 'android' || stylo # bug 1330824 for stylo
+skip-if = toolkit == 'android'
 [test_value_storage.html]
-skip-if = stylo # bug 1330824
 [test_variable_serialization_computed.html]
 [test_variable_serialization_specified.html]
 [test_variables.html]
 support-files = support/external-variable-url.css
 [test_video_object_fit.html]
 [test_viewport_units.html]
 [test_visited_image_loading.html]
 skip-if = (toolkit == 'android' || stylo) # TIMED_OUT for android, timeout bug 1328511 for stylo
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/EventDispatcher.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/EventDispatcher.java
@@ -84,21 +84,20 @@ public final class EventDispatcher exten
 
     @WrapForJNI private static final int DETACHED = 0;
     @WrapForJNI private static final int ATTACHED = 1;
     @WrapForJNI private static final int REATTACHING = 2;
 
     @WrapForJNI(calledFrom = "gecko")
     private synchronized void setAttachedToGecko(final int state) {
         if (mAttachedToGecko && state == DETACHED) {
-            if (GeckoThread.isStateAtLeast(GeckoThread.State.JNI_READY)) {
+            if (GeckoThread.isRunning()) {
                 disposeNative();
             } else {
-                GeckoThread.queueNativeCallUntil(GeckoThread.State.JNI_READY,
-                        this, "disposeNative");
+                GeckoThread.queueNativeCall(this, "disposeNative");
             }
         }
         mAttachedToGecko = (state == ATTACHED);
     }
 
     private <T> void registerListener(final Class<?> listType,
                                       final Map<String, List<T>> listenersMap,
                                       final T listener,
@@ -402,17 +401,29 @@ public final class EventDispatcher exten
         }
 
         if (dispatchToThread(type, jsMessage, bundleMessage, callback,
                              mBackgroundThreadListeners, ThreadUtils.getBackgroundHandler())) {
             return true;
         }
 
         if (jsMessage == null) {
-            Log.w(LOGTAG, "No listeners for " + type + " in dispatchToThreads");
+            Log.w(LOGTAG, "No listeners for " + type);
+        }
+
+        if (!GeckoThread.isRunning() && jsMessage == null) {
+            // Usually, we discard an event if there is no listeners for it by the time of
+            // the dispatch. However, if Gecko is not ready and there is no listener for
+            // this event that's possibly headed to Gecko, we make a special exception to
+            // queue this event until Gecko is ready. This way, Gecko can first register
+            // its listeners, and accept the event when it is ready.
+            GeckoThread.queueNativeCall(this, "dispatchToGecko",
+                                        String.class, type, GeckoBundle.class, bundleMessage,
+                                        EventCallback.class, JavaCallbackDelegate.wrap(callback));
+            return true;
         }
 
         if (!AppConstants.RELEASE_OR_BETA && jsMessage == null) {
             // We're dispatching a Bundle message. Because Gecko thread listeners are not
             // supported for Bundle messages, do a sanity check to make sure we don't have
             // matching Gecko thread listeners.
             boolean hasGeckoListener = false;
             synchronized (mGeckoThreadNativeListeners) {
@@ -482,18 +493,16 @@ public final class EventDispatcher exten
         // on a separate thread.
         synchronized (listenersMap) {
             final List<BundleEventListener> listeners = listenersMap.get(type);
             if (listeners == null) {
                 return false;
             }
 
             if (listeners.isEmpty()) {
-                Log.w(LOGTAG, "No listeners for " + type + " in dispatchToThread");
-
                 // There were native listeners, and they're gone.
                 return false;
             }
 
             final GeckoBundle messageAsBundle;
             try {
                 messageAsBundle = jsMessage != null ?
                         convertBundle(jsMessage.toBundle(), jsMessage) : bundleMessage;
@@ -524,18 +533,17 @@ public final class EventDispatcher exten
         //   "event_specific": "value",
         //   ...
         try {
             final String type = message.getString("type");
 
             final List<GeckoEventListener> listeners = getGeckoListeners(type);
 
             if (listeners == null || listeners.isEmpty()) {
-                Log.w(LOGTAG, "No listeners for " + type + " in dispatchEvent");
-
+                Log.w(LOGTAG, "No listeners for " + type);
                 return false;
             }
 
             for (final GeckoEventListener listener : listeners) {
                 listener.handleMessage(type, message);
             }
         } catch (final JSONException e) {
             Log.e(LOGTAG, "handleGeckoMessage throws " + e, e);
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoEditable.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoEditable.java
@@ -1130,17 +1130,17 @@ final class GeckoEditable extends JNIObj
                 if (mListener == null) {
                     return;
                 }
                 mListener.notifyIMEContext(state, typeHint, modeHint, actionHint);
             }
         });
     }
 
-    @WrapForJNI(calledFrom = "gecko")
+    @WrapForJNI(calledFrom = "gecko", exceptionMode = "ignore")
     private void onSelectionChange(final int start, final int end) {
         if (DEBUG) {
             // GeckoEditableListener methods should all be called from the Gecko thread
             ThreadUtils.assertOnGeckoThread();
             Log.d(LOGTAG, "onSelectionChange(" + start + ", " + end + ")");
         }
 
         final int currentLength = mText.getCurrentText().length();
@@ -1159,17 +1159,17 @@ final class GeckoEditable extends JNIObj
         geckoScheduleSyncShadowText();
     }
 
     private boolean geckoIsSameText(int start, int oldEnd, CharSequence newText) {
         return oldEnd - start == newText.length() &&
                TextUtils.regionMatches(mText.getCurrentText(), start, newText, 0, oldEnd - start);
     }
 
-    @WrapForJNI(calledFrom = "gecko")
+    @WrapForJNI(calledFrom = "gecko", exceptionMode = "ignore")
     private void onTextChange(final CharSequence text, final int start,
                               final int unboundedOldEnd, final int unboundedNewEnd) {
         if (DEBUG) {
             // GeckoEditableListener methods should all be called from the Gecko thread
             ThreadUtils.assertOnGeckoThread();
             StringBuilder sb = new StringBuilder("onTextChange(");
             debugAppend(sb, text);
             sb.append(", ").append(start).append(", ")
--- a/security/sandbox/chromium/sandbox/win/src/broker_services.cc
+++ b/security/sandbox/chromium/sandbox/win/src/broker_services.cc
@@ -404,24 +404,16 @@ ResultCode BrokerServicesBase::SpawnTarg
       startup_info.startup_info()->dwFlags |= STARTF_USESTDHANDLES;
       startup_info.startup_info()->hStdInput = INVALID_HANDLE_VALUE;
       startup_info.startup_info()->hStdOutput = stdout_handle;
       startup_info.startup_info()->hStdError = stderr_handle;
       // Allowing inheritance of handles is only secure now that we
       // have limited which handles will be inherited.
       inherit_handles = true;
     }
-  } else if (getenv("MOZ_WIN_INHERIT_STD_HANDLES_PRE_VISTA")) {
-    // On pre-Vista versions even if we can't limit what gets inherited, we
-    // sometimes want to inherit stdout/err for testing purposes.
-    startup_info.startup_info()->dwFlags |= STARTF_USESTDHANDLES;
-    startup_info.startup_info()->hStdInput = INVALID_HANDLE_VALUE;
-    startup_info.startup_info()->hStdOutput = policy_base->GetStdoutHandle();
-    startup_info.startup_info()->hStdError = policy_base->GetStderrHandle();
-    inherit_handles = true;
   }
 
   // Construct the thread pool here in case it is expensive.
   // The thread pool is shared by all the targets
   if (NULL == thread_pool_)
     thread_pool_ = new Win2kThreadPool();
 
   // Create the TargetProces object and spawn the target suspended. Note that
--- a/security/sandbox/modifications-to-chromium-to-reapply-after-upstream-merge.txt
+++ b/security/sandbox/modifications-to-chromium-to-reapply-after-upstream-merge.txt
@@ -1,9 +1,8 @@
 Please add a link to the bugzilla bug and patch name that should be re-applied.
 Also, please update any existing links to their actual mozilla-central changeset.
 
-https://bugzilla.mozilla.org/show_bug.cgi?id=1287426 bug1287426part4.patch
 https://bugzilla.mozilla.org/show_bug.cgi?id=1287426 bug1287426part5.patch
 https://hg.mozilla.org/mozilla-central/rev/7df8d6639971
 https://bugzilla.mozilla.org/show_bug.cgi?id=1287426 bug1287426part7.patch
 https://bugzilla.mozilla.org/show_bug.cgi?id=1273372 bug1273372part2.patch
 https://bugzilla.mozilla.org/show_bug.cgi?id=1273372 bug1273372part3.patch
--- a/services/sync/tests/unit/test_fxa_startOver.js
+++ b/services/sync/tests/unit/test_fxa_startOver.js
@@ -7,17 +7,17 @@ Cu.import("resource://services-sync/brow
 Cu.import("resource://services-sync/service.js");
 
 function run_test() {
   initTestLogging("Trace");
   run_next_test();
 }
 
 add_task(async function test_startover() {
-  let oldValue = Services.prefs.getBoolPref("services.sync-testing.startOverKeepIdentity", true);
+  let oldValue = Services.prefs.getBoolPref("services.sync-testing.startOverKeepIdentity");
   Services.prefs.setBoolPref("services.sync-testing.startOverKeepIdentity", false);
 
   ensureLegacyIdentityManager();
   await configureIdentity({username: "johndoe"});
 
   // The boolean flag on the xpcom service should reflect a legacy provider.
   let xps = Cc["@mozilla.org/weave/service;1"]
             .getService(Components.interfaces.nsISupports)
--- a/services/sync/tps/extensions/tps/resource/tps.jsm
+++ b/services/sync/tps/extensions/tps/resource/tps.jsm
@@ -744,17 +744,17 @@ var TPS = {
         SyncTelemetry.shutdown();
         // we're all done
         Logger.logInfo("test phase " + this._currentPhase + ": " +
                        (this._errors ? "FAIL" : "PASS"));
         this._phaseFinished = true;
         this.quit();
         return;
       }
-      this.seconds_since_epoch = prefs.getIntPref("tps.seconds_since_epoch", 0);
+      this.seconds_since_epoch = prefs.getIntPref("tps.seconds_since_epoch");
       if (this.seconds_since_epoch)
         this._usSinceEpoch = this.seconds_since_epoch * 1000 * 1000;
       else {
         this.DumpError("seconds-since-epoch not set");
         return;
       }
 
       let phase = this._phaselist[this._currentPhase];
--- a/testing/mochitest/runrobocop.py
+++ b/testing/mochitest/runrobocop.py
@@ -391,18 +391,16 @@ class RobocopTestRunner(MochitestDesktop
            Return an environment dictionary suitable for remote use.
 
            This is similar to buildBrowserEnv in runtestsremote.py.
         """
         browserEnv = self.environment(
             xrePath=None,
             debugger=None)
         # remove desktop environment not used on device
-        if "MOZ_WIN_INHERIT_STD_HANDLES_PRE_VISTA" in browserEnv:
-            del browserEnv["MOZ_WIN_INHERIT_STD_HANDLES_PRE_VISTA"]
         if "XPCOM_MEM_BLOAT_LOG" in browserEnv:
             del browserEnv["XPCOM_MEM_BLOAT_LOG"]
         browserEnv["MOZ_LOG_FILE"] = os.path.join(
             self.remoteMozLog,
             self.mozLogName)
 
         try:
             browserEnv.update(
--- a/testing/mochitest/runtests.py
+++ b/testing/mochitest/runtests.py
@@ -1479,24 +1479,16 @@ toolbar#nav-bar {
             debugger=debugger,
             dmdPath=options.dmdPath,
             lsanPath=lsanPath)
 
         # These variables are necessary for correct application startup; change
         # via the commandline at your own risk.
         browserEnv["XPCOM_DEBUG_BREAK"] = "stack"
 
-        # When creating child processes on Windows pre-Vista (e.g. Windows XP) we
-        # don't normally inherit stdout/err handles, because you can only do it by
-        # inheriting all other inheritable handles as well.
-        # We need to inherit them for plain mochitests for test logging purposes, so
-        # we do so on the basis of a specific environment variable.
-        if options.flavor == 'plain':
-            browserEnv["MOZ_WIN_INHERIT_STD_HANDLES_PRE_VISTA"] = "1"
-
         # interpolate environment passed with options
         try:
             browserEnv.update(
                 dict(
                     parseKeyValue(
                         options.environment,
                         context='--setenv')))
         except KeyValueParseError as e:
--- a/testing/mochitest/runtestsremote.py
+++ b/testing/mochitest/runtestsremote.py
@@ -261,18 +261,16 @@ class MochiRemote(MochitestDesktop):
         return None
 
     def buildBrowserEnv(self, options, debugger=False):
         browserEnv = MochitestDesktop.buildBrowserEnv(
             self,
             options,
             debugger=debugger)
         # remove desktop environment not used on device
-        if "MOZ_WIN_INHERIT_STD_HANDLES_PRE_VISTA" in browserEnv:
-            del browserEnv["MOZ_WIN_INHERIT_STD_HANDLES_PRE_VISTA"]
         if "XPCOM_MEM_BLOAT_LOG" in browserEnv:
             del browserEnv["XPCOM_MEM_BLOAT_LOG"]
         # override mozLogs to avoid processing in MochitestDesktop base class
         self.mozLogs = None
         browserEnv["MOZ_LOG_FILE"] = os.path.join(
             self.remoteMozLog,
             self.mozLogName)
         return browserEnv
--- a/testing/specialpowers/content/SpecialPowersObserverAPI.js
+++ b/testing/specialpowers/content/SpecialPowersObserverAPI.js
@@ -378,17 +378,17 @@ SpecialPowersObserverAPI.prototype = {
             break;
           case "remove":
             Services.perms.removeFromPrincipal(principal, msg.type);
             break;
           case "has":
             let hasPerm = Services.perms.testPermissionFromPrincipal(principal, msg.type);
             return hasPerm == Ci.nsIPermissionManager.ALLOW_ACTION;
           case "test":
-            let testPerm = Services.perms.testPermissionFromPrincipal(principal, msg.type, msg.value);
+            let testPerm = Services.perms.testPermissionFromPrincipal(principal, msg.type);
             return testPerm == msg.value;
           default:
             throw new SpecialPowersError(
               "Invalid operation for SPPermissionManager");
         }
         return undefined;	// See comment at the beginning of this function.
       }
 
--- a/testing/talos/talos/ffsetup.py
+++ b/testing/talos/talos/ffsetup.py
@@ -59,19 +59,16 @@ class FFSetup(object):
         self.profile_dir = os.path.join(self._tmp_dir, 'profile')
         self.sps_profile = None
 
     def _init_env(self):
         self.env = dict(os.environ)
         for k, v in self.browser_config['env'].iteritems():
             self.env[k] = str(v)
         self.env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'
-        # for winxp e10s logging:
-        # https://bugzilla.mozilla.org/show_bug.cgi?id=1037445
-        self.env['MOZ_WIN_INHERIT_STD_HANDLES_PRE_VISTA'] = '1'
         if self.browser_config['symbols_path']:
             self.env['MOZ_CRASHREPORTER'] = '1'
         else:
             self.env['MOZ_CRASHREPORTER_DISABLE'] = '1'
 
         self.env['MOZ_DISABLE_NONLOCAL_CONNECTIONS'] = '1'
 
         self.env["LD_LIBRARY_PATH"] = \
--- a/toolkit/components/osfile/tests/xpcshell/test_shutdown.js
+++ b/toolkit/components/osfile/tests/xpcshell/test_shutdown.js
@@ -62,17 +62,17 @@ add_task(function system_shutdown() {
         resolved = true;
       } catch (ex if ex == "timeout") {
         resolved = false;
       }
       Services.console.unregisterListener(observer);
       Services.prefs.clearUserPref("toolkit.osfile.log");
       Services.prefs.clearUserPref("toolkit.osfile.log.redirect");
       Services.prefs.clearUserPref("toolkit.osfile.test.shutdown.observer");
-      Services.prefs.clearUserPref("toolkit.async_shutdown.testing", true);
+      Services.prefs.clearUserPref("toolkit.async_shutdown.testing");
 
       throw new Task.Result(resolved);
     });
   }
 
   let TEST_DIR = OS.Path.join((yield OS.File.getCurrentDirectory()), "..");
   do_print("Testing for leaks of directory iterator " + TEST_DIR);
   let iterator = new OS.File.DirectoryIterator(TEST_DIR);
--- a/toolkit/components/passwordmgr/LoginManagerContent.jsm
+++ b/toolkit/components/passwordmgr/LoginManagerContent.jsm
@@ -580,33 +580,46 @@ var LoginManagerContent = {
           .then(null, Cu.reportError);
     } else {
       // Ignore the event, it's for some input we don't care about.
     }
   },
 
   /**
    * @param {FormLike} form - the FormLike to look for password fields in.
-   * @param {bool} [skipEmptyFields=false] - Whether to ignore password fields with no value.
-   *                                         Used at capture time since saving empty values isn't
-   *                                         useful.
+   * @param {Object} options
+   * @param {bool} [options.skipEmptyFields=false] - Whether to ignore password fields with no value.
+   *                                                 Used at capture time since saving empty values isn't
+   *                                                 useful.
+   * @param {Object} [options.fieldOverrideRecipe=null] - A relevant field override recipe to use.
    * @return {Array|null} Array of password field elements for the specified form.
    *                      If no pw fields are found, or if more than 3 are found, then null
    *                      is returned.
    */
-  _getPasswordFields(form, skipEmptyFields = false) {
+  _getPasswordFields(form, {
+    fieldOverrideRecipe = null,
+    skipEmptyFields = false,
+  } = {}) {
     // Locate the password fields in the form.
     let pwFields = [];
     for (let i = 0; i < form.elements.length; i++) {
       let element = form.elements[i];
       if (!(element instanceof Ci.nsIDOMHTMLInputElement) ||
           element.type != "password") {
         continue;
       }
 
+      // Exclude ones matching a `notPasswordSelector`, if specified.
+      if (fieldOverrideRecipe && fieldOverrideRecipe.notPasswordSelector &&
+          element.matches(fieldOverrideRecipe.notPasswordSelector)) {
+        log("skipping password field (id/name is", element.id, " / ",
+            element.name + ") due to recipe:", fieldOverrideRecipe);
+        continue;
+      }
+
       if (skipEmptyFields && !element.value) {
         continue;
       }
 
       pwFields[pwFields.length] = {
                                     index   : i,
                                     element
                                   };
@@ -670,17 +683,20 @@ var LoginManagerContent = {
       if (usernameOverrideField) {
         usernameField = usernameOverrideField;
       }
     }
 
     if (!pwFields) {
       // Locate the password field(s) in the form. Up to 3 supported.
       // If there's no password field, there's nothing for us to do.
-      pwFields = this._getPasswordFields(form, isSubmission);
+      pwFields = this._getPasswordFields(form, {
+        fieldOverrideRecipe,
+        skipEmptyFields: isSubmission,
+      });
     }
 
     if (!pwFields) {
       return [null, null, null];
     }
 
     if (!usernameField) {
       // Locate the username field in the form by searching backwards
--- a/toolkit/components/passwordmgr/LoginRecipes.jsm
+++ b/toolkit/components/passwordmgr/LoginRecipes.jsm
@@ -3,17 +3,24 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 this.EXPORTED_SYMBOLS = ["LoginRecipesContent", "LoginRecipesParent"];
 
 const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
 const REQUIRED_KEYS = ["hosts"];
-const OPTIONAL_KEYS = ["description", "notUsernameSelector", "passwordSelector", "pathRegex", "usernameSelector"];
+const OPTIONAL_KEYS = [
+  "description",
+  "notPasswordSelector",
+  "notUsernameSelector",
+  "passwordSelector",
+  "pathRegex",
+  "usernameSelector",
+];
 const SUPPORTED_KEYS = REQUIRED_KEYS.concat(OPTIONAL_KEYS);
 
 Cu.importGlobalProperties(["URL"]);
 
 Cu.import("resource://gre/modules/NetUtil.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
@@ -221,17 +228,17 @@ var LoginRecipesContent = {
     if (!recipes.size) {
       return null;
     }
 
     let chosenRecipe = null;
     // Find the first (most-specific recipe that involves field overrides).
     for (let recipe of recipes) {
       if (!recipe.usernameSelector && !recipe.passwordSelector &&
-          !recipe.notUsernameSelector) {
+          !recipe.notUsernameSelector && !recipe.notPasswordSelector) {
         continue;
       }
 
       chosenRecipe = recipe;
       break;
     }
 
     return chosenRecipe;
--- a/toolkit/components/passwordmgr/content/recipes.json
+++ b/toolkit/components/passwordmgr/content/recipes.json
@@ -21,11 +21,22 @@
       "usernameSelector": "#accountname, input[name='loginname']",
       "passwordSelector": "#password1, input[name='loginpassword']",
       "pathRegex": "^\/account\/"
     },
     {
       "description": "Username field will be incorrectly captured in the change password form (bug 1243722)",
       "hosts": ["www.facebook.com"],
       "notUsernameSelector": "#password_strength"
+    },
+    {
+      "description": "United uses a useless password field plus one per frequent flyer number during checkin. Don't save any of them (Bug 1330810)",
+      "hosts": ["www.united.com"],
+      "notPasswordSelector": "input[type='password']",
+      "pathRegex": "^\/travel\/checkin\/changefqtv.aspx"
+    },
+    {
+      "description": "Gogo In-Flight uses a password field for credit card numbers on the same page as login",
+      "hosts": ["buy.gogoinflight.com"],
+      "notPasswordSelector": "#cardNumber"
     }
   ]
 }
--- a/toolkit/components/passwordmgr/test/mochitest/test_recipe_login_fields.html
+++ b/toolkit/components/passwordmgr/test/mochitest/test_recipe_login_fields.html
@@ -128,16 +128,80 @@ add_task(function* testNotUsernameFieldN
     </form>`;
 
   let elements = yield waitForFills(1);
   for (let element of elements) {
     is(element.dataset.expected, "true", `${element.name} was filled`);
   }
 });
 
+add_task(function* loadNotPasswordSelectorRecipes() {
+  yield resetRecipes();
+  yield loadRecipes({
+    siteRecipes: [{
+      hosts: ["mochi.test:8888"],
+      notPasswordSelector: "input[name='not_pword'], input[name='not_pword2']",
+    }],
+  });
+});
+
+add_task(function* testNotPasswordField() {
+  document.getElementById("content").innerHTML = `
+    <!-- The field matching notPasswordSelector should be skipped -->
+    <form id="form5">
+      <input type="text"     name="uname7" data-expected="true">
+      <input type="password" name="not_pword" data-expected="false">
+      <input type="password" name="pword7" data-expected="true">
+    </form>`;
+
+  let elements = yield waitForFills(2);
+  for (let element of elements) {
+    is(element.dataset.expected, "true", `${element.name} was filled`);
+  }
+});
+
+add_task(function* testNotPasswordFieldNoPassword() {
+  document.getElementById("content").innerHTML = `
+    <!-- The field matching notPasswordSelector should be skipped.
+         No username or password field should be found and filled in this case.
+         A dummy form7 is added after so we know when the login manager is done
+         considering filling form6. -->
+    <form id="form6">
+      <input type="text"     name="uname8" data-expected="false">
+      <input type="password" name="not_pword" data-expected="false">
+    </form>
+    <form id="form7">
+      <input type="password" name="pword9" data-expected="true">
+    </form>`;
+
+  let elements = yield waitForFills(1);
+  for (let element of elements) {
+    is(element.dataset.expected, "true", `${element.name} was filled`);
+  }
+});
+
+add_task(function* testNotPasswordField_tooManyToOkay() {
+  document.getElementById("content").innerHTML = `
+    <!-- The field matching notPasswordSelector should be skipped so we won't
+         have too many pw fields to handle (3). -->
+    <form id="form8">
+      <input type="text"     name="uname9" data-expected="true">
+      <input type="password" name="not_pword2" data-expected="false">
+      <input type="password" name="not_pword" data-expected="false">
+      <input type="password" name="pword10" data-expected="true">
+      <input type="password" name="pword11" data-expected="false">
+      <input type="password" name="pword12" data-expected="false">
+    </form>`;
+
+  let elements = yield waitForFills(2);
+  for (let element of elements) {
+    is(element.dataset.expected, "true", `${element.name} was filled`);
+  }
+});
+
 </script>
 
 <p id="display"></p>
 
 <div id="content">
   // Forms are inserted dynamically
 </div>
 <pre id="test"></pre>
--- a/toolkit/components/passwordmgr/test/unit/test_getPasswordFields.js
+++ b/toolkit/components/passwordmgr/test/unit/test_getPasswordFields.js
@@ -77,16 +77,31 @@ const TESTCASES = [
     skipEmptyFields: true,
   },
   {
     description: "2 password fields outside of a <form> with 1 linked via @form + skipEmpty with 1 empty",
     document: `<input id="pw1" type=password value="pass1"><input id="pw2" type=password form="form1">
       <form id="form1"></form>`,
     returnedFieldIDsByFormLike: [["pw1"], []],
     skipEmptyFields: true,
+    fieldOverrideRecipe: {
+      // Ensure a recipe without `notPasswordSelector` doesn't cause a problem.
+      hosts: ["localhost:8080"],
+    },
+  },
+  {
+    description: "3 password fields outside of a <form> with 1 linked via @form + skipEmpty",
+    document: `<input id="pw1" type=password value="pass1"><input id="pw2" type=password form="form1" value="pass2"><input id="pw3" type=password value="pass3">
+      <form id="form1"><input id="pw4" type=password></form>`,
+    returnedFieldIDsByFormLike: [["pw3"], ["pw2"]],
+    skipEmptyFields: true,
+    fieldOverrideRecipe: {
+      hosts: ["localhost:8080"],
+      notPasswordSelector: "#pw1",
+    },
   },
 ];
 
 for (let tc of TESTCASES) {
   do_print("Sanity checking the testcase: " + tc.description);
 
   (function() {
     let testcase = tc;
@@ -110,18 +125,20 @@ for (let tc of TESTCASES) {
       }
 
       Assert.strictEqual(mapRootElementToFormLike.size, testcase.returnedFieldIDsByFormLike.length,
                          "Check the correct number of different formLikes were returned");
 
       let formLikeIndex = -1;
       for (let formLikeFromInput of mapRootElementToFormLike.values()) {
         formLikeIndex++;
-        let pwFields = LoginManagerContent._getPasswordFields(formLikeFromInput,
-                                                              testcase.skipEmptyFields);
+        let pwFields = LoginManagerContent._getPasswordFields(formLikeFromInput, {
+          fieldOverrideRecipe: testcase.fieldOverrideRecipe,
+          skipEmptyFields: testcase.skipEmptyFields,
+        });
 
         if (formLikeFromInput.rootElement instanceof Ci.nsIDOMHTMLFormElement) {
           let formLikeFromForm = LoginFormFactory.createFromForm(formLikeFromInput.rootElement);
           do_print("Checking that the FormLike created for the <form> matches" +
                    " the one from a password field");
           formLikeEqual(formLikeFromInput, formLikeFromForm);
         }
 
--- a/toolkit/components/printing/content/printUtils.js
+++ b/toolkit/components/printing/content/printUtils.js
@@ -435,18 +435,18 @@ var PrintUtils = {
     // now augment them with any values from last time
     aPSSVC.initPrintSettingsFromPrefs(aPrintSettings, true, aPrintSettings.kInitSaveAll);
   },
 
   getPrintSettings() {
     var pref = Components.classes["@mozilla.org/preferences-service;1"]
                          .getService(Components.interfaces.nsIPrefBranch);
     if (pref) {
-      gPrintSettingsAreGlobal = pref.getBoolPref("print.use_global_printsettings", false);
-      gSavePrintSettings = pref.getBoolPref("print.save_print_settings", false);
+      gPrintSettingsAreGlobal = pref.getBoolPref("print.use_global_printsettings");
+      gSavePrintSettings = pref.getBoolPref("print.save_print_settings");
     }
 
     var printSettings;
     try {
       var PSSVC = Components.classes["@mozilla.org/gfx/printsettings-service;1"]
                             .getService(Components.interfaces.nsIPrintSettingsService);
       if (gPrintSettingsAreGlobal) {
         printSettings = PSSVC.globalPrintSettings;
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -9626,16 +9626,23 @@
   },
   "SERVICE_WORKER_LIFE_TIME": {
     "expires_in_version": "50",
     "kind": "exponential",
     "high": 120000,
     "n_buckets": 20,
     "description": "Tracking how long a ServiceWorker stays alive after it is spawned. File bugs in Core::DOM in case of a Telemetry regression."
   },
+  "FILE_EMBEDDED_SERVICEWORKERS": {
+    "alert_emails": ["dparks@mozilla.com"],
+    "expires_in_version": "58",
+    "kind": "count",
+    "bug_numbers": [1312788],
+    "description": "Count ServiceWorkers that are embedded in pages loading with the file:/// protocol."
+  },
   "GRAPHICS_SANITY_TEST": {
     "expires_in_version": "never",
     "alert_emails": ["gfx-telemetry-alerts@mozilla.com","msreckovic@mozilla.com"],
     "kind": "enumerated",
     "n_values": 20,
     "releaseChannelCollection": "opt-out",
     "description": "Reports results from the graphics sanity test to track which drivers are having problems (0=TEST_PASSED, 1=TEST_FAILED_RENDER, 2=TEST_FAILED_VIDEO, 3=TEST_CRASHED)"
   },
--- a/toolkit/components/telemetry/TelemetryController.jsm
+++ b/toolkit/components/telemetry/TelemetryController.jsm
@@ -315,16 +315,17 @@ this.TelemetryController = Object.freeze
   promiseInitialized() {
     return Impl.promiseInitialized();
   },
 });
 
 var Impl = {
   _initialized: false,
   _initStarted: false, // Whether we started setting up TelemetryController.
+  _shuttingDown: false, // Whether the browser is shutting down.
   _logger: null,
   _prevValues: {},
   // The previous build ID, if this is the first run with a new build.
   // Undefined if this is not the first run, or the previous build ID is unknown.
   _previousBuildID: undefined,
   _clientID: null,
   // A task performing delayed initialization
   _delayedInitTask: null,
@@ -488,16 +489,23 @@ var Impl = {
    * @param {Boolean} [aOptions.addEnvironment=false] true if the ping should contain the
    *                  environment data.
    * @param {Object}  [aOptions.overrideEnvironment=null] set to override the environment data.
    * @returns {Promise} Test-only - a promise that is resolved with the ping id once the ping is stored or sent.
    */
   submitExternalPing: function send(aType, aPayload, aOptions) {
     this._log.trace("submitExternalPing - type: " + aType + ", aOptions: " + JSON.stringify(aOptions));
 
+    // Reject pings sent after shutdown.
+    if (this._shuttingDown) {
+      const errorMessage = "submitExternalPing - Submission is not allowed after shutdown, discarding ping of type: " + aType;
+      this._log.error(errorMessage);
+      return Promise.reject(new Error(errorMessage));
+    }
+
     // Enforce the type string to only contain sane characters.
     const typeUuid = /^[a-z0-9][a-z0-9-]+[a-z0-9]$/i;
     if (!typeUuid.test(aType)) {
       this._log.error("submitExternalPing - invalid ping type: " + aType);
       let histogram = Telemetry.getKeyedHistogramById("TELEMETRY_INVALID_PING_TYPE_SUBMITTED");
       histogram.add(aType, 1);
       return Promise.reject(new Error("Invalid type string submitted."));
     }
@@ -653,16 +661,17 @@ var Impl = {
    *   3) _delayedInitTask is currently running.
    *   4) _delayedInitTask finished running and is nulled out.
    *
    * @return {Promise} Resolved when TelemetryController and TelemetrySession are fully
    *                   initialized. This is only used in tests.
    */
   setupTelemetry: function setupTelemetry(testing) {
     this._initStarted = true;
+    this._shuttingDown = false;
     this._testMode = testing;
 
     this._log.trace("setupTelemetry");
 
     if (this._delayedInitTask) {
       this._log.error("setupTelemetry - init task already running");
       return this._delayedInitTaskDeferred.promise;
     }
@@ -784,31 +793,33 @@ var Impl = {
       yield this._connectionsBarrier.wait();
 
       // Perform final shutdown operations.
       yield TelemetryStorage.shutdown();
     } finally {
       // Reset state.
       this._initialized = false;
       this._initStarted = false;
+      this._shuttingDown = true;
     }
   }),
 
   shutdown() {
     this._log.trace("shutdown");
 
     // We can be in one the following states here:
     // 1) setupTelemetry was never called
     // or it was called and
     //   2) _delayedInitTask was scheduled, but didn't run yet.
     //   3) _delayedInitTask is running now.
     //   4) _delayedInitTask finished running already.
 
     // This handles 1).
     if (!this._initStarted) {
+      this._shuttingDown = true;
       return Promise.resolve();
     }
 
     // This handles 4).
     if (!this._delayedInitTask) {
       // We already ran the delayed initialization.
       return this._cleanupOnShutdown();
     }
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryController.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryController.js
@@ -447,16 +447,19 @@ add_task(function* test_telemetryEnabled
   Assert.equal(Telemetry.canRecordExtended, true,
                "True must enable Telemetry recording.");
 
   // Also check that the false works as well.
   Preferences.set(PREF_ENABLED, false);
   yield TelemetryController.testReset();
   Assert.equal(Telemetry.canRecordExtended, false,
                "False must disable Telemetry recording.");
+
+  // Restore the state of the pref.
+  Preferences.set(PREF_ENABLED, true);
 });
 
 add_task(function* test_telemetryCleanFHRDatabase() {
   const FHR_DBNAME_PREF = "datareporting.healthreport.dbName";
   const CUSTOM_DB_NAME = "unlikely.to.be.used.sqlite";
   const DEFAULT_DB_NAME = "healthreport.sqlite";
 
   // Check that we're able to remove a FHR DB with a custom name.
@@ -497,11 +500,20 @@ add_task(function* test_telemetryCleanFH
 
   // Trigger the cleanup and check that the files were removed.
   yield TelemetryStorage.removeFHRDatabase();
   for (let dbFilePath of DEFAULT_DB_PATHS) {
     Assert.ok(!(yield OS.File.exists(dbFilePath)), "The DB must not be on the disk anymore: " + dbFilePath);
   }
 });
 
+// Testing shutdown and checking that pings sent afterwards are rejected.
+add_task(function* test_pingRejection() {
+  yield TelemetryController.testReset();
+  yield TelemetryController.testShutdown();
+  yield sendPing(false, false)
+    .then(() => Assert.ok(false, "Pings submitted after shutdown must be rejected."),
+          () => Assert.ok(true, "Ping submitted after shutdown correctly rejected."));
+});
+
 add_task(function* stopServer() {
   yield PingServer.stop();
 });
--- a/toolkit/content/browser-content.js
+++ b/toolkit/content/browser-content.js
@@ -417,18 +417,18 @@ var Printing = {
   ],
 
   init() {
     this.MESSAGES.forEach(msgName => addMessageListener(msgName, this));
     addEventListener("PrintingError", this, true);
   },
 
   get shouldSavePrintSettings() {
-    return Services.prefs.getBoolPref("print.use_global_printsettings", false) &&
-           Services.prefs.getBoolPref("print.save_print_settings", false);
+    return Services.prefs.getBoolPref("print.use_global_printsettings") &&
+           Services.prefs.getBoolPref("print.save_print_settings");
   },
 
   handleEvent(event) {
     if (event.type == "PrintingError") {
       let win = event.target.defaultView;
       let wbp = win.QueryInterface(Ci.nsIInterfaceRequestor)
                    .getInterface(Ci.nsIWebBrowserPrint);
       let nsresult = event.detail;
--- a/toolkit/modules/AppConstants.jsm
+++ b/toolkit/modules/AppConstants.jsm
@@ -255,16 +255,23 @@ this.AppConstants = Object.freeze({
 
   MOZ_REQUIRE_SIGNING:
 #ifdef MOZ_REQUIRE_SIGNING
   true,
 #else
   false,
 #endif
 
+  INSTALL_COMPACT_THEMES:
+#ifdef INSTALL_COMPACT_THEMES
+  true,
+#else
+  false,
+#endif
+
   MENUBAR_CAN_AUTOHIDE:
 #ifdef MENUBAR_CAN_AUTOHIDE
   true,
 #else
   false,
 #endif
 
   CAN_DRAW_IN_TITLEBAR:
--- a/toolkit/modules/moz.build
+++ b/toolkit/modules/moz.build
@@ -98,16 +98,17 @@ EXTRA_JS_MODULES += [
     'UpdateUtils.jsm',
     'WebChannel.jsm',
     'WindowDraggingUtils.jsm',
     'ZipUtils.jsm',
 ]
 EXTRA_JS_MODULES.third_party.jsesc += ['third_party/jsesc/jsesc.js']
 EXTRA_JS_MODULES.sessionstore += ['sessionstore/Utils.jsm']
 
+DEFINES['INSTALL_COMPACT_THEMES'] = 1
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'cocoa'):
     DEFINES['CAN_DRAW_IN_TITLEBAR'] = 1
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3'):
     DEFINES['MENUBAR_CAN_AUTOHIDE'] = 1
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3', 'cocoa'):
     DEFINES['HAVE_SHELL_SERVICE'] = 1
--- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_regexp.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_regexp.js
@@ -62,17 +62,17 @@ function load_blocklist(aFile, aCallback
 
   Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
                              gPort + "/data/" + aFile);
   var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
                   getService(Ci.nsITimerCallback);
   // if we're not using the blocklist.xml for certificate blocklist state,
   // ensure that kinto update is enabled
   if (!Services.prefs.getBoolPref("security.onecrl.via.amo")) {
-    ok(Services.prefs.getBoolPref("services.blocklist.update_enabled", false),
+    ok(Services.prefs.getBoolPref("services.blocklist.update_enabled"),
                                   "Kinto update should be enabled");
   }
   blocklist.notify(null);
 }
 
 
 function end_test() {
   testserver.stop(do_test_finished);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_startup.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_startup.js
@@ -638,17 +638,17 @@ function run_test_8() {
     do_check_false(isExtensionInAddonsList(globalDir, "addon2@tests.mozilla.org"));
 
     do_execute_soon(run_test_9);
   });
 }
 
 // More hiding and revealing
 function run_test_9() {
-  Services.prefs.clearUserPref("extensions.enabledScopes", 0);
+  Services.prefs.clearUserPref("extensions.enabledScopes");
 
   var dest = userDir.clone();
   dest.append(do_get_expected_addon_name("addon1@tests.mozilla.org"));
   dest.remove(true);
   dest = globalDir.clone();
   dest.append(do_get_expected_addon_name("addon2@tests.mozilla.org"));
   dest.remove(true);
   addon2.version = "2.4";
--- a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-useless-parameters.js
+++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-useless-parameters.js
@@ -24,16 +24,22 @@ module.exports = function(context) {
   return {
     "CallExpression": function(node) {
       let callee = node.callee;
       if (callee.type !== "MemberExpression" ||
           callee.property.type !== "Identifier") {
         return;
       }
 
+      if ((["getCharPref", "getBoolPref", "getIntPref", "clearUserPref"]
+           .indexOf(callee.property.name) != -1) &&
+          node.arguments.length > 1) {
+        context.report(node, callee.property.name + " takes only 1 parameter.");
+      }
+
       if (callee.property.name === "removeObserver" &&
           node.arguments.length === 3) {
         let arg = node.arguments[2];
         if (arg.type === "Literal" && (arg.value === false ||
                                        arg.value === true)) {
           context.report(node, "removeObserver only takes 2 parameters.");
         }
       }
--- a/tools/lint/eslint/eslint-plugin-mozilla/package.json
+++ b/tools/lint/eslint/eslint-plugin-mozilla/package.json
@@ -1,11 +1,11 @@
 {
   "name": "eslint-plugin-mozilla",
-  "version": "0.2.8",
+  "version": "0.2.10",
   "description": "A collection of rules that help enforce JavaScript coding standard in the Mozilla project.",
   "keywords": [
     "eslint",
     "eslintplugin",
     "eslint-plugin",
     "mozilla",
     "firefox"