Merge autoland to mozilla-central. a=merge
authorCiure Andrei <aciure@mozilla.com>
Wed, 11 Apr 2018 11:56:26 +0300
changeset 412733 f6c3a0a19d82db25750d8badccd5cf37e79d028e
parent 412732 d1db4d5030c827ada3c01ec9d2ab5d665de2cd59 (current diff)
parent 412704 279d83c6f6ed28e669028ffb98b2b176c98bb34f (diff)
child 412734 40d4e0214db560bedb460164c491f0dd5c79b64f
child 412838 9422362ff3fd216a47bd7973c8d37eff5c06e95d
push id62482
push useraciure@mozilla.com
push dateWed, 11 Apr 2018 08:59:59 +0000
treeherderautoland@40d4e0214db5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone61.0a1
first release with
nightly linux32
f6c3a0a19d82 / 61.0a1 / 20180411100123 / files
nightly linux64
f6c3a0a19d82 / 61.0a1 / 20180411100123 / files
nightly mac
f6c3a0a19d82 / 61.0a1 / 20180411100123 / files
nightly win32
f6c3a0a19d82 / 61.0a1 / 20180411100123 / files
nightly win64
f6c3a0a19d82 / 61.0a1 / 20180411100123 / 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 autoland to mozilla-central. a=merge
dom/html/HTMLInputElement.cpp
layout/style/res/number-control.css
--- a/browser/components/extensions/test/browser/browser-common.ini
+++ b/browser/components/extensions/test/browser/browser-common.ini
@@ -65,16 +65,17 @@ skip-if = (os == 'win' && !debug) # bug 
 [browser_ext_browsingData_serviceWorkers.js]
 [browser_ext_chrome_settings_overrides_home.js]
 [browser_ext_commands_execute_browser_action.js]
 [browser_ext_commands_execute_page_action.js]
 [browser_ext_commands_execute_sidebar_action.js]
 [browser_ext_commands_getAll.js]
 [browser_ext_commands_onCommand.js]
 [browser_ext_commands_update.js]
+[browser_ext_connect_and_move_tabs.js]
 [browser_ext_contentscript_connect.js]
 [browser_ext_contextMenus.js]
 [browser_ext_contextMenus_checkboxes.js]
 [browser_ext_contextMenus_commands.js]
 [browser_ext_contextMenus_icons.js]
 [browser_ext_contextMenus_onclick.js]
 [browser_ext_contextMenus_radioGroups.js]
 [browser_ext_contextMenus_uninstall.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_connect_and_move_tabs.js
@@ -0,0 +1,95 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+// Tests that the Port object created by browser.runtime.connect is not
+// prematurely disconnected as the underlying message managers change when a
+// tab is moved between windows.
+
+function loadExtension() {
+  return ExtensionTestUtils.loadExtension({
+    manifest: {
+      "content_scripts": [{
+        "js": ["script.js"],
+        "matches": ["http://mochi.test/"],
+      }],
+    },
+    background() {
+      browser.runtime.onConnect.addListener((port) => {
+        port.onDisconnect.addListener(() => {
+          browser.test.fail("onDisconnect should not fire because the port is to be closed from this side");
+          browser.test.sendMessage("port_disconnected");
+        });
+        port.onMessage.addListener(async msg => {
+          browser.test.assertEq("connect_from_contentscript", msg, "expected message");
+          // Move a tab to a new window and back. Regression test for bugzil.la/1448674
+          let {windowId, id: tabId, index} = port.sender.tab;
+          await browser.windows.create({tabId});
+          await browser.tabs.move(tabId, {index, windowId});
+          await browser.windows.create({tabId});
+          await browser.tabs.move(tabId, {index, windowId});
+          try {
+            // When the port is unexpectedly disconnected, postMessage will throw an error.
+            port.postMessage("ping");
+          } catch (e) {
+            browser.test.fail(`Error: ${e} :: ${e.stack}`);
+            browser.test.sendMessage("port_ping_ponged_before_disconnect");
+          }
+        });
+
+        browser.runtime.onMessage.addListener((msg, sender) => {
+          browser.test.assertEq("disconnect-me", msg, "expected message");
+          port.disconnect();
+          // Now port.onDisconnect should fire in the content script.
+        });
+      });
+
+      browser.test.onMessage.addListener(msg => {
+        browser.test.assertEq("open_extension_tab", msg, "expected message");
+        browser.tabs.create({url: "tab.html"});
+      });
+    },
+
+    files: {
+      "tab.html": `
+        <!DOCTYPE html><meta charset="utf-8">
+        <script src="script.js"></script>
+      `,
+      "script.js": function() {
+        let port = browser.runtime.connect();
+        port.onMessage.addListener(msg => {
+          browser.test.assertEq("ping", msg, "expected message");
+          browser.test.sendMessage("port_ping_ponged_before_disconnect");
+          port.onDisconnect.addListener(() => {
+            browser.test.sendMessage("port_disconnected");
+          });
+          browser.runtime.sendMessage("disconnect-me");
+        });
+        port.postMessage("connect_from_contentscript");
+      },
+    },
+  });
+}
+
+add_task(async function contentscript_connect_and_move_tabs() {
+  let extension = loadExtension();
+  await extension.startup();
+  await BrowserTestUtils.openNewForegroundTab(gBrowser, "http://mochi.test:8888/");
+  await extension.awaitMessage("port_ping_ponged_before_disconnect");
+  await extension.awaitMessage("port_disconnected");
+  // Must use gBrowser.selectedTab instead of the return value of
+  // BrowserTestUtils.openNewForegroundTab because the latter does not refer to
+  // the tab because the tab is moved between windows during the test.
+  await BrowserTestUtils.removeTab(gBrowser.selectedTab);
+  await extension.unload();
+});
+
+add_task(async function extension_tab_connect_and_move_tabs() {
+  let extension = loadExtension();
+  await extension.startup();
+  extension.sendMessage("open_extension_tab");
+  await extension.awaitMessage("port_ping_ponged_before_disconnect");
+  await extension.awaitMessage("port_disconnected");
+  // Upon unloading the extension, the extension tab is automatically removed.
+  await extension.unload();
+});
--- a/build/unix/build-gcc/build-gcc.sh
+++ b/build/unix/build-gcc/build-gcc.sh
@@ -24,37 +24,49 @@ prepare() {
   cd gcc-$gcc_version
 
   (
     # Divert commands that download_prerequisites use
     ln() { :; }
     tar() { :; }
     sed() { :; }
     wget() {
-      echo $1
+      # Get last argument given to wget.
+      eval echo \$$# >&3
     }
 
+    # In GCC >= 7, the download_prerequisites script tried to do its own
+    # verification, but we have ours, so disable it.
+    set -- --no-verify
     . ./contrib/download_prerequisites
-  ) | while read url; do
+  ) 3>&1 > /dev/null | while read url; do
     file=$(basename $url)
     case "$file" in
     gmp-*.tar.*)
       # If download_prerequisites wants 4.3.2, use 5.1.3 instead.
       file=${file/4.3.2/5.1.3}
       download_and_check https://gmplib.org/download/gmp $file.sig
       ;;
     mpfr-*.tar.*)
       # If download_prerequisites wants 2.4.2, use 3.1.5 instead.
       file=${file/2.4.2/3.1.5}
       download_and_check http://www.mpfr.org/${file%.tar.*} $file.asc
       ;;
     mpc-*.tar.*)
       # If download_prerequisites wants 0.8.1, use 0.8.2 instead.
       file=${file/0.8.1/0.8.2}
-      download_and_check http://www.multiprecision.org/downloads $file.asc
+      case "$file" in
+      *-0.8.2.tar*|*-0.9.tar*|*-1.0.tar*)
+        ext=asc
+        ;;
+      *)
+        ext=sig
+        ;;
+      esac
+      download_and_check http://www.multiprecision.org/downloads $file.$ext
       ;;
     *)
       download $(dirname $url) $file
       ;;
     esac
     tar xaf $TMPDIR/$file
     ln -sf ${file%.tar.*} ${file%-*}
   done
--- a/devtools/client/inspector/animation/components/AnimatedPropertyListContainer.js
+++ b/devtools/client/inspector/animation/components/AnimatedPropertyListContainer.js
@@ -50,16 +50,22 @@ class AnimatedPropertyListContainer exte
           addAnimationsCurrentTimeListener,
           animation,
           getAnimationsCurrentTime,
           removeAnimationsCurrentTimeListener,
           simulateAnimationForKeyframesProgressBar,
           timeScale,
         }
       ),
+      dom.div(
+        {
+          className: "animated-property-list-background",
+        },
+        dom.span()
+      ),
       AnimatedPropertyList(
         {
           animation,
           emitEventForTest,
           getAnimatedPropertyMap,
           getComputedStyle,
           simulateAnimation,
         }
--- a/devtools/client/inspector/animation/components/AnimatedPropertyListHeader.js
+++ b/devtools/client/inspector/animation/components/AnimatedPropertyListHeader.js
@@ -30,18 +30,23 @@ class AnimatedPropertyListHeader extends
       getAnimationsCurrentTime,
       removeAnimationsCurrentTimeListener,
       simulateAnimationForKeyframesProgressBar,
       timeScale,
     } = this.props;
 
     return dom.div(
       {
-        className: "animated-property-list-header devtools-toolbar"
+        className: "animated-property-list-header"
       },
+      dom.div(
+        {
+          className: "devtools-toolbar"
+        }
+      ),
       KeyframesProgressTickList(),
       KeyframesProgressBar(
         {
           addAnimationsCurrentTimeListener,
           animation,
           getAnimationsCurrentTime,
           removeAnimationsCurrentTimeListener,
           simulateAnimationForKeyframesProgressBar,
--- a/devtools/client/inspector/animation/components/AnimationListHeader.js
+++ b/devtools/client/inspector/animation/components/AnimationListHeader.js
@@ -28,18 +28,23 @@ class AnimationListHeader extends PureCo
       addAnimationsCurrentTimeListener,
       removeAnimationsCurrentTimeListener,
       setAnimationsCurrentTime,
       timeScale,
     } = this.props;
 
     return dom.div(
       {
-        className: "animation-list-header devtools-toolbar"
+        className: "animation-list-header"
       },
+      dom.div(
+        {
+          className: "devtools-toolbar"
+        }
+      ),
       AnimationTimelineTickList(
         {
           timeScale
         }
       ),
       CurrentTimeScrubberController(
         {
           addAnimationsCurrentTimeListener,
--- a/devtools/client/inspector/animation/components/CurrentTimeScrubberController.js
+++ b/devtools/client/inspector/animation/components/CurrentTimeScrubberController.js
@@ -35,18 +35,18 @@ class CurrentTimeScrubberController exte
       // offset of the position for the scrubber
       offset: 0,
     };
 
     addAnimationsCurrentTimeListener(this.onCurrentTimeUpdated);
   }
 
   componentDidMount() {
-    const parentEl = ReactDOM.findDOMNode(this).parentElement;
-    parentEl.addEventListener("mousedown", this.onMouseDown);
+    const el = ReactDOM.findDOMNode(this);
+    el.addEventListener("mousedown", this.onMouseDown);
   }
 
   componentWillUnmount() {
     const { removeAnimationsCurrentTimeListener } = this.props;
     removeAnimationsCurrentTimeListener(this.onCurrentTimeUpdated);
   }
 
   onCurrentTimeUpdated(currentTime) {
@@ -122,17 +122,17 @@ class CurrentTimeScrubberController exte
     setAnimationsCurrentTime(time, needRefresh);
   }
 
   render() {
     const { offset } = this.state;
 
     return dom.div(
       {
-        className: "current-time-scrubber-controller devtools-toolbar",
+        className: "current-time-scrubber-controller",
       },
       CurrentTimeScrubber(
         {
           offset,
         }
       )
     );
   }
--- a/devtools/client/inspector/animation/test/browser_animation_animation-timeline-tick.js
+++ b/devtools/client/inspector/animation/test/browser_animation_animation-timeline-tick.js
@@ -23,48 +23,48 @@ add_task(async function() {
   const timeScale = new TimeScale(animationInspector.state.animations);
 
   info("Checking animation list header element existence");
   const listContainerEl = panel.querySelector(".animation-list-container");
   const listHeaderEl = listContainerEl.querySelector(".devtools-toolbar");
   ok(listHeaderEl, "The header element should be in animation list container element");
 
   info("Checking time tick item elements existence");
-  assertTimelineTickItems(timeScale, listHeaderEl);
+  assertTimelineTickItems(timeScale, listContainerEl);
   const timelineTickItemLength =
-    listHeaderEl.querySelectorAll(".animation-timeline-tick-item").length;
+    listContainerEl.querySelectorAll(".animation-timeline-tick-item").length;
 
   info("Checking timeline tick item elements after enlarge sidebar width");
   await setSidebarWidth("100%", inspector);
-  assertTimelineTickItems(timeScale, listHeaderEl);
+  assertTimelineTickItems(timeScale, listContainerEl);
   ok(timelineTickItemLength <
-    listHeaderEl.querySelectorAll(".animation-timeline-tick-item").length,
+     listContainerEl.querySelectorAll(".animation-timeline-tick-item").length,
      "The timeline tick item elements should increase");
 });
 
 /**
  * Assert timeline tick item's position and label.
  *
  * @param {TimeScale} - timeScale
- * @param {Element} - listHeaderEl which is header element
+ * @param {Element} - listContainerEl
  */
-function assertTimelineTickItems(timeScale, listHeaderEl) {
-  const animationTimelineTickListEl =
-    listHeaderEl.querySelector(".animation-timeline-tick-list");
-  ok(animationTimelineTickListEl,
+function assertTimelineTickItems(timeScale, listContainerEl) {
+  const timelineTickListEl =
+    listContainerEl.querySelector(".animation-timeline-tick-list");
+  ok(timelineTickListEl,
     "The animation timeline tick list element should be in header");
 
-  const width = animationTimelineTickListEl.offsetWidth;
+  const width = timelineTickListEl.offsetWidth;
   const animationDuration = timeScale.getDuration();
   const minTimeInterval = TIME_GRADUATION_MIN_SPACING * animationDuration / width;
   const interval = findOptimalTimeInterval(minTimeInterval);
   const expectedTickItem = Math.ceil(animationDuration / interval);
 
   const timelineTickItemEls =
-    listHeaderEl.querySelectorAll(".animation-timeline-tick-item");
+    timelineTickListEl.querySelectorAll(".animation-timeline-tick-item");
   is(timelineTickItemEls.length, expectedTickItem,
     "The expected number of timeline ticks were found");
 
   info("Make sure graduations are evenly distributed and show the right times");
   for (const [index, tickEl] of timelineTickItemEls.entries()) {
     const left = parseFloat(tickEl.style.left);
     const expectedPos = index * interval * 100 / animationDuration;
     is(Math.round(left), Math.round(expectedPos),
--- a/devtools/client/netmonitor/src/actions/ui.js
+++ b/devtools/client/netmonitor/src/actions/ui.js
@@ -12,25 +12,33 @@ const {
   DISABLE_BROWSER_CACHE,
   OPEN_STATISTICS,
   RESET_COLUMNS,
   SELECT_DETAILS_PANEL_TAB,
   TOGGLE_COLUMN,
   WATERFALL_RESIZE,
 } = require("../constants");
 
+const { getDisplayedRequests } = require("../selectors/index");
+
 /**
  * Change network details panel.
  *
  * @param {boolean} open - expected network details panel open state
  */
 function openNetworkDetails(open) {
-  return {
-    type: OPEN_NETWORK_DETAILS,
-    open,
+  return (dispatch, getState) => {
+    const visibleRequestItems = getDisplayedRequests(getState());
+    let defaultSelectedId = visibleRequestItems.length ? visibleRequestItems[0].id : null;
+
+    return dispatch({
+      type: OPEN_NETWORK_DETAILS,
+      open,
+      defaultSelectedId,
+    });
   };
 }
 
 /**
  * Change network details panel size.
  *
  * @param {integer} width
  * @param {integer} height
--- a/devtools/client/netmonitor/src/reducers/requests.js
+++ b/devtools/client/netmonitor/src/reducers/requests.js
@@ -172,18 +172,18 @@ function requestsReducer(state = Request
     // Side bar with request details opened.
     case OPEN_NETWORK_DETAILS: {
       let nextState = { ...state };
       if (!action.open) {
         nextState.selectedId = null;
         return nextState;
       }
 
-      if (!state.selectedId && state.requests.size > 0) {
-        nextState.selectedId = [...state.requests.values()][0].id;
+      if (!state.selectedId && action.defaultSelectedId) {
+        nextState.selectedId = action.defaultSelectedId;
         return nextState;
       }
 
       return state;
     }
 
     default:
       return state;
--- a/devtools/client/netmonitor/test/browser.ini
+++ b/devtools/client/netmonitor/test/browser.ini
@@ -137,16 +137,17 @@ skip-if = (os == 'linux' && debug && bit
 [browser_net_json_text_mime.js]
 [browser_net_jsonp.js]
 [browser_net_large-response.js]
 [browser_net_leak_on_tab_close.js]
 [browser_net_open_in_debugger.js]
 [browser_net_open_in_style_editor.js]
 [browser_net_open_request_in_tab.js]
 [browser_net_pane-collapse.js]
+[browser_net_pane-network-details.js]
 [browser_net_pane-toggle.js]
 [browser_net_pause.js]
 [browser_net_params_sorted.js]
 [browser_net_persistent_logs.js]
 [browser_net_post-data-01.js]
 [browser_net_post-data-02.js]
 [browser_net_post-data-03.js]
 [browser_net_post-data-04.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/test/browser_net_pane-network-details.js
@@ -0,0 +1,127 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/**
+ * Test the action of request details panel when filters are applied.
+ * If there are any visible requests, the first request from the
+ * list of visible requests should be displayed in the network
+ * details panel
+ * If there are no visible requests the panel should remain closed
+ */
+
+const REQUESTS_WITH_MEDIA_AND_FLASH_AND_WS = [
+  { url: "sjs_content-type-test-server.sjs?fmt=html&res=undefined&text=Sample" },
+  { url: "sjs_content-type-test-server.sjs?fmt=css&text=sample" },
+  { url: "sjs_content-type-test-server.sjs?fmt=js&text=sample" },
+  { url: "sjs_content-type-test-server.sjs?fmt=font" },
+  { url: "sjs_content-type-test-server.sjs?fmt=image" },
+  { url: "sjs_content-type-test-server.sjs?fmt=audio" },
+  { url: "sjs_content-type-test-server.sjs?fmt=video" },
+  { url: "sjs_content-type-test-server.sjs?fmt=flash" },
+  { url: "sjs_content-type-test-server.sjs?fmt=ws" },
+];
+
+add_task(async function() {
+  let { monitor } = await initNetMonitor(FILTERING_URL);
+  let { document, store, windowRequire } = monitor.panelWin;
+  let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
+  let {
+    getSelectedRequest,
+    getSortedRequests,
+  } = windowRequire("devtools/client/netmonitor/src/selectors/index");
+
+  store.dispatch(Actions.batchEnable(false));
+
+  function setFreetextFilter(value) {
+    store.dispatch(Actions.setRequestFilterText(value));
+  }
+
+  info("Starting test... ");
+
+  let wait = waitForNetworkEvents(monitor, 9);
+  loadFrameScriptUtils();
+  await performRequestsInContent(REQUESTS_WITH_MEDIA_AND_FLASH_AND_WS);
+  await wait;
+
+  let toggleButton = document.querySelector(".network-details-panel-toggle");
+
+  info("Test with the first request in the list visible");
+  EventUtils.sendMouseEvent({ type: "click" },
+      document.querySelector(".requests-list-filter-all-button"));
+  testDetailsPanel(true, 0);
+
+  info("Test with first request in the list not visible");
+  EventUtils.sendMouseEvent({ type: "click" },
+      document.querySelector(".requests-list-filter-all-button"));
+  EventUtils.sendMouseEvent({ type: "click" },
+      document.querySelector(".requests-list-filter-js-button"));
+  testFilterButtons(monitor, "js");
+  testDetailsPanel(true, 2);
+
+  info("Test with no request in the list visible i.e. no request match the filters");
+  EventUtils.sendMouseEvent({ type: "click" },
+      document.querySelector(".requests-list-filter-all-button"));
+  setFreetextFilter("foobar");
+  // The network details panel should not open as there are no available requests visible
+  testDetailsPanel(false);
+
+  await teardown(monitor);
+
+  function getSelectedIndex(state) {
+    if (!state.requests.selectedId) {
+      return -1;
+    }
+    return getSortedRequests(state).findIndex(r => r.id === state.requests.selectedId);
+  }
+
+  async function testDetailsPanel(shouldPanelOpen, selectedItemIndex = 0) {
+    // Expected default state should be panel closed
+    if (shouldPanelOpen) {
+      // Toggle switch should be enabled only when there are visible requests
+      is(toggleButton.hasAttribute("disabled"), false,
+          "The pane toggle button should be enabled.");
+    } else {
+      is(toggleButton.hasAttribute("disabled"), true,
+          "The pane toggle button should be disabled.");
+    }
+
+    is(toggleButton.classList.contains("pane-collapsed"), true,
+        "The pane toggle button should still indicate that the details pane is " +
+        "collapsed.");
+    is(!!document.querySelector(".network-details-panel"), false,
+        "The details pane should still be hidden.");
+    is(getSelectedRequest(store.getState()), null,
+        "There should still be no selected item in the requests menu.");
+
+    // Trigger the details panel toggle action
+    EventUtils.sendMouseEvent({ type: "click" }, toggleButton);
+
+    if (shouldPanelOpen) {
+      is(toggleButton.hasAttribute("disabled"), false,
+          "The pane toggle button should still be enabled after being pressed.");
+      is(toggleButton.classList.contains("pane-collapsed"), false,
+          "The pane toggle button should now indicate that the details pane is " +
+          "not collapsed anymore after being pressed.");
+      is(!!document.querySelector(".network-details-panel"), true,
+          "The details pane should not be hidden after toggle button was pressed.");
+      isnot(getSelectedRequest(store.getState()), null,
+          "There should be a selected item in the requests menu.");
+      is(getSelectedIndex(store.getState()), selectedItemIndex,
+          `The item index ${selectedItemIndex} should be selected in the requests menu.`);
+      // Close the panel
+      EventUtils.sendMouseEvent({ type: "click" }, toggleButton);
+    } else {
+      is(toggleButton.hasAttribute("disabled"), true,
+          "The pane toggle button should be disabled.");
+      is(toggleButton.classList.contains("pane-collapsed"), true,
+          "The pane toggle button should still indicate that the details pane is " +
+          "collapsed.");
+      is(!!document.querySelector(".network-details-panel"), false,
+          "The details pane should still be hidden.");
+      is(getSelectedRequest(store.getState()), null,
+          "There should still be no selected item in the requests menu.");
+    }
+  }
+});
--- a/devtools/client/themes/animation.css
+++ b/devtools/client/themes/animation.css
@@ -2,16 +2,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/. */
 
 /* Animation-inspector specific theme variables */
 
 :root {
   --animation-even-background-color: rgba(0, 0, 0, 0.05);
   --command-pick-image: url(chrome://devtools/skin/images/command-pick.svg);
+  --devtools-toolbar-height: 24px;
   --fast-track-image: url("images/animation-fast-track.svg");
   --fill-color-cssanimation: var(--theme-contrast-background);
   --fill-color-csstransition: var(--theme-highlight-blue);
   --fill-color-scriptanimation: var(--theme-graphs-green);
   --graph-right-offset: 10px;
   --keyframe-marker-shadow-color: #c4c4c4;
   --pause-image: url(chrome://devtools/skin/images/pause.svg);
   --progress-bar-color: #909090;
@@ -42,17 +43,17 @@
   overflow: hidden;
 }
 
 #animation-container:not(.animation-detail-visible) .controlled {
   display: none;
 }
 
 #animation-container .animation-container-splitter {
-  overflow: auto;
+  overflow: hidden;
 }
 
 /* Animation Toolbar */
 .animation-toolbar {
   display: flex;
 }
 
 .pause-resume-button::before {
@@ -81,59 +82,89 @@ select.playback-rate-selector.devtools-b
 }
 
 .rewind-button::before {
   background-image: var(--rewind-image);
 }
 
 /* Animation List Container */
 .animation-list-container {
-  display: flex;
-  flex-direction: column;
   height: 100%;
-  overflow: hidden;
+  overflow-y: auto;
+  overflow-x: hidden;
+  position: relative;
   width: 100%;
   -moz-user-select: none;
 }
 
 .animation-list-container.active-scrubber {
   cursor: col-resize;
 }
 
 /* Animation List Header */
 .animation-list-header {
   display: grid;
   grid-template-columns: var(--sidebar-width) calc(100% - var(--sidebar-width) - var(--graph-right-offset)) var(--graph-right-offset);
+  line-height: var(--devtools-toolbar-height);
+  min-height: 100%;
   padding: 0;
+  pointer-events: none;
+  position: sticky;
+  top: 0;
+  z-index: 2;
+}
+
+.animation-list-header .devtools-toolbar {
+  position: absolute;
+  width: 100%;
 }
 
 /* Animation Timeline Tick List */
 .animation-timeline-tick-list {
   grid-column: 2/3;
+  height: 100%;
   position: relative;
 }
 
 .animation-timeline-tick-item {
+  height: 100%;
+  position: absolute;
+}
+
+.animation-timeline-tick-item::before {
   border-left: var(--tick-line-style);
-  height: 100vh;
-  pointer-events: none;
+  content: "";
+  height: 100%;
   position: absolute;
 }
 
 /* Current Time Scrubber */
 .current-time-scrubber-controller {
+  grid-column: 2 / 3;
+  height: 100%;
+  padding: 0;
+  position: absolute;
+  width: 100%;
+}
+
+.current-time-scrubber-controller::before {
+  content: "";
   cursor: col-resize;
-  grid-column: 2 / 3;
-  padding: 0;
+  height: var(--devtools-toolbar-height);
+  pointer-events: auto;
+  position: absolute;
+  /* In order to click on edge of current-time-scrubber-controller element */
+  width: calc(100% + 1px);
 }
 
 .current-time-scrubber {
   cursor: col-resize;
-  height: 100vh;
+  height: 100%;
   margin-left: -6px;
+  pointer-events: auto;
   position: absolute;
   width: 12px;
   z-index: 1;
 }
 
 .current-time-scrubber::before {
   border-left: 5px solid transparent;
   border-right: 5px solid transparent;
@@ -151,21 +182,22 @@ select.playback-rate-selector.devtools-b
   left: 5px;
   position: absolute;
   top: 0;
   width: 0;
 }
 
 /* Animation List */
 .animation-list {
-  flex: 1;
   list-style-type: none;
   margin: 0;
-  overflow: auto;
   padding: 0;
+  position: absolute;
+  top: var(--devtools-toolbar-height);
+  width: 100%;
 }
 
 /* Animation Item */
 .animation-item {
   display: flex;
   height: 30px;
 }
 
@@ -229,18 +261,18 @@ select.playback-rate-selector.devtools-b
   content: "";
   display: block;
   fill: var(--theme-content-color3);
   height: 100%;
   position: absolute;
   right: 0;
   top: 5px;
   width: 15px;
+  -moz-context-properties: fill;
   z-index: 1;
-  -moz-context-properties: fill;
 }
 
 .animation-summary-graph-path {
   height: 100%;
   width: 100%;
 }
 
 .animation-computed-timing-path path {
@@ -358,56 +390,70 @@ select.playback-rate-selector.devtools-b
   background-image: url(chrome://devtools/skin/images/close.svg);
 }
 
 /* Animated Property List Container */
 .animated-property-list-container {
   display: flex;
   flex: 1;
   flex-direction: column;
-  overflow: hidden;
+  overflow-y: auto;
+  position: relative;
 }
 
 /* Animated Property List Header */
 .animated-property-list-header {
   display: grid;
   grid-template-columns: var(--sidebar-width) calc(100% - var(--sidebar-width) - var(--graph-right-offset)) var(--graph-right-offset);
+  line-height: var(--devtools-toolbar-height);
+  min-height: 100%;
   padding: 0;
+  pointer-events: none;
+  position: sticky;
+  top: 0;
+  z-index: 1;
+}
+
+.animated-property-list-header .devtools-toolbar {
+  position: absolute;
+  width: 100%;
 }
 
 /* Keyframes Progress Tick List */
 .keyframes-progress-tick-list {
   grid-column: 2 / 3;
-  position: relative;
+  height: 100%;
+  position: absolute;
+  width: 100%;
 }
 
 .keyframes-progress-tick-item {
-  height: 100vh;
   position: absolute;
 }
 
 .keyframes-progress-tick-item.left {
   border-left: var(--tick-line-style);
 }
 
 .keyframes-progress-tick-item.right {
   border-right: var(--tick-line-style);
 }
 
 /* Keyframes Progress Bar */
 .keyframes-progress-bar-area {
   background: none;
   grid-column: 2 / 3;
   padding: 0;
-  pointer-events: none;
-  position: relative;
+  height: 100%;
+  position: absolute;
+  width: 100%;
 }
 
 .keyframes-progress-bar {
-  height: 100vh;
+  height: 100%;
   position: absolute;
   z-index: 1;
 }
 
 .keyframes-progress-bar::before {
   border-left: 5px solid transparent;
   border-right: 5px solid transparent;
   border-top: 5px solid var(--progress-bar-color);
@@ -423,22 +469,42 @@ select.playback-rate-selector.devtools-b
   content: "";
   height: 100%;
   position: absolute;
   top: 0;
   width: 0;
 }
 
 /* Animated Property List */
+.animated-property-list-background {
+  border-left: var(--tick-line-style);
+  border-right: var(--tick-line-style);
+  bottom: 0;
+	left: var(--sidebar-width);
+  min-height: 100%;
+	position: sticky;
+  top: 0;
+	width: calc(100% - var(--sidebar-width) - var(--graph-right-offset));
+}
+
+.animated-property-list-background span {
+  border-left: var(--tick-line-style);
+	height: 100%;
+	left: 50%;
+	position: absolute;
+}
+
 .animated-property-list {
   flex: 1;
   list-style-type: none;
   margin: 0;
-  overflow-y: auto;
   padding: 0;
+  position: absolute;
+  top: var(--devtools-toolbar-height);
+  width: 100%;
 }
 
 /* Animated Property Item */
 .animated-property-item {
   display: flex;
   height: 30px;
 }
 
@@ -491,18 +557,18 @@ select.playback-rate-selector.devtools-b
 }
 
 .animated-property-name.warning span {
   text-decoration: underline dotted;
 }
 
 /* Keyframes Graph */
 .keyframes-graph {
+  padding-top: 3px;
   height: 100%;
-  padding-top: 3px;
   position: relative;
   width: calc(100% - var(--sidebar-width) - var(--graph-right-offset));
 }
 
 .keyframes-graph-path {
   height: 100%;
   width: 100%;
 }
--- a/devtools/shared/css/generated/properties-db.js
+++ b/devtools/shared/css/generated/properties-db.js
@@ -3106,17 +3106,16 @@ exports.CSS_PROPERTIES = {
       "stroke",
       "stroke-dasharray",
       "stroke-dashoffset",
       "stroke-linecap",
       "stroke-linejoin",
       "stroke-miterlimit",
       "stroke-opacity",
       "stroke-width",
-      "-x-system-font",
       "-moz-tab-size",
       "table-layout",
       "text-align",
       "text-align-last",
       "text-anchor",
       "text-combine-upright",
       "text-decoration-color",
       "text-decoration-line",
@@ -5715,17 +5714,16 @@ exports.CSS_PROPERTIES = {
     "subproperties": [
       "font-family",
       "font-style",
       "font-weight",
       "font-size",
       "line-height",
       "font-size-adjust",
       "font-stretch",
-      "-x-system-font",
       "font-feature-settings",
       "font-language-override",
       "font-kerning",
       "font-optical-sizing",
       "font-variation-settings",
       "font-variant-alternates",
       "font-variant-caps",
       "font-variant-east-asian",
--- a/dom/animation/test/chrome/test_animation_properties.html
+++ b/dom/animation/test/chrome/test_animation_properties.html
@@ -151,19 +151,18 @@ var gTests = [
                             valueFormat(1, 'dashed', 'replace') ] },
                 { property: 'border-top-style',
                   values: [ valueFormat(0, 'dotted', 'replace', 'linear'),
                             valueFormat(1, 'dashed', 'replace') ] },
                 { property: 'border-image-outset',
                   values: [ valueFormat(0, '0', 'replace', 'linear'),
                             valueFormat(1, '0', 'replace') ] },
                 { property: 'border-image-repeat',
-                  values: [ valueFormat(0,
-                                        'stretch stretch', 'replace', 'linear'),
-                            valueFormat(1, 'stretch stretch', 'replace') ] },
+                  values: [ valueFormat(0, 'stretch', 'replace', 'linear'),
+                            valueFormat(1, 'stretch', 'replace') ] },
                 { property: 'border-image-slice',
                   values: [ valueFormat(0, '100%', 'replace', 'linear'),
                             valueFormat(1, '100%', 'replace') ] },
                 { property: 'border-image-source',
                   values: [ valueFormat(0, 'none', 'replace', 'linear'),
                             valueFormat(1, 'none', 'replace') ] },
                 { property: 'border-image-width',
                   values: [ valueFormat(0, '1', 'replace', 'linear'),
@@ -211,19 +210,18 @@ var gTests = [
                             valueFormat(1, 'dashed', 'replace') ] },
                 { property: 'border-top-style',
                   values: [ valueFormat(0, 'dotted', 'replace', 'linear'),
                             valueFormat(1, 'dashed', 'replace') ] },
                 { property: 'border-image-outset',
                   values: [ valueFormat(0, '0', 'replace', 'linear'),
                             valueFormat(1, '0', 'replace') ] },
                 { property: 'border-image-repeat',
-                  values: [ valueFormat(0,
-                                        'stretch stretch', 'replace', 'linear'),
-                            valueFormat(1, 'stretch stretch', 'replace') ] },
+                  values: [ valueFormat(0, 'stretch', 'replace', 'linear'),
+                            valueFormat(1, 'stretch', 'replace') ] },
                 { property: 'border-image-slice',
                   values: [ valueFormat(0, '100%', 'replace', 'linear'),
                             valueFormat(1, '100%', 'replace') ] },
                 { property: 'border-image-source',
                   values: [ valueFormat(0, 'none', 'replace', 'linear'),
                             valueFormat(1, 'none', 'replace') ] },
                 { property: 'border-image-width',
                   values: [ valueFormat(0, '1', 'replace', 'linear'),
@@ -480,19 +478,18 @@ var gTests = [
                             valueFormat(1, 'dashed', 'replace') ] },
                 { property: 'border-top-style',
                   values: [ valueFormat(0, 'dotted', 'replace', 'linear'),
                             valueFormat(1, 'dashed', 'replace') ] },
                 { property: 'border-image-outset',
                   values: [ valueFormat(0, '0', 'replace', 'linear'),
                             valueFormat(1, '0', 'replace') ] },
                 { property: 'border-image-repeat',
-                  values: [ valueFormat(0,
-                                        'stretch stretch', 'replace', 'linear'),
-                            valueFormat(1, 'stretch stretch', 'replace') ] },
+                  values: [ valueFormat(0, 'stretch', 'replace', 'linear'),
+                            valueFormat(1, 'stretch', 'replace') ] },
                 { property: 'border-image-slice',
                   values: [ valueFormat(0, '100%', 'replace', 'linear'),
                             valueFormat(1, '100%', 'replace') ] },
                 { property: 'border-image-source',
                   values: [ valueFormat(0, 'none', 'replace', 'linear'),
                             valueFormat(1, 'none', 'replace') ] },
                 { property: 'border-image-width',
                   values: [ valueFormat(0, '1', 'replace', 'linear'),
@@ -539,19 +536,18 @@ var gTests = [
                             valueFormat(1, 'dashed', 'replace') ] },
                 { property: 'border-top-style',
                   values: [ valueFormat(0, 'dotted', 'replace', 'linear'),
                             valueFormat(1, 'dashed', 'replace') ] },
                 { property: 'border-image-outset',
                   values: [ valueFormat(0, '0', 'replace', 'linear'),
                             valueFormat(1, '0', 'replace') ] },
                 { property: 'border-image-repeat',
-                  values: [ valueFormat(0,
-                                        'stretch stretch', 'replace', 'linear'),
-                            valueFormat(1, 'stretch stretch', 'replace') ] },
+                  values: [ valueFormat(0, 'stretch', 'replace', 'linear'),
+                            valueFormat(1, 'stretch', 'replace') ] },
                 { property: 'border-image-slice',
                   values: [ valueFormat(0, '100%', 'replace', 'linear'),
                             valueFormat(1, '100%', 'replace') ] },
                 { property: 'border-image-source',
                   values: [ valueFormat(0, 'none', 'replace', 'linear'),
                             valueFormat(1, 'none', 'replace') ] },
                 { property: 'border-image-width',
                   values: [ valueFormat(0, '1', 'replace', 'linear'),
--- a/dom/gamepad/windows/WindowsGamepad.cpp
+++ b/dom/gamepad/windows/WindowsGamepad.cpp
@@ -244,26 +244,26 @@ UnpackDpad(LONG dpad_value, const Gamepa
   }
 
   // Normalize value to start at 0.
   int value = dpad_value - gamepad->dpadCaps.LogicalMin;
 
   // Value will be in the range 0-7. The value represents the
   // position of the d-pad around a circle, with 0 being straight up,
   // 2 being right, 4 being straight down, and 6 being left.
-  if (value < 2 || value > 6) {
+  if ((value < 2 || value > 6) && buttons.Length() > kUp) {
     buttons[kUp] = true;
   }
-  if (value > 2 && value < 6) {
+  if ((value > 2 && value < 6) && buttons.Length() > kDown) {
     buttons[kDown] = true;
   }
-  if (value > 4) {
+  if (value > 4 && buttons.Length() > kLeft) {
     buttons[kLeft] = true;
   }
-  if (value > 0 && value < 4) {
+  if ((value > 0 && value < 4) && buttons.Length() > kRight) {
     buttons[kRight] = true;
   }
 }
 
 /*
  * Return true if this USB HID usage page and usage are of a type we
  * know how to handle.
  */
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -5656,30 +5656,16 @@ HTMLInputElement::IsInputDateTimeOthersE
     Preferences::AddBoolVarCache(&sDateTimeOthersEnabled,
                                  "dom.forms.datetime.others", false);
   }
 
   return sDateTimeOthersEnabled;
 }
 
 /* static */ bool
-HTMLInputElement::IsInputNumberEnabled()
-{
-  static bool sInputNumberEnabled = false;
-  static bool sInputNumberPrefCached = false;
-  if (!sInputNumberPrefCached) {
-    sInputNumberPrefCached = true;
-    Preferences::AddBoolVarCache(&sInputNumberEnabled, "dom.forms.number",
-                                 false);
-  }
-
-  return sInputNumberEnabled;
-}
-
-/* static */ bool
 HTMLInputElement::IsInputColorEnabled()
 {
   static bool sInputColorEnabled = false;
   static bool sInputColorPrefCached = false;
   if (!sInputColorPrefCached) {
     sInputColorPrefCached = true;
     Preferences::AddBoolVarCache(&sInputColorEnabled, "dom.forms.color",
                                  false);
@@ -5705,18 +5691,17 @@ HTMLInputElement::ParseAttribute(int32_t
   MOZ_ASSERT(kInputTypeTable[ArrayLength(kInputTypeTable) - 2].value ==
                NS_FORM_INPUT_TEXT,
              "Next to last entry in the table must be the \"text\" entry");
 
   if (aNamespaceID == kNameSpaceID_None) {
     if (aAttribute == nsGkAtoms::type) {
       aResult.ParseEnumValue(aValue, kInputTypeTable, false, kInputDefaultType);
       int32_t newType = aResult.GetEnumValue();
-      if ((newType == NS_FORM_INPUT_NUMBER && !IsInputNumberEnabled()) ||
-          (newType == NS_FORM_INPUT_COLOR && !IsInputColorEnabled()) ||
+      if ((newType == NS_FORM_INPUT_COLOR && !IsInputColorEnabled()) ||
           (IsDateTimeInputType(newType) && !IsDateTimeTypeSupported(newType))) {
         // There's no public way to set an nsAttrValue to an enum value, but we
         // can just re-parse with a table that doesn't have any types other than
         // "text" in it.
         aResult.ParseEnumValue(aValue, kInputDefaultType, false, kInputDefaultType);
       }
 
       return true;
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -1752,23 +1752,16 @@ private:
   /**
    * Checks preference "dom.forms.datetime.others" to determine if input week,
    * month and datetime-local should be supported.
    */
   static bool
   IsInputDateTimeOthersEnabled();
 
   /**
-   * Checks preference "dom.forms.number" to determine if input type=number
-   * should be supported.
-   */
-  static bool
-  IsInputNumberEnabled();
-
-  /**
    * Checks preference "dom.forms.color" to determine if date/time related
    * types should be supported.
    */
   static bool
   IsInputColorEnabled();
 
   struct nsFilePickerFilter {
     nsFilePickerFilter()
--- a/dom/html/reftests/autofocus/reftest.list
+++ b/dom/html/reftests/autofocus/reftest.list
@@ -1,9 +1,9 @@
-default-preferences pref(dom.forms.number,true) pref(dom.forms.datetime,true)
+default-preferences pref(dom.forms.datetime,true)
 fuzzy-if(skiaContent,1,3) needs-focus == input-load.html input-ref.html
 fuzzy-if(skiaContent,1,3) needs-focus == input-create.html input-ref.html
 fuzzy-if(skiaContent,1,3) needs-focus == input-number.html input-number-ref.html
 fuzzy-if(skiaContent,1,3) needs-focus == input-time.html input-time-ref.html
 fuzzy-if(skiaContent,1,3) needs-focus == button-load.html button-ref.html
 fuzzy-if(skiaContent,1,3) needs-focus == button-create.html button-ref.html
 fuzzy-if(skiaContent,1,3) needs-focus == textarea-load.html textarea-ref.html
 fuzzy-if(skiaContent,1,3) needs-focus == textarea-create.html textarea-ref.html
--- a/dom/html/test/forms/test_input_types_pref.html
+++ b/dom/html/test/forms/test_input_types_pref.html
@@ -15,24 +15,16 @@ https://bugzilla.mozilla.org/show_bug.cg
 </div>
 <pre id="test">
 <script type="application/javascript">
 
   var input = document.createElement("input");
 
   var testData = [
     {
-      prefs: [["dom.forms.number", false]],
-      inputType: "number",
-      expectedType: "text"
-    }, {
-      prefs: [["dom.forms.number", true]],
-      inputType: "number",
-      expectedType: "number"
-    }, {
       prefs: [["dom.forms.color", false]],
       inputType: "color",
       expectedType: "text"
     }, {
       prefs: [["dom.forms.color", true]],
       inputType: "color",
       expectedType: "color"
     }, {
--- a/dom/svg/SVGDocument.cpp
+++ b/dom/svg/SVGDocument.cpp
@@ -152,21 +152,16 @@ SVGDocument::EnsureNonSVGUserAgentStyleS
           }
         }
       }
     }
   }
 
   auto cache = nsLayoutStylesheetCache::Singleton();
 
-  StyleSheet* sheet = cache->NumberControlSheet();
-  if (sheet) {
-    // number-control.css can be behind a pref
-    EnsureOnDemandBuiltInUASheet(sheet);
-  }
   EnsureOnDemandBuiltInUASheet(cache->FormsSheet());
   EnsureOnDemandBuiltInUASheet(cache->CounterStylesSheet());
   EnsureOnDemandBuiltInUASheet(cache->HTMLSheet());
   if (nsLayoutUtils::ShouldUseNoFramesSheet(this)) {
     EnsureOnDemandBuiltInUASheet(cache->NoFramesSheet());
   }
   if (nsLayoutUtils::ShouldUseNoScriptSheet(this)) {
     EnsureOnDemandBuiltInUASheet(cache->NoScriptSheet());
--- a/image/test/reftest/downscaling/reftest.list
+++ b/image/test/reftest/downscaling/reftest.list
@@ -21,20 +21,20 @@
 # Also note that Mac OS X has its own system-level downscaling algorithm, so
 # tests here may need Mac-specific "fuzzy-if(cocoaWidget,...)" annotations.
 # Similarly, modern versions of Windows have slightly different downscaling
 # behavior than other platforms, and may require "fuzzy-if(winWidget,...)".
 
 
 # RUN TESTS NOT AFFECTED BY DOWNSCALE-DURING-DECODE:
 # ==================================================
-fuzzy-if(skiaContent,14,416) fuzzy-if(webrender,102-102,396-396) fails-if(webrender&&winWidget) == downscale-svg-1a.html downscale-svg-1-ref.html?80
-fuzzy(80,468) fuzzy-if(webrender,65-65,579-579) fails-if(webrender&&winWidget) == downscale-svg-1b.html downscale-svg-1-ref.html?72
+fuzzy-if(skiaContent,14,416) fuzzy-if(webrender,102-102,396-472) == downscale-svg-1a.html downscale-svg-1-ref.html?80
+fuzzy(80,468) fuzzy-if(webrender,65-65,579-580) == downscale-svg-1b.html downscale-svg-1-ref.html?72
 fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),1,62) fuzzy-if(skiaContent,8,292) fuzzy-if(webrender,14-14,316-316) == downscale-svg-1c.html downscale-svg-1-ref.html?64
-fuzzy(17,208) fuzzy-if(webrender,83-83,325-325) fails-if(webrender&&winWidget) == downscale-svg-1d.html downscale-svg-1-ref.html?53
+fuzzy(17,208) fuzzy-if(webrender,83-84,274-325) == downscale-svg-1d.html downscale-svg-1-ref.html?53
 fuzzy(80,216) fuzzy-if(skiaContent,110,181) fuzzy-if(webrender,84-84,216-216) == downscale-svg-1e.html downscale-svg-1-ref.html?40
 fuzzy(51,90) fuzzy-if(skiaContent,142,77) fuzzy-if(webrender,62-62,98-98) == downscale-svg-1f.html downscale-svg-1-ref.html?24
 
 # RUN TESTS WITH DOWNSCALE-DURING-DECODE DISABLED:
 # ================================================
 default-preferences pref(image.downscale-during-decode.enabled,false)
 
 fuzzy-if(winWidget,16,20) fuzzy-if(cocoaWidget,106,31) == downscale-1.html downscale-1-ref.html
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -2403,21 +2403,16 @@ nsDocumentViewer::CreateStyleSet(nsIDocu
     // !!! SVGDocument::EnsureNonSVGUserAgentStyleSheetsLoaded.
 
     // SVGForeignObjectElement::BindToTree calls SVGDocument::
     // EnsureNonSVGUserAgentStyleSheetsLoaded to loads these UA sheet
     // on-demand. (Excluding the quirks sheet, which should never be loaded for
     // an SVG document, and excluding xul.css which will be loaded on demand by
     // nsXULElement::BindToTree.)
 
-    sheet = cache->NumberControlSheet();
-    if (sheet) {
-      styleSet->PrependStyleSheet(SheetType::Agent, sheet->AsServo());
-    }
-
     sheet = cache->FormsSheet();
     if (sheet) {
       styleSet->PrependStyleSheet(SheetType::Agent, sheet->AsServo());
     }
 
     if (aDocument->LoadsFullXULStyleSheetUpFront()) {
       // This is the only place components.css gets loaded, unlike xul.css
       sheet = cache->XULComponentsSheet();
--- a/layout/inspector/InspectorUtils.cpp
+++ b/layout/inspector/InspectorUtils.cpp
@@ -401,27 +401,31 @@ static void InsertNoDuplicates(nsTArray<
     return;
   }
   aArray.InsertElementAt(i, aString);
 }
 
 static void GetKeywordsForProperty(const nsCSSPropertyID aProperty,
                                    nsTArray<nsString>& aArray)
 {
+  const nsCSSProps::KTableEntry* keywordTable;
   if (nsCSSProps::IsShorthand(aProperty)) {
-    // Shorthand props have no keywords.
-    return;
-  }
-  const nsCSSProps::KTableEntry* keywordTable =
-    nsCSSProps::kKeywordTableTable[aProperty];
-
-  // Special cases where nsCSSPropList.h doesn't hold the table.
-  if (keywordTable == nullptr) {
-    if (aProperty == eCSSProperty_clip_path) {
-      keywordTable = nsCSSProps::kClipPathGeometryBoxKTable;
+    if (aProperty == eCSSProperty_font) {
+      keywordTable = nsCSSProps::kFontKTable;
+    } else {
+      // Other shorthand props have no keywords.
+      return;
+    }
+  } else {
+    keywordTable = nsCSSProps::kKeywordTableTable[aProperty];
+    // Special cases where nsCSSPropList.h doesn't hold the table.
+    if (keywordTable == nullptr) {
+      if (aProperty == eCSSProperty_clip_path) {
+        keywordTable = nsCSSProps::kClipPathGeometryBoxKTable;
+      }
     }
   }
 
   if (keywordTable) {
     for (size_t i = 0; !keywordTable[i].IsSentinel(); ++i) {
       nsCSSKeyword word = keywordTable[i].mKeyword;
 
       // These are extra -moz values which are added while rebuilding
@@ -793,16 +797,18 @@ InspectorUtils::GetCSSValuesForProperty(
                                          CSSEnabledState::eForAllContent) {
       // Get colors (once) first.
       uint32_t propertyParserVariant = nsCSSProps::ParserVariant(*subproperty);
       if (propertyParserVariant & VARIANT_COLOR) {
         GetColorsForProperty(propertyParserVariant, aResult);
         break;
       }
     }
+    // Some shorthands may have keywords not available in subproperties.
+    GetKeywordsForProperty(propertyID, aResult);
     CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subproperty, propertyID,
                                          CSSEnabledState::eForAllContent) {
       uint32_t propertyParserVariant = nsCSSProps::ParserVariant(*subproperty);
       GetKeywordsForProperty(*subproperty, aResult);
       GetOtherValuesForProperty(propertyParserVariant, aResult);
     }
   }
   // All CSS properties take initial, inherit and unset.
--- a/layout/reftests/backgrounds/gradient/reftest.list
+++ b/layout/reftests/backgrounds/gradient/reftest.list
@@ -1,3 +1,3 @@
 == scaled-color-stop-position.html scaled-color-stop-position-ref.html
 == color-stop-clamp-interpolation.html color-stop-clamp-interpolation-ref.html
-fails-if(webrender&&winWidget) == linear-gradient-repeated.html linear-gradient-repeated-ref.html
+fuzzy-if(webrender&&winWidget,2-2,72-72) == linear-gradient-repeated.html linear-gradient-repeated-ref.html
--- a/layout/reftests/backgrounds/reftest.list
+++ b/layout/reftests/backgrounds/reftest.list
@@ -173,15 +173,15 @@ fuzzy(80,500) fuzzy-if(skiaContent,109,9
 
 fuzzy-if(skiaContent,1,8) fuzzy-if(webrender,1,84) == background-multiple-with-border-radius.html background-multiple-with-border-radius-ref.html
 == background-repeat-large-area.html background-repeat-large-area-ref.html
 
 fuzzy(30,474) fuzzy-if(skiaContent,31,474) == background-tiling-zoom-1.html background-tiling-zoom-1-ref.html
 
 skip-if(!cocoaWidget) == background-repeat-resampling.html background-repeat-resampling-ref.html
 
-fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) fails-if(webrender&&winWidget) == background-clip-text-1a.html background-clip-text-1-ref.html
-fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) fails-if(webrender&&winWidget) == background-clip-text-1b.html background-clip-text-1-ref.html
-fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) fails-if(webrender&&winWidget) == background-clip-text-1c.html background-clip-text-1-ref.html
-fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) fails-if(webrender&&winWidget) == background-clip-text-1d.html background-clip-text-1-ref.html
-fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) fails-if(webrender&&winWidget) == background-clip-text-1e.html background-clip-text-1-ref.html
+fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) fuzzy-if(webrender&&winWidget,153-153,2866-2866) == background-clip-text-1a.html background-clip-text-1-ref.html
+fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) fuzzy-if(webrender&&winWidget,153-153,2866-2866) == background-clip-text-1b.html background-clip-text-1-ref.html
+fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) fuzzy-if(webrender&&winWidget,153-153,2866-2866) == background-clip-text-1c.html background-clip-text-1-ref.html
+fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) fuzzy-if(webrender&&winWidget,153-153,2866-2866) == background-clip-text-1d.html background-clip-text-1-ref.html
+fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) fuzzy-if(webrender&&winWidget,153-153,2866-2866) == background-clip-text-1e.html background-clip-text-1-ref.html
 
 == background-clip-text-2.html background-clip-text-2-ref.html
--- a/layout/reftests/border-image/reftest.list
+++ b/layout/reftests/border-image/reftest.list
@@ -6,18 +6,18 @@
 # This is fuzzy temporarily until bug 1044702 makes it possible to use source
 # clipping on Windows. (Any other fix would have a significant perf cost.)
 fuzzy-if(winWidget,1,1) == multicolor-image-2.html multicolor-image-2-ref.html
 == multicolor-image-3.html multicolor-image-3-ref.html
 == multicolor-image-4.html multicolor-image-4-ref.html
 == multicolor-image-5.html multicolor-image-5-ref.html
 == transparent-image-1.html transparent-image-1-ref.html
 != repeat-image-1.html repeat-image-1-ref.html
-fuzzy-if(webrender,15-15,975-975) fails-if(webrender&&winWidget) == 470250-1.html 470250-1-ref.html
-fuzzy-if(webrender,15-15,975-975) fails-if(webrender&&winWidget) == 470250-2.html 470250-2-ref.html
+fuzzy-if(webrender,15-15,975-986) == 470250-1.html 470250-1-ref.html
+fuzzy-if(webrender,15-15,975-986) == 470250-2.html 470250-2-ref.html
 != different-h-v-1.html different-h-v-ref.html
 != different-h-v-2.html different-h-v-ref.html
 != different-h-v-1.html different-h-v-2.html
 == center-scaling-1.html center-scaling-1-ref.html
 fails-if(Android) fails-if(usesRepeatResampling) == center-scaling-2.html center-scaling-2-ref.html # Android: very different scaling (blurriness) on some sides
 fails-if(Android) fails-if(usesRepeatResampling) == center-scaling-3.html center-scaling-3-ref.html # Android: very different scaling (blurriness) on some sides
 == center-scaling-4t.html center-scaling-4t-ref.html
 == center-scaling-4r.html center-scaling-4r-ref.html
@@ -38,48 +38,48 @@ fails-if(Android) fails-if(usesRepeatRes
 == border-image-outset-resize-1.html border-image-outset-resize-1-ref.html
 fuzzy-if(asyncPan&&!layersGPUAccelerated,140,514) fuzzy-if(winWidget&&stylo,144,448) == border-image-outset-move-1.html border-image-outset-move-1-ref.html
 == border-image-style-none.html border-image-style-none-ref.html
 == border-image-style-none-length.html border-image-style-none-length-ref.html
 == border-image-style-none-auto.html border-image-style-none-auto-ref.html
 
 # border images with gradients
 fuzzy-if(webrender,1-1,1488-1804) == border-image-linear-gradient.html border-image-linear-gradient-ref.html
-fuzzy(1,98) fuzzy-if(skiaContent,1,350) fuzzy-if(webrender,1-1,37537-37537) fails-if(webrender&&winWidget) == border-image-linear-gradient-slice-1.html border-image-linear-gradient-slice-1-ref.html
-fuzzy(1,149) fuzzy-if(OSX,1,10595) fuzzy-if(webrender,1,25007) fails-if(webrender&&winWidget) == border-image-linear-gradient-slice-2.html border-image-linear-gradient-slice-2-ref.html
-fuzzy(1,433) fuzzy-if(skiaContent,1,2500) fuzzy-if(webrender,1,85584) fails-if(webrender&&winWidget) == border-image-linear-gradient-slice-fill-1.html border-image-linear-gradient-slice-fill-1-ref.html
-fuzzy(1,177) fuzzy-if(OSX,1,25771) fuzzy-if(skiaContent&&!Android,1,400) fuzzy-if(Android,1,6093) fuzzy-if(webrender,1,57412) fails-if(webrender&&winWidget) == border-image-linear-gradient-slice-fill-2.html border-image-linear-gradient-slice-fill-2-ref.html
-fuzzy(1,48)  fuzzy-if(OSX,5,1676) fuzzy-if(webrender,1,4479) fails-if(webrender&&winWidget) == border-image-linear-gradient-width.html border-image-linear-gradient-width-ref.html
-fuzzy(1,5000) fuzzy-if(OSX,1,15000) fuzzy-if(webrender,2,58670) == border-image-linear-gradient-slice-width.html border-image-linear-gradient-slice-width-ref.html
-fuzzy(1,3000) fuzzy-if(OSX,1,6000) fuzzy-if(webrender,1,26302) fails-if(webrender&&winWidget) == border-image-linear-gradient-outset.html border-image-linear-gradient-outset-ref.html
-fuzzy(1,12) fuzzy-if(skiaContent,1,400) fuzzy-if(webrender,1-1,26872-26872) fails-if(webrender&&winWidget) == border-image-linear-gradient-repeat-repeat-1.html border-image-linear-gradient-repeat-repeat-1-ref.html
-fuzzy(1,13) fuzzy-if(skiaContent,1,300) fuzzy-if(webrender,1-1,27131-27131) fails-if(webrender&&winWidget) == border-image-linear-gradient-repeat-round-1.html border-image-linear-gradient-repeat-round-1-ref.html
-fuzzy-if(webrender,1-1,65098-65098) fails-if(webrender&&winWidget) == border-image-linear-gradient-repeat-repeat-2.html border-image-linear-gradient-repeat-repeat-2-ref.html
-fuzzy(1,576) fuzzy-if(skiaContent,1,2000) fuzzy-if(webrender,1-1,64806-64806) fails-if(webrender&&winWidget) == border-image-linear-gradient-repeat-round-2.html border-image-linear-gradient-repeat-round-2-ref.html
-fuzzy(1,8533) fuzzy-if(webrender,1,85925) fails-if(webrender&&winWidget) == border-image-linear-gradient-repeat-repeat-3.html border-image-linear-gradient-repeat-repeat-3-ref.html
-fuzzy(1,7161) fuzzy-if(webrender,2,107112) fails-if(webrender&&winWidget) == border-image-linear-gradient-repeat-round-3.html border-image-linear-gradient-repeat-round-3-ref.html
+fuzzy(1,98) fuzzy-if(skiaContent,1,350) fuzzy-if(webrender,1-2,37234-37537) == border-image-linear-gradient-slice-1.html border-image-linear-gradient-slice-1-ref.html
+fuzzy(1,149) fuzzy-if(OSX,1,10595) fuzzy-if(webrender,1-3,24999-25007) == border-image-linear-gradient-slice-2.html border-image-linear-gradient-slice-2-ref.html
+fuzzy(1,433) fuzzy-if(skiaContent,1,2500) fuzzy-if(webrender,1-3,84860-85584) == border-image-linear-gradient-slice-fill-1.html border-image-linear-gradient-slice-fill-1-ref.html
+fuzzy(1,177) fuzzy-if(OSX,1,25771) fuzzy-if(skiaContent&&!Android,1,400) fuzzy-if(Android,1,6093) fuzzy-if(webrender,1-3,57249-57412) == border-image-linear-gradient-slice-fill-2.html border-image-linear-gradient-slice-fill-2-ref.html
+fuzzy(1,48)  fuzzy-if(OSX,5,1676) fuzzy-if(webrender,1-1,4479-4530) == border-image-linear-gradient-width.html border-image-linear-gradient-width-ref.html
+fuzzy(1,5000) fuzzy-if(OSX,1,15000) fuzzy-if(webrender,2-2,58629-58667) == border-image-linear-gradient-slice-width.html border-image-linear-gradient-slice-width-ref.html
+fuzzy(1,3000) fuzzy-if(OSX,1,6000) fuzzy-if(webrender,1-1,26067-26353) == border-image-linear-gradient-outset.html border-image-linear-gradient-outset-ref.html
+fuzzy(1,12) fuzzy-if(skiaContent,1,400) fuzzy-if(webrender,1-2,26394-26872) == border-image-linear-gradient-repeat-repeat-1.html border-image-linear-gradient-repeat-repeat-1-ref.html
+fuzzy(1,13) fuzzy-if(skiaContent,1,300) fuzzy-if(webrender,1-2,26265-27131) == border-image-linear-gradient-repeat-round-1.html border-image-linear-gradient-repeat-round-1-ref.html
+fuzzy-if(webrender,1-2,65098-66334) == border-image-linear-gradient-repeat-repeat-2.html border-image-linear-gradient-repeat-repeat-2-ref.html
+fuzzy(1,576) fuzzy-if(skiaContent,1,2000) fuzzy-if(webrender,1-2,64806-66821) == border-image-linear-gradient-repeat-round-2.html border-image-linear-gradient-repeat-round-2-ref.html
+fuzzy(1,8533) fuzzy-if(webrender,1-2,84604-85925) == border-image-linear-gradient-repeat-repeat-3.html border-image-linear-gradient-repeat-repeat-3-ref.html
+fuzzy(1,7161) fuzzy-if(webrender,2-3,92540-92746) == border-image-linear-gradient-repeat-round-3.html border-image-linear-gradient-repeat-round-3-ref.html
 
 fuzzy-if(webrender,1,2096) == border-image-radial-gradient.html border-image-radial-gradient-ref.html
 fuzzy(1,42) fuzzy-if(skiaContent,2,20) fuzzy-if(webrender,1,37818) == border-image-radial-gradient-slice-1.html border-image-radial-gradient-slice-1-ref.html
 fuzzy(1,46) fuzzy-if(OSX,2,4472) fuzzy-if(webrender,1,26363) == border-image-radial-gradient-slice-2.html border-image-radial-gradient-slice-2-ref.html
 fuzzy(1,105) fuzzy-if(webrender,1,90873) == border-image-radial-gradient-slice-fill-1.html border-image-radial-gradient-slice-fill-1-ref.html
 fuzzy(1,139) fuzzy-if(OSX,2,4478) fuzzy-if(skiaContent,2,120) fuzzy-if(webrender,1,61729) == border-image-radial-gradient-slice-fill-2.html border-image-radial-gradient-slice-fill-2-ref.html
 fuzzy-if(skiaContent,1,2) fuzzy-if(webrender,1,4894) == border-image-radial-gradient-width.html border-image-radial-gradient-width-ref.html
 fuzzy(1,9000) fuzzy-if(webrender,3,66698) == border-image-radial-gradient-slice-width.html border-image-radial-gradient-slice-width-ref.html
 
 # OS X failures tracked in bug 957025
-fuzzy-if(webrender,1-1,1766-1766) fails-if(webrender&&winWidget) == border-image-repeating-linear-gradient.html border-image-repeating-linear-gradient-ref.html
+fuzzy-if(webrender,1-1,1766-1800) == border-image-repeating-linear-gradient.html border-image-repeating-linear-gradient-ref.html
 fuzzy(1,5608) fails-if(OSX) fuzzy-if(skiaContent,1,6093) fuzzy-if(webrender,3,95449) == border-image-repeating-linear-gradient-slice-fill-2.html border-image-repeating-linear-gradient-slice-fill-2-ref.html
 fuzzy(1,19200) fails-if(OSX) fuzzy-if(skiaContent,3,20000) fuzzy-if(webrender,3-3,18896-18896) fuzzy-if(webrender,2,112082) == border-image-repeating-linear-gradient-repeat-round-2.html border-image-repeating-linear-gradient-repeat-round-2-ref.html
 
 fuzzy(1,657) fuzzy-if(webrender,3,3008) == border-image-repeating-radial-gradient.html border-image-repeating-radial-gradient-ref.html
 fuzzy(1,510) fuzzy-if(skiaContent,3,362) fuzzy-if(webrender,3,62078) == border-image-repeating-radial-gradient-slice-1.html border-image-repeating-radial-gradient-slice-1-ref.html
 fuzzy(1,438) fuzzy-if(skiaContent,3,437) fuzzy-if(webrender,3,40536) == border-image-repeating-radial-gradient-slice-2.html border-image-repeating-radial-gradient-slice-2-ref.html
-fuzzy(1,1357) fuzzy-if(skiaContent,3,964) fuzzy-if(webrender,3,143220) fails-if(webrender&&winWidget) == border-image-repeating-radial-gradient-slice-fill-1.html border-image-repeating-radial-gradient-slice-fill-1-ref.html
-fuzzy(1,1058) fails-if(OSX) fuzzy-if(skiaContent,3,887) fuzzy-if(webrender,3,94677) fails-if(webrender&&winWidget) == border-image-repeating-radial-gradient-slice-fill-2.html border-image-repeating-radial-gradient-slice-fill-2-ref.html
+fuzzy(1,1357) fuzzy-if(skiaContent,3,964) fuzzy-if(webrender,1-4,85742-85800) == border-image-repeating-radial-gradient-slice-fill-1.html border-image-repeating-radial-gradient-slice-fill-1-ref.html
+fuzzy(1,1058) fails-if(OSX) fuzzy-if(skiaContent,3,887) fuzzy-if(webrender,1-4,57087-57193) == border-image-repeating-radial-gradient-slice-fill-2.html border-image-repeating-radial-gradient-slice-fill-2-ref.html
 fuzzy(1,602) fuzzy-if(webrender,3,7441) == border-image-repeating-radial-gradient-width.html border-image-repeating-radial-gradient-width-ref.html
 fuzzy(3,18000) fails-if(OSX) fuzzy-if(skiaContent,4,16462) fuzzy-if(webrender,5,99728) == border-image-repeating-radial-gradient-slice-width.html border-image-repeating-radial-gradient-slice-width-ref.html
 fuzzy-if(webrender,3,117768) == border-image-repeating-radial-gradient-repeat-repeat-2.html border-image-repeating-radial-gradient-repeat-repeat-2-ref.html
 fuzzy(1,1054) fails-if(OSX) fuzzy-if(skiaContent,2,952) fuzzy-if(webrender,3,116185) == border-image-repeating-radial-gradient-repeat-round-2.html border-image-repeating-radial-gradient-repeat-round-2-ref.html
 
 # border-image-source (-moz-)element
 fuzzy(125,5808) == border-image-element.html border-image-element-ref.html
 
--- a/layout/reftests/box-shadow/reftest.list
+++ b/layout/reftests/box-shadow/reftest.list
@@ -6,17 +6,17 @@ random != boxshadow-blur-2.html boxshado
 == boxshadow-multiple.html boxshadow-multiple-ref.html
 == boxshadow-spread.html boxshadow-spread-ref.html
 == tableboxshadow-basic.html tableboxshadow-basic-ref.html
 == tableboxshadow-trshadow.html tableboxshadow-trshadow-ref.html
 == tableboxshadow-tdshadow.html tableboxshadow-tdshadow-ref.html
 == boxshadow-rounding.html boxshadow-rounding-ref.html
 # One uses old path, one uses WR box shadow.
 fails-if(Android) == boxshadow-button.html boxshadow-button-ref.html
-fuzzy-if(OSX==1010,1,24) fuzzy-if(d2d,16,999) fuzzy-if(skiaContent,1,12) fuzzy-if(webrender,7-7,1560-1680) fails-if(webrender&&winWidget) == boxshadow-large-border-radius.html boxshadow-large-border-radius-ref.html # Bug 1209649
+fuzzy-if(OSX==1010,1,24) fuzzy-if(d2d,16,999) fuzzy-if(skiaContent,1,12) fuzzy-if(webrender,5-7,1560-1680) == boxshadow-large-border-radius.html boxshadow-large-border-radius-ref.html # Bug 1209649
 
 fails-if(Android) == boxshadow-fileupload.html boxshadow-fileupload-ref.html
 fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),98,152) fuzzy-if(skiaContent,13,28) fuzzy-if(webrender,19-19,50-50) == boxshadow-inner-basic.html boxshadow-inner-basic-ref.svg
 random-if(layersGPUAccelerated) == boxshadow-mixed.html boxshadow-mixed-ref.html
 == boxshadow-mixed-2.html boxshadow-mixed-2-ref.html
 random-if(d2d) fuzzy-if(skiaContent,1,100) fuzzy-if(webrender,127,3528) == boxshadow-rounded-spread.html boxshadow-rounded-spread-ref.html
 fuzzy-if(skiaContent,1,50) == boxshadow-dynamic.xul boxshadow-dynamic-ref.xul
 random-if(d2d) == boxshadow-onecorner.html boxshadow-onecorner-ref.html
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -407,17 +407,17 @@ fuzzy-if(Android,2,18) == 315920-17.html
 == 315920-28c.html 315920-28-ref.html
 == 315920-29a.html 315920-29-ref.html
 == 315920-29b.html 315920-29-ref.html
 == 315920-30.html 315920-30-ref.html
 == 316057-1.html 316057-1-ref.html
 == 320979-1.html 320979-1-ref.html
 != 321402-1.html about:blank
 != 321402-2.html about:blank
-fails-if(webrender&&winWidget) == 321402-3.xul 321402-3-ref.xul
+fuzzy-if(webrender&&winWidget,35-35,1-1) == 321402-3.xul 321402-3-ref.xul
 == 321402-4.xul 321402-4-ref.xul
 == 321402-5.xul 321402-5-ref.xul
 == 321402-6.xul 321402-6-ref.xul
 == 321738-1.html 321738-1-ref.html
 == 322436-1.html 322436-1-ref.html
 == 322461-1.xml 322461-1-ref.html
 == 323656-1.html 323656-1-ref.html
 == 323656-2.html 323656-2-ref.html
@@ -551,19 +551,19 @@ fuzzy-if(skiaContent,2,4) == 362594-2c.h
 skip-if(Android) == 363706-1.html 363706-1-ref.html
 != 363706-1.html about:blank
 == 363728-1.html 363728-1-ref.html
 == 363728-2.html 363728-2-ref.html
 fuzzy-if(skiaContent||Android,4,11) == 363858-1.html 363858-1-ref.html
 == 363858-2.html 363858-2-ref.html
 == 363858-3.html 363858-3-ref.html
 == 363858-4.html 363858-4-ref.html
-# fuzzy-if(OSX,45,2) fuzzy-if(winWidget,114,1) fails-if(webrender&&winWidget) == 363858-5a.html 363858-5-ref.html # bug 1452797
+# fuzzy-if(OSX,45,2) fuzzy-if(winWidget,116,1) == 363858-5a.html 363858-5-ref.html # bug 1452797
 == 363858-5b.html 363858-5-ref.html
-# fuzzy-if(OSX,45,2) fuzzy-if(winWidget,114,1) fails-if(webrender&&winWidget) == 363858-6a.html 363858-6-ref.html # bug 1452797
+# fuzzy-if(OSX,45,2) fuzzy-if(winWidget,116,1) == 363858-6a.html 363858-6-ref.html # bug 1452797
 == 363858-6b.html 363858-6-ref.html
 == 363874.html 363874-ref.html
 == 363874-max-width.html 363874-max-width-ref.html
 == 364066-1.html 364066-1-ref.html
 == 364079-1.html 364079-1-ref.html
 == 364318-1.xhtml 364318-1-ref.xhtml
 == 364861-1.html 364861-1-ref.html
 == 364862-1.html 364862-1-ref.html
@@ -649,17 +649,17 @@ fails-if(Android&&!asyncPan) == 371561-1
 == 371925-1b.html 371925-1-ref.html
 == 372037-1.html 372037-1-ref.html
 == 372062-1.html 372062-1-ref.html
 == 372063-1.html 372063-1-ref.html
 == 372323-1.xhtml 372323-1-ref.xhtml
 == 372553-1.html 372553-1-ref.html
 == 372632-1.html 372632-1-ref.html
 == 372768-1.html 372768-1-ref.html
-fails-if(webrender&&winWidget) == 373295-1.html 373295-1-ref.html
+fuzzy-if(webrender&&winWidget,83-83,2-2) == 373295-1.html 373295-1-ref.html
 == 373298-1.html 373298-1-ref.html
 == 373381-1.html 373381-1-ref.html
 fuzzy-if(skiaContent&&!Android,2,40) == 373381-2.html 373381-2-ref.html
 random-if(d2d) == 373381-3.html 373381-3-ref.html
 == 373381-4.html 373381-4-ref.html
 == 373383-1.html 373383-1-ref.html
 == 373433-1.html 373433-1-ref.html
 == 373533-1.xhtml about:blank
@@ -723,18 +723,18 @@ fuzzy-if(skiaContent,2,5) == 381507-1.ht
 == 383883-4.html 383883-4-ref.html
 == 383884-1.html 383884-1-ref.html
 == 383885-1.html 383885-1-ref.html
 == 384322-1.html 384322-1-ref.html
 == 384576-1.html 384576-1-ref.html
 == 384762-1.html about:blank
 == 384876-1.html 384876-1-ref.html
 == 385533-1.html about:blank # assertion test
-fails-if(webrender&&winWidget) == 385569-1a.html 385569-1-ref.html
-fails-if(webrender&&winWidget) == 385569-1b.html 385569-1-ref.html
+fuzzy-if(webrender&&winWidget,137-137,303-303) == 385569-1a.html 385569-1-ref.html
+fuzzy-if(webrender&&winWidget,137-137,303-303) == 385569-1b.html 385569-1-ref.html
 == 385607-1.html 385607-1-ref.html
 == 385823-1.html 385823-1-ref.html
 fuzzy-if(webrender,0-1,0-600) == 385823-2a.html 385823-2-ref.html
 fails == 385823-2b.html 385823-2-ref.html
 fuzzy-if(webrender,0-1,0-600) == 385823-2c.html 385823-2-ref.html
 fuzzy-if(skiaContent,2,11) == 385870-1.html 385870-1-ref.html
 fuzzy-if(skiaContent,2,3) == 385870-2.html 385870-2-ref.html
 == 386014-1a.html 386014-1-ref.html
@@ -936,17 +936,17 @@ fuzzy-if(Android,13,9) == 407111-1.html 
 == 409089-2.html 409089-2-ref.html
 == 409089-3.html 409089-3-ref.html
 fuzzy-if(winWidget,123,1600) == 409659-1a.html 409659-1-ref.html  # Bug 1128229
 != 409659-1b.html 409659-1-ref.html
 != 409659-1c.html 409659-1-ref.html
 fuzzy-if(winWidget,123,1900) == 409659-1d.html 409659-1-ref.html  # Bug 1128229
 == 410621-1.html 410621-1-ref.html
 == 411059-1.html 411059-1-ref.html
-fails-if(webrender&&winWidget) == 411334-1.xml 411334-1-ref.xml
+fuzzy-if(webrender&&winWidget,129-129,770-770) == 411334-1.xml 411334-1-ref.xml
 == 411367-1.html 411367-1-ref.html
 == 411367-2.html 411367-2-ref.html
 == 411367-3.html 411367-3-ref.html
 == 411585-1.html 411585-1-ref.html
 == 411585-2.html 411585-2-ref.html
 fails == 411585-3.html 411585-3-ref.html # bug 426909
 == 411792-1.html 411792-1-ref.html
 == 412093-1.html 412093-1-ref.html
@@ -997,17 +997,17 @@ asserts(1) == 418574-2.html 418574-2-ref
 == 420069-2.html 420069-2-ref.html
 == 420351-1.html 420351-1-ref.html
 == 420790-1.xhtml 420790-1-ref.xhtml
 == 421069.html 421069-ref.html
 == 421069.html 421069-ref2.html
 == 421069-ref.html 421069-ref2.html
 == 421203-1.xul 421203-1-ref.html
 == 421203-2.xul 421203-1-ref.html
-fails-if(webrender&&winWidget) == 421203-3.xul 321402-3-ref.xul
+fuzzy-if(webrender&&winWidget,35-35,1-1) == 421203-3.xul 321402-3-ref.xul
 == 421203-4.xul 321402-4-ref.xul
 == 421203-5.xul 321402-5-ref.xul
 == 421203-6.xul 321402-6-ref.xul
 == 421234-1.html 421234-1-ref.html
 == 421239-1.html 421239-1-ref.html
 == 421239-2.html 421239-2-ref.html
 == 421419-1.html 421419-1-ref.html
 == 421436-1a.html 421436-1-ref.html
@@ -1190,17 +1190,17 @@ fuzzy-if(webrender,4,361) == 449519-1.ht
 == 452915-1.html 452915-1-ref.html
 == 452964-1.html 452964-1-ref.html
 == 454361.html about:blank
 == 455105-1.html 455105-ref.html
 == 455105-2.html 455105-ref.html
 == 455171-5.html 455171-5-ref.html
 == 455280-1.xhtml 455280-1-ref.xhtml
 == 455826-1.html 455826-1-ref.html
-fails-if(Android||cocoaWidget) fails-if(webrender&&winWidget) == 456147.xul 456147-ref.html # bug 458047
+fails-if(Android||cocoaWidget) fuzzy-if(webrender&&winWidget,222-222,2806-2806) == 456147.xul 456147-ref.html # bug 458047
 fuzzy-if(Android,11,41) fuzzy-if(winWidget||gtkWidget,4,6) fuzzy-if(d2d,15,69) fuzzy-if(skiaContent,42,150) == 456219-1a.html 456219-1-ref.html # bug 1128229
 fuzzy-if(Android,11,41) fuzzy-if(winWidget||gtkWidget,4,6) fuzzy-if(d2d,15,69) fuzzy-if(skiaContent,42,150) == 456219-1b.html 456219-1-ref.html # bug 1128229
 fuzzy-if(Android,11,41) fuzzy-if(winWidget||gtkWidget,4,6) fuzzy-if(d2d,15,69) fuzzy-if(skiaContent,42,150) == 456219-1c.html 456219-1-ref.html # bug 1128229
 fuzzy-if(skiaContent,1,45) == 456219-2.html 456219-2-ref.html
 == 456330-1.gif 456330-1-ref.png
 == 456484-1.html 456484-1-ref.html
 == 457398-1.html 457398-1-ref.html
 == 457398-2.html 457398-2-ref.html
@@ -1228,17 +1228,17 @@ fuzzy-if(skiaContent,1,5) == 459443-1.ht
 == 460012-1.html 460012-1-ref.html
 == 461266-1.html 461266-1-ref.html
 fuzzy-if(skiaContent,1,12000) fails-if(webrender) == 461512-1.html 461512-1-ref.html # bug 1382896 for webrender
 == 462844-1.html 462844-ref.html
 == 462844-2.html 462844-ref.html
 == 462844-3.html 462844-ref.html
 == 462844-4.html 462844-ref.html
 == 463204-1.html 463204-1-ref.html
-fuzzy-if(webrender,16-16,3425-3425) fails-if(webrender&&winWidget) == 463217-1.xul 463217-1-ref.xul
+fuzzy-if(webrender,16-16,3425-3483) == 463217-1.xul 463217-1-ref.xul
 == 463952-1.html 463952-1-ref.html
 == 464811-1.html 464811-1-ref.html
 == 465574-1.html 465574-1-ref.html # bug 421436
 == 466258-1.html 466258-1-ref.html
 == 466395-1.html 466395-1-ref.html
 == 466395-2.html 466395-2-ref.html
 == 467084-1.html 467084-1-ref.html
 == 467084-2.html 467084-2-ref.html
@@ -1682,17 +1682,17 @@ HTTP == 652991-3.html 652991-3-ref.html
 HTTP == 652991-4.html 652991-4-ref.html
 fuzzy-if(skiaContent,1,5) == 653930-1.html 653930-1-ref.html
 == 654057-1.html 654057-1-ref.html
 fuzzy-if(skiaContent,1,4500) == 654950-1.html 654950-1-ref.html # Quartz alpha blending doesn't match GL alpha blending
 == 655549-1.html 655549-1-ref.html
 == 655836-1.html 655836-1-ref.html
 != 656875.html about:blank
 == 658952.html 658952-ref.html
-fuzzy-if(skiaContent,7,3500) fails-if(webrender&&winWidget) == 660682-1.html 660682-1-ref.html
+fuzzy-if(skiaContent,7,3500) fuzzy-if(webrender&&winWidget,37-37,777-777) == 660682-1.html 660682-1-ref.html
 fuzzy-if(d2d,1,256) skip-if(Android) fuzzy-if(skiaContent,1,68000) == 664127-1.xul 664127-1-ref.xul # Android: Intermittent failures - bug 1019131
 == 665597-1.html 665597-1-ref.html
 == 665597-2.html 665597-2-ref.html
 == 667079-1.html 667079-1-ref.html
 == 668319-1.xul about:blank
 != 669015-1.xul 669015-1-notref.xul
 skip-if(azureSkiaGL) == 670442-1.html 670442-1-ref.html
 == 670467-1.html 670467-1-ref.html
--- a/layout/reftests/css-blending/reftest.list
+++ b/layout/reftests/css-blending/reftest.list
@@ -1,13 +1,13 @@
 pref(layout.css.mix-blend-mode.enabled,true) == blend-canvas.html blend-canvas-ref.html
 pref(layout.css.mix-blend-mode.enabled,true) == blend-constant-background-color.html blend-constant-background-color-ref.html
 pref(layout.css.mix-blend-mode.enabled,true) fuzzy-if(webrender,1-1,1411-7875) == blend-gradient-background-color.html blend-gradient-background-color-ref.html
 pref(layout.css.mix-blend-mode.enabled,true) == blend-image.html blend-image-ref.html
-pref(layout.css.mix-blend-mode.enabled,true) fails-if(webrender&&winWidget) == blend-difference-stacking.html blend-difference-stacking-ref.html
+pref(layout.css.mix-blend-mode.enabled,true) fuzzy-if(webrender&&winWidget,36-36,4-4) == blend-difference-stacking.html blend-difference-stacking-ref.html
 
 fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),1,10000) fuzzy-if(skiaContent,1,30000) pref(layout.css.background-blend-mode.enabled,true) == background-blending-alpha.html background-blending-alpha-ref.html
 pref(layout.css.background-blend-mode.enabled,true) fuzzy-if(webrender,1-1,1411-7875) == background-blending-gradient-color.html background-blending-gradient-color-ref.html
 fuzzy-if(azureSkiaGL,3,7597) fuzzy-if(cocoaWidget,3,7597) fuzzy-if(d2d,1,3800) fuzzy-if(d3d11,1,4200) fuzzy-if(skiaContent,2,9450) fuzzy-if(webrender,1-1,3938-23625) pref(layout.css.background-blend-mode.enabled,true) == background-blending-gradient-gradient.html background-blending-gradient-gradient-ref.html
 fuzzy-if(azureSkiaGL,2,7174) fuzzy-if(webrender,1-1,1312-7875) pref(layout.css.background-blend-mode.enabled,true) == background-blending-gradient-image.html background-blending-gradient-color-ref.html
 fuzzy-if(azureSkia||d2d||gtkWidget,1,10000) pref(layout.css.background-blend-mode.enabled,true) == background-blending-image-color-jpg.html background-blending-image-color-ref.html
 pref(layout.css.background-blend-mode.enabled,true) == background-blending-image-color-png.html background-blending-image-color-ref.html
 pref(layout.css.background-blend-mode.enabled,true) == background-blending-image-color-svg.html background-blending-image-color-ref.html
--- a/layout/reftests/css-break/reftest.list
+++ b/layout/reftests/css-break/reftest.list
@@ -1,12 +1,12 @@
 default-preferences pref(layout.css.box-decoration-break.enabled,true)
 
 == box-decoration-break-1.html box-decoration-break-1-ref.html
-fuzzy(1,20) fuzzy-if(skiaContent,1,700) fuzzy-if(webrender,21-21,12245-12245) fails-if(webrender&&winWidget) == box-decoration-break-with-inset-box-shadow-1.html box-decoration-break-with-inset-box-shadow-1-ref.html
+fuzzy(1,20) fuzzy-if(skiaContent,1,700) fuzzy-if(webrender,21-21,12245-12245) fuzzy-if(webrender&&winWidget,26-26,9123-9123) == box-decoration-break-with-inset-box-shadow-1.html box-decoration-break-with-inset-box-shadow-1-ref.html
 fuzzy(45,460) fuzzy-if(skiaContent,57,439) fuzzy-if(Android,57,1330) == box-decoration-break-with-outset-box-shadow-1.html box-decoration-break-with-outset-box-shadow-1-ref.html # Bug 1386543
 random-if(!gtkWidget) == box-decoration-break-border-image.html box-decoration-break-border-image-ref.html
 == box-decoration-break-block-border-padding.html box-decoration-break-block-border-padding-ref.html
 == box-decoration-break-block-margin.html box-decoration-break-block-margin-ref.html
 fuzzy-if(!Android,1,62) fuzzy-if(Android,8,6627) == box-decoration-break-first-letter.html box-decoration-break-first-letter-ref.html #Bug 1313773
 == box-decoration-break-with-bidi.html box-decoration-break-with-bidi-ref.html
 == box-decoration-break-bug-1235152.html box-decoration-break-bug-1235152-ref.html
 == box-decoration-break-bug-1249913.html box-decoration-break-bug-1249913-ref.html
--- a/layout/reftests/forms/input/number/reftest.list
+++ b/layout/reftests/forms/input/number/reftest.list
@@ -1,10 +1,8 @@
-default-preferences pref(dom.forms.number,true)
-
 # sanity checks:
 # not valid on Android where type=number looks like type=text
 skip-if(Android) != not-other-type-unthemed-1.html not-other-type-unthemed-1a-notref.html
 skip-if(Android) != not-other-type-unthemed-1.html not-other-type-unthemed-1b-notref.html
 # only valid on Android where type=number looks the same as type=text
 skip-if(!Android) == number-same-as-text-unthemed.html number-same-as-text-unthemed-ref.html
 
 # should look the same as type=text, except for the spin box
--- a/layout/reftests/image-element/reftest.list
+++ b/layout/reftests/image-element/reftest.list
@@ -2,27 +2,27 @@ random == bug-364968.html bug-364968-ref
 == bug-463204.html bug-463204-ref.html
 == canvas-outside-document.html canvas-inside-document.html
 == mozsetimageelement-01.html mozsetimageelement-01-ref.html
 == mozsetimageelement-02.html about:blank
 == image-outside-document-invalidate.html about:blank
 == canvas-outside-document-invalidate-01.html about:blank
 fails-if(azureSkia) fails-if(cocoaWidget) == canvas-outside-document-invalidate-02.html about:blank # See bug 666800
 #fails with Skia due to Skia bug http://code.google.com/p/skia/issues/detail?id=568
-fails-if(webrender&&winWidget) == element-paint-simple.html element-paint-simple-ref.html
+fuzzy-if(webrender&&winWidget,117-117,54-54) == element-paint-simple.html element-paint-simple-ref.html
 == element-paint-repeated.html element-paint-repeated-ref.html
 == element-paint-recursion.html element-paint-recursion-ref.html
 == element-paint-continuation.html element-paint-continuation-ref.html
 == element-paint-transform-01.html element-paint-transform-01-ref.html
 random-if(d2d) == element-paint-transform-02.html element-paint-transform-02-ref.html # bug 587133
 fuzzy-if(d2d&&/^Windows\x20NT\x206\.1/.test(http.oscpu),16,90) == element-paint-background-size-01.html element-paint-background-size-01-ref.html
 == element-paint-background-size-02.html element-paint-background-size-02-ref.html
 fuzzy-if(skiaContent,255,4) == element-paint-transform-repeated.html element-paint-transform-repeated-ref.html
 fuzzy-if(d2d,255,24) == element-paint-transform-03.html element-paint-transform-03-ref.html
-fuzzy-if(asyncPan,2,140) fuzzy-if(skiaContent,3,106) fails-if(webrender&&winWidget) == element-paint-native-widget.html element-paint-native-widget-ref.html   # in -ref the scrollframe is active and layerized differently with APZ
+fuzzy-if(asyncPan,2,140) fuzzy-if(skiaContent,3,106) fuzzy-if(webrender&&winWidget,222-222,1323-1323) == element-paint-native-widget.html element-paint-native-widget-ref.html   # in -ref the scrollframe is active and layerized differently with APZ
 fails-if(usesRepeatResampling&&!(webrender&&winWidget)) == element-paint-subimage-sampling-restriction.html about:blank
 == element-paint-clippath.html element-paint-clippath-ref.html
 fuzzy-if(webrender,35-35,706-706) == element-paint-sharpness-01a.html element-paint-sharpness-01b.html
 fuzzy-if(skiaContent,1,326) == element-paint-sharpness-01b.html element-paint-sharpness-01c.html
 fuzzy-if(webrender,35-35,706-706) == element-paint-sharpness-01c.html element-paint-sharpness-01d.html
 == element-paint-sharpness-02a.html element-paint-sharpness-02b.html
 == element-paint-sharpness-02b.html element-paint-sharpness-02c.html
 == element-paint-paintserversize-rounding-01.html element-paint-paintserversize-rounding-01-ref.html
--- a/layout/reftests/mathml/reftest.list
+++ b/layout/reftests/mathml/reftest.list
@@ -12,17 +12,17 @@ fails == dir-9.html dir-9-ref.html # Bug
 == dir-11.html dir-11-ref.html
 == css-spacing-1.html css-spacing-1-ref.html
 pref(mathml.disabled,true) == disabled-scriptlevel-1.html disabled-scriptlevel-1-ref.html
 pref(mathml.disabled,true) == disabled-scriptlevel-1.xhtml disabled-scriptlevel-1-ref.xhtml
 == displaystyle-1.html displaystyle-1-ref.html
 == displaystyle-2.html displaystyle-2-ref.html
 == displaystyle-3.html displaystyle-3-ref.html
 == displaystyle-4.html displaystyle-4-ref.html
-random-if(smallScreen&&Android) fuzzy(255,200) fails-if(webrender&&winWidget) == mirror-op-1.html mirror-op-1-ref.html
+random-if(smallScreen&&Android) fuzzy(255,200) fuzzy-if(webrender&&winWidget,255-255,265-265) == mirror-op-1.html mirror-op-1-ref.html
 != mirror-op-2.html mirror-op-2-ref.html
 != mirror-op-3.html mirror-op-3-ref.html
 != mirror-op-4.html mirror-op-4-ref.html
 == dynamic-mi.xhtml dynamic-mi-ref.xhtml
 == mphantom-1.html mphantom-1-ref.html
 == mphantom-2.html mphantom-2-ref.html
 == mfenced-1.xhtml mfenced-1-ref.xhtml
 == mfenced-2a.xhtml mfenced-2-ref.xhtml
--- a/layout/reftests/position-sticky/reftest.list
+++ b/layout/reftests/position-sticky/reftest.list
@@ -35,17 +35,17 @@ fuzzy-if(Android,2,3) == stacking-contex
 == left-right-3.html left-right-3-ref.html
 fuzzy-if(Android,4,810) == containing-block-1.html containing-block-1-ref.html
 == overconstrained-1.html overconstrained-1-ref.html
 == overconstrained-2.html overconstrained-2-ref.html
 == overconstrained-3.html overconstrained-3-ref.html
 == inline-1.html inline-1-ref.html
 == inline-2.html inline-2-ref.html
 fuzzy-if(OSX,99,210) == inline-3.html inline-3-ref.html
-skip-if(!asyncPan) fails-if(webrender&&winWidget) == inline-4.html inline-4-ref.html
+skip-if(!asyncPan) fuzzy-if(webrender&&winWidget,126-126,4-4) == inline-4.html inline-4-ref.html
 fails == column-contain-1a.html column-contain-1-ref.html
 == column-contain-1b.html column-contain-1-ref.html
 == column-contain-2.html column-contain-2-ref.html
 == block-in-inline-1.html block-in-inline-1-ref.html
 fuzzy-if(skiaContent,1,22) fuzzy-if(winWidget&&!layersGPUAccelerated,116,1320) fuzzy-if(Android,8,1533) == block-in-inline-2.html block-in-inline-2-ref.html
 fuzzy-if(Android,8,630) fuzzy-if(OSX,1,11) fuzzy-if(skiaContent,1,220) fuzzy-if(winWidget&&!layersGPUAccelerated,116,1320) == block-in-inline-3.html block-in-inline-3-ref.html
 == block-in-inline-continuations.html block-in-inline-continuations-ref.html
 == iframe-1.html iframe-1-ref.html
--- a/layout/reftests/svg/as-image/reftest.list
+++ b/layout/reftests/svg/as-image/reftest.list
@@ -41,17 +41,17 @@ include zoom/reftest.list
 == canvas-drawImage-scale-1b.html lime100x100-ref.html
 == canvas-drawImage-scale-1c.html lime100x100-ref.html
 
 fuzzy(1,2) fuzzy-if(skiaContent,1,529) == canvas-drawImage-scale-2a.html canvas-drawImage-scale-2-ref.html
 fuzzy(1,2) fuzzy-if(skiaContent,1,529) == canvas-drawImage-scale-2b.html canvas-drawImage-scale-2-ref.html
 
 fuzzy-if(winWidget&&!d2d,1,10000) fuzzy-if(azureSkia,1,10000) fuzzy-if(Android,1,10000) == canvas-drawImage-alpha-1.html canvas-drawImage-alpha-1-ref.html
 #Same as scale-2a but with globalAlpha:
-fuzzy(1,2) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),1,7018) fuzzy-if(azureSkia,1,40000) fails-if(webrender&&winWidget) == canvas-drawImage-alpha-2.html canvas-drawImage-alpha-2-ref.html
+fuzzy(1,2) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),1,7018) fuzzy-if(azureSkia,1,40000) fuzzy-if(webrender&&winWidget,1-1,39743-39743) == canvas-drawImage-alpha-2.html canvas-drawImage-alpha-2-ref.html
 
 == canvas-drawImage-slice-1a.html lime100x100-ref.html
 == canvas-drawImage-slice-1b.html lime100x100-ref.html
 
 == canvas-drawImage-origin-clean-1.html lime100x100-ref.html
 == canvas-drawImage-transform-restored.html canvas-drawImage-transform-restored-ref.html
 
 # Context paint tests (this feature is currently not part of any spec.)
--- a/layout/reftests/svg/filters/css-filter-chains/reftest.list
+++ b/layout/reftests/svg/filters/css-filter-chains/reftest.list
@@ -1,9 +1,9 @@
 # These tests verify that CSS filter chains behave properly.
 # e.g. filter: blur(3px) grayscale(0.5) invert(0.2);
 
 default-preferences pref(layout.css.filters.enabled,true)
 
 # Some platforms render this complex filter chain a little differently, and that's ok.
-fuzzy(5,13000) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)&&layersGPUAccelerated,35,13269) fuzzy-if(webrender,6-6,18006-18006) fails-if(webrender&&winWidget) == long-chain.html long-chain-ref.html # Win10: Bug 1258241
+fuzzy(5,13000) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)&&layersGPUAccelerated,35,13269) fuzzy-if(webrender,5-6,18006-18071) == long-chain.html long-chain-ref.html # Win10: Bug 1258241
 == moz-element.html moz-element-ref.html
 fuzzy-if(webrender,15-15,7958-8262) == same-filter.html same-filter-ref.html
--- a/layout/reftests/svg/filters/css-filters/reftest.list
+++ b/layout/reftests/svg/filters/css-filters/reftest.list
@@ -1,39 +1,39 @@
 # These tests verify that CSS filters behave properly.
 # e.g. filter: blur(3px)
 
 default-preferences pref(layout.css.filters.enabled,true)
 
-fuzzy-if(webrender,9-9,4780-4780) fails-if(webrender&&winWidget) == blur.html blur-ref.html
+fuzzy-if(webrender,9-9,4780-4784) == blur.html blur-ref.html
 == blur.svg blur-ref.svg
 == blur-calc.html blur-calc-ref.html
 == blur-calc-negative.html blur-calc-negative-ref.html
 skip-if(d2d) == blur-cap-large-radius-on-software.html blur-cap-large-radius-on-software-ref.html
-fuzzy-if(webrender,9-9,4780-4780) fails-if(webrender&&winWidget) == blur-em-radius.html blur-em-radius-ref.html
+fuzzy-if(webrender,9-9,4780-4784) == blur-em-radius.html blur-em-radius-ref.html
 == blur-invalid-radius.html blur-invalid-radius-ref.html
-fuzzy-if(webrender,9-9,4780-4780) fails-if(webrender&&winWidget) == blur-rem-radius.html blur-rem-radius-ref.html
+fuzzy-if(webrender,9-9,4780-4784) == blur-rem-radius.html blur-rem-radius-ref.html
 == blur-zero-radius.html blur-zero-radius-ref.html
-fuzzy-if(webrender,6-6,21308-21308) fails-if(webrender&&winWidget) == blur-zoomed-page.html blur-zoomed-page-ref.html
+fuzzy-if(webrender,6-7,20420-21308) == blur-zoomed-page.html blur-zoomed-page-ref.html
 == brightness.html brightness-ref.html
 == brightness-darken.html brightness-darken-ref.html
 == brightness-extreme.html brightness-extreme-ref.html
 == brightness-one.html brightness-one-ref.html
 == brightness-percent.html brightness-percent-ref.html
 == brightness-zero.html brightness-zero-ref.html
 == containing-block-1.html containing-block-1-ref.html
 == contrast.html contrast-ref.html
 == contrast-extreme.html contrast-extreme-ref.html
 == contrast-one.html contrast-one-ref.html
 == contrast-percent.html contrast-percent-ref.html
 == contrast-reduce.html contrast-reduce-ref.html
 == contrast-zero.html contrast-zero-ref.html
-fuzzy-if(webrender,9-9,2625-2625) fails-if(webrender&&winWidget) == drop-shadow.html drop-shadow-ref.html
-fuzzy-if(webrender,9-9,2625-2625) fails-if(webrender&&winWidget) == drop-shadow-default-color.html drop-shadow-default-color-ref.html
-fuzzy-if(webrender,9-9,2625-2625) fails-if(webrender&&winWidget) == drop-shadow-negative-offset.html drop-shadow-negative-offset-ref.html
+fuzzy-if(webrender,9-9,2625-2628) == drop-shadow.html drop-shadow-ref.html
+fuzzy-if(webrender,9-9,2625-2628) fails-if(webrender&&winWidget) == drop-shadow-default-color.html drop-shadow-default-color-ref.html
+fuzzy-if(webrender,9-9,2625-2628) fails-if(webrender&&winWidget) == drop-shadow-negative-offset.html drop-shadow-negative-offset-ref.html
 == filter-on-huge-bbox.html pass.svg
 == filter-on-outer-svg.html pass.svg
 fuzzy-if(webrender,1,10000) fuzzy-if(d2d,1,10000) == grayscale.html grayscale-ref.html
 fuzzy-if(webrender,1,10000) fuzzy-if(d2d,1,10000) == grayscale-one.html grayscale-one-ref.html
 fuzzy-if(webrender,1,10000) fuzzy-if(d2d,1,10000) == grayscale-over-one.html grayscale-over-one-ref.html
 fuzzy-if(webrender,1,10000) fuzzy-if(d2d,1,10000) == grayscale-percent.html grayscale-percent-ref.html
 fuzzy-if(webrender,1,10000) == grayscale-zero.html grayscale-zero-ref.html
 == hue-rotate.html hue-rotate-ref.html
--- a/layout/reftests/svg/reftest.list
+++ b/layout/reftests/svg/reftest.list
@@ -211,17 +211,17 @@ fuzzy-if(skiaContent,1,500) == filter-sc
 == filter-use-element-01.svg pass.svg
 fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||skiaContent,1,800000) == filters-and-group-opacity-01.svg filters-and-group-opacity-01-ref.svg
 
 == foreignObject-01.svg pass.svg
 == foreignObject-02.svg foreignObject-02-ref.svg
 == foreignObject-ancestor-style-change-01.svg foreignObject-ancestor-style-change-01-ref.svg
 == foreignObject-change-transform-01.svg pass.svg
 == foreignObject-display-01.svg pass.svg
-fuzzy-if(webrender,190,229) fails-if(webrender&&winWidget) == foreignObject-form-theme.svg foreignObject-form-theme-ref.html # Bug 1439980
+fuzzy-if(webrender,190-255,229-1552) == foreignObject-form-theme.svg foreignObject-form-theme-ref.html # Bug 1439980
 == foreignObject-img.html foreignObject-img-ref.html
 == foreignObject-img-form-theme.html foreignObject-img-form-theme-ref.html
 == foreignObject-move-repaint-01.svg pass.svg
 == foreignObject-overflow-01.svg pass.svg
 == foreignObject-start-hidden-01.svg pass.svg # followup from Bug 596765
 == foreignObject-start-hidden-02.svg pass.svg
 == foreignObject-style-change-01.svg pass.svg
 == foreignObject-dynamic-abspos-01.html foreignObject-dynamic-abspos-01-ref.html
--- a/layout/reftests/svg/text/reftest.list
+++ b/layout/reftests/svg/text/reftest.list
@@ -1,54 +1,54 @@
-fails-if(webrender&&winWidget) == simple.svg simple-ref.html
+fuzzy-if(webrender&&winWidget,122-122,254-254) == simple.svg simple-ref.html
 == simple-2.svg simple.svg
-fails-if(webrender&&winWidget) == simple-underline.svg simple-underline-ref.html
+fuzzy-if(webrender&&winWidget,122-122,254-254) == simple-underline.svg simple-underline-ref.html
 == simple-underline-scaled.svg simple-underline-scaled-ref.svg
-fails-if(webrender&&winWidget) == simple-anchor-end-bidi.svg simple-anchor-end-bidi-ref.html
-fails-if(webrender&&winWidget) == simple-anchor-end-rtl.svg simple-anchor-end-rtl-ref.html
-fails-if(webrender&&winWidget) == simple-anchor-end.svg simple-anchor-end-ref.html
-fuzzy-if(skiaContent&&dwrite,104,131) fails-if(webrender&&winWidget) == simple-anchor-middle-bidi.svg simple-anchor-middle-bidi-ref.html
-fails-if(webrender&&winWidget) == simple-anchor-middle-rtl.svg simple-anchor-middle-rtl-ref.html
-fuzzy-if(skiaContent,111,81) fails-if(webrender&&winWidget) == simple-anchor-middle.svg simple-anchor-middle-ref.html
-fails-if(webrender&&winWidget) == simple-bidi.svg simple-bidi-ref.html
+fuzzy-if(webrender&&winWidget,166-166,318-318) == simple-anchor-end-bidi.svg simple-anchor-end-bidi-ref.html
+fuzzy-if(webrender&&winWidget,132-132,204-204) == simple-anchor-end-rtl.svg simple-anchor-end-rtl-ref.html
+fuzzy-if(webrender&&winWidget,122-122,250-250) == simple-anchor-end.svg simple-anchor-end-ref.html
+fuzzy-if(skiaContent&&dwrite,104,131) fuzzy-if(webrender&&winWidget,194-194,319-319) == simple-anchor-middle-bidi.svg simple-anchor-middle-bidi-ref.html
+fuzzy-if(webrender&&winWidget,132-132,207-207) == simple-anchor-middle-rtl.svg simple-anchor-middle-rtl-ref.html
+fuzzy-if(skiaContent,111,81) fuzzy-if(webrender&&winWidget,122-122,254-254) == simple-anchor-middle.svg simple-anchor-middle-ref.html
+fuzzy-if(webrender&&winWidget,132-132,319-319) == simple-bidi.svg simple-bidi-ref.html
 == simple-bidi-2.svg simple-bidi.svg
 
 == simple-dx.svg simple.svg
 == simple-dx-2.svg simple-dx-2-ref.svg
 == simple-dx-anchor-end-bidi.svg simple-dx-anchor-end-bidi-ref.svg
 == simple-dx-anchor-end-rtl.svg simple-dx-anchor-end-rtl-ref.svg
 == simple-dx-anchor-end.svg simple-dx-anchor-end-ref.svg
 == simple-dx-anchor-middle-bidi.svg simple-dx-anchor-middle-bidi-ref.svg
 == simple-dx-anchor-middle-rtl.svg simple-dx-anchor-middle-rtl-ref.svg
 == simple-dx-anchor-middle.svg simple-dx-anchor-middle-ref.svg
 == simple-dx-bidi.svg simple-dx-bidi-ref.svg
 == simple-dx-bidi-2.svg simple-dx-bidi-2-ref.svg
 == simple-dx-rtl.svg simple-dx-rtl-ref.svg
 == simple-dx-rtl-2.svg simple-dx-rtl-2-ref.svg
 
 == simple-fill-color-dynamic.svg simple-fill-color-dynamic-ref.svg
-fails-if(webrender&&winWidget) == simple-fill-color.svg simple-fill-color-ref.html
+fuzzy-if(webrender&&winWidget,125-125,254-254) == simple-fill-color.svg simple-fill-color-ref.html
 == simple-fill-gradient.svg simple-fill-gradient-ref.svg
 == simple-fill-none.svg simple.svg
 == simple-pointer-events.svg simple.svg
 
-fails-if(webrender&&winWidget) == simple-multiple-dx.svg simple-multiple-dx-ref.html
+fuzzy-if(webrender&&winWidget,122-122,254-254) == simple-multiple-dx.svg simple-multiple-dx-ref.html
 == simple-multiple-dx-2.svg simple-multiple-dx.svg
 == simple-multiple-dx-anchor-end-bidi.svg simple-multiple-dx-anchor-end-bidi-ref.svg
 == simple-multiple-dx-anchor-middle-bidi.svg simple-multiple-dx-anchor-middle-bidi-ref.svg
 == simple-multiple-dx-anchor-end-rtl.svg simple-multiple-dx-anchor-end-rtl-ref.svg
 == simple-multiple-dx-anchor-end.svg simple-multiple-dx-anchor-end-ref.svg
 fuzzy-if(skiaContent,1,2) == simple-multiple-dx-anchor-middle-rtl.svg simple-multiple-dx-anchor-middle-rtl-ref.svg
 == simple-multiple-dx-anchor-middle.svg simple-multiple-dx-anchor-middle-ref.svg
 == simple-multiple-dx-bidi.svg simple-multiple-dx-bidi-ref.svg
 == simple-multiple-dx-bidi-2.svg simple-multiple-dx-bidi.svg
 == simple-multiple-dx-rtl.svg simple-multiple-dx-rtl-ref.svg
 == simple-multiple-dx-rtl-2.svg simple-multiple-dx-rtl.svg
 
-fails-if(webrender&&winWidget) == simple-rtl.svg simple-rtl-ref.html
+fuzzy-if(webrender&&winWidget,132-132,206-206) == simple-rtl.svg simple-rtl-ref.html
 == simple-rtl-2.svg simple-rtl.svg
 == simple-transform-rotate.svg simple-transform-rotate-ref.svg
 
 == multiple-x.svg multiple-x-ref.svg
 == multiple-x-bidi.svg multiple-x-bidi-ref.svg
 == multiple-x-rtl.svg multiple-x-rtl-ref.svg
 == multiple-x-anchor-end-bidi.svg multiple-x-anchor-end-bidi-ref.svg
 == multiple-x-anchor-end-rtl.svg multiple-x-anchor-end-rtl-ref.svg
@@ -191,15 +191,15 @@ fuzzy-if(skiaContent&&winWidget,126,336)
 # vertical text
 fuzzy-if(skiaContent,1,80) == textpath-vertical-dx.svg textpath-vertical-dx-ref.svg
 
 # selection
 needs-focus == deselectAll.svg deselectAll-ref.svg
 fuzzy-if(skiaContent,1,250) needs-focus == selectSubString.svg selectSubString-ref.svg
 fuzzy-if(skiaContent,1,600) needs-focus == selectSubString-2.svg selectSubString-2-ref.svg
 fuzzy-if(skiaContent,1,250) needs-focus == selectSubString-3.svg selectSubString-3-ref.svg
-fuzzy-if(webrender,1-1,237-237) needs-focus fails-if(webrender&&winWidget) == simple-selection.svg simple-selection-ref.html
-fuzzy-if(skiaContent,1,100) fuzzy-if(webrender,1-1,575-575) needs-focus fails-if(webrender&&winWidget) == simple-bidi-selection.svg simple-bidi-selection-ref.html
-fuzzy-if(skiaContent,1,50) fuzzy-if(webrender,1-1,237-237) needs-focus fails-if(webrender&&winWidget) == simple-fill-color-selection.svg simple-fill-color-selection-ref.html
-fuzzy-if(skiaContent,1,150) fuzzy-if(webrender,1-1,222-222) needs-focus fails-if(webrender&&winWidget) == simple-underline-selection.svg simple-underline-selection-ref.html
-fuzzy-if(skiaContent,1,300) fuzzy-if(webrender,1-1,934-934) needs-focus fails-if(webrender&&winWidget) == multiple-text-selection.svg multiple-text-selection-ref.html
+fuzzy-if(webrender,1-1,237-237) needs-focus fuzzy-if(webrender&&winWidget,148-148,254-254) == simple-selection.svg simple-selection-ref.html
+fuzzy-if(skiaContent,1,100) fuzzy-if(webrender,1-1,575-575) needs-focus fuzzy-if(webrender&&winWidget,148-148,318-318) == simple-bidi-selection.svg simple-bidi-selection-ref.html
+fuzzy-if(skiaContent,1,50) fuzzy-if(webrender,1-1,237-237) needs-focus fuzzy-if(webrender&&winWidget,148-148,254-254) == simple-fill-color-selection.svg simple-fill-color-selection-ref.html
+fuzzy-if(skiaContent,1,150) fuzzy-if(webrender,1-1,222-222) needs-focus fuzzy-if(webrender&&winWidget,148-148,254-254) == simple-underline-selection.svg simple-underline-selection-ref.html
+fuzzy-if(skiaContent,1,300) fuzzy-if(webrender,1-1,934-934) needs-focus fuzzy-if(webrender&&winWidget,152-152,494-494) == multiple-text-selection.svg multiple-text-selection-ref.html
 needs-focus == multiple-chunks-selection.svg multiple-chunks-selection-ref.svg
 fuzzy-if(skiaContent,1,200) needs-focus == textpath-selection.svg textpath-selection-ref.svg
--- a/layout/reftests/text-overflow/reftest.list
+++ b/layout/reftests/text-overflow/reftest.list
@@ -1,16 +1,16 @@
 == ellipsis-font-fallback.html ellipsis-font-fallback-ref.html
 == line-clipping.html line-clipping-ref.html
 fuzzy-if(Android,16,244) == marker-basic.html marker-basic-ref.html  # Bug 1128229
 == marker-string.html marker-string-ref.html
 skip-if(Android) == bidi-simple.html bidi-simple-ref.html # Fails on Android due to anti-aliasing
 skip-if(!gtkWidget) fuzzy-if(gtkWidget,2,289) == bidi-simple-scrolled.html bidi-simple-scrolled-ref.html # Fails on Windows and OSX due to anti-aliasing
 fuzzy-if(Android,24,4000) fuzzy-if(cocoaWidget,1,40) fuzzy-if(asyncPan&&!layersGPUAccelerated,149,1836) == scroll-rounding.html scroll-rounding-ref.html # bug 760264
-fuzzy(2,453) fuzzy-if(skiaContent,9,2100) fails-if(gtkWidget) fails-if(webrender&&winWidget) == anonymous-block.html anonymous-block-ref.html # gtkWidget:bug 1309103
+fuzzy(2,453) fuzzy-if(skiaContent,9,2100) fails-if(gtkWidget) fuzzy-if(webrender&&winWidget,50-50,499-499) == anonymous-block.html anonymous-block-ref.html # gtkWidget:bug 1309103
 == false-marker-overlap.html false-marker-overlap-ref.html
 == visibility-hidden.html visibility-hidden-ref.html
 fuzzy-if(asyncPan&&!layersGPUAccelerated,102,1724) fuzzy-if(gtkWidget,10,8) == block-padding.html block-padding-ref.html
 fuzzy-if(webrender,3,825) == quirks-decorations.html quirks-decorations-ref.html
 == quirks-line-height.html quirks-line-height-ref.html
 == standards-decorations.html standards-decorations-ref.html
 == standards-line-height.html standards-line-height-ref.html
 fuzzy-if(skiaContent,1,4200) == selection.html selection-ref.html
--- a/layout/reftests/text-shadow/reftest.list
+++ b/layout/reftests/text-shadow/reftest.list
@@ -1,15 +1,15 @@
 == 723669.html 723669-ref.html
 
-fails-if(webrender&&winWidget) == basic.xul basic-ref.xul
-random-if(Android) fails-if(webrender&&winWidget) == basic-negcoord.xul basic-negcoord-ref.xul
+fuzzy-if(webrender&&winWidget,1-1,7-7) == basic.xul basic-ref.xul
+random-if(Android) fuzzy-if(webrender&&winWidget,1-1,6-6) == basic-negcoord.xul basic-negcoord-ref.xul
 != blur.xul blur-notref.xul
-fails-if(webrender&&winWidget) == color-inherit.xul color-inherit-ref.xul
-fails-if(webrender&&winWidget) == multiple-noblur.xul multiple-noblur-ref.xul
+fuzzy-if(webrender&&winWidget,1-1,6-6) == color-inherit.xul color-inherit-ref.xul
+fuzzy-if(webrender&&winWidget,1-1,44-44) == multiple-noblur.xul multiple-noblur-ref.xul
 == blur-opacity.html blur-opacity-ref.html
 
 == basic.html basic-ref.html
 == basic-negcoord.html basic-negcoord-ref.html
 == basic-opacity.html basic-opacity-ref.html
 != blur.html blur-notref.html
 == color-inherit.html color-inherit-ref.html
 == color-parserorder.html color-parserorder-ref.html
--- a/layout/reftests/text-svgglyphs/reftest.list
+++ b/layout/reftests/text-svgglyphs/reftest.list
@@ -1,16 +1,16 @@
 pref(gfx.font_rendering.opentype_svg.enabled,false)   != svg-glyph-basic.svg svg-glyph-basic-ref.svg
 pref(gfx.font_rendering.opentype_svg.enabled,true)    fuzzy-if(skiaContent,1,200) == svg-glyph-basic.svg svg-glyph-basic-ref.svg
 pref(gfx.font_rendering.opentype_svg.enabled,true)    == svg-glyph-invalid-ids.svg svg-glyph-invalid-ids-ref.svg
 pref(gfx.font_rendering.opentype_svg.enabled,false)   != svg-glyph-positioning.svg svg-glyph-positioning-ref.svg
 pref(gfx.font_rendering.opentype_svg.enabled,true)    fuzzy-if(skiaContent,2,350) == svg-glyph-positioning.svg svg-glyph-positioning-ref.svg
 pref(gfx.font_rendering.opentype_svg.enabled,true)    == svg-glyph-html.html svg-glyph-html-ref.svg
 pref(gfx.font_rendering.opentype_svg.enabled,true)    == svg-glyph-direct.svg svg-glyph-direct-ref.svg
-pref(gfx.font_rendering.opentype_svg.enabled,true)    fails-if(webrender&&winWidget) == svg-glyph-invalid.html svg-glyph-invalid-ref.html
+pref(gfx.font_rendering.opentype_svg.enabled,true)    fuzzy-if(webrender&&winWidget,138-138,2461-2461) == svg-glyph-invalid.html svg-glyph-invalid-ref.html
 pref(gfx.font_rendering.opentype_svg.enabled,true)    == svg-glyph-objectfill-solid.svg svg-glyph-objectfill-solid-ref.svg
 pref(gfx.font_rendering.opentype_svg.enabled,true)    fuzzy-if(skiaContent,2,200) == svg-glyph-objectstroke-solid.svg svg-glyph-objectstroke-solid-ref.svg
 pref(gfx.font_rendering.opentype_svg.enabled,true)    fuzzy(1,7) fuzzy-if(gtkWidget&&/^Linux\x20x86_64/.test(http.oscpu),1,79) fuzzy-if(skiaContent,1,300) == svg-glyph-objectgradient.svg svg-glyph-objectgradient-ref.svg # see bug 871961#c5
 pref(gfx.font_rendering.opentype_svg.enabled,true)    fuzzy-if(cocoaWidget,1,7028) fuzzy-if(gtkWidget&&/^Linux\x20x86_64/.test(http.oscpu),1,23) fuzzy-if(skiaContent,1,250) fuzzy-if(webrender,128-128,90-94) == svg-glyph-objectgradient-zoom.svg svg-glyph-objectgradient-zoom-ref.svg
 pref(gfx.font_rendering.opentype_svg.enabled,true)    fuzzy-if(gtkWidget,1,1438) fuzzy-if(winWidget,1,1954) fuzzy-if(Android,8,3795) fuzzy-if(skiaContent,14,13000) == svg-glyph-objectpattern.svg svg-glyph-objectpattern-ref.svg
 pref(gfx.font_rendering.opentype_svg.enabled,true)    == clip.html clip-ref.html
 pref(gfx.font_rendering.opentype_svg.enabled,true)    fuzzy(1,13) fuzzy-if(gtkWidget&&/^Linux\x20x86_64/.test(http.oscpu),1,62) fuzzy-if(skiaContent,1,350) == svg-glyph-objectopacity.svg svg-glyph-objectopacity-ref.svg # see bug 871961#c5
 pref(gfx.font_rendering.opentype_svg.enabled,true)    fuzzy-if(gtkWidget,1,2268) fuzzy-if(winWidget,1,3074) fuzzy-if(Android,5,4715) fuzzy-if(skiaContent,8,13000) == svg-glyph-objectopacity2.svg svg-glyph-objectopacity2-ref.svg
--- a/layout/reftests/transform-3d/reftest.list
+++ b/layout/reftests/transform-3d/reftest.list
@@ -75,18 +75,18 @@ fuzzy-if(cocoaWidget,128,9) == animate-p
 == animate-backface-hidden.html about:blank
 == 1245450-1.html green-rect.html
 fuzzy(1,2000) == opacity-preserve3d-1.html opacity-preserve3d-1-ref.html
 fuzzy(1,15000) == opacity-preserve3d-2.html opacity-preserve3d-2-ref.html
 fuzzy(1,10000) == opacity-preserve3d-3.html opacity-preserve3d-3-ref.html
 fuzzy(1,10000) == opacity-preserve3d-4.html opacity-preserve3d-4-ref.html
 == opacity-preserve3d-5.html opacity-preserve3d-5-ref.html
 == snap-perspective-1.html snap-perspective-1-ref.html
-fails-if(webrender&&winWidget) == mask-layer-1.html mask-layer-ref.html
-fails-if(webrender&&winWidget) == mask-layer-2.html mask-layer-ref.html
+fuzzy-if(webrender&&winWidget,1-1,16-16) == mask-layer-1.html mask-layer-ref.html
+fuzzy-if(webrender&&winWidget,1-1,16-16) == mask-layer-2.html mask-layer-ref.html
 fails-if(webrender) == mask-layer-3.html mask-layer-ref.html
 == split-intersect1.html split-intersect1-ref.html
 fuzzy(255,150) == split-intersect2.html split-intersect2-ref.html
 fuzzy(255,100) == split-non-ortho1.html split-non-ortho1-ref.html
 fuzzy-if(winWidget,150,120) == component-alpha-1.html component-alpha-1-ref.html
 == nested-transform-1.html nested-transform-1-ref.html
 == transform-geometry-1.html transform-geometry-1-ref.html
 == intermediate-1.html intermediate-1-ref.html
--- a/layout/reftests/w3c-css/failures.list
+++ b/layout/reftests/w3c-css/failures.list
@@ -87,31 +87,31 @@ fails-if(Android) css-writing-modes/sizi
 # Fuzzy
 fuzzy-if(OSX||winWidget,255,480)  css-writing-modes/abs-pos-non-replaced-v??-???.xht
 fuzzy-if(OSX||winWidget,93,600)   css-writing-modes/baseline-inline-non-replaced-00?.xht
 fuzzy-if(OSX||winWidget,213,1540) css-writing-modes/block-flow-direction-???-0??.xht
 fuzzy-if(OSX,255,200)  css-writing-modes/box-offsets-rel-pos-vlr-005.xht
 fuzzy-if(OSX,255,200)  css-writing-modes/box-offsets-rel-pos-vrl-004.xht
 fuzzy-if(OSX||winWidget,93,300)   css-writing-modes/caption-side-v??-00?.xht
 fuzzy-if(OSX||winWidget,215,780)  css-writing-modes/central-baseline-alignment-00?.xht
-fuzzy-if(OSX||winWidget,75,404) fails-if(webrender&&winWidget) css-writing-modes/direction-v??-00?.xht
+fuzzy-if(OSX||winWidget,75,404) fuzzy-if(webrender&&winWidget,92-92,300-300) css-writing-modes/direction-v??-00?.xht
 fuzzy-if(OSX||winWidget,135,902)  css-writing-modes/float-contiguous-v??-01?.xht
 fuzzy-if(OSX||winWidget,93,300)   css-writing-modes/float-shrink-to-fit-vlr-009.xht
 fuzzy-if(OSX||winWidget,93,300)   css-writing-modes/float-shrink-to-fit-vrl-008.xht
 fuzzy-if(OSX||winWidget,93,300)   css-writing-modes/float-v??-0??.xht
-fuzzy-if(OSX||winWidget,62,404) fails-if(webrender&&winWidget) css-writing-modes/height-width-inline-non-replaced-v??-00?.xht
+fuzzy-if(OSX||winWidget,62,404) fuzzy-if(webrender&&winWidget,92-92,100-100) css-writing-modes/height-width-inline-non-replaced-v??-00?.xht
 fuzzy-if(OSX||winWidget,218,621)  css-writing-modes/inline-block-alignment-orthogonal-v??-00?.xht
 fuzzy-if(OSX||winWidget,135,1080) css-writing-modes/inline-block-alignment-slr-009.xht
 fuzzy-if(OSX||winWidget,111,960)  css-writing-modes/inline-block-alignment-srl-008.xht
 fuzzy-if(OSX||winWidget,213,1540) css-writing-modes/line-box-direction-???-0??.xht
 fuzzy-if(OSX||winWidget,110,1200) css-writing-modes/row-progression-???-0??.xht
 fuzzy-if(OSX||winWidget,110,1200) css-writing-modes/table-column-order-00?.xht
 fuzzy-if(winWidget,110,1200) css-writing-modes/table-column-order-slr-007.xht
 fuzzy-if(OSX||winWidget,110,1200) css-writing-modes/table-column-order-srl-006.xht
-fuzzy-if(OSX||winWidget,75,404) fails-if(webrender&&winWidget) css-writing-modes/text-align-v??-0??.xht
+fuzzy-if(OSX||winWidget,75,404) fuzzy-if(webrender&&winWidget,92-92,300-300) css-writing-modes/text-align-v??-0??.xht
 fuzzy-if(OSX||winWidget,215,780)  css-writing-modes/text-baseline-???-00?.xht
 fuzzy-if(OSX,15,16) css-writing-modes/text-combine-upright-decorations-001.html
 fuzzy-if(OSX||winWidget,255,480)  css-writing-modes/text-indent-v??-0??.xht
 fuzzy-if(OSX||winWidget,226,960)  css-writing-modes/text-orientation-016.xht
 fuzzy-if(OSX||winWidget,223,720)  css-writing-modes/vertical-alignment-*.xht
 fuzzy-if(OSX||winWidget,153,612)  css-writing-modes/writing-mode-vertical-??-00?.*
 fuzzy(255,960) css-writing-modes/text-combine-upright-value-all-00?.html
 
--- a/layout/reftests/w3c-css/received/reftest.list
+++ b/layout/reftests/w3c-css/received/reftest.list
@@ -709,20 +709,20 @@ fails == css-writing-modes/contiguous-fl
 fails == css-writing-modes/contiguous-floated-table-vlr-007.xht reference/ref-filled-green-100px-square.xht
 fails == css-writing-modes/contiguous-floated-table-vlr-009.xht reference/ref-filled-green-100px-square.xht
 fails == css-writing-modes/contiguous-floated-table-vrl-002.xht reference/ref-filled-green-100px-square.xht
 fails == css-writing-modes/contiguous-floated-table-vrl-004.xht reference/ref-filled-green-100px-square.xht
 fails == css-writing-modes/contiguous-floated-table-vrl-006.xht reference/ref-filled-green-100px-square.xht
 fails == css-writing-modes/contiguous-floated-table-vrl-008.xht reference/ref-filled-green-100px-square.xht
 == css-writing-modes/different-block-flow-dir-001.xht reference/ref-filled-green-100px-square.xht
 == css-writing-modes/different-block-flow-dir-002.xht reference/ref-filled-green-100px-square.xht
-fuzzy-if(OSX||winWidget,75,404) fails-if(webrender&&winWidget) == css-writing-modes/direction-vlr-003.xht css-writing-modes/direction-vlr-003-ref.xht
-fuzzy-if(OSX||winWidget,75,404) fails-if(webrender&&winWidget) == css-writing-modes/direction-vlr-005.xht reference/ref-filled-green-100px-square.xht
-fuzzy-if(OSX||winWidget,75,404) fails-if(webrender&&winWidget) == css-writing-modes/direction-vrl-002.xht css-writing-modes/direction-vrl-002-ref.xht
-fuzzy-if(OSX||winWidget,75,404) fails-if(webrender&&winWidget) == css-writing-modes/direction-vrl-004.xht css-writing-modes/direction-vrl-004-ref.xht
+fuzzy-if(OSX||winWidget,75,404) fuzzy-if(webrender&&winWidget,92-92,300-300) == css-writing-modes/direction-vlr-003.xht css-writing-modes/direction-vlr-003-ref.xht
+fuzzy-if(OSX||winWidget,75,404) fuzzy-if(webrender&&winWidget,92-92,300-300) == css-writing-modes/direction-vlr-005.xht reference/ref-filled-green-100px-square.xht
+fuzzy-if(OSX||winWidget,75,404) fuzzy-if(webrender&&winWidget,92-92,300-300) == css-writing-modes/direction-vrl-002.xht css-writing-modes/direction-vrl-002-ref.xht
+fuzzy-if(OSX||winWidget,75,404) fuzzy-if(webrender&&winWidget,92-92,300-300) == css-writing-modes/direction-vrl-004.xht css-writing-modes/direction-vrl-004-ref.xht
 == css-writing-modes/flexbox_align-items-stretch-writing-modes.html css-writing-modes/flexbox_align-items-stretch-writing-modes-ref.html
 == css-writing-modes/float-clear-vlr-003.xht reference/ref-filled-green-100px-square.xht
 == css-writing-modes/float-clear-vlr-005.xht reference/ref-filled-green-100px-square.xht
 == css-writing-modes/float-clear-vlr-007.xht reference/ref-filled-green-100px-square.xht
 == css-writing-modes/float-clear-vlr-009.xht reference/ref-filled-green-100px-square.xht
 == css-writing-modes/float-clear-vrl-002.xht reference/ref-filled-green-100px-square.xht
 == css-writing-modes/float-clear-vrl-004.xht reference/ref-filled-green-100px-square.xht
 == css-writing-modes/float-clear-vrl-006.xht reference/ref-filled-green-100px-square.xht
@@ -769,18 +769,18 @@ fuzzy-if(OSX||winWidget,93,300) == css-w
 fuzzy-if(OSX||winWidget,93,300) == css-writing-modes/float-vrl-010.xht reference/ref-filled-green-100px-square.xht
 fuzzy-if(OSX||winWidget,93,300) == css-writing-modes/float-vrl-012.xht reference/ref-filled-green-100px-square.xht
 != css-writing-modes/full-width-001.html css-writing-modes/reference/full-width-001-horizontal-notref.html
 != css-writing-modes/full-width-001.html css-writing-modes/reference/full-width-001-nofullwidth-notref.html
 != css-writing-modes/full-width-002.html css-writing-modes/reference/full-width-002-notcu-notref.html
 != css-writing-modes/full-width-002.html css-writing-modes/reference/full-width-002-horizontal-notref.html
 skip != css-writing-modes/full-width-003.html css-writing-modes/reference/full-width-002-notcu-notref.html
 skip != css-writing-modes/full-width-003.html css-writing-modes/reference/full-width-002-horizontal-notref.html
-fuzzy-if(OSX||winWidget,62,404) fails-if(webrender&&winWidget) == css-writing-modes/height-width-inline-non-replaced-vlr-003.xht reference/ref-filled-green-100px-square.xht
-fuzzy-if(OSX||winWidget,62,404) fails-if(webrender&&winWidget) == css-writing-modes/height-width-inline-non-replaced-vrl-002.xht css-writing-modes/abs-pos-non-replaced-icb-vrl-008-ref.xht
+fuzzy-if(OSX||winWidget,62,404) fuzzy-if(webrender&&winWidget,92-92,100-100) == css-writing-modes/height-width-inline-non-replaced-vlr-003.xht reference/ref-filled-green-100px-square.xht
+fuzzy-if(OSX||winWidget,62,404) fuzzy-if(webrender&&winWidget,92-92,100-100) == css-writing-modes/height-width-inline-non-replaced-vrl-002.xht css-writing-modes/abs-pos-non-replaced-icb-vrl-008-ref.xht
 == css-writing-modes/horizontal-rule-vlr-003.xht css-writing-modes/horizontal-rule-vlr-003-ref.xht
 == css-writing-modes/horizontal-rule-vlr-005.xht css-writing-modes/horizontal-rule-vrl-004-ref.xht
 == css-writing-modes/horizontal-rule-vrl-002.xht css-writing-modes/horizontal-rule-vrl-002-ref.xht
 == css-writing-modes/horizontal-rule-vrl-004.xht css-writing-modes/horizontal-rule-vrl-004-ref.xht
 fails == css-writing-modes/inline-block-alignment-002.xht css-writing-modes/inline-block-alignment-002-ref.xht
 fails == css-writing-modes/inline-block-alignment-003.xht css-writing-modes/inline-block-alignment-003-ref.xht
 fails == css-writing-modes/inline-block-alignment-004.xht css-writing-modes/inline-block-alignment-002-ref.xht
 fails == css-writing-modes/inline-block-alignment-005.xht css-writing-modes/inline-block-alignment-003-ref.xht
@@ -1043,34 +1043,34 @@ fails == css-writing-modes/table-progres
 == css-writing-modes/table-progression-vlr-001.html css-writing-modes/table-progression-001-ref.html
 fails == css-writing-modes/table-progression-vlr-002.html css-writing-modes/table-progression-002-ref.html
 fails == css-writing-modes/table-progression-vlr-003.html css-writing-modes/table-progression-001-ref.html
 fails == css-writing-modes/table-progression-vlr-004.html css-writing-modes/table-progression-002-ref.html
 == css-writing-modes/table-progression-vrl-001.html css-writing-modes/table-progression-001-ref.html
 fails == css-writing-modes/table-progression-vrl-002.html css-writing-modes/table-progression-002-ref.html
 fails == css-writing-modes/table-progression-vrl-003.html css-writing-modes/table-progression-001-ref.html
 fails == css-writing-modes/table-progression-vrl-004.html css-writing-modes/table-progression-002-ref.html
-fuzzy-if(OSX||winWidget,75,404) fails-if(webrender&&winWidget) == css-writing-modes/text-align-vlr-003.xht reference/ref-filled-green-100px-square.xht
-fuzzy-if(OSX||winWidget,75,404) fails-if(webrender&&winWidget) == css-writing-modes/text-align-vlr-005.xht reference/ref-filled-green-100px-square.xht
-fuzzy-if(OSX||winWidget,75,404) fails-if(webrender&&winWidget) == css-writing-modes/text-align-vlr-007.xht reference/ref-filled-green-100px-square.xht
-fuzzy-if(OSX||winWidget,75,404) fails-if(webrender&&winWidget) == css-writing-modes/text-align-vlr-009.xht css-writing-modes/text-align-vlr-009-ref.xht
-fuzzy-if(OSX||winWidget,75,404) fails-if(webrender&&winWidget) == css-writing-modes/text-align-vlr-011.xht css-writing-modes/text-align-vlr-009-ref.xht
-fuzzy-if(OSX||winWidget,75,404) fails-if(webrender&&winWidget) == css-writing-modes/text-align-vlr-013.xht css-writing-modes/text-align-vlr-009-ref.xht
-fuzzy-if(OSX||winWidget,75,404) fails-if(webrender&&winWidget) == css-writing-modes/text-align-vlr-015.xht css-writing-modes/direction-vlr-003-ref.xht
-fuzzy-if(OSX||winWidget,75,404) fails-if(webrender&&winWidget) == css-writing-modes/text-align-vlr-017.xht css-writing-modes/direction-vlr-003-ref.xht
-fuzzy-if(OSX||winWidget,75,404) fails-if(webrender&&winWidget) == css-writing-modes/text-align-vlr-019.xht css-writing-modes/direction-vlr-003-ref.xht
-fuzzy-if(OSX||winWidget,75,404) fails-if(webrender&&winWidget) == css-writing-modes/text-align-vrl-002.xht css-writing-modes/direction-vrl-004-ref.xht
-fuzzy-if(OSX||winWidget,75,404) fails-if(webrender&&winWidget) == css-writing-modes/text-align-vrl-004.xht css-writing-modes/direction-vrl-004-ref.xht
-fuzzy-if(OSX||winWidget,75,404) fails-if(webrender&&winWidget) == css-writing-modes/text-align-vrl-006.xht css-writing-modes/direction-vrl-004-ref.xht
-fuzzy-if(OSX||winWidget,75,404) fails-if(webrender&&winWidget) == css-writing-modes/text-align-vrl-008.xht css-writing-modes/text-align-vrl-008-ref.xht
-fuzzy-if(OSX||winWidget,75,404) fails-if(webrender&&winWidget) == css-writing-modes/text-align-vrl-010.xht css-writing-modes/text-align-vrl-008-ref.xht
-fuzzy-if(OSX||winWidget,75,404) fails-if(webrender&&winWidget) == css-writing-modes/text-align-vrl-012.xht css-writing-modes/text-align-vrl-008-ref.xht
-fuzzy-if(OSX||winWidget,75,404) fails-if(webrender&&winWidget) == css-writing-modes/text-align-vrl-014.xht css-writing-modes/direction-vrl-002-ref.xht
-fuzzy-if(OSX||winWidget,75,404) fails-if(webrender&&winWidget) == css-writing-modes/text-align-vrl-016.xht css-writing-modes/direction-vrl-002-ref.xht
-fuzzy-if(OSX||winWidget,75,404) fails-if(webrender&&winWidget) == css-writing-modes/text-align-vrl-018.xht css-writing-modes/direction-vrl-002-ref.xht
+fuzzy-if(OSX||winWidget,75,404) fuzzy-if(webrender&&winWidget,92-92,300-300) == css-writing-modes/text-align-vlr-003.xht reference/ref-filled-green-100px-square.xht
+fuzzy-if(OSX||winWidget,75,404) fuzzy-if(webrender&&winWidget,92-92,300-300) == css-writing-modes/text-align-vlr-005.xht reference/ref-filled-green-100px-square.xht
+fuzzy-if(OSX||winWidget,75,404) fuzzy-if(webrender&&winWidget,92-92,300-300) == css-writing-modes/text-align-vlr-007.xht reference/ref-filled-green-100px-square.xht
+fuzzy-if(OSX||winWidget,75,404) fuzzy-if(webrender&&winWidget,92-92,300-300) == css-writing-modes/text-align-vlr-009.xht css-writing-modes/text-align-vlr-009-ref.xht
+fuzzy-if(OSX||winWidget,75,404) fuzzy-if(webrender&&winWidget,92-92,300-300) == css-writing-modes/text-align-vlr-011.xht css-writing-modes/text-align-vlr-009-ref.xht
+fuzzy-if(OSX||winWidget,75,404) fuzzy-if(webrender&&winWidget,92-92,300-300) == css-writing-modes/text-align-vlr-013.xht css-writing-modes/text-align-vlr-009-ref.xht
+fuzzy-if(OSX||winWidget,75,404) fuzzy-if(webrender&&winWidget,92-92,300-300) == css-writing-modes/text-align-vlr-015.xht css-writing-modes/direction-vlr-003-ref.xht
+fuzzy-if(OSX||winWidget,75,404) fuzzy-if(webrender&&winWidget,92-92,300-300) == css-writing-modes/text-align-vlr-017.xht css-writing-modes/direction-vlr-003-ref.xht
+fuzzy-if(OSX||winWidget,75,404) fuzzy-if(webrender&&winWidget,92-92,300-300) == css-writing-modes/text-align-vlr-019.xht css-writing-modes/direction-vlr-003-ref.xht
+fuzzy-if(OSX||winWidget,75,404) fuzzy-if(webrender&&winWidget,92-92,300-300) == css-writing-modes/text-align-vrl-002.xht css-writing-modes/direction-vrl-004-ref.xht
+fuzzy-if(OSX||winWidget,75,404) fuzzy-if(webrender&&winWidget,92-92,300-300) == css-writing-modes/text-align-vrl-004.xht css-writing-modes/direction-vrl-004-ref.xht
+fuzzy-if(OSX||winWidget,75,404) fuzzy-if(webrender&&winWidget,92-92,300-300) == css-writing-modes/text-align-vrl-006.xht css-writing-modes/direction-vrl-004-ref.xht
+fuzzy-if(OSX||winWidget,75,404) fuzzy-if(webrender&&winWidget,92-92,300-300) == css-writing-modes/text-align-vrl-008.xht css-writing-modes/text-align-vrl-008-ref.xht
+fuzzy-if(OSX||winWidget,75,404) fuzzy-if(webrender&&winWidget,92-92,300-300) == css-writing-modes/text-align-vrl-010.xht css-writing-modes/text-align-vrl-008-ref.xht
+fuzzy-if(OSX||winWidget,75,404) fuzzy-if(webrender&&winWidget,92-92,300-300) == css-writing-modes/text-align-vrl-012.xht css-writing-modes/text-align-vrl-008-ref.xht
+fuzzy-if(OSX||winWidget,75,404) fuzzy-if(webrender&&winWidget,92-92,300-300) == css-writing-modes/text-align-vrl-014.xht css-writing-modes/direction-vrl-002-ref.xht
+fuzzy-if(OSX||winWidget,75,404) fuzzy-if(webrender&&winWidget,92-92,300-300) == css-writing-modes/text-align-vrl-016.xht css-writing-modes/direction-vrl-002-ref.xht
+fuzzy-if(OSX||winWidget,75,404) fuzzy-if(webrender&&winWidget,92-92,300-300) == css-writing-modes/text-align-vrl-018.xht css-writing-modes/direction-vrl-002-ref.xht
 fuzzy-if(OSX||winWidget,215,780) == css-writing-modes/text-baseline-slr-009.xht css-writing-modes/text-baseline-slr-009-ref.xht
 fuzzy-if(OSX||winWidget,215,780) == css-writing-modes/text-baseline-srl-008.xht css-writing-modes/text-baseline-vrl-006-ref.xht
 fuzzy-if(OSX||winWidget,215,780) == css-writing-modes/text-baseline-vlr-003.xht css-writing-modes/text-baseline-vrl-002-ref.xht
 fuzzy-if(OSX||winWidget,215,780) == css-writing-modes/text-baseline-vlr-005.xht css-writing-modes/text-baseline-vrl-002-ref.xht
 fuzzy-if(OSX||winWidget,215,780) == css-writing-modes/text-baseline-vlr-007.xht css-writing-modes/text-baseline-vrl-006-ref.xht
 fuzzy-if(OSX||winWidget,215,780) == css-writing-modes/text-baseline-vrl-002.xht css-writing-modes/text-baseline-vrl-002-ref.xht
 fuzzy-if(OSX||winWidget,215,780) == css-writing-modes/text-baseline-vrl-004.xht css-writing-modes/text-baseline-vrl-002-ref.xht
 fuzzy-if(OSX||winWidget,215,780) == css-writing-modes/text-baseline-vrl-006.xht css-writing-modes/text-baseline-vrl-006-ref.xht
--- a/layout/reftests/w3c-css/submitted/background/reftest.list
+++ b/layout/reftests/w3c-css/submitted/background/reftest.list
@@ -17,17 +17,17 @@
 == background-repeat-round-1d.html background-repeat-round-1-ref.html
 == background-repeat-round-1e.html background-repeat-round-1-ref.html
 == background-repeat-round-2.html background-repeat-round-2-ref.html
 == background-repeat-round-3.html background-repeat-round-3-ref.html
 == background-repeat-round-4.html background-repeat-round-4-ref.html
 
 #border-image test cases
 fuzzy-if(webrender,9-10,572-576) == border-image-repeat-round-1.html border-image-repeat-round-1-ref.html
-fuzzy-if(webrender,7-7,216-216) fails-if(webrender&&winWidget) == border-image-repeat-round-2.html border-image-repeat-round-2-ref.html
+fuzzy-if(webrender,7-7,216-224) == border-image-repeat-round-2.html border-image-repeat-round-2-ref.html
 == border-image-repeat-space-1.html border-image-repeat-space-1-ref.html
 == border-image-repeat-space-2.html border-image-repeat-space-2-ref.html
 == border-image-repeat-space-3.html border-image-repeat-space-3-ref.html
 == border-image-repeat-space-4.html border-image-repeat-space-4-ref-1.html
 == border-image-repeat-space-4-ref-1.html border-image-repeat-space-4-ref-2.html
 == border-image-repeat-space-5.html border-image-repeat-space-5-ref-1.html
 == border-image-repeat-space-5-ref-1.html border-image-repeat-space-5-ref-2.html
 == border-image-repeat-space-6.html border-image-repeat-space-6-ref.html
--- a/layout/reftests/writing-mode/reftest.list
+++ b/layout/reftests/writing-mode/reftest.list
@@ -145,17 +145,17 @@ test-pref(dom.meta-viewport.enabled,true
 == 1188061-1-nsChangeHint_ClearAncestorIntrinsics.html 1188061-1-nsChangeHint_ClearAncestorIntrinsics-ref.html
 == 1188061-2-nsChangeHint_UpdateComputedBSize.html 1188061-2-nsChangeHint_UpdateComputedBSize-ref.html
 
 # tests involving sideways-lr mode
 == 1193519-sideways-lr-1.html 1193519-sideways-lr-1-ref.html
 == 1193519-sideways-lr-2.html 1193519-sideways-lr-2-ref.html
 fuzzy-if(winWidget,3,84) fails-if(webrender&&winWidget) == 1193519-sideways-lr-3.html 1193519-sideways-lr-3-ref.html
 fuzzy-if(winWidget,3,112) fails-if(webrender) == 1193519-sideways-lr-4.html 1193519-sideways-lr-4-ref.html # see bug 1366692. Rounding error with WR enabled.
-fuzzy-if(gtkWidget,255,6) fuzzy-if(cocoaWidget,65,69) fails-if(webrender&&winWidget) == 1193519-sideways-lr-decoration-1.html 1193519-sideways-lr-decoration-1-ref.html
+fuzzy-if(gtkWidget,255,6) fuzzy-if(cocoaWidget,65,69) fuzzy-if(webrender&&winWidget,255-255,608-608) == 1193519-sideways-lr-decoration-1.html 1193519-sideways-lr-decoration-1-ref.html
 
 == 1196887-1-computed-display-inline-block.html 1196887-1-computed-display-inline-block-ref.html
 == 1205787-legacy-svg-values-1.html 1205787-legacy-svg-values-1-ref.html
 
 == 1216747-1.html 1216747-1-ref.html
 != 1216747-1.html 1216747-1-notref.html
 
 == 1243125-1-floats-overflowing.html 1243125-1-floats-overflowing-ref.html
--- a/layout/style/ErrorReporter.cpp
+++ b/layout/style/ErrorReporter.cpp
@@ -20,19 +20,18 @@
 #include "nsIScriptError.h"
 #include "nsISensitiveInfoHiddenURI.h"
 #include "nsIStringBundle.h"
 #include "nsServiceManagerUtils.h"
 #include "nsStyleUtil.h"
 #include "nsThreadUtils.h"
 #include "nsNetUtil.h"
 
-#ifdef CSS_REPORT_PARSE_ERRORS
-
 using namespace mozilla;
+using namespace mozilla::css;
 
 namespace {
 class ShortTermURISpecCache : public Runnable {
 public:
   ShortTermURISpecCache()
    : Runnable("ShortTermURISpecCache")
    , mPending(false) {}
 
@@ -62,73 +61,65 @@ public:
 private:
   nsCOMPtr<nsIURI> mURI;
   nsString mSpec;
   bool mPending;
 };
 
 } // namespace
 
-static bool sReportErrors;
+bool ErrorReporter::sReportErrors = false;
+bool ErrorReporter::sInitialized = false;
+
 static nsIConsoleService *sConsoleService;
 static nsIFactory *sScriptErrorFactory;
 static nsIStringBundle *sStringBundle;
 static ShortTermURISpecCache *sSpecCache;
 
 #define CSS_ERRORS_PREF "layout.css.report_errors"
 
-static bool
-InitGlobals()
+void
+ErrorReporter::InitGlobals()
 {
-  MOZ_ASSERT(!sConsoleService && !sScriptErrorFactory && !sStringBundle,
-             "should not have been called");
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!sInitialized, "should not have been called");
+
+  sInitialized = true;
 
-  if (NS_FAILED(Preferences::AddBoolVarCache(&sReportErrors, CSS_ERRORS_PREF,
+  if (NS_FAILED(Preferences::AddBoolVarCache(&sReportErrors,
+                                             CSS_ERRORS_PREF,
                                              true))) {
-    return false;
+    return;
   }
 
   nsCOMPtr<nsIConsoleService> cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
   if (!cs) {
-    return false;
+    return;
   }
 
   nsCOMPtr<nsIFactory> sf = do_GetClassObject(NS_SCRIPTERROR_CONTRACTID);
   if (!sf) {
-    return false;
+    return;
   }
 
   nsCOMPtr<nsIStringBundleService> sbs = services::GetStringBundleService();
   if (!sbs) {
-    return false;
+    return;
   }
 
   nsCOMPtr<nsIStringBundle> sb;
   nsresult rv = sbs->CreateBundle("chrome://global/locale/css.properties",
                                   getter_AddRefs(sb));
   if (NS_FAILED(rv) || !sb) {
-    return false;
+    return;
   }
 
   cs.forget(&sConsoleService);
   sf.forget(&sScriptErrorFactory);
   sb.forget(&sStringBundle);
-
-  return true;
-}
-
-static inline bool
-ShouldReportErrors()
-{
-  if (!sConsoleService) {
-    if (!InitGlobals()) {
-      return false;
-    }
-  }
-  return sReportErrors;
 }
 
 namespace mozilla {
 namespace css {
 
 /* static */ void
 ErrorReporter::ReleaseGlobals()
 {
@@ -165,23 +156,22 @@ ErrorReporter::~ErrorReporter()
       sSpecCache->SetPending();
     }
   }
 }
 
 void
 ErrorReporter::OutputError()
 {
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(ShouldReportErrors());
+
   if (mError.IsEmpty()) {
     return;
   }
-  if (!ShouldReportErrors()) {
-    ClearError();
-    return;
-  }
 
   if (mInnerWindowID == 0 && (mSheet || mLoader)) {
     if (mSheet) {
       mInnerWindowID = mSheet->FindOwningWindowInnerID();
     }
     if (mInnerWindowID == 0 && mLoader) {
       nsIDocument* doc = mLoader->GetDocument();
       if (doc) {
@@ -224,24 +214,16 @@ ErrorReporter::OutputError()
     if (NS_SUCCEEDED(rv)) {
       sConsoleService->LogMessage(errorObject);
     }
   }
 
   ClearError();
 }
 
-void
-ErrorReporter::OutputError(uint32_t aLineNumber, uint32_t aColNumber)
-{
-  mErrorLineNumber = aLineNumber;
-  mErrorColNumber = aColNumber;
-  OutputError();
-}
-
 // When Stylo's CSS parser is in use, this reporter does not have access to the CSS parser's
 // state. The users of ErrorReporter need to provide:
 // - the line number of the error
 // - the column number of the error
 // - the complete source line containing the invalid CSS
 
 void
 ErrorReporter::OutputError(uint32_t aLineNumber,
@@ -292,118 +274,23 @@ ErrorReporter::ReportUnexpected(const ch
   if (!ShouldReportErrors()) return;
 
   nsAutoString str;
   sStringBundle->GetStringFromName(aMessage, str);
   AddToError(str);
 }
 
 void
-ErrorReporter::ReportUnexpected(const char *aMessage,
-                                const nsString &aParam)
-{
-  if (!ShouldReportErrors()) return;
-
-  nsAutoString qparam;
-  nsStyleUtil::AppendEscapedCSSIdent(aParam, qparam);
-  const char16_t *params[1] = { qparam.get() };
-
-  nsAutoString str;
-  sStringBundle->FormatStringFromName(aMessage, params, ArrayLength(params),
-                                      str);
-  AddToError(str);
-}
-
-void
 ErrorReporter::ReportUnexpectedUnescaped(const char *aMessage,
                                          const nsAutoString& aParam)
 {
   if (!ShouldReportErrors()) return;
 
   const char16_t *params[1] = { aParam.get() };
 
   nsAutoString str;
   sStringBundle->FormatStringFromName(aMessage, params, ArrayLength(params),
                                       str);
   AddToError(str);
 }
 
-void
-ErrorReporter::ReportUnexpected(const char *aMessage,
-                                const nsCSSToken &aToken)
-{
-  if (!ShouldReportErrors()) return;
-
-  nsAutoString tokenString;
-  aToken.AppendToString(tokenString);
-  ReportUnexpectedUnescaped(aMessage, tokenString);
-}
-
-void
-ErrorReporter::ReportUnexpected(const char *aMessage,
-                                const nsCSSToken &aToken,
-                                char16_t aChar)
-{
-  if (!ShouldReportErrors()) return;
-
-  nsAutoString tokenString;
-  aToken.AppendToString(tokenString);
-  const char16_t charStr[2] = { aChar, 0 };
-  const char16_t *params[2] = { tokenString.get(), charStr };
-
-  nsAutoString str;
-  sStringBundle->FormatStringFromName(aMessage, params, ArrayLength(params),
-                                      str);
-  AddToError(str);
-}
-
-void
-ErrorReporter::ReportUnexpected(const char *aMessage,
-                                const nsString &aParam,
-                                const nsString &aValue)
-{
-  if (!ShouldReportErrors()) return;
-
-  nsAutoString qparam;
-  nsStyleUtil::AppendEscapedCSSIdent(aParam, qparam);
-  const char16_t *params[2] = { qparam.get(), aValue.get() };
-
-  nsAutoString str;
-  sStringBundle->FormatStringFromName(aMessage, params, ArrayLength(params),
-                                      str);
-  AddToError(str);
-}
-
-void
-ErrorReporter::ReportUnexpectedEOF(const char *aMessage)
-{
-  if (!ShouldReportErrors()) return;
-
-  nsAutoString innerStr;
-  sStringBundle->GetStringFromName(aMessage, innerStr);
-  const char16_t *params[1] = { innerStr.get() };
-
-  nsAutoString str;
-  sStringBundle->FormatStringFromName("PEUnexpEOF2", params,
-                                      ArrayLength(params), str);
-  AddToError(str);
-}
-
-void
-ErrorReporter::ReportUnexpectedEOF(char16_t aExpected)
-{
-  if (!ShouldReportErrors()) return;
-
-  const char16_t expectedStr[] = {
-    char16_t('\''), aExpected, char16_t('\''), char16_t(0)
-  };
-  const char16_t *params[1] = { expectedStr };
-
-  nsAutoString str;
-  sStringBundle->FormatStringFromName("PEUnexpEOF2", params,
-                                      ArrayLength(params), str);
-  AddToError(str);
-}
-
 } // namespace css
 } // namespace mozilla
-
-#endif
--- a/layout/style/ErrorReporter.h
+++ b/layout/style/ErrorReporter.h
@@ -4,112 +4,81 @@
  * 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/. */
 
 /* diagnostic reporting for CSS style sheet parser */
 
 #ifndef mozilla_css_ErrorReporter_h_
 #define mozilla_css_ErrorReporter_h_
 
-// XXX turn this off for minimo builds
-#define CSS_REPORT_PARSE_ERRORS
-
 #include "nsString.h"
 
 struct nsCSSToken;
 class nsIURI;
 
 namespace mozilla {
 class ServoStyleSheet;
 class StyleSheet;
 
 namespace css {
 
 class Loader;
 
-// If CSS_REPORT_PARSE_ERRORS is not defined, all of this class's
-// methods become inline stubs.
 class ErrorReporter {
 public:
   ErrorReporter(const StyleSheet* aSheet,
                 const Loader* aLoader,
                 nsIURI* aURI);
   ~ErrorReporter();
 
   static void ReleaseGlobals();
+  static void EnsureGlobalsInitialized()
+  {
+    if (MOZ_UNLIKELY(!sInitialized)) {
+      InitGlobals();
+    }
+  }
 
-  void OutputError();
-  void OutputError(uint32_t aLineNumber, uint32_t aLineOffset);
-  void OutputError(uint32_t aLineNumber, uint32_t aLineOffset, const nsACString& aSource);
+  bool ShouldReportErrors() const
+  {
+    EnsureGlobalsInitialized();
+    return sReportErrors;
+  }
+
+  void OutputError(uint32_t aLineNumber,
+                   uint32_t aLineOffset,
+                   const nsACString& aSource);
   void ClearError();
 
   // In all overloads of ReportUnexpected, aMessage is a stringbundle
   // name, which will be processed as a format string with the
   // indicated number of parameters.
 
   // no parameters
   void ReportUnexpected(const char *aMessage);
-  // one parameter, a string
-  void ReportUnexpected(const char *aMessage, const nsString& aParam);
-  // one parameter, a token
-  void ReportUnexpected(const char *aMessage, const nsCSSToken& aToken);
   // one parameter which has already been escaped appropriately
   void ReportUnexpectedUnescaped(const char *aMessage,
                                  const nsAutoString& aParam);
-  // two parameters, a token and a character, in that order
-  void ReportUnexpected(const char *aMessage, const nsCSSToken& aToken,
-                        char16_t aChar);
-  // two parameters, a param and a value
-  void ReportUnexpected(const char *aMessage, const nsString& aParam,
-                        const nsString& aValue);
-
-  // for ReportUnexpectedEOF, aExpected can be either a stringbundle
-  // name or a single character.  In the former case there may not be
-  // any format parameters.
-  void ReportUnexpectedEOF(const char *aExpected);
-  void ReportUnexpectedEOF(char16_t aExpected);
 
 private:
+  void OutputError();
   void AddToError(const nsString &aErrorText);
+  static void InitGlobals();
 
-#ifdef CSS_REPORT_PARSE_ERRORS
+  static bool sInitialized;
+  static bool sReportErrors;
+
   nsAutoString mError;
   nsString mErrorLine;
   nsString mFileName;
   const StyleSheet *mSheet;
   const Loader *mLoader;
   nsIURI *mURI;
   uint64_t mInnerWindowID;
   uint32_t mErrorLineNumber;
   uint32_t mPrevErrorLineNumber;
   uint32_t mErrorColNumber;
-#endif
 };
 
-#ifndef CSS_REPORT_PARSE_ERRORS
-inline ErrorReporter::ErrorReporter(const StyleSheet*,
-                                    const Loader*,
-                                    nsIURI*) {}
-inline ErrorReporter::~ErrorReporter() {}
-
-inline void ErrorReporter::ReleaseGlobals() {}
-
-inline void ErrorReporter::OutputError() {}
-inline void ErrorReporter::ClearError() {}
-
-inline void ErrorReporter::ReportUnexpected(const char *) {}
-inline void ErrorReporter::ReportUnexpected(const char *, const nsString &) {}
-inline void ErrorReporter::ReportUnexpected(const char *, const nsCSSToken &) {}
-inline void ErrorReporter::ReportUnexpected(const char *, const nsCSSToken &,
-                                            char16_t) {}
-inline void ErrorReporter::ReportUnexpected(const char *, const nsString &,
-                                            const nsString &) {}
-
-inline void ErrorReporter::ReportUnexpectedEOF(const char *) {}
-inline void ErrorReporter::ReportUnexpectedEOF(char16_t) {}
-
-inline void ErrorReporter::AddToError(const nsString &) {}
-#endif
-
 } // namespace css
 } // namespace mozilla
 
 #endif // mozilla_css_ErrorReporter_h_
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -2676,17 +2676,21 @@ Gecko_ReportUnexpectedCSSError(ErrorRepo
                                const char* prefixParam,
                                uint32_t prefixParamLen,
                                const char* suffix,
                                const char* source,
                                uint32_t sourceLen,
                                uint32_t lineNumber,
                                uint32_t colNumber)
 {
-  MOZ_ASSERT(NS_IsMainThread());
+  if (!reporter->ShouldReportErrors()) {
+    return;
+  }
+
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
 
   if (prefix) {
     if (prefixParam) {
       nsDependentCSubstring paramValue(prefixParam, prefixParamLen);
       nsAutoString wideParam = NS_ConvertUTF8toUTF16(paramValue);
       reporter->ReportUnexpectedUnescaped(prefix, wideParam);
     } else {
       reporter->ReportUnexpected(prefix);
--- a/layout/style/jar.mn
+++ b/layout/style/jar.mn
@@ -5,17 +5,16 @@
 toolkit.jar:
 *  res/ua.css                                (res/ua.css)
 *  res/html.css                              (res/html.css)
    res/quirk.css                             (res/quirk.css)
    res/counterstyles.css                     (res/counterstyles.css)
    res/noscript.css                          (res/noscript.css)
    res/noframes.css                          (res/noframes.css)
 *  res/forms.css                             (res/forms.css)
-   res/number-control.css                    (res/number-control.css)
    res/arrow.gif                             (res/arrow.gif)
    res/arrow-left.gif                        (res/arrow-left.gif)
    res/arrow-right.gif                       (res/arrow-right.gif)
    res/arrowd.gif                            (res/arrowd.gif)
    res/arrowd-left.gif                       (res/arrowd-left.gif)
    res/arrowd-right.gif                      (res/arrowd-right.gif)
    res/accessiblecaret-normal@1x.png         (res/accessiblecaret-normal@1x.png)
    res/accessiblecaret-normal@1.5x.png       (res/accessiblecaret-normal@1.5x.png)
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -2953,28 +2953,16 @@ CSS_PROP_(
     stroke-width,
     stroke_width,
     StrokeWidth,
     0,
     "",
     VARIANT_HLPN | VARIANT_OPENTYPE_SVG_KEYWORD,
     kStrokeContextValueKTable,
     eStyleAnimType_Coord)
-#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
-CSS_PROP_(
-    -x-system-font,
-    _x_system_font,
-    CSS_PROP_DOMPROP_PREFIXED(SystemFont),
-    CSS_PROPERTY_INTERNAL |
-        CSS_PROPERTY_PARSE_INACCESSIBLE,
-    "",
-    0,
-    kFontKTable,
-    eStyleAnimType_None)
-#endif // CSS_PROP_LIST_EXCLUDE_INTERNAL
 CSS_PROP_(
     -moz-tab-size,
     _moz_tab_size,
     CSS_PROP_DOMPROP_PREFIXED(TabSize),
     0,
     "",
     VARIANT_INHERIT | VARIANT_LNCALC,
     nullptr,
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -2486,17 +2486,16 @@ static const nsCSSPropertyID gBorderWidt
 static const nsCSSPropertyID gFontSubpropTable[] = {
   eCSSProperty_font_family,
   eCSSProperty_font_style,
   eCSSProperty_font_weight,
   eCSSProperty_font_size,
   eCSSProperty_line_height,
   eCSSProperty_font_size_adjust,
   eCSSProperty_font_stretch,
-  eCSSProperty__x_system_font,
   eCSSProperty_font_feature_settings,
   eCSSProperty_font_language_override,
   eCSSProperty_font_kerning,
   eCSSProperty_font_optical_sizing,
   eCSSProperty_font_variation_settings,
   eCSSProperty_font_variant_alternates,
   eCSSProperty_font_variant_caps,
   eCSSProperty_font_variant_east_asian,
--- a/layout/style/nsCSSScanner.cpp
+++ b/layout/style/nsCSSScanner.cpp
@@ -347,17 +347,16 @@ nsCSSScanner::nsCSSScanner(const nsAStri
   , mCount(aBuffer.Length())
   , mLineNumber(aLineNumber)
   , mLineOffset(0)
   , mTokenLineNumber(aLineNumber)
   , mTokenLineOffset(0)
   , mTokenOffset(0)
   , mRecordStartOffset(0)
   , mEOFCharacters(eEOFCharacters_None)
-  , mReporter(nullptr)
   , mRecording(false)
   , mSeenBadToken(false)
   , mSeenVariableReference(false)
 {
   MOZ_COUNT_CTOR(nsCSSScanner);
 }
 
 nsCSSScanner::~nsCSSScanner()
@@ -587,30 +586,26 @@ nsCSSScanner::SkipComment()
       mSourceURL.Truncate();
       directive = &mSourceURL;
     }
   }
 
   for (;;) {
     int32_t ch = Peek();
     if (ch < 0) {
-      if (mReporter)
-        mReporter->ReportUnexpectedEOF("PECommentEOF");
       SetEOFCharacters(eEOFCharacters_Asterisk | eEOFCharacters_Slash);
       return;
     }
 
     if (ch == '*') {
       Advance();
       ch = Peek();
       if (ch < 0) {
         // In this case, even if we saw a source map directive, leave
         // the "*" out of it.
-        if (mReporter)
-          mReporter->ReportUnexpectedEOF("PECommentEOF");
         SetEOFCharacters(eEOFCharacters_Slash);
         return;
       }
       if (ch == '/') {
         Advance();
         return;
       }
       if (directive != nullptr) {
@@ -1041,18 +1036,16 @@ nsCSSScanner::ScanString(nsCSSToken& aTo
     if (ch == '"' || ch == '\'') {
       aToken.mIdent.Append(ch);
       Advance();
       continue;
     }
 
     mSeenBadToken = true;
     aToken.mType = eCSSToken_Bad_String;
-    if (mReporter)
-      mReporter->ReportUnexpected("SEUnterminatedString", aToken);
     break;
   }
   return true;
 }
 
 /**
  * Scan a unicode-range token.  These match the regular expression
  *
--- a/layout/style/nsCSSScanner.h
+++ b/layout/style/nsCSSScanner.h
@@ -201,20 +201,16 @@ class nsCSSScanner {
   public:
   // |aLineNumber == 1| is the beginning of a file, use |aLineNumber == 0|
   // when the line number is unknown.  The scanner does not take
   // ownership of |aBuffer|, so the caller must be sure to keep it
   // alive for the lifetime of the scanner.
   nsCSSScanner(const nsAString& aBuffer, uint32_t aLineNumber);
   ~nsCSSScanner();
 
-  void SetErrorReporter(mozilla::css::ErrorReporter* aReporter) {
-    mReporter = aReporter;
-  }
-
   // Reset or check whether a BAD_URL or BAD_STRING token has been seen.
   void ClearSeenBadToken() { mSeenBadToken = false; }
   bool SeenBadToken() const { return mSeenBadToken; }
 
   // Reset or check whether a "var(" FUNCTION token has been seen.
   void ClearSeenVariableReference() { mSeenVariableReference = false; }
   bool SeenVariableReference() const { return mSeenVariableReference; }
 
@@ -359,18 +355,16 @@ protected:
 
   uint32_t mTokenLineNumber;
   uint32_t mTokenLineOffset;
   uint32_t mTokenOffset;
 
   uint32_t mRecordStartOffset;
   EOFCharacters mEOFCharacters;
 
-  mozilla::css::ErrorReporter *mReporter;
-
   bool mRecording;
   bool mSeenBadToken;
   bool mSeenVariableReference;
 
   nsString mSourceMapURL;
   nsString mSourceURL;
 };
 
--- a/layout/style/nsLayoutStylesheetCache.cpp
+++ b/layout/style/nsLayoutStylesheetCache.cpp
@@ -35,20 +35,16 @@
 #include "nsXULAppAPI.h"
 #include "nsZipArchive.h"
 
 #include "zlib.h"
 
 using namespace mozilla;
 using namespace mozilla::css;
 
-static bool sNumberControlEnabled;
-
-#define NUMBER_CONTROL_PREF "dom.forms.number"
-
 NS_IMPL_ISUPPORTS(
   nsLayoutStylesheetCache, nsIObserver, nsIMemoryReporter)
 
 nsresult
 nsLayoutStylesheetCache::Observe(nsISupports* aSubject,
                             const char* aTopic,
                             const char16_t* aData)
 {
@@ -58,17 +54,16 @@ nsLayoutStylesheetCache::Observe(nsISupp
   }
   else if (!strcmp(aTopic, "profile-do-change")) {
     InitFromProfile();
   }
   else if (strcmp(aTopic, "chrome-flush-skin-caches") == 0 ||
            strcmp(aTopic, "chrome-flush-caches") == 0) {
     mScrollbarsSheet = nullptr;
     mFormsSheet = nullptr;
-    mNumberControlSheet = nullptr;
   }
   else {
     NS_NOTREACHED("Unexpected observer topic.");
   }
   return NS_OK;
 }
 
 StyleSheet*
@@ -91,31 +86,16 @@ nsLayoutStylesheetCache::FormsSheet()
     LoadSheetURL("resource://gre-resources/forms.css",
                  &mFormsSheet, eAgentSheetFeatures, eCrash);
   }
 
   return mFormsSheet;
 }
 
 StyleSheet*
-nsLayoutStylesheetCache::NumberControlSheet()
-{
-  if (!sNumberControlEnabled) {
-    return nullptr;
-  }
-
-  if (!mNumberControlSheet) {
-    LoadSheetURL("resource://gre-resources/number-control.css",
-                 &mNumberControlSheet, eAgentSheetFeatures, eCrash);
-  }
-
-  return mNumberControlSheet;
-}
-
-StyleSheet*
 nsLayoutStylesheetCache::UserContentSheet()
 {
   return mUserContentSheet;
 }
 
 StyleSheet*
 nsLayoutStylesheetCache::UserChromeSheet()
 {
@@ -305,17 +285,16 @@ nsLayoutStylesheetCache::SizeOfIncluding
   MEASURE(mCounterStylesSheet);
   MEASURE(mDesignModeSheet);
   MEASURE(mFormsSheet);
   MEASURE(mHTMLSheet);
   MEASURE(mMathMLSheet);
   MEASURE(mMinimalXULSheet);
   MEASURE(mNoFramesSheet);
   MEASURE(mNoScriptSheet);
-  MEASURE(mNumberControlSheet);
   MEASURE(mQuirkSheet);
   MEASURE(mSVGSheet);
   MEASURE(mScrollbarsSheet);
   MEASURE(mUASheet);
   MEASURE(mUserChromeSheet);
   MEASURE(mUserContentSheet);
   MEASURE(mXULSheet);
   MEASURE(mXULComponentsSheet);
@@ -387,19 +366,16 @@ nsLayoutStylesheetCache::InitMemoryRepor
 nsLayoutStylesheetCache::Singleton()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!gStyleCache) {
     gStyleCache = new nsLayoutStylesheetCache;
     gStyleCache->InitMemoryReporter();
 
-    Preferences::AddBoolVarCache(&sNumberControlEnabled, NUMBER_CONTROL_PREF,
-                                 true);
-
     // For each pref that controls a CSS feature that a UA style sheet depends
     // on (such as a pref that enables a property that a UA style sheet uses),
     // register DependentPrefChanged as a callback to ensure that the relevant
     // style sheets will be re-parsed.
     // Preferences::RegisterCallback(&DependentPrefChanged,
     //                               "layout.css.example-pref.enabled");
   }
 
--- a/layout/style/nsLayoutStylesheetCache.h
+++ b/layout/style/nsLayoutStylesheetCache.h
@@ -40,19 +40,16 @@ class nsLayoutStylesheetCache final
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
   NS_DECL_NSIMEMORYREPORTER
 
   static nsLayoutStylesheetCache* Singleton();
 
   mozilla::StyleSheet* ScrollbarsSheet();
   mozilla::StyleSheet* FormsSheet();
-  // This function is expected to return nullptr when the dom.forms.number
-  // pref is disabled.
-  mozilla::StyleSheet* NumberControlSheet();
   mozilla::StyleSheet* UserContentSheet();
   mozilla::StyleSheet* UserChromeSheet();
   mozilla::StyleSheet* UASheet();
   mozilla::StyleSheet* HTMLSheet();
   mozilla::StyleSheet* MinimalXULSheet();
   mozilla::StyleSheet* XULSheet();
   mozilla::StyleSheet* XULComponentsSheet();
   mozilla::StyleSheet* QuirkSheet();
@@ -103,17 +100,16 @@ private:
   RefPtr<mozilla::StyleSheet> mCounterStylesSheet;
   RefPtr<mozilla::StyleSheet> mDesignModeSheet;
   RefPtr<mozilla::StyleSheet> mFormsSheet;
   RefPtr<mozilla::StyleSheet> mHTMLSheet;
   RefPtr<mozilla::StyleSheet> mMathMLSheet;
   RefPtr<mozilla::StyleSheet> mMinimalXULSheet;
   RefPtr<mozilla::StyleSheet> mNoFramesSheet;
   RefPtr<mozilla::StyleSheet> mNoScriptSheet;
-  RefPtr<mozilla::StyleSheet> mNumberControlSheet;
   RefPtr<mozilla::StyleSheet> mQuirkSheet;
   RefPtr<mozilla::StyleSheet> mSVGSheet;
   RefPtr<mozilla::StyleSheet> mScrollbarsSheet;
   RefPtr<mozilla::StyleSheet> mUASheet;
   RefPtr<mozilla::StyleSheet> mUserChromeSheet;
   RefPtr<mozilla::StyleSheet> mUserContentSheet;
   RefPtr<mozilla::StyleSheet> mXULSheet;
   RefPtr<mozilla::StyleSheet> mXULComponentsSheet;
--- a/layout/style/res/forms.css
+++ b/layout/style/res/forms.css
@@ -1029,19 +1029,24 @@ input[type=range]::-moz-range-thumb {
   height: 1em;
   border: 0.1em solid #999;
   border-radius: 0.5em;
   background-color: #F0F0F0;
   /* Prevent nsFrame::HandlePress setting mouse capture to this element. */
   -moz-user-select: none ! important;
 }
 
-/* As a temporary workaround until bug 677302 the rule for input[type=number]
- * has moved to number-control.css
- */
+input[type="number"] {
+  -moz-appearance: number-input;
+  /* Has to revert some properties applied by the generic input rule. */
+  -moz-binding: none;
+  inline-size: 20ch; /* It'd be nice if this matched the default inline-size
+                        of <input type=text>, but that's not easy to achieve
+                        due to platform differences. */
+}
 
 input[type=number]::-moz-number-wrapper {
   /* Prevent styling that would change the type of frame we construct. */
   display: flex;
   float: none !important;
   position: static !important;
   block-size: 100%;
 }
deleted file mode 100644
--- a/layout/style/res/number-control.css
+++ /dev/null
@@ -1,18 +0,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/. */
-
-/* This file exists purely because we need the styling for input[type=number]
- * to apply only if the pref dom.forms.number is true. Once bug 677302 is
- * fixed this rule can move back to forms.css.
- */
-
-input[type="number"] {
-  -moz-appearance: number-input;
-  /* Has to revert some properties applied by the generic input rule. */
-  -moz-binding: none;
-  inline-size: 20ch; /* It'd be nice if this matched the default inline-size
-                        of <input type=text>, but that's not easy to achieve
-                        due to platform differences. */
-}
-
--- a/layout/style/test/ListCSSProperties.cpp
+++ b/layout/style/test/ListCSSProperties.cpp
@@ -96,17 +96,16 @@ const char* gShorthandPropertiesWithDOMP
 };
 
 const char *gInaccessibleProperties[] = {
     // Don't print the properties that aren't accepted by the parser, per
     // CSSParserImpl::ParseProperty
     "-x-cols",
     "-x-lang",
     "-x-span",
-    "-x-system-font",
     "-x-text-zoom",
     "-moz-context-properties",
     "-moz-control-character-visibility",
     "-moz-script-level", // parsed by UA sheets only
     "-moz-script-size-multiplier",
     "-moz-script-min-size",
     "-moz-math-variant",
     "-moz-math-display", // parsed by UA sheets only
--- a/layout/style/test/test_shorthand_property_getters.html
+++ b/layout/style/test/test_shorthand_property_getters.html
@@ -232,17 +232,17 @@ is(e.style.animation, "", "should not ha
 e.setAttribute("style", "animation-name: bounce, roll; animation-duration: 1s, 200ms; animation-timing-function: ease-in, linear; animation-delay: 0s, 1s; animation-direction: normal, reverse; animation-fill-mode: forwards, backwards; animation-iteration-count: infinite, 2; animation-play-state: paused, running, running;");
 is(e.style.animation, "", "should not have animation shorthand (lists different lengths)");
 
 // Check that the 'border' shorthand resets 'border-image' and
 // but that other 'border-*' shorthands don't
 // (bug 482692).
 e.setAttribute("style", 'border-image: url("foo.png") 5 5 5 5 / 5 5 5 5 / 5 5 5 5 repeat repeat; border-left: medium solid green');
 is(e.style.cssText,
-   'border-image: url("foo.png") 5 / 5 / 5 repeat repeat; border-left: medium solid green;',
+   'border-image: url("foo.png") 5 / 5 / 5 repeat; border-left: medium solid green;',
    "border-left does NOT reset border-image");
 e.setAttribute("style", 'border-image: url("foo.png") 5 5 5 5; border: medium solid green');
 is(e.style.cssText,
    'border: medium solid green;',
    "border DOES reset border-image");
 
 // Test that the color goes at the beginning of the last item of the
 // background shorthand.
--- a/layout/style/test/test_variables.html
+++ b/layout/style/test/test_variables.html
@@ -85,29 +85,16 @@ var tests = [
     var element = document.getElementById("t5");
     var cs = window.getComputedStyle(element);
 
     is(cs.item(cs.length - 1), "--SomeVariableName", "custom property name returned by item() on computed style");
     is(cs[cs.length - 1], "--SomeVariableName", "custom property name returned by indexed getter on style declaration");
   },
 
   function() {
-    // https://bugzilla.mozilla.org/show_bug.cgi?id=969756
-    if (SpecialPowers.DOMWindowUtils.isStyledByServo) {
-      // This test is irrelevant when using stylo.
-      return;
-    }
-    var test6 = document.getElementById("test6");
-    test6.textContent = "p { font: var(--var6) hangul mongolian; font-size-adjust: none; }";
-    var declaration = test6.sheet.cssRules[0].style;
-    test6.style.color = "white";
-    is(declaration.getPropertyValue("-x-system-font"), " var(--var6) hangul mongolian");
-  },
-
-  function() {
     // https://bugzilla.mozilla.org/show_bug.cgi?id=1154356
     var test7 = document.getElementById("test7");
     test7.textContent = "p { --weird\\;name: green; }";
     is(test7.sheet.cssRules[0].style.cssText, "--weird\\;name: green;");
     test7.textContent = "p { --0: green; }";
     is(test7.sheet.cssRules[0].style.cssText, "--0: green;");
   },
 
--- a/layout/tools/reftest/reftest.jsm
+++ b/layout/tools/reftest/reftest.jsm
@@ -158,17 +158,17 @@ function OnRefTestLoad(win)
               getService(Ci.nsIEnvironment);
 
     var prefs = Cc["@mozilla.org/preferences-service;1"].
                 getService(Ci.nsIPrefBranch);
     g.browserIsRemote = prefs.getBoolPref("browser.tabs.remote.autostart", false);
 
     g.browserIsIframe = prefs.getBoolPref("reftest.browser.iframe.enabled", false);
 
-    g.logLevel = prefs.getCharPref("reftest.logLevel", "info");
+    g.logLevel = prefs.getStringPref("reftest.logLevel", "info");
 
     if (win === undefined || win == null) {
       win = window;
     }
     if (g.containingWindow == null && win != null) {
       g.containingWindow = win;
     }
 
@@ -232,17 +232,17 @@ function InitAndStartRefTests()
     try {
         g.loadTimeout = prefs.getIntPref("reftest.timeout");
     } catch(e) {
         g.loadTimeout = 5 * 60 * 1000; //5 minutes as per bug 479518
     }
 
     /* Get the logfile for android tests */
     try {
-        var logFile = prefs.getCharPref("reftest.logFile");
+        var logFile = prefs.getStringPref("reftest.logFile");
         if (logFile) {
             var f = FileUtils.File(logFile);
             g.logFile = FileUtils.openFileOutputStream(f, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE);
         }
     } catch(e) {}
 
     g.remote = prefs.getBoolPref("reftest.remote", false);
 
@@ -254,17 +254,17 @@ function InitAndStartRefTests()
         g.thisChunk = prefs.getIntPref("reftest.thisChunk");
     }
     catch(e) {
         g.totalChunks = 0;
         g.thisChunk = 0;
     }
 
     try {
-        g.focusFilterMode = prefs.getCharPref("reftest.focusFilterMode");
+        g.focusFilterMode = prefs.getStringPref("reftest.focusFilterMode");
     } catch(e) {}
 
     try {
         g.compareRetainedDisplayLists = prefs.getBoolPref("reftest.compareRetainedDisplayLists");
     } catch (e) {}
 
 #ifdef MOZ_ENABLE_SKIA_PDF
     try {
@@ -348,19 +348,19 @@ function ReadTests() {
          * The first will parse the specified manifests, then immediately
          * run the tests. The second will parse the manifests, save the test
          * objects to a file and exit. The third will load a file of test
          * objects and run them.
          *
          * The latter two modes are used to pass test data back and forth
          * with python harness.
         */
-        let manifests = prefs.getCharPref("reftest.manifests", null);
-        let dumpTests = prefs.getCharPref("reftest.manifests.dumpTests", null);
-        let testList = prefs.getCharPref("reftest.tests", null);
+        let manifests = prefs.getStringPref("reftest.manifests", null);
+        let dumpTests = prefs.getStringPref("reftest.manifests.dumpTests", null);
+        let testList = prefs.getStringPref("reftest.tests", null);
 
         if ((testList && manifests) || !(testList || manifests)) {
             logger.error("Exactly one of reftest.manifests or reftest.tests must be specified.");
             DoneTests();
         }
 
         if (testList) {
             logger.debug("Reading test objects from: " + testList);
@@ -495,17 +495,17 @@ function StartTests()
 
             g.urls = g.urls.slice(start, end);
         }
 
         if (g.manageSuite && !g.suiteStarted) {
             var ids = g.urls.map(function(obj) {
                 return obj.identifier;
             });
-            var suite = prefs.getCharPref('reftest.suite', 'reftest');
+            var suite = prefs.getStringPref('reftest.suite', 'reftest');
             logger.suiteStart(ids, suite, {"skipped": g.urls.length - numActiveTests});
             g.suiteStarted = true
         }
 
         if (g.shuffle) {
             Shuffle(g.urls);
         }
 
@@ -667,17 +667,17 @@ function StartCurrentURI(aURLTargetType)
                     try {
                         oldVal = prefs.getBoolPref(ps.name);
                     } catch (e) {
                         badPref = "boolean preference '" + ps.name + "'";
                         throw "bad pref";
                     }
                 } else if (ps.type == PREF_STRING) {
                     try {
-                        oldVal = prefs.getCharPref(ps.name);
+                        oldVal = prefs.getStringPref(ps.name);
                     } catch (e) {
                         badPref = "string preference '" + ps.name + "'";
                         throw "bad pref";
                     }
                 } else if (ps.type == PREF_INTEGER) {
                     try {
                         oldVal = prefs.getIntPref(ps.name);
                     } catch (e) {
@@ -690,17 +690,17 @@ function StartCurrentURI(aURLTargetType)
                 if (oldVal != ps.value) {
                     g.prefsToRestore.push( { name: ps.name,
                                             type: ps.type,
                                             value: oldVal } );
                     var value = ps.value;
                     if (ps.type == PREF_BOOLEAN) {
                         prefs.setBoolPref(ps.name, value);
                     } else if (ps.type == PREF_STRING) {
-                        prefs.setCharPref(ps.name, value);
+                        prefs.setStringPref(ps.name, value);
                         value = '"' + value + '"';
                     } else if (ps.type == PREF_INTEGER) {
                         prefs.setIntPref(ps.name, value);
                     }
                     logger.info("SET PREFERENCE pref(" + ps.name + "," + value + ")");
                 }
             });
         } catch (e) {
@@ -1359,17 +1359,17 @@ function RestoreChangedPreferences()
         var prefs = Cc["@mozilla.org/preferences-service;1"].
                     getService(Ci.nsIPrefBranch);
         g.prefsToRestore.reverse();
         g.prefsToRestore.forEach(function(ps) {
             var value = ps.value;
             if (ps.type == PREF_BOOLEAN) {
                 prefs.setBoolPref(ps.name, value);
             } else if (ps.type == PREF_STRING) {
-                prefs.setCharPref(ps.name, value);
+                prefs.setStringPref(ps.name, value);
                 value = '"' + value + '"';
             } else if (ps.type == PREF_INTEGER) {
                 prefs.setIntPref(ps.name, value);
             }
             logger.info("RESTORE PREFERENCE pref(" + ps.name + "," + value + ")");
         });
         g.prefsToRestore = [];
     }
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -176,17 +176,16 @@ pref("findhelper.autozoom", true);
 pref("browser.formfill.enable", true);
 
 /* spellcheck */
 pref("layout.spellcheckDefault", 0);
 
 /* new html5 forms */
 pref("dom.forms.datetime", true);
 pref("dom.forms.datetime.others", true);
-pref("dom.forms.number", true);
 
 /* extension manager and xpinstall */
 pref("xpinstall.whitelist.directRequest", false);
 pref("xpinstall.whitelist.fileRequest", false);
 pref("xpinstall.whitelist.add", "https://addons.mozilla.org,https://testpilot.firefox.com");
 
 pref("xpinstall.signatures.required", true);
 
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -1367,16 +1367,18 @@ public class BrowserApp extends GeckoApp
                 final SharedPreferences sharedPrefs = GeckoSharedPrefs.forProfileName(BrowserApp.this, profile.getName());
                 FileCleanupController.startIfReady(BrowserApp.this, sharedPrefs, profile.getDir().getAbsolutePath());
             }
         });
 
         for (final BrowserAppDelegate delegate : delegates) {
             delegate.onStart(this);
         }
+
+        MmaDelegate.track(MmaDelegate.RESUMED_FROM_BACKGROUND);
     }
 
     @Override
     public void onStop() {
         super.onStop();
         if (mIsAbortingAppLaunch) {
             return;
         }
--- a/mobile/android/base/java/org/mozilla/gecko/mma/MmaDelegate.java
+++ b/mobile/android/base/java/org/mozilla/gecko/mma/MmaDelegate.java
@@ -42,16 +42,17 @@ public class MmaDelegate {
     public static final String CLEARED_PRIVATE_DATA = "E_Cleared_Private_Data";
     public static final String SAVED_BOOKMARK = "E_Saved_Bookmark";
     public static final String OPENED_BOOKMARK = "E_Opened_Bookmark";
     public static final String INTERACT_WITH_SEARCH_URL_AREA = "E_Interact_With_Search_URL_Area";
     public static final String SCREENSHOT = "E_Screenshot";
     public static final String SAVED_LOGIN_AND_PASSWORD = "E_Saved_Login_And_Password";
     public static final String LAUNCH_BUT_NOT_DEFAULT_BROWSER = "E_Launch_But_Not_Default_Browser";
     public static final String LAUNCH_BROWSER = "E_Launch_Browser";
+    public static final String RESUMED_FROM_BACKGROUND = "E_Resumed_From_Background";
     public static final String NEW_TAB = "E_Opened_New_Tab";
     public static final String DISMISS_ONBOARDING = "E_Dismiss_Onboarding";
 
 
     public static final String USER_ATT_FOCUS_INSTALLED = "Focus Installed";
     public static final String USER_ATT_KLAR_INSTALLED = "Klar Installed";
     public static final String USER_ATT_POCKET_INSTALLED = "Pocket Installed";
     public static final String USER_ATT_DEFAULT_BROWSER = "Default Browser";
--- a/mobile/android/docs/mma.rst
+++ b/mobile/android/docs/mma.rst
@@ -59,16 +59,17 @@ following parameters::
   // Sent when the app starts
   "action" -> "start"                   // start: Leanplum SDK starts. heartbeat
   "userAttributes" -> "{                // A set of key-value pairs used to describe the user.
     "Focus Installed" -> true           // If Focus for Android is installed.
     "Klar Installed" -> true            // If Klar for Android is installed.
     "Pocket Installed" -> true          // If Pocket for Android is installed.
     "Signed In Sync" -> true            // If the user has signed in to Mozilla account.
     "Default Browser" -> true           // If the user has set Fennec as default browser.
+    "Pocket in Top Sites" -> true       // If Top Sites home panel contain websites recommended by Pocket
   }
   "appId" -> "app_6Ao...."              // Leanplum App ID.
   "clientKey" -> "dev_srwDUNZR...."     // Leanplum client access key.
   "systemName" -> "Android OS"          // Fixed String in SDK.
   "locale" -> "zh_TW"                   // System Locale.
   "timezone" -> "Asia/Taipei"           // System Timezone.
   "versionName" -> "55.0a1"             // Fennec version.
   "systemVersion" -> "7.1.2"            // System version.
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/GeckoBundle.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/GeckoBundle.java
@@ -244,59 +244,59 @@ public final class GeckoBundle implement
      */
     public int[] getIntArray(final String key) {
         final Object value = mMap.get(key);
         return value == null ? null : Array.getLength(value) == 0 ? EMPTY_INT_ARRAY :
                value instanceof double[] ? getIntArray((double[]) value) : (int[]) value;
     }
 
     /**
-     * Returns the value associated with a long mapping, or defaultValue if the mapping
-     * does not exist.
+     * Returns the value associated with an int/double mapping as a long value, or
+     * defaultValue if the mapping does not exist.
      *
      * @param key Key to look for.
      * @param defaultValue Value to return if mapping does not exist.
-     * @return long value
+     * @return Long value
      */
     public long getLong(final String key, final long defaultValue) {
         final Object value = mMap.get(key);
         return value == null ? defaultValue : ((Number) value).longValue();
     }
 
     /**
-     * Returns the value associated with a long mapping, or defaultValue if the mapping
-     * does not exist.
+     * Returns the value associated with an int/double mapping as a long value, or
+     * 0 if the mapping does not exist.
      *
      * @param key Key to look for.
-     * @return long value
+     * @return Long value
      */
     public long getLong(final String key) {
         return getLong(key, 0L);
     }
 
-    private static long[] getLongArray(final double[] array) {
-        final int len = array.length;
+    private static long[] getLongArray(final Object array) {
+        final int len = Array.getLength(array);
         final long[] ret = new long[len];
         for (int i = 0; i < len; i++) {
-            ret[i] = (long) array[i];
+            ret[i] = ((Number) Array.get(array, i)).longValue();
         }
         return ret;
     }
 
     /**
-     * Returns the value associated with a long array mapping, or null if the mapping does
-     * not exist.
+     * Returns the value associated with an int/double array mapping as a long array, or
+     * null if the mapping does not exist.
      *
      * @param key Key to look for.
-     * @return long array value
+     * @return Long array value
      */
     public long[] getLongArray(final String key) {
         final Object value = mMap.get(key);
-        return value == null ? null : Array.getLength(value) == 0 ? EMPTY_LONG_ARRAY :
-                value instanceof double[] ? getLongArray((double[]) value) : (long[]) value;
+        return value == null ? null :
+               Array.getLength(value) == 0 ? EMPTY_LONG_ARRAY : getLongArray(value);
     }
 
     /**
      * Returns the value associated with a String mapping, or defaultValue if the mapping
      * does not exist.
      *
      * @param key Key to look for.
      * @param defaultValue Value to return if mapping value is null or mapping does not exist.
@@ -502,25 +502,17 @@ public final class GeckoBundle implement
 
     /**
      * Map a key to a double array value.
      *
      * @param key Key to map.
      * @param value Value to map to.
      */
     public void putDoubleArray(final String key, final Double[] value) {
-        if (value == null) {
-            mMap.put(key, null);
-            return;
-        }
-        final double[] array = new double[value.length];
-        for (int i = 0; i < value.length; i++) {
-            array[i] = value[i];
-        }
-        mMap.put(key, array);
+        putDoubleArray(key, Arrays.asList(value));
     }
 
     /**
      * Map a key to a double array value.
      *
      * @param key Key to map.
      * @param value Value to map to.
      */
@@ -559,25 +551,17 @@ public final class GeckoBundle implement
 
     /**
      * Map a key to a int array value.
      *
      * @param key Key to map.
      * @param value Value to map to.
      */
     public void putIntArray(final String key, final Integer[] value) {
-        if (value == null) {
-            mMap.put(key, null);
-            return;
-        }
-        final int[] array = new int[value.length];
-        for (int i = 0; i < value.length; i++) {
-            array[i] = value[i];
-        }
-        mMap.put(key, array);
+        putIntArray(key, Arrays.asList(value));
     }
 
     /**
      * Map a key to a int array value.
      *
      * @param key Key to map.
      * @param value Value to map to.
      */
@@ -590,16 +574,73 @@ public final class GeckoBundle implement
         int i = 0;
         for (final Integer element : value) {
             array[i++] = element;
         }
         mMap.put(key, array);
     }
 
     /**
+     * Map a key to a long value stored as a double value.
+     *
+     * @param key Key to map.
+     * @param value Value to map to.
+     */
+    public void putLong(final String key, final long value) {
+        mMap.put(key, (double) value);
+    }
+
+    /**
+     * Map a key to a long array value stored as a double array value.
+     *
+     * @param key Key to map.
+     * @param value Value to map to.
+     */
+    public void putLongArray(final String key, final long[] value) {
+        if (value == null) {
+            mMap.put(key, null);
+            return;
+        }
+        final double[] array = new double[value.length];
+        for (int i = 0; i < value.length; i++) {
+            array[i] = (double) value[i];
+        }
+        mMap.put(key, array);
+    }
+
+    /**
+     * Map a key to a long array value stored as a double array value.
+     *
+     * @param key Key to map.
+     * @param value Value to map to.
+     */
+    public void putLongArray(final String key, final Long[] value) {
+        putLongArray(key, Arrays.asList(value));
+    }
+
+    /**
+     * Map a key to a long array value stored as a double array value.
+     *
+     * @param key Key to map.
+     * @param value Value to map to.
+     */
+    public void putLongArray(final String key, final Collection<Long> value) {
+        if (value == null) {
+            mMap.put(key, null);
+            return;
+        }
+        final double[] array = new double[value.size()];
+        int i = 0;
+        for (final Long element : value) {
+            array[i++] = (double) element;
+        }
+        mMap.put(key, array);
+    }
+
+    /**
      * Map a key to a String value.
      *
      * @param key Key to map.
      * @param value Value to map to.
      */
     public void putString(final String key, final String value) {
         mMap.put(key, value);
     }
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/BasicSelectionActionDelegate.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/BasicSelectionActionDelegate.java
@@ -3,49 +3,74 @@
  * 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/. */
 
 package org.mozilla.geckoview;
 
 import android.annotation.TargetApi;
 import android.app.Activity;
+import android.content.ActivityNotFoundException;
+import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.os.Build;
+import android.support.annotation.NonNull;
+import android.util.Log;
 import android.view.ActionMode;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
 
 import java.util.Arrays;
 import java.util.List;
 
+/**
+ * Class that implements a basic SelectionActionDelegate. This class is used by GeckoView by
+ * default if the consumer does not explicitly set a SelectionActionDelegate.
+ *
+ * To provide custom actions, extend this class and override the following methods,
+ *
+ * 1) Override {@link #getAllActions} to include custom action IDs in the returned array. This
+ * array must include all actions, available or not, and must not change over the class lifetime.
+ *
+ * 2) Override {@link #isActionAvailable} to return whether a custom action is currently available.
+ *
+ * 3) Override {@link #prepareAction} to set custom title and/or icon for a custom action.
+ *
+ * 4) Override {@link #performAction} to perform a custom action when used.
+ */
 public class BasicSelectionActionDelegate implements ActionMode.Callback,
-                                             GeckoSession.SelectionActionDelegate {
+                                                     GeckoSession.SelectionActionDelegate {
     private static final String LOGTAG = "GeckoBasicSelectionAction";
 
+    protected static final String ACTION_PROCESS_TEXT = Intent.ACTION_PROCESS_TEXT;
+
     private static final String[] FLOATING_TOOLBAR_ACTIONS = new String[] {
-            ACTION_CUT, ACTION_COPY, ACTION_PASTE, ACTION_SELECT_ALL
+        ACTION_CUT, ACTION_COPY, ACTION_PASTE, ACTION_SELECT_ALL, ACTION_PROCESS_TEXT
     };
     private static final String[] FIXED_TOOLBAR_ACTIONS = new String[] {
-            ACTION_SELECT_ALL, ACTION_CUT, ACTION_COPY, ACTION_PASTE
+        ACTION_SELECT_ALL, ACTION_CUT, ACTION_COPY, ACTION_PASTE
     };
 
     protected final Activity mActivity;
     protected final boolean mUseFloatingToolbar;
     protected final Matrix mTempMatrix = new Matrix();
     protected final RectF mTempRect = new RectF();
 
+    private boolean mExternalActionsEnabled;
+
     protected ActionMode mActionMode;
     protected GeckoSession mSession;
     protected Selection mSelection;
     protected List<String> mActions;
     protected GeckoSession.Response<String> mResponse;
+    protected boolean mRepopulatedMenu;
 
     @TargetApi(Build.VERSION_CODES.M)
     private class Callback2Wrapper extends ActionMode.Callback2 {
         @Override
         public boolean onCreateActionMode(final ActionMode actionMode, final Menu menu) {
             return BasicSelectionActionDelegate.this.onCreateActionMode(actionMode, menu);
         }
 
@@ -66,104 +91,160 @@ public class BasicSelectionActionDelegat
 
         @Override
         public void onGetContentRect(final ActionMode mode, final View view, final Rect outRect) {
             super.onGetContentRect(mode, view, outRect);
             BasicSelectionActionDelegate.this.onGetContentRect(mode, view, outRect);
         }
     }
 
-    public BasicSelectionActionDelegate(final Activity activity) {
+    public BasicSelectionActionDelegate(final @NonNull Activity activity) {
         this(activity, Build.VERSION.SDK_INT >= 23);
     }
 
-    public BasicSelectionActionDelegate(final Activity activity, final boolean useFloatingToolbar) {
+    public BasicSelectionActionDelegate(final @NonNull Activity activity,
+                                        final boolean useFloatingToolbar) {
         mActivity = activity;
         mUseFloatingToolbar = useFloatingToolbar;
+        mExternalActionsEnabled = true;
+    }
+
+    /**
+     * Set whether to include text actions from other apps in the floating toolbar.
+     *
+     * @param enable True if external actions should be enabled.
+     */
+    public void enableExternalActions(final boolean enable) {
+        mExternalActionsEnabled = enable;
+
+        if (mActionMode != null) {
+            mActionMode.invalidate();
+        }
+    }
+
+    /**
+     * Get whether text actions from other apps are enabled.
+     *
+     * @return True if external actions are enabled.
+     */
+    public boolean areExternalActionsEnabled() {
+        return mExternalActionsEnabled;
     }
 
     /**
      * Return list of all actions in proper order, regardless of their availability at present.
      * Override to add to or remove from the default set.
      *
      * @return Array of action IDs in proper order.
      */
-    protected String[] getAllActions() {
+    protected @NonNull String[] getAllActions() {
         return mUseFloatingToolbar ? FLOATING_TOOLBAR_ACTIONS
                                    : FIXED_TOOLBAR_ACTIONS;
     }
 
     /**
      * Return whether an action is presently available. Override to indicate
      * availability for custom actions.
      *
      * @param id Action ID.
      * @return True if the action is presently available.
      */
-    protected boolean isActionAvailable(final String id) {
+    protected boolean isActionAvailable(final @NonNull String id) {
+        if (mExternalActionsEnabled && !mSelection.text.isEmpty() &&
+                ACTION_PROCESS_TEXT.equals(id)) {
+            final PackageManager pm = mActivity.getPackageManager();
+            return pm.resolveActivity(getProcessTextIntent(),
+                                      PackageManager.MATCH_DEFAULT_ONLY) != null;
+        }
         return mActions.contains(id);
     }
 
     /**
      * Prepare a menu item corresponding to a certain action. Override to prepare
      * menu item for custom action.
      *
      * @param id Action ID.
      * @param item New menu item to prepare.
      */
-    protected void prepareAction(final String id, final MenuItem item) {
+    protected void prepareAction(final @NonNull String id, final @NonNull MenuItem item) {
         switch (id) {
             case ACTION_CUT:
                 item.setTitle(android.R.string.cut);
                 break;
             case ACTION_COPY:
                 item.setTitle(android.R.string.copy);
                 break;
             case ACTION_PASTE:
                 item.setTitle(android.R.string.paste);
                 break;
             case ACTION_SELECT_ALL:
                 item.setTitle(android.R.string.selectAll);
                 break;
+            case ACTION_PROCESS_TEXT:
+                throw new IllegalStateException("Unexpected action");
         }
     }
 
     /**
      * Perform the specified action. Override to perform custom actions.
      *
      * @param id Action ID.
+     * @param item Nenu item for the action.
      * @return True if the action was performed.
      */
-    protected boolean performAction(final String id) {
+    protected boolean performAction(final @NonNull String id, final @NonNull MenuItem item) {
+        if (ACTION_PROCESS_TEXT.equals(id)) {
+            try {
+                mActivity.startActivity(item.getIntent());
+            } catch (final ActivityNotFoundException e) {
+                Log.e(LOGTAG, "Cannot perform action", e);
+                return false;
+            }
+            return true;
+        }
+
         if (mResponse == null) {
             return false;
         }
         mResponse.respond(id);
 
         // Android behavior is to clear selection on copy.
         if (ACTION_COPY.equals(id)) {
             if (mUseFloatingToolbar) {
                 clearSelection();
             } else {
                 mActionMode.finish();
             }
         }
         return true;
     }
 
+    /**
+     * Clear the current selection, if possible.
+     */
     protected void clearSelection() {
         if (mResponse != null) {
             if (isActionAvailable(ACTION_COLLAPSE_TO_END)) {
                 mResponse.respond(ACTION_COLLAPSE_TO_END);
             } else {
                 mResponse.respond(ACTION_UNSELECT);
             }
         }
     }
 
+    private Intent getProcessTextIntent() {
+        final Intent intent = new Intent(Intent.ACTION_PROCESS_TEXT);
+        intent.addCategory(Intent.CATEGORY_DEFAULT);
+        intent.setType("text/plain");
+        intent.putExtra(Intent.EXTRA_PROCESS_TEXT, mSelection.text);
+        // TODO: implement ability to replace text in Gecko for editable selection (bug 1453137).
+        intent.putExtra(Intent.EXTRA_PROCESS_TEXT_READONLY, true);
+        return intent;
+    }
+
     @Override
     public boolean onCreateActionMode(final ActionMode actionMode, final Menu menu) {
         final String[] allActions = getAllActions();
         for (final String actionId : allActions) {
             if (isActionAvailable(actionId)) {
                 if (!mUseFloatingToolbar && (
                         Build.VERSION.SDK_INT == 22 || Build.VERSION.SDK_INT == 23)) {
                     // Android bug where onPrepareActionMode is not called initially.
@@ -175,38 +256,78 @@ public class BasicSelectionActionDelegat
         return false;
     }
 
     @Override
     public boolean onPrepareActionMode(final ActionMode actionMode, final Menu menu) {
         final String[] allActions = getAllActions();
         boolean changed = false;
 
+        // Whether we are repopulating an existing menu.
+        mRepopulatedMenu = menu.size() != 0;
+
         // For each action, see if it's available at present, and if necessary,
         // add to or remove from menu.
-        for (int menuId = 0; menuId < allActions.length; menuId++) {
-            final String actionId = allActions[menuId];
+        for (int i = 0; i < allActions.length; i++) {
+            final String actionId = allActions[i];
+            final int menuId = i + Menu.FIRST;
+
+            if (ACTION_PROCESS_TEXT.equals(actionId)) {
+                if (mExternalActionsEnabled && !mSelection.text.isEmpty()) {
+                    menu.addIntentOptions(menuId, menuId, menuId,
+                                          mActivity.getComponentName(),
+                                          /* specifiec */ null, getProcessTextIntent(),
+                                          /* flags */ 0, /* items */ null);
+                    changed = true;
+                } else if (menu.findItem(menuId) != null) {
+                    menu.removeGroup(menuId);
+                    changed = true;
+                }
+                continue;
+            }
+
             if (isActionAvailable(actionId)) {
                 if (menu.findItem(menuId) == null) {
                     prepareAction(actionId, menu.add(/* group */ Menu.NONE, menuId,
                                                      menuId, /* title */ ""));
                     changed = true;
                 }
             } else if (menu.findItem(menuId) != null) {
                 menu.removeItem(menuId);
                 changed = true;
             }
         }
         return changed;
     }
 
     @Override
     public boolean onActionItemClicked(final ActionMode actionMode, final MenuItem menuItem) {
+        MenuItem realMenuItem = null;
+        if (mRepopulatedMenu) {
+            // When we repopulate an existing menu, Android can sometimes give us an old,
+            // deleted MenuItem. Find the current MenuItem that corresponds to the old one.
+            final Menu menu = actionMode.getMenu();
+            final int size = menu.size();
+            for (int i = 0; i < size; i++) {
+                final MenuItem item = menu.getItem(i);
+                if (item == menuItem || (item.getItemId() == menuItem.getItemId() &&
+                        item.getTitle().equals(menuItem.getTitle()))) {
+                    realMenuItem = item;
+                    break;
+                }
+            }
+        } else {
+            realMenuItem = menuItem;
+        }
+
+        if (realMenuItem == null) {
+            return false;
+        }
         final String[] allActions = getAllActions();
-        return performAction(allActions[menuItem.getItemId()]);
+        return performAction(allActions[realMenuItem.getItemId() - Menu.FIRST], realMenuItem);
     }
 
     @Override
     public void onDestroyActionMode(final ActionMode actionMode) {
         if (!mUseFloatingToolbar) {
             clearSelection();
         }
         mSession = null;
--- a/mobile/android/geckoview/src/test/java/org/mozilla/gecko/util/GeckoBundleTest.java
+++ b/mobile/android/geckoview/src/test/java/org/mozilla/gecko/util/GeckoBundleTest.java
@@ -15,53 +15,57 @@ import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
 
 import java.util.Arrays;
 import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
 @SmallTest
 public class GeckoBundleTest {
-    private static final int INNER_BUNDLE_SIZE = 25;
+    private static final int INNER_BUNDLE_SIZE = 28;
     private static final int OUTER_BUNDLE_SIZE = INNER_BUNDLE_SIZE + 6;
 
     private static GeckoBundle createInnerBundle() {
         final GeckoBundle bundle = new GeckoBundle();
 
         bundle.putBoolean("boolean", true);
         bundle.putBooleanArray("booleanArray", new boolean[] {false, true});
 
         bundle.putInt("int", 1);
         bundle.putIntArray("intArray", new int[] {2, 3});
 
         bundle.putDouble("double", 0.5);
         bundle.putDoubleArray("doubleArray", new double[] {1.5, 2.5});
 
+        bundle.putLong("long", 1L);
+        bundle.putLongArray("longArray", new long[] {2L, 3L});
+
         bundle.putString("string", "foo");
         bundle.putString("nullString", null);
         bundle.putString("emptyString", "");
         bundle.putStringArray("stringArray", new String[] {"bar", "baz"});
         bundle.putStringArray("stringArrayOfNull", new String[2]);
 
         bundle.putBooleanArray("emptyBooleanArray", new boolean[0]);
         bundle.putIntArray("emptyIntArray", new int[0]);
         bundle.putDoubleArray("emptyDoubleArray", new double[0]);
+        bundle.putLongArray("emptyLongArray", new long[0]);
         bundle.putStringArray("emptyStringArray", new String[0]);
 
         bundle.putBooleanArray("nullBooleanArray", (boolean[]) null);
         bundle.putIntArray("nullIntArray", (int[]) null);
         bundle.putDoubleArray("nullDoubleArray", (double[]) null);
+        bundle.putLongArray("nullLongArray", (long[]) null);
         bundle.putStringArray("nullStringArray", (String[]) null);
 
         bundle.putDoubleArray("mixedArray", new double[] {1.0, 1.5});
 
         bundle.putInt("byte", 1);
         bundle.putInt("short", 1);
         bundle.putDouble("float", 0.5);
-        bundle.putDouble("long", 1.0);
         bundle.putString("char", "f");
 
         return bundle;
     }
 
     private static GeckoBundle createBundle() {
         final GeckoBundle outer = createInnerBundle();
         final GeckoBundle inner = createInnerBundle();
@@ -83,38 +87,42 @@ public class GeckoBundleTest {
         assertArrayEquals(new boolean[] {false, true}, bundle.getBooleanArray("booleanArray"));
 
         assertEquals(1, bundle.getInt("int"));
         assertArrayEquals(new int[] {2, 3}, bundle.getIntArray("intArray"));
 
         assertEquals(0.5, bundle.getDouble("double"), 0.0);
         assertArrayEquals(new double[] {1.5, 2.5}, bundle.getDoubleArray("doubleArray"), 0.0);
 
+        assertEquals(1L, bundle.getLong("long"));
+        assertArrayEquals(new long[] {2L, 3L}, bundle.getLongArray("longArray"));
+
         assertEquals("foo", bundle.getString("string"));
         assertEquals(null, bundle.getString("nullString"));
         assertEquals("", bundle.getString("emptyString"));
         assertArrayEquals(new String[] {"bar", "baz"}, bundle.getStringArray("stringArray"));
         assertArrayEquals(new String[2], bundle.getStringArray("stringArrayOfNull"));
 
         assertArrayEquals(new boolean[0], bundle.getBooleanArray("emptyBooleanArray"));
         assertArrayEquals(new int[0], bundle.getIntArray("emptyIntArray"));
         assertArrayEquals(new double[0], bundle.getDoubleArray("emptyDoubleArray"), 0.0);
+        assertArrayEquals(new long[0], bundle.getLongArray("emptyLongArray"));
         assertArrayEquals(new String[0], bundle.getStringArray("emptyStringArray"));
 
         assertArrayEquals(null, bundle.getBooleanArray("nullBooleanArray"));
         assertArrayEquals(null, bundle.getIntArray("nullIntArray"));
         assertArrayEquals(null, bundle.getDoubleArray("nullDoubleArray"), 0.0);
+        assertArrayEquals(null, bundle.getLongArray("nullLongArray"));
         assertArrayEquals(null, bundle.getStringArray("nullStringArray"));
 
         assertArrayEquals(new double[] {1.0, 1.5}, bundle.getDoubleArray("mixedArray"), 0.0);
 
         assertEquals(1, bundle.getInt("byte"));
         assertEquals(1, bundle.getInt("short"));
         assertEquals(0.5, bundle.getDouble("float"), 0.0);
-        assertEquals(1.0, bundle.getDouble("long"), 0.0);
         assertEquals("f", bundle.getString("char"));
     }
 
     private static void checkBundle(final GeckoBundle bundle) {
         checkInnerBundle(bundle, OUTER_BUNDLE_SIZE);
 
         checkInnerBundle(bundle.getBundle("object"), INNER_BUNDLE_SIZE);
         assertEquals(null, bundle.getBundle("nullObject"));
@@ -204,34 +212,37 @@ public class GeckoBundleTest {
 
         testRemove(test, "nonexistent");
         testRemove(test, "boolean");
         testRemove(test, "booleanArray");
         testRemove(test, "int");
         testRemove(test, "intArray");
         testRemove(test, "double");
         testRemove(test, "doubleArray");
+        testRemove(test, "long");
+        testRemove(test, "longArray");
         testRemove(test, "string");
         testRemove(test, "nullString");
         testRemove(test, "emptyString");
         testRemove(test, "stringArray");
         testRemove(test, "stringArrayOfNull");
         testRemove(test, "emptyBooleanArray");
         testRemove(test, "emptyIntArray");
         testRemove(test, "emptyDoubleArray");
+        testRemove(test, "emptyLongArray");
         testRemove(test, "emptyStringArray");
         testRemove(test, "nullBooleanArray");
         testRemove(test, "nullIntArray");
         testRemove(test, "nullDoubleArray");
+        testRemove(test, "nullLongArray");
         testRemove(test, "nullStringArray");
         testRemove(test, "mixedArray");
         testRemove(test, "byte");
         testRemove(test, "short");
         testRemove(test, "float");
-        testRemove(test, "long");
         testRemove(test, "char");
         testRemove(test, "object");
         testRemove(test, "nullObject");
         testRemove(test, "objectArray");
         testRemove(test, "objectArrayOfNull");
         testRemove(test, "emptyObjectArray");
         testRemove(test, "nullObjectArray");
 
@@ -245,22 +256,23 @@ public class GeckoBundleTest {
         test.clear();
         assertEquals(0, test.size());
     }
 
     @Test
     public void keysShouldReturnCorrectResult() {
         final String[] actual = reference.keys();
         final String[] expected = new String[] {
-            "boolean", "booleanArray", "int", "intArray", "double", "doubleArray", "string",
-            "nullString", "emptyString", "stringArray", "stringArrayOfNull",
-            "emptyBooleanArray", "emptyIntArray", "emptyDoubleArray", "emptyStringArray",
-            "nullBooleanArray", "nullIntArray", "nullDoubleArray", "nullStringArray",
-            "mixedArray", "byte", "short", "float", "long", "char", "object", "nullObject",
-            "objectArray", "objectArrayOfNull", "emptyObjectArray", "nullObjectArray"
+            "boolean", "booleanArray", "int", "intArray", "double", "doubleArray", "long",
+            "longArray", "string", "nullString", "emptyString", "stringArray", "stringArrayOfNull",
+            "emptyBooleanArray", "emptyIntArray", "emptyDoubleArray", "emptyLongArray",
+            "emptyStringArray", "nullBooleanArray", "nullIntArray", "nullDoubleArray",
+            "nullLongArray", "nullStringArray", "mixedArray", "byte", "short", "float", "char",
+            "object", "nullObject", "objectArray", "objectArrayOfNull", "emptyObjectArray",
+            "nullObjectArray"
         };
 
         Arrays.sort(expected);
         Arrays.sort(actual);
 
         assertArrayEquals(expected, actual);
     }
 
@@ -270,16 +282,17 @@ public class GeckoBundleTest {
         assertTrue(new GeckoBundle().isEmpty());
     }
 
     @Test
     public void getExistentKeysShouldNotReturnDefaultValues() {
         assertNotEquals(false, reference.getBoolean("boolean", false));
         assertNotEquals(0, reference.getInt("int", 0));
         assertNotEquals(0.0, reference.getDouble("double", 0.0), 0.0);
+        assertNotEquals(0L, reference.getLong("long", 0L));
         assertNotEquals("", reference.getString("string", ""));
     }
 
     private static void testDefaultValueForNull(final GeckoBundle bundle, final String key) {
         // We return default values for null values.
         assertEquals(true, bundle.getBoolean(key, true));
         assertEquals(1, bundle.getInt(key, 1));
         assertEquals(0.5, bundle.getDouble(key, 0.5), 0.0);
@@ -298,25 +311,27 @@ public class GeckoBundleTest {
         assertEquals(0.5, reference.getDouble("nonexistent", 0.5), 0.0);
         assertEquals(null, reference.getString("nonexistent"));
         assertEquals("foo", reference.getString("nonexistent", "foo"));
         assertEquals(null, reference.getBundle("nonexistent"));
 
         assertArrayEquals(null, reference.getBooleanArray("nonexistent"));
         assertArrayEquals(null, reference.getIntArray("nonexistent"));
         assertArrayEquals(null, reference.getDoubleArray("nonexistent"), 0.0);
+        assertArrayEquals(null, reference.getLongArray("nonexistent"));
         assertArrayEquals(null, reference.getStringArray("nonexistent"));
         assertArrayEquals(null, reference.getBundleArray("nonexistent"));
 
         // We return default values for null values.
         testDefaultValueForNull(reference, "nullObject");
         testDefaultValueForNull(reference, "nullString");
         testDefaultValueForNull(reference, "nullBooleanArray");
         testDefaultValueForNull(reference, "nullIntArray");
         testDefaultValueForNull(reference, "nullDoubleArray");
+        testDefaultValueForNull(reference, "nullLongArray");
         testDefaultValueForNull(reference, "nullStringArray");
         testDefaultValueForNull(reference, "nullObjectArray");
     }
 
     @Test
     public void bundleConversionShouldWork() {
         assertEquals(reference, GeckoBundle.fromBundle(reference.toBundle()));
     }
@@ -405,16 +420,35 @@ public class GeckoBundleTest {
             try {
                 bundle.getDoubleArray(key);
                 fail(String.format("%s should not coerce to double array", key));
             } catch (final Exception e) {
                 assertTrue(true);
             }
         }
 
+        if (!allowed.contains("long")) {
+            try {
+                bundle.getLong(key);
+                fail(String.format("%s should not coerce to long", key));
+            } catch (final Exception e) {
+                assertTrue(true);
+            }
+        }
+
+        if (!allowed.contains("longArray") && !allowed.contains("emptyLongArray") &&
+            !allowed.contains("nullLongArray")) {
+            try {
+                bundle.getLongArray(key);
+                fail(String.format("%s should not coerce to long array", key));
+            } catch (final Exception e) {
+                assertTrue(true);
+            }
+        }
+
         if (!allowed.contains("string") && !allowed.contains("nullString")) {
             try {
                 bundle.getString(key);
                 fail(String.format("%s should not coerce to string", key));
             } catch (final Exception e) {
                 assertTrue(true);
             }
         }
@@ -461,31 +495,64 @@ public class GeckoBundleTest {
 
     @Test
     public void intShouldCoerceToDouble() {
         assertEquals(1.0, reference.getDouble("int"), 0.0);
         assertArrayEquals(new double[] {2.0, 3.0}, reference.getDoubleArray("intArray"), 0.0);
     }
 
     @Test
+    public void intShouldCoerceToLong() {
+        assertEquals(1L, reference.getLong("int"));
+        assertArrayEquals(new long[] {2L, 3L}, reference.getLongArray("intArray"));
+    }
+
+    @Test
     public void intShouldNotCoerceToOtherTypes() {
-        testInvalidCoercions(reference, "int", /* except */ "double");
-        testInvalidCoercions(reference, "intArray", /* except */ "doubleArray");
+        testInvalidCoercions(reference, "int", /* except */ "double", "long");
+        testInvalidCoercions(reference, "intArray",
+                             /* except */ "doubleArray", "longArray");
     }
 
     @Test
     public void doubleShouldCoerceToInt() {
         assertEquals(0, reference.getInt("double"));
         assertArrayEquals(new int[] {1, 2}, reference.getIntArray("doubleArray"));
     }
 
     @Test
+    public void doubleShouldCoerceToLong() {
+        assertEquals(0L, reference.getLong("double"));
+        assertArrayEquals(new long[] {1L, 2L}, reference.getLongArray("doubleArray"));
+    }
+
+    @Test
     public void doubleShouldNotCoerceToOtherTypes() {
-        testInvalidCoercions(reference, "double", /* except */ "int");
-        testInvalidCoercions(reference, "doubleArray", /* except */ "intArray");
+        testInvalidCoercions(reference, "double", /* except */ "int", "long");
+        testInvalidCoercions(reference, "doubleArray",
+                             /* except */ "intArray", "longArray");
+    }
+
+    @Test
+    public void longShouldCoerceToInt() {
+        assertEquals(1, reference.getInt("long"));
+        assertArrayEquals(new int[] {2, 3}, reference.getIntArray("longArray"));
+    }
+
+    @Test
+    public void longShouldCoerceToDouble() {
+        assertEquals(1.0, reference.getDouble("long"), 0.0);
+        assertArrayEquals(new double[] {2.0, 3.0}, reference.getDoubleArray("longArray"), 0.0);
+    }
+
+    @Test
+    public void longShouldNotCoerceToOtherTypes() {
+        testInvalidCoercions(reference, "long", /* except */ "int", "double");
+        testInvalidCoercions(reference, "longArray",
+                             /* except */ "intArray", "doubleArray");
     }
 
     @Test
     public void nullStringShouldCoerceToBundle() {
         assertEquals(null, reference.getBundle("nullString"));
         assertArrayEquals(new GeckoBundle[2], reference.getBundleArray("stringArrayOfNull"));
     }
 
@@ -514,74 +581,98 @@ public class GeckoBundleTest {
     public void nonNullBundleShouldNotCoerceToOtherTypes() {
         testInvalidCoercions(reference, "object");
     }
 
     @Test
     public void emptyArrayShouldCoerceToAnyArray() {
         assertArrayEquals(new int[0], reference.getIntArray("emptyBooleanArray"));
         assertArrayEquals(new double[0], reference.getDoubleArray("emptyBooleanArray"), 0.0);
+        assertArrayEquals(new long[0], reference.getLongArray("emptyBooleanArray"));
         assertArrayEquals(new String[0], reference.getStringArray("emptyBooleanArray"));
         assertArrayEquals(new GeckoBundle[0], reference.getBundleArray("emptyBooleanArray"));
 
         assertArrayEquals(new boolean[0], reference.getBooleanArray("emptyIntArray"));
         assertArrayEquals(new double[0], reference.getDoubleArray("emptyIntArray"), 0.0);
+        assertArrayEquals(new long[0], reference.getLongArray("emptyIntArray"));
         assertArrayEquals(new String[0], reference.getStringArray("emptyIntArray"));
         assertArrayEquals(new GeckoBundle[0], reference.getBundleArray("emptyIntArray"));
 
         assertArrayEquals(new boolean[0], reference.getBooleanArray("emptyDoubleArray"));
         assertArrayEquals(new int[0], reference.getIntArray("emptyDoubleArray"));
+        assertArrayEquals(new long[0], reference.getLongArray("emptyDoubleArray"));
         assertArrayEquals(new String[0], reference.getStringArray("emptyDoubleArray"));
         assertArrayEquals(new GeckoBundle[0], reference.getBundleArray("emptyDoubleArray"));
 
+        assertArrayEquals(new boolean[0], reference.getBooleanArray("emptyLongArray"));
+        assertArrayEquals(new int[0], reference.getIntArray("emptyLongArray"));
+        assertArrayEquals(new double[0], reference.getDoubleArray("emptyLongArray"), 0.0);
+        assertArrayEquals(new String[0], reference.getStringArray("emptyLongArray"));
+        assertArrayEquals(new GeckoBundle[0], reference.getBundleArray("emptyLongArray"));
+
         assertArrayEquals(new boolean[0], reference.getBooleanArray("emptyStringArray"));
         assertArrayEquals(new int[0], reference.getIntArray("emptyStringArray"));
         assertArrayEquals(new double[0], reference.getDoubleArray("emptyStringArray"), 0.0);
+        assertArrayEquals(new long[0], reference.getLongArray("emptyStringArray"));
         assertArrayEquals(new GeckoBundle[0], reference.getBundleArray("emptyStringArray"));
 
         assertArrayEquals(new boolean[0], reference.getBooleanArray("emptyObjectArray"));
         assertArrayEquals(new int[0], reference.getIntArray("emptyObjectArray"));
         assertArrayEquals(new double[0], reference.getDoubleArray("emptyObjectArray"), 0.0);
+        assertArrayEquals(new long[0], reference.getLongArray("emptyObjectArray"));
         assertArrayEquals(new String[0], reference.getStringArray("emptyObjectArray"));
     }
 
     @Test
     public void emptyArrayShouldNotCoerceToOtherTypes() {
         testInvalidCoercions(reference, "emptyBooleanArray", /* except */ "intArray",
-                             "doubleArray", "stringArray", "objectArray");
+                             "doubleArray", "longArray", "stringArray", "objectArray");
         testInvalidCoercions(reference, "emptyIntArray", /* except */ "booleanArray",
-                             "doubleArray", "stringArray", "objectArray");
+                             "doubleArray", "longArray", "stringArray", "objectArray");
         testInvalidCoercions(reference, "emptyDoubleArray", /* except */ "booleanArray",
-                             "intArray", "stringArray", "objectArray");
+                             "intArray", "longArray", "stringArray", "objectArray");
+        testInvalidCoercions(reference, "emptyLongArray", /* except */ "booleanArray",
+                             "intArray", "doubleArray", "stringArray", "objectArray");
         testInvalidCoercions(reference, "emptyStringArray", /* except */ "booleanArray",
-                             "intArray", "doubleArray", "objectArray");
+                             "intArray", "doubleArray", "longArray", "objectArray");
         testInvalidCoercions(reference, "emptyObjectArray", /* except */ "booleanArray",
-                             "intArray", "doubleArray", "stringArray");
+                             "intArray", "doubleArray", "longArray", "stringArray");
     }
 
     @Test
     public void nullArrayShouldCoerceToAnyArray() {
         assertArrayEquals(null, reference.getIntArray("nullBooleanArray"));
         assertArrayEquals(null, reference.getDoubleArray("nullBooleanArray"), 0.0);
+        assertArrayEquals(null, reference.getLongArray("nullBooleanArray"));
         assertArrayEquals(null, reference.getStringArray("nullBooleanArray"));
         assertArrayEquals(null, reference.getBundleArray("nullBooleanArray"));
 
         assertArrayEquals(null, reference.getBooleanArray("nullIntArray"));
         assertArrayEquals(null, reference.getDoubleArray("nullIntArray"), 0.0);
+        assertArrayEquals(null, reference.getLongArray("nullIntArray"));
         assertArrayEquals(null, reference.getStringArray("nullIntArray"));
         assertArrayEquals(null, reference.getBundleArray("nullIntArray"));
 
         assertArrayEquals(null, reference.getBooleanArray("nullDoubleArray"));
         assertArrayEquals(null, reference.getIntArray("nullDoubleArray"));
+        assertArrayEquals(null, reference.getLongArray("nullDoubleArray"));
         assertArrayEquals(null, reference.getStringArray("nullDoubleArray"));
         assertArrayEquals(null, reference.getBundleArray("nullDoubleArray"));
 
+        assertArrayEquals(null, reference.getBooleanArray("nullLongArray"));
+        assertArrayEquals(null, reference.getIntArray("nullLongArray"));
+        assertArrayEquals(null, reference.getDoubleArray("nullLongArray"), 0.0);
+        assertArrayEquals(null, reference.getStringArray("nullLongArray"));
+        assertArrayEquals(null, reference.getBundleArray("nullLongArray"));
+
         assertArrayEquals(null, reference.getBooleanArray("nullStringArray"));
         assertArrayEquals(null, reference.getIntArray("nullStringArray"));
         assertArrayEquals(null, reference.getDoubleArray("nullStringArray"), 0.0);
+        assertArrayEquals(null, reference.getLongArray("nullStringArray"));
         assertArrayEquals(null, reference.getBundleArray("nullStringArray"));
 
         assertArrayEquals(null, reference.getBooleanArray("nullObjectArray"));
         assertArrayEquals(null, reference.getIntArray("nullObjectArray"));
         assertArrayEquals(null, reference.getDoubleArray("nullObjectArray"), 0.0);
+        assertArrayEquals(null, reference.getLongArray("nullObjectArray"));
         assertArrayEquals(null, reference.getStringArray("nullObjectArray"));
     }
 }
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1266,19 +1266,16 @@ pref("dom.timeout.foreground_throttling_
 // The maximum amount a timeout can be delayed by budget throttling
 pref("dom.timeout.budget_throttling_max_delay", 15000);
 // Turn on budget throttling by default
 pref("dom.timeout.enable_budget_timer_throttling", true);
 
 // Don't use new input types
 pref("dom.experimental_forms", false);
 
-// Enable <input type=number>:
-pref("dom.forms.number", true);
-
 // Enable <input type=color> by default. It will be turned off for remaining
 // platforms which don't have a color picker implemented yet.
 pref("dom.forms.color", true);
 
 // Support for input type=date and type=time.
 pref("dom.forms.datetime", true);
 
 // Support for input type=month, type=week and type=datetime-local. By default,
--- a/servo/components/script/dom/dissimilaroriginwindow.rs
+++ b/servo/components/script/dom/dissimilaroriginwindow.rs
@@ -187,14 +187,18 @@ impl DissimilarOriginWindowMethods for D
     // https://html.spec.whatwg.org/multipage/#dom-location
     fn Location(&self) -> DomRoot<DissimilarOriginLocation> {
         self.location.or_init(|| DissimilarOriginLocation::new(self))
     }
 }
 
 impl DissimilarOriginWindow {
     pub fn post_message(&self, origin: Option<ImmutableOrigin>, data: StructuredCloneData) {
+        let incumbent = match GlobalScope::incumbent() {
+            None => return warn!("postMessage called with no incumbent global"),
+            Some(incumbent) => incumbent,
+        };
         let msg = ScriptMsg::PostMessage(self.window_proxy.browsing_context_id(),
                                                 origin,
                                                 data.move_to_arraybuffer());
-        let _ = self.upcast::<GlobalScope>().script_to_constellation_chan().send(msg);
+        let _ = incumbent.script_to_constellation_chan().send(msg);
     }
 }
--- a/servo/components/selectors/attr.rs
+++ b/servo/components/selectors/attr.rs
@@ -14,19 +14,17 @@ pub struct AttrSelectorWithNamespace<Imp
     pub operation: ParsedAttrSelectorOperation<Impl::AttrValue>,
     pub never_matches: bool,
 }
 
 impl<Impl: SelectorImpl> AttrSelectorWithNamespace<Impl> {
     pub fn namespace(&self) -> NamespaceConstraint<&Impl::NamespaceUrl> {
         match self.namespace {
             NamespaceConstraint::Any => NamespaceConstraint::Any,
-            NamespaceConstraint::Specific((_, ref url)) => {
-                NamespaceConstraint::Specific(url)
-            }
+            NamespaceConstraint::Specific((_, ref url)) => NamespaceConstraint::Specific(url),
         }
     }
 }
 
 #[derive(Clone, Eq, PartialEq)]
 pub enum NamespaceConstraint<NamespaceUrl> {
     Any,
 
@@ -36,94 +34,102 @@ pub enum NamespaceConstraint<NamespaceUr
 
 #[derive(Clone, Eq, PartialEq)]
 pub enum ParsedAttrSelectorOperation<AttrValue> {
     Exists,
     WithValue {
         operator: AttrSelectorOperator,
         case_sensitivity: ParsedCaseSensitivity,
         expected_value: AttrValue,
-    }
+    },
 }
 
 #[derive(Clone, Eq, PartialEq)]
 pub enum AttrSelectorOperation<AttrValue> {
     Exists,
     WithValue {
         operator: AttrSelectorOperator,
         case_sensitivity: CaseSensitivity,
         expected_value: AttrValue,
-    }
+    },
 }
 
 impl<AttrValue> AttrSelectorOperation<AttrValue> {
-    pub fn eval_str(&self, element_attr_value: &str) -> bool where AttrValue: AsRef<str> {
+    pub fn eval_str(&self, element_attr_value: &str) -> bool
+    where
+        AttrValue: AsRef<str>,
+    {
         match *self {
             AttrSelectorOperation::Exists => true,
-            AttrSelectorOperation::WithValue { operator, case_sensitivity, ref expected_value } => {
-                operator.eval_str(element_attr_value, expected_value.as_ref(), case_sensitivity)
-            }
+            AttrSelectorOperation::WithValue {
+                operator,
+                case_sensitivity,
+                ref expected_value,
+            } => operator.eval_str(
+                element_attr_value,
+                expected_value.as_ref(),
+                case_sensitivity,
+            ),
         }
     }
 }
 
 #[derive(Clone, Copy, Eq, PartialEq)]
 pub enum AttrSelectorOperator {
     Equal,
     Includes,
     DashMatch,
     Prefix,
     Substring,
     Suffix,
 }
 
 impl ToCss for AttrSelectorOperator {
-    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
+    where
+        W: fmt::Write,
+    {
         // https://drafts.csswg.org/cssom/#serializing-selectors
         // See "attribute selector".
         dest.write_str(match *self {
             AttrSelectorOperator::Equal => "=",
             AttrSelectorOperator::Includes => "~=",
             AttrSelectorOperator::DashMatch => "|=",
             AttrSelectorOperator::Prefix => "^=",
             AttrSelectorOperator::Substring => "*=",
             AttrSelectorOperator::Suffix => "$=",
         })
     }
 }
 
 impl AttrSelectorOperator {
-    pub fn eval_str(self, element_attr_value: &str, attr_selector_value: &str,
-                    case_sensitivity: CaseSensitivity) -> bool {
+    pub fn eval_str(
+        self,
+        element_attr_value: &str,
+        attr_selector_value: &str,
+        case_sensitivity: CaseSensitivity,
+    ) -> bool {
         let e = element_attr_value.as_bytes();
         let s = attr_selector_value.as_bytes();
         let case = case_sensitivity;
         match self {
-            AttrSelectorOperator::Equal => {
-                case.eq(e, s)
-            }
-            AttrSelectorOperator::Prefix => {
-                e.len() >= s.len() && case.eq(&e[..s.len()], s)
-            }
+            AttrSelectorOperator::Equal => case.eq(e, s),
+            AttrSelectorOperator::Prefix => e.len() >= s.len() && case.eq(&e[..s.len()], s),
             AttrSelectorOperator::Suffix => {
                 e.len() >= s.len() && case.eq(&e[(e.len() - s.len())..], s)
-            }
+            },
             AttrSelectorOperator::Substring => {
                 case.contains(element_attr_value, attr_selector_value)
-            }
-            AttrSelectorOperator::Includes => {
-                element_attr_value.split(SELECTOR_WHITESPACE)
-                                  .any(|part| case.eq(part.as_bytes(), s))
-            }
+            },
+            AttrSelectorOperator::Includes => element_attr_value
+                .split(SELECTOR_WHITESPACE)
+                .any(|part| case.eq(part.as_bytes(), s)),
             AttrSelectorOperator::DashMatch => {
-                case.eq(e, s) || (
-                    e.get(s.len()) == Some(&b'-') &&
-                    case.eq(&e[..s.len()], s)
-                )
-            }
+                case.eq(e, s) || (e.get(s.len()) == Some(&b'-') && case.eq(&e[..s.len()], s))
+            },
         }
     }
 }
 
 /// The definition of whitespace per CSS Selectors Level 3 § 4.
 pub static SELECTOR_WHITESPACE: &'static [char] = &[' ', '\t', '\n', '\r', '\x0C'];
 
 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
@@ -132,22 +138,23 @@ pub enum ParsedCaseSensitivity {
     AsciiCaseInsensitive,
     AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument,
 }
 
 impl ParsedCaseSensitivity {
     pub fn to_unconditional(self, is_html_element_in_html_document: bool) -> CaseSensitivity {
         match self {
             ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument
-            if is_html_element_in_html_document => {
+                if is_html_element_in_html_document =>
+            {
                 CaseSensitivity::AsciiCaseInsensitive
-            }
+            },
             ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {
                 CaseSensitivity::CaseSensitive
-            }
+            },
             ParsedCaseSensitivity::CaseSensitive => CaseSensitivity::CaseSensitive,
             ParsedCaseSensitivity::AsciiCaseInsensitive => CaseSensitivity::AsciiCaseInsensitive,
         }
     }
 }
 
 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
 pub enum CaseSensitivity {
@@ -165,27 +172,25 @@ impl CaseSensitivity {
 
     pub fn contains(self, haystack: &str, needle: &str) -> bool {
         match self {
             CaseSensitivity::CaseSensitive => haystack.contains(needle),
             CaseSensitivity::AsciiCaseInsensitive => {
                 if let Some((&n_first_byte, n_rest)) = needle.as_bytes().split_first() {
                     haystack.bytes().enumerate().any(|(i, byte)| {
                         if !byte.eq_ignore_ascii_case(&n_first_byte) {
-                            return false
+                            return false;
                         }
                         let after_this_byte = &haystack.as_bytes()[i + 1..];
                         match after_this_byte.get(..n_rest.len()) {
                             None => false,
-                            Some(haystack_slice) => {
-                                haystack_slice.eq_ignore_ascii_case(n_rest)
-                            }
+                            Some(haystack_slice) => haystack_slice.eq_ignore_ascii_case(n_rest),
                         }
                     })
                 } else {
                     // any_str.contains("") == true,
                     // though these cases should be handled with *NeverMatches and never go here.
                     true
                 }
-            }
+            },
         }
     }
 }
--- a/servo/components/selectors/bloom.rs
+++ b/servo/components/selectors/bloom.rs
@@ -67,21 +67,27 @@ pub type NonCountingBloomFilter = Counti
 ///
 /// What this means in practice is that for a few hundred keys using a
 /// KeySize of 12 gives false positive rates on the order of 0.25-4%.
 ///
 /// Similarly, using a KeySize of 10 would lead to a 4% false
 /// positive rate for N == 100 and to quite bad false positive
 /// rates for larger N.
 #[derive(Clone)]
-pub struct CountingBloomFilter<S> where S: BloomStorage {
+pub struct CountingBloomFilter<S>
+where
+    S: BloomStorage,
+{
     storage: S,
 }
 
-impl<S> CountingBloomFilter<S> where S: BloomStorage {
+impl<S> CountingBloomFilter<S>
+where
+    S: BloomStorage,
+{
     /// Creates a new bloom filter.
     #[inline]
     pub fn new() -> Self {
         CountingBloomFilter {
             storage: Default::default(),
         }
     }
 
@@ -123,43 +129,45 @@ impl<S> CountingBloomFilter<S> where S: 
     /// Removes an item from the bloom filter.
     #[inline]
     pub fn remove<T: Hash>(&mut self, elem: &T) {
         self.remove_hash(hash(elem))
     }
 
     #[inline]
     pub fn might_contain_hash(&self, hash: u32) -> bool {
-        !self.storage.first_slot_is_empty(hash) &&
-            !self.storage.second_slot_is_empty(hash)
+        !self.storage.first_slot_is_empty(hash) && !self.storage.second_slot_is_empty(hash)
     }
 
     /// Check whether the filter might contain an item.  This can
     /// sometimes return true even if the item is not in the filter,
     /// but will never return false for items that are actually in the
     /// filter.
     #[inline]
     pub fn might_contain<T: Hash>(&self, elem: &T) -> bool {
         self.might_contain_hash(hash(elem))
     }
 }
 
-impl<S> Debug for CountingBloomFilter<S> where S: BloomStorage {
+impl<S> Debug for CountingBloomFilter<S>
+where
+    S: BloomStorage,
+{
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         let mut slots_used = 0;
         for i in 0..ARRAY_SIZE {
             if !self.storage.slot_is_empty(i) {
                 slots_used += 1;
             }
         }
         write!(f, "BloomFilter({}/{})", slots_used, ARRAY_SIZE)
     }
 }
 
-pub trait BloomStorage : Clone + Default {
+pub trait BloomStorage: Clone + Default {
     fn slot_is_empty(&self, index: usize) -> bool;
     fn adjust_slot(&mut self, index: usize, increment: bool);
     fn is_zeroed(&self) -> bool;
 
     #[inline]
     fn first_slot_is_empty(&self, hash: u32) -> bool {
         self.slot_is_empty(Self::first_slot_index(hash))
     }
@@ -194,17 +202,18 @@ pub trait BloomStorage : Clone + Default
 pub struct BloomStorageU8 {
     counters: [u8; ARRAY_SIZE],
 }
 
 impl BloomStorage for BloomStorageU8 {
     #[inline]
     fn adjust_slot(&mut self, index: usize, increment: bool) {
         let slot = &mut self.counters[index];
-        if *slot != 0xff {  // full
+        if *slot != 0xff {
+            // full
             if increment {
                 *slot += 1;
             } else {
                 *slot -= 1;
             }
         }
     }
 
@@ -244,18 +253,20 @@ impl BloomStorage for BloomStorageBool {
     #[inline]
     fn adjust_slot(&mut self, index: usize, increment: bool) {
         let bit = 1 << (index % 8);
         let byte = &mut self.counters[index / 8];
 
         // Since we have only one bit for storage, decrementing it
         // should never do anything.  Assert against an accidental
         // decrementing of a bit that was never set.
-        assert!(increment || (*byte & bit) != 0,
-                "should not decrement if slot is already false");
+        assert!(
+            increment || (*byte & bit) != 0,
+            "should not decrement if slot is already false"
+        );
 
         if increment {
             *byte |= bit;
         }
     }
 
     #[inline]
     fn slot_is_empty(&self, index: usize) -> bool {
@@ -309,44 +320,43 @@ fn create_and_insert_some_stuff() {
     let mut bf = BloomFilter::new();
 
     // Statically assert that ARRAY_SIZE is a multiple of 8, which
     // BloomStorageBool relies on.
     unsafe {
         transmute::<[u8; ARRAY_SIZE % 8], [u8; 0]>([]);
     }
 
-    for i in 0_usize .. 1000 {
+    for i in 0_usize..1000 {
         bf.insert(&i);
     }
 
-    for i in 0_usize .. 1000 {
+    for i in 0_usize..1000 {
         assert!(bf.might_contain(&i));
     }
 
-    let false_positives =
-        (1001_usize .. 2000).filter(|i| bf.might_contain(i)).count();
+    let false_positives = (1001_usize..2000).filter(|i| bf.might_contain(i)).count();
 
     assert!(false_positives < 150, "{} is not < 150", false_positives); // 15%.
 
-    for i in 0_usize .. 100 {
+    for i in 0_usize..100 {
         bf.remove(&i);
     }
 
-    for i in 100_usize .. 1000 {
+    for i in 100_usize..1000 {
         assert!(bf.might_contain(&i));
     }
 
-    let false_positives = (0_usize .. 100).filter(|i| bf.might_contain(i)).count();
+    let false_positives = (0_usize..100).filter(|i| bf.might_contain(i)).count();
 
     assert!(false_positives < 20, "{} is not < 20", false_positives); // 20%.
 
     bf.clear();
 
-    for i in 0_usize .. 2000 {
+    for i in 0_usize..2000 {
         assert!(!bf.might_contain(&i));
     }
 }
 
 #[cfg(feature = "bench")]
 #[cfg(test)]
 mod bench {
     extern crate test;
@@ -371,54 +381,60 @@ mod bench {
     }
 
     #[bench]
     fn create_insert_1000_remove_100_lookup_100(b: &mut test::Bencher) {
         b.iter(|| {
             let mut gen1 = HashGenerator::default();
             let mut gen2 = HashGenerator::default();
             let mut bf = BloomFilter::new();
-            for _ in 0_usize .. 1000 {
+            for _ in 0_usize..1000 {
                 bf.insert_hash(gen1.next());
             }
-            for _ in 0_usize .. 100 {
+            for _ in 0_usize..100 {
                 bf.remove_hash(gen2.next());
             }
-            for _ in 100_usize .. 200 {
+            for _ in 100_usize..200 {
                 test::black_box(bf.might_contain_hash(gen2.next()));
             }
         });
     }
 
     #[bench]
     fn might_contain_10(b: &mut test::Bencher) {
         let bf = BloomFilter::new();
         let mut gen = HashGenerator::default();
-        b.iter(|| for _ in 0..10 {
-            test::black_box(bf.might_contain_hash(gen.next()));
+        b.iter(|| {
+            for _ in 0..10 {
+                test::black_box(bf.might_contain_hash(gen.next()));
+            }
         });
     }
 
     #[bench]
     fn clear(b: &mut test::Bencher) {
         let mut bf = Box::new(BloomFilter::new());
         b.iter(|| test::black_box(&mut bf).clear());
     }
 
     #[bench]
     fn insert_10(b: &mut test::Bencher) {
         let mut bf = BloomFilter::new();
         let mut gen = HashGenerator::default();
-        b.iter(|| for _ in 0..10 {
-            test::black_box(bf.insert_hash(gen.next()));
+        b.iter(|| {
+            for _ in 0..10 {
+                test::black_box(bf.insert_hash(gen.next()));
+            }
         });
     }
 
     #[bench]
     fn remove_10(b: &mut test::Bencher) {
         let mut bf = BloomFilter::new();
         let mut gen = HashGenerator::default();
         // Note: this will underflow, and that's ok.
-        b.iter(|| for _ in 0..10 {
-            bf.remove_hash(gen.next())
+        b.iter(|| {
+            for _ in 0..10 {
+                bf.remove_hash(gen.next())
+            }
         });
     }
 }
--- a/servo/components/selectors/build.rs
+++ b/servo/components/selectors/build.rs
@@ -9,18 +9,17 @@ use std::fs::File;
 use std::io::{BufWriter, Write};
 use std::path::Path;
 
 fn main() {
     let path = Path::new(&env::var_os("OUT_DIR").unwrap())
         .join("ascii_case_insensitive_html_attributes.rs");
     let mut file = BufWriter::new(File::create(&path).unwrap());
 
-    write!(&mut file, "{{ static SET: ::phf::Set<&'static str> = ",
-    ).unwrap();
+    write!(&mut file, "{{ static SET: ::phf::Set<&'static str> = ").unwrap();
     let mut set = phf_codegen::Set::new();
     for name in ASCII_CASE_INSENSITIVE_HTML_ATTRIBUTES.split_whitespace() {
         set.entry(name);
     }
     set.build(&mut file).unwrap();
     write!(&mut file, "; &SET }}").unwrap();
 }
 
--- a/servo/components/selectors/builder.rs
+++ b/servo/components/selectors/builder.rs
@@ -111,22 +111,23 @@ impl<Impl: SelectorImpl> SelectorBuilder
 
         if parsed_slotted {
             spec.0 |= HAS_SLOTTED_BIT;
         }
 
         self.build_with_specificity_and_flags(spec)
     }
 
-
     /// Builds with an explicit SpecificityAndFlags. This is separated from build() so
     /// that unit tests can pass an explicit specificity.
     #[inline(always)]
-    pub fn build_with_specificity_and_flags(&mut self, spec: SpecificityAndFlags)
-                                            -> ThinArc<SpecificityAndFlags, Component<Impl>> {
+    pub fn build_with_specificity_and_flags(
+        &mut self,
+        spec: SpecificityAndFlags,
+    ) -> ThinArc<SpecificityAndFlags, Component<Impl>> {
         // First, compute the total number of Components we'll need to allocate
         // space for.
         let full_len = self.simple_selectors.len() + self.combinators.len();
 
         // Create the header.
         let header = HeaderWithLength::new(spec, full_len);
 
         // Create the Arc using an iterator that drains our buffers.
@@ -154,33 +155,30 @@ impl<Impl: SelectorImpl> SelectorBuilder
 struct SelectorBuilderIter<'a, Impl: SelectorImpl> {
     current_simple_selectors: slice::Iter<'a, Component<Impl>>,
     rest_of_simple_selectors: &'a [Component<Impl>],
     combinators: iter::Rev<smallvec::Drain<'a, (Combinator, usize)>>,
 }
 
 impl<'a, Impl: SelectorImpl> ExactSizeIterator for SelectorBuilderIter<'a, Impl> {
     fn len(&self) -> usize {
-        self.current_simple_selectors.len() +
-        self.rest_of_simple_selectors.len() +
-        self.combinators.len()
+        self.current_simple_selectors.len() + self.rest_of_simple_selectors.len() +
+            self.combinators.len()
     }
 }
 
 impl<'a, Impl: SelectorImpl> Iterator for SelectorBuilderIter<'a, Impl> {
     type Item = Component<Impl>;
     #[inline(always)]
     fn next(&mut self) -> Option<Self::Item> {
         if let Some(simple_selector_ref) = self.current_simple_selectors.next() {
             // Move a simple selector out of this slice iterator.
             // This is safe because we’ve called SmallVec::set_len(0) above,
             // so SmallVec::drop won’t drop this simple selector.
-            unsafe {
-                Some(ptr::read(simple_selector_ref))
-            }
+            unsafe { Some(ptr::read(simple_selector_ref)) }
         } else {
             self.combinators.next().map(|(combinator, len)| {
                 let (rest, current) = split_from_end(self.rest_of_simple_selectors, len);
                 self.rest_of_simple_selectors = rest;
                 self.current_simple_selectors = current.iter();
                 Component::Combinator(combinator)
             })
         }
@@ -230,20 +228,18 @@ struct Specificity {
 }
 
 impl Add for Specificity {
     type Output = Specificity;
 
     fn add(self, rhs: Specificity) -> Specificity {
         Specificity {
             id_selectors: self.id_selectors + rhs.id_selectors,
-            class_like_selectors:
-                self.class_like_selectors + rhs.class_like_selectors,
-            element_selectors:
-                self.element_selectors + rhs.element_selectors,
+            class_like_selectors: self.class_like_selectors + rhs.class_like_selectors,
+            element_selectors: self.element_selectors + rhs.element_selectors,
         }
     }
 }
 
 impl Default for Specificity {
     fn default() -> Specificity {
         Specificity {
             id_selectors: 0,
@@ -261,86 +257,83 @@ impl From<u32> for Specificity {
             class_like_selectors: (value >> 10) & MAX_10BIT,
             element_selectors: value & MAX_10BIT,
         }
     }
 }
 
 impl From<Specificity> for u32 {
     fn from(specificity: Specificity) -> u32 {
-        cmp::min(specificity.id_selectors, MAX_10BIT) << 20
-        | cmp::min(specificity.class_like_selectors, MAX_10BIT) << 10
-        | cmp::min(specificity.element_selectors, MAX_10BIT)
+        cmp::min(specificity.id_selectors, MAX_10BIT) << 20 |
+            cmp::min(specificity.class_like_selectors, MAX_10BIT) << 10 |
+            cmp::min(specificity.element_selectors, MAX_10BIT)
     }
 }
 
 fn specificity<Impl>(iter: slice::Iter<Component<Impl>>) -> u32
-    where Impl: SelectorImpl
+where
+    Impl: SelectorImpl,
 {
     complex_selector_specificity(iter).into()
 }
 
-fn complex_selector_specificity<Impl>(mut iter: slice::Iter<Component<Impl>>)
-                                      -> Specificity
-    where Impl: SelectorImpl
+fn complex_selector_specificity<Impl>(mut iter: slice::Iter<Component<Impl>>) -> Specificity
+where
+    Impl: SelectorImpl,
 {
     fn simple_selector_specificity<Impl>(
         simple_selector: &Component<Impl>,
         specificity: &mut Specificity,
-    )
-    where
-        Impl: SelectorImpl
+    ) where
+        Impl: SelectorImpl,
     {
         match *simple_selector {
             Component::Combinator(..) => unreachable!(),
             // FIXME(emilio): Spec doesn't define any particular specificity for
             // ::slotted(), so apply the general rule for pseudos per:
             //
             // https://github.com/w3c/csswg-drafts/issues/1915
             //
             // Though other engines compute it dynamically, so maybe we should
             // do that instead, eventually.
-            Component::Slotted(..) |
-            Component::PseudoElement(..) |
-            Component::LocalName(..) => {
+            Component::Slotted(..) | Component::PseudoElement(..) | Component::LocalName(..) => {
                 specificity.element_selectors += 1
-            }
-            Component::ID(..) => {
-                specificity.id_selectors += 1
-            }
+            },
+            Component::ID(..) => specificity.id_selectors += 1,
             Component::Class(..) |
             Component::AttributeInNoNamespace { .. } |
             Component::AttributeInNoNamespaceExists { .. } |
             Component::AttributeOther(..) |
-
-            Component::FirstChild | Component::LastChild |
-            Component::OnlyChild | Component::Root |
-            Component::Empty | Component::Scope |
+            Component::FirstChild |
+            Component::LastChild |
+            Component::OnlyChild |
+            Component::Root |
+            Component::Empty |
+            Component::Scope |
             Component::Host(..) |
             Component::NthChild(..) |
             Component::NthLastChild(..) |
             Component::NthOfType(..) |
             Component::NthLastOfType(..) |
-            Component::FirstOfType | Component::LastOfType |
+            Component::FirstOfType |
+            Component::LastOfType |
             Component::OnlyOfType |
-            Component::NonTSPseudoClass(..) => {
-                specificity.class_like_selectors += 1
-            }
+            Component::NonTSPseudoClass(..) => specificity.class_like_selectors += 1,
             Component::ExplicitUniversalType |
             Component::ExplicitAnyNamespace |
             Component::ExplicitNoNamespace |
             Component::DefaultNamespace(..) |
             Component::Namespace(..) => {
                 // Does not affect specificity
-            }
+            },
             Component::Negation(ref negated) => {
                 for ss in negated.iter() {
                     simple_selector_specificity(&ss, specificity);
                 }
-            }
+            },
         }
     }
 
     let mut specificity = Default::default();
     for simple_selector in &mut iter {
         simple_selector_specificity(&simple_selector, &mut specificity);
     }
     specificity
--- a/servo/components/selectors/context.rs
+++ b/servo/components/selectors/context.rs
@@ -49,26 +49,26 @@ pub enum VisitedHandlingMode {
 }
 
 impl VisitedHandlingMode {
     #[inline]
     pub fn matches_visited(&self) -> bool {
         matches!(
             *self,
             VisitedHandlingMode::RelevantLinkVisited |
-            VisitedHandlingMode::AllLinksVisitedAndUnvisited
+                VisitedHandlingMode::AllLinksVisitedAndUnvisited
         )
     }
 
     #[inline]
     pub fn matches_unvisited(&self) -> bool {
         matches!(
             *self,
             VisitedHandlingMode::AllLinksUnvisited |
-            VisitedHandlingMode::AllLinksVisitedAndUnvisited
+                VisitedHandlingMode::AllLinksVisitedAndUnvisited
         )
     }
 }
 
 /// Which quirks mode is this document in.
 ///
 /// See: https://quirks.spec.whatwg.org/
 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
@@ -80,18 +80,17 @@ pub enum QuirksMode {
     /// No quirks mode.
     NoQuirks,
 }
 
 impl QuirksMode {
     #[inline]
     pub fn classes_and_ids_case_sensitivity(self) -> CaseSensitivity {
         match self {
-            QuirksMode::NoQuirks |
-            QuirksMode::LimitedQuirks => CaseSensitivity::CaseSensitive,
+            QuirksMode::NoQuirks | QuirksMode::LimitedQuirks => CaseSensitivity::CaseSensitive,
             QuirksMode::Quirks => CaseSensitivity::AsciiCaseInsensitive,
         }
     }
 }
 
 /// Data associated with the matching process for a element.  This context is
 /// used across many selectors for an element, so it's not appropriate for
 /// transient data that applies to only a single selector.
@@ -156,17 +155,17 @@ where
         nth_index_cache: Option<&'a mut NthIndexCache>,
         quirks_mode: QuirksMode,
     ) -> Self {
         Self::new_for_visited(
             matching_mode,
             bloom_filter,
             nth_index_cache,
             VisitedHandlingMode::AllLinksUnvisited,
-            quirks_mode
+            quirks_mode,
         )
     }
 
     /// Constructs a new `MatchingContext` for use in visited matching.
     pub fn new_for_visited(
         matching_mode: MatchingMode,
         bloom_filter: Option<&'a BloomFilter>,
         nth_index_cache: Option<&'a mut NthIndexCache>,
@@ -191,18 +190,17 @@ where
     }
 
     /// Override the quirks mode we're matching against.
     ///
     /// FIXME(emilio): This is a hack for XBL quirks-mode mismatches.
     #[inline]
     pub fn set_quirks_mode(&mut self, quirks_mode: QuirksMode) {
         self.quirks_mode = quirks_mode;
-        self.classes_and_ids_case_sensitivity =
-            quirks_mode.classes_and_ids_case_sensitivity();
+        self.classes_and_ids_case_sensitivity = quirks_mode.classes_and_ids_case_sensitivity();
     }
 
     /// Whether we're matching a nested selector.
     #[inline]
     pub fn is_nested(&self) -> bool {
         self.nesting_level != 0
     }
 
@@ -244,20 +242,17 @@ where
 
     /// Runs F with a deeper nesting level, and marking ourselves in a negation,
     /// for a :not(..) selector, for example.
     #[inline]
     pub fn nest_for_negation<F, R>(&mut self, f: F) -> R
     where
         F: FnOnce(&mut Self) -> R,
     {
-        debug_assert!(
-            !self.in_negation,
-            "Someone messed up parsing?"
-        );
+        debug_assert!(!self.in_negation, "Someone messed up parsing?");
         self.in_negation = true;
         let result = self.nest(f);
         self.in_negation = false;
         result
     }
 
     #[inline]
     pub fn visited_handling(&self) -> VisitedHandlingMode {
@@ -279,21 +274,17 @@ where
         let result = f(self);
         self.visited_handling = original_handling_mode;
         result
     }
 
     /// Runs F with a given shadow host which is the root of the tree whose
     /// rules we're matching.
     #[inline]
-    pub fn with_shadow_host<F, E, R>(
-        &mut self,
-        host: Option<E>,
-        f: F,
-    ) -> R
+    pub fn with_shadow_host<F, E, R>(&mut self, host: Option<E>, f: F) -> R
     where
         E: Element,
         F: FnOnce(&mut Self) -> R,
     {
         let original_host = self.current_host.take();
         self.current_host = host.map(|h| h.opaque());
         let result = f(self);
         self.current_host = original_host;
--- a/servo/components/selectors/lib.rs
+++ b/servo/components/selectors/lib.rs
@@ -1,20 +1,24 @@
 /* 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/. */
 
 // Make |cargo bench| work.
 #![cfg_attr(feature = "bench", feature(test))]
 
-#[macro_use] extern crate bitflags;
-#[macro_use] extern crate cssparser;
-#[macro_use] extern crate log;
-#[macro_use] extern crate matches;
+#[macro_use]
+extern crate bitflags;
+#[macro_use]
+extern crate cssparser;
 extern crate fnv;
+#[macro_use]
+extern crate log;
+#[macro_use]
+extern crate matches;
 extern crate phf;
 extern crate precomputed_hash;
 extern crate servo_arc;
 extern crate smallvec;
 
 pub mod attr;
 pub mod bloom;
 mod builder;
@@ -22,10 +26,10 @@ pub mod context;
 pub mod matching;
 mod nth_index_cache;
 pub mod parser;
 pub mod sink;
 mod tree;
 pub mod visitor;
 
 pub use nth_index_cache::NthIndexCache;
-pub use parser::{SelectorImpl, Parser, SelectorList};
+pub use parser::{Parser, SelectorImpl, SelectorList};
 pub use tree::{Element, OpaqueElement};
--- a/servo/components/selectors/matching.rs
+++ b/servo/components/selectors/matching.rs
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use attr::{ParsedAttrSelectorOperation, AttrSelectorOperation, NamespaceConstraint};
-use bloom::{BLOOM_HASH_MASK, BloomFilter};
+use attr::{AttrSelectorOperation, NamespaceConstraint, ParsedAttrSelectorOperation};
+use bloom::{BloomFilter, BLOOM_HASH_MASK};
 use nth_index_cache::NthIndexCacheInner;
 use parser::{AncestorHashes, Combinator, Component, LocalName};
-use parser::{Selector, SelectorImpl, SelectorIter, SelectorList, NonTSPseudoClass};
+use parser::{NonTSPseudoClass, Selector, SelectorImpl, SelectorIter, SelectorList};
 use std::borrow::Borrow;
 use std::iter;
 use tree::Element;
 
 pub use context::*;
 
 // The bloom filter for descendant CSS selectors will have a <1% false
 // positive rate until it has this many selectors in it, then it will
@@ -47,47 +47,40 @@ impl ElementSelectorFlags {
     /// Returns the subset of flags that apply to the element.
     pub fn for_self(self) -> ElementSelectorFlags {
         self & (ElementSelectorFlags::HAS_EMPTY_SELECTOR)
     }
 
     /// Returns the subset of flags that apply to the parent.
     pub fn for_parent(self) -> ElementSelectorFlags {
         self & (ElementSelectorFlags::HAS_SLOW_SELECTOR |
-                ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS |
-                ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR)
+            ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS |
+            ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR)
     }
 }
 
 /// Holds per-compound-selector data.
 struct LocalMatchingContext<'a, 'b: 'a, Impl: SelectorImpl> {
     shared: &'a mut MatchingContext<'b, Impl>,
     matches_hover_and_active_quirk: MatchesHoverAndActiveQuirk,
 }
 
 #[inline(always)]
 pub fn matches_selector_list<E>(
     selector_list: &SelectorList<E::Impl>,
     element: &E,
     context: &mut MatchingContext<E::Impl>,
 ) -> bool
 where
-    E: Element
+    E: Element,
 {
     // This is pretty much any(..) but manually inlined because the compiler
     // refuses to do so from querySelector / querySelectorAll.
     for selector in &selector_list.0 {
-        let matches = matches_selector(
-            selector,
-            0,
-            None,
-            element,
-            context,
-            &mut |_, _| {},
-        );
+        let matches = matches_selector(selector, 0, None, element, context, &mut |_, _| {});
 
         if matches {
             return true;
         }
     }
 
     false
 }
@@ -214,17 +207,17 @@ where
 
 /// Whether a compound selector matched, and whether it was the rightmost
 /// selector inside the complex selector.
 pub enum CompoundSelectorMatchingResult {
     /// The selector was fully matched.
     FullyMatched,
     /// The compound selector matched, and the next combinator offset is
     /// `next_combinator_offset`.
-    Matched { next_combinator_offset: usize, },
+    Matched { next_combinator_offset: usize },
     /// The selector didn't match.
     NotMatched,
 }
 
 /// Matches a compound selector belonging to `selector`, starting at offset
 /// `from_offset`, matching left to right.
 ///
 /// Requires that `from_offset` points to a `Combinator`.
@@ -233,17 +226,17 @@ pub enum CompoundSelectorMatchingResult 
 /// complex selector, but it happens to be the case we don't need it.
 pub fn matches_compound_selector_from<E>(
     selector: &Selector<E::Impl>,
     mut from_offset: usize,
     context: &mut MatchingContext<E::Impl>,
     element: &E,
 ) -> CompoundSelectorMatchingResult
 where
-    E: Element
+    E: Element,
 {
     if cfg!(debug_assertions) && from_offset != 0 {
         selector.combinator_at_parse_order(from_offset - 1); // This asserts.
     }
 
     let mut local_context = LocalMatchingContext {
         shared: context,
         matches_hover_and_active_quirk: MatchesHoverAndActiveQuirk::No,
@@ -262,44 +255,39 @@ where
         from_offset += 1;
     }
 
     debug_assert!(from_offset >= 1);
     debug_assert!(from_offset <= selector.len());
 
     let iter = selector.iter_from(selector.len() - from_offset);
     debug_assert!(
-        iter.clone().next().is_some() || (
-            from_offset != selector.len() && matches!(
-                selector.combinator_at_parse_order(from_offset),
-                Combinator::SlotAssignment | Combinator::PseudoElement
-            )
-        ),
+        iter.clone().next().is_some() ||
+            (from_offset != selector.len() &&
+                matches!(
+                    selector.combinator_at_parse_order(from_offset),
+                    Combinator::SlotAssignment | Combinator::PseudoElement
+                )),
         "Got the math wrong: {:?} | {:?} | {} {}",
         selector,
         selector.iter_raw_match_order().as_slice(),
         from_offset,
         start_offset
     );
 
     for component in iter {
-        if !matches_simple_selector(
-            component,
-            element,
-            &mut local_context,
-            &mut |_, _| {}
-        ) {
+        if !matches_simple_selector(component, element, &mut local_context, &mut |_, _| {}) {
             return CompoundSelectorMatchingResult::NotMatched;
         }
     }
 
     if from_offset != selector.len() {
         return CompoundSelectorMatchingResult::Matched {
             next_combinator_offset: from_offset,
-        }
+        };
     }
 
     CompoundSelectorMatchingResult::FullyMatched
 }
 
 /// Matches a complex selector.
 #[inline(always)]
 pub fn matches_complex_selector<E, F>(
@@ -309,60 +297,58 @@ pub fn matches_complex_selector<E, F>(
     flags_setter: &mut F,
 ) -> bool
 where
     E: Element,
     F: FnMut(&E, ElementSelectorFlags),
 {
     // If this is the special pseudo-element mode, consume the ::pseudo-element
     // before proceeding, since the caller has already handled that part.
-    if context.matching_mode() == MatchingMode::ForStatelessPseudoElement &&
-        !context.is_nested() {
+    if context.matching_mode() == MatchingMode::ForStatelessPseudoElement && !context.is_nested() {
         // Consume the pseudo.
         match *iter.next().unwrap() {
             Component::PseudoElement(ref pseudo) => {
                 if let Some(ref f) = context.pseudo_element_matching_fn {
                     if !f(pseudo) {
                         return false;
                     }
                 }
-            }
+            },
             _ => {
-                debug_assert!(false,
-                              "Used MatchingMode::ForStatelessPseudoElement \
-                               in a non-pseudo selector");
-            }
+                debug_assert!(
+                    false,
+                    "Used MatchingMode::ForStatelessPseudoElement \
+                     in a non-pseudo selector"
+                );
+            },
         }
 
         // The only other parser-allowed Component in this sequence is a state
         // class. We just don't match in that case.
         if let Some(s) = iter.next() {
-            debug_assert!(matches!(*s, Component::NonTSPseudoClass(..)),
-                          "Someone messed up pseudo-element parsing");
+            debug_assert!(
+                matches!(*s, Component::NonTSPseudoClass(..)),
+                "Someone messed up pseudo-element parsing"
+            );
             return false;
         }
 
         // Advance to the non-pseudo-element part of the selector, but let the
         // context note that .
         if iter.next_sequence().is_none() {
             return true;
         }
     }
 
-    let result = matches_complex_selector_internal(
-        iter,
-        element,
-        context,
-        flags_setter,
-        Rightmost::Yes,
-    );
+    let result =
+        matches_complex_selector_internal(iter, element, context, flags_setter, Rightmost::Yes);
 
     match result {
         SelectorMatchingResult::Matched => true,
-        _ => false
+        _ => false,
     }
 }
 
 #[inline]
 fn matches_hover_and_active_quirk<Impl: SelectorImpl>(
     selector_iter: &SelectorIter<Impl>,
     context: &MatchingContext<Impl>,
     rightmost: Rightmost,
@@ -373,46 +359,43 @@ fn matches_hover_and_active_quirk<Impl: 
 
     if context.is_nested() {
         return MatchesHoverAndActiveQuirk::No;
     }
 
     // This compound selector had a pseudo-element to the right that we
     // intentionally skipped.
     if rightmost == Rightmost::Yes &&
-        context.matching_mode() == MatchingMode::ForStatelessPseudoElement {
+        context.matching_mode() == MatchingMode::ForStatelessPseudoElement
+    {
         return MatchesHoverAndActiveQuirk::No;
     }
 
-    let all_match = selector_iter.clone().all(|simple| {
-        match *simple {
-            Component::LocalName(_) |
-            Component::AttributeInNoNamespaceExists { .. } |
-            Component::AttributeInNoNamespace { .. } |
-            Component::AttributeOther(_) |
-            Component::ID(_) |
-            Component::Class(_) |
-            Component::PseudoElement(_) |
-            Component::Negation(_) |
-            Component::FirstChild |
-            Component::LastChild |
-            Component::OnlyChild |
-            Component::Empty |
-            Component::NthChild(_, _) |
-            Component::NthLastChild(_, _) |
-            Component::NthOfType(_, _) |
-            Component::NthLastOfType(_, _) |
-            Component::FirstOfType |
-            Component::LastOfType |
-            Component::OnlyOfType => false,
-            Component::NonTSPseudoClass(ref pseudo_class) => {
-                pseudo_class.is_active_or_hover()
-            },
-            _ => true,
-        }
+    let all_match = selector_iter.clone().all(|simple| match *simple {
+        Component::LocalName(_) |
+        Component::AttributeInNoNamespaceExists { .. } |
+        Component::AttributeInNoNamespace { .. } |
+        Component::AttributeOther(_) |
+        Component::ID(_) |
+        Component::Class(_) |
+        Component::PseudoElement(_) |
+        Component::Negation(_) |
+        Component::FirstChild |
+        Component::LastChild |
+        Component::OnlyChild |
+        Component::Empty |
+        Component::NthChild(_, _) |
+        Component::NthLastChild(_, _) |
+        Component::NthOfType(_, _) |
+        Component::NthLastOfType(_, _) |
+        Component::FirstOfType |
+        Component::LastOfType |
+        Component::OnlyOfType => false,
+        Component::NonTSPseudoClass(ref pseudo_class) => pseudo_class.is_active_or_hover(),
+        _ => true,
     });
 
     if all_match {
         MatchesHoverAndActiveQuirk::Yes
     } else {
         MatchesHoverAndActiveQuirk::No
     }
 }
@@ -428,29 +411,25 @@ fn next_element_for_combinator<E>(
     element: &E,
     combinator: Combinator,
     selector: &SelectorIter<E::Impl>,
 ) -> Option<E>
 where
     E: Element,
 {
     match combinator {
-        Combinator::NextSibling |
-        Combinator::LaterSibling => {
-            element.prev_sibling_element()
-        }
-        Combinator::Child |
-        Combinator::Descendant => {
+        Combinator::NextSibling | Combinator::LaterSibling => element.prev_sibling_element(),
+        Combinator::Child | Combinator::Descendant => {
             if element.blocks_ancestor_combinators() {
                 return None;
             }
 
             match element.parent_element() {
                 Some(e) => return Some(e),
-                None => {}
+                None => {},
             }
 
             if !element.parent_node_is_shadow_root() {
                 return None;
             }
 
             // https://drafts.csswg.org/css-scoping/#host-element-in-tree:
             //
@@ -468,156 +447,157 @@ where
             // Since we know that the parent is a shadow root, we necessarily
             // are in a shadow tree of the host, and the next selector will only
             // match if the selector is a featureless :host selector.
             if !selector.clone().is_featureless_host_selector() {
                 return None;
             }
 
             element.containing_shadow_host()
-        }
+        },
         Combinator::SlotAssignment => {
-            debug_assert!(element.assigned_slot().map_or(true, |s| s.is_html_slot_element()));
+            debug_assert!(
+                element
+                    .assigned_slot()
+                    .map_or(true, |s| s.is_html_slot_element())
+            );
             element.assigned_slot()
-        }
-        Combinator::PseudoElement => {
-            element.pseudo_element_originating_element()
-        }
+        },
+        Combinator::PseudoElement => element.pseudo_element_originating_element(),
     }
 }
 
 fn matches_complex_selector_internal<E, F>(
     mut selector_iter: SelectorIter<E::Impl>,
     element: &E,
     context: &mut MatchingContext<E::Impl>,
     flags_setter: &mut F,
     rightmost: Rightmost,
 ) -> SelectorMatchingResult
 where
     E: Element,
     F: FnMut(&E, ElementSelectorFlags),
 {
-    debug!("Matching complex selector {:?} for {:?}", selector_iter, element);
+    debug!(
+        "Matching complex selector {:?} for {:?}",
+        selector_iter, element
+    );
 
     let matches_compound_selector = matches_compound_selector(
         &mut selector_iter,
         element,
         context,
         flags_setter,
-        rightmost
+        rightmost,
     );
 
     let combinator = selector_iter.next_sequence();
     if combinator.map_or(false, |c| c.is_sibling()) {
-        flags_setter(element, ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS);
+        flags_setter(
+            element,
+            ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS,
+        );
     }
 
     if !matches_compound_selector {
         return SelectorMatchingResult::NotMatchedAndRestartFromClosestLaterSibling;
     }
 
     let combinator = match combinator {
         None => return SelectorMatchingResult::Matched,
         Some(c) => c,
     };
 
     let candidate_not_found = match combinator {
-        Combinator::NextSibling |
-        Combinator::LaterSibling => {
+        Combinator::NextSibling | Combinator::LaterSibling => {
             SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant
-        }
+        },
         Combinator::Child |
         Combinator::Descendant |
         Combinator::SlotAssignment |
-        Combinator::PseudoElement => {
-            SelectorMatchingResult::NotMatchedGlobally
-        }
+        Combinator::PseudoElement => SelectorMatchingResult::NotMatchedGlobally,
     };
 
-    let mut next_element =
-        next_element_for_combinator(element, combinator, &selector_iter);
+    let mut next_element = next_element_for_combinator(element, combinator, &selector_iter);
 
     // Stop matching :visited as soon as we find a link, or a combinator for
     // something that isn't an ancestor.
     let mut visited_handling = if element.is_link() || combinator.is_sibling() {
         VisitedHandlingMode::AllLinksUnvisited
     } else {
         context.visited_handling()
     };
 
     loop {
         let element = match next_element {
             None => return candidate_not_found,
             Some(next_element) => next_element,
         };
 
-        let result =
-            context.with_visited_handling_mode(visited_handling, |context| {
-                matches_complex_selector_internal(
-                    selector_iter.clone(),
-                    &element,
-                    context,
-                    flags_setter,
-                    Rightmost::No,
-                )
-            });
+        let result = context.with_visited_handling_mode(visited_handling, |context| {
+            matches_complex_selector_internal(
+                selector_iter.clone(),
+                &element,
+                context,
+                flags_setter,
+                Rightmost::No,
+            )
+        });
 
         match (result, combinator) {
             // Return the status immediately.
             (SelectorMatchingResult::Matched, _) |
             (SelectorMatchingResult::NotMatchedGlobally, _) |
             (_, Combinator::NextSibling) => {
                 return result;
-            }
+            },
 
             // Upgrade the failure status to
             // NotMatchedAndRestartFromClosestDescendant.
-            (_, Combinator::PseudoElement) |
-            (_, Combinator::Child) => {
+            (_, Combinator::PseudoElement) | (_, Combinator::Child) => {
                 return SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant;
-            }
+            },
 
             // If the failure status is
             // NotMatchedAndRestartFromClosestDescendant and combinator is
             // Combinator::LaterSibling, give up this Combinator::LaterSibling
             // matching and restart from the closest descendant combinator.
-            (SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant, Combinator::LaterSibling) => {
+            (
+                SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant,
+                Combinator::LaterSibling,
+            ) => {
                 return result;
-            }
+            },
 
             // The Combinator::Descendant combinator and the status is
             // NotMatchedAndRestartFromClosestLaterSibling or
             // NotMatchedAndRestartFromClosestDescendant, or the
             // Combinator::LaterSibling combinator and the status is
             // NotMatchedAndRestartFromClosestDescendant, we can continue to
             // matching on the next candidate element.
             _ => {},
         }
 
         if element.is_link() || combinator.is_sibling() {
             visited_handling = VisitedHandlingMode::AllLinksUnvisited;
         }
 
-        next_element =
-            next_element_for_combinator(&element, combinator, &selector_iter);
+        next_element = next_element_for_combinator(&element, combinator, &selector_iter);
     }
 }
 
 #[inline]
-fn matches_local_name<E>(
-    element: &E,
-    local_name: &LocalName<E::Impl>
-) -> bool
+fn matches_local_name<E>(element: &E, local_name: &LocalName<E::Impl>) -> bool
 where
     E: Element,
 {
     let name = select_name(
         element.is_html_element_in_html_document(),
         &local_name.name,
-        &local_name.lower_name
+        &local_name.lower_name,
     ).borrow();
     element.local_name() == name
 }
 
 /// Determines whether the given element matches the given compound selector.
 #[inline]
 fn matches_compound_selector<E, F>(
     selector_iter: &mut SelectorIter<E::Impl>,
@@ -656,29 +636,23 @@ where
         }
         selector = selector_iter.next();
     }
     let selector = match selector {
         Some(s) => s,
         None => return true,
     };
 
-    let mut local_context =
-        LocalMatchingContext {
-            shared: context,
-            matches_hover_and_active_quirk,
-        };
-    iter::once(selector).chain(selector_iter).all(|simple| {
-        matches_simple_selector(
-            simple,
-            element,
-            &mut local_context,
-            flags_setter,
-        )
-    })
+    let mut local_context = LocalMatchingContext {
+        shared: context,
+        matches_hover_and_active_quirk,
+    };
+    iter::once(selector)
+        .chain(selector_iter)
+        .all(|simple| matches_simple_selector(simple, element, &mut local_context, flags_setter))
 }
 
 /// Determines whether the given element matches the given single selector.
 fn matches_simple_selector<E, F>(
     selector: &Component<E::Impl>,
     element: &E,
     context: &mut LocalMatchingContext<E::Impl>,
     flags_setter: &mut F,
@@ -688,194 +662,160 @@ where
     F: FnMut(&E, ElementSelectorFlags),
 {
     debug_assert!(context.shared.is_nested() || !context.shared.in_negation());
 
     match *selector {
         Component::Combinator(_) => unreachable!(),
         Component::Slotted(ref selector) => {
             // <slots> are never flattened tree slottables.
-            !element.is_html_slot_element() &&
-            element.assigned_slot().is_some() &&
-            context.shared.nest(|context| {
-                matches_complex_selector(
-                    selector.iter(),
-                    element,
-                    context,
-                    flags_setter,
-                )
-            })
-        }
+            !element.is_html_slot_element() && element.assigned_slot().is_some() &&
+                context.shared.nest(|context| {
+                    matches_complex_selector(selector.iter(), element, context, flags_setter)
+                })
+        },
         Component::PseudoElement(ref pseudo) => {
             element.match_pseudo_element(pseudo, context.shared)
-        }
-        Component::LocalName(ref local_name) => {
-            matches_local_name(element, local_name)
-        }
-        Component::ExplicitUniversalType |
-        Component::ExplicitAnyNamespace => {
-            true
-        }
-        Component::Namespace(_, ref url) |
-        Component::DefaultNamespace(ref url) => {
+        },
+        Component::LocalName(ref local_name) => matches_local_name(element, local_name),
+        Component::ExplicitUniversalType | Component::ExplicitAnyNamespace => true,
+        Component::Namespace(_, ref url) | Component::DefaultNamespace(ref url) => {
             element.namespace() == url.borrow()
-        }
+        },
         Component::ExplicitNoNamespace => {
             let ns = ::parser::namespace_empty_string::<E::Impl>();
             element.namespace() == ns.borrow()
-        }
+        },
         Component::ID(ref id) => {
             element.has_id(id, context.shared.classes_and_ids_case_sensitivity())
-        }
+        },
         Component::Class(ref class) => {
             element.has_class(class, context.shared.classes_and_ids_case_sensitivity())
-        }
-        Component::AttributeInNoNamespaceExists { ref local_name, ref local_name_lower } => {
+        },
+        Component::AttributeInNoNamespaceExists {
+            ref local_name,
+            ref local_name_lower,
+        } => {
             let is_html = element.is_html_element_in_html_document();
             element.attr_matches(
                 &NamespaceConstraint::Specific(&::parser::namespace_empty_string::<E::Impl>()),
                 select_name(is_html, local_name, local_name_lower),
-                &AttrSelectorOperation::Exists
+                &AttrSelectorOperation::Exists,
             )
-        }
+        },
         Component::AttributeInNoNamespace {
             ref local_name,
             ref local_name_lower,
             ref value,
             operator,
             case_sensitivity,
             never_matches,
         } => {
             if never_matches {
-                return false
+                return false;
             }
             let is_html = element.is_html_element_in_html_document();
             element.attr_matches(
                 &NamespaceConstraint::Specific(&::parser::namespace_empty_string::<E::Impl>()),
                 select_name(is_html, local_name, local_name_lower),
                 &AttrSelectorOperation::WithValue {
                     operator: operator,
                     case_sensitivity: case_sensitivity.to_unconditional(is_html),
                     expected_value: value,
-                }
+                },
             )
-        }
+        },
         Component::AttributeOther(ref attr_sel) => {
             if attr_sel.never_matches {
-                return false
+                return false;
             }
             let is_html = element.is_html_element_in_html_document();
             element.attr_matches(
                 &attr_sel.namespace(),
                 select_name(is_html, &attr_sel.local_name, &attr_sel.local_name_lower),
                 &match attr_sel.operation {
                     ParsedAttrSelectorOperation::Exists => AttrSelectorOperation::Exists,
                     ParsedAttrSelectorOperation::WithValue {
                         operator,
                         case_sensitivity,
                         ref expected_value,
-                    } => {
-                        AttrSelectorOperation::WithValue {
-                            operator: operator,
-                            case_sensitivity: case_sensitivity.to_unconditional(is_html),
-                            expected_value: expected_value,
-                        }
-                    }
-                }
+                    } => AttrSelectorOperation::WithValue {
+                        operator: operator,
+                        case_sensitivity: case_sensitivity.to_unconditional(is_html),
+                        expected_value: expected_value,
+                    },
+                },
             )
-        }
+        },
         Component::NonTSPseudoClass(ref pc) => {
             if context.matches_hover_and_active_quirk == MatchesHoverAndActiveQuirk::Yes &&
-               !context.shared.is_nested() &&
-               pc.is_active_or_hover() &&
-               !element.is_link()
+                !context.shared.is_nested() && pc.is_active_or_hover() &&
+                !element.is_link()
             {
                 return false;
             }
 
-            element.match_non_ts_pseudo_class(
-                pc,
-                &mut context.shared,
-                flags_setter
-            )
-        }
-        Component::FirstChild => {
-            matches_first_child(element, flags_setter)
-        }
-        Component::LastChild => {
-            matches_last_child(element, flags_setter)
-        }
+            element.match_non_ts_pseudo_class(pc, &mut context.shared, flags_setter)
+        },
+        Component::FirstChild => matches_first_child(element, flags_setter),
+        Component::LastChild => matches_last_child(element, flags_setter),
         Component::OnlyChild => {
-            matches_first_child(element, flags_setter) &&
-            matches_last_child(element, flags_setter)
-        }
-        Component::Root => {
-            element.is_root()
-        }
+            matches_first_child(element, flags_setter) && matches_last_child(element, flags_setter)
+        },
+        Component::Root => element.is_root(),
         Component::Empty => {
             flags_setter(element, ElementSelectorFlags::HAS_EMPTY_SELECTOR);
             element.is_empty()
-        }
+        },
         Component::Host(ref selector) => {
-            context.shared.shadow_host().map_or(false, |host| host == element.opaque()) &&
-            selector.as_ref().map_or(true, |selector| {
-                context.shared.nest(|context| {
-                    matches_complex_selector(
-                        selector.iter(),
-                        element,
-                        context,
-                        flags_setter,
-                    )
+            context
+                .shared
+                .shadow_host()
+                .map_or(false, |host| host == element.opaque()) &&
+                selector.as_ref().map_or(true, |selector| {
+                    context.shared.nest(|context| {
+                        matches_complex_selector(selector.iter(), element, context, flags_setter)
+                    })
                 })
-            })
-        }
-        Component::Scope => {
-            match context.shared.scope_element {
-                Some(ref scope_element) => element.opaque() == *scope_element,
-                None => element.is_root(),
-            }
-        }
+        },
+        Component::Scope => match context.shared.scope_element {
+            Some(ref scope_element) => element.opaque() == *scope_element,
+            None => element.is_root(),
+        },
         Component::NthChild(a, b) => {
             matches_generic_nth_child(element, context, a, b, false, false, flags_setter)
-        }
+        },
         Component::NthLastChild(a, b) => {
             matches_generic_nth_child(element, context, a, b, false, true, flags_setter)
-        }
+        },
         Component::NthOfType(a, b) => {
             matches_generic_nth_child(element, context, a, b, true, false, flags_setter)
-        }
+        },
         Component::NthLastOfType(a, b) => {
             matches_generic_nth_child(element, context, a, b, true, true, flags_setter)
-        }
+        },
         Component::FirstOfType => {
             matches_generic_nth_child(element, context, 0, 1, true, false, flags_setter)
-        }
+        },
         Component::LastOfType => {
             matches_generic_nth_child(element, context, 0, 1, true, true, flags_setter)
-        }
+        },
         Component::OnlyOfType => {
             matches_generic_nth_child(element, context, 0, 1, true, false, flags_setter) &&
-            matches_generic_nth_child(element, context, 0, 1, true, true, flags_setter)
-        }
-        Component::Negation(ref negated) => {
-            context.shared.nest_for_negation(|context| {
-                let mut local_context = LocalMatchingContext {
-                    matches_hover_and_active_quirk: MatchesHoverAndActiveQuirk::No,
-                    shared: context,
-                };
-                !negated.iter().all(|ss| {
-                    matches_simple_selector(
-                        ss,
-                        element,
-                        &mut local_context,
-                        flags_setter,
-                    )
-                })
-            })
-        }
+                matches_generic_nth_child(element, context, 0, 1, true, true, flags_setter)
+        },
+        Component::Negation(ref negated) => context.shared.nest_for_negation(|context| {
+            let mut local_context = LocalMatchingContext {
+                matches_hover_and_active_quirk: MatchesHoverAndActiveQuirk::No,
+                shared: context,
+            };
+            !negated
+                .iter()
+                .all(|ss| matches_simple_selector(ss, element, &mut local_context, flags_setter))
+        }),
     }
 }
 
 #[inline(always)]
 fn select_name<'a, T>(is_html: bool, local_name: &'a T, local_name_lower: &'a T) -> &'a T {
     if is_html {
         local_name_lower
     } else {
@@ -896,51 +836,64 @@ fn matches_generic_nth_child<E, F>(
 where
     E: Element,
     F: FnMut(&E, ElementSelectorFlags),
 {
     if element.ignores_nth_child_selectors() {
         return false;
     }
 
-    flags_setter(element, if is_from_end {
-        ElementSelectorFlags::HAS_SLOW_SELECTOR
-    } else {
-        ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS
-    });
+    flags_setter(
+        element,
+        if is_from_end {
+            ElementSelectorFlags::HAS_SLOW_SELECTOR
+        } else {
+            ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS
+        },
+    );
 
     // Grab a reference to the appropriate cache.
-    let mut cache = context.shared.nth_index_cache.as_mut().map(|c| {
-        c.get(is_of_type, is_from_end)
-    });
+    let mut cache = context
+        .shared
+        .nth_index_cache
+        .as_mut()
+        .map(|c| c.get(is_of_type, is_from_end));
 
     // Lookup or compute the index.
     let index = if let Some(i) = cache.as_mut().and_then(|c| c.lookup(element.opaque())) {
         i
     } else {
-        let i = nth_child_index(element, is_of_type, is_from_end, cache.as_mut().map(|s| &mut **s));
+        let i = nth_child_index(
+            element,
+            is_of_type,
+            is_from_end,
+            cache.as_mut().map(|s| &mut **s),
+        );
         cache.as_mut().map(|c| c.insert(element.opaque(), i));
         i
     };
-    debug_assert_eq!(index, nth_child_index(element, is_of_type, is_from_end, None), "invalid cache");
+    debug_assert_eq!(
+        index,
+        nth_child_index(element, is_of_type, is_from_end, None),
+        "invalid cache"
+    );
 
     // Is there a non-negative integer n such that An+B=index?
     match index.checked_sub(b) {
         None => false,
         Some(an) => match an.checked_div(a) {
             Some(n) => n >= 0 && a * n == an,
             None /* a == 0 */ => an == 0,
         },
     }
 }
 
 #[inline]
 fn same_type<E: Element>(a: &E, b: &E) -> bool {
-    a.local_name() == b.local_name() &&
-    a.namespace() == b.namespace()
+    a.local_name() == b.local_name() && a.namespace() == b.namespace()
 }
 
 #[inline]
 fn nth_child_index<E>(
     element: &E,
     is_of_type: bool,
     is_from_end: bool,
     mut cache: Option<&mut NthIndexCacheInner>,
@@ -967,26 +920,32 @@ where
                     index += 1;
                 }
             }
         }
     }
 
     let mut index: i32 = 1;
     let mut curr = element.clone();
-    let next = |e: E| if is_from_end { e.next_sibling_element() } else { e.prev_sibling_element() };
+    let next = |e: E| {
+        if is_from_end {
+            e.next_sibling_element()
+        } else {
+            e.prev_sibling_element()
+        }
+    };
     while let Some(e) = next(curr) {
         curr = e;
         if !is_of_type || same_type(element, &curr) {
             // If we're computing indices from the left, check each element in the
             // cache. We handle the indices-from-the-right case at the top of this
             // function.
             if !is_from_end {
                 if let Some(i) = cache.as_mut().and_then(|c| c.lookup(curr.opaque())) {
-                    return i + index
+                    return i + index;
                 }
             }
             index += 1;
         }
     }
 
     index
 }
--- a/servo/components/selectors/nth_index_cache.rs
+++ b/servo/components/selectors/nth_index_cache.rs
@@ -15,21 +15,17 @@ pub struct NthIndexCache {
     nth: NthIndexCacheInner,
     nth_last: NthIndexCacheInner,
     nth_of_type: NthIndexCacheInner,
     nth_last_of_type: NthIndexCacheInner,
 }
 
 impl NthIndexCache {
     /// Gets the appropriate cache for the given parameters.
-    pub fn get(
-        &mut self,
-        is_of_type: bool,
-        is_from_end: bool
-    ) -> &mut NthIndexCacheInner {
+    pub fn get(&mut self, is_of_type: bool, is_from_end: bool) -> &mut NthIndexCacheInner {
         match (is_of_type, is_from_end) {
             (false, false) => &mut self.nth,
             (false, true) => &mut self.nth_last,
             (true, false) => &mut self.nth_of_type,
             (true, true) => &mut self.nth_last_of_type,
         }
     }
 }
--- a/servo/components/selectors/parser.rs
+++ b/servo/components/selectors/parser.rs
@@ -1,47 +1,48 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use attr::{AttrSelectorWithNamespace, ParsedAttrSelectorOperation, AttrSelectorOperator};
-use attr::{ParsedCaseSensitivity, SELECTOR_WHITESPACE, NamespaceConstraint};
+use attr::{AttrSelectorOperator, AttrSelectorWithNamespace, ParsedAttrSelectorOperation};
+use attr::{NamespaceConstraint, ParsedCaseSensitivity, SELECTOR_WHITESPACE};
 use bloom::BLOOM_HASH_MASK;
 use builder::{SelectorBuilder, SpecificityAndFlags};
 use context::QuirksMode;
-use cssparser::{ParseError, ParseErrorKind, BasicParseError, BasicParseErrorKind};
-use cssparser::{SourceLocation, CowRcStr, Delimiter};
-use cssparser::{Token, Parser as CssParser, parse_nth, ToCss, serialize_identifier, CssStringWriter};
+use cssparser::{BasicParseError, BasicParseErrorKind, ParseError, ParseErrorKind};
+use cssparser::{CowRcStr, Delimiter, SourceLocation};
+use cssparser::{CssStringWriter, Parser as CssParser, ToCss, Token};
+use cssparser::{parse_nth, serialize_identifier};
 use precomputed_hash::PrecomputedHash;
 use servo_arc::ThinArc;
 use sink::Push;
 use smallvec::SmallVec;
 use std::borrow::{Borrow, Cow};
-use std::fmt::{self, Display, Debug, Write};
+use std::fmt::{self, Debug, Display, Write};
 use std::iter::Rev;
 use std::slice;
-pub use visitor::{Visit, SelectorVisitor};
+pub use visitor::{SelectorVisitor, Visit};
 
 /// A trait that represents a pseudo-element.
-pub trait PseudoElement : Sized + ToCss {
+pub trait PseudoElement: Sized + ToCss {
     /// The `SelectorImpl` this pseudo-element is used for.
     type Impl: SelectorImpl;
 
     /// Whether the pseudo-element supports a given state selector to the right
     /// of it.
     fn supports_pseudo_class(
         &self,
         _pseudo_class: &<Self::Impl as SelectorImpl>::NonTSPseudoClass,
     ) -> bool {
         false
     }
 }
 
 /// A trait that represents a pseudo-class.
-pub trait NonTSPseudoClass : Sized + ToCss {
+pub trait NonTSPseudoClass: Sized + ToCss {
     /// The `SelectorImpl` this pseudo-element is used for.
     type Impl: SelectorImpl;
 
     /// Whether this pseudo-class is :active or :hover.
     fn is_active_or_hover(&self) -> bool;
 }
 
 fn to_ascii_lowercase(s: &str) -> Cow<str> {
@@ -149,41 +150,57 @@ pub trait Parser<'i> {
 
     /// This function can return an "Err" pseudo-element in order to support CSS2.1
     /// pseudo-elements.
     fn parse_non_ts_pseudo_class(
         &self,
         location: SourceLocation,
         name: CowRcStr<'i>,
     ) -> Result<<Self::Impl as SelectorImpl>::NonTSPseudoClass, ParseError<'i, Self::Error>> {
-        Err(location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name)))
+        Err(
+            location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
+                name,
+            )),
+        )
     }
 
     fn parse_non_ts_functional_pseudo_class<'t>(
         &self,
         name: CowRcStr<'i>,
         arguments: &mut CssParser<'i, 't>,
     ) -> Result<<Self::Impl as SelectorImpl>::NonTSPseudoClass, ParseError<'i, Self::Error>> {
-        Err(arguments.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name)))
+        Err(
+            arguments.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
+                name,
+            )),
+        )
     }
 
     fn parse_pseudo_element(
         &self,
         location: SourceLocation,
         name: CowRcStr<'i>,
     ) -> Result<<Self::Impl as SelectorImpl>::PseudoElement, ParseError<'i, Self::Error>> {
-        Err(location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name)))
+        Err(
+            location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
+                name,
+            )),
+        )
     }
 
     fn parse_functional_pseudo_element<'t>(
         &self,
         name: CowRcStr<'i>,
         arguments: &mut CssParser<'i, 't>,
     ) -> Result<<Self::Impl as SelectorImpl>::PseudoElement, ParseError<'i, Self::Error>> {
-        Err(arguments.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name)))
+        Err(
+            arguments.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
+                name,
+            )),
+        )
     }
 
     fn default_namespace(&self) -> Option<<Self::Impl as SelectorImpl>::NamespaceUrl> {
         None
     }
 
     fn namespace_for_prefix(
         &self,
@@ -201,21 +218,23 @@ impl<Impl: SelectorImpl> SelectorList<Im
     /// <https://drafts.csswg.org/selectors/#grouping>
     ///
     /// Return the Selectors or Err if there is an invalid selector.
     pub fn parse<'i, 't, P>(
         parser: &P,
         input: &mut CssParser<'i, 't>,
     ) -> Result<Self, ParseError<'i, P::Error>>
     where
-        P: Parser<'i, Impl=Impl>,
+        P: Parser<'i, Impl = Impl>,
     {
         let mut values = SmallVec::new();
         loop {
-            values.push(input.parse_until_before(Delimiter::Comma, |input| parse_selector(parser, input))?);
+            values
+                .push(input
+                    .parse_until_before(Delimiter::Comma, |input| parse_selector(parser, input))?);
             match input.next() {
                 Err(_) => return Ok(SelectorList(values)),
                 Ok(&Token::Comma) => continue,
                 Ok(_) => unreachable!(),
             }
         }
     }
 
@@ -226,43 +245,41 @@ impl<Impl: SelectorImpl> SelectorList<Im
 }
 
 /// Parses one compound selector suitable for nested stuff like ::-moz-any, etc.
 fn parse_inner_compound_selector<'i, 't, P, Impl>(
     parser: &P,
     input: &mut CssParser<'i, 't>,
 ) -> Result<Selector<Impl>, ParseError<'i, P::Error>>
 where
-    P: Parser<'i, Impl=Impl>,
+    P: Parser<'i, Impl = Impl>,
     Impl: SelectorImpl,
 {
     let location = input.current_source_location();
     let selector = Selector::parse(parser, input)?;
     // Ensure they're actually all compound selectors.
     if selector.iter_raw_match_order().any(|s| s.is_combinator()) {
-        return Err(location.new_custom_error(
-            SelectorParseErrorKind::NonCompoundSelector
-        ))
+        return Err(location.new_custom_error(SelectorParseErrorKind::NonCompoundSelector));
     }
 
     Ok(selector)
 }
 
 /// Parse a comma separated list of compound selectors.
 pub fn parse_compound_selector_list<'i, 't, P, Impl>(
     parser: &P,
     input: &mut CssParser<'i, 't>,
 ) -> Result<Box<[Selector<Impl>]>, ParseError<'i, P::Error>>
 where
-    P: Parser<'i, Impl=Impl>,
+    P: Parser<'i, Impl = Impl>,
     Impl: SelectorImpl,
 {
-    input.parse_comma_separated(|input| {
-        parse_inner_compound_selector(parser, input)
-    }).map(|selectors| selectors.into_boxed_slice())
+    input
+        .parse_comma_separated(|input| parse_inner_compound_selector(parser, input))
+        .map(|selectors| selectors.into_boxed_slice())
 }
 
 /// Ancestor hashes for the bloom filter. We precompute these and store them
 /// inline with selectors to optimize cache performance during matching.
 /// This matters a lot.
 ///
 /// We use 4 hashes, which is copied from Gecko, who copied it from WebKit.
 /// Note that increasing the number of hashes here will adversely affect the
@@ -276,41 +293,36 @@ where
 /// complicated to assemble, because we often bail out before checking all the
 /// hashes.
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub struct AncestorHashes {
     pub packed_hashes: [u32; 3],
 }
 
 impl AncestorHashes {
-    pub fn new<Impl: SelectorImpl>(
-        selector: &Selector<Impl>,
-        quirks_mode: QuirksMode,
-    ) -> Self
-        where Impl::Identifier: PrecomputedHash,
-              Impl::ClassName: PrecomputedHash,
-              Impl::LocalName: PrecomputedHash,
-              Impl::NamespaceUrl: PrecomputedHash,
+    pub fn new<Impl: SelectorImpl>(selector: &Selector<Impl>, quirks_mode: QuirksMode) -> Self
+    where
+        Impl::Identifier: PrecomputedHash,
+        Impl::ClassName: PrecomputedHash,
+        Impl::LocalName: PrecomputedHash,
+        Impl::NamespaceUrl: PrecomputedHash,
     {
         Self::from_iter(selector.iter(), quirks_mode)
     }
 
-    fn from_iter<Impl: SelectorImpl>(
-        iter: SelectorIter<Impl>,
-        quirks_mode: QuirksMode,
-    ) -> Self
-        where Impl::Identifier: PrecomputedHash,
-              Impl::ClassName: PrecomputedHash,
-              Impl::LocalName: PrecomputedHash,
-              Impl::NamespaceUrl: PrecomputedHash,
+    fn from_iter<Impl: SelectorImpl>(iter: SelectorIter<Impl>, quirks_mode: QuirksMode) -> Self
+    where
+        Impl::Identifier: PrecomputedHash,
+        Impl::ClassName: PrecomputedHash,
+        Impl::LocalName: PrecomputedHash,
+        Impl::NamespaceUrl: PrecomputedHash,
     {
         // Compute ancestor hashes for the bloom filter.
         let mut hashes = [0u32; 4];
-        let mut hash_iter = AncestorIter::new(iter)
-                             .filter_map(|x| x.ancestor_hash(quirks_mode));
+        let mut hash_iter = AncestorIter::new(iter).filter_map(|x| x.ancestor_hash(quirks_mode));
         for i in 0..4 {
             hashes[i] = match hash_iter.next() {
                 Some(x) => x & BLOOM_HASH_MASK,
                 None => break,
             }
         }
 
         // Now, pack the fourth hash (if it exists) into the upper byte of each of
@@ -325,22 +337,25 @@ impl AncestorHashes {
         AncestorHashes {
             packed_hashes: [hashes[0], hashes[1], hashes[2]],
         }
     }
 
     /// Returns the fourth hash, reassembled from parts.
     pub fn fourth_hash(&self) -> u32 {
         ((self.packed_hashes[0] & 0xff000000) >> 24) |
-        ((self.packed_hashes[1] & 0xff000000) >> 16) |
-        ((self.packed_hashes[2] & 0xff000000) >> 8)
+            ((self.packed_hashes[1] & 0xff000000) >> 16) |
+            ((self.packed_hashes[2] & 0xff000000) >> 8)
     }
 }
 
-impl<Impl: SelectorImpl> Visit for Selector<Impl> where Impl::NonTSPseudoClass: Visit<Impl=Impl> {
+impl<Impl: SelectorImpl> Visit for Selector<Impl>
+where
+    Impl::NonTSPseudoClass: Visit<Impl = Impl>,
+{
     type Impl = Impl;
 
     fn visit<V>(&self, visitor: &mut V) -> bool
     where
         V: SelectorVisitor<Impl = Impl>,
     {
         let mut current = self.iter();
         let mut combinator = None;
@@ -362,17 +377,17 @@ impl<Impl: SelectorImpl> Visit for Selec
         }
 
         true
     }
 }
 
 impl<Impl: SelectorImpl> Visit for Component<Impl>
 where
-    Impl::NonTSPseudoClass: Visit<Impl=Impl>
+    Impl::NonTSPseudoClass: Visit<Impl = Impl>,
 {
     type Impl = Impl;
 
     fn visit<V>(&self, visitor: &mut V) -> bool
     where
         V: SelectorVisitor<Impl = Impl>,
     {
         use self::Component::*;
@@ -380,65 +395,73 @@ where
             return false;
         }
 
         match *self {
             Slotted(ref selector) => {
                 if !selector.visit(visitor) {
                     return false;
                 }
-            }
+            },
             Host(Some(ref selector)) => {
                 if !selector.visit(visitor) {
                     return false;
                 }
-            }
+            },
             Negation(ref negated) => {
                 for component in negated.iter() {
                     if !component.visit(visitor) {
                         return false;
                     }
                 }
-            }
+            },
 
-            AttributeInNoNamespaceExists { ref local_name, ref local_name_lower } => {
+            AttributeInNoNamespaceExists {
+                ref local_name,
+                ref local_name_lower,
+            } => {
                 if !visitor.visit_attribute_selector(
                     &NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()),
                     local_name,
                     local_name_lower,
                 ) {
                     return false;
                 }
-            }
-            AttributeInNoNamespace { ref local_name, ref local_name_lower, never_matches, .. }
-            if !never_matches => {
+            },
+            AttributeInNoNamespace {
+                ref local_name,
+                ref local_name_lower,
+                never_matches,
+                ..
+            } if !never_matches =>
+            {
                 if !visitor.visit_attribute_selector(
                     &NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()),
                     local_name,
                     local_name_lower,
                 ) {
                     return false;
                 }
-            }
+            },
             AttributeOther(ref attr_selector) if !attr_selector.never_matches => {
                 if !visitor.visit_attribute_selector(
                     &attr_selector.namespace(),
                     &attr_selector.local_name,
                     &attr_selector.local_name_lower,
                 ) {
                     return false;
                 }
-            }
+            },
 
             NonTSPseudoClass(ref pseudo_class) => {
                 if !pseudo_class.visit(visitor) {
                     return false;
                 }
             },
-            _ => {}
+            _ => {},
         }
 
         true
     }
 }
 
 pub fn namespace_empty_string<Impl: SelectorImpl>() -> Impl::NamespaceUrl {
     // Rust type’s default, not default namespace
@@ -476,40 +499,42 @@ impl<Impl: SelectorImpl> Selector<Impl> 
     #[inline]
     pub fn is_slotted(&self) -> bool {
         self.0.header.header.is_slotted()
     }
 
     #[inline]
     pub fn pseudo_element(&self) -> Option<&Impl::PseudoElement> {
         if !self.has_pseudo_element() {
-            return None
+            return None;
         }
 
         for component in self.iter() {
             if let Component::PseudoElement(ref pseudo) = *component {
-                return Some(pseudo)
+                return Some(pseudo);
             }
         }
 
         debug_assert!(false, "has_pseudo_element lied!");
         None
     }
 
     /// Whether this selector (pseudo-element part excluded) matches every element.
     ///
     /// Used for "pre-computed" pseudo-elements in components/style/stylist.rs
     #[inline]
     pub fn is_universal(&self) -> bool {
-        self.iter_raw_match_order().all(|c| matches!(*c,
-            Component::ExplicitUniversalType |
-            Component::ExplicitAnyNamespace |
-            Component::Combinator(Combinator::PseudoElement) |
-            Component::PseudoElement(..)
-        ))
+        self.iter_raw_match_order().all(|c| {
+            matches!(
+                *c,
+                Component::ExplicitUniversalType | Component::ExplicitAnyNamespace |
+                    Component::Combinator(Combinator::PseudoElement) |
+                    Component::PseudoElement(..)
+            )
+        })
     }
 
     /// Returns an iterator over this selector in matching order (right-to-left).
     /// When a combinator is reached, the iterator will return None, and
     /// next_sequence() may be called to continue to the next sequence.
     #[inline]
     pub fn iter(&self) -> SelectorIter<Impl> {
         SelectorIter {
@@ -537,40 +562,40 @@ impl<Impl: SelectorImpl> Selector<Impl> 
     }
 
     /// Returns the combinator at index `index` (zero-indexed from the right),
     /// or panics if the component is not a combinator.
     #[inline]
     pub fn combinator_at_match_order(&self, index: usize) -> Combinator {
         match self.0.slice[index] {
             Component::Combinator(c) => c,
-            ref other => {
-                panic!("Not a combinator: {:?}, {:?}, index: {}",
-                       other, self, index)
-            }
+            ref other => panic!(
+                "Not a combinator: {:?}, {:?}, index: {}",
+                other, self, index
+            ),
         }
     }
 
     /// Returns an iterator over the entire sequence of simple selectors and
     /// combinators, in matching order (from right to left).
     #[inline]
     pub fn iter_raw_match_order(&self) -> slice::Iter<Component<Impl>> {
         self.0.slice.iter()
     }
 
     /// Returns the combinator at index `index` (zero-indexed from the left),
     /// or panics if the component is not a combinator.
     #[inline]
     pub fn combinator_at_parse_order(&self, index: usize) -> Combinator {
         match self.0.slice[self.len() - index - 1] {
             Component::Combinator(c) => c,
-            ref other => {
-                panic!("Not a combinator: {:?}, {:?}, index: {}",
-                       other, self, index)
-            }
+            ref other => panic!(
+                "Not a combinator: {:?}, {:?}, index: {}",
+                other, self, index
+            ),
         }
     }
 
     /// Returns an iterator over the sequence of simple selectors and
     /// combinators, in parse order (from left to right), starting from
     /// `offset`.
     #[inline]
     pub fn iter_raw_parse_order_from(&self, offset: usize) -> Rev<slice::Iter<Component<Impl>>> {
@@ -617,33 +642,35 @@ impl<'a, Impl: 'a + SelectorImpl> Select
         self.next_combinator.take()
     }
 
     /// Whether this selector is a featureless host selector, with no
     /// combinators to the left.
     #[inline]
     pub(crate) fn is_featureless_host_selector(&mut self) -> bool {
         self.all(|component| matches!(*component, Component::Host(..))) &&
-        self.next_sequence().is_none()
+            self.next_sequence().is_none()
     }
 
     /// Returns remaining count of the simple selectors and combinators in the Selector.
     #[inline]
     pub fn selector_length(&self) -> usize {
         self.iter.len()
     }
 }
 
 impl<'a, Impl: SelectorImpl> Iterator for SelectorIter<'a, Impl> {
     type Item = &'a Component<Impl>;
 
     #[inline]
     fn next(&mut self) -> Option<Self::Item> {
-        debug_assert!(self.next_combinator.is_none(),
-                      "You should call next_sequence!");
+        debug_assert!(
+            self.next_combinator.is_none(),
+            "You should call next_sequence!"
+        );
         match *self.iter.next()? {
             Component::Combinator(c) => {
                 self.next_combinator = Some(c);
                 None
             },
             ref x => Some(x),
         }
     }
@@ -673,17 +700,19 @@ impl<'a, Impl: 'a + SelectorImpl> Ancest
     /// Skips a sequence of simple selectors and all subsequent sequences until
     /// a non-pseudo-element ancestor combinator is reached.
     fn skip_until_ancestor(&mut self) {
         loop {
             while self.0.next().is_some() {}
             // If this is ever changed to stop at the "pseudo-element"
             // combinator, we will need to fix the way we compute hashes for
             // revalidation selectors.
-            if self.0.next_sequence().map_or(true, |x| matches!(x, Combinator::Child | Combinator::Descendant)) {
+            if self.0.next_sequence().map_or(true, |x| {
+                matches!(x, Combinator::Child | Combinator::Descendant)
+            }) {
                 break;
             }
         }
     }
 }
 
 impl<'a, Impl: SelectorImpl> Iterator for AncestorIter<'a, Impl> {
     type Item = &'a Component<Impl>;
@@ -702,41 +731,41 @@ impl<'a, Impl: SelectorImpl> Iterator fo
         }
 
         self.0.next()
     }
 }
 
 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
 pub enum Combinator {
-    Child,  //  >
-    Descendant,  // space
+    Child,        //  >
+    Descendant,   // space
     NextSibling,  // +
-    LaterSibling,  // ~
+    LaterSibling, // ~
     /// A dummy combinator we use to the left of pseudo-elements.
     ///
     /// It serializes as the empty string, and acts effectively as a child
     /// combinator in most cases.  If we ever actually start using a child
     /// combinator for this, we will need to fix up the way hashes are computed
     /// for revalidation selectors.
     PseudoElement,
     /// Another combinator used for ::slotted(), which represent the jump from
     /// a node to its assigned slot.
     SlotAssignment,
 }
 
 impl Combinator {
     /// Returns true if this combinator is a child or descendant combinator.
     #[inline]
     pub fn is_ancestor(&self) -> bool {
-        matches!(*self,
-                 Combinator::Child |
-                 Combinator::Descendant |
-                 Combinator::PseudoElement |
-                 Combinator::SlotAssignment)
+        matches!(
+            *self,
+            Combinator::Child | Combinator::Descendant | Combinator::PseudoElement |
+                Combinator::SlotAssignment
+        )
     }
 
     /// Returns true if this combinator is a pseudo-element combinator.
     #[inline]
     pub fn is_pseudo_element(&self) -> bool {
         matches!(*self, Combinator::PseudoElement)
     }
 
@@ -787,17 +816,19 @@ pub enum Component<Impl: SelectorImpl> {
     /// treat it as a compound selector because it might be a type selector
     /// which we represent as a namespace and a localname.
     ///
     /// Note: if/when we upgrade this to CSS4, which supports combinators, we
     /// need to think about how this should interact with
     /// visit_complex_selector, and what the consumers of those APIs should do
     /// about the presence of combinators in negation.
     Negation(Box<[Component<Impl>]>),
-    FirstChild, LastChild, OnlyChild,
+    FirstChild,
+    LastChild,
+    OnlyChild,
     Root,
     Empty,
     Scope,
     NthChild(i32, i32),
     NthLastChild(i32, i32),
     NthOfType(i32, i32),
     NthLastOfType(i32, i32),
     FirstOfType,
@@ -828,34 +859,37 @@ pub enum Component<Impl: SelectorImpl> {
     /// See https://github.com/w3c/csswg-drafts/issues/2158
     Host(Option<Selector<Impl>>),
     PseudoElement(Impl::PseudoElement),
 }
 
 impl<Impl: SelectorImpl> Component<Impl> {
     /// Compute the ancestor hash to check against the bloom filter.
     fn ancestor_hash(&self, quirks_mode: QuirksMode) -> Option<u32>
-        where Impl::Identifier: PrecomputedHash,
-              Impl::ClassName: PrecomputedHash,
-              Impl::LocalName: PrecomputedHash,
-              Impl::NamespaceUrl: PrecomputedHash,
+    where
+        Impl::Identifier: PrecomputedHash,
+        Impl::ClassName: PrecomputedHash,
+        Impl::LocalName: PrecomputedHash,
+        Impl::NamespaceUrl: PrecomputedHash,
     {
         match *self {
-            Component::LocalName(LocalName { ref name, ref lower_name }) => {
+            Component::LocalName(LocalName {
+                ref name,
+                ref lower_name,
+            }) => {
                 // Only insert the local-name into the filter if it's all
                 // lowercase.  Otherwise we would need to test both hashes, and
                 // our data structures aren't really set up for that.
                 if name == lower_name {
                     Some(name.precomputed_hash())
                 } else {
                     None
                 }
             },
-            Component::DefaultNamespace(ref url) |
-            Component::Namespace(_, ref url) => {
+            Component::DefaultNamespace(ref url) | Component::Namespace(_, ref url) => {
                 Some(url.precomputed_hash())
             },
             // In quirks mode, class and id selectors should match
             // case-insensitively, so just avoid inserting them into the filter.
             Component::ID(ref id) if quirks_mode != QuirksMode::Quirks => {
                 Some(id.precomputed_hash())
             },
             Component::Class(ref class) if quirks_mode != QuirksMode::Quirks => {
@@ -889,55 +923,73 @@ impl<Impl: SelectorImpl> Debug for Selec
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.write_str("Selector(")?;
         self.to_css(f)?;
         write!(f, ", specificity = 0x{:x})", self.specificity())
     }
 }
 
 impl<Impl: SelectorImpl> Debug for Component<Impl> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.to_css(f) }
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.to_css(f)
+    }
 }
 impl<Impl: SelectorImpl> Debug for AttrSelectorWithNamespace<Impl> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.to_css(f) }
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.to_css(f)
+    }
 }
 impl<Impl: SelectorImpl> Debug for LocalName<Impl> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.to_css(f) }
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.to_css(f)
+    }
 }
 
 impl<Impl: SelectorImpl> ToCss for SelectorList<Impl> {
-    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
+    where
+        W: fmt::Write,
+    {
         let mut iter = self.0.iter();
         let first = iter.next()
             .expect("Empty SelectorList, should contain at least one selector");
         first.to_css(dest)?;
         for selector in iter {
             dest.write_str(", ")?;
             selector.to_css(dest)?;
         }
         Ok(())
     }
 }
 
 impl<Impl: SelectorImpl> ToCss for Selector<Impl> {
-    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
+    where
+        W: fmt::Write,
+    {
         // Compound selectors invert the order of their contents, so we need to
         // undo that during serialization.
         //
         // This two-iterator strategy involves walking over the selector twice.
         // We could do something more clever, but selector serialization probably
         // isn't hot enough to justify it, and the stringification likely
         // dominates anyway.
         //
         // NB: A parse-order iterator is a Rev<>, which doesn't expose as_slice(),
         // which we need for |split|. So we split by combinators on a match-order
         // sequence and then reverse.
 
-        let mut combinators = self.iter_raw_match_order().rev().filter(|x| x.is_combinator()).peekable();
-        let compound_selectors = self.iter_raw_match_order().as_slice().split(|x| x.is_combinator()).rev();
+        let mut combinators = self.iter_raw_match_order()
+            .rev()
+            .filter(|x| x.is_combinator())
+            .peekable();
+        let compound_selectors = self.iter_raw_match_order()
+            .as_slice()
+            .split(|x| x.is_combinator())
+            .rev();
 
         let mut combinators_exhausted = false;
         for compound in compound_selectors {
             debug_assert!(!combinators_exhausted);
 
             // https://drafts.csswg.org/cssom/#serializing-selectors
 
             if !compound.is_empty() {
@@ -973,17 +1025,17 @@ impl<Impl: SelectorImpl> ToCss for Selec
                         (_, &Component::ExplicitUniversalType) => {
                             // Iterate over everything so we serialize the namespace
                             // too.
                             for simple in compound.iter() {
                                 simple.to_css(dest)?;
                             }
                             // Skip step 2, which is an "otherwise".
                             perform_step_2 = false;
-                        }
+                        },
                         (_, _) => (),
                     }
                 }
 
                 // 2. Otherwise, for each simple selector in the compound selectors
                 //    that is not a universal selector of which the namespace prefix
                 //    maps to a namespace that is not the default namespace
                 //    serialize the simple selector and append the result to s.
@@ -995,17 +1047,17 @@ impl<Impl: SelectorImpl> ToCss for Selec
                 if perform_step_2 {
                     for simple in compound.iter() {
                         if let Component::ExplicitUniversalType = *simple {
                             // Can't have a namespace followed by a pseudo-element
                             // selector followed by a universal selector in the same
                             // compound selector, so we don't have to worry about the
                             // real namespace being in a different `compound`.
                             if can_elide_namespace {
-                                continue
+                                continue;
                             }
                         }
                         simple.to_css(dest)?;
                     }
                 }
             }
 
             // 3. If this is not the last part of the chain of the selector
@@ -1020,114 +1072,125 @@ impl<Impl: SelectorImpl> ToCss for Selec
 
             // 4. If this is the last part of the chain of the selector and
             //    there is a pseudo-element, append "::" followed by the name of
             //    the pseudo-element, to s.
             //
             // (we handle this above)
         }
 
-       Ok(())
+        Ok(())
     }
 }
 
 impl ToCss for Combinator {
-    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
+    where
+        W: fmt::Write,
+    {
         match *self {
             Combinator::Child => dest.write_str(" > "),
             Combinator::Descendant => dest.write_str(" "),
             Combinator::NextSibling => dest.write_str(" + "),
             Combinator::LaterSibling => dest.write_str(" ~ "),
             Combinator::PseudoElement => Ok(()),
             Combinator::SlotAssignment => Ok(()),
         }
     }
 }
 
 impl<Impl: SelectorImpl> ToCss for Component<Impl> {
-    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
+    where
+        W: fmt::Write,
+    {
         use self::Component::*;
 
         /// Serialize <an+b> values (part of the CSS Syntax spec, but currently only used here).
         /// <https://drafts.csswg.org/css-syntax-3/#serialize-an-anb-value>
-        fn write_affine<W>(dest: &mut W, a: i32, b: i32) -> fmt::Result where W: fmt::Write {
+        fn write_affine<W>(dest: &mut W, a: i32, b: i32) -> fmt::Result
+        where
+            W: fmt::Write,
+        {
             match (a, b) {
                 (0, 0) => dest.write_char('0'),
 
                 (1, 0) => dest.write_char('n'),
                 (-1, 0) => dest.write_str("-n"),
                 (_, 0) => write!(dest, "{}n", a),
 
                 (0, _) => write!(dest, "{}", b),
                 (1, _) => write!(dest, "n{:+}", b),
                 (-1, _) => write!(dest, "-n{:+}", b),
                 (_, _) => write!(dest, "{}n{:+}", a, b),
             }
         }
 
         match *self {
-            Combinator(ref c) => {
-                c.to_css(dest)
-            }
+            Combinator(ref c) => c.to_css(dest),
             Slotted(ref selector) => {
                 dest.write_str("::slotted(")?;
                 selector.to_css(dest)?;
                 dest.write_char(')')
-            }
-            PseudoElement(ref p) => {
-                p.to_css(dest)
-            }
+            },
+            PseudoElement(ref p) => p.to_css(dest),
             ID(ref s) => {
                 dest.write_char('#')?;
                 display_to_css_identifier(s, dest)
-            }
+            },
             Class(ref s) => {
                 dest.write_char('.')?;
                 display_to_css_identifier(s, dest)
-            }
+            },
             LocalName(ref s) => s.to_css(dest),
             ExplicitUniversalType => dest.write_char('*'),
 
             DefaultNamespace(_) => Ok(()),
             ExplicitNoNamespace => dest.write_char('|'),
             ExplicitAnyNamespace => dest.write_str("*|"),
             Namespace(ref prefix, _) => {
                 display_to_css_identifier(prefix, dest)?;
                 dest.write_char('|')
-            }
+            },
 
             AttributeInNoNamespaceExists { ref local_name, .. } => {
                 dest.write_char('[')?;
                 display_to_css_identifier(local_name, dest)?;
                 dest.write_char(']')
-            }
-            AttributeInNoNamespace { ref local_name, operator, ref value, case_sensitivity, .. } => {
+            },
+            AttributeInNoNamespace {
+                ref local_name,
+                operator,
+                ref value,
+                case_sensitivity,
+                ..
+            } => {
                 dest.write_char('[')?;
                 display_to_css_identifier(local_name, dest)?;
                 operator.to_css(dest)?;
                 dest.write_char('"')?;
                 write!(CssStringWriter::new(dest), "{}", value)?;
                 dest.write_char('"')?;
                 match case_sensitivity {
                     ParsedCaseSensitivity::CaseSensitive |
                     ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {},
                     ParsedCaseSensitivity::AsciiCaseInsensitive => dest.write_str(" i")?,
                 }
                 dest.write_char(']')
-            }
+            },
             AttributeOther(ref attr_selector) => attr_selector.to_css(dest),
 
             // Pseudo-classes
             Negation(ref arg) => {
                 dest.write_str(":not(")?;
                 for component in arg.iter() {
                     component.to_css(dest)?;
                 }
                 dest.write_str(")")
-            }
+            },
 
             FirstChild => dest.write_str(":first-child"),
             LastChild => dest.write_str(":last-child"),
             OnlyChild => dest.write_str(":only-child"),
             Root => dest.write_str(":root"),
             Empty => dest.write_str(":empty"),
             Scope => dest.write_str(":scope"),
             Host(ref selector) => {
@@ -1147,39 +1210,42 @@ impl<Impl: SelectorImpl> ToCss for Compo
                     NthChild(_, _) => dest.write_str(":nth-child(")?,
                     NthLastChild(_, _) => dest.write_str(":nth-last-child(")?,
                     NthOfType(_, _) => dest.write_str(":nth-of-type(")?,
                     NthLastOfType(_, _) => dest.write_str(":nth-last-of-type(")?,
                     _ => unreachable!(),
                 }
                 write_affine(dest, a, b)?;
                 dest.write_char(')')
-            }
+            },
             NonTSPseudoClass(ref pseudo) => pseudo.to_css(dest),
         }
     }
 }
 
 impl<Impl: SelectorImpl> ToCss for AttrSelectorWithNamespace<Impl> {
-    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
+    where
+        W: fmt::Write,
+    {
         dest.write_char('[')?;
         match self.namespace {
             NamespaceConstraint::Specific((ref prefix, _)) => {
                 display_to_css_identifier(prefix, dest)?;
                 dest.write_char('|')?
-            }
-            NamespaceConstraint::Any => {
-                dest.write_str("*|")?
-            }
+            },
+            NamespaceConstraint::Any => dest.write_str("*|")?,
         }
         display_to_css_identifier(&self.local_name, dest)?;
         match self.operation {
             ParsedAttrSelectorOperation::Exists => {},
             ParsedAttrSelectorOperation::WithValue {
-                operator, case_sensitivity, ref expected_value
+                operator,
+                case_sensitivity,
+                ref expected_value,
             } => {
                 operator.to_css(dest)?;
                 dest.write_char('"')?;
                 write!(CssStringWriter::new(dest), "{}", expected_value)?;
                 dest.write_char('"')?;
                 match case_sensitivity {
                     ParsedCaseSensitivity::CaseSensitive |
                     ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {},
@@ -1187,17 +1253,20 @@ impl<Impl: SelectorImpl> ToCss for AttrS
                 }
             },
         }
         dest.write_char(']')
     }
 }
 
 impl<Impl: SelectorImpl> ToCss for LocalName<Impl> {
-    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
+    where
+        W: fmt::Write,
+    {
         display_to_css_identifier(&self.name, dest)
     }
 }
 
 /// Serialize the output of Display as a CSS identifier
 fn display_to_css_identifier<T: Display, W: fmt::Write>(x: &T, dest: &mut W) -> fmt::Result {
     // FIXME(SimonSapin): it is possible to avoid this heap allocation
     // by creating a stream adapter like cssparser::CssStringWriter
@@ -1220,181 +1289,181 @@ fn display_to_css_identifier<T: Display,
 /// selector : simple_selector_sequence [ combinator simple_selector_sequence ]* ;
 ///
 /// `Err` means invalid selector.
 fn parse_selector<'i, 't, P, Impl>(
     parser: &P,
     input: &mut CssParser<'i, 't>,
 ) -> Result<Selector<Impl>, ParseError<'i, P::Error>>
 where
-    P: Parser<'i, Impl=Impl>,
+    P: Parser<'i, Impl = Impl>,
     Impl: SelectorImpl,
 {
     let mut builder = SelectorBuilder::default();
 
     let mut has_pseudo_element;
     let mut slotted;
     'outer_loop: loop {
         // Parse a sequence of simple selectors.
         match parse_compound_selector(parser, input, &mut builder)? {
             Some((has_pseudo, slot)) => {
                 has_pseudo_element = has_pseudo;
                 slotted = slot;
-            }
+            },
             None => {
                 return Err(input.new_custom_error(if builder.has_combinators() {
                     SelectorParseErrorKind::DanglingCombinator
                 } else {
                     SelectorParseErrorKind::EmptySelector
                 }))
-            }
+            },
         };
 
         if has_pseudo_element || slotted {
             break;
         }
 
         // Parse a combinator.
         let combinator;
         let mut any_whitespace = false;
         loop {
             let before_this_token = input.state();
             match input.next_including_whitespace() {
                 Err(_e) => break 'outer_loop,
                 Ok(&Token::WhiteSpace(_)) => any_whitespace = true,
                 Ok(&Token::Delim('>')) => {
                     combinator = Combinator::Child;
-                    break
-                }
+                    break;
+                },
                 Ok(&Token::Delim('+')) => {
                     combinator = Combinator::NextSibling;
-                    break
-                }
+                    break;
+                },
                 Ok(&Token::Delim('~')) => {
                     combinator = Combinator::LaterSibling;
-                    break
-                }
+                    break;
+                },
                 Ok(_) => {
                     input.reset(&before_this_token);
                     if any_whitespace {
                         combinator = Combinator::Descendant;
-                        break
+                        break;
                     } else {
-                        break 'outer_loop
+                        break 'outer_loop;
                     }
-                }
+                },
             }
         }
         builder.push_combinator(combinator);
     }
 
     Ok(Selector(builder.build(has_pseudo_element, slotted)))
 }
 
 impl<Impl: SelectorImpl> Selector<Impl> {
     /// Parse a selector, without any pseudo-element.
     pub fn parse<'i, 't, P>(
         parser: &P,
         input: &mut CssParser<'i, 't>,
     ) -> Result<Self, ParseError<'i, P::Error>>
     where
-        P: Parser<'i, Impl=Impl>
+        P: Parser<'i, Impl = Impl>,
     {
         let selector = parse_selector(parser, input)?;
         if selector.has_pseudo_element() {
-            return Err(input.new_custom_error(SelectorParseErrorKind::PseudoElementInComplexSelector))
+            let e = SelectorParseErrorKind::PseudoElementInComplexSelector;
+            return Err(input.new_custom_error(e));
         }
         Ok(selector)
     }
 }
 
 /// * `Err(())`: Invalid selector, abort
 /// * `Ok(false)`: Not a type selector, could be something else. `input` was not consumed.
 /// * `Ok(true)`: Length 0 (`*|*`), 1 (`*|E` or `ns|*`) or 2 (`|E` or `ns|E`)
 fn parse_type_selector<'i, 't, P, Impl, S>(
     parser: &P,
     input: &mut CssParser<'i, 't>,
     sink: &mut S,
 ) -> Result<bool, ParseError<'i, P::Error>>
 where
-    P: Parser<'i, Impl=Impl>,
+    P: Parser<'i, Impl = Impl>,
     Impl: SelectorImpl,
     S: Push<Component<Impl>>,
 {
     match parse_qualified_name(parser, input, /* in_attr_selector = */ false) {
-        Err(ParseError { kind: ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput), .. }) |
+        Err(ParseError {
+            kind: ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput),
+            ..
+        }) |
         Ok(OptionalQName::None(_)) => Ok(false),
         Ok(OptionalQName::Some(namespace, local_name)) => {
             match namespace {
-                QNamePrefix::ImplicitAnyNamespace => {}
+                QNamePrefix::ImplicitAnyNamespace => {},
                 QNamePrefix::ImplicitDefaultNamespace(url) => {
                     sink.push(Component::DefaultNamespace(url))
-                }
+                },
                 QNamePrefix::ExplicitNamespace(prefix, url) => {
                     sink.push(match parser.default_namespace() {
-                        Some(ref default_url) if url == *default_url => Component::DefaultNamespace(url),
+                        Some(ref default_url) if url == *default_url => {
+                            Component::DefaultNamespace(url)
+                        },
                         _ => Component::Namespace(prefix, url),
                     })
-                }
-                QNamePrefix::ExplicitNoNamespace => {
-                    sink.push(Component::ExplicitNoNamespace)
-                }
+                },
+                QNamePrefix::ExplicitNoNamespace => sink.push(Component::ExplicitNoNamespace),
                 QNamePrefix::ExplicitAnyNamespace => {
                     match parser.default_namespace() {
                         // Element type selectors that have no namespace
                         // component (no namespace separator) represent elements
                         // without regard to the element's namespace (equivalent
                         // to "*|") unless a default namespace has been declared
                         // for namespaced selectors (e.g. in CSS, in the style
                         // sheet). If a default namespace has been declared,
                         // such selectors will represent only elements in the
                         // default namespace.
                         // -- Selectors § 6.1.1
                         // So we'll have this act the same as the
                         // QNamePrefix::ImplicitAnyNamespace case.
                         None => {},
                         Some(_) => sink.push(Component::ExplicitAnyNamespace),
                     }
-                }
+                },
                 QNamePrefix::ImplicitNoNamespace => {
-                    unreachable!()  // Not returned with in_attr_selector = false
-                }
+                    unreachable!() // Not returned with in_attr_selector = false
+                },
             }
             match local_name {
-                Some(name) => {
-                    sink.push(Component::LocalName(LocalName {
-                        lower_name: to_ascii_lowercase(&name).as_ref().into(),
-                        name: name.as_ref().into(),
-                    }))
-                }
-                None => {
-                    sink.push(Component::ExplicitUniversalType)
-                }
+                Some(name) => sink.push(Component::LocalName(LocalName {
+                    lower_name: to_ascii_lowercase(&name).as_ref().into(),
+                    name: name.as_ref().into(),
+                })),
+                None => sink.push(Component::ExplicitUniversalType),
             }
             Ok(true)
-        }
-        Err(e) => Err(e)
+        },
+        Err(e) => Err(e),
     }
 }
 
 #[derive(Debug)]
 enum SimpleSelectorParseResult<Impl: SelectorImpl> {
     SimpleSelector(Component<Impl>),
     PseudoElement(Impl::PseudoElement),
     SlottedPseudo(Selector<Impl>),
 }
 
 #[derive(Debug)]
 enum QNamePrefix<Impl: SelectorImpl> {
-    ImplicitNoNamespace, // `foo` in attr selectors
-    ImplicitAnyNamespace, // `foo` in type selectors, without a default ns
-    ImplicitDefaultNamespace(Impl::NamespaceUrl),  // `foo` in type selectors, with a default ns
-    ExplicitNoNamespace,  // `|foo`
-    ExplicitAnyNamespace,  // `*|foo`
-    ExplicitNamespace(Impl::NamespacePrefix, Impl::NamespaceUrl),  // `prefix|foo`
+    ImplicitNoNamespace,                          // `foo` in attr selectors
+    ImplicitAnyNamespace,                         // `foo` in type selectors, without a default ns
+    ImplicitDefaultNamespace(Impl::NamespaceUrl), // `foo` in type selectors, with a default ns
+    ExplicitNoNamespace,                          // `|foo`
+    ExplicitAnyNamespace,                         // `*|foo`
+    ExplicitNamespace(Impl::NamespacePrefix, Impl::NamespaceUrl), // `prefix|foo`
 }
 
 enum OptionalQName<'i, Impl: SelectorImpl> {
     Some(QNamePrefix<Impl>, Option<CowRcStr<'i>>),
     None(Token<'i>),
 }
 
 /// * `Err(())`: Invalid selector, abort
@@ -1402,305 +1471,304 @@ enum OptionalQName<'i, Impl: SelectorImp
 ///                      but the token is still returned.
 /// * `Ok(Some(namespace, local_name))`: `None` for the local name means a `*` universal selector
 fn parse_qualified_name<'i, 't, P, Impl>(
     parser: &P,
     input: &mut CssParser<'i, 't>,
     in_attr_selector: bool,
 ) -> Result<OptionalQName<'i, Impl>, ParseError<'i, P::Error>>
 where
-    P: Parser<'i, Impl=Impl>,
+    P: Parser<'i, Impl = Impl>,
     Impl: SelectorImpl,
 {
     let default_namespace = |local_name| {
         let namespace = match parser.default_namespace() {
             Some(url) => QNamePrefix::ImplicitDefaultNamespace(url),
             None => QNamePrefix::ImplicitAnyNamespace,
         };
         Ok(OptionalQName::Some(namespace, local_name))
     };
 
     let explicit_namespace = |input: &mut CssParser<'i, 't>, namespace| {
         let location = input.current_source_location();
         match input.next_including_whitespace() {
-            Ok(&Token::Delim('*')) if !in_attr_selector => {
-                Ok(OptionalQName::Some(namespace, None))
-            }
+            Ok(&Token::Delim('*')) if !in_attr_selector => Ok(OptionalQName::Some(namespace, None)),
             Ok(&Token::Ident(ref local_name)) => {
                 Ok(OptionalQName::Some(namespace, Some(local_name.clone())))
-            }
+            },
             Ok(t) if in_attr_selector => {
-                Err(location.new_custom_error(
-                    SelectorParseErrorKind::InvalidQualNameInAttr(t.clone())
-                ))
-            }
-            Ok(t) => {
-                Err(location.new_custom_error(
-                    SelectorParseErrorKind::ExplicitNamespaceUnexpectedToken(t.clone())
-                ))
-            }
+                let e = SelectorParseErrorKind::InvalidQualNameInAttr(t.clone());
+                Err(location.new_custom_error(e))
+            },
+            Ok(t) => Err(location.new_custom_error(
+                SelectorParseErrorKind::ExplicitNamespaceUnexpectedToken(t.clone()),
+            )),
             Err(e) => Err(e.into()),
         }
     };
 
     let start = input.state();
     // FIXME: remove clone() when lifetimes are non-lexical
     match input.next_including_whitespace().map(|t| t.clone()) {
         Ok(Token::Ident(value)) => {
             let after_ident = input.state();
             match input.next_including_whitespace() {
                 Ok(&Token::Delim('|')) => {
                     let prefix = value.as_ref().into();
                     let result = parser.namespace_for_prefix(&prefix);
-                    let url = result.ok_or(after_ident.source_location().new_custom_error(
-                        SelectorParseErrorKind::ExpectedNamespace(value)))?;
+                    let url = result.ok_or(
+                        after_ident
+                            .source_location()
+                            .new_custom_error(SelectorParseErrorKind::ExpectedNamespace(value)),
+                    )?;
                     explicit_namespace(input, QNamePrefix::ExplicitNamespace(prefix, url))
                 },
                 _ => {
                     input.reset(&after_ident);
                     if in_attr_selector {
-                        Ok(OptionalQName::Some(QNamePrefix::ImplicitNoNamespace, Some(value)))
+                        Ok(OptionalQName::Some(
+                            QNamePrefix::ImplicitNoNamespace,
+                            Some(value),
+                        ))
                     } else {
                         default_namespace(Some(value))
                     }
-                }
+                },
             }
         },
         Ok(Token::Delim('*')) => {
             let after_star = input.state();
             // FIXME: remove clone() when lifetimes are non-lexical
             match input.next_including_whitespace().map(|t| t.clone()) {
                 Ok(Token::Delim('|')) => {
                     explicit_namespace(input, QNamePrefix::ExplicitAnyNamespace)
-                }
+                },
                 result => {
                     input.reset(&after_star);
                     if in_attr_selector {
                         match result {
-                            Ok(t) => Err(after_star.source_location().new_custom_error(
-                                SelectorParseErrorKind::ExpectedBarInAttr(t)
-                            )),
+                            Ok(t) => Err(after_star
+                                .source_location()
+                                .new_custom_error(SelectorParseErrorKind::ExpectedBarInAttr(t))),
                             Err(e) => Err(e.into()),
                         }
                     } else {
                         default_namespace(None)
                     }
                 },
             }
         },
-        Ok(Token::Delim('|')) => {
-            explicit_namespace(input, QNamePrefix::ExplicitNoNamespace)
-        }
+        Ok(Token::Delim('|')) => explicit_namespace(input, QNamePrefix::ExplicitNoNamespace),
         Ok(t) => {
             input.reset(&start);
             Ok(OptionalQName::None(t))
-        }
+        },
         Err(e) => {
             input.reset(&start);
             Err(e.into())
-        }
+        },
     }
 }
 
 fn parse_attribute_selector<'i, 't, P, Impl>(
     parser: &P,
     input: &mut CssParser<'i, 't>,
 ) -> Result<Component<Impl>, ParseError<'i, P::Error>>
 where
-    P: Parser<'i, Impl=Impl>,
+    P: Parser<'i, Impl = Impl>,
     Impl: SelectorImpl,
 {
     let namespace;
     let local_name;
 
     input.skip_whitespace();
 
     match parse_qualified_name(parser, input, /* in_attr_selector = */ true)? {
         OptionalQName::None(t) => {
             return Err(input.new_custom_error(
-                SelectorParseErrorKind::NoQualifiedNameInAttributeSelector(t)
+                SelectorParseErrorKind::NoQualifiedNameInAttributeSelector(t),
             ))
-        }
+        },
         OptionalQName::Some(_, None) => unreachable!(),
         OptionalQName::Some(ns, Some(ln)) => {
             local_name = ln;
             namespace = match ns {
-                QNamePrefix::ImplicitNoNamespace |
-                QNamePrefix::ExplicitNoNamespace => {
-                    None
-                }
+                QNamePrefix::ImplicitNoNamespace | QNamePrefix::ExplicitNoNamespace => None,
                 QNamePrefix::ExplicitNamespace(prefix, url) => {
                     Some(NamespaceConstraint::Specific((prefix, url)))
-                }
-                QNamePrefix::ExplicitAnyNamespace => {
-                    Some(NamespaceConstraint::Any)
-                }
-                QNamePrefix::ImplicitAnyNamespace |
-                QNamePrefix::ImplicitDefaultNamespace(_) => {
-                    unreachable!()  // Not returned with in_attr_selector = true
-                }
+                },
+                QNamePrefix::ExplicitAnyNamespace => Some(NamespaceConstraint::Any),
+                QNamePrefix::ImplicitAnyNamespace | QNamePrefix::ImplicitDefaultNamespace(_) => {
+                    unreachable!() // Not returned with in_attr_selector = true
+                },
             }
-        }
+        },
     }
 
     let location = input.current_source_location();
     let operator = match input.next() {
         // [foo]
         Err(_) => {
             let local_name_lower = to_ascii_lowercase(&local_name).as_ref().into();
             let local_name = local_name.as_ref().into();
             if let Some(namespace) = namespace {
-                return Ok(Component::AttributeOther(Box::new(AttrSelectorWithNamespace {
-                    namespace: namespace,
-                    local_name: local_name,
-                    local_name_lower: local_name_lower,
-                    operation: ParsedAttrSelectorOperation::Exists,
-                    never_matches: false,
-                })))
+                return Ok(Component::AttributeOther(Box::new(
+                    AttrSelectorWithNamespace {
+                        namespace: namespace,
+                        local_name: local_name,
+                        local_name_lower: local_name_lower,
+                        operation: ParsedAttrSelectorOperation::Exists,
+                        never_matches: false,
+                    },
+                )));
             } else {
                 return Ok(Component::AttributeInNoNamespaceExists {
                     local_name: local_name,
                     local_name_lower: local_name_lower,
-                })
+                });
             }
-        }
+        },
 
         // [foo=bar]
         Ok(&Token::Delim('=')) => AttrSelectorOperator::Equal,
         // [foo~=bar]
         Ok(&Token::IncludeMatch) => AttrSelectorOperator::Includes,
         // [foo|=bar]
         Ok(&Token::DashMatch) => AttrSelectorOperator::DashMatch,
         // [foo^=bar]
         Ok(&Token::PrefixMatch) => AttrSelectorOperator::Prefix,
         // [foo*=bar]
         Ok(&Token::SubstringMatch) => AttrSelectorOperator::Substring,
         // [foo$=bar]
         Ok(&Token::SuffixMatch) => AttrSelectorOperator::Suffix,
-        Ok(t) => return Err(location.new_custom_error(
-            SelectorParseErrorKind::UnexpectedTokenInAttributeSelector(t.clone())
-        ))
+        Ok(t) => {
+            return Err(location.new_custom_error(
+                SelectorParseErrorKind::UnexpectedTokenInAttributeSelector(t.clone()),
+            ))
+        },
     };
 
     let value = match input.expect_ident_or_string() {
         Ok(t) => t.clone(),
-        Err(BasicParseError { kind: BasicParseErrorKind::UnexpectedToken(t), location }) => {
-            return Err(location.new_custom_error(SelectorParseErrorKind::BadValueInAttr(t)))
-        }
+        Err(BasicParseError {
+            kind: BasicParseErrorKind::UnexpectedToken(t),
+            location,
+        }) => return Err(location.new_custom_error(SelectorParseErrorKind::BadValueInAttr(t))),
         Err(e) => return Err(e.into()),
     };
     let never_matches = match operator {
-        AttrSelectorOperator::Equal |
-        AttrSelectorOperator::DashMatch => false,
+        AttrSelectorOperator::Equal | AttrSelectorOperator::DashMatch => false,
 
-        AttrSelectorOperator::Includes => {
-            value.is_empty() || value.contains(SELECTOR_WHITESPACE)
-        }
+        AttrSelectorOperator::Includes => value.is_empty() || value.contains(SELECTOR_WHITESPACE),
 
         AttrSelectorOperator::Prefix |
         AttrSelectorOperator::Substring |
-        AttrSelectorOperator::Suffix => value.is_empty()
+        AttrSelectorOperator::Suffix => value.is_empty(),
     };
 
     let mut case_sensitivity = parse_attribute_flags(input)?;
 
     let value = value.as_ref().into();
     let local_name_lower;
     {
         let local_name_lower_cow = to_ascii_lowercase(&local_name);
         if let ParsedCaseSensitivity::CaseSensitive = case_sensitivity {
             if namespace.is_none() &&
-                include!(concat!(env!("OUT_DIR"), "/ascii_case_insensitive_html_attributes.rs"))
-                .contains(&*local_name_lower_cow)
+                include!(concat!(
+                    env!("OUT_DIR"),
+                    "/ascii_case_insensitive_html_attributes.rs"
+                )).contains(&*local_name_lower_cow)
             {
                 case_sensitivity =
                     ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument
             }
         }
         local_name_lower = local_name_lower_cow.as_ref().into();
     }
     let local_name = local_name.as_ref().into();
     if let Some(namespace) = namespace {
-        Ok(Component::AttributeOther(Box::new(AttrSelectorWithNamespace {
-            namespace: namespace,
-            local_name: local_name,
-            local_name_lower: local_name_lower,
-            never_matches: never_matches,
-            operation: ParsedAttrSelectorOperation::WithValue {
-                operator: operator,
-                case_sensitivity: case_sensitivity,
-                expected_value: value,
-            }
-        })))
+        Ok(Component::AttributeOther(Box::new(
+            AttrSelectorWithNamespace {
+                namespace: namespace,
+                local_name: local_name,
+                local_name_lower: local_name_lower,
+                never_matches: never_matches,
+                operation: ParsedAttrSelectorOperation::WithValue {
+                    operator: operator,
+                    case_sensitivity: case_sensitivity,
+                    expected_value: value,
+                },
+            },
+        )))
     } else {
         Ok(Component::AttributeInNoNamespace {
             local_name: local_name,
             local_name_lower: local_name_lower,
             operator: operator,
             value: value,
             case_sensitivity: case_sensitivity,
             never_matches: never_matches,
         })
     }
 }
 
-
 fn parse_attribute_flags<'i, 't>(
     input: &mut CssParser<'i, 't>,
 ) -> Result<ParsedCaseSensitivity, BasicParseError<'i>> {
     let location = input.current_source_location();
     match input.next() {
         Err(_) => {
             // Selectors spec says language-defined, but HTML says sensitive.
             Ok(ParsedCaseSensitivity::CaseSensitive)
-        }
+        },
         Ok(&Token::Ident(ref value)) if value.eq_ignore_ascii_case("i") => {
             Ok(ParsedCaseSensitivity::AsciiCaseInsensitive)
-        }
-        Ok(t) => Err(location.new_basic_unexpected_token_error(t.clone()))
+        },
+        Ok(t) => Err(location.new_basic_unexpected_token_error(t.clone())),
     }
 }
 
-
 /// Level 3: Parse **one** simple_selector.  (Though we might insert a second
 /// implied "<defaultns>|*" type selector.)
 fn parse_negation<'i, 't, P, Impl>(
     parser: &P,
     input: &mut CssParser<'i, 't>,
 ) -> Result<Component<Impl>, ParseError<'i, P::Error>>
 where
-    P: Parser<'i, Impl=Impl>,
+    P: Parser<'i, Impl = Impl>,
     Impl: SelectorImpl,
 {
     // We use a sequence because a type selector may be represented as two Components.
     let mut sequence = SmallVec::<[Component<Impl>; 2]>::new();
 
     input.skip_whitespace();
 
     // Get exactly one simple selector. The parse logic in the caller will verify
     // that there are no trailing tokens after we're done.
     let is_type_sel = match parse_type_selector(parser, input, &mut sequence) {
         Ok(result) => result,
-        Err(ParseError { kind: ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput), .. }) => {
-            return Err(input.new_custom_error(SelectorParseErrorKind::EmptyNegation))
-        }
+        Err(ParseError {
+            kind: ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput),
+            ..
+        }) => return Err(input.new_custom_error(SelectorParseErrorKind::EmptyNegation)),
         Err(e) => return Err(e.into()),
     };
     if !is_type_sel {
         match parse_one_simple_selector(parser, input, /* inside_negation = */ true)? {
             Some(SimpleSelectorParseResult::SimpleSelector(s)) => {
                 sequence.push(s);
             },
             None => {
                 return Err(input.new_custom_error(SelectorParseErrorKind::EmptyNegation));
             },
             Some(SimpleSelectorParseResult::PseudoElement(_)) |
             Some(SimpleSelectorParseResult::SlottedPseudo(_)) => {
-                return Err(input.new_custom_error(SelectorParseErrorKind::NonSimpleSelectorInNegation));
-            }
+                let e = SelectorParseErrorKind::NonSimpleSelectorInNegation;
+                return Err(input.new_custom_error(e));
+            },
         }
     }
 
     // Success.
     Ok(Component::Negation(sequence.into_vec().into_boxed_slice()))
 }
 
 /// simple_selector_sequence
@@ -1713,17 +1781,17 @@ where
 /// The booleans represent whether a pseudo-element has been parsed, and whether
 /// ::slotted() has been parsed, respectively.
 fn parse_compound_selector<'i, 't, P, Impl>(
     parser: &P,
     input: &mut CssParser<'i, 't>,
     builder: &mut SelectorBuilder<Impl>,
 ) -> Result<Option<(bool, bool)>, ParseError<'i, P::Error>>
 where
-    P: Parser<'i, Impl=Impl>,
+    P: Parser<'i, Impl = Impl>,
     Impl: SelectorImpl,
 {
     input.skip_whitespace();
 
     let mut empty = true;
     let mut slot = false;
     if !parse_type_selector(parser, input, builder)? {
         if let Some(url) = parser.default_namespace() {
@@ -1743,78 +1811,80 @@ where
                 None => break,
                 Some(result) => result,
             };
 
         match parse_result {
             SimpleSelectorParseResult::SimpleSelector(s) => {
                 builder.push_simple_selector(s);
                 empty = false
-            }
+            },
             SimpleSelectorParseResult::PseudoElement(p) => {
                 // Try to parse state to its right. There are only 3 allowable
                 // state selectors that can go on pseudo-elements.
                 let mut state_selectors = SmallVec::<[Component<Impl>; 3]>::new();
 
                 loop {
                     let location = input.current_source_location();
                     match input.next_including_whitespace() {
                         Ok(&Token::Colon) => {},
                         Ok(&Token::WhiteSpace(_)) | Err(_) => break,
-                        Ok(t) =>
-                            return Err(location.new_custom_error(
-                                SelectorParseErrorKind::PseudoElementExpectedColon(t.clone())
-                            )),
+                        Ok(t) => {
+                            let e = SelectorParseErrorKind::PseudoElementExpectedColon(t.clone());
+                            return Err(location.new_custom_error(e));
+                        },
                     }
 
                     let location = input.current_source_location();
                     // TODO(emilio): Functional pseudo-classes too?
                     // We don't need it for now.
                     let name = match input.next_including_whitespace()? {
                         &Token::Ident(ref name) => name.clone(),
-                        t => return Err(location.new_custom_error(
-                            SelectorParseErrorKind::NoIdentForPseudo(t.clone())
-                        )),
+                        t => {
+                            return Err(location.new_custom_error(
+                                SelectorParseErrorKind::NoIdentForPseudo(t.clone()),
+                            ))
+                        },
                     };
 
                     let pseudo_class =
                         P::parse_non_ts_pseudo_class(parser, location, name.clone())?;
                     if !p.supports_pseudo_class(&pseudo_class) {
                         return Err(input.new_custom_error(
-                            SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name)
+                            SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name),
                         ));
                     }
                     state_selectors.push(Component::NonTSPseudoClass(pseudo_class));
                 }
 
                 if !builder.is_empty() {
                     builder.push_combinator(Combinator::PseudoElement);
                 }
 
                 builder.push_simple_selector(Component::PseudoElement(p));
                 for state_selector in state_selectors.drain() {
                     builder.push_simple_selector(state_selector);
                 }
 
                 pseudo = true;
                 empty = false;
-                break
-            }
+                break;
+            },
             SimpleSelectorParseResult::SlottedPseudo(selector) => {
                 empty = false;
                 slot = true;
                 if !builder.is_empty() {
                     builder.push_combinator(Combinator::SlotAssignment);
                 }
                 builder.push_simple_selector(Component::Slotted(selector));
                 // FIXME(emilio): ::slotted() should support ::before and
                 // ::after after it, so we shouldn't break, but we shouldn't
                 // push more type selectors either.
                 break;
-            }
+            },
         }
     }
     if empty {
         // An empty selector is invalid.
         Ok(None)
     } else {
         Ok(Some((pseudo, slot)))
     }
@@ -1822,17 +1892,17 @@ where
 
 fn parse_functional_pseudo_class<'i, 't, P, Impl>(
     parser: &P,
     input: &mut CssParser<'i, 't>,
     name: CowRcStr<'i>,
     inside_negation: bool,
 ) -> Result<Component<Impl>, ParseError<'i, P::Error>>
 where
-    P: Parser<'i, Impl=Impl>,
+    P: Parser<'i, Impl = Impl>,
     Impl: SelectorImpl,
 {
     match_ignore_ascii_case! { &name,
         "nth-child" => return Ok(parse_nth_pseudo_class(input, Component::NthChild)?),
         "nth-of-type" => return Ok(parse_nth_pseudo_class(input, Component::NthOfType)?),
         "nth-last-child" => return Ok(parse_nth_pseudo_class(input, Component::NthLastChild)?),
         "nth-last-of-type" => return Ok(parse_nth_pseudo_class(input, Component::NthLastOfType)?),
         "host" => return Ok(Component::Host(Some(parse_inner_compound_selector(parser, input)?))),
@@ -1841,34 +1911,31 @@ where
                 return Err(input.new_custom_error(
                     SelectorParseErrorKind::UnexpectedIdent("not".into())
                 ));
             }
             return parse_negation(parser, input)
         },
         _ => {}
     }
-    P::parse_non_ts_functional_pseudo_class(parser, name, input)
-        .map(Component::NonTSPseudoClass)
+    P::parse_non_ts_functional_pseudo_class(parser, name, input).map(Component::NonTSPseudoClass)
 }
 
-
 fn parse_nth_pseudo_class<'i, 't, Impl, F>(
     input: &mut CssParser<'i, 't>,
     selector: F,
 ) -> Result<Component<Impl>, BasicParseError<'i>>
 where
     Impl: SelectorImpl,
     F: FnOnce(i32, i32) -> Component<Impl>,
 {
     let (a, b) = parse_nth(input)?;
     Ok(selector(a, b))
 }
 
-
 /// Returns whether the name corresponds to a CSS2 pseudo-element that
 /// can be specified with the single colon syntax (in addition to the
 /// double-colon syntax, which can be used for all pseudo-elements).
 pub fn is_css2_pseudo_element(name: &str) -> bool {
     // ** Do not add to this list! **
     match_ignore_ascii_case! { name,
         "before" | "after" | "first-line" | "first-letter" => true,
         _ => false,
@@ -1881,135 +1948,131 @@ pub fn is_css2_pseudo_element(name: &str
 /// * `Ok(None)`: Not a simple selector, could be something else. `input` was not consumed.
 /// * `Ok(Some(_))`: Parsed a simple selector or pseudo-element
 fn parse_one_simple_selector<'i, 't, P, Impl>(
     parser: &P,
     input: &mut CssParser<'i, 't>,
     inside_negation: bool,
 ) -> Result<Option<SimpleSelectorParseResult<Impl>>, ParseError<'i, P::Error>>
 where
-    P: Parser<'i, Impl=Impl>,
+    P: Parser<'i, Impl = Impl>,
     Impl: SelectorImpl,
 {
     let start = input.state();
     // FIXME: remove clone() when lifetimes are non-lexical
     match input.next_including_whitespace().map(|t| t.clone()) {
         Ok(Token::IDHash(id)) => {
             let id = Component::ID(id.as_ref().into());
             Ok(Some(SimpleSelectorParseResult::SimpleSelector(id)))
-        }
+        },
         Ok(Token::Delim('.')) => {
             let location = input.current_source_location();
             match *input.next_including_whitespace()? {
                 Token::Ident(ref class) => {
                     let class = Component::Class(class.as_ref().into());
                     Ok(Some(SimpleSelectorParseResult::SimpleSelector(class)))
-                }
-                ref t => Err(location.new_custom_error(
-                    SelectorParseErrorKind::ClassNeedsIdent(t.clone())
-                )),
+                },
+                ref t => {
+                    let e = SelectorParseErrorKind::ClassNeedsIdent(t.clone());
+                    Err(location.new_custom_error(e))
+                },
             }
-        }
+        },
         Ok(Token::SquareBracketBlock) => {
             let attr = input.parse_nested_block(|input| parse_attribute_selector(parser, input))?;
             Ok(Some(SimpleSelectorParseResult::SimpleSelector(attr)))
-        }
+        },
         Ok(Token::Colon) => {
             let location = input.current_source_location();
             let (is_single_colon, next_token) = match input.next_including_whitespace()?.clone() {
                 Token::Colon => (false, input.next_including_whitespace()?.clone()),
                 t => (true, t),
             };
             let (name, is_functional) = match next_token {
                 Token::Ident(name) => (name, false),
                 Token::Function(name) => (name, true),
-                t => return Err(input.new_custom_error(
-                    SelectorParseErrorKind::PseudoElementExpectedIdent(t)
-                )),
+                t => {
+                    let e = SelectorParseErrorKind::PseudoElementExpectedIdent(t);
+                    return Err(input.new_custom_error(e));
+                },
             };
-            let is_pseudo_element = !is_single_colon ||
-                P::pseudo_element_allows_single_colon(&name);
+            let is_pseudo_element =
+                !is_single_colon || P::pseudo_element_allows_single_colon(&name);
             if is_pseudo_element {
                 let parse_result = if is_functional {
                     if P::parse_slotted(parser) && name.eq_ignore_ascii_case("slotted") {
-                        SimpleSelectorParseResult::SlottedPseudo(
-                            input.parse_nested_block(|input| {
-                                parse_inner_compound_selector(
-                                    parser,
-                                    input,
-                                )
-                            })?
-                        )
+                        let selector = input.parse_nested_block(|input| {
+                            parse_inner_compound_selector(parser, input)
+                        })?;
+                        SimpleSelectorParseResult::SlottedPseudo(selector)
                     } else {
-                        SimpleSelectorParseResult::PseudoElement(
-                            input.parse_nested_block(|input| {
-                                P::parse_functional_pseudo_element(
-                                    parser,
-                                    name,
-                                    input,
-                                )
-                            })?
-                        )
+                        let selector = input.parse_nested_block(|input| {
+                            P::parse_functional_pseudo_element(parser, name, input)
+                        })?;
+                        SimpleSelectorParseResult::PseudoElement(selector)
                     }
                 } else {
-                    SimpleSelectorParseResult::PseudoElement(
-                        P::parse_pseudo_element(parser, location, name)?
-                    )
+                    SimpleSelectorParseResult::PseudoElement(P::parse_pseudo_element(
+                        parser,
+                        location,
+                        name,
+                    )?)
                 };
                 Ok(Some(parse_result))
             } else {
                 let pseudo_class = if is_functional {
                     input.parse_nested_block(|input| {
                         parse_functional_pseudo_class(parser, input, name, inside_negation)
                     })?
                 } else {
                     parse_simple_pseudo_class(parser, location, name)?
                 };
-                Ok(Some(SimpleSelectorParseResult::SimpleSelector(pseudo_class)))
+                Ok(Some(SimpleSelectorParseResult::SimpleSelector(
+                    pseudo_class,
+                )))
             }
-        }
+        },
         _ => {
             input.reset(&start);
             Ok(None)
-        }
+        },
     }
 }
 
 fn parse_simple_pseudo_class<'i, P, Impl>(
     parser: &P,
     location: SourceLocation,
     name: CowRcStr<'i>,
 ) -> Result<Component<Impl>, ParseError<'i, P::Error>>
 where
-    P: Parser<'i, Impl=Impl>,
-    Impl: SelectorImpl
+    P: Parser<'i, Impl = Impl>,
+    Impl: SelectorImpl,
 {
     (match_ignore_ascii_case! { &name,
         "first-child" => Ok(Component::FirstChild),
         "last-child"  => Ok(Component::LastChild),
         "only-child"  => Ok(Component::OnlyChild),
         "root" => Ok(Component::Root),
         "empty" => Ok(Component::Empty),
         "scope" => Ok(Component::Scope),
         "host" if P::parse_host(parser) => Ok(Component::Host(None)),
         "first-of-type" => Ok(Component::FirstOfType),
         "last-of-type" => Ok(Component::LastOfType),
         "only-of-type" => Ok(Component::OnlyOfType),
         _ => Err(())
     }).or_else(|()| {
-        P::parse_non_ts_pseudo_class(parser, location, name)
-            .map(Component::NonTSPseudoClass)
+        P::parse_non_ts_pseudo_class(parser, location, name).map(Component::NonTSPseudoClass)
     })
 }
 
 // NB: pub module in order to access the DummyParser
 #[cfg(test)]
 pub mod tests {
     use builder::HAS_PSEUDO_BIT;
-    use cssparser::{Parser as CssParser, ToCss, serialize_identifier, ParserInput};
+    use cssparser::{serialize_identifier, Parser as CssParser, ParserInput, ToCss};
     use parser;
     use std::collections::HashMap;
     use std::fmt;
     use super::*;
 
     #[derive(Clone, Debug, Eq, PartialEq)]
     pub enum PseudoClass {
         Hover,
@@ -2024,47 +2087,52 @@ pub mod tests {
     }
 
     impl parser::PseudoElement for PseudoElement {
         type Impl = DummySelectorImpl;
 
         fn supports_pseudo_class(&self, pc: &PseudoClass) -> bool {
             match *pc {
                 PseudoClass::Hover => true,
-                PseudoClass::Active |
-                PseudoClass::Lang(..) => false,
+                PseudoClass::Active | PseudoClass::Lang(..) => false,
             }
         }
     }
 
     impl parser::NonTSPseudoClass for PseudoClass {
         type Impl = DummySelectorImpl;
 
         #[inline]
         fn is_active_or_hover(&self) -> bool {
             matches!(*self, PseudoClass::Active | PseudoClass::Hover)
         }
     }
 
     impl ToCss for PseudoClass {
-        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+        fn to_css<W>(&self, dest: &mut W) -> fmt::Result
+        where
+            W: fmt::Write,
+        {
             match *self {
                 PseudoClass::Hover => dest.write_str(":hover"),
                 PseudoClass::Active => dest.write_str(":active"),
                 PseudoClass::Lang(ref lang) => {
                     dest.write_str(":lang(")?;
                     serialize_identifier(lang, dest)?;
                     dest.write_char(')')
-                }
+                },
             }
         }
     }
 
     impl ToCss for PseudoElement {
-        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+        fn to_css<W>(&self, dest: &mut W) -> fmt::Result
+        where
+            W: fmt::Write,
+        {
             match *self {
                 PseudoElement::Before => dest.write_str("::before"),
                 PseudoElement::After => dest.write_str("::after"),
             }
         }
     }
 
     impl Visit for PseudoClass {
@@ -2144,42 +2212,57 @@ pub mod tests {
             location: SourceLocation,
             name: CowRcStr<'i>,
         ) -> Result<PseudoClass, SelectorParseError<'i>> {
             match_ignore_ascii_case! { &name,
                 "hover" => return Ok(PseudoClass::Hover),
                 "active" => return Ok(PseudoClass::Active),
                 _ => {}
             }
-            Err(location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name)))
+            Err(
+                location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
+                    name,
+                )),
+            )
         }
 
         fn parse_non_ts_functional_pseudo_class<'t>(
             &self,
             name: CowRcStr<'i>,
             parser: &mut CssParser<'i, 't>,
         ) -> Result<PseudoClass, SelectorParseError<'i>> {
             match_ignore_ascii_case! { &name,
-                "lang" => return Ok(PseudoClass::Lang(parser.expect_ident_or_string()?.as_ref().to_owned())),
+                "lang" => {
+                    let lang = parser.expect_ident_or_string()?.as_ref().to_owned();
+                    return Ok(PseudoClass::Lang(lang));
+                },
                 _ => {}
             }
-            Err(parser.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name)))
+            Err(
+                parser.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
+                    name,
+                )),
+            )
         }
 
         fn parse_pseudo_element(
             &self,
             location: SourceLocation,
             name: CowRcStr<'i>,
         ) -> Result<PseudoElement, SelectorParseError<'i>> {
             match_ignore_ascii_case! { &name,
                 "before" => return Ok(PseudoElement::Before),
                 "after" => return Ok(PseudoElement::After),
                 _ => {}
             }
-            Err(location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name)))
+            Err(
+                location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
+                    name,
+                )),
+            )
         }
 
         fn default_namespace(&self) -> Option<DummyAtom> {
             self.default_ns.clone()
         }
 
         fn namespace_for_prefix(&self, prefix: &DummyAtom) -> Option<DummyAtom> {
             self.ns_prefixes.get(prefix).cloned()
@@ -2204,30 +2287,30 @@ pub mod tests {
         parser: &DummyParser,
     ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
         parse_ns_expected(input, parser, None)
     }
 
     fn parse_ns_expected<'i, 'a>(
         input: &'i str,
         parser: &DummyParser,
-        expected: Option<&'a str>
+        expected: Option<&'a str>,
     ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
         let mut parser_input = ParserInput::new(input);
         let result = SelectorList::parse(parser, &mut CssParser::new(&mut parser_input));
         if let Ok(ref selectors) = result {
             assert_eq!(selectors.0.len(), 1);
             // We can't assume that the serialized parsed selector will equal
             // the input; for example, if there is no default namespace, '*|foo'
             // should serialize to 'foo'.
             assert_eq!(
                 selectors.0[0].to_css_string(),
                 match expected {
                     Some(x) => x,
-                    None => input
+                    None => input,
                 }
             );
         }
         result
     }
 
     fn specificity(a: u32, b: u32, c: u32) -> u32 {
         a << 20 | b << 10 | c
@@ -2243,322 +2326,525 @@ pub mod tests {
     const MATHML: &'static str = "http://www.w3.org/1998/Math/MathML";
     const SVG: &'static str = "http://www.w3.org/2000/svg";
 
     #[test]
     fn test_parsing() {
         assert!(parse("").is_err());
         assert!(parse(":lang(4)").is_err());
         assert!(parse(":lang(en US)").is_err());
-        assert_eq!(parse("EeÉ"), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(
-                Component::LocalName(LocalName {
-                    name: DummyAtom::from("EeÉ"),
-                    lower_name: DummyAtom::from("eeÉ") })
-            ), specificity(0, 0, 1))
-        ))));
-        assert_eq!(parse("|e"), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(
-                Component::ExplicitNoNamespace,
-                Component::LocalName(LocalName {
-                    name: DummyAtom::from("e"),
-                    lower_name: DummyAtom::from("e")
-                })), specificity(0, 0, 1))
-        ))));
+        assert_eq!(
+            parse("EeÉ"),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::LocalName(LocalName {
+                            name: DummyAtom::from("EeÉ"),
+                            lower_name: DummyAtom::from("eeÉ"),
+                        }),
+                    ],
+                    specificity(0, 0, 1),
+                ),
+            ]))
+        );
+        assert_eq!(
+            parse("|e"),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::ExplicitNoNamespace,
+                        Component::LocalName(LocalName {
+                            name: DummyAtom::from("e"),
+                            lower_name: DummyAtom::from("e"),
+                        }),
+                    ],
+                    specificity(0, 0, 1),
+                ),
+            ]))
+        );
         // When the default namespace is not set, *| should be elided.
         // https://github.com/servo/servo/pull/17537
-        assert_eq!(parse_expected("*|e", Some("e")), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(
-                Component::LocalName(LocalName {
-                    name: DummyAtom::from("e"),
-                    lower_name: DummyAtom::from("e")
-                })
-            ), specificity(0, 0, 1))
-        ))));
+        assert_eq!(
+            parse_expected("*|e", Some("e")),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::LocalName(LocalName {
+                            name: DummyAtom::from("e"),
+                            lower_name: DummyAtom::from("e"),
+                        }),
+                    ],
+                    specificity(0, 0, 1),
+                ),
+            ]))
+        );
         // When the default namespace is set, *| should _not_ be elided (as foo
         // is no longer equivalent to *|foo--the former is only for foo in the
         // default namespace).
         // https://github.com/servo/servo/issues/16020
         assert_eq!(
             parse_ns(
                 "*|e",
                 &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org"))
             ),
-            Ok(SelectorList::from_vec(vec!(
-                Selector::from_vec(vec!(
-                    Component::ExplicitAnyNamespace,
-                    Component::LocalName(LocalName {
-                        name: DummyAtom::from("e"),
-                        lower_name: DummyAtom::from("e")
-                    })
-                ), specificity(0, 0, 1)))))
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::ExplicitAnyNamespace,
+                        Component::LocalName(LocalName {
+                            name: DummyAtom::from("e"),
+                            lower_name: DummyAtom::from("e"),
+                        }),
+                    ],
+                    specificity(0, 0, 1),
+                ),
+            ]))
+        );
+        assert_eq!(
+            parse("*"),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(vec![Component::ExplicitUniversalType], specificity(0, 0, 0)),
+            ]))
         );
-        assert_eq!(parse("*"), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(
-                Component::ExplicitUniversalType,
-            ), specificity(0, 0, 0))
-        ))));
-        assert_eq!(parse("|*"), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(
-                Component::ExplicitNoNamespace,
-                Component::ExplicitUniversalType,
-            ), specificity(0, 0, 0))
-        ))));
-        assert_eq!(parse_expected("*|*", Some("*")), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(
-                Component::ExplicitUniversalType,
-            ), specificity(0, 0, 0))
-        ))));
+        assert_eq!(
+            parse("|*"),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::ExplicitNoNamespace,
+                        Component::ExplicitUniversalType,
+                    ],
+                    specificity(0, 0, 0),
+                ),
+            ]))
+        );
+        assert_eq!(
+            parse_expected("*|*", Some("*")),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(vec![Component::ExplicitUniversalType], specificity(0, 0, 0)),
+            ]))
+        );
         assert_eq!(
             parse_ns(
                 "*|*",
                 &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org"))
             ),
-            Ok(SelectorList::from_vec(vec!(
-                Selector::from_vec(vec!(
-                    Component::ExplicitAnyNamespace,
-                    Component::ExplicitUniversalType,
-                ), specificity(0, 0, 0)))))
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::ExplicitAnyNamespace,
+                        Component::ExplicitUniversalType,
+                    ],
+                    specificity(0, 0, 0),
+                ),
+            ]))
+        );
+        assert_eq!(
+            parse(".foo:lang(en-US)"),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::Class(DummyAtom::from("foo")),
+                        Component::NonTSPseudoClass(PseudoClass::Lang("en-US".to_owned())),
+                    ],
+                    specificity(0, 2, 0),
+                ),
+            ]))
+        );
+        assert_eq!(
+            parse("#bar"),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![Component::ID(DummyAtom::from("bar"))],
+                    specificity(1, 0, 0),
+                ),
+            ]))
         );
-        assert_eq!(parse(".foo:lang(en-US)"), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(
-                    Component::Class(DummyAtom::from("foo")),
-                    Component::NonTSPseudoClass(PseudoClass::Lang("en-US".to_owned()))
-            ), specificity(0, 2, 0))
-        ))));
-        assert_eq!(parse("#bar"), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(
-                Component::ID(DummyAtom::from("bar"))
-            ), specificity(1, 0, 0))
-        ))));
-        assert_eq!(parse("e.foo#bar"), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(
-                Component::LocalName(LocalName {
-                    name: DummyAtom::from("e"),
-                    lower_name: DummyAtom::from("e")
-                }),
-                Component::Class(DummyAtom::from("foo")),
-                Component::ID(DummyAtom::from("bar"))
-            ), specificity(1, 1, 1))
-        ))));
-        assert_eq!(parse("e.foo #bar"), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(
-               Component::LocalName(LocalName {
-                   name: DummyAtom::from("e"),
-                   lower_name: DummyAtom::from("e")
-               }),
-               Component::Class(DummyAtom::from("foo")),
-               Component::Combinator(Combinator::Descendant),
-               Component::ID(DummyAtom::from("bar")),
-            ), specificity(1, 1, 1))
-        ))));
+        assert_eq!(
+            parse("e.foo#bar"),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::LocalName(LocalName {
+                            name: DummyAtom::from("e"),
+                            lower_name: DummyAtom::from("e"),
+                        }),
+                        Component::Class(DummyAtom::from("foo")),
+                        Component::ID(DummyAtom::from("bar")),
+                    ],
+                    specificity(1, 1, 1),
+                ),
+            ]))
+        );
+        assert_eq!(
+            parse("e.foo #bar"),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::LocalName(LocalName {
+                            name: DummyAtom::from("e"),
+                            lower_name: DummyAtom::from("e"),
+                        }),
+                        Component::Class(DummyAtom::from("foo")),
+                        Component::Combinator(Combinator::Descendant),
+                        Component::ID(DummyAtom::from("bar")),
+                    ],
+                    specificity(1, 1, 1),
+                ),
+            ]))
+        );
         // Default namespace does not apply to attribute selectors
         // https://github.com/mozilla/servo/pull/1652
         let mut parser = DummyParser::default();
-        assert_eq!(parse_ns("[Foo]", &parser), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(
-                Component::AttributeInNoNamespaceExists {
-                    local_name: DummyAtom::from("Foo"),
-                    local_name_lower: DummyAtom::from("foo"),
-                }
-            ), specificity(0, 1, 0))
-        ))));
+        assert_eq!(
+            parse_ns("[Foo]", &parser),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::AttributeInNoNamespaceExists {
+                            local_name: DummyAtom::from("Foo"),
+                            local_name_lower: DummyAtom::from("foo"),
+                        },
+                    ],
+                    specificity(0, 1, 0),
+                ),
+            ]))
+        );
         assert!(parse_ns("svg|circle", &parser).is_err());
-        parser.ns_prefixes.insert(DummyAtom("svg".into()), DummyAtom(SVG.into()));
-        assert_eq!(parse_ns("svg|circle", &parser), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(
-                Component::Namespace(DummyAtom("svg".into()), SVG.into()),
-                Component::LocalName(LocalName {
-                    name: DummyAtom::from("circle"),
-                    lower_name: DummyAtom::from("circle"),
-                })
-            ), specificity(0, 0, 1))
-        ))));
-        assert_eq!(parse_ns("svg|*", &parser), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(
-                Component::Namespace(DummyAtom("svg".into()), SVG.into()),
-                Component::ExplicitUniversalType,
-            ), specificity(0, 0, 0))
-        ))));
+        parser
+            .ns_prefixes
+            .insert(DummyAtom("svg".into()), DummyAtom(SVG.into()));
+        assert_eq!(
+            parse_ns("svg|circle", &parser),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::Namespace(DummyAtom("svg".into()), SVG.into()),
+                        Component::LocalName(LocalName {
+                            name: DummyAtom::from("circle"),
+                            lower_name: DummyAtom::from("circle"),
+                        }),
+                    ],
+                    specificity(0, 0, 1),
+                ),
+            ]))
+        );
+        assert_eq!(
+            parse_ns("svg|*", &parser),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::Namespace(DummyAtom("svg".into()), SVG.into()),
+                        Component::ExplicitUniversalType,
+                    ],
+                    specificity(0, 0, 0),
+                ),
+            ]))
+        );
         // Default namespace does not apply to attribute selectors
         // https://github.com/mozilla/servo/pull/1652
         // but it does apply to implicit type selectors
         // https://github.com/servo/rust-selectors/pull/82
         parser.default_ns = Some(MATHML.into());
-        assert_eq!(parse_ns("[Foo]", &parser), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(
-                Component::DefaultNamespace(MATHML.into()),
-                Component::AttributeInNoNamespaceExists {
-                    local_name: DummyAtom::from("Foo"),
-                    local_name_lower: DummyAtom::from("foo"),
-                },
-            ), specificity(0, 1, 0))
-        ))));
+        assert_eq!(
+            parse_ns("[Foo]", &parser),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::DefaultNamespace(MATHML.into()),
+                        Component::AttributeInNoNamespaceExists {
+                            local_name: DummyAtom::from("Foo"),
+                            local_name_lower: DummyAtom::from("foo"),
+                        },
+                    ],
+                    specificity(0, 1, 0),
+                ),
+            ]))
+        );
         // Default namespace does apply to type selectors
-        assert_eq!(parse_ns("e", &parser), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(
-                Component::DefaultNamespace(MATHML.into()),
-                Component::LocalName(LocalName {
-                    name: DummyAtom::from("e"),
-                    lower_name: DummyAtom::from("e") }),
-            ), specificity(0, 0, 1))
-        ))));
-        assert_eq!(parse_ns("*", &parser), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(
-                Component::DefaultNamespace(MATHML.into()),
-                Component::ExplicitUniversalType,
-            ), specificity(0, 0, 0))
-        ))));
-        assert_eq!(parse_ns("*|*", &parser), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(
-                Component::ExplicitAnyNamespace,
-                Component::ExplicitUniversalType,
-            ), specificity(0, 0, 0))
-        ))));
+        assert_eq!(
+            parse_ns("e", &parser),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::DefaultNamespace(MATHML.into()),
+                        Component::LocalName(LocalName {
+                            name: DummyAtom::from("e"),
+                            lower_name: DummyAtom::from("e"),
+                        }),
+                    ],
+                    specificity(0, 0, 1),
+                ),
+            ]))
+        );
+        assert_eq!(
+            parse_ns("*", &parser),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::DefaultNamespace(MATHML.into()),
+                        Component::ExplicitUniversalType,
+                    ],
+                    specificity(0, 0, 0),
+                ),
+            ]))
+        );
+        assert_eq!(
+            parse_ns("*|*", &parser),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::ExplicitAnyNamespace,
+                        Component::ExplicitUniversalType,
+                    ],
+                    specificity(0, 0, 0),
+                ),
+            ]))
+        );
         // Default namespace applies to universal and type selectors inside :not and :matches,
         // but not otherwise.
-        assert_eq!(parse_ns(":not(.cl)", &parser), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(
-                Component::DefaultNamespace(MATHML.into()),
-                Component::Negation(vec![
-                    Component::Class(DummyAtom::from("cl"))
-                ].into_boxed_slice()),
-            ), specificity(0, 1, 0))
-        ))));
-        assert_eq!(parse_ns(":not(*)", &parser), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(
-                Component::DefaultNamespace(MATHML.into()),
-                Component::Negation(vec![
-                    Component::DefaultNamespace(MATHML.into()),
-                    Component::ExplicitUniversalType,
-                ].into_boxed_slice()),
-            ), specificity(0, 0, 0))
-        ))));
-        assert_eq!(parse_ns(":not(e)", &parser), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(
-                Component::DefaultNamespace(MATHML.into()),
-                Component::Negation(vec![
-                    Component::DefaultNamespace(MATHML.into()),
-                    Component::LocalName(LocalName {
-                        name: DummyAtom::from("e"),
-                        lower_name: DummyAtom::from("e")
-                    }),
-                ].into_boxed_slice())
-            ), specificity(0, 0, 1))
-        ))));
-        assert_eq!(parse("[attr|=\"foo\"]"), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(
-                Component::AttributeInNoNamespace {
-                    local_name: DummyAtom::from("attr"),
-                    local_name_lower: DummyAtom::from("attr"),
-                    operator: AttrSelectorOperator::DashMatch,
-                    value: DummyAtom::from("foo"),
-                    never_matches: false,
-                    case_sensitivity: ParsedCaseSensitivity::CaseSensitive,
-                }
-            ), specificity(0, 1, 0))
-        ))));
+        assert_eq!(
+            parse_ns(":not(.cl)", &parser),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::DefaultNamespace(MATHML.into()),
+                        Component::Negation(
+                            vec![Component::Class(DummyAtom::from("cl"))].into_boxed_slice(),
+                        ),
+                    ],
+                    specificity(0, 1, 0),
+                ),
+            ]))
+        );
+        assert_eq!(
+            parse_ns(":not(*)", &parser),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::DefaultNamespace(MATHML.into()),
+                        Component::Negation(
+                            vec![
+                                Component::DefaultNamespace(MATHML.into()),
+                                Component::ExplicitUniversalType,
+                            ].into_boxed_slice(),
+                        ),
+                    ],
+                    specificity(0, 0, 0),
+                ),
+            ]))
+        );
+        assert_eq!(
+            parse_ns(":not(e)", &parser),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::DefaultNamespace(MATHML.into()),
+                        Component::Negation(
+                            vec![
+                                Component::DefaultNamespace(MATHML.into()),
+                                Component::LocalName(LocalName {
+                                    name: DummyAtom::from("e"),
+                                    lower_name: DummyAtom::from("e"),
+                                }),
+                            ].into_boxed_slice(),
+                        ),
+                    ],
+                    specificity(0, 0, 1),
+                ),
+            ]))
+        );
+        assert_eq!(
+            parse("[attr|=\"foo\"]"),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::AttributeInNoNamespace {
+                            local_name: DummyAtom::from("attr"),
+                            local_name_lower: DummyAtom::from("attr"),
+                            operator: AttrSelectorOperator::DashMatch,
+                            value: DummyAtom::from("foo"),
+                            never_matches: false,
+                            case_sensitivity: ParsedCaseSensitivity::CaseSensitive,
+                        },
+                    ],
+                    specificity(0, 1, 0),
+                ),
+            ]))
+        );
         // https://github.com/mozilla/servo/issues/1723
-        assert_eq!(parse("::before"), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(
-                Component::PseudoElement(PseudoElement::Before),
-            ), specificity(0, 0, 1) | HAS_PSEUDO_BIT)
-        ))));
-        assert_eq!(parse("::before:hover"), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(
-                Component::PseudoElement(PseudoElement::Before),
-                Component::NonTSPseudoClass(PseudoClass::Hover),
-            ), specificity(0, 1, 1) | HAS_PSEUDO_BIT)
-        ))));
-        assert_eq!(parse("::before:hover:hover"), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(
-                Component::PseudoElement(PseudoElement::Before),
-                Component::NonTSPseudoClass(PseudoClass::Hover),
-                Component::NonTSPseudoClass(PseudoClass::Hover),
-            ), specificity(0, 2, 1) | HAS_PSEUDO_BIT)
-        ))));
+        assert_eq!(
+            parse("::before"),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![Component::PseudoElement(PseudoElement::Before)],
+                    specificity(0, 0, 1) | HAS_PSEUDO_BIT,
+                ),
+            ]))
+        );
+        assert_eq!(
+            parse("::before:hover"),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::PseudoElement(PseudoElement::Before),
+                        Component::NonTSPseudoClass(PseudoClass::Hover),
+                    ],
+                    specificity(0, 1, 1) | HAS_PSEUDO_BIT,
+                ),
+            ]))
+        );
+        assert_eq!(
+            parse("::before:hover:hover"),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::PseudoElement(PseudoElement::Before),
+                        Component::NonTSPseudoClass(PseudoClass::Hover),
+                        Component::NonTSPseudoClass(PseudoClass::Hover),
+                    ],
+                    specificity(0, 2, 1) | HAS_PSEUDO_BIT,
+                ),
+            ]))
+        );
         assert!(parse("::before:hover:active").is_err());
         assert!(parse("::before:hover .foo").is_err());
         assert!(parse("::before .foo").is_err());
         assert!(parse("::before ~ bar").is_err());
         assert!(parse("::before:active").is_err());
 
         // https://github.com/servo/servo/issues/15335
         assert!(parse(":: before").is_err());
-        assert_eq!(parse("div ::after"), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(
-                 Component::LocalName(LocalName {
-                    name: DummyAtom::from("div"),
-                    lower_name: DummyAtom::from("div") }),
-                Component::Combinator(Combinator::Descendant),
-                Component::Combinator(Combinator::PseudoElement),
-                Component::PseudoElement(PseudoElement::After),
-            ), specificity(0, 0, 2) | HAS_PSEUDO_BIT)
-        ))));
-        assert_eq!(parse("#d1 > .ok"), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(
-                Component::ID(DummyAtom::from("d1")),
-                Component::Combinator(Combinator::Child),
-                Component::Class(DummyAtom::from("ok")),
-            ), (1 << 20) + (1 << 10) + (0 << 0))
-        ))));
+        assert_eq!(
+            parse("div ::after"),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::LocalName(LocalName {
+                            name: DummyAtom::from("div"),
+                            lower_name: DummyAtom::from("div"),
+                        }),
+                        Component::Combinator(Combinator::Descendant),
+                        Component::Combinator(Combinator::PseudoElement),
+                        Component::PseudoElement(PseudoElement::After),
+                    ],
+                    specificity(0, 0, 2) | HAS_PSEUDO_BIT,
+                ),
+            ]))
+        );
+        assert_eq!(
+            parse("#d1 > .ok"),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::ID(DummyAtom::from("d1")),
+                        Component::Combinator(Combinator::Child),
+                        Component::Class(DummyAtom::from("ok")),
+                    ],
+                    (1 << 20) + (1 << 10) + (0 << 0),
+                ),
+            ]))
+        );
         parser.default_ns = None;
         assert!(parse(":not(#provel.old)").is_err());
         assert!(parse(":not(#provel > old)").is_err());
         assert!(parse("table[rules]:not([rules=\"none\"]):not([rules=\"\"])").is_ok());
-        assert_eq!(parse(":not(#provel)"), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(Component::Negation(vec!(
-                    Component::ID(DummyAtom::from("provel")),
-                ).into_boxed_slice()
-            )), specificity(1, 0, 0))
-        ))));
-        assert_eq!(parse_ns(":not(svg|circle)", &parser), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(Component::Negation(
-                vec![
-                    Component::Namespace(DummyAtom("svg".into()), SVG.into()),
-                    Component::LocalName(LocalName {
-                        name: DummyAtom::from("circle"),
-                        lower_name: DummyAtom::from("circle")
-                    }),
-                ].into_boxed_slice()
-            )), specificity(0, 0, 1))
-        ))));
+        assert_eq!(
+            parse(":not(#provel)"),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::Negation(
+                            vec![Component::ID(DummyAtom::from("provel"))].into_boxed_slice(),
+                        ),
+                    ],
+                    specificity(1, 0, 0),
+                ),
+            ]))
+        );
+        assert_eq!(
+            parse_ns(":not(svg|circle)", &parser),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::Negation(
+                            vec![
+                                Component::Namespace(DummyAtom("svg".into()), SVG.into()),
+                                Component::LocalName(LocalName {
+                                    name: DummyAtom::from("circle"),
+                                    lower_name: DummyAtom::from("circle"),
+                                }),
+                            ].into_boxed_slice(),
+                        ),
+                    ],
+                    specificity(0, 0, 1),
+                ),
+            ]))
+        );
         // https://github.com/servo/servo/issues/16017
-        assert_eq!(parse_ns(":not(*)", &parser), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(Component::Negation(
-                vec![
-                    Component::ExplicitUniversalType,
-                ].into_boxed_slice()
-            )), specificity(0, 0, 0))
-        ))));
-        assert_eq!(parse_ns(":not(|*)", &parser), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(Component::Negation(
-                vec![
-                    Component::ExplicitNoNamespace,
-                    Component::ExplicitUniversalType,
-                ].into_boxed_slice()
-            )), specificity(0, 0, 0))
-        ))));
+        assert_eq!(
+            parse_ns(":not(*)", &parser),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::Negation(
+                            vec![Component::ExplicitUniversalType].into_boxed_slice(),
+                        ),
+                    ],
+                    specificity(0, 0, 0),
+                ),
+            ]))
+        );
+        assert_eq!(
+            parse_ns(":not(|*)", &parser),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::Negation(
+                            vec![
+                                Component::ExplicitNoNamespace,
+                                Component::ExplicitUniversalType,
+                            ].into_boxed_slice(),
+                        ),
+                    ],
+                    specificity(0, 0, 0),
+                ),
+            ]))
+        );
         // *| should be elided if there is no default namespace.
         // https://github.com/servo/servo/pull/17537
-        assert_eq!(parse_ns_expected(":not(*|*)", &parser, Some(":not(*)")), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(Component::Negation(
-                vec![
-                    Component::ExplicitUniversalType,
-                ].into_boxed_slice()
-            )), specificity(0, 0, 0))
-        ))));
-        assert_eq!(parse_ns(":not(svg|*)", &parser), Ok(SelectorList::from_vec(vec!(
-            Selector::from_vec(vec!(Component::Negation(
-                vec![
-                    Component::Namespace(DummyAtom("svg".into()), SVG.into()),
-                    Component::ExplicitUniversalType,
-                ].into_boxed_slice()
-            )), specificity(0, 0, 0))
-        ))));
+        assert_eq!(
+            parse_ns_expected(":not(*|*)", &parser, Some(":not(*)")),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::Negation(
+                            vec![Component::ExplicitUniversalType].into_boxed_slice(),
+                        ),
+                    ],
+                    specificity(0, 0, 0),
+                ),
+            ]))
+        );
+        assert_eq!(
+            parse_ns(":not(svg|*)", &parser),
+            Ok(SelectorList::from_vec(vec![
+                Selector::from_vec(
+                    vec![
+                        Component::Negation(
+                            vec![
+                                Component::Namespace(DummyAtom("svg".into()), SVG.into()),
+                                Component::ExplicitUniversalType,
+                            ].into_boxed_slice(),
+                        ),
+                    ],
+                    specificity(0, 0, 0),
+                ),
+            ]))
+        );
 
         assert!(parse("::slotted()").is_err());
         assert!(parse("::slotted(div)").is_ok());
         assert!(parse("::slotted(div).foo").is_err());
         assert!(parse("::slotted(div + bar)").is_err());
         assert!(parse("::slotted(div) + foo").is_err());
         assert!(parse("div ::slotted(div)").is_ok());
         assert!(parse("div + slot::slotted(div)").is_ok());
@@ -2569,40 +2855,47 @@ pub mod tests {
         assert!(parse("slot::slotted(div,foo)").is_err());
     }
 
     #[test]
     fn test_pseudo_iter() {
         let selector = &parse("q::before").unwrap().0[0];
         assert!(!selector.is_universal());
         let mut iter = selector.iter();
-        assert_eq!(iter.next(), Some(&Component::PseudoElement(PseudoElement::Before)));
+        assert_eq!(
+            iter.next(),
+            Some(&Component::PseudoElement(PseudoElement::Before))
+        );
         assert_eq!(iter.next(), None);
         let combinator = iter.next_sequence();
         assert_eq!(combinator, Some(Combinator::PseudoElement));
         assert!(matches!(iter.next(), Some(&Component::LocalName(..))));
         assert_eq!(iter.next(), None);
         assert_eq!(iter.next_sequence(), None);
     }
 
     #[test]
     fn test_universal() {
         let selector = &parse_ns(
             "*|*::before",
-            &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org"))
-        ).unwrap().0[0];
+            &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org")),
+        ).unwrap()
+            .0[0];
         assert!(selector.is_universal());
     }
 
     #[test]
     fn test_empty_pseudo_iter() {
         let selector = &parse("::before").unwrap().0[0];
         assert!(selector.is_universal());
         let mut iter = selector.iter();
-        assert_eq!(iter.next(), Some(&Component::PseudoElement(PseudoElement::Before)));
+        assert_eq!(
+            iter.next(),
+            Some(&Component::PseudoElement(PseudoElement::Before))
+        );
         assert_eq!(iter.next(), None);
         assert_eq!(iter.next_sequence(), None);
     }
 
     struct TestVisitor {
         seen: Vec<String>,
     }
 
@@ -2614,17 +2907,17 @@ pub mod tests {
             s.to_css(&mut dest).unwrap();
             self.seen.push(dest);
             true
         }
     }
 
     #[test]
     fn visitor() {
-        let mut test_visitor = TestVisitor { seen: vec![], };
+        let mut test_visitor = TestVisitor { seen: vec![] };
         parse(":not(:hover) ~ label").unwrap().0[0].visit(&mut test_visitor);
         assert!(test_visitor.seen.contains(&":hover".into()));
 
-        let mut test_visitor = TestVisitor { seen: vec![], };
+        let mut test_visitor = TestVisitor { seen: vec![] };
         parse("::before:hover").unwrap().0[0].visit(&mut test_visitor);
         assert!(test_visitor.seen.contains(&":hover".into()));
     }
 }
--- a/servo/components/selectors/tree.rs
+++ b/servo/components/selectors/tree.rs
@@ -1,16 +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/. */
 
 //! Traits that nodes must implement. Breaks the otherwise-cyclic dependency
 //! between layout and style.
 
-use attr::{AttrSelectorOperation, NamespaceConstraint, CaseSensitivity};
+use attr::{AttrSelectorOperation, CaseSensitivity, NamespaceConstraint};
 use matching::{ElementSelectorFlags, MatchingContext};
 use parser::SelectorImpl;
 use servo_arc::NonZeroPtrMut;
 use std::fmt::Debug;
 
 /// Opaque representation of an Element, for identity comparisons. We use
 /// NonZeroPtrMut to get the NonZero optimization.
 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
--- a/servo/components/selectors/visitor.rs
+++ b/servo/components/selectors/visitor.rs
@@ -33,19 +33,17 @@ pub trait SelectorVisitor {
     fn visit_simple_selector(&mut self, _: &Component<Self::Impl>) -> bool {
         true
     }
 
     /// Visits a complex selector.
     ///
     /// Gets the combinator to the right of the selector, or `None` if the
     /// selector is the rightmost one.
-    fn visit_complex_selector(&mut self,
-                              _combinator_to_right: Option<Combinator>)
-                              -> bool {
+    fn visit_complex_selector(&mut self, _combinator_to_right: Option<Combinator>) -> bool {
         true
     }
 }
 
 /// Enables traversing selector components stored in various types
 pub trait Visit {
     /// The type parameter of selector component types.
     type Impl: SelectorImpl;
--- a/servo/components/servo_arc/lib.rs
+++ b/servo/components/servo_arc/lib.rs
@@ -19,17 +19,18 @@
 //!
 //! [1]: https://bugzilla.mozilla.org/show_bug.cgi?id=1360883
 
 // The semantics of Arc are alread documented in the Rust docs, so we don't
 // duplicate those here.
 #![allow(missing_docs)]
 
 extern crate nodrop;
-#[cfg(feature = "servo")] extern crate serde;
+#[cfg(feature = "servo")]
+extern crate serde;
 extern crate stable_deref_trait;
 
 use nodrop::NoDrop;
 #[cfg(feature = "servo")]
 use serde::{Deserialize, Serialize};
 use stable_deref_trait::{CloneStableDeref, StableDeref};
 use std::{isize, usize};
 use std::borrow;
@@ -181,17 +182,19 @@ unsafe impl<T: ?Sized + Sync + Send> Syn
 
 impl<T> Arc<T> {
     #[inline]
     pub fn new(data: T) -> Self {
         let x = Box::new(ArcInner {
             count: atomic::AtomicUsize::new(1),
             data: data,
         });
-        Arc { p: NonZeroPtrMut::new(Box::into_raw(x)) }
+        Arc {
+            p: NonZeroPtrMut::new(Box::into_raw(x)),
+        }
     }
 
     #[inline]
     pub fn into_raw(this: Self) -> *const T {
         let ptr = unsafe { &((*this.ptr()).data) as *const _ };
         mem::forget(this);
         ptr
     }
@@ -212,17 +215,18 @@ impl<T> Arc<T> {
     pub fn borrow_arc<'a>(&'a self) -> ArcBorrow<'a, T> {
         ArcBorrow(&**self)
     }
 
     /// Temporarily converts |self| into a bonafide RawOffsetArc and exposes it to the
     /// provided callback. The refcount is not modified.
     #[inline(always)]
     pub fn with_raw_offset_arc<F, U>(&self, f: F) -> U
-        where F: FnOnce(&RawOffsetArc<T>) -> U
+    where
+        F: FnOnce(&RawOffsetArc<T>) -> U,
     {
         // Synthesize transient Arc, which never touches the refcount of the ArcInner.
         let transient = unsafe { NoDrop::new(Arc::into_raw_offset(ptr::read(self))) };
 
         // Expose the transient Arc to the callback, which may clone it if it wants.
         let result = f(&transient);
 
         // Forget the transient Arc to leave the refcount untouched.
@@ -251,17 +255,16 @@ impl<T: ?Sized> Arc<T> {
     }
 
     // Non-inlined part of `drop`. Just invokes the destructor.
     #[inline(never)]
     unsafe fn drop_slow(&mut self) {
         let _ = Box::from_raw(self.ptr());
     }
 
-
     #[inline]
     pub fn ptr_eq(this: &Self, other: &Self) -> bool {
         this.ptr() == other.ptr()
     }
 
     fn ptr(&self) -> *mut ArcInner<T> {
         self.p.ptr()
     }
@@ -291,17 +294,19 @@ impl<T: ?Sized> Clone for Arc<T> {
         // any realistic program.
         //
         // We abort because such a program is incredibly degenerate, and we
         // don't care to support it.
         if old_size > MAX_REFCOUNT {
             process::abort();
         }
 
-        Arc { p: NonZeroPtrMut::new(self.ptr()) }
+        Arc {
+            p: NonZeroPtrMut::new(self.ptr()),
+        }
     }
 }
 
 impl<T: ?Sized> Deref for Arc<T> {
     type Target = T;
 
     #[inline]
     fn deref(&self) -> &T {
@@ -479,29 +484,27 @@ impl<T: ?Sized> AsRef<T> for Arc<T> {
         &**self
     }
 }
 
 unsafe impl<T: ?Sized> StableDeref for Arc<T> {}
 unsafe impl<T: ?Sized> CloneStableDeref for Arc<T> {}
 
 #[cfg(feature = "servo")]
-impl<'de, T: Deserialize<'de>> Deserialize<'de> for Arc<T>
-{
+impl<'de, T: Deserialize<'de>> Deserialize<'de> for Arc<T> {
     fn deserialize<D>(deserializer: D) -> Result<Arc<T>, D::Error>
     where
         D: ::serde::de::Deserializer<'de>,
     {
         T::deserialize(deserializer).map(Arc::new)
     }
 }
 
 #[cfg(feature = "servo")]
-impl<T: Serialize> Serialize for Arc<T>
-{
+impl<T: Serialize> Serialize for Arc<T> {
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     where
         S: ::serde::ser::Serializer,
     {
         (**self).serialize(serializer)
     }
 }
 
@@ -521,19 +524,20 @@ fn divide_rounding_up(dividend: usize, d
     (dividend + divisor - 1) / divisor
 }
 
 impl<H, T> Arc<HeaderSlice<H, [T]>> {
     /// Creates an Arc for a HeaderSlice using the given header struct and
     /// iterator to generate the slice. The resulting Arc will be fat.
     #[inline]
     pub fn from_header_and_iter<I>(header: H, mut items: I) -> Self
-        where I: Iterator<Item=T> + ExactSizeIterator
+    where
+        I: Iterator<Item = T> + ExactSizeIterator,
     {
-        use ::std::mem::size_of;
+        use std::mem::size_of;
         assert_ne!(size_of::<T>(), 0, "Need to think about ZST");
 
         // Compute the required size for the allocation.
         let num_items = items.len();
         let size = {
             // First, determine the alignment of a hypothetical pointer to a
             // HeaderSlice.
             let fake_slice_ptr_align: usize = mem::align_of::<ArcInner<HeaderSlice<H, [T; 1]>>>();
@@ -587,28 +591,42 @@ impl<H, T> Arc<HeaderSlice<H, [T]>> {
             // Write the data.
             //
             // Note that any panics here (i.e. from the iterator) are safe, since
             // we'll just leak the uninitialized memory.
             ptr::write(&mut ((*ptr).count), atomic::AtomicUsize::new(1));
             ptr::write(&mut ((*ptr).data.header), header);
             let mut current: *mut T = &mut (*ptr).data.slice[0];
             for _ in 0..num_items {
-                ptr::write(current, items.next().expect("ExactSizeIterator over-reported length"));
+                ptr::write(
+                    current,
+                    items
+                        .next()
+                        .expect("ExactSizeIterator over-reported length"),
+                );
                 current = current.offset(1);
             }
-            assert!(items.next().is_none(), "ExactSizeIterator under-reported length");
+            assert!(
+                items.next().is_none(),
+                "ExactSizeIterator under-reported length"
+            );
 
             // We should have consumed the buffer exactly.
             debug_assert_eq!(current as *mut u8, buffer.offset(size as isize));
         }
 
         // Return the fat Arc.
-        assert_eq!(size_of::<Self>(), size_of::<usize>() * 2, "The Arc will be fat");
-        Arc { p: NonZeroPtrMut::new(ptr) }
+        assert_eq!(
+            size_of::<Self>(),
+            size_of::<usize>() * 2,
+            "The Arc will be fat"
+        );
+        Arc {
+            p: NonZeroPtrMut::new(ptr),
+        }
     }
 
     #[inline]
     unsafe fn allocate_buffer<W>(size: usize) -> *mut u8 {
         let words_to_allocate = divide_rounding_up(size, mem::size_of::<W>());
         let mut vec = Vec::<W>::with_capacity(words_to_allocate);
         vec.set_len(words_to_allocate);
         Box::into_raw(vec.into_boxed_slice()) as *mut W as *mut u8
@@ -642,37 +660,36 @@ pub struct ThinArc<H: 'static, T: 'stati
 }
 
 unsafe impl<H: Sync + Send, T: Sync + Send> Send for ThinArc<H, T> {}
 unsafe impl<H: Sync + Send, T: Sync + Send> Sync for ThinArc<H, T> {}
 
 // Synthesize a fat pointer from a thin pointer.
 //
 // See the comment around the analogous operation in from_header_and_iter.
-fn thin_to_thick<H, T>(thin: *mut ArcInner<HeaderSliceWithLength<H, [T; 1]>>)
-    -> *mut ArcInner<HeaderSliceWithLength<H, [T]>>
-{
+fn thin_to_thick<H, T>(
+    thin: *mut ArcInner<HeaderSliceWithLength<H, [T; 1]>>,
+) -> *mut ArcInner<HeaderSliceWithLength<H, [T]>> {
     let len = unsafe { (*thin).data.header.length };
-    let fake_slice: *mut [T] = unsafe {
-        slice::from_raw_parts_mut(thin as *mut T, len)
-    };
+    let fake_slice: *mut [T] = unsafe { slice::from_raw_parts_mut(thin as *mut T, len) };
 
     fake_slice as *mut ArcInner<HeaderSliceWithLength<H, [T]>>
 }
 
 impl<H: 'static, T: 'static> ThinArc<H, T> {
     /// Temporarily converts |self| into a bonafide Arc and exposes it to the
     /// provided callback. The refcount is not modified.
     #[inline]
     pub fn with_arc<F, U>(&self, f: F) -> U
-        where F: FnOnce(&Arc<HeaderSliceWithLength<H, [T]>>) -> U
+    where
+        F: FnOnce(&Arc<HeaderSliceWithLength<H, [T]>>) -> U,
     {
         // Synthesize transient Arc, which never touches the refcount of the ArcInner.
         let transient = NoDrop::new(Arc {
-            p: NonZeroPtrMut::new(thin_to_thick(self.ptr))
+            p: NonZeroPtrMut::new(thin_to_thick(self.ptr)),
         });
 
         // Expose the transient Arc to the callback, which may clone it if it wants.
         let result = f(&transient);
 
         // Forget the transient Arc to leave the refcount untouched.
         // XXXManishearth this can be removed when unions stabilize,
         // since then NoDrop becomes zero overhead
@@ -713,46 +730,45 @@ impl<H: 'static, T: 'static> Drop for Th
     }
 }
 
 impl<H: 'static, T: 'static> Arc<HeaderSliceWithLength<H, [T]>> {
     /// Converts an Arc into a ThinArc. This consumes the Arc, so the refcount
     /// is not modified.
     #[inline]
     pub fn into_thin(a: Self) -> ThinArc<H, T> {
-        assert_eq!(a.header.length, a.slice.len(),
-                "Length needs to be correct for ThinArc to work");
+        assert_eq!(
+            a.header.length,
+            a.slice.len(),
+            "Length needs to be correct for ThinArc to work"
+        );
         let fat_ptr: *mut ArcInner<HeaderSliceWithLength<H, [T]>> = a.ptr();
         mem::forget(a);
         let thin_ptr = fat_ptr as *mut [usize] as *mut usize;
         ThinArc {
-            ptr: thin_ptr as *mut ArcInner<HeaderSliceWithLength<H, [T; 1]>>
+            ptr: thin_ptr as *mut ArcInner<HeaderSliceWithLength<H, [T; 1]>>,
         }
     }
 
     /// Converts a ThinArc into an Arc. This consumes the ThinArc, so the refcount
     /// is not modified.
     #[inline]
     pub fn from_thin(a: ThinArc<H, T>) -> Self {
         let ptr = thin_to_thick(a.ptr);
         mem::forget(a);
         Arc {
-            p: NonZeroPtrMut::new(ptr)
+            p: NonZeroPtrMut::new(ptr),
         }
     }
 }
 
 impl<H: PartialEq + 'static, T: PartialEq + 'static> PartialEq for ThinArc<H, T> {
     #[inline]
     fn eq(&self, other: &ThinArc<H, T>) -> bool {
-        ThinArc::with_arc(self, |a| {
-            ThinArc::with_arc(other, |b| {
-                *a == *b
-            })
-        })
+        ThinArc::with_arc(self, |a| ThinArc::with_arc(other, |b| *a == *b))
     }
 }
 
 impl<H: Eq + 'static, T: Eq + 'static> Eq for ThinArc<H, T> {}
 
 /// An Arc, except it holds a pointer to the T instead of to the
 /// entire ArcInner.
 ///
@@ -788,21 +804,22 @@ impl<T: 'static> Clone for RawOffsetArc<
     #[inline]
     fn clone(&self) -> Self {
         Arc::into_raw_offset(self.clone_arc())
     }
 }
 
 impl<T: 'static> Drop for RawOffsetArc<T> {
     fn drop(&mut self) {
-        let _ = Arc::from_raw_offset(RawOffsetArc { ptr: self.ptr.clone() });
+        let _ = Arc::from_raw_offset(RawOffsetArc {
+            ptr: self.ptr.clone(),
+        });
     }
 }
 
-
 impl<T: fmt::Debug + 'static> fmt::Debug for RawOffsetArc<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         fmt::Debug::fmt(&**self, f)
     }
 }
 
 impl<T: PartialEq> PartialEq for RawOffsetArc<T> {
     fn eq(&self, other: &RawOffsetArc<T>) -> bool {
@@ -814,17 +831,18 @@ impl<T: PartialEq> PartialEq for RawOffs
     }
 }
 
 impl<T: 'static> RawOffsetArc<T> {
     /// Temporarily converts |self| into a bonafide Arc and exposes it to the
     /// provided callback. The refcount is not modified.
     #[inline]
     pub fn with_arc<F, U>(&self, f: F) -> U
-        where F: FnOnce(&Arc<T>) -> U
+    where
+        F: FnOnce(&Arc<T>) -> U,
     {
         // Synthesize transient Arc, which never touches the refcount of the ArcInner.
         let transient = unsafe { NoDrop::new(Arc::from_raw(self.ptr.ptr())) };
 
         // Expose the transient Arc to the callback, which may clone it if it wants.
         let result = f(&transient);
 
         // Forget the transient Arc to leave the refcount untouched.
@@ -834,17 +852,20 @@ impl<T: 'static> RawOffsetArc<T> {
 
         // Forward the result.
         result
     }
 
     /// If uniquely owned, provide a mutable reference
     /// Else create a copy, and mutate that
     #[inline]
-    pub fn make_mut(&mut self) -> &mut T where T: Clone {
+    pub fn make_mut(&mut self) -> &mut T
+    where
+        T: Clone,
+    {
         unsafe {
             // extract the RawOffsetArc as an owned variable
             let this = ptr::read(self);
             // treat it as a real Arc
             let mut arc = Arc::from_raw_offset(this);
             // obtain the mutable reference. Cast away the lifetime
             // This may mutate `arc`
             let ret = Arc::make_mut(&mut arc) as *mut _;
@@ -926,17 +947,21 @@ impl<'a, T> ArcBorrow<'a, T> {
     /// For constructing from a reference known to be Arc-backed,
     /// e.g. if we obtain such a reference over FFI
     #[inline]
     pub unsafe fn from_ref(r: &'a T) -> Self {
         ArcBorrow(r)
     }
 
     #[inline]
-    pub fn with_arc<F, U>(&self, f: F) -> U where F: FnOnce(&Arc<T>) -> U, T: 'static {
+    pub fn with_arc<F, U>(&self, f: F) -> U
+    where
+        F: FnOnce(&Arc<T>) -> U,
+        T: 'static,
+    {
         // Synthesize transient Arc, which never touches the refcount.
         let transient = unsafe { NoDrop::new(Arc::from_raw(self.0)) };
 
         // Expose the transient Arc to the callback, which may clone it if it wants.
         let result = f(&transient);
 
         // Forget the transient Arc to leave the refcount untouched.
         // XXXManishearth this can be removed when unions stabilize,
@@ -965,17 +990,19 @@ mod tests {
     use std::sync::atomic::Ordering::{Acquire, SeqCst};
     use super::{Arc, HeaderWithLength, ThinArc};
 
     #[derive(PartialEq)]
     struct Canary(*mut atomic::AtomicUsize);
 
     impl Drop for Canary {
         fn drop(&mut self) {
-            unsafe { (*self.0).fetch_add(1, SeqCst); }
+            unsafe {
+                (*self.0).fetch_add(1, SeqCst);
+            }
         }
     }
 
     #[test]
     fn slices_and_thin() {
         let mut canary = atomic::AtomicUsize::new(0);
         let c = Canary(&mut canary as *mut atomic::AtomicUsize);
         let v = vec![5, 6];
--- a/servo/components/style/animation.rs
+++ b/servo/components/style/animation.rs
@@ -98,43 +98,43 @@ impl KeyframesAnimationState {
             // needed for the correct handling of animation-fill-mode.
             if *current >= *max {
                 return false;
             }
         }
 
         // Update the next iteration direction if applicable.
         match self.direction {
-            AnimationDirection::Alternate |
-            AnimationDirection::AlternateReverse => {
+            AnimationDirection::Alternate | AnimationDirection::AlternateReverse => {
                 self.current_direction = match self.current_direction {
                     AnimationDirection::Normal => AnimationDirection::Reverse,
                     AnimationDirection::Reverse => AnimationDirection::Normal,
                     _ => unreachable!(),
                 };
-            }
+            },
             _ => {},
         }
 
         true
     }
 
     /// Updates the appropiate state from other animation.
     ///
     /// This happens when an animation is re-submitted to layout, presumably
     /// because of an state change.
     ///
     /// There are some bits of state we can't just replace, over all taking in
     /// account times, so here's that logic.
-    pub fn update_from_other(&mut self,
-                             other: &Self,
-                             timer: &Timer) {
+    pub fn update_from_other(&mut self, other: &Self, timer: &Timer) {
         use self::KeyframesRunningState::*;
 
-        debug!("KeyframesAnimationState::update_from_other({:?}, {:?})", self, other);
+        debug!(
+            "KeyframesAnimationState::update_from_other({:?}, {:?})",
+            self, other
+        );
 
         // NB: We shall not touch the started_at field, since we don't want to
         // restart the animation.
         let old_started_at = self.started_at;
         let old_duration = self.duration;
         let old_direction = self.current_direction;
         let old_running_state = self.running_state.clone();
         let old_iteration_state = self.iteration_state.clone();
@@ -144,32 +144,35 @@ impl KeyframesAnimationState {
 
         // If we're unpausing the animation, fake the start time so we seem to
         // restore it.
         //
         // If the animation keeps paused, keep the old value.
         //
         // If we're pausing the animation, compute the progress value.
         match (&mut self.running_state, old_running_state) {
-            (&mut Running, Paused(progress))
-                => new_started_at = timer.seconds() - (self.duration * progress),
-            (&mut Paused(ref mut new), Paused(old))
-                => *new = old,
-            (&mut Paused(ref mut progress), Running)
-                => *progress = (timer.seconds() - old_started_at) / old_duration,
+            (&mut Running, Paused(progress)) => {
+                new_started_at = timer.seconds() - (self.duration * progress)
+            },
+            (&mut Paused(ref mut new), Paused(old)) => *new = old,
+            (&mut Paused(ref mut progress), Running) => {
+                *progress = (timer.seconds() - old_started_at) / old_duration
+            },
             _ => {},
         }
 
         // Don't update the iteration count, just the iteration limit.
         // TODO: see how changing the limit affects rendering in other browsers.
         // We might need to keep the iteration count even when it's infinite.
         match (&mut self.iteration_state, old_iteration_state) {
-            (&mut KeyframesIterationState::Finite(ref mut iters, _), KeyframesIterationState::Finite(old_iters, _))
-                => *iters = old_iters,
-            _ => {}
+            (
+                &mut KeyframesIterationState::Finite(ref mut iters, _),
+                KeyframesIterationState::Finite(old_iters, _),
+            ) => *iters = old_iters,
+            _ => {},
         }
 
         self.current_direction = old_direction;
         self.started_at = new_started_at;
     }
 
     #[inline]
     fn is_paused(&self) -> bool {
@@ -237,17 +240,16 @@ impl Animation {
     pub fn is_transition(&self) -> bool {
         match *self {
             Animation::Transition(..) => true,
             Animation::Keyframes(..) => false,
         }
     }
 }
 
-
 /// A single animation frame of a single property.
 #[derive(Clone, Debug)]
 pub struct AnimationFrame {
     /// A description of the property animation that is occurring.
     pub property_animation: PropertyAnimation,
     /// The duration of the animation. This is either relative in the keyframes
     /// case (a number between 0 and 1), or absolute in the transition case.
     pub duration: f64,
@@ -279,56 +281,53 @@ impl PropertyAnimation {
         let mut result = vec![];
         let box_style = new_style.get_box();
         let transition_property = box_style.transition_property_at(transition_index);
         let timing_function = box_style.transition_timing_function_mod(transition_index);
         let duration = box_style.transition_duration_mod(transition_index);
 
         match transition_property {
             TransitionProperty::Unsupported(_) => result,
-            TransitionProperty::Shorthand(ref shorthand_id) => {
-                shorthand_id.longhands().filter_map(|longhand| {
+            TransitionProperty::Shorthand(ref shorthand_id) => shorthand_id
+                .longhands()
+                .filter_map(|longhand| {
                     PropertyAnimation::from_longhand(
                         longhand,
                         timing_function,
                         duration,
                         old_style,
                         new_style,
                     )
-                }).collect()
-            }
+                })
+                .collect(),
             TransitionProperty::Longhand(longhand_id) => {
                 let animation = PropertyAnimation::from_longhand(
                     longhand_id,
                     timing_function,
                     duration,
                     old_style,
                     new_style,
                 );
 
                 if let Some(animation) = animation {
                     result.push(animation);
                 }
                 result
-            }
+            },
         }
     }
 
     fn from_longhand(
         longhand: LonghandId,
         timing_function: TimingFunction,
         duration: Time,
         old_style: &ComputedValues,
         new_style: &ComputedValues,
     ) -> Option<PropertyAnimation> {
-        let animated_property = AnimatedProperty::from_longhand(
-            longhand,
-            old_style,
-            new_style,
-        )?;
+        let animated_property = AnimatedProperty::from_longhand(longhand, old_style, new_style)?;
 
         let property_animation = PropertyAnimation {
             property: animated_property,
             timing_function: timing_function,
             duration: duration,
         };
 
         if property_animation.does_animate() {
@@ -393,52 +392,57 @@ impl PropertyAnimation {
 /// Returns true if any animations were kicked off and false otherwise.
 #[cfg(feature = "servo")]
 pub fn start_transitions_if_applicable(
     new_animations_sender: &Sender<Animation>,
     opaque_node: OpaqueNode,
     old_style: &ComputedValues,
     new_style: &mut Arc<ComputedValues>,
     timer: &Timer,
-    possibly_expired_animations: &[PropertyAnimation]
+    possibly_expired_animations: &[PropertyAnimation],
 ) -> bool {
     let mut had_animations = false;
     for i in 0..new_style.get_box().transition_property_count() {
         // Create any property animations, if applicable.
-        let property_animations = PropertyAnimation::from_transition(i,
-                                                                     old_style,
-                                                                     Arc::make_mut(new_style));
+        let property_animations =
+            PropertyAnimation::from_transition(i, old_style, Arc::make_mut(new_style));
         for property_animation in property_animations {
             // Set the property to the initial value.
             //
             // NB: get_mut is guaranteed to succeed since we called make_mut()
             // above.
             property_animation.update(Arc::get_mut(new_style).unwrap(), 0.0);
 
             // Per [1], don't trigger a new transition if the end state for that
             // transition is the same as that of a transition that's already
             // running on the same node.
             //
             // [1]: https://drafts.csswg.org/css-transitions/#starting
-            if possibly_expired_animations.iter().any(|animation| {
-                animation.has_the_same_end_value_as(&property_animation)
-            }) {
-                continue
+            if possibly_expired_animations
+                .iter()
+                .any(|animation| animation.has_the_same_end_value_as(&property_animation))
+            {
+                continue;
             }
 
             // Kick off the animation.
             let box_style = new_style.get_box();
             let now = timer.seconds();
-            let start_time =
-                now + (box_style.transition_delay_mod(i).seconds() as f64);
+            let start_time = now + (box_style.transition_delay_mod(i).seconds() as f64);
             new_animations_sender
-                .send(Animation::Transition(opaque_node, start_time, AnimationFrame {
-                    duration: box_style.transition_duration_mod(i).seconds() as f64,
-                    property_animation: property_animation,
-                }, /* is_expired = */ false)).unwrap();
+                .send(Animation::Transition(
+                    opaque_node,
+                    start_time,
+                    AnimationFrame {
+                        duration: box_style.transition_duration_mod(i).seconds() as f64,
+                        property_animation: property_animation,
+                    },
+                    /* is_expired = */ false,
+                ))
+                .unwrap();
 
             had_animations = true;
         }
     }
 
     had_animations
 }
 
@@ -449,51 +453,53 @@ fn compute_style_for_animation_step<E>(
     style_from_cascade: &Arc<ComputedValues>,
     font_metrics_provider: &FontMetricsProvider,
 ) -> Arc<ComputedValues>
 where
     E: TElement,
 {
     match step.value {
         KeyframesStepValue::ComputedValues => style_from_cascade.clone(),
-        KeyframesStepValue::Declarations { block: ref declarations } => {
+        KeyframesStepValue::Declarations {
+            block: ref declarations,
+        } => {
             let guard = declarations.read_with(context.guards.author);
 
             let iter = || {
                 // It's possible to have !important properties in keyframes
                 // so we have to filter them out.
                 // See the spec issue https://github.com/w3c/csswg-drafts/issues/1824
                 // Also we filter our non-animatable properties.
-                guard.normal_declaration_iter()
-                     .filter(|declaration| declaration.is_animatable())
-                     .map(|decl| (decl, CascadeLevel::Animations))
+                guard
+                    .normal_declaration_iter()
+                    .filter(|declaration| declaration.is_animatable())
+                    .map(|decl| (decl, CascadeLevel::Animations))
             };
 
             // This currently ignores visited styles, which seems acceptable,
             // as existing browsers don't appear to animate visited styles.
-            let computed =
-                properties::apply_declarations::<E, _, _>(
-                    context.stylist.device(),
-                    /* pseudo = */ None,
-                    previous_style.rules(),
-                    &context.guards,
-                    iter,
-                    Some(previous_style),
-                    Some(previous_style),
-                    Some(previous_style),
-                    /* visited_style = */ None,
-                    font_metrics_provider,
-                    CascadeFlags::empty(),
-                    context.quirks_mode(),
-                    /* rule_cache = */ None,
-                    &mut Default::default(),
-                    /* element = */ None,
-                );
+            let computed = properties::apply_declarations::<E, _, _>(
+                context.stylist.device(),
+                /* pseudo = */ None,
+                previous_style.rules(),
+                &context.guards,
+                iter,
+                Some(previous_style),
+                Some(previous_style),
+                Some(previous_style),
+                /* visited_style = */ None,
+                font_metrics_provider,
+                CascadeFlags::empty(),
+                context.quirks_mode(),
+                /* rule_cache = */ None,
+                &mut Default::default(),
+                /* element = */ None,
+            );
             computed
-        }
+        },
     }
 }
 
 /// Triggers animations for a given node looking at the animation property
 /// values.
 pub fn maybe_start_animations(
     context: &SharedStyleContext,
     new_animations_sender: &Sender<Animation>,
@@ -502,23 +508,23 @@ pub fn maybe_start_animations(
 ) -> bool {
     let mut had_animations = false;
 
     let box_style = new_style.get_box();
     for (i, name) in box_style.animation_name_iter().enumerate() {
         let name = if let Some(atom) = name.as_atom() {
             atom
         } else {
-            continue
+            continue;
         };
 
         debug!("maybe_start_animations: name={}", name);
         let total_duration = box_style.animation_duration_mod(i).seconds();
         if total_duration == 0. {
-            continue
+            continue;
         }
 
         if let Some(ref anim) = context.stylist.get_animation(name) {
             debug!("maybe_start_animations: animation {} found", name);
 
             // If this animation doesn't have any keyframe, we can just continue
             // without submitting it to the compositor, since both the first and
             // the second keyframes would be synthetised from the computed
@@ -534,192 +540,223 @@ pub fn maybe_start_animations(
             let iteration_state = match box_style.animation_iteration_count_mod(i) {
                 AnimationIterationCount::Infinite => KeyframesIterationState::Infinite,
                 AnimationIterationCount::Number(n) => KeyframesIterationState::Finite(0.0, n),
             };
 
             let animation_direction = box_style.animation_direction_mod(i);
 
             let initial_direction = match animation_direction {
-                AnimationDirection::Normal |
-                AnimationDirection::Alternate => AnimationDirection::Normal,
-                AnimationDirection::Reverse |
-                AnimationDirection::AlternateReverse => AnimationDirection::Reverse,
+                AnimationDirection::Normal | AnimationDirection::Alternate => {
+                    AnimationDirection::Normal
+                },
+                AnimationDirection::Reverse | AnimationDirection::AlternateReverse => {
+                    AnimationDirection::Reverse
+                },
             };
 
             let running_state = match box_style.animation_play_state_mod(i) {
                 AnimationPlayState::Paused => KeyframesRunningState::Paused(0.),
                 AnimationPlayState::Running => KeyframesRunningState::Running,
             };
 
-
             new_animations_sender
-                .send(Animation::Keyframes(node, name.clone(), KeyframesAnimationState {
-                    started_at: animation_start,
-                    duration: duration as f64,
-                    delay: delay as f64,
-                    iteration_state: iteration_state,
-                    running_state: running_state,
-                    direction: animation_direction,
-                    current_direction: initial_direction,
-                    expired: false,
-                    cascade_style: new_style.clone(),
-                })).unwrap();
+                .send(Animation::Keyframes(
+                    node,
+                    name.clone(),
+                    KeyframesAnimationState {
+                        started_at: animation_start,
+                        duration: duration as f64,
+                        delay: delay as f64,
+                        iteration_state: iteration_state,
+                        running_state: running_state,
+                        direction: animation_direction,
+                        current_direction: initial_direction,
+                        expired: false,
+                        cascade_style: new_style.clone(),
+                    },
+                ))
+                .unwrap();
             had_animations = true;
         }
     }
 
     had_animations
 }
 
 /// Updates a given computed style for a given animation frame. Returns a bool
 /// representing if the style was indeed updated.
-pub fn update_style_for_animation_frame(mut new_style: &mut Arc<ComputedValues>,
-                                        now: f64,
-                                        start_time: f64,
-                                        frame: &AnimationFrame) -> bool {
+pub fn update_style_for_animation_frame(
+    mut new_style: &mut Arc<ComputedValues>,
+    now: f64,
+    start_time: f64,
+    frame: &AnimationFrame,
+) -> bool {
     let mut progress = (now - start_time) / frame.duration;
     if progress > 1.0 {
         progress = 1.0
     }
 
     if progress <= 0.0 {
         return false;
     }
 
-    frame.property_animation.update(Arc::make_mut(&mut new_style), progress);
+    frame
+        .property_animation
+        .update(Arc::make_mut(&mut new_style), progress);
 
     true
 }
 /// Updates a single animation and associated style based on the current time.
 pub fn update_style_for_animation<E>(
     context: &SharedStyleContext,
     animation: &Animation,
     style: &mut Arc<ComputedValues>,
     font_metrics_provider: &FontMetricsProvider,
-)
-where
+) where
     E: TElement,
 {
     debug!("update_style_for_animation: entering");
     debug_assert!(!animation.is_expired());
 
     match *animation {
         Animation::Transition(_, start_time, ref frame, _) => {
             debug!("update_style_for_animation: transition found");
             let now = context.timer.seconds();
             let mut new_style = (*style).clone();
-            let updated_style = update_style_for_animation_frame(&mut new_style,
-                                                                 now, start_time,
-                                                                 frame);
+            let updated_style =
+                update_style_for_animation_frame(&mut new_style, now, start_time, frame);
             if updated_style {
                 *style = new_style
             }
-        }
+        },
         Animation::Keyframes(_, ref name, ref state) => {
-            debug!("update_style_for_animation: animation found: \"{}\", {:?}", name, state);
+            debug!(
+                "update_style_for_animation: animation found: \"{}\", {:?}",
+                name, state
+            );
             let duration = state.duration;
             let started_at = state.started_at;
 
             let now = match state.running_state {
                 KeyframesRunningState::Running => context.timer.seconds(),
                 KeyframesRunningState::Paused(progress) => started_at + duration * progress,
             };
 
             let animation = match context.stylist.get_animation(name) {
                 None => {
                     warn!("update_style_for_animation: Animation {:?} not found", name);
                     return;
-                }
+                },
                 Some(animation) => animation,
             };
 
             debug_assert!(!animation.steps.is_empty());
 
             let maybe_index = style
                 .get_box()
                 .animation_name_iter()
                 .position(|animation_name| Some(name) == animation_name.as_atom());
 
             let index = match maybe_index {
                 Some(index) => index,
                 None => {
-                    warn!("update_style_for_animation: Animation {:?} not found in style", name);
+                    warn!(
+                        "update_style_for_animation: Animation {:?} not found in style",
+                        name
+                    );
                     return;
-                }
+                },
             };
 
             let total_duration = style.get_box().animation_duration_mod(index).seconds() as f64;
             if total_duration == 0. {
-                debug!("update_style_for_animation: zero duration for animation {:?}", name);
+                debug!(
+                    "update_style_for_animation: zero duration for animation {:?}",
+                    name
+                );
                 return;
             }
 
             let mut total_progress = (now - started_at) / total_duration;
             if total_progress < 0. {
                 warn!("Negative progress found for animation {:?}", name);
                 r