Merge mozilla-central to mozilla-inbound
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 01 Mar 2017 16:39:27 +0100
changeset 345319 33c9d4c02376826733a4a35687e1e8be21b58f4d
parent 345318 831f13e13f320430af31fa37553fadddfa898585 (current diff)
parent 345277 34c6c2f302e7b48e3ad2cec575cbd34d423a9d32 (diff)
child 345320 e297bafab4ae9d6320bff24d9aa02202c1a33e10
push id31436
push userkwierso@gmail.com
push dateThu, 02 Mar 2017 01:18:52 +0000
treeherdermozilla-central@e91de6fb2b3d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to mozilla-inbound
devtools/server/actors/highlighters/css-grid.js
js/src/vm/SelfHosting.cpp
taskcluster/taskgraph/util/scriptworker.py
testing/mozharness/mozharness/mozilla/repo_manupulation.py
third_party/rust/cssparser/src/macros/match_byte.rs
third_party/rust/cssparser/src/macros/mod.rs
--- a/.clang-format-ignore
+++ b/.clang-format-ignore
@@ -1,15 +1,18 @@
 ^build/clang-plugin/tests/.*
 ^config/gcc-stl-wrapper.template.h
 ^config/msvc-stl-wrapper.template.h
 ^js/src/jsapi-tests/.*
 ^widget/android/GeneratedJNINatives.h
 ^widget/android/GeneratedJNIWrappers.cpp
 ^widget/android/GeneratedJNIWrappers.h
+^widget/android/fennec/FennecJNINatives.h
+^widget/android/fennec/FennecJNIWrappers.cpp
+^widget/android/fennec/FennecJNIWrappers.h
 
 # Generated from ./tools/rewriting/ThirdPartyPaths.txt
 # awk '{print "^"$1".*"}' ./tools/rewriting/ThirdPartyPaths.txt
 ^browser/components/translation/cld2/.*
 ^build/stlport/.*
 ^db/sqlite3/src/.*
 ^dom/media/platforms/ffmpeg/libav.*
 ^extensions/spellcheck/hunspell/src/.*
--- a/.eslintignore
+++ b/.eslintignore
@@ -82,18 +82,16 @@ devtools/client/commandline/**
 devtools/client/debugger/**
 devtools/client/framework/**
 !devtools/client/framework/selection.js
 !devtools/client/framework/target*
 !devtools/client/framework/toolbox*
 devtools/client/inspector/markup/test/doc_markup_events_*.html
 devtools/client/inspector/rules/test/doc_media_queries.html
 devtools/client/memory/test/chrome/*.html
-devtools/client/netmonitor/test/**
-devtools/client/netmonitor/har/test/**
 devtools/client/performance/components/test/test_jit_optimizations_01.html
 devtools/client/projecteditor/**
 devtools/client/responsive.html/test/browser/touch.html
 devtools/client/responsivedesign/**
 devtools/client/scratchpad/**
 devtools/client/shadereditor/**
 devtools/client/shared/*.jsm
 devtools/client/shared/components/reps/reps.js
--- a/browser/base/content/test/webextensions/head.js
+++ b/browser/base/content/test/webextensions/head.js
@@ -114,16 +114,47 @@ function is_visible(element) {
   // Hiding a parent element will hide all its children
   if (element.parentNode != element.ownerDocument)
     return is_visible(element.parentNode);
 
   return true;
 }
 
 /**
+ * Check the contents of an individual permission string.
+ * This function is fairly specific to the use here and probably not
+ * suitable for re-use elsewhere...
+ *
+ * @param {string} string
+ *        The string value to check (i.e., pulled from the DOM)
+ * @param {string} key
+ *        The key in browser.properties for the localized string to
+ *        compare with.
+ * @param {string|null} param
+ *        Optional string to substitute for %S in the localized string.
+ * @param {string} msg
+ *        The message to be emitted as part of the actual test.
+ */
+function checkPermissionString(string, key, param, msg) {
+  let localizedString = param ?
+                        gBrowserBundle.formatStringFromName(key, [param], 1) :
+                        gBrowserBundle.GetStringFromName(key);
+
+  // If this is a parameterized string and the parameter isn't given,
+  // just do a simple comparison of the text before and after the %S
+  if (localizedString.includes("%S")) {
+    let i = localizedString.indexOf("%S");
+    ok(string.startsWith(localizedString.slice(0, i)), msg);
+    ok(string.endsWith(localizedString.slice(i + 2)), msg);
+  } else {
+    is(string, localizedString, msg);
+  }
+}
+
+/**
  * Test that install-time permission prompts work for a given
  * installation method.
  *
  * @param {Function} installFn
  *        Callable that takes the name of an xpi file to install and
  *        starts to install it.  Should return a Promise that resolves
  *        when the install is finished or rejects if the install is canceled.
  *
@@ -191,17 +222,34 @@ async function testInstallMethod(install
       // The icon should come from the extension, don't bother with the precise
       // path, just make sure we've got a jar url pointing to the right path
       // inside the jar.
       ok(icon.startsWith("jar:file://"), "Icon is a jar url");
       ok(icon.endsWith("/icon.png"), "Icon is icon.png inside a jar");
 
       is(header.getAttribute("hidden"), "", "Permission list header is visible");
       is(ul.childElementCount, 5, "Permissions list has 5 entries");
-      // Real checking of the contents here is deferred until bug 1316996 lands
+
+      checkPermissionString(ul.children[0].textContent,
+                            "webextPerms.hostDescription.wildcard",
+                            "wildcard.domain",
+                            "First permission is domain permission");
+      checkPermissionString(ul.children[1].textContent,
+                            "webextPerms.hostDescription.oneSite",
+                            "singlehost.domain",
+                            "Second permission is single host permission");
+      checkPermissionString(ul.children[2].textContent,
+                            "webextPerms.description.nativeMessaging", null,
+                            "Third permission is nativeMessaging");
+      checkPermissionString(ul.children[3].textContent,
+                            "webextPerms.description.tabs", null,
+                            "Fourth permission is tabs");
+      checkPermissionString(ul.children[4].textContent,
+                            "webextPerms.description.history", null,
+                            "Fifth permission is history");
     } else if (filename == NO_PERMS_XPI) {
       // This extension has no icon, it should have the default
       ok(isDefaultIcon(icon), "Icon is the default extension icon");
 
       is(header.getAttribute("hidden"), "true", "Permission list header is hidden");
       is(ul.childElementCount, 0, "Permissions list has 0 entries");
     }
 
--- a/browser/components/preferences/in-content/applications.js
+++ b/browser/components/preferences/in-content/applications.js
@@ -1343,19 +1343,20 @@ var gApplicationsPane = {
     var menu =
       document.getAnonymousElementByAttribute(typeItem, "class", "actionsMenu");
     var menuPopup = menu.menupopup;
 
     // Clear out existing items.
     while (menuPopup.hasChildNodes())
       menuPopup.removeChild(menuPopup.lastChild);
 
+    let internalMenuItem;
     // Add the "Preview in Firefox" option for optional internal handlers.
     if (handlerInfo instanceof InternalHandlerInfoWrapper) {
-      let internalMenuItem = document.createElement("menuitem");
+      internalMenuItem = document.createElement("menuitem");
       internalMenuItem.setAttribute("action", Ci.nsIHandlerInfo.handleInternally);
       let label = this._prefsBundle.getFormattedString("previewInApp",
                                                        [this._brandShortName]);
       internalMenuItem.setAttribute("label", label);
       internalMenuItem.setAttribute("tooltiptext", label);
       internalMenuItem.setAttribute(APP_ICON_ATTR_NAME, "ask");
       menuPopup.appendChild(internalMenuItem);
     }
@@ -1387,17 +1388,17 @@ var gApplicationsPane = {
       saveMenuItem.setAttribute("label", label);
       saveMenuItem.setAttribute("tooltiptext", label);
       saveMenuItem.setAttribute(APP_ICON_ATTR_NAME, "save");
       menuPopup.appendChild(saveMenuItem);
     }
 
     // If this is the feed type, add a Live Bookmarks item.
     if (isFeedType(handlerInfo.type)) {
-      let internalMenuItem = document.createElement("menuitem");
+      internalMenuItem = document.createElement("menuitem");
       internalMenuItem.setAttribute("action", Ci.nsIHandlerInfo.handleInternally);
       let label = this._prefsBundle.getFormattedString("addLiveBookmarksInApp",
                                                        [this._brandShortName]);
       internalMenuItem.setAttribute("label", label);
       internalMenuItem.setAttribute("tooltiptext", label);
       internalMenuItem.setAttribute(APP_ICON_ATTR_NAME, "feed");
       menuPopup.appendChild(internalMenuItem);
     }
@@ -1499,17 +1500,21 @@ var gApplicationsPane = {
     // Select the item corresponding to the preferred action.  If the always
     // ask flag is set, it overrides the preferred action.  Otherwise we pick
     // the item identified by the preferred action (when the preferred action
     // is to use a helper app, we have to pick the specific helper app item).
     if (handlerInfo.alwaysAskBeforeHandling)
       menu.selectedItem = askMenuItem;
     else switch (handlerInfo.preferredAction) {
       case Ci.nsIHandlerInfo.handleInternally:
-        menu.selectedItem = internalMenuItem;
+        if (internalMenuItem) {
+          menu.selectedItem = internalMenuItem;
+        } else {
+          Cu.reportError("No menu item defined to set!")
+        }
         break;
       case Ci.nsIHandlerInfo.useSystemDefault:
         menu.selectedItem = defaultMenuItem;
         break;
       case Ci.nsIHandlerInfo.useHelperApp:
         if (preferredApp)
           menu.selectedItem =
             possibleAppMenuItems.filter(v => v.handlerApp.equals(preferredApp))[0];
--- a/browser/components/preferences/in-content/tests/browser.ini
+++ b/browser/components/preferences/in-content/tests/browser.ini
@@ -1,14 +1,15 @@
 [DEFAULT]
 support-files =
   head.js
   privacypane_tests_perwindow.js
   site_data_test.html
 
+[browser_applications_selection.js]
 [browser_advanced_siteData.js]
 [browser_advanced_update.js]
 skip-if = !updater
 [browser_basic_rebuild_fonts_test.js]
 [browser_bug410900.js]
 [browser_bug705422.js]
 [browser_bug731866.js]
 [browser_bug795764_cachedisabled.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/preferences/in-content/tests/browser_applications_selection.js
@@ -0,0 +1,79 @@
+var win;
+var feedItem;
+var container;
+
+SimpleTest.requestCompleteLog();
+
+add_task(function* setup() {
+  yield openPreferencesViaOpenPreferencesAPI("applications", null, {leaveOpen: true});
+  info("Preferences page opened on the applications pane.");
+
+  registerCleanupFunction(() => {
+    gBrowser.removeCurrentTab();
+  });
+});
+
+add_task(function* getFeedItem() {
+  win = gBrowser.selectedBrowser.contentWindow;
+
+  container = win.document.getElementById("handlersView");
+  feedItem = container.querySelector("richlistitem[type='application/vnd.mozilla.maybe.feed']");
+  Assert.ok(feedItem, "feedItem is present in handlersView.");
+})
+
+add_task(function* selectInternalOptionForFeed() {
+  // Select the item.
+  feedItem.scrollIntoView();
+  container.selectItem(feedItem);
+  Assert.ok(feedItem.selected, "Should be able to select our item.");
+
+  // Wait for the menu.
+  let list = yield waitForCondition(() =>
+    win.document.getAnonymousElementByAttribute(feedItem, "class", "actionsMenu"));
+  info("Got list after item was selected");
+
+  // Find the "Add Live bookmarks option".
+  let chooseItems = list.getElementsByAttribute("action", Ci.nsIHandlerInfo.handleInternally);
+  Assert.equal(chooseItems.length, 1, "Should only be one action to handle internally");
+
+  // Select the option.
+  let cmdEvent = win.document.createEvent("xulcommandevent");
+  cmdEvent.initCommandEvent("command", true, true, win, 0, false, false, false, false, null);
+  chooseItems[0].dispatchEvent(cmdEvent);
+
+  // Check that we display the correct result.
+  list = yield waitForCondition(() =>
+    win.document.getAnonymousElementByAttribute(feedItem, "class", "actionsMenu"));
+  info("Got list after item was selected");
+  Assert.ok(list.selectedItem, "Should have a selected item.");
+  Assert.equal(list.selectedItem.getAttribute("action"),
+               Ci.nsIHandlerInfo.handleInternally,
+               "Newly selected item should be the expected one.");
+});
+
+// This builds on the previous selectInternalOptionForFeed task.
+add_task(function* reselectInternalOptionForFeed() {
+  // Now select a different option in the list - use the pdf item as that doesn't
+  // need to load any favicons.
+  let anotherItem = container.querySelector("richlistitem[type='application/pdf']");
+
+  container.selectItem(anotherItem);
+
+  // Wait for the menu so that we don't hit race conditions.
+  yield waitForCondition(() =>
+    win.document.getAnonymousElementByAttribute(anotherItem, "class", "actionsMenu"));
+  info("Got list after item was selected");
+
+  // Now select the feed item again, and check what it is displaying.
+  container.selectItem(feedItem);
+
+  let list = yield waitForCondition(() =>
+    win.document.getAnonymousElementByAttribute(feedItem, "class", "actionsMenu"));
+  info("Got list after item was selected");
+
+  Assert.ok(list.selectedItem,
+            "Should have a selected item");
+  Assert.equal(list.selectedItem.getAttribute("action"),
+               Ci.nsIHandlerInfo.handleInternally,
+               "Selected item should still be the same as the previously selected item.");
+});
--- a/browser/locales/search/list.json
+++ b/browser/locales/search/list.json
@@ -93,16 +93,23 @@
     },
     "az": {
       "default": {
         "visibleDefaultEngines": [
           "google", "amazondotcom", "azerdict", "bing", "ddg", "wikipedia-az", "yandex-az"
         ]
       }
     },
+    "be": {
+      "default": {
+        "visibleDefaultEngines": [
+          "yandex-by", "google", "ddg", "wikipedia-be", "wikipedia-be-tarask"
+        ]
+      }
+    },
     "bg": {
       "default": {
         "visibleDefaultEngines": [
           "google", "diribg", "amazondotcom", "ddg", "portalbgdict", "wikipedia-bg"
         ]
       }
     },
     "bn-BD": {
new file mode 100644
--- /dev/null
+++ b/browser/locales/searchplugins/wikipedia-be-tarask.xml
@@ -0,0 +1,19 @@
+<!-- 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/. -->
+
+<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>Вікіпэдыя (be-tarask)</ShortName>
+<Description>Вікіпэдыя, вольная энцыкляпэдыя</Description>
+<InputEncoding>UTF-8</InputEncoding>
+<Image width="16" height="16">resource://search-plugins/images/wikipedia.ico</Image>
+<Url type="application/x-suggestions+json" method="GET" template="https://be-tarask.wikipedia.org/w/api.php">
+  <Param name="action" value="opensearch"/>
+  <Param name="search" value="{searchTerms}"/>
+</Url>
+<Url type="text/html" method="GET" template="https://be-tarask.wikipedia.org/wiki/Спэцыяльныя:Пошук"
+     resultdomain="wikipedia.org" rel="searchform">
+  <Param name="search" value="{searchTerms}"/>
+  <Param name="sourceid" value="Mozilla-search"/>
+</Url>
+</SearchPlugin>
new file mode 100644
--- /dev/null
+++ b/browser/locales/searchplugins/wikipedia-be.xml
@@ -0,0 +1,19 @@
+<!-- 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/. -->
+
+<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>Вікіпедыя (be)</ShortName>
+<Description>Вікіпедыя, свабодная энцыклапедыя</Description>
+<InputEncoding>UTF-8</InputEncoding>
+<Image width="16" height="16">resource://search-plugins/images/wikipedia.ico</Image>
+<Url type="application/x-suggestions+json" method="GET" template="https://be.wikipedia.org/w/api.php">
+  <Param name="action" value="opensearch"/>
+  <Param name="search" value="{searchTerms}"/>
+</Url>
+<Url type="text/html" method="GET" template="https://be.wikipedia.org/wiki/Адмысловае:Search"
+     resultdomain="wikipedia.org" rel="searchform">
+  <Param name="search" value="{searchTerms}"/>
+  <Param name="sourceid" value="Mozilla-search"/>
+</Url>
+</SearchPlugin>
new file mode 100644
--- /dev/null
+++ b/browser/locales/searchplugins/yandex-by.xml
@@ -0,0 +1,22 @@
+<!-- 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/. -->
+
+<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>Яндекс</ShortName>
+<Description>Пошук з дапамогаю Яндекс</Description>
+<InputEncoding>UTF-8</InputEncoding>
+<Image width="16" height="16">data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAB50lEQVQ4T43SvWsacRgH8OcPCITSLRQ6BSRL1gxZTNZQsgYC3QKunVoMnTKFhBQSnDqIUa5gxNbBCgriC4pv50sJ1lIR5SROpRVbz+O4b5/flbvedekJH+557nvfH8chdbvdIFMYPAgBICdqt9uKpmnw8huNRuDnX8J5QKvVgmEYnqiqClmWwZ113kmger0OXdf/Wv6EIb0BTo+AgB94ceDKJ5MJuHPOMwlUqVSwWq1sevQaxqvn0O5l6HdvgaMdV75cLtFoNMC9Xd6JisWiedNiPNuB9l4yZ+1jEvBvuXJBURRwL8YzUT6fx2KxsGHrKdQPCXNW794Bvieu3CLegrsnlM1mMZ/PbfqeH6vToDkvb2+Bx49cuWU2m4G7bUqn0xiPx7ZpqYRf29v4cXyMxf4+tLU1V24ZDAbgbptSqRSGw6HL9OwM37n4bXPTvP6bC7lcDtw9oWQyiX6/b/vMH1XZ2MAoEMDXqytM+QBnLtRqNXAvxjNRPB5Hr9ez9Q8PMfD50OM/2P3FBb7wAc680+mIMri3yzuRJEloNpsmORTCJy7INzd/9stLc7dyIZPJgDvnPJNA0WgU1WrVkxJ/4FgsBu6s804CRSKRh0KhgHK5/F+JRAL8fJBnslA4HH7NHhg8CDnLwm8IYz560xw92AAAAABJRU5ErkJggg==</Image>
+<Url type="application/x-suggestions+json" method="GET" template="https://suggest.yandex.net/suggest-ff.cgi">
+  <Param name="part" value="{searchTerms}"/>
+</Url>
+<Url type="text/html" method="GET" template="https://yandex.by/yandsearch" resultdomain="yandex.by">
+  <MozParam name="clid" condition="purpose" purpose="searchbar"   value="2186618"/>
+  <MozParam name="clid" condition="purpose" purpose="keyword"     value="2186621"/>
+  <MozParam name="clid" condition="purpose" purpose="contextmenu" value="2186623"/>
+  <MozParam name="clid" condition="purpose" purpose="homepage"    value="2186617"/>
+  <MozParam name="clid" condition="purpose" purpose="newtab"      value="2186620"/>
+  <Param    name="text" value="{searchTerms}"/>
+</Url>
+<SearchForm>https://www.yandex.by/</SearchForm>
+</SearchPlugin>
--- a/browser/modules/ExtensionsUI.jsm
+++ b/browser/modules/ExtensionsUI.jsm
@@ -215,33 +215,17 @@ this.ExtensionsUI = {
       result.header = "";
       result.text = bundle.formatStringFromName("webextPerms.updateText", [addonName], 1);
       result.acceptText = bundle.GetStringFromName("webextPerms.updateAccept.label");
       result.acceptKey = bundle.GetStringFromName("webextPerms.updateAccept.accessKey");
     }
 
     let perms = info.permissions || {hosts: [], permissions: []};
 
-    result.msgs = [];
-    for (let permission of perms.permissions) {
-      let key = `webextPerms.description.${permission}`;
-      if (permission == "nativeMessaging") {
-        let brandBundle = Services.strings.createBundle(BRAND_PROPERTIES);
-        let appName = brandBundle.GetStringFromName("brandShortName");
-        result.msgs.push(bundle.formatStringFromName(key, [appName], 1));
-      } else {
-        try {
-          result.msgs.push(bundle.GetStringFromName(key));
-        } catch (err) {
-          // We deliberately do not include all permissions in the prompt.
-          // So if we don't find one then just skip it.
-        }
-      }
-    }
-
+    // First classify our host permissions
     let allUrls = false, wildcards = [], sites = [];
     for (let permission of perms.hosts) {
       if (permission == "<all_urls>") {
         allUrls = true;
         break;
       }
       let match = /^[htps*]+:\/\/([^/]+)\//.exec(permission);
       if (!match) {
@@ -251,16 +235,20 @@ this.ExtensionsUI = {
         allUrls = true;
       } else if (match[1].startsWith("*.")) {
         wildcards.push(match[1].slice(2));
       } else {
         sites.push(match[1]);
       }
     }
 
+    // Format the host permissions.  If we have a wildcard for all urls,
+    // a single string will suffice.  Otherwise, show domain wildcards
+    // first, then individual host permissions.
+    result.msgs = [];
     if (allUrls) {
       result.msgs.push(bundle.GetStringFromName("webextPerms.hostDescription.allUrls"));
     } else {
       // Formats a list of host permissions.  If we have 4 or fewer, display
       // them all, otherwise display the first 3 followed by an item that
       // says "...plus N others"
       function format(list, itemKey, moreKey) {
         function formatItems(items) {
@@ -278,16 +266,40 @@ this.ExtensionsUI = {
       }
 
       format(wildcards, "webextPerms.hostDescription.wildcard",
              "webextPerms.hostDescription.tooManyWildcards");
       format(sites, "webextPerms.hostDescription.oneSite",
              "webextPerms.hostDescription.tooManySites");
     }
 
+    let permissionKey = perm => `webextPerms.description.${perm}`;
+
+    // Next, show the native messaging permission if it is present.
+    const NATIVE_MSG_PERM = "nativeMessaging";
+    if (perms.permissions.includes(NATIVE_MSG_PERM)) {
+      let brandBundle = Services.strings.createBundle(BRAND_PROPERTIES);
+      let appName = brandBundle.GetStringFromName("brandShortName");
+      result.msgs.push(bundle.formatStringFromName(permissionKey(NATIVE_MSG_PERM), [appName], 1));
+    }
+
+    // Finally, show remaining permissions, in any order.
+    for (let permission of perms.permissions) {
+      // Handled above
+      if (permission == "nativeMessaging") {
+        continue;
+      }
+      try {
+        result.msgs.push(bundle.GetStringFromName(permissionKey(permission)));
+      } catch (err) {
+        // We deliberately do not include all permissions in the prompt.
+        // So if we don't find one then just skip it.
+      }
+    }
+
     return result;
   },
 
   showPermissionsPrompt(browser, strings, icon) {
     function eventCallback(topic) {
       if (topic == "showing") {
         let doc = this.browser.ownerDocument;
         doc.getElementById("addon-webext-perm-header").innerHTML = strings.header;
--- a/browser/themes/shared/customizableui/panelUI.inc.css
+++ b/browser/themes/shared/customizableui/panelUI.inc.css
@@ -585,16 +585,18 @@ toolbarpaletteitem[place="palette"] > to
 
 #PanelUI-update-status[update-status="failed"]::after {
   background-image: url(chrome://browser/skin/update-badge-failed.svg);
   background-color: #D90000;
 }
 
 #PanelUI-footer-addons > toolbarbutton {
   background-color: #FFEFBF;
+  /* Force border to override `#PanelUI-footer-addons > toolbarbutton` selector below */
+  border-top: 1px solid hsl(45, 100%, 77%) !important;
   display: flex;
   flex: 1 1 0%;
   width: calc(@menuPanelWidth@ + 30px);
   padding-inline-start: 15px;
   border-inline-start-style: none;
 }
 
 #PanelUI-footer-addons > toolbarbutton:hover {
--- a/devtools/client/inspector/rules/test/browser.ini
+++ b/devtools/client/inspector/rules/test/browser.ini
@@ -139,16 +139,17 @@ skip-if = os == "mac" # Bug 1245996 : cl
 [browser_rules_editable-field-focus_01.js]
 [browser_rules_editable-field-focus_02.js]
 [browser_rules_eyedropper.js]
 [browser_rules_filtereditor-appears-on-swatch-click.js]
 [browser_rules_filtereditor-commit-on-ENTER.js]
 [browser_rules_filtereditor-revert-on-ESC.js]
 skip-if = (os == "win" && debug) # bug 963492: win.
 [browser_rules_grid-highlighter-on-navigate.js]
+[browser_rules_grid-highlighter-on-reload.js]
 [browser_rules_grid-toggle_01.js]
 [browser_rules_grid-toggle_01b.js]
 [browser_rules_grid-toggle_02.js]
 [browser_rules_grid-toggle_03.js]
 [browser_rules_guessIndentation.js]
 [browser_rules_inherited-properties_01.js]
 [browser_rules_inherited-properties_02.js]
 [browser_rules_inherited-properties_03.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/rules/test/browser_rules_grid-highlighter-on-reload.js
@@ -0,0 +1,53 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that a grid highlighter showing grid gaps can be displayed after reloading the
+// page (Bug 1342051).
+
+const TEST_URI = `
+  <style type='text/css'>
+    #grid {
+      display: grid;
+      grid-gap: 10px;
+    }
+  </style>
+  <div id="grid">
+    <div id="cell1">cell1</div>
+    <div id="cell2">cell2</div>
+  </div>
+`;
+
+add_task(function* () {
+  yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+
+  info("Check that the grid highlighter can be displayed");
+  yield checkGridHighlighter();
+
+  info("Close the toolbox before reloading the tab");
+  let target = TargetFactory.forTab(gBrowser.selectedTab);
+  yield gDevTools.closeToolbox(target);
+
+  yield refreshTab(gBrowser.selectedTab);
+
+  info("Check that the grid highlighter can be displayed after reloading the page");
+  yield checkGridHighlighter();
+});
+
+function* checkGridHighlighter() {
+  let {inspector, view} = yield openRuleView();
+  let {highlighters} = view;
+
+  yield selectNode("#grid", inspector);
+  let container = getRuleViewProperty(view, "#grid", "display").valueSpan;
+  let gridToggle = container.querySelector(".ruleview-grid");
+
+  info("Toggling ON the CSS grid highlighter from the rule-view.");
+  let onHighlighterShown = highlighters.once("grid-highlighter-shown");
+  gridToggle.click();
+  yield onHighlighterShown;
+
+  ok(highlighters.gridHighlighterShown, "CSS grid highlighter is shown.");
+}
--- a/devtools/client/netmonitor/har/test/browser_net_har_copy_all_as_har.js
+++ b/devtools/client/netmonitor/har/test/browser_net_har_copy_all_as_har.js
@@ -6,17 +6,17 @@
 /**
  * Basic tests for exporting Network panel content into HAR format.
  */
 add_task(function* () {
   let { tab, monitor } = yield initNetMonitor(SIMPLE_URL);
 
   info("Starting test... ");
 
-  let { document, gStore, windowRequire } = monitor.panelWin;
+  let { gStore, windowRequire } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/actions/index");
   let RequestListContextMenu = windowRequire(
     "devtools/client/netmonitor/request-list-context-menu");
 
   gStore.dispatch(Actions.batchEnable(false));
 
   let wait = waitForNetworkEvents(monitor, 1);
   tab.linkedBrowser.reload();
--- a/devtools/client/netmonitor/har/test/browser_net_har_post_data.js
+++ b/devtools/client/netmonitor/har/test/browser_net_har_post_data.js
@@ -7,17 +7,17 @@
  * Tests for exporting POST data into HAR format.
  */
 add_task(function* () {
   let { tab, monitor } = yield initNetMonitor(
     HAR_EXAMPLE_URL + "html_har_post-data-test-page.html");
 
   info("Starting test... ");
 
-  let { document, gStore, windowRequire } = monitor.panelWin;
+  let { gStore, windowRequire } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/actions/index");
   let RequestListContextMenu = windowRequire(
     "devtools/client/netmonitor/request-list-context-menu");
 
   gStore.dispatch(Actions.batchEnable(false));
 
   // Execute one POST request on the page and wait till its done.
   let wait = waitForNetworkEvents(monitor, 0, 1);
--- a/devtools/client/netmonitor/har/test/browser_net_har_throttle_upload.js
+++ b/devtools/client/netmonitor/har/test/browser_net_har_throttle_upload.js
@@ -11,17 +11,17 @@ add_task(function* () {
 });
 
 function* throttleUploadTest(actuallyThrottle) {
   let { tab, monitor } = yield initNetMonitor(
     HAR_EXAMPLE_URL + "html_har_post-data-test-page.html");
 
   info("Starting test... (actuallyThrottle = " + actuallyThrottle + ")");
 
-  let { document, gStore, windowRequire, NetMonitorController } = monitor.panelWin;
+  let { gStore, windowRequire, NetMonitorController } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/actions/index");
   let RequestListContextMenu = windowRequire(
     "devtools/client/netmonitor/request-list-context-menu");
 
   gStore.dispatch(Actions.batchEnable(false));
 
   const size = 4096;
   const uploadSize = actuallyThrottle ? size / 3 : 0;
--- a/devtools/client/netmonitor/har/test/html_har_post-data-test-page.html
+++ b/devtools/client/netmonitor/har/test/html_har_post-data-test-page.html
@@ -11,30 +11,33 @@
     <meta http-equiv="Expires" content="0" />
     <title>Network Monitor Test Page</title>
   </head>
 
   <body>
     <p>HAR POST data test</p>
 
     <script type="text/javascript">
-      function post(aAddress, aData) {
-        var xhr = new XMLHttpRequest();
-        xhr.open("POST", aAddress, true);
+      /* exported executeTest, executeTest2 */
+      "use strict";
+
+      function post(address, data) {
+        let xhr = new XMLHttpRequest();
+        xhr.open("POST", address, true);
         xhr.setRequestHeader("Content-Type", "application/json");
-        xhr.send(aData);
+        xhr.send(data);
       }
 
       function executeTest() {
-        var url = "html_har_post-data-test-page.html";
-        var data = "{'first': 'John', 'last': 'Doe'}";
+        const url = "html_har_post-data-test-page.html";
+        const data = "{'first': 'John', 'last': 'Doe'}";
         post(url, data);
       }
 
       function executeTest2(size) {
-        var url = "html_har_post-data-test-page.html";
-        var data = "x".repeat(size);
+        const url = "html_har_post-data-test-page.html";
+        const data = "x".repeat(size);
         post(url, data);
       }
     </script>
   </body>
 
 </html>
--- a/devtools/client/netmonitor/test/browser_net_autoscroll.js
+++ b/devtools/client/netmonitor/test/browser_net_autoscroll.js
@@ -61,17 +61,17 @@ add_task(function* () {
   }
 
   function* waitForRequestsToOverflowContainer() {
     info("Waiting for enough requests to overflow the container");
     while (true) {
       info("Waiting for one network request");
       yield waitForNetworkEvents(monitor, 1);
       console.log(requestsContainer.scrollHeight);
-      console.log(requestsContainer.clientHeight)
+      console.log(requestsContainer.clientHeight);
       if (requestsContainer.scrollHeight > requestsContainer.clientHeight) {
         info("The list is long enough, returning");
         return;
       }
     }
   }
 
   function scrolledToBottom(element) {
--- a/devtools/client/netmonitor/test/browser_net_cause.js
+++ b/devtools/client/netmonitor/test/browser_net_cause.js
@@ -33,52 +33,52 @@ const EXPECTED_REQUESTS = [
     causeUri: CAUSE_URL,
     stack: false
   },
   {
     method: "GET",
     url: EXAMPLE_URL + "xhr_request",
     causeType: "xhr",
     causeUri: CAUSE_URL,
-    stack: [{ fn: "performXhrRequest", file: CAUSE_FILE_NAME, line: 22 }]
+    stack: [{ fn: "performXhrRequest", file: CAUSE_FILE_NAME, line: 24 }]
   },
   {
     method: "GET",
     url: EXAMPLE_URL + "fetch_request",
     causeType: "fetch",
     causeUri: CAUSE_URL,
-    stack: [{ fn: "performFetchRequest", file: CAUSE_FILE_NAME, line: 26 }]
+    stack: [{ fn: "performFetchRequest", file: CAUSE_FILE_NAME, line: 28 }]
   },
   {
     method: "GET",
     url: EXAMPLE_URL + "promise_fetch_request",
     causeType: "fetch",
     causeUri: CAUSE_URL,
     stack: [
-      { fn: "performPromiseFetchRequest", file: CAUSE_FILE_NAME, line: 38 },
-      { fn: null, file: CAUSE_FILE_NAME, line: 37, asyncCause: "promise callback" },
+      { fn: "performPromiseFetchRequest", file: CAUSE_FILE_NAME, line: 40 },
+      { fn: null, file: CAUSE_FILE_NAME, line: 39, asyncCause: "promise callback" },
     ]
   },
   {
     method: "GET",
     url: EXAMPLE_URL + "timeout_fetch_request",
     causeType: "fetch",
     causeUri: CAUSE_URL,
     stack: [
-      { fn: "performTimeoutFetchRequest", file: CAUSE_FILE_NAME, line: 40 },
-      { fn: "performPromiseFetchRequest", file: CAUSE_FILE_NAME, line: 39,
+      { fn: "performTimeoutFetchRequest", file: CAUSE_FILE_NAME, line: 42 },
+      { fn: "performPromiseFetchRequest", file: CAUSE_FILE_NAME, line: 41,
         asyncCause: "setTimeout handler" },
     ]
   },
   {
     method: "POST",
     url: EXAMPLE_URL + "beacon_request",
     causeType: "beacon",
     causeUri: CAUSE_URL,
-    stack: [{ fn: "performBeaconRequest", file: CAUSE_FILE_NAME, line: 30 }]
+    stack: [{ fn: "performBeaconRequest", file: CAUSE_FILE_NAME, line: 32 }]
   },
 ];
 
 add_task(function* () {
   // Async stacks aren't on by default in all builds
   yield SpecialPowers.pushPrefEnv({ set: [["javascript.options.asyncstack", true]] });
 
   // the initNetMonitor function clears the network request list after the
--- a/devtools/client/netmonitor/test/browser_net_charts-03.js
+++ b/devtools/client/netmonitor/test/browser_net_charts-03.js
@@ -62,17 +62,16 @@ add_task(function* () {
     "The first column of the header exists.");
   is(rows[0].querySelectorAll("span")[1].getAttribute("name"), "label2",
     "The second column of the header exists.");
   is(rows[0].querySelectorAll("span")[0].textContent, "label1header",
     "The first column of the header displays the correct text.");
   is(rows[0].querySelectorAll("span")[1].textContent, "label2header",
     "The second column of the header displays the correct text.");
 
-
   ok(rows[1].querySelector(".table-chart-row-box.chart-colored-blob"),
     "A colored blob exists for the firt row.");
   is(rows[1].querySelectorAll("span")[0].getAttribute("name"), "label1",
     "The first column of the first row exists.");
   is(rows[1].querySelectorAll("span")[1].getAttribute("name"), "label2",
     "The second column of the first row exists.");
   is(rows[1].querySelectorAll("span")[0].textContent, "1",
     "The first column of the first row displays the correct text.");
--- a/devtools/client/netmonitor/test/browser_net_clear.js
+++ b/devtools/client/netmonitor/test/browser_net_clear.js
@@ -9,17 +9,16 @@
 
 add_task(function* () {
   let { tab, monitor } = yield initNetMonitor(SIMPLE_URL);
   info("Starting test... ");
 
   let { document, gStore, windowRequire } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/actions/index");
   let { EVENTS } = windowRequire("devtools/client/netmonitor/constants");
-  let detailsPane = document.querySelector("#details-pane");
   let detailsPanelToggleButton = document.querySelector(".network-details-panel-toggle");
   let clearButton = document.querySelector(".requests-list-clear-button");
 
   gStore.dispatch(Actions.batchEnable(false));
 
   // Make sure we start in a sane state
   assertNoRequestState();
 
--- a/devtools/client/netmonitor/test/browser_net_content-type.js
+++ b/devtools/client/netmonitor/test/browser_net_content-type.js
@@ -36,100 +36,110 @@ add_task(function* () {
     CONTENT_TYPE_SJS + "?fmt=xml",
     {
       status: 200,
       statusText: "OK",
       type: "xml",
       fullMimeType: "text/xml; charset=utf-8",
       size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 42),
       time: true
-    });
-   verifyRequestItemTarget(
+    }
+  );
+  verifyRequestItemTarget(
     document,
     getDisplayedRequests(gStore.getState()),
     getSortedRequests(gStore.getState()).get(1),
     "GET",
     CONTENT_TYPE_SJS + "?fmt=css",
     {
       status: 200,
       statusText: "OK",
       type: "css",
       fullMimeType: "text/css; charset=utf-8",
       size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 34),
       time: true
-    });
-   verifyRequestItemTarget(
+    }
+  );
+  verifyRequestItemTarget(
     document,
     getDisplayedRequests(gStore.getState()),
     getSortedRequests(gStore.getState()).get(2),
     "GET",
     CONTENT_TYPE_SJS + "?fmt=js",
     {
       status: 200,
       statusText: "OK",
       type: "js",
       fullMimeType: "application/javascript; charset=utf-8",
       size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 34),
       time: true
-    });
-   verifyRequestItemTarget(
+    }
+  );
+  verifyRequestItemTarget(
     document,
     getDisplayedRequests(gStore.getState()),
     getSortedRequests(gStore.getState()).get(3),
     "GET",
     CONTENT_TYPE_SJS + "?fmt=json",
     {
       status: 200,
       statusText: "OK",
       type: "json",
       fullMimeType: "application/json; charset=utf-8",
       size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 29),
       time: true
-    });
-   verifyRequestItemTarget(
+    }
+  );
+  verifyRequestItemTarget(
     document,
     getDisplayedRequests(gStore.getState()),
     getSortedRequests(gStore.getState()).get(4),
     "GET",
-    CONTENT_TYPE_SJS + "?fmt=bogus", {
+    CONTENT_TYPE_SJS + "?fmt=bogus",
+    {
       status: 404,
       statusText: "Not Found",
       type: "html",
       fullMimeType: "text/html; charset=utf-8",
       size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 24),
       time: true
-    });
-   verifyRequestItemTarget(
+    }
+  );
+  verifyRequestItemTarget(
     document,
     getDisplayedRequests(gStore.getState()),
     getSortedRequests(gStore.getState()).get(5),
     "GET",
-    TEST_IMAGE, {
+    TEST_IMAGE,
+    {
       fuzzyUrl: true,
       status: 200,
       statusText: "OK",
       type: "png",
       fullMimeType: "image/png",
       size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 580),
       time: true
-    });
-   verifyRequestItemTarget(
+    }
+  );
+  verifyRequestItemTarget(
     document,
     getDisplayedRequests(gStore.getState()),
     getSortedRequests(gStore.getState()).get(6),
     "GET",
-    CONTENT_TYPE_SJS + "?fmt=gzip", {
+    CONTENT_TYPE_SJS + "?fmt=gzip",
+    {
       status: 200,
       statusText: "OK",
       type: "plain",
       fullMimeType: "text/plain",
       transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 73),
       size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 10.73),
       time: true
-    });
+    }
+  );
 
   yield selectIndexAndWaitForEditor(0);
   yield testResponseTab("xml");
 
   yield selectIndexAndWaitForEditor(1);
   yield testResponseTab("css");
 
   yield selectIndexAndWaitForEditor(2);
--- a/devtools/client/netmonitor/test/browser_net_copy_as_curl.js
+++ b/devtools/client/netmonitor/test/browser_net_copy_as_curl.js
@@ -36,18 +36,17 @@ add_task(function* () {
     header("X-Custom-Header-2: 8.8.8.8"),
     header("X-Custom-Header-3: Mon, 3 Mar 2014 11:11:11 GMT"),
     header("Referer: " + CURL_URL),
     header("Connection: keep-alive"),
     header("Pragma: no-cache"),
     header("Cache-Control: no-cache")
   ];
 
-  let { document, gStore, windowRequire } = monitor.panelWin;
-  let Actions = windowRequire("devtools/client/netmonitor/actions/index");
+  let { document } = monitor.panelWin;
 
   let wait = waitForNetworkEvents(monitor, 1);
   yield ContentTask.spawn(tab.linkedBrowser, SIMPLE_SJS, function* (url) {
     content.wrappedJSObject.performRequest(url);
   });
   yield wait;
 
   EventUtils.sendMouseEvent({ type: "mousedown" },
--- a/devtools/client/netmonitor/test/browser_net_copy_image_as_data_uri.js
+++ b/devtools/client/netmonitor/test/browser_net_copy_image_as_data_uri.js
@@ -6,17 +6,17 @@
 /**
  * Tests if copying an image as data uri works.
  */
 
 add_task(function* () {
   let { tab, monitor } = yield initNetMonitor(CONTENT_TYPE_WITHOUT_CACHE_URL);
   info("Starting test... ");
 
-  let { document, gStore, windowRequire } = monitor.panelWin;
+  let { document } = monitor.panelWin;
 
   let wait = waitForNetworkEvents(monitor, CONTENT_TYPE_WITHOUT_CACHE_REQUESTS);
   yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
     content.wrappedJSObject.performRequests();
   });
   yield wait;
 
   EventUtils.sendMouseEvent({ type: "mousedown" },
@@ -24,14 +24,14 @@ add_task(function* () {
   EventUtils.sendMouseEvent({ type: "contextmenu" },
     document.querySelectorAll(".request-list-item")[5]);
 
   yield waitForClipboardPromise(function setup() {
     // Context menu is appending in XUL document, we must select it from
     // toolbox.doc
     monitor.toolbox.doc
       .querySelector("#request-list-context-copy-image-as-data-uri").click();
- }, TEST_IMAGE_DATA_URI);
+  }, TEST_IMAGE_DATA_URI);
 
   ok(true, "Clipboard contains the currently selected image as data uri.");
 
   yield teardown(monitor);
 });
--- a/devtools/client/netmonitor/test/browser_net_curl-utils.js
+++ b/devtools/client/netmonitor/test/browser_net_curl-utils.js
@@ -8,17 +8,17 @@
  */
 
 const { CurlUtils } = require("devtools/client/shared/curl");
 
 add_task(function* () {
   let { tab, monitor } = yield initNetMonitor(CURL_UTILS_URL);
   info("Starting test... ");
 
-  let { document, gStore, windowRequire, gNetwork } = monitor.panelWin;
+  let { gStore, windowRequire, gNetwork } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/actions/index");
   let { getSortedRequests } = windowRequire("devtools/client/netmonitor/selectors/index");
 
   gStore.dispatch(Actions.batchEnable(false));
 
   let wait = waitForNetworkEvents(monitor, 1, 3);
   yield ContentTask.spawn(tab.linkedBrowser, SIMPLE_SJS, function* (url) {
     content.wrappedJSObject.performRequests(url);
--- a/devtools/client/netmonitor/test/browser_net_cyrillic-02.js
+++ b/devtools/client/netmonitor/test/browser_net_cyrillic-02.js
@@ -8,17 +8,16 @@
  * when loaded directly from an HTML page.
  */
 
 add_task(function* () {
   let { tab, monitor } = yield initNetMonitor(CYRILLIC_URL);
   info("Starting test... ");
 
   let { document, gStore, windowRequire } = monitor.panelWin;
-  let Actions = windowRequire("devtools/client/netmonitor/actions/index");
   let {
     getDisplayedRequests,
     getSortedRequests,
   } = windowRequire("devtools/client/netmonitor/selectors/index");
 
   let wait = waitForNetworkEvents(monitor, 1);
   tab.linkedBrowser.reload();
   yield wait;
--- a/devtools/client/netmonitor/test/browser_net_filter-04.js
+++ b/devtools/client/netmonitor/test/browser_net_filter-04.js
@@ -25,17 +25,18 @@ const REQUESTS_WITH_MEDIA_AND_FLASH = RE
 ]);
 
 const REQUESTS_WITH_MEDIA_AND_FLASH_AND_WS = REQUESTS_WITH_MEDIA_AND_FLASH.concat([
   /* "Upgrade" is a reserved header and can not be set on XMLHttpRequest */
   { url: "sjs_content-type-test-server.sjs?fmt=ws" },
 ]);
 
 add_task(function* () {
-  Services.prefs.setCharPref("devtools.netmonitor.filters", '["bogus", "js", "alsobogus"]');
+  Services.prefs.setCharPref("devtools.netmonitor.filters",
+                             '["bogus", "js", "alsobogus"]');
 
   let { monitor } = yield initNetMonitor(FILTERING_URL);
   info("Starting test... ");
 
   let { gStore, windowRequire } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/actions/index");
   let { Prefs } = windowRequire("devtools/client/netmonitor/utils/prefs");
 
--- a/devtools/client/netmonitor/test/browser_net_footer-summary.js
+++ b/devtools/client/netmonitor/test/browser_net_footer-summary.js
@@ -44,18 +44,19 @@ add_task(function* () {
       EventUtils.sendMouseEvent({ type: "click" }, buttonEl);
       testStatus();
     }
   }
 
   yield teardown(monitor);
 
   function testStatus() {
-    let value = document.querySelector(".requests-list-network-summary-button").textContent;
-   info("Current summary: " + value);
+    let value = document.querySelector(".requests-list-network-summary-button")
+                        .textContent;
+    info("Current summary: " + value);
 
     let state = gStore.getState();
     let totalRequestsCount = state.requests.requests.size;
     let requestsSummary = getDisplayedRequestsSummary(state);
     info(`Current requests: ${requestsSummary.count} of ${totalRequestsCount}.`);
 
     if (!totalRequestsCount || !requestsSummary.count) {
       is(value, L10N.getStr("networkMenu.empty"),
--- a/devtools/client/netmonitor/test/browser_net_frame.js
+++ b/devtools/client/netmonitor/test/browser_net_frame.js
@@ -34,52 +34,52 @@ const EXPECTED_REQUESTS_TOP = [
     causeUri: TOP_URL,
     stack: false
   },
   {
     method: "GET",
     url: EXAMPLE_URL + "xhr_request",
     causeType: "xhr",
     causeUri: TOP_URL,
-    stack: [{ fn: "performXhrRequest", file: TOP_FILE_NAME, line: 23 }]
+    stack: [{ fn: "performXhrRequest", file: TOP_FILE_NAME, line: 25 }]
   },
   {
     method: "GET",
     url: EXAMPLE_URL + "fetch_request",
     causeType: "fetch",
     causeUri: TOP_URL,
-    stack: [{ fn: "performFetchRequest", file: TOP_FILE_NAME, line: 27 }]
+    stack: [{ fn: "performFetchRequest", file: TOP_FILE_NAME, line: 29 }]
   },
   {
     method: "GET",
     url: EXAMPLE_URL + "promise_fetch_request",
     causeType: "fetch",
     causeUri: TOP_URL,
     stack: [
-      { fn: "performPromiseFetchRequest", file: TOP_FILE_NAME, line: 39 },
-      { fn: null, file: TOP_FILE_NAME, line: 38, asyncCause: "promise callback" },
+      { fn: "performPromiseFetchRequest", file: TOP_FILE_NAME, line: 41 },
+      { fn: null, file: TOP_FILE_NAME, line: 40, asyncCause: "promise callback" },
     ]
   },
   {
     method: "GET",
     url: EXAMPLE_URL + "timeout_fetch_request",
     causeType: "fetch",
     causeUri: TOP_URL,
     stack: [
-      { fn: "performTimeoutFetchRequest", file: TOP_FILE_NAME, line: 41 },
-      { fn: "performPromiseFetchRequest", file: TOP_FILE_NAME, line: 40,
+      { fn: "performTimeoutFetchRequest", file: TOP_FILE_NAME, line: 43 },
+      { fn: "performPromiseFetchRequest", file: TOP_FILE_NAME, line: 42,
         asyncCause: "setTimeout handler" },
     ]
   },
   {
     method: "POST",
     url: EXAMPLE_URL + "beacon_request",
     causeType: "beacon",
     causeUri: TOP_URL,
-    stack: [{ fn: "performBeaconRequest", file: TOP_FILE_NAME, line: 31 }]
+    stack: [{ fn: "performBeaconRequest", file: TOP_FILE_NAME, line: 33 }]
   },
 ];
 
 const EXPECTED_REQUESTS_SUB = [
   {
     method: "GET",
     url: SUB_URL,
     causeType: "subdocument",
@@ -100,52 +100,52 @@ const EXPECTED_REQUESTS_SUB = [
     causeUri: SUB_URL,
     stack: false
   },
   {
     method: "GET",
     url: EXAMPLE_URL + "xhr_request",
     causeType: "xhr",
     causeUri: SUB_URL,
-    stack: [{ fn: "performXhrRequest", file: SUB_FILE_NAME, line: 22 }]
+    stack: [{ fn: "performXhrRequest", file: SUB_FILE_NAME, line: 24 }]
   },
   {
     method: "GET",
     url: EXAMPLE_URL + "fetch_request",
     causeType: "fetch",
     causeUri: SUB_URL,
-    stack: [{ fn: "performFetchRequest", file: SUB_FILE_NAME, line: 26 }]
+    stack: [{ fn: "performFetchRequest", file: SUB_FILE_NAME, line: 28 }]
   },
   {
     method: "GET",
     url: EXAMPLE_URL + "promise_fetch_request",
     causeType: "fetch",
     causeUri: SUB_URL,
     stack: [
-      { fn: "performPromiseFetchRequest", file: SUB_FILE_NAME, line: 38 },
-      { fn: null, file: SUB_FILE_NAME, line: 37, asyncCause: "promise callback" },
+      { fn: "performPromiseFetchRequest", file: SUB_FILE_NAME, line: 40 },
+      { fn: null, file: SUB_FILE_NAME, line: 39, asyncCause: "promise callback" },
     ]
   },
   {
     method: "GET",
     url: EXAMPLE_URL + "timeout_fetch_request",
     causeType: "fetch",
     causeUri: SUB_URL,
     stack: [
-      { fn: "performTimeoutFetchRequest", file: SUB_FILE_NAME, line: 40 },
-      { fn: "performPromiseFetchRequest", file: SUB_FILE_NAME, line: 39,
+      { fn: "performTimeoutFetchRequest", file: SUB_FILE_NAME, line: 42 },
+      { fn: "performPromiseFetchRequest", file: SUB_FILE_NAME, line: 41,
         asyncCause: "setTimeout handler" },
     ]
   },
   {
     method: "POST",
     url: EXAMPLE_URL + "beacon_request",
     causeType: "beacon",
     causeUri: SUB_URL,
-    stack: [{ fn: "performBeaconRequest", file: SUB_FILE_NAME, line: 30 }]
+    stack: [{ fn: "performBeaconRequest", file: SUB_FILE_NAME, line: 32 }]
   },
 ];
 
 const REQUEST_COUNT = EXPECTED_REQUESTS_TOP.length + EXPECTED_REQUESTS_SUB.length;
 
 add_task(function* () {
   // Async stacks aren't on by default in all builds
   yield SpecialPowers.pushPrefEnv({ set: [["javascript.options.asyncstack", true]] });
--- a/devtools/client/netmonitor/test/browser_net_header-docs.js
+++ b/devtools/client/netmonitor/test/browser_net_header-docs.js
@@ -11,17 +11,16 @@ const { getHeadersURL } = require("devto
  */
 add_task(function* () {
   let { tab, monitor } = yield initNetMonitor(POST_DATA_URL);
   info("Starting test... ");
 
   let { document, gStore, windowRequire } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/actions/index");
   let {
-    getDisplayedRequests,
     getSortedRequests,
   } = windowRequire("devtools/client/netmonitor/selectors/index");
 
   gStore.dispatch(Actions.batchEnable(false));
 
   let wait = waitForNetworkEvents(monitor, 0, 2);
   yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
     content.wrappedJSObject.performRequests();
@@ -35,23 +34,25 @@ add_task(function* () {
 
   return teardown(monitor);
 
   /*
    * Tests that a "Learn More" button is only shown if
    * and only if a header is documented in MDN.
    */
   function testShowLearnMore(data) {
-    document.querySelectorAll(".properties-view .treeRow.stringRow").forEach((rowEl, index) => {
-      let headerName = rowEl.querySelectorAll(".treeLabelCell .treeLabel")[0].textContent;
+    let selector = ".properties-view .treeRow.stringRow";
+    document.querySelectorAll(selector).forEach((rowEl, index) => {
+      let headerName = rowEl.querySelectorAll(".treeLabelCell .treeLabel")[0]
+                            .textContent;
       let headerDocURL = getHeadersURL(headerName);
       let learnMoreEl = rowEl.querySelectorAll(".treeValueCell .learn-more-link");
 
       if (headerDocURL === null) {
         ok(learnMoreEl.length === 0,
-          "undocumented header does not include a \"Learn More\" button");
+           "undocumented header does not include a \"Learn More\" button");
       } else {
         ok(learnMoreEl[0].getAttribute("title") === headerDocURL,
-          "documented header includes a \"Learn More\" button with a link to MDN");
+           "documented header includes a \"Learn More\" button with a link to MDN");
       }
     });
   }
 });
--- a/devtools/client/netmonitor/test/browser_net_icon-preview.js
+++ b/devtools/client/netmonitor/test/browser_net_icon-preview.js
@@ -59,14 +59,15 @@ add_task(function* () {
   function* reloadAndPerformRequests() {
     yield NetMonitorController.triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_ENABLED);
     yield performRequests();
   }
 
   function checkImageThumbnail() {
     is(document.querySelectorAll(".requests-list-icon[data-type=thumbnail]").length, 1,
       "There should be only one image request with a thumbnail displayed.");
-    is(document.querySelector(".requests-list-icon[data-type=thumbnail]").src, TEST_IMAGE_DATA_URI,
+    is(document.querySelector(".requests-list-icon[data-type=thumbnail]").src,
+      TEST_IMAGE_DATA_URI,
       "The image requests-list-icon thumbnail is displayed correctly.");
     is(document.querySelector(".requests-list-icon[data-type=thumbnail]").hidden, false,
       "The image requests-list-icon thumbnail should not be hidden.");
   }
 });
--- a/devtools/client/netmonitor/test/browser_net_image-tooltip.js
+++ b/devtools/client/netmonitor/test/browser_net_image-tooltip.js
@@ -11,95 +11,90 @@ const IMAGE_TOOLTIP_REQUESTS = 1;
  */
 add_task(function* test() {
   let { tab, monitor } = yield initNetMonitor(IMAGE_TOOLTIP_URL);
   info("Starting test... ");
 
   let { document, gStore, windowRequire, NetMonitorController } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/actions/index");
   let { ACTIVITY_TYPE, EVENTS } = windowRequire("devtools/client/netmonitor/constants");
-  let {
-    getDisplayedRequests,
-    getSortedRequests,
-  } = windowRequire("devtools/client/netmonitor/selectors/index");
   let toolboxDoc = monitor.toolbox.doc;
 
   gStore.dispatch(Actions.batchEnable(false));
 
   let onEvents = waitForNetworkEvents(monitor, IMAGE_TOOLTIP_REQUESTS);
   let onThumbnail = monitor.panelWin.once(EVENTS.RESPONSE_IMAGE_THUMBNAIL_DISPLAYED);
   yield performRequests();
   yield onEvents;
   yield onThumbnail;
 
   info("Checking the image thumbnail after a few requests were made...");
-  yield showTooltipAndVerify(toolboxDoc,
-    document.querySelectorAll(".request-list-item")[0]);
+  yield showTooltipAndVerify(document.querySelectorAll(".request-list-item")[0]);
 
   // Hide tooltip before next test, to avoid the situation that tooltip covers
   // the icon for the request of the next test.
   info("Checking the image thumbnail gets hidden...");
-  yield hideTooltipAndVerify(monitor.toolbox.doc,
-    document.querySelectorAll(".request-list-item")[0]);
+  yield hideTooltipAndVerify(document.querySelectorAll(".request-list-item")[0]);
 
   // +1 extra document reload
   onEvents = waitForNetworkEvents(monitor, IMAGE_TOOLTIP_REQUESTS + 1);
   onThumbnail = monitor.panelWin.once(EVENTS.RESPONSE_IMAGE_THUMBNAIL_DISPLAYED);
 
   info("Reloading the debuggee and performing all requests again...");
   yield NetMonitorController.triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_ENABLED);
   yield performRequests();
   yield onEvents;
   yield onThumbnail;
 
   info("Checking the image thumbnail after a reload.");
-  yield showTooltipAndVerify(toolboxDoc,
-    document.querySelectorAll(".request-list-item")[1]);
+  yield showTooltipAndVerify(document.querySelectorAll(".request-list-item")[1]);
 
   info("Checking if the image thumbnail is hidden when mouse leaves the menu widget");
   let requestsListContents = document.querySelector(".requests-list-contents");
-  EventUtils.synthesizeMouse(requestsListContents, 0, 0, { type: "mouseout" }, monitor.panelWin);
+  EventUtils.synthesizeMouse(requestsListContents, 0, 0, { type: "mouseout" },
+                             monitor.panelWin);
   yield waitUntil(() => !toolboxDoc.querySelector(".tooltip-container.tooltip-visible"));
 
   yield teardown(monitor);
 
   function performRequests() {
     return ContentTask.spawn(tab.linkedBrowser, {}, function* () {
       content.wrappedJSObject.performRequests();
     });
   }
 
   /**
    * Show a tooltip on the {target} and verify that it was displayed
    * with the expected content.
    */
-  function* showTooltipAndVerify(toolboxDoc, target) {
+  function* showTooltipAndVerify(target) {
     let anchor = target.querySelector(".requests-list-file");
-    yield showTooltipOn(toolboxDoc, anchor);
+    yield showTooltipOn(anchor);
 
     info("Tooltip was successfully opened for the image request.");
     is(toolboxDoc.querySelector(".tooltip-panel img").src, TEST_IMAGE_DATA_URI,
       "The tooltip's image content is displayed correctly.");
   }
 
   /**
    * Trigger a tooltip over an element by sending mousemove event.
    * @return a promise that resolves when the tooltip is shown
    */
-  function* showTooltipOn(toolboxDoc, element) {
+  function* showTooltipOn(element) {
     let win = element.ownerDocument.defaultView;
     EventUtils.synthesizeMouseAtCenter(element, { type: "mousemove" }, win);
     yield waitUntil(() => toolboxDoc.querySelector(".tooltip-panel img"));
   }
 
   /**
    * Hide a tooltip on the {target} and verify that it was closed.
    */
-  function* hideTooltipAndVerify(toolboxDoc, target) {
+  function* hideTooltipAndVerify(target) {
     // Hovering over the "method" column hides the tooltip.
     let anchor = target.querySelector(".requests-list-method");
     let win = anchor.ownerDocument.defaultView;
     EventUtils.synthesizeMouseAtCenter(anchor, { type: "mousemove" }, win);
 
-    yield waitUntil(() => !toolboxDoc.querySelector(".tooltip-container.tooltip-visible"));
+    yield waitUntil(
+      () => !toolboxDoc.querySelector(".tooltip-container.tooltip-visible"));
     info("Tooltip was successfully closed.");
   }
 });
--- a/devtools/client/netmonitor/test/browser_net_json-null.js
+++ b/devtools/client/netmonitor/test/browser_net_json-null.js
@@ -10,20 +10,16 @@ const { L10N } = require("devtools/clien
  */
 
 add_task(function* () {
   let { tab, monitor } = yield initNetMonitor(JSON_BASIC_URL + "?name=null");
   info("Starting test... ");
 
   let { document, gStore, windowRequire } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/actions/index");
-  let {
-    getDisplayedRequests,
-    getSortedRequests,
-  } = windowRequire("devtools/client/netmonitor/selectors/index");
 
   gStore.dispatch(Actions.batchEnable(false));
 
   let wait = waitForNetworkEvents(monitor, 1);
   yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
     content.wrappedJSObject.performRequests();
   });
   yield wait;
--- a/devtools/client/netmonitor/test/browser_net_open_request_in_tab.js
+++ b/devtools/client/netmonitor/test/browser_net_open_request_in_tab.js
@@ -8,20 +8,16 @@
  */
 
 add_task(function* () {
   let { tab, monitor } = yield initNetMonitor(CUSTOM_GET_URL);
   info("Starting test...");
 
   let { document, gStore, windowRequire } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/actions/index");
-  let {
-    getDisplayedRequests,
-    getSortedRequests,
-  } = windowRequire("devtools/client/netmonitor/selectors/index");
 
   gStore.dispatch(Actions.batchEnable(false));
 
   let wait = waitForNetworkEvents(monitor, 1);
   yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
     content.wrappedJSObject.performRequests(1);
   });
   yield wait;
--- a/devtools/client/netmonitor/test/browser_net_persistent_logs.js
+++ b/devtools/client/netmonitor/test/browser_net_persistent_logs.js
@@ -7,17 +7,17 @@
  * Tests if the network monitor leaks on initialization and sudden destruction.
  * You can also use this initialization format as a template for other tests.
  */
 
 add_task(function* () {
   let { tab, monitor } = yield initNetMonitor(SINGLE_GET_URL);
   info("Starting test... ");
 
-  let { document, windowRequire } = monitor.panelWin;
+  let { document } = monitor.panelWin;
 
   Services.prefs.setBoolPref("devtools.webconsole.persistlog", false);
 
   yield reloadAndWait();
 
   is(document.querySelectorAll(".request-list-item").length, 2,
     "The request list should have two items at this point.");
 
--- a/devtools/client/netmonitor/test/browser_net_post-data-01.js
+++ b/devtools/client/netmonitor/test/browser_net_post-data-01.js
@@ -39,31 +39,33 @@ add_task(function* () {
     SIMPLE_SJS + "?foo=bar&baz=42&type=urlencoded",
     {
       status: 200,
       statusText: "Och Aye",
       type: "plain",
       fullMimeType: "text/plain; charset=utf-8",
       size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 12),
       time: true
-    });
-   verifyRequestItemTarget(
+    }
+  );
+  verifyRequestItemTarget(
     document,
     getDisplayedRequests(gStore.getState()),
     getSortedRequests(gStore.getState()).get(1),
     "POST",
     SIMPLE_SJS + "?foo=bar&baz=42&type=multipart",
     {
       status: 200,
       statusText: "Och Aye",
       type: "plain",
       fullMimeType: "text/plain; charset=utf-8",
       size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 12),
       time: true
-    });
+    }
+  );
 
   // Wait for all tree sections updated by react
   wait = waitForDOM(document, "#params-panel .tree-section", 2);
   EventUtils.sendMouseEvent({ type: "mousedown" },
     document.querySelectorAll(".request-list-item")[0]);
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#params-tab"));
   yield wait;
@@ -102,39 +104,43 @@ add_task(function* () {
     is(treeSections[0].querySelector(".treeLabel").textContent,
       L10N.getStr("paramsQueryString"),
       "The query section doesn't have the correct title.");
 
     is(treeSections[1].querySelector(".treeLabel").textContent,
       L10N.getStr(type == "urlencoded" ? "paramsFormData" : "paramsPostPayload"),
       "The post section doesn't have the correct title.");
 
-    let labels = tabpanel.querySelectorAll("tr:not(.tree-section) .treeLabelCell .treeLabel");
-    let values = tabpanel.querySelectorAll("tr:not(.tree-section) .treeValueCell .objectBox");
+    let labels = tabpanel
+      .querySelectorAll("tr:not(.tree-section) .treeLabelCell .treeLabel");
+    let values = tabpanel
+      .querySelectorAll("tr:not(.tree-section) .treeValueCell .objectBox");
 
     is(labels[0].textContent, "foo", "The first query param name was incorrect.");
     is(values[0].textContent, "\"bar\"", "The first query param value was incorrect.");
     is(labels[1].textContent, "baz", "The second query param name was incorrect.");
     is(values[1].textContent, "\"42\"", "The second query param value was incorrect.");
     is(labels[2].textContent, "type", "The third query param name was incorrect.");
-    is(values[2].textContent, "\"" + type + "\"", "The third query param value was incorrect.");
+    is(values[2].textContent, "\"" + type + "\"",
+      "The third query param value was incorrect.");
 
     if (type == "urlencoded") {
       checkVisibility("params");
       is(labels.length, 5, "There should be 5 param values displayed in this tabpanel.");
       is(labels[3].textContent, "foo", "The first post param name was incorrect.");
       is(values[3].textContent, "\"bar\"", "The first post param value was incorrect.");
       is(labels[4].textContent, "baz", "The second post param name was incorrect.");
       is(values[4].textContent, "\"123\"", "The second post param value was incorrect.");
     } else {
       checkVisibility("params editor");
 
       is(labels.length, 3, "There should be 3 param values displayed in this tabpanel.");
 
-      let text = editorFrames[0].contentDocument.querySelector(".CodeMirror-code").textContent;
+      let text = editorFrames[0].contentDocument.querySelector(".CodeMirror-code")
+                                                .textContent;
 
       ok(text.includes("Content-Disposition: form-data; name=\"text\""),
         "The text shown in the source editor is incorrect (1.1).");
       ok(text.includes("Content-Disposition: form-data; name=\"email\""),
         "The text shown in the source editor is incorrect (2.1).");
       ok(text.includes("Content-Disposition: form-data; name=\"range\""),
         "The text shown in the source editor is incorrect (3.1).");
       ok(text.includes("Content-Disposition: form-data; name=\"Custom field\""),
--- a/devtools/client/netmonitor/test/browser_net_post-data-02.js
+++ b/devtools/client/netmonitor/test/browser_net_post-data-02.js
@@ -11,20 +11,16 @@
 add_task(function* () {
   let { L10N } = require("devtools/client/netmonitor/utils/l10n");
 
   let { tab, monitor } = yield initNetMonitor(POST_RAW_URL);
   info("Starting test... ");
 
   let { document, gStore, windowRequire } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/actions/index");
-  let {
-    getDisplayedRequests,
-    getSortedRequests,
-  } = windowRequire("devtools/client/netmonitor/selectors/index");
 
   gStore.dispatch(Actions.batchEnable(false));
 
   let wait = waitForNetworkEvents(monitor, 0, 1);
   yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
     content.wrappedJSObject.performRequests();
   });
   yield wait;
--- a/devtools/client/netmonitor/test/browser_net_prefs-reload.js
+++ b/devtools/client/netmonitor/test/browser_net_prefs-reload.js
@@ -6,28 +6,30 @@
 /**
  * Tests if the prefs that should survive across tool reloads work.
  */
 
 add_task(function* () {
   let { monitor } = yield initNetMonitor(SIMPLE_URL);
   let { getRequestFilterTypes } = monitor.panelWin
     .windowRequire("devtools/client/netmonitor/selectors/index");
-  let Actions = monitor.panelWin.windowRequire("devtools/client/netmonitor/actions/index");
+  let Actions = monitor.panelWin
+    .windowRequire("devtools/client/netmonitor/actions/index");
   info("Starting test... ");
 
   // This test reopens the network monitor a bunch of times, for different
   // hosts (bottom, side, window). This seems to be slow on debug builds.
   requestLongerTimeout(3);
 
   // Use these getters instead of caching instances inside the panel win,
   // since the tool is reopened a bunch of times during this test
   // and the instances will differ.
   let getDoc = () => monitor.panelWin.document;
-  let getPrefs = () => monitor.panelWin.windowRequire("devtools/client/netmonitor/utils/prefs").Prefs;
+  let getPrefs = () => monitor.panelWin
+    .windowRequire("devtools/client/netmonitor/utils/prefs").Prefs;
   let getStore = () => monitor.panelWin.gStore;
   let getState = () => getStore().getState();
 
   let prefsToCheck = {
     filters: {
       // A custom new value to be used for the verified preference.
       newValue: ["html", "css"],
       // Getter used to retrieve the current value from the frontend, in order
@@ -39,25 +41,29 @@ add_task(function* () {
       // before trying to validate the changes.
       modifyFrontend: (value) => value.forEach(e =>
         getStore().dispatch(Actions.toggleRequestFilterType(e)))
     },
     networkDetailsWidth: {
       newValue: ~~(Math.random() * 200 + 100),
       validateValue: () =>
         getDoc().querySelector(".monitor-panel .split-box .controlled").clientWidth,
-      modifyFrontend: (value) =>
-        getDoc().querySelector(".monitor-panel .split-box .controlled").style.width = `${value}px`,
+      modifyFrontend: function (value) {
+        getDoc().querySelector(".monitor-panel .split-box .controlled")
+                .style.width = `${value}px`;
+      }
     },
     networkDetailsHeight: {
       newValue: ~~(Math.random() * 300 + 100),
       validateValue: () =>
         getDoc().querySelector(".monitor-panel .split-box .controlled").clientHeight,
-      modifyFrontend: (value) =>
-        getDoc().querySelector(".monitor-panel .split-box .controlled").style.height = `${value}px`
+      modifyFrontend: function (value) {
+        getDoc().querySelector(".monitor-panel .split-box .controlled")
+                .style.height = `${value}px`;
+      }
     }
     /* add more prefs here... */
   };
 
   yield testBottom();
   yield testSide();
   yield testWindow();
 
@@ -75,17 +81,17 @@ add_task(function* () {
   }
 
   function validateFirstPrefValues(isVerticalSplitter) {
     info("Validating current pref values to the UI elements.");
 
     for (let name in prefsToCheck) {
       if ((isVerticalSplitter && name === "networkDetailsHeight") ||
           (!isVerticalSplitter && name === "networkDetailsWidth")) {
-        continue
+        continue;
       }
 
       let currentValue = getPrefs()[name];
       let firstValue = prefsToCheck[name].firstValue;
       let validateValue = prefsToCheck[name].validateValue;
 
       is(firstValue.toSource(), currentValue.toSource(),
         "Pref " + name + " should be equal to first value: " + currentValue);
@@ -95,17 +101,17 @@ add_task(function* () {
   }
 
   function modifyFrontend(isVerticalSplitter) {
     info("Modifying UI elements to the specified new values.");
 
     for (let name in prefsToCheck) {
       if ((isVerticalSplitter && name === "networkDetailsHeight") ||
           (!isVerticalSplitter && name === "networkDetailsWidth")) {
-        continue
+        continue;
       }
 
       let currentValue = getPrefs()[name];
       let firstValue = prefsToCheck[name].firstValue;
       let newValue = prefsToCheck[name].newValue;
       let validateValue = prefsToCheck[name].validateValue;
       let modFrontend = prefsToCheck[name].modifyFrontend;
 
@@ -122,17 +128,17 @@ add_task(function* () {
   }
 
   function validateNewPrefValues(isVerticalSplitter) {
     info("Invalidating old pref values to the modified UI elements.");
 
     for (let name in prefsToCheck) {
       if ((isVerticalSplitter && name === "networkDetailsHeight") ||
           (!isVerticalSplitter && name === "networkDetailsWidth")) {
-        continue
+        continue;
       }
 
       let currentValue = getPrefs()[name];
       let firstValue = prefsToCheck[name].firstValue;
       let newValue = prefsToCheck[name].newValue;
       let validateValue = prefsToCheck[name].validateValue;
 
       isnot(firstValue.toSource(), currentValue.toSource(),
@@ -145,17 +151,17 @@ add_task(function* () {
   }
 
   function resetFrontend(isVerticalSplitter) {
     info("Resetting UI elements to the cached initial pref values.");
 
     for (let name in prefsToCheck) {
       if ((isVerticalSplitter && name === "networkDetailsHeight") ||
           (!isVerticalSplitter && name === "networkDetailsWidth")) {
-        continue
+        continue;
       }
 
       let currentValue = getPrefs()[name];
       let firstValue = prefsToCheck[name].firstValue;
       let newValue = prefsToCheck[name].newValue;
       let validateValue = prefsToCheck[name].validateValue;
       let modFrontend = prefsToCheck[name].modifyFrontend;
 
--- a/devtools/client/netmonitor/test/browser_net_reload-markers.js
+++ b/devtools/client/netmonitor/test/browser_net_reload-markers.js
@@ -6,17 +6,17 @@
 /**
  * Tests if the empty-requests reload button works.
  */
 
 add_task(function* () {
   let { monitor } = yield initNetMonitor(SIMPLE_URL);
   info("Starting test... ");
 
-  let { document, windowRequire } = monitor.panelWin;
+  let { document } = monitor.panelWin;
   let button = document.querySelector(".requests-list-reload-notice-button");
   button.click();
 
   let markers = [];
 
   monitor.panelWin.on(EVENTS.TIMELINE_EVENT, (_, marker) => {
     markers.push(marker);
   });
--- a/devtools/client/netmonitor/test/browser_net_resend.js
+++ b/devtools/client/netmonitor/test/browser_net_resend.js
@@ -69,17 +69,17 @@ add_task(function* () {
     let expectedUrl = orig.url + "&" + ADD_QUERY;
 
     is(url, expectedUrl, "menu item is updated to reflect url entered in form");
   }
 
   /*
    * Test that the New Request form was populated correctly
    */
-  function testCustomForm(data) {
+  function* testCustomForm(data) {
     yield waitUntil(() => document.querySelector(".custom-request-panel"));
     is(document.getElementById("custom-method-value").value, data.method,
        "new request form showing correct method");
 
     is(document.getElementById("custom-url-value").value, data.url,
        "new request form showing correct url");
 
     let query = document.getElementById("custom-query-value");
--- a/devtools/client/netmonitor/test/browser_net_resend_cors.js
+++ b/devtools/client/netmonitor/test/browser_net_resend_cors.js
@@ -7,20 +7,19 @@
  * Tests if resending a CORS request avoids the security checks and doesn't send
  * a preflight OPTIONS request (bug 1270096 and friends)
  */
 
 add_task(function* () {
   let { tab, monitor } = yield initNetMonitor(CORS_URL);
   info("Starting test... ");
 
-  let { document, gStore, windowRequire } = monitor.panelWin;
+  let { gStore, windowRequire } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/actions/index");
   let {
-    getDisplayedRequests,
     getSortedRequests,
   } = windowRequire("devtools/client/netmonitor/selectors/index");
 
   gStore.dispatch(Actions.batchEnable(false));
 
   let requestUrl = "http://test1.example.com" + CORS_SJS_PATH;
 
   info("Waiting for OPTIONS, then POST");
@@ -39,17 +38,17 @@ add_task(function* () {
     is(item.url, requestUrl, `The ${item.method} request has the right URL`);
   });
 
   // Resend both requests without modification. Wait for resent OPTIONS, then POST.
   // POST is supposed to have no preflight OPTIONS request this time (CORS is disabled)
   let onRequests = waitForNetworkEvents(monitor, 1, 0);
   ITEMS.forEach((item) => {
     info(`Selecting the ${item.method} request`);
-    gStore.dispatch(Actions.selectRequest(item.id))
+    gStore.dispatch(Actions.selectRequest(item.id));
 
     info("Cloning the selected request into a custom clone");
     gStore.dispatch(Actions.cloneSelectedRequest());
 
     info("Sending the cloned request (without change)");
     gStore.dispatch(Actions.sendCustomRequest());
   });
 
--- a/devtools/client/netmonitor/test/browser_net_resend_headers.js
+++ b/devtools/client/netmonitor/test/browser_net_resend_headers.js
@@ -6,20 +6,19 @@
 /**
  * Test if custom request headers are not ignored (bug 1270096 and friends)
  */
 
 add_task(function* () {
   let { monitor } = yield initNetMonitor(SIMPLE_SJS);
   info("Starting test... ");
 
-  let { document, gStore, windowRequire, NetMonitorController } = monitor.panelWin;
+  let { gStore, windowRequire, NetMonitorController } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/actions/index");
   let {
-    getDisplayedRequests,
     getSortedRequests,
   } = windowRequire("devtools/client/netmonitor/selectors/index");
 
   gStore.dispatch(Actions.batchEnable(false));
 
   let requestUrl = SIMPLE_SJS;
   let requestHeaders = [
     { name: "Host", value: "fakehost.example.com" },
--- a/devtools/client/netmonitor/test/browser_net_security-details.js
+++ b/devtools/client/netmonitor/test/browser_net_security-details.js
@@ -41,27 +41,28 @@ add_task(function* () {
   // The cipher suite used by the test server example.com might change at any
   // moment but all of them should start with "TLS_".
   // http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml
   let suite = textboxes[1].value;
   ok(suite.startsWith("TLS_"), "The suite " + suite + " seems valid.");
 
   // Host
   is(tabpanel.querySelectorAll(".treeLabel.objectLabel")[1].textContent,
-    "Host example.com:",
-    "Label has the expected value.");
+     "Host example.com:",
+     "Label has the expected value.");
   is(textboxes[2].value, "Disabled", "Label has the expected value.");
   is(textboxes[3].value, "Disabled", "Label has the expected value.");
 
   // Cert
   is(textboxes[4].value, "example.com", "Label has the expected value.");
   is(textboxes[5].value, "<Not Available>", "Label has the expected value.");
   is(textboxes[6].value, "<Not Available>", "Label has the expected value.");
 
-  is(textboxes[7].value, "Temporary Certificate Authority", "Label has the expected value.");
+  is(textboxes[7].value, "Temporary Certificate Authority",
+     "Label has the expected value.");
   is(textboxes[8].value, "Mozilla Testing", "Label has the expected value.");
   is(textboxes[9].value, "Profile Guided Optimization", "Label has the expected value.");
 
   // Locale sensitive and varies between timezones. Cant't compare equality or
   // the test fails depending on which part of the world the test is executed.
 
   // cert validity begins
   isnot(textboxes[10].value, "", "Label was not empty.");
--- a/devtools/client/netmonitor/test/browser_net_security-icon-click.js
+++ b/devtools/client/netmonitor/test/browser_net_security-icon-click.js
@@ -6,20 +6,16 @@
 /**
  * Test that clicking on the security indicator opens the security details tab.
  */
 
 add_task(function* () {
   let { tab, monitor } = yield initNetMonitor(CUSTOM_GET_URL);
   let { document, gStore, windowRequire } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/actions/index");
-  let {
-    getDisplayedRequests,
-    getSortedRequests,
-  } = windowRequire("devtools/client/netmonitor/selectors/index");
 
   gStore.dispatch(Actions.batchEnable(false));
 
   info("Requesting a resource over HTTPS.");
   yield performRequestAndWait("https://example.com" + CORS_SJS_PATH + "?request_2");
   yield performRequestAndWait("https://example.com" + CORS_SJS_PATH + "?request_1");
 
   is(gStore.getState().requests.requests.size, 2, "Two events event logged.");
@@ -49,11 +45,12 @@ add_task(function* () {
   }
 
   function* clickAndTestSecurityIcon() {
     let icon = document.querySelector(".requests-security-state-icon");
 
     info("Clicking security icon of the first request and waiting for panel update.");
     EventUtils.synthesizeMouseAtCenter(icon, {}, monitor.panelWin);
 
-    ok(document.querySelector("#security-tab[aria-selected=true]"), "Security tab is selected.");
+    ok(document.querySelector("#security-tab[aria-selected=true]"),
+       "Security tab is selected.");
   }
 });
--- a/devtools/client/netmonitor/test/browser_net_security-redirect.js
+++ b/devtools/client/netmonitor/test/browser_net_security-redirect.js
@@ -7,36 +7,32 @@
  * Test a http -> https redirect shows secure icon only for redirected https
  * request.
  */
 
 add_task(function* () {
   let { tab, monitor } = yield initNetMonitor(CUSTOM_GET_URL);
   let { document, gStore, windowRequire } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/actions/index");
-  let {
-    getDisplayedRequests,
-    getSortedRequests,
-  } = windowRequire("devtools/client/netmonitor/selectors/index");
 
   gStore.dispatch(Actions.batchEnable(false));
 
   let wait = waitForNetworkEvents(monitor, 2);
   yield ContentTask.spawn(tab.linkedBrowser, HTTPS_REDIRECT_SJS, function* (url) {
     content.wrappedJSObject.performRequests(1, url);
   });
   yield wait;
 
-  is(gStore.getState().requests.requests.size, 2, "There were two requests due to redirect.");
+  is(gStore.getState().requests.requests.size, 2,
+     "There were two requests due to redirect.");
 
-  let initial = getSortedRequests(gStore.getState()).get(0);
-  let redirect = getSortedRequests(gStore.getState()).get(1);
-
-  let initialSecurityIcon = document.querySelectorAll(".requests-security-state-icon")[0];
-  let redirectSecurityIcon = document.querySelectorAll(".requests-security-state-icon")[1];
+  let [
+    initialSecurityIcon,
+    redirectSecurityIcon,
+  ] = document.querySelectorAll(".requests-security-state-icon");
 
   ok(initialSecurityIcon.classList.contains("security-state-insecure"),
      "Initial request was marked insecure.");
 
   ok(redirectSecurityIcon.classList.contains("security-state-secure"),
      "Redirected request was marked secure.");
 
   yield teardown(monitor);
--- a/devtools/client/netmonitor/test/browser_net_security-state.js
+++ b/devtools/client/netmonitor/test/browser_net_security-state.js
@@ -14,20 +14,16 @@ add_task(function* () {
     "example.com": "security-state-secure",
     "nocert.example.com": "security-state-broken",
     "localhost": "security-state-local",
   };
 
   let { tab, monitor } = yield initNetMonitor(CUSTOM_GET_URL);
   let { document, gStore, windowRequire } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/actions/index");
-  let {
-    getDisplayedRequests,
-    getSortedRequests,
-  } = windowRequire("devtools/client/netmonitor/selectors/index");
 
   gStore.dispatch(Actions.batchEnable(false));
 
   yield performRequests();
 
   for (let subitemNode of Array.from(document.querySelectorAll(
     "requests-list-subitem.requests-list-security-and-domain"))) {
     let domain = subitemNode.querySelector(".requests-list-domain").textContent;
--- a/devtools/client/netmonitor/test/browser_net_security-tab-visibility.js
+++ b/devtools/client/netmonitor/test/browser_net_security-tab-visibility.js
@@ -29,17 +29,19 @@ add_task(function* () {
       visibleOnSecurityInfo: true,
       visibleOnceComplete: true,
     }
   ];
 
   let { tab, monitor } = yield initNetMonitor(CUSTOM_GET_URL);
   let { document, gStore, windowRequire } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/actions/index");
-  let { getSelectedRequest } = windowRequire("devtools/client/netmonitor/selectors/index");
+  let {
+    getSelectedRequest,
+  } = windowRequire("devtools/client/netmonitor/selectors/index");
 
   gStore.dispatch(Actions.batchEnable(false));
 
   for (let testcase of TEST_DATA) {
     info("Testing Security tab visibility for " + testcase.desc);
     let onNewItem = monitor.panelWin.once(EVENTS.NETWORK_EVENT);
     let onSecurityInfo = monitor.panelWin.once(EVENTS.RECEIVED_SECURITY_INFO);
     let onComplete = testcase.isBroken ?
--- a/devtools/client/netmonitor/test/browser_net_send-beacon.js
+++ b/devtools/client/netmonitor/test/browser_net_send-beacon.js
@@ -4,17 +4,17 @@
 "use strict";
 
 /**
  * Tests if beacons are handled correctly.
  */
 
 add_task(function* () {
   let { tab, monitor } = yield initNetMonitor(SEND_BEACON_URL);
- let { gStore, windowRequire } = monitor.panelWin;
+  let { gStore, windowRequire } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/actions/index");
   let { getSortedRequests } = windowRequire("devtools/client/netmonitor/selectors/index");
 
   gStore.dispatch(Actions.batchEnable(false));
 
   is(gStore.getState().requests.requests.size, 0, "The requests menu should be empty.");
 
   let wait = waitForNetworkEvents(monitor, 1);
--- a/devtools/client/netmonitor/test/browser_net_simple-request-data.js
+++ b/devtools/client/netmonitor/test/browser_net_simple-request-data.js
@@ -218,22 +218,25 @@ function test() {
       );
     });
 
     monitor.panelWin.once(EVENTS.RECEIVED_RESPONSE_CONTENT, () => {
       let requestItem = getSortedRequests(gStore.getState()).get(0);
 
       ok(requestItem.responseContent,
         "There should be a responseContent data available.");
+      // eslint-disable-next-line mozilla/no-cpows-in-tests
       is(requestItem.responseContent.content.mimeType,
         "text/plain; charset=utf-8",
         "The responseContent data has an incorrect |content.mimeType| property.");
+      // eslint-disable-next-line mozilla/no-cpows-in-tests
       is(requestItem.responseContent.content.text,
         "Hello world!",
         "The responseContent data has an incorrect |content.text| property.");
+      // eslint-disable-next-line mozilla/no-cpows-in-tests
       is(requestItem.responseContent.content.size,
         12,
         "The responseContent data has an incorrect |content.size| property.");
 
       verifyRequestItemTarget(
         document,
         getDisplayedRequests(gStore.getState()),
         requestItem,
--- a/devtools/client/netmonitor/test/browser_net_simple-request-details.js
+++ b/devtools/client/netmonitor/test/browser_net_simple-request-details.js
@@ -8,23 +8,24 @@
  */
 
 add_task(function* () {
   let { L10N } = require("devtools/client/netmonitor/utils/l10n");
 
   let { tab, monitor } = yield initNetMonitor(SIMPLE_SJS);
   info("Starting test... ");
 
-  let { document, gStore, windowRequire } = monitor.panelWin;
+  let { document, gStore, windowRequire, NetMonitorView } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/actions/index");
   let { EVENTS } = windowRequire("devtools/client/netmonitor/constants");
   let {
-    getDisplayedRequests,
+    getSelectedRequest,
     getSortedRequests,
   } = windowRequire("devtools/client/netmonitor/selectors/index");
+  let Editor = require("devtools/client/sourceeditor/editor");
 
   gStore.dispatch(Actions.batchEnable(false));
 
   let wait = waitForNetworkEvents(monitor, 1);
   tab.linkedBrowser.reload();
   yield wait;
 
   is(getSelectedRequest(gStore.getState()), undefined,
--- a/devtools/client/netmonitor/test/browser_net_simple-request.js
+++ b/devtools/client/netmonitor/test/browser_net_simple-request.js
@@ -13,21 +13,16 @@
  * 4) Number of requests displayed
  */
 add_task(function* () {
   let { tab, monitor } = yield initNetMonitor(SIMPLE_URL);
   info("Starting test... ");
 
   let { document, gStore, windowRequire } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/actions/index");
-  let { EVENTS } = windowRequire("devtools/client/netmonitor/constants");
-  let {
-    getDisplayedRequests,
-    getSortedRequests,
-  } = windowRequire("devtools/client/netmonitor/selectors/index");
 
   gStore.dispatch(Actions.batchEnable(false));
 
   is(document.querySelector(".network-details-panel-toggle").hasAttribute("disabled"),
     true,
     "The pane toggle button should be disabled when the frontend is opened.");
   ok(document.querySelector(".request-list-empty-notice"),
     "An empty notice should be displayed when the frontend is opened.");
--- a/devtools/client/netmonitor/test/browser_net_statistics-01.js
+++ b/devtools/client/netmonitor/test/browser_net_statistics-01.js
@@ -22,27 +22,31 @@ add_task(function* () {
   gStore.dispatch(Actions.openStatistics(true));
 
   ok(document.querySelector(".statistics-panel"),
     "The current main panel is correct.");
 
   info("Waiting for placeholder to display");
 
   yield waitUntil(
-    () => document.querySelectorAll(".pie-chart-container[placeholder=true]").length == 2);
+    () => document.querySelectorAll(".pie-chart-container[placeholder=true]")
+                  .length == 2);
   ok(true, "Two placeholder pie charts appear to be rendered correctly.");
 
   yield waitUntil(
-    () => document.querySelectorAll(".table-chart-container[placeholder=true]").length == 2);
+    () => document.querySelectorAll(".table-chart-container[placeholder=true]")
+                  .length == 2);
   ok(true, "Two placeholde table charts appear to be rendered correctly.");
 
   info("Waiting for chart to display");
 
   yield waitUntil(
-    () => document.querySelectorAll(".pie-chart-container:not([placeholder=true])").length == 2);
+    () => document.querySelectorAll(".pie-chart-container:not([placeholder=true])")
+                  .length == 2);
   ok(true, "Two real pie charts appear to be rendered correctly.");
 
   yield waitUntil(
-    () => document.querySelectorAll(".table-chart-container:not([placeholder=true])").length == 2);
+    () => document.querySelectorAll(".table-chart-container:not([placeholder=true])")
+                  .length == 2);
   ok(true, "Two real table charts appear to be rendered correctly.");
 
   yield teardown(monitor);
 });
--- a/devtools/client/netmonitor/test/browser_net_statistics-02.js
+++ b/devtools/client/netmonitor/test/browser_net_statistics-02.js
@@ -30,17 +30,18 @@ add_task(function* () {
   info("The correct filtering predicates are used before entering perf. analysis mode.");
 
   gStore.dispatch(Actions.openStatistics(true));
 
   ok(document.querySelector(".statistics-panel"),
     "The main panel is switched to the statistics panel.");
 
   yield waitUntil(
-    () => document.querySelectorAll(".pie-chart-container:not([placeholder=true])").length == 2);
+    () => document.querySelectorAll(".pie-chart-container:not([placeholder=true])")
+                  .length == 2);
   ok(true, "Two real pie charts appear to be rendered correctly.");
 
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".pie-chart-slice"));
 
   ok(document.querySelector(".monitor-panel"),
     "The main panel is switched back to the monitor panel.");
 
--- a/devtools/client/netmonitor/test/browser_net_throttle.js
+++ b/devtools/client/netmonitor/test/browser_net_throttle.js
@@ -9,18 +9,17 @@ add_task(function* () {
   yield throttleTest(true);
   yield throttleTest(false);
 });
 
 function* throttleTest(actuallyThrottle) {
   requestLongerTimeout(2);
 
   let { monitor } = yield initNetMonitor(SIMPLE_URL);
-  let { document, gStore, windowRequire, NetMonitorController } = monitor.panelWin;
-  let Actions = windowRequire("devtools/client/netmonitor/actions/index");
+  let { gStore, windowRequire, NetMonitorController } = monitor.panelWin;
   let { ACTIVITY_TYPE } = windowRequire("devtools/client/netmonitor/constants");
   let { EVENTS } = windowRequire("devtools/client/netmonitor/constants");
   let {
     getSortedRequests,
   } = windowRequire("devtools/client/netmonitor/selectors/index");
 
   info("Starting test... (actuallyThrottle = " + actuallyThrottle + ")");
 
--- a/devtools/client/netmonitor/test/browser_net_timing-division.js
+++ b/devtools/client/netmonitor/test/browser_net_timing-division.js
@@ -34,25 +34,26 @@ add_task(function* () {
   info("Number of millisecond divisions: " + milDivs.length);
   info("Number of second divisions: " + secDivs.length);
   info("Number of minute divisions: " + minDivs.length);
 
   milDivs.forEach(div => info(`Millisecond division: ${div.textContent}`));
   secDivs.forEach(div => info(`Second division: ${div.textContent}`));
   minDivs.forEach(div => info(`Minute division: ${div.textContent}`));
 
-  is(gStore.getState().requests.requests.size, 2, "There should be only two requests made.");
+  is(gStore.getState().requests.requests.size, 2,
+     "There should be only two requests made.");
 
   let firstRequest = getSortedRequests(gStore.getState()).get(0);
   let lastRequest = getSortedRequests(gStore.getState()).get(1);
 
   info("First request happened at: " +
-    firstRequest.responseHeaders.headers.find(e => e.name == "Date").value);
+       firstRequest.responseHeaders.headers.find(e => e.name == "Date").value);
   info("Last request happened at: " +
-    lastRequest.responseHeaders.headers.find(e => e.name == "Date").value);
+       lastRequest.responseHeaders.headers.find(e => e.name == "Date").value);
 
   ok(secDivs.length,
-    "There should be at least one division on the seconds time scale.");
+     "There should be at least one division on the seconds time scale.");
   ok(secDivs[0].textContent.match(/\d+\.\d{2}\s\w+/),
-    "The division on the seconds time scale looks legit.");
+     "The division on the seconds time scale looks legit.");
 
   return teardown(monitor);
 });
--- a/devtools/client/netmonitor/test/head.js
+++ b/devtools/client/netmonitor/test/head.js
@@ -1,29 +1,33 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /* import-globals-from ../../framework/test/shared-head.js */
+/* exported Toolbox, restartNetMonitor, teardown, waitForExplicitFinish,
+   verifyRequestItemTarget, waitFor, testFilterButtons, loadCommonFrameScript,
+   performRequestsInContent, waitForNetworkEvents */
 
 "use strict";
 
 // shared-head.js handles imports, constants, and utility functions
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js",
   this);
 
 const { EVENTS } = require("devtools/client/netmonitor/constants");
-var { Toolbox } = require("devtools/client/framework/toolbox");
+let { Toolbox } = require("devtools/client/framework/toolbox");
 const {
   decodeUnicodeUrl,
   getUrlBaseName,
   getUrlQuery,
   getUrlHost,
 } = require("devtools/client/netmonitor/utils/request-utils");
 
+/* eslint-disable no-unused-vars, max-len */
 const EXAMPLE_URL = "http://example.com/browser/devtools/client/netmonitor/test/";
 const HTTPS_EXAMPLE_URL = "https://example.com/browser/devtools/client/netmonitor/test/";
 
 const API_CALLS_URL = EXAMPLE_URL + "html_api-calls-test-page.html";
 const SIMPLE_URL = EXAMPLE_URL + "html_simple-test-page.html";
 const NAVIGATE_URL = EXAMPLE_URL + "html_navigate-test-page.html";
 const CONTENT_TYPE_URL = EXAMPLE_URL + "html_content-type-test-page.html";
 const CONTENT_TYPE_WITHOUT_CACHE_URL = EXAMPLE_URL + "html_content-type-without-cache-test-page.html";
@@ -64,16 +68,17 @@ const HSTS_SJS = EXAMPLE_URL + "sjs_hsts
 
 const HSTS_BASE_URL = EXAMPLE_URL;
 const HSTS_PAGE_URL = CUSTOM_GET_URL;
 
 const TEST_IMAGE = EXAMPLE_URL + "test-image.png";
 const TEST_IMAGE_DATA_URI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==";
 
 const FRAME_SCRIPT_UTILS_URL = "chrome://devtools/content/shared/frame-script-utils.js";
+/* eslint-enable no-unused-vars, max-len */
 
 // All tests are asynchronous.
 waitForExplicitFinish();
 
 const gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log");
 // To enable logging for try runs, just set the pref to true.
 Services.prefs.setBoolPref("devtools.debugger.log", false);
 
@@ -86,55 +91,55 @@ const gDefaultFilters = Services.prefs.g
 registerCleanupFunction(() => {
   info("finish() was called, cleaning up...");
 
   Services.prefs.setBoolPref("devtools.debugger.log", gEnableLogging);
   Services.prefs.setCharPref("devtools.netmonitor.filters", gDefaultFilters);
   Services.prefs.clearUserPref("devtools.cache.disabled");
 });
 
-function waitForNavigation(aTarget) {
+function waitForNavigation(target) {
   let deferred = promise.defer();
-  aTarget.once("will-navigate", () => {
-    aTarget.once("navigate", () => {
+  target.once("will-navigate", () => {
+    target.once("navigate", () => {
       deferred.resolve();
     });
   });
   return deferred.promise;
 }
 
-function reconfigureTab(aTarget, aOptions) {
+function reconfigureTab(target, options) {
   let deferred = promise.defer();
-  aTarget.activeTab.reconfigure(aOptions, deferred.resolve);
+  target.activeTab.reconfigure(options, deferred.resolve);
   return deferred.promise;
 }
 
-function toggleCache(aTarget, aDisabled) {
-  let options = { cacheDisabled: aDisabled, performReload: true };
-  let navigationFinished = waitForNavigation(aTarget);
+function toggleCache(target, disabled) {
+  let options = { cacheDisabled: disabled, performReload: true };
+  let navigationFinished = waitForNavigation(target);
 
   // Disable the cache for any toolbox that it is opened from this point on.
-  Services.prefs.setBoolPref("devtools.cache.disabled", aDisabled);
+  Services.prefs.setBoolPref("devtools.cache.disabled", disabled);
 
-  return reconfigureTab(aTarget, options).then(() => navigationFinished);
+  return reconfigureTab(target, options).then(() => navigationFinished);
 }
 
-function initNetMonitor(aUrl, aWindow, aEnableCache) {
+function initNetMonitor(url, window, enableCache) {
   info("Initializing a network monitor pane.");
 
   return Task.spawn(function* () {
-    let tab = yield addTab(aUrl);
-    info("Net tab added successfully: " + aUrl);
+    let tab = yield addTab(url);
+    info("Net tab added successfully: " + url);
 
     let target = TargetFactory.forTab(tab);
 
     yield target.makeRemote();
     info("Target remoted.");
 
-    if (!aEnableCache) {
+    if (!enableCache) {
       info("Disabling cache and reloading page.");
       yield toggleCache(target, true);
       info("Cache disabled when the current and all future toolboxes are open.");
       // Remove any requests generated by the reload while toggling the cache to
       // avoid interfering with the test.
       isnot([...target.activeConsole.getNetworkEvents()].length, 0,
          "Request to reconfigure the tab was recorded.");
       target.activeConsole.clearNetworkRequests();
@@ -170,19 +175,19 @@ function teardown(monitor) {
     let tab = monitor.toolbox.target.tab;
 
     let onDestroyed = monitor.once("destroyed");
     yield removeTab(tab);
     yield onDestroyed;
   });
 }
 
-function waitForNetworkEvents(aMonitor, aGetRequests, aPostRequests = 0) {
+function waitForNetworkEvents(monitor, getRequests, postRequests = 0) {
   let deferred = promise.defer();
-  let panel = aMonitor.panelWin;
+  let panel = monitor.panelWin;
   let progress = {};
   let genericEvents = 0;
   let postEvents = 0;
   let awaitedEventsToListeners = [
     ["UPDATING_REQUEST_HEADERS", onGenericEvent],
     ["RECEIVED_REQUEST_HEADERS", onGenericEvent],
     ["UPDATING_REQUEST_COOKIES", onGenericEvent],
     ["RECEIVED_REQUEST_COOKIES", onGenericEvent],
@@ -195,19 +200,23 @@ function waitForNetworkEvents(aMonitor, 
     ["STARTED_RECEIVING_RESPONSE", onGenericEvent],
     ["UPDATING_RESPONSE_CONTENT", onGenericEvent],
     ["RECEIVED_RESPONSE_CONTENT", onGenericEvent],
     ["UPDATING_EVENT_TIMINGS", onGenericEvent],
     ["RECEIVED_EVENT_TIMINGS", onGenericEvent]
   ];
 
   function initProgressForURL(url) {
-    if (progress[url]) return;
+    if (progress[url]) {
+      return;
+    }
     progress[url] = {};
-    awaitedEventsToListeners.forEach(([e]) => progress[url][e] = 0);
+    awaitedEventsToListeners.forEach(function ([e]) {
+      progress[url][e] = 0;
+    });
   }
 
   function updateProgressForURL(url, event) {
     initProgressForURL(url);
     progress[url][Object.keys(EVENTS).find(e => EVENTS[e] == event)] = 1;
   }
 
   function onGenericEvent(event, actor) {
@@ -217,137 +226,141 @@ function waitForNetworkEvents(aMonitor, 
 
   function onPostEvent(event, actor) {
     postEvents++;
     maybeResolve(event, actor);
   }
 
   function maybeResolve(event, actor) {
     info("> Network events progress: " +
-      genericEvents + "/" + ((aGetRequests + aPostRequests) * 13) + ", " +
-      postEvents + "/" + (aPostRequests * 2) + ", " +
+      genericEvents + "/" + ((getRequests + postRequests) * 13) + ", " +
+      postEvents + "/" + (postRequests * 2) + ", " +
       "got " + event + " for " + actor);
 
     let networkInfo =
       panel.NetMonitorController.webConsoleClient.getNetworkRequest(actor);
     let url = networkInfo.request.url;
     updateProgressForURL(url, event);
 
     // Uncomment this to get a detailed progress logging (when debugging a test)
     // info("> Current state: " + JSON.stringify(progress, null, 2));
 
     // There are 15 updates which need to be fired for a request to be
     // considered finished. The "requestPostData" packet isn't fired for
     // non-POST requests.
-    if (genericEvents >= (aGetRequests + aPostRequests) * 13 &&
-        postEvents >= aPostRequests * 2) {
-
+    if (genericEvents >= (getRequests + postRequests) * 13 &&
+        postEvents >= postRequests * 2) {
       awaitedEventsToListeners.forEach(([e, l]) => panel.off(EVENTS[e], l));
       executeSoon(deferred.resolve);
     }
   }
 
   awaitedEventsToListeners.forEach(([e, l]) => panel.on(EVENTS[e], l));
   return deferred.promise;
 }
 
-function verifyRequestItemTarget(document, requestList, requestItem, aMethod,
-                                 aUrl, aData = {}) {
-  info("> Verifying: " + aMethod + " " + aUrl + " " + aData.toSource());
+function verifyRequestItemTarget(document, requestList, requestItem, method,
+                                 url, data = {}) {
+  info("> Verifying: " + method + " " + url + " " + data.toSource());
 
   let visibleIndex = requestList.indexOf(requestItem);
 
   info("Visible index of item: " + visibleIndex);
 
   let { fuzzyUrl, status, statusText, cause, type, fullMimeType,
-        transferred, size, time, displayedStatus } = aData;
+        transferred, size, time, displayedStatus } = data;
 
   let target = document.querySelectorAll(".request-list-item")[visibleIndex];
-  let unicodeUrl = decodeUnicodeUrl(aUrl);
-  let name = getUrlBaseName(aUrl);
-  let query = getUrlQuery(aUrl);
-  let hostPort = getUrlHost(aUrl);
+  let unicodeUrl = decodeUnicodeUrl(url);
+  let name = getUrlBaseName(url);
+  let query = getUrlQuery(url);
+  let hostPort = getUrlHost(url);
   let remoteAddress = requestItem.remoteAddress;
 
   if (fuzzyUrl) {
-    ok(requestItem.method.startsWith(aMethod), "The attached method is correct.");
-    ok(requestItem.url.startsWith(aUrl), "The attached url is correct.");
+    ok(requestItem.method.startsWith(method), "The attached method is correct.");
+    ok(requestItem.url.startsWith(url), "The attached url is correct.");
   } else {
-    is(requestItem.method, aMethod, "The attached method is correct.");
-    is(requestItem.url, aUrl, "The attached url is correct.");
+    is(requestItem.method, method, "The attached method is correct.");
+    is(requestItem.url, url, "The attached url is correct.");
   }
 
   is(target.querySelector(".requests-list-method").textContent,
-    aMethod, "The displayed method is correct.");
+    method, "The displayed method is correct.");
 
   if (fuzzyUrl) {
     ok(target.querySelector(".requests-list-file").textContent.startsWith(
       name + (query ? "?" + query : "")), "The displayed file is correct.");
-    ok(target.querySelector(".requests-list-file").getAttribute("title").startsWith(unicodeUrl),
+    ok(target.querySelector(".requests-list-file").getAttribute("title")
+                                                  .startsWith(unicodeUrl),
       "The tooltip file is correct.");
   } else {
     is(target.querySelector(".requests-list-file").textContent,
       name + (query ? "?" + query : ""), "The displayed file is correct.");
     is(target.querySelector(".requests-list-file").getAttribute("title"),
       unicodeUrl, "The tooltip file is correct.");
   }
 
   is(target.querySelector(".requests-list-domain").textContent,
     hostPort, "The displayed domain is correct.");
 
   let domainTooltip = hostPort + (remoteAddress ? " (" + remoteAddress + ")" : "");
   is(target.querySelector(".requests-list-domain").getAttribute("title"),
     domainTooltip, "The tooltip domain is correct.");
 
   if (status !== undefined) {
-    let value = target.querySelector(".requests-list-status-icon").getAttribute("data-code");
+    let value = target.querySelector(".requests-list-status-icon")
+                      .getAttribute("data-code");
     let codeValue = target.querySelector(".requests-list-status-code").textContent;
     let tooltip = target.querySelector(".requests-list-status").getAttribute("title");
     info("Displayed status: " + value);
     info("Displayed code: " + codeValue);
     info("Tooltip status: " + tooltip);
-    is(value, displayedStatus ? displayedStatus : status, "The displayed status is correct.");
+    is(value, displayedStatus ? displayedStatus : status,
+      "The displayed status is correct.");
     is(codeValue, status, "The displayed status code is correct.");
     is(tooltip, status + " " + statusText, "The tooltip status is correct.");
   }
   if (cause !== undefined) {
     let value = target.querySelector(".requests-list-cause > .subitem-label").textContent;
     let tooltip = target.querySelector(".requests-list-cause").getAttribute("title");
     info("Displayed cause: " + value);
     info("Tooltip cause: " + tooltip);
     is(value, cause.type, "The displayed cause is correct.");
-    is(tooltip, cause.loadingDocumentUri, "The tooltip cause is correct.")
+    is(tooltip, cause.loadingDocumentUri, "The tooltip cause is correct.");
   }
   if (type !== undefined) {
     let value = target.querySelector(".requests-list-type").textContent;
     let tooltip = target.querySelector(".requests-list-type").getAttribute("title");
     info("Displayed type: " + value);
     info("Tooltip type: " + tooltip);
     is(value, type, "The displayed type is correct.");
     is(tooltip, fullMimeType, "The tooltip type is correct.");
   }
   if (transferred !== undefined) {
     let value = target.querySelector(".requests-list-transferred").textContent;
-    let tooltip = target.querySelector(".requests-list-transferred").getAttribute("title");
+    let tooltip = target.querySelector(".requests-list-transferred")
+                        .getAttribute("title");
     info("Displayed transferred size: " + value);
     info("Tooltip transferred size: " + tooltip);
     is(value, transferred, "The displayed transferred size is correct.");
     is(tooltip, transferred, "The tooltip transferred size is correct.");
   }
   if (size !== undefined) {
     let value = target.querySelector(".requests-list-size").textContent;
     let tooltip = target.querySelector(".requests-list-size").getAttribute("title");
     info("Displayed size: " + value);
     info("Tooltip size: " + tooltip);
     is(value, size, "The displayed size is correct.");
     is(tooltip, size, "The tooltip size is correct.");
   }
   if (time !== undefined) {
     let value = target.querySelector(".requests-list-timings-total").textContent;
-    let tooltip = target.querySelector(".requests-list-timings-total").getAttribute("title");
+    let tooltip = target.querySelector(".requests-list-timings-total")
+                        .getAttribute("title");
     info("Displayed time: " + value);
     info("Tooltip time: " + tooltip);
     ok(~~(value.match(/[0-9]+/)) >= 0, "The displayed time is correct.");
     ok(~~(tooltip.match(/[0-9]+/)) >= 0, "The tooltip time is correct.");
   }
 
   if (visibleIndex !== -1) {
     if (visibleIndex % 2 === 0) {
@@ -398,22 +411,22 @@ function testFilterButtons(monitor, filt
 /**
  * Tests if filter buttons have 'checked' attributes set correctly.
  *
  * @param array aIsChecked
  *        An array specifying if a button at given index should have a
  *        'checked' attribute. For example, if the third item of the array
  *        evaluates to true, the third button should be checked.
  */
-function testFilterButtonsCustom(aMonitor, aIsChecked) {
-  let doc = aMonitor.panelWin.document;
+function testFilterButtonsCustom(monitor, isChecked) {
+  let doc = monitor.panelWin.document;
   let buttons = doc.querySelectorAll("#requests-list-filter-buttons button");
-  for (let i = 0; i < aIsChecked.length; i++) {
+  for (let i = 0; i < isChecked.length; i++) {
     let button = buttons[i];
-    if (aIsChecked[i]) {
+    if (isChecked[i]) {
       is(button.classList.contains("checked"), true,
         "The " + button.id + " button should have a 'checked' class.");
       is(button.getAttribute("aria-pressed"), "true",
         "The " + button.id + " button should set 'aria-pressed' = true.");
     } else {
       is(button.classList.contains("checked"), false,
         "The " + button.id + " button should not have a 'checked' class.");
       is(button.getAttribute("aria-pressed"), "false",
@@ -468,19 +481,18 @@ function performRequestsInContent(reques
  *         resolves otherwise
  */
 function executeInContent(name, data = {}, objects = {}, expectResponse = true) {
   let mm = gBrowser.selectedBrowser.messageManager;
 
   mm.sendAsyncMessage(name, data, objects);
   if (expectResponse) {
     return waitForContentMessage(name);
-  } else {
-    return promise.resolve();
   }
+  return promise.resolve();
 }
 
 /**
  * Wait for a content -> chrome message on the message manager (the window
  * messagemanager is used).
  * @param {String} name The message name
  * @return {Promise} A promise that resolves to the response data when the
  * message has been received
--- a/devtools/client/netmonitor/test/html_api-calls-test-page.html
+++ b/devtools/client/netmonitor/test/html_api-calls-test-page.html
@@ -10,37 +10,42 @@
     <meta http-equiv="Expires" content="0" />
     <title>Network Monitor test page</title>
   </head>
 
   <body>
     <p>API calls request test</p>
 
     <script type="text/javascript">
-      function get(aAddress, aCallback) {
-        var xhr = new XMLHttpRequest();
-        xhr.open("GET", aAddress, true);
+      /* exported performRequests */
+      "use strict";
 
-        xhr.onreadystatechange = function() {
+      function get(address, callback) {
+        let xhr = new XMLHttpRequest();
+        xhr.open("GET", address, true);
+
+        xhr.onreadystatechange = function () {
           if (this.readyState == this.DONE) {
-            aCallback();
+            callback();
           }
         };
         xhr.send();
       }
 
       function performRequests() {
-        get("/api/fileName.xml", function() {
-          get("/api/file%E2%98%A2.xml", function() {
-            get("/api/ascii/get/", function() {
-              get("/api/unicode/%E2%98%A2/", function() {
-                get("/api/search/?q=search%E2%98%A2", function() {
+        /* eslint-disable max-nested-callbacks */
+        get("/api/fileName.xml", function () {
+          get("/api/file%E2%98%A2.xml", function () {
+            get("/api/ascii/get/", function () {
+              get("/api/unicode/%E2%98%A2/", function () {
+                get("/api/search/?q=search%E2%98%A2", function () {
                   // Done.
                 });
               });
             });
           });
         });
+        /* eslint-enable max-nested-callbacks */
       }
     </script>
   </body>
 
 </html>
--- a/devtools/client/netmonitor/test/html_brotli-test-page.html
+++ b/devtools/client/netmonitor/test/html_brotli-test-page.html
@@ -10,29 +10,32 @@
     <meta http-equiv="Expires" content="0" />
     <title>Network Monitor test page</title>
   </head>
 
   <body>
     <p>Brotli test</p>
 
     <script type="text/javascript">
-      function get(aAddress, aCallback) {
-        var xhr = new XMLHttpRequest();
-        xhr.open("GET", aAddress, true);
+      /* exported performRequests */
+      "use strict";
 
-        xhr.onreadystatechange = function() {
+      function get(address, callback) {
+        let xhr = new XMLHttpRequest();
+        xhr.open("GET", address, true);
+
+        xhr.onreadystatechange = function () {
           if (this.readyState == this.DONE) {
-            aCallback();
+            callback();
           }
         };
         xhr.send(null);
       }
 
       function performRequests() {
-        get("sjs_content-type-test-server.sjs?fmt=br", function() {
+        get("sjs_content-type-test-server.sjs?fmt=br", function () {
           // Done.
         });
       }
     </script>
   </body>
 
 </html>
--- a/devtools/client/netmonitor/test/html_cause-test-page.html
+++ b/devtools/client/netmonitor/test/html_cause-test-page.html
@@ -11,18 +11,20 @@
     <title>Network Monitor test page</title>
     <link rel="stylesheet" type="text/css" href="stylesheet_request" />
   </head>
 
   <body>
     <p>Request cause test</p>
     <img src="img_request" />
     <script type="text/javascript">
+      "use strict";
+
       function performXhrRequest() {
-        var xhr = new XMLHttpRequest();
+        let xhr = new XMLHttpRequest();
         xhr.open("GET", "xhr_request", true);
         xhr.send();
       }
 
       function performFetchRequest() {
         fetch("fetch_request");
       }
 
--- a/devtools/client/netmonitor/test/html_content-type-test-page.html
+++ b/devtools/client/netmonitor/test/html_content-type-test-page.html
@@ -10,39 +10,44 @@
     <meta http-equiv="Expires" content="0" />
     <title>Network Monitor test page</title>
   </head>
 
   <body>
     <p>Content type test</p>
 
     <script type="text/javascript">
-      function get(aAddress, aCallback) {
-        var xhr = new XMLHttpRequest();
-        xhr.open("GET", aAddress, true);
+      /* exported performRequests */
+      "use strict";
 
-        xhr.onreadystatechange = function() {
+      function get(address, callback) {
+        let xhr = new XMLHttpRequest();
+        xhr.open("GET", address, true);
+
+        xhr.onreadystatechange = function () {
           if (this.readyState == this.DONE) {
-            aCallback();
+            callback();
           }
         };
         xhr.send(null);
       }
 
       function performRequests() {
-        get("sjs_content-type-test-server.sjs?fmt=xml", function() {
-          get("sjs_content-type-test-server.sjs?fmt=css", function() {
-            get("sjs_content-type-test-server.sjs?fmt=js", function() {
-              get("sjs_content-type-test-server.sjs?fmt=json", function() {
-                get("sjs_content-type-test-server.sjs?fmt=bogus", function() {
-                  get("test-image.png", function() {
+        /* eslint-disable max-nested-callbacks */
+        get("sjs_content-type-test-server.sjs?fmt=xml", function () {
+          get("sjs_content-type-test-server.sjs?fmt=css", function () {
+            get("sjs_content-type-test-server.sjs?fmt=js", function () {
+              get("sjs_content-type-test-server.sjs?fmt=json", function () {
+                get("sjs_content-type-test-server.sjs?fmt=bogus", function () {
+                  get("test-image.png", function () {
                     // Done.
                   });
                 });
               });
             });
           });
         });
+        /* eslint-enable max-nested-callbacks */
       }
     </script>
   </body>
 
 </html>
--- a/devtools/client/netmonitor/test/html_content-type-without-cache-test-page.html
+++ b/devtools/client/netmonitor/test/html_content-type-without-cache-test-page.html
@@ -10,43 +10,48 @@
     <meta http-equiv="Expires" content="0" />
     <title>Network Monitor test page</title>
   </head>
 
   <body>
     <p>Content type test</p>
 
     <script type="text/javascript">
-      function get(aAddress, aCallback) {
-        var xhr = new XMLHttpRequest();
-        xhr.open("GET", aAddress, true);
+      /* exported performRequests */
+      "use strict";
 
-        xhr.onreadystatechange = function() {
+      function get(address, callback) {
+        let xhr = new XMLHttpRequest();
+        xhr.open("GET", address, true);
+
+        xhr.onreadystatechange = function () {
           if (this.readyState == this.DONE) {
-            aCallback();
+            callback();
           }
         };
         xhr.send(null);
       }
 
       function performRequests() {
-        get("sjs_content-type-test-server.sjs?fmt=xml", function() {
-          get("sjs_content-type-test-server.sjs?fmt=css", function() {
-            get("sjs_content-type-test-server.sjs?fmt=js", function() {
-              get("sjs_content-type-test-server.sjs?fmt=json", function() {
-                get("sjs_content-type-test-server.sjs?fmt=bogus", function() {
-                  get("test-image.png?v=" + Math.random(), function() {
-                    get("sjs_content-type-test-server.sjs?fmt=gzip", function() {
-                      get("sjs_content-type-test-server.sjs?fmt=br", function() {
+        /* eslint-disable max-nested-callbacks */
+        get("sjs_content-type-test-server.sjs?fmt=xml", function () {
+          get("sjs_content-type-test-server.sjs?fmt=css", function () {
+            get("sjs_content-type-test-server.sjs?fmt=js", function () {
+              get("sjs_content-type-test-server.sjs?fmt=json", function () {
+                get("sjs_content-type-test-server.sjs?fmt=bogus", function () {
+                  get("test-image.png?v=" + Math.random(), function () {
+                    get("sjs_content-type-test-server.sjs?fmt=gzip", function () {
+                      get("sjs_content-type-test-server.sjs?fmt=br", function () {
                         // Done.
                       });
                     });
                   });
                 });
               });
             });
           });
         });
+        /* eslint-enable max-nested-callbacks */
       }
     </script>
   </body>
 
 </html>
--- a/devtools/client/netmonitor/test/html_copy-as-curl.html
+++ b/devtools/client/netmonitor/test/html_copy-as-curl.html
@@ -10,19 +10,22 @@
     <meta http-equiv="Expires" content="0" />
     <title>Network Monitor test page</title>
   </head>
 
   <body>
     <p>Performing a GET request</p>
 
     <script type="text/javascript">
-      function performRequest(aUrl) {
-        var xhr = new XMLHttpRequest();
-        xhr.open("GET", aUrl, true);
+      /* exported performRequest */
+      "use strict";
+
+      function performRequest(url) {
+        let xhr = new XMLHttpRequest();
+        xhr.open("GET", url, true);
         xhr.setRequestHeader("Accept-Language", window.navigator.language);
         xhr.setRequestHeader("X-Custom-Header-1", "Custom value");
         xhr.setRequestHeader("X-Custom-Header-2", "8.8.8.8");
         xhr.setRequestHeader("X-Custom-Header-3", "Mon, 3 Mar 2014 11:11:11 GMT");
         xhr.send(null);
       }
     </script>
   </body>
--- a/devtools/client/netmonitor/test/html_cors-test-page.html
+++ b/devtools/client/netmonitor/test/html_cors-test-page.html
@@ -10,18 +10,21 @@
     <meta http-equiv="Expires" content="0" />
     <title>Network Monitor test page</title>
   </head>
 
   <body>
     <p>POST with CORS test page</p>
 
     <script type="text/javascript">
+      /* exported performRequests */
+      "use strict";
+
       function post(url, contentType, postData) {
-        var xhr = new XMLHttpRequest();
+        let xhr = new XMLHttpRequest();
         xhr.open("POST", url, true);
         xhr.setRequestHeader("Content-Type", contentType);
         xhr.send(postData);
       }
 
       function performRequests(url, contentType, postData) {
         post(url, contentType, postData);
       }
--- a/devtools/client/netmonitor/test/html_curl-utils.html
+++ b/devtools/client/netmonitor/test/html_curl-utils.html
@@ -24,76 +24,78 @@
       <input type="text" name="param1" value="value1"/>
       <input type="text" name="param2" value="value2"/>
       <input type="text" name="param3" value="value3"/>
       <input type="submit"/>
     </form>
     <iframe name="target"></iframe>
 
     <script type="text/javascript">
+      /* exported performRequests */
+      "use strict";
 
-      function ajaxGet(aUrl, aCallback) {
-        var xhr = new XMLHttpRequest();
-        xhr.open("GET", aUrl + "?param1=value1&param2=value2&param3=value3", true);
+      function ajaxGet(url, callback) {
+        let xhr = new XMLHttpRequest();
+        xhr.open("GET", url + "?param1=value1&param2=value2&param3=value3", true);
         xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
-        xhr.onload = function() {
-          aCallback();
+        xhr.onload = function () {
+          callback();
         };
         xhr.send();
       }
 
-      function ajaxPost(aUrl, aCallback) {
-        var xhr = new XMLHttpRequest();
-        xhr.open("POST", aUrl, true);
+      function ajaxPost(url, callback) {
+        let xhr = new XMLHttpRequest();
+        xhr.open("POST", url, true);
         xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
         xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
-        xhr.onload = function() {
-          aCallback();
+        xhr.onload = function () {
+          callback();
         };
-        var params = "param1=value1&param2=value2&param3=value3";
+        const params = "param1=value1&param2=value2&param3=value3";
         xhr.send(params);
       }
 
-      function ajaxMultipart(aUrl, aCallback) {
-        var xhr = new XMLHttpRequest();
-        xhr.open("POST", aUrl, true);
+      function ajaxMultipart(url, callback) {
+        let xhr = new XMLHttpRequest();
+        xhr.open("POST", url, true);
         xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
-        xhr.onload = function() {
-          aCallback();
+        xhr.onload = function () {
+          callback();
         };
 
         getCanvasElem().toBlob((blob) => {
-          var formData = new FormData();
+          let formData = new FormData();
           formData.append("param1", "value1");
           formData.append("file", blob, "filename.png");
           xhr.send(formData);
         });
       }
 
       function submitForm() {
-        var form = document.querySelector("#post-form");
+        let form = document.querySelector("#post-form");
         form.submit();
       }
 
       function getCanvasElem() {
         return document.querySelector("canvas");
       }
 
       function initCanvas() {
-        var canvas = getCanvasElem();
-        var ctx = canvas.getContext("2d");
-        ctx.fillRect(0,0,100,100);
-        ctx.clearRect(20,20,60,60);
-        ctx.strokeRect(25,25,50,50);
+        let canvas = getCanvasElem();
+        let ctx = canvas.getContext("2d");
+        ctx.fillRect(0, 0, 100, 100);
+        ctx.clearRect(20, 20, 60, 60);
+        ctx.strokeRect(25, 25, 50, 50);
       }
 
-      function performRequests(aUrl) {
-        ajaxGet(aUrl, () => {
-          ajaxPost(aUrl, () => {
-            ajaxMultipart(aUrl, () => {
+      function performRequests(url) {
+        ajaxGet(url, () => {
+          ajaxPost(url, () => {
+            ajaxMultipart(url, () => {
               submitForm();
             });
           });
         });
       }
 
       initCanvas();
     </script>
--- a/devtools/client/netmonitor/test/html_custom-get-page.html
+++ b/devtools/client/netmonitor/test/html_custom-get-page.html
@@ -10,35 +10,38 @@
     <meta http-equiv="Expires" content="0" />
     <title>Network Monitor test page</title>
   </head>
 
   <body>
     <p>Performing a custom number of GETs</p>
 
     <script type="text/javascript">
-      function get(aAddress, aCallback) {
-        var xhr = new XMLHttpRequest();
-        xhr.open("GET", aAddress, true);
+      /* exported performRequests */
+      "use strict";
 
-        xhr.onreadystatechange = function() {
+      function get(address, callback) {
+        let xhr = new XMLHttpRequest();
+        xhr.open("GET", address, true);
+
+        xhr.onreadystatechange = function () {
           if (this.readyState == this.DONE) {
-            aCallback();
+            callback();
           }
         };
         xhr.send(null);
       }
 
       // Use a count parameter to defeat caching.
-      var count = 0;
+      let count = 0;
 
-      function performRequests(aTotal, aUrl, aTimeout = 0) {
-        if (!aTotal) {
+      function performRequests(total, url, timeout = 0) {
+        if (!total) {
           return;
         }
-        get(aUrl || "request_" + (count++), function() {
-          setTimeout(performRequests.bind(this, --aTotal, aUrl, aTimeout), aTimeout);
+        get(url || "request_" + (count++), function () {
+          setTimeout(performRequests.bind(this, --total, url, timeout), timeout);
         });
       }
     </script>
   </body>
 
 </html>
--- a/devtools/client/netmonitor/test/html_cyrillic-test-page.html
+++ b/devtools/client/netmonitor/test/html_cyrillic-test-page.html
@@ -11,29 +11,32 @@
     <title>Network Monitor test page</title>
   </head>
 
   <body>
     <p>Cyrillic type test</p>
     <p>Братан, ты вообще качаешься?</p>
 
     <script type="text/javascript">
-      function get(aAddress, aCallback) {
-        var xhr = new XMLHttpRequest();
-        xhr.open("GET", aAddress, true);
+      /* exported performRequests */
+      "use strict";
 
-        xhr.onreadystatechange = function() {
+      function get(address, callback) {
+        let xhr = new XMLHttpRequest();
+        xhr.open("GET", address, true);
+
+        xhr.onreadystatechange = function () {
           if (this.readyState == this.DONE) {
-            aCallback();
+            callback();
           }
         };
         xhr.send(null);
       }
 
       function performRequests() {
-        get("sjs_content-type-test-server.sjs?fmt=txt", function() {
+        get("sjs_content-type-test-server.sjs?fmt=txt", function () {
           // Done.
         });
       }
     </script>
   </body>
 
 </html>
--- a/devtools/client/netmonitor/test/html_filter-test-page.html
+++ b/devtools/client/netmonitor/test/html_filter-test-page.html
@@ -10,51 +10,59 @@
     <meta http-equiv="Expires" content="0" />
     <title>Network Monitor test page</title>
   </head>
 
   <body>
     <p>Filtering test</p>
 
     <script type="text/javascript">
-      function get(aAddress, aCallback) {
-        var xhr = new XMLHttpRequest();
+      /* exported performRequests */
+      "use strict";
+
+      function get(address, callback) {
+        let xhr = new XMLHttpRequest();
         // Use a random parameter to defeat caching.
-        xhr.open("GET", aAddress + "&" + Math.random(), true);
+        xhr.open("GET", address + "&" + Math.random(), true);
 
-        xhr.onreadystatechange = function() {
+        xhr.onreadystatechange = function () {
           if (this.readyState == this.DONE) {
-            aCallback();
+            callback();
           }
         };
         xhr.send(null);
       }
 
-      function performRequests(aOptions) {
-        var options = JSON.parse(aOptions);
-        get("sjs_content-type-test-server.sjs?fmt=html&res=" + options.htmlContent, function() {
-          get("sjs_content-type-test-server.sjs?fmt=css", function() {
-            get("sjs_content-type-test-server.sjs?fmt=js", function() {
-              if (!options.getMedia) {
-                return;
-              }
-              get("sjs_content-type-test-server.sjs?fmt=font", function() {
-                get("sjs_content-type-test-server.sjs?fmt=image", function() {
-                  get("sjs_content-type-test-server.sjs?fmt=audio", function() {
-                    get("sjs_content-type-test-server.sjs?fmt=video", function() {
-                      if (!options.getFlash) {
-                        return;
-                      }
-                      get("sjs_content-type-test-server.sjs?fmt=flash", function() {
-                        // Done.
+      function performRequests(optionsText) {
+        const options = JSON.parse(optionsText);
+
+        /* eslint-disable max-nested-callbacks */
+        get("sjs_content-type-test-server.sjs?fmt=html&res=" + options.htmlContent,
+            function () {
+              get("sjs_content-type-test-server.sjs?fmt=css", function () {
+                get("sjs_content-type-test-server.sjs?fmt=js", function () {
+                  if (!options.getMedia) {
+                    return;
+                  }
+                  get("sjs_content-type-test-server.sjs?fmt=font", function () {
+                    get("sjs_content-type-test-server.sjs?fmt=image", function () {
+                      get("sjs_content-type-test-server.sjs?fmt=audio", function () {
+                        get("sjs_content-type-test-server.sjs?fmt=video", function () {
+                          if (!options.getFlash) {
+                            return;
+                          }
+                          get("sjs_content-type-test-server.sjs?fmt=flash", function () {
+                            // Done.
+                          });
+                        });
                       });
                     });
                   });
                 });
               });
-            });
-          });
-        });
+            }
+        );
+        /* eslint-enable max-nested-callbacks */
       }
     </script>
   </body>
 
 </html>
--- a/devtools/client/netmonitor/test/html_frame-subdocument.html
+++ b/devtools/client/netmonitor/test/html_frame-subdocument.html
@@ -11,18 +11,20 @@
     <title>Network Monitor test page</title>
     <link rel="stylesheet" type="text/css" href="stylesheet_request" />
   </head>
 
   <body>
     <p>Request frame test</p>
     <img src="img_request" />
     <script type="text/javascript">
+      "use strict";
+
       function performXhrRequest() {
-        var xhr = new XMLHttpRequest();
+        let xhr = new XMLHttpRequest();
         xhr.open("GET", "xhr_request", true);
         xhr.send();
       }
 
       function performFetchRequest() {
         fetch("fetch_request");
       }
 
--- a/devtools/client/netmonitor/test/html_frame-test-page.html
+++ b/devtools/client/netmonitor/test/html_frame-test-page.html
@@ -12,18 +12,20 @@
     <link rel="stylesheet" type="text/css" href="stylesheet_request" />
   </head>
 
   <body>
     <p>Request frame test</p>
     <img src="img_request" />
     <iframe src="html_frame-subdocument.html"></iframe>
     <script type="text/javascript">
+      "use strict";
+
       function performXhrRequest() {
-        var xhr = new XMLHttpRequest();
+        let xhr = new XMLHttpRequest();
         xhr.open("GET", "xhr_request", true);
         xhr.send();
       }
 
       function performFetchRequest() {
         fetch("fetch_request");
       }
 
--- a/devtools/client/netmonitor/test/html_image-tooltip-test-page.html
+++ b/devtools/client/netmonitor/test/html_image-tooltip-test-page.html
@@ -10,17 +10,20 @@
     <meta http-equiv="Expires" content="0" />
     <title>Network Monitor test page</title>
   </head>
 
   <body>
     <p>tooltip test</p>
 
     <script type="text/javascript">
+      /* exported performRequests */
+      "use strict";
+
       function performRequests() {
-        var xhr = new XMLHttpRequest();
+        let xhr = new XMLHttpRequest();
         xhr.open("GET", "test-image.png?v=" + Math.random(), true);
         xhr.send(null);
       }
     </script>
   </body>
 
 </html>
--- a/devtools/client/netmonitor/test/html_infinite-get-page.html
+++ b/devtools/client/netmonitor/test/html_infinite-get-page.html
@@ -10,32 +10,34 @@
     <meta http-equiv="Expires" content="0" />
     <title>Network Monitor test page</title>
   </head>
 
   <body>
     <p>Infinite GETs</p>
 
     <script type="text/javascript">
-      function get(aAddress, aCallback) {
-        var xhr = new XMLHttpRequest();
-        xhr.open("GET", aAddress, true);
+      "use strict";
 
-        xhr.onreadystatechange = function() {
+      function get(address, callback) {
+        let xhr = new XMLHttpRequest();
+        xhr.open("GET", address, true);
+
+        xhr.onreadystatechange = function () {
           if (this.readyState == this.DONE) {
-            aCallback();
+            callback();
           }
         };
         xhr.send(null);
       }
 
       // Use a count parameter to defeat caching.
-      var count = 0;
+      let count = 0;
 
       (function performRequests() {
-        get("request_" + (count++), function() {
+        get("request_" + (count++), function () {
           setTimeout(performRequests, 50);
         });
       })();
     </script>
   </body>
 
 </html>
--- a/devtools/client/netmonitor/test/html_json-b64.html
+++ b/devtools/client/netmonitor/test/html_json-b64.html
@@ -10,29 +10,32 @@
     <meta http-equiv="Expires" content="0" />
     <title>Network Monitor test page</title>
   </head>
 
   <body>
     <p>JSON b64 test</p>
 
     <script type="text/javascript">
-      function get(aAddress, aCallback) {
-        var xhr = new XMLHttpRequest();
-        xhr.open("GET", aAddress, true);
+      /* exported performRequests */
+      "use strict";
 
-        xhr.onreadystatechange = function() {
+      function get(address, callback) {
+        let xhr = new XMLHttpRequest();
+        xhr.open("GET", address, true);
+
+        xhr.onreadystatechange = function () {
           if (this.readyState == this.DONE) {
-            aCallback();
+            callback();
           }
         };
         xhr.send(null);
       }
 
       function performRequests() {
-        get("sjs_content-type-test-server.sjs?fmt=json-b64", function() {
+        get("sjs_content-type-test-server.sjs?fmt=json-b64", function () {
           // Done.
         });
       }
     </script>
   </body>
 
 </html>
--- a/devtools/client/netmonitor/test/html_json-basic.html
+++ b/devtools/client/netmonitor/test/html_json-basic.html
@@ -11,30 +11,33 @@
     <title>Network Monitor test page</title>
   </head>
 
   <body>
     <p>JSON request test page</p>
     <p>Pass the JSON name (as supported by sjs_json-test-server.sjs) as a query parameter</p>
 
     <script type="text/javascript">
-      function get(aAddress, aCallback) {
-        var xhr = new XMLHttpRequest();
-        xhr.open("GET", aAddress, true);
+      /* exported performRequests */
+      "use strict";
 
-        xhr.onreadystatechange = function() {
+      function get(address, callback) {
+        let xhr = new XMLHttpRequest();
+        xhr.open("GET", address, true);
+
+        xhr.onreadystatechange = function () {
           if (this.readyState == this.DONE) {
-            aCallback();
+            callback();
           }
         };
         xhr.send(null);
       }
 
       function performRequests() {
         // Forward the query parameter for this page to sjs_json-test-server
-        get("sjs_json-test-server.sjs" + window.location.search, function() {
+        get("sjs_json-test-server.sjs" + window.location.search, function () {
           // Done.
         });
       }
     </script>
   </body>
 
 </html>
--- a/devtools/client/netmonitor/test/html_json-custom-mime-test-page.html
+++ b/devtools/client/netmonitor/test/html_json-custom-mime-test-page.html
@@ -10,29 +10,32 @@
     <meta http-equiv="Expires" content="0" />
     <title>Network Monitor test page</title>
   </head>
 
   <body>
     <p>JSONP test</p>
 
     <script type="text/javascript">
-      function get(aAddress, aCallback) {
-        var xhr = new XMLHttpRequest();
-        xhr.open("GET", aAddress, true);
+      /* exported performRequests */
+      "use strict";
 
-        xhr.onreadystatechange = function() {
+      function get(address, callback) {
+        let xhr = new XMLHttpRequest();
+        xhr.open("GET", address, true);
+
+        xhr.onreadystatechange = function () {
           if (this.readyState == this.DONE) {
-            aCallback();
+            callback();
           }
         };
         xhr.send(null);
       }
 
       function performRequests() {
-        get("sjs_content-type-test-server.sjs?fmt=json-custom-mime", function() {
+        get("sjs_content-type-test-server.sjs?fmt=json-custom-mime", function () {
           // Done.
         });
       }
     </script>
   </body>
 
 </html>
--- a/devtools/client/netmonitor/test/html_json-long-test-page.html
+++ b/devtools/client/netmonitor/test/html_json-long-test-page.html
@@ -10,29 +10,32 @@
     <meta http-equiv="Expires" content="0" />
     <title>Network Monitor test page</title>
   </head>
 
   <body>
     <p>JSON long string test</p>
 
     <script type="text/javascript">
-      function get(aAddress, aCallback) {
-        var xhr = new XMLHttpRequest();
-        xhr.open("GET", aAddress, true);
+      /* exported performRequests */
+      "use strict";
 
-        xhr.onreadystatechange = function() {
+      function get(address, callback) {
+        let xhr = new XMLHttpRequest();
+        xhr.open("GET", address, true);
+
+        xhr.onreadystatechange = function () {
           if (this.readyState == this.DONE) {
-            aCallback();
+            callback();
           }
         };
         xhr.send(null);
       }
 
       function performRequests() {
-        get("sjs_content-type-test-server.sjs?fmt=json-long", function() {
+        get("sjs_content-type-test-server.sjs?fmt=json-long", function () {
           // Done.
         });
       }
     </script>
   </body>
 
 </html>
--- a/devtools/client/netmonitor/test/html_json-malformed-test-page.html
+++ b/devtools/client/netmonitor/test/html_json-malformed-test-page.html
@@ -10,29 +10,32 @@
     <meta http-equiv="Expires" content="0" />
     <title>Network Monitor test page</title>
   </head>
 
   <body>
     <p>JSON malformed test</p>
 
     <script type="text/javascript">
-      function get(aAddress, aCallback) {
-        var xhr = new XMLHttpRequest();
-        xhr.open("GET", aAddress, true);
+      /* exported performRequests */
+      "use strict";
 
-        xhr.onreadystatechange = function() {
+      function get(address, callback) {
+        let xhr = new XMLHttpRequest();
+        xhr.open("GET", address, true);
+
+        xhr.onreadystatechange = function () {
           if (this.readyState == this.DONE) {
-            aCallback();
+            callback();
           }
         };
         xhr.send(null);
       }
 
       function performRequests() {
-        get("sjs_content-type-test-server.sjs?fmt=json-malformed", function() {
+        get("sjs_content-type-test-server.sjs?fmt=json-malformed", function () {
           // Done.
         });
       }
     </script>
   </body>
 
 </html>
--- a/devtools/client/netmonitor/test/html_json-text-mime-test-page.html
+++ b/devtools/client/netmonitor/test/html_json-text-mime-test-page.html
@@ -10,29 +10,32 @@
     <meta http-equiv="Expires" content="0" />
     <title>Network Monitor test page</title>
   </head>
 
   <body>
     <p>JSON text test</p>
 
     <script type="text/javascript">
-      function get(aAddress, aCallback) {
-        var xhr = new XMLHttpRequest();
-        xhr.open("GET", aAddress, true);
+      /* exported performRequests */
+      "use strict";
 
-        xhr.onreadystatechange = function() {
+      function get(address, callback) {
+        let xhr = new XMLHttpRequest();
+        xhr.open("GET", address, true);
+
+        xhr.onreadystatechange = function () {
           if (this.readyState == this.DONE) {
-            aCallback();
+            callback();
           }
         };
         xhr.send(null);
       }
 
       function performRequests() {
-        get("sjs_content-type-test-server.sjs?fmt=json-text-mime", function() {
+        get("sjs_content-type-test-server.sjs?fmt=json-text-mime", function () {
           // Done.
         });
       }
     </script>
   </body>
 
 </html>
--- a/devtools/client/netmonitor/test/html_jsonp-test-page.html
+++ b/devtools/client/netmonitor/test/html_jsonp-test-page.html
@@ -10,31 +10,34 @@
     <meta http-equiv="Expires" content="0" />
     <title>Network Monitor test page</title>
   </head>
 
   <body>
     <p>JSONP test</p>
 
     <script type="text/javascript">
-      function get(aAddress, aCallback) {
-        var xhr = new XMLHttpRequest();
-        xhr.open("GET", aAddress, true);
+      /* exported performRequests */
+      "use strict";
 
-        xhr.onreadystatechange = function() {
+      function get(address, callback) {
+        let xhr = new XMLHttpRequest();
+        xhr.open("GET", address, true);
+
+        xhr.onreadystatechange = function () {
           if (this.readyState == this.DONE) {
-            aCallback();
+            callback();
           }
         };
         xhr.send(null);
       }
 
       function performRequests() {
-        get("sjs_content-type-test-server.sjs?fmt=jsonp&jsonp=$_0123Fun", function() {
-          get("sjs_content-type-test-server.sjs?fmt=jsonp2&jsonp=$_4567Sad", function() {
+        get("sjs_content-type-test-server.sjs?fmt=jsonp&jsonp=$_0123Fun", function () {
+          get("sjs_content-type-test-server.sjs?fmt=jsonp2&jsonp=$_4567Sad", function () {
             // Done.
           });
         });
       }
     </script>
   </body>
 
 </html>
--- a/devtools/client/netmonitor/test/html_params-test-page.html
+++ b/devtools/client/netmonitor/test/html_params-test-page.html
@@ -10,58 +10,63 @@
     <meta http-equiv="Expires" content="0" />
     <title>Network Monitor test page</title>
   </head>
 
   <body>
     <p>Request params type test</p>
 
     <script type="text/javascript">
-      function get(aAddress, aQuery) {
-        var xhr = new XMLHttpRequest();
-        xhr.open("GET", aAddress + aQuery, true);
+      /* exported performRequests */
+      "use strict";
+
+      function get(address, query) {
+        let xhr = new XMLHttpRequest();
+        xhr.open("GET", address + query, true);
         xhr.send();
       }
 
-      function post(aAddress, aQuery, aContentType, aPostBody) {
-        var xhr = new XMLHttpRequest();
-        xhr.open("POST", aAddress + aQuery, true);
-        xhr.setRequestHeader("content-type", aContentType);
-        xhr.send(aPostBody);
+      function post(address, query, contentType, postBody) {
+        let xhr = new XMLHttpRequest();
+        xhr.open("POST", address + query, true);
+        xhr.setRequestHeader("content-type", contentType);
+        xhr.send(postBody);
       }
 
       function performRequests() {
-        var urlencoded = "application/x-www-form-urlencoded";
+        const urlencoded = "application/x-www-form-urlencoded";
 
-        setTimeout(function() {
+        /* eslint-disable max-nested-callbacks */
+        setTimeout(function () {
           post("baz", "?a", urlencoded, '{ "foo": "bar" }');
 
-          setTimeout(function() {
+          setTimeout(function () {
             post("baz", "?a=b", urlencoded, '{ "foo": "bar" }');
 
-            setTimeout(function() {
-              post("baz", "?a=b", urlencoded, '?foo=bar');
+            setTimeout(function () {
+              post("baz", "?a=b", urlencoded, "?foo=bar");
 
-              setTimeout(function() {
+              setTimeout(function () {
                 post("baz", "?a", undefined, '{ "foo": "bar" }');
 
-                setTimeout(function() {
+                setTimeout(function () {
                   post("baz", "?a=b", undefined, '{ "foo": "bar" }');
 
-                  setTimeout(function() {
-                    post("baz", "?a=b", undefined, '?foo=bar');
+                  setTimeout(function () {
+                    post("baz", "?a=b", undefined, "?foo=bar");
 
-                    setTimeout(function() {
+                    setTimeout(function () {
                       get("baz", "");
 
                       // Done.
                     }, 10);
                   }, 10);
                 }, 10);
               }, 10);
             }, 10);
           }, 10);
         }, 10);
+        /* eslint-enable max-nested-callbacks */
       }
     </script>
   </body>
 
 </html>
--- a/devtools/client/netmonitor/test/html_post-data-test-page.html
+++ b/devtools/client/netmonitor/test/html_post-data-test-page.html
@@ -22,56 +22,59 @@
     <form enctype="multipart/form-data" method="post" name="form-name">
       <input type="text" name="text" placeholder="text" value="Some text..."/>
       <input type="email" name="email" placeholder="email"/>
       <input type="range" name="range" value="42"/>
       <input type="button" value="Post me!" onclick="window.form()">
     </form>
 
     <script type="text/javascript">
-      function post(aAddress, aMessage, aCallback) {
-        var xhr = new XMLHttpRequest();
-        xhr.open("POST", aAddress, true);
+      /* exported performRequests */
+      "use strict";
+
+      function post(address, message, callback) {
+        let xhr = new XMLHttpRequest();
+        xhr.open("POST", address, true);
         xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
 
-        var data = "";
-        for (var i in aMessage) {
-          data += "&" + i + "=" + aMessage[i];
+        let data = "";
+        for (let i in message) {
+          data += "&" + i + "=" + message[i];
         }
 
-        xhr.onreadystatechange = function() {
+        xhr.onreadystatechange = function () {
           if (this.readyState == this.DONE) {
-            aCallback();
+            callback();
           }
         };
         xhr.send(data);
       }
 
-      function form(aAddress, aForm, aCallback) {
-        var formData = new FormData(document.forms.namedItem(aForm));
+      function form(address, formName, callback) {
+        let formData = new FormData(document.forms.namedItem(formName));
         formData.append("Custom field", "Extra data");
 
-        var xhr = new XMLHttpRequest();
-        xhr.open("POST", aAddress, true);
+        let xhr = new XMLHttpRequest();
+        xhr.open("POST", address, true);
 
-        xhr.onreadystatechange = function() {
+        xhr.onreadystatechange = function () {
           if (this.readyState == this.DONE) {
-            aCallback();
+            callback();
           }
         };
         xhr.send(formData);
       }
 
       function performRequests() {
-        var url = "sjs_simple-test-server.sjs";
-        var url1 = url + "?foo=bar&baz=42&type=urlencoded";
-        var url2 = url + "?foo=bar&baz=42&type=multipart";
+        const url = "sjs_simple-test-server.sjs";
+        const url1 = url + "?foo=bar&baz=42&type=urlencoded";
+        const url2 = url + "?foo=bar&baz=42&type=multipart";
 
-        post(url1, { foo: "bar", baz: 123 }, function() {
-          form(url2, "form-name", function() {
+        post(url1, { foo: "bar", baz: 123 }, function () {
+          form(url2, "form-name", function () {
             // Done.
           });
         });
       }
     </script>
   </body>
 
 </html>
--- a/devtools/client/netmonitor/test/html_post-json-test-page.html
+++ b/devtools/client/netmonitor/test/html_post-json-test-page.html
@@ -10,16 +10,19 @@
     <meta http-equiv="Expires" content="0" />
     <title>Network Monitor test page</title>
   </head>
 
   <body>
     <p>POST raw test</p>
 
     <script type="text/javascript">
+      /* exported performRequests */
+      "use strict";
+
       function post(address, message, callback) {
         let xhr = new XMLHttpRequest();
         xhr.open("POST", address, true);
         xhr.setRequestHeader("Content-Type", "application/json");
 
         xhr.onreadystatechange = function () {
           if (this.readyState == this.DONE) {
             callback();
--- a/devtools/client/netmonitor/test/html_post-raw-test-page.html
+++ b/devtools/client/netmonitor/test/html_post-raw-test-page.html
@@ -10,31 +10,34 @@
     <meta http-equiv="Expires" content="0" />
     <title>Network Monitor test page</title>
   </head>
 
   <body>
     <p>POST raw test</p>
 
     <script type="text/javascript">
-      function post(aAddress, aMessage, aCallback) {
-        var xhr = new XMLHttpRequest();
-        xhr.open("POST", aAddress, true);
+      /* exported performRequests */
+      "use strict";
+
+      function post(address, message, callback) {
+        let xhr = new XMLHttpRequest();
+        xhr.open("POST", address, true);
         xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded");
 
-        xhr.onreadystatechange = function() {
+        xhr.onreadystatechange = function () {
           if (this.readyState == this.DONE) {
-            aCallback();
+            callback();
           }
         };
-        xhr.send(aMessage);
+        xhr.send(message);
       }
 
       function performRequests() {
-        var rawData = "foo=bar&baz=123";
-        post("sjs_simple-test-server.sjs", rawData, function() {
+        const rawData = "foo=bar&baz=123";
+        post("sjs_simple-test-server.sjs", rawData, function () {
           // Done.
         });
       }
     </script>
   </body>
 
 </html>
--- a/devtools/client/netmonitor/test/html_post-raw-with-headers-test-page.html
+++ b/devtools/client/netmonitor/test/html_post-raw-with-headers-test-page.html
@@ -10,36 +10,39 @@
     <meta http-equiv="Expires" content="0" />
     <title>Network Monitor test page</title>
   </head>
 
   <body>
     <p>POST raw with headers test</p>
 
     <script type="text/javascript">
-      function post(aAddress, aMessage, aCallback) {
-        var xhr = new XMLHttpRequest();
-        xhr.open("POST", aAddress, true);
+      /* exported performRequests */
+      "use strict";
 
-        xhr.onreadystatechange = function() {
+      function post(address, message, callback) {
+        let xhr = new XMLHttpRequest();
+        xhr.open("POST", address, true);
+
+        xhr.onreadystatechange = function () {
           if (this.readyState == this.DONE) {
-            aCallback();
+            callback();
           }
         };
-        xhr.send(aMessage);
+        xhr.send(message);
       }
 
       function performRequests() {
-        var rawData = [
+        let rawData = [
           "content-type: application/x-www-form-urlencoded\r",
           "custom-header: hello world!\r",
           "\r",
           "\r",
           "foo=bar&baz=123"
         ];
-        post("sjs_simple-test-server.sjs", rawData.join("\n"), function() {
+        post("sjs_simple-test-server.sjs", rawData.join("\n"), function () {
           // Done.
         });
       }
     </script>
   </body>
 
 </html>
--- a/devtools/client/netmonitor/test/html_send-beacon.html
+++ b/devtools/client/netmonitor/test/html_send-beacon.html
@@ -10,14 +10,17 @@
     <meta http-equiv="Expires" content="0" />
     <title>Network Monitor test page</title>
   </head>
 
   <body>
     <p>Send beacon test</p>
 
     <script type="text/javascript">
+    /* exported performRequest */
+    "use strict";
+
     function performRequest() {
       navigator.sendBeacon("beacon_request");
     }
     </script>
   </body>
 </html>
--- a/devtools/client/netmonitor/test/html_single-get-page.html
+++ b/devtools/client/netmonitor/test/html_single-get-page.html
@@ -10,27 +10,29 @@
     <meta http-equiv="Expires" content="0" />
     <title>Network Monitor test page</title>
   </head>
 
   <body>
     <p>Performing a custom number of GETs</p>
 
     <script type="text/javascript">
-      function get(aAddress, aCallback) {
-        var xhr = new XMLHttpRequest();
-        xhr.open("GET", aAddress, true);
+      "use strict";
 
-        xhr.onreadystatechange = function() {
+      function get(address, callback) {
+        let xhr = new XMLHttpRequest();
+        xhr.open("GET", address, true);
+
+        xhr.onreadystatechange = function () {
           if (this.readyState == this.DONE) {
-            aCallback();
+            callback();
           }
         };
         xhr.send(null);
       }
 
       (function performRequests() {
-        get("request_0", function() {});
+        get("request_0", function () {});
       })();
     </script>
   </body>
 
 </html>
--- a/devtools/client/netmonitor/test/html_statistics-test-page.html
+++ b/devtools/client/netmonitor/test/html_statistics-test-page.html
@@ -10,19 +10,21 @@
     <meta http-equiv="Expires" content="0" />
     <title>Network Monitor test page</title>
   </head>
 
   <body>
     <p>Statistics test</p>
 
     <script type="text/javascript">
-      function get(aAddress) {
-        var xhr = new XMLHttpRequest();
-        xhr.open("GET", aAddress, true);
+      "use strict";
+
+      function get(address) {
+        let xhr = new XMLHttpRequest();
+        xhr.open("GET", address, true);
         xhr.send(null);
       }
 
       get("sjs_content-type-test-server.sjs?sts=304&fmt=txt");
       get("sjs_content-type-test-server.sjs?sts=304&fmt=xml");
       get("sjs_content-type-test-server.sjs?sts=304&fmt=html");
       get("sjs_content-type-test-server.sjs?sts=304&fmt=css");
       get("sjs_content-type-test-server.sjs?sts=304&fmt=js");
--- a/devtools/client/netmonitor/test/html_status-codes-test-page.html
+++ b/devtools/client/netmonitor/test/html_status-codes-test-page.html
@@ -10,45 +10,50 @@
     <meta http-equiv="Expires" content="0" />
     <title>Network Monitor test page</title>
   </head>
 
   <body>
     <p>Status codes test</p>
 
     <script type="text/javascript">
-      function get(aAddress, aCallback) {
-        var xhr = new XMLHttpRequest();
-        xhr.open("GET", aAddress, true);
+      /* exported performRequests, performCachedRequests */
+      "use strict";
 
-        xhr.onreadystatechange = function() {
+      function get(address, callback) {
+        let xhr = new XMLHttpRequest();
+        xhr.open("GET", address, true);
+
+        xhr.onreadystatechange = function () {
           if (this.readyState == this.DONE) {
-            aCallback();
+            callback();
           }
         };
         xhr.send(null);
       }
 
       function performRequests() {
-        get("sjs_status-codes-test-server.sjs?sts=100", function() {
-          get("sjs_status-codes-test-server.sjs?sts=200", function() {
-            get("sjs_status-codes-test-server.sjs?sts=300", function() {
-              get("sjs_status-codes-test-server.sjs?sts=400", function() {
-                get("sjs_status-codes-test-server.sjs?sts=500", function() {
+        /* eslint-disable max-nested-callbacks */
+        get("sjs_status-codes-test-server.sjs?sts=100", function () {
+          get("sjs_status-codes-test-server.sjs?sts=200", function () {
+            get("sjs_status-codes-test-server.sjs?sts=300", function () {
+              get("sjs_status-codes-test-server.sjs?sts=400", function () {
+                get("sjs_status-codes-test-server.sjs?sts=500", function () {
                   // Done.
                 });
               });
             });
           });
         });
+        /* eslint-enable max-nested-callbacks */
       }
 
       function performCachedRequests() {
-        get("sjs_status-codes-test-server.sjs?sts=ok&cached", function() {
-          get("sjs_status-codes-test-server.sjs?sts=redirect&cached", function() {
+        get("sjs_status-codes-test-server.sjs?sts=ok&cached", function () {
+          get("sjs_status-codes-test-server.sjs?sts=redirect&cached", function () {
             // Done.
           });
         });
       }
 
     </script>
   </body>
 
--- a/devtools/client/netmonitor/test/require-helper.js
+++ b/devtools/client/netmonitor/test/require-helper.js
@@ -26,9 +26,11 @@ requireHacker.global_hook("default", pat
   // Some modules depend on Chrome APIs which don't work in mocha. When such a module
   // is required, replace it with a mock version.
   switch (path) {
     case "devtools/shared/l10n":
       return `module.exports = require("devtools/client/netmonitor/test/fixtures/localization-helper")`;
     case "devtools/client/shared/redux/create-store":
       return `module.exports = require("devtools/client/netmonitor/test/fixtures/create-store")`;
   }
+
+  return null;
 });
--- a/devtools/client/netmonitor/test/service-workers/status-codes.html
+++ b/devtools/client/netmonitor/test/service-workers/status-codes.html
@@ -11,32 +11,35 @@
     <meta http-equiv="Expires" content="0" />
     <title>Network Monitor test page</title>
   </head>
 
   <body>
     <p>Status codes test</p>
 
     <script type="text/javascript">
+      /* exported registerServiceWorker, unregisterServiceWorker, performRequests */
+      "use strict";
+
       let swRegistration;
 
       function registerServiceWorker() {
         let sw = navigator.serviceWorker;
         return sw.register("status-codes-service-worker.js")
           .then(registration => {
             swRegistration = registration;
             console.log("Registered, scope is:", registration.scope);
             return sw.ready;
           }).then(() => {
             // wait until the page is controlled
             return new Promise(resolve => {
               if (sw.controller) {
                 resolve();
               } else {
-                sw.addEventListener('controllerchange', function () {
+                sw.addEventListener("controllerchange", function () {
                   resolve();
                 }, {once: true});
               }
             });
           }).catch(err => {
             console.error("Registration failed");
           });
       }
--- a/devtools/server/actors/highlighters/css-grid.js
+++ b/devtools/server/actors/highlighters/css-grid.js
@@ -236,16 +236,19 @@ CssGridHighlighter.prototype = extend(Au
     let { highlighterEnv } = this;
     highlighterEnv.off("navigate", this.onNavigate);
     highlighterEnv.off("will-navigate", this.onWillNavigate);
 
     let { pageListenerTarget } = highlighterEnv;
     pageListenerTarget.removeEventListener("pagehide", this.onPageHide);
 
     this.markup.destroy();
+
+    // Clear the pattern cache to avoid dead object exceptions (Bug 1342051).
+    this._clearCache();
     AutoRefreshHighlighter.prototype.destroy.call(this);
   },
 
   getElement(id) {
     return this.markup.getElement(this.ID_CLASS_PREFIX + id);
   },
 
   get ctx() {
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -5261,16 +5261,19 @@ void HTMLMediaElement::NetworkError()
 
 void HTMLMediaElement::DecodeError(const MediaResult& aError)
 {
   nsAutoString src;
   GetCurrentSrc(src);
   const char16_t* params[] = { src.get() };
   ReportLoadError("MediaLoadDecodeError", params, ArrayLength(params));
 
+  DecoderDoctorDiagnostics diagnostics;
+  diagnostics.StoreDecodeError(OwnerDoc(), aError, src, __func__);
+
   AudioTracks()->EmptyTracks();
   VideoTracks()->EmptyTracks();
   if (mIsLoadingFromSourceChildren) {
     mErrorSink->ResetError();
     if (mSourceLoadCandidate) {
       DispatchAsyncSourceError(mSourceLoadCandidate);
       QueueLoadFromSourceTask();
     } else {
@@ -5278,16 +5281,24 @@ void HTMLMediaElement::DecodeError(const
     }
   } else if (mReadyState == nsIDOMHTMLMediaElement::HAVE_NOTHING) {
     NoSupportedMediaSourceError(aError.Description());
   } else {
     Error(MEDIA_ERR_DECODE, aError.Description());
   }
 }
 
+void HTMLMediaElement::DecodeWarning(const MediaResult& aError)
+{
+  nsAutoString src;
+  GetCurrentSrc(src);
+  DecoderDoctorDiagnostics diagnostics;
+  diagnostics.StoreDecodeError(OwnerDoc(), aError, src, __func__);
+}
+
 bool HTMLMediaElement::HasError() const
 {
   return GetError();
 }
 
 void HTMLMediaElement::LoadAborted()
 {
   Error(MEDIA_ERR_ABORTED);
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -170,16 +170,21 @@ public:
   // Called by the video decoder object, on the main thread,
   // when the resource has a network error during loading.
   virtual void NetworkError() final override;
 
   // Called by the video decoder object, on the main thread, when the
   // resource has a decode error during metadata loading or decoding.
   virtual void DecodeError(const MediaResult& aError) final override;
 
+  // Called by the decoder object, on the main thread, when the
+  // resource has a decode issue during metadata loading or decoding, but can
+  // continue decoding.
+  virtual void DecodeWarning(const MediaResult& aError) final override;
+
   // Return true if error attribute is not null.
   virtual bool HasError() const final override;
 
   // Called by the video decoder object, on the main thread, when the
   // resource load has been cancelled.
   virtual void LoadAborted() final override;
 
   // Called by the video decoder object, on the main thread,
--- a/dom/media/DecoderDoctorDiagnostics.cpp
+++ b/dom/media/DecoderDoctorDiagnostics.cpp
@@ -449,21 +449,24 @@ DecoderDoctorDocumentWatcher::Synthesize
           if (issue != DecoderDoctorDiagnostics::eUnset) {
             lastKeySystemIssue = issue;
           }
         }
         break;
       case DecoderDoctorDiagnostics::eEvent:
         MOZ_ASSERT_UNREACHABLE("Events shouldn't be stored for processing.");
         break;
+      case DecoderDoctorDiagnostics::eDecodeError:
+        // TODO
+        break;
+      case DecoderDoctorDiagnostics::eDecodeWarning:
+        // TODO
+        break;
       default:
-        MOZ_ASSERT(diag.mDecoderDoctorDiagnostics.Type()
-                     == DecoderDoctorDiagnostics::eFormatSupportCheck
-                   || diag.mDecoderDoctorDiagnostics.Type()
-                        == DecoderDoctorDiagnostics::eMediaKeySystemAccessRequest);
+        MOZ_ASSERT_UNREACHABLE("Unhandled DecoderDoctorDiagnostics type");
         break;
     }
   }
 
   // Check if issues have been solved, by finding if some now-playable
   // key systems or formats were previously recorded as having issues.
   if (!supportedKeySystems.IsEmpty() || !playableFormats.IsEmpty()) {
     DD_DEBUG("DecoderDoctorDocumentWatcher[%p, doc=%p]::SynthesizeAnalysis() - supported key systems '%s', playable formats '%s'; See if they show issues have been solved...",
@@ -774,16 +777,98 @@ DecoderDoctorDiagnostics::StoreEvent(nsI
         ReportAnalysis(aDocument, sCannotInitializePulseAudio,
                        true, NS_LITERAL_STRING("*"));
       }
       break;
   }
 #endif // MOZ_PULSEAUDIO
 }
 
+void
+DecoderDoctorDiagnostics::StoreDecodeError(nsIDocument* aDocument,
+                                           const MediaResult& aError,
+                                           const nsString& aMediaSrc,
+                                           const char* aCallSite)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  // Make sure we only store once.
+  MOZ_ASSERT(mDiagnosticsType == eUnsaved);
+  mDiagnosticsType = eDecodeError;
+
+  if (NS_WARN_IF(!aDocument)) {
+    DD_WARN("DecoderDoctorDiagnostics[%p]::StoreDecodeError("
+            "nsIDocument* aDocument=nullptr, aError=%s,"
+            " aMediaSrc=<provided>, call site '%s')",
+            this, aError.Description().get(), aCallSite);
+    return;
+  }
+
+  RefPtr<DecoderDoctorDocumentWatcher> watcher =
+    DecoderDoctorDocumentWatcher::RetrieveOrCreate(aDocument);
+
+  if (NS_WARN_IF(!watcher)) {
+    DD_WARN("DecoderDoctorDiagnostics[%p]::StoreDecodeError("
+            "nsIDocument* aDocument=%p, aError='%s', aMediaSrc=<provided>,"
+            " call site '%s') - Could not create document watcher",
+            this, aDocument, aError.Description().get(), aCallSite);
+    return;
+  }
+
+  mDecodeIssue = aError;
+  mDecodeIssueMediaSrc = aMediaSrc;
+
+  // StoreDecodeError should only be called once, after all data is
+  // available, so it is safe to Move() from this object.
+  watcher->AddDiagnostics(Move(*this), aCallSite);
+  // Even though it's moved-from, the type should stay set
+  // (Only used to ensure that we do store only once.)
+  MOZ_ASSERT(mDiagnosticsType == eDecodeError);
+}
+
+void
+DecoderDoctorDiagnostics::StoreDecodeWarning(nsIDocument* aDocument,
+                                             const MediaResult& aWarning,
+                                             const nsString& aMediaSrc,
+                                             const char* aCallSite)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  // Make sure we only store once.
+  MOZ_ASSERT(mDiagnosticsType == eUnsaved);
+  mDiagnosticsType = eDecodeWarning;
+
+  if (NS_WARN_IF(!aDocument)) {
+    DD_WARN("DecoderDoctorDiagnostics[%p]::StoreDecodeWarning("
+            "nsIDocument* aDocument=nullptr, aWarning=%s,"
+            " aMediaSrc=<provided>, call site '%s')",
+            this, aWarning.Description().get(), aCallSite);
+    return;
+  }
+
+  RefPtr<DecoderDoctorDocumentWatcher> watcher =
+    DecoderDoctorDocumentWatcher::RetrieveOrCreate(aDocument);
+
+  if (NS_WARN_IF(!watcher)) {
+    DD_WARN("DecoderDoctorDiagnostics[%p]::StoreDecodeWarning("
+            "nsIDocument* aDocument=%p, aWarning='%s', aMediaSrc=<provided>,"
+            " call site '%s') - Could not create document watcher",
+            this, aDocument, aWarning.Description().get(), aCallSite);
+    return;
+  }
+
+  mDecodeIssue = aWarning;
+  mDecodeIssueMediaSrc = aMediaSrc;
+
+  // StoreDecodeWarning should only be called once, after all data is
+  // available, so it is safe to Move() from this object.
+  watcher->AddDiagnostics(Move(*this), aCallSite);
+  // Even though it's moved-from, the type should stay set
+  // (Only used to ensure that we do store only once.)
+  MOZ_ASSERT(mDiagnosticsType == eDecodeWarning);
+}
+
 static const char*
 EventDomainString(DecoderDoctorEvent::Domain aDomain)
 {
   switch (aDomain) {
     case DecoderDoctorEvent::eAudioSinkStartup:
       return "audio-sink-startup";
   }
   return "?";
@@ -832,16 +917,30 @@ DecoderDoctorDiagnostics::GetDescription
           s += ", Widevine with no WMF";
           break;
       }
       break;
     case eEvent:
       s = nsPrintfCString("event domain %s result=%" PRIu32,
                           EventDomainString(mEvent.mDomain), static_cast<uint32_t>(mEvent.mResult));
       break;
+    case eDecodeError:
+      s = "decode error: ";
+      s += mDecodeIssue.Description();
+      s += ", src='";
+      s += mDecodeIssueMediaSrc.IsEmpty() ? "<none>" : "<provided>";
+      s += "'";
+      break;
+    case eDecodeWarning:
+      s = "decode warning: ";
+      s += mDecodeIssue.Description();
+      s += ", src='";
+      s += mDecodeIssueMediaSrc.IsEmpty() ? "<none>" : "<provided>";
+      s += "'";
+      break;
     default:
       MOZ_ASSERT_UNREACHABLE("Unexpected DiagnosticsType");
       s = "?";
       break;
   }
   return s;
 }
 
--- a/dom/media/DecoderDoctorDiagnostics.h
+++ b/dom/media/DecoderDoctorDiagnostics.h
@@ -2,16 +2,17 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef DecoderDoctorDiagnostics_h_
 #define DecoderDoctorDiagnostics_h_
 
+#include "MediaResult.h"
 #include "nsString.h"
 
 class nsIDocument;
 
 namespace mozilla {
 
 struct DecoderDoctorEvent {
   enum Domain {
@@ -52,21 +53,34 @@ public:
                                  const nsAString& aKeySystem,
                                  bool aIsSupported,
                                  const char* aCallSite);
 
   void StoreEvent(nsIDocument* aDocument,
                   const DecoderDoctorEvent& aEvent,
                   const char* aCallSite);
 
-  enum DiagnosticsType {
+  void StoreDecodeError(nsIDocument* aDocument,
+                        const MediaResult& aError,
+                        const nsString& aMediaSrc,
+                        const char* aCallSite);
+
+  void StoreDecodeWarning(nsIDocument* aDocument,
+                          const MediaResult& aWarning,
+                          const nsString& aMediaSrc,
+                          const char* aCallSite);
+
+  enum DiagnosticsType
+  {
     eUnsaved,
     eFormatSupportCheck,
     eMediaKeySystemAccessRequest,
-    eEvent
+    eEvent,
+    eDecodeError,
+    eDecodeWarning
   };
   DiagnosticsType Type() const { return mDiagnosticsType; }
 
   // Description string, for logging purposes; only call on stored diags.
   nsCString GetDescription() const;
 
   // Methods to record diagnostic information:
 
@@ -103,16 +117,22 @@ public:
     return mKeySystemIssue;
   }
 
   DecoderDoctorEvent event() const
   {
     return mEvent;
   }
 
+  const MediaResult& DecodeIssue() const { return mDecodeIssue; }
+  const nsString& DecodeIssueMediaSrc() const
+  {
+    return mDecodeIssueMediaSrc;
+  }
+
 private:
   // Currently-known type of diagnostics. Set from one of the 'Store...' methods.
   // This helps ensure diagnostics are only stored once,
   // and makes it easy to know what information they contain.
   DiagnosticsType mDiagnosticsType = eUnsaved;
 
   nsString mFormat;
   // True if there is at least one decoder that can play that format.
@@ -125,13 +145,16 @@ private:
   bool mAudioNotSupported = false;
   nsCString mGMP;
 
   nsString mKeySystem;
   bool mIsKeySystemSupported = false;
   KeySystemIssue mKeySystemIssue = eUnset;
 
   DecoderDoctorEvent mEvent;
+
+  MediaResult mDecodeIssue = NS_OK;
+  nsString mDecodeIssueMediaSrc;
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/MediaDecoderOwner.h
+++ b/dom/media/MediaDecoderOwner.h
@@ -69,16 +69,21 @@ public:
   virtual void NetworkError() = 0;
 
   // Called by the decoder object, on the main thread, when the
   // resource has a decode error during metadata loading or decoding.
   // The decoder owner should call Shutdown() on the decoder and drop the
   // reference to the decoder to prevent further calls into the decoder.
   virtual void DecodeError(const MediaResult& aError) = 0;
 
+  // Called by the decoder object, on the main thread, when the
+  // resource has a decode issue during metadata loading or decoding, but can
+  // continue decoding.
+  virtual void DecodeWarning(const MediaResult& aError) = 0;
+
   // Return true if media element error attribute is not null.
   virtual bool HasError() const = 0;
 
   // Called by the video decoder object, on the main thread, when the
   // resource load has been cancelled.
   virtual void LoadAborted() = 0;
 
   // Called by the video decoder object, on the main thread,
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -979,34 +979,16 @@ MediaFormatReader::DemuxerProxy::NotifyD
     }
     if (data->mVideoDemuxer) {
       data->mVideoDemuxer->UpdateBuffered();
     }
     return NotifyDataArrivedPromise::CreateAndResolve(true, __func__);
   });
 }
 
-static const char*
-TrackTypeToStr(TrackInfo::TrackType aTrack)
-{
-  MOZ_ASSERT(aTrack == TrackInfo::kAudioTrack
-             || aTrack == TrackInfo::kVideoTrack
-             || aTrack == TrackInfo::kTextTrack);
-  switch (aTrack) {
-  case TrackInfo::kAudioTrack:
-    return "Audio";
-  case TrackInfo::kVideoTrack:
-    return "Video";
-  case TrackInfo::kTextTrack:
-    return "Text";
-  default:
-    return "Unknown";
-  }
-}
-
 MediaFormatReader::MediaFormatReader(AbstractMediaDecoder* aDecoder,
                                      MediaDataDemuxer* aDemuxer,
                                      VideoFrameContainer* aVideoFrameContainer)
   : MediaDecoderReader(aDecoder)
   , mAudio(this, MediaData::AUDIO_DATA,
            Preferences::GetUint("media.audio-max-decode-error", 3))
   , mVideo(this, MediaData::VIDEO_DATA,
            Preferences::GetUint("media.video-max-decode-error", 2))
--- a/dom/media/MediaInfo.cpp
+++ b/dom/media/MediaInfo.cpp
@@ -3,16 +3,34 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MediaInfo.h"
 
 namespace mozilla {
 
+const char*
+TrackTypeToStr(TrackInfo::TrackType aTrack)
+{
+  MOZ_ASSERT(aTrack == TrackInfo::kAudioTrack
+             || aTrack == TrackInfo::kVideoTrack
+             || aTrack == TrackInfo::kTextTrack);
+  switch (aTrack) {
+  case TrackInfo::kAudioTrack:
+    return "Audio";
+  case TrackInfo::kVideoTrack:
+    return "Video";
+  case TrackInfo::kTextTrack:
+    return "Text";
+  default:
+    return "Unknown";
+  }
+}
+
 typedef AudioConfig::ChannelLayout ChannelLayout;
 
 /**
  * AudioConfig::ChannelLayout
  */
 
 /*
  SMPTE channel layout (also known as wave order)
--- a/dom/media/MediaInfo.h
+++ b/dom/media/MediaInfo.h
@@ -173,16 +173,19 @@ protected:
     mTags = aOther.mTags;
     MOZ_COUNT_CTOR(TrackInfo);
   }
 
 private:
   TrackType mType;
 };
 
+// String version of track type. Don't use with kUndefinedTrack.
+const char* TrackTypeToStr(TrackInfo::TrackType aTrack);
+
 // Stores info relevant to presenting media frames.
 class VideoInfo : public TrackInfo
 {
 public:
   enum Rotation
   {
     kDegree_0 = 0,
     kDegree_90 = 90,
--- a/dom/media/fmp4/MP4Demuxer.cpp
+++ b/dom/media/fmp4/MP4Demuxer.cpp
@@ -119,24 +119,16 @@ MP4Demuxer::MP4Demuxer(MediaResource* aR
 {
 }
 
 RefPtr<MP4Demuxer::InitPromise>
 MP4Demuxer::Init()
 {
   AutoPinned<mp4_demuxer::ResourceStream> stream(mStream);
 
-  // Check that we have enough data to read the metadata.
-  if (!mp4_demuxer::MP4Metadata::HasCompleteMetadata(stream)) {
-    return InitPromise::CreateAndReject(
-      MediaResult(NS_ERROR_DOM_MEDIA_DEMUXER_ERR,
-                  RESULT_DETAIL("Incomplete MP4 metadata")),
-      __func__);
-  }
-
   RefPtr<MediaByteBuffer> initData = mp4_demuxer::MP4Metadata::Metadata(stream);
   if (!initData) {
     return InitPromise::CreateAndReject(
       MediaResult(NS_ERROR_DOM_MEDIA_DEMUXER_ERR,
                   RESULT_DETAIL("Invalid MP4 metadata or OOM")),
       __func__);
   }
 
--- a/dom/media/test/external/external_media_tests/media_utils/video_puppeteer.py
+++ b/dom/media/test/external/external_media_tests/media_utils/video_puppeteer.py
@@ -55,17 +55,17 @@ class VideoPuppeteer(object):
      of the video.
     :param stall_wait_time: The amount of time to wait to see if a stall has
      cleared. If 0, do not check for stalls.
     :param timeout: The amount of time to wait until the video starts.
     """
 
     _video_var_script = (
         'var video = arguments[0];'
-        'var baseURI = arguments[0].baseURI;'
+        'var baseURI = video.baseURI;'
         'var currentTime = video.wrappedJSObject.currentTime;'
         'var duration = video.wrappedJSObject.duration;'
         'var buffered = video.wrappedJSObject.buffered;'
         'var bufferedRanges = [];'
         'for (var i = 0; i < buffered.length; i++) {'
         'bufferedRanges.push([buffered.start(i), buffered.end(i)]);'
         '}'
         'var played = video.wrappedJSObject.played;'
@@ -200,17 +200,17 @@ class VideoPuppeteer(object):
         if self._last_seen_video_state.remaining_time < self.interval:
             return True
 
         # Check to see if the video has stalled. Accumulate the amount of lag
         # since the video started, and if it is too high, then raise.
         if (self.stall_wait_time and
                 self._last_seen_video_state.lag > self.stall_wait_time):
             raise VideoException('Video {} stalled.\n{}'
-                                 .format(self._last_seen_video_state.video_uri,
+                                 .format(self._last_seen_video_state.base_uri,
                                          self))
 
         # We are cruising, so we are not done.
         return False
 
     def _update_expected_duration(self):
         """
         Update the duration of the target video at self.test_url (in seconds).
--- a/gfx/cairo/cairo/src/cairo-scaled-font.c
+++ b/gfx/cairo/cairo/src/cairo-scaled-font.c
@@ -1504,17 +1504,19 @@ cairo_scaled_font_glyph_extents (cairo_s
     for (i = 0; i < num_glyphs; i++) {
 	double			left, top, right, bottom;
 
 	status = _cairo_scaled_glyph_lookup (scaled_font,
 					     glyphs[i].index,
 					     CAIRO_SCALED_GLYPH_INFO_METRICS,
 					     &scaled_glyph);
 	if (unlikely (status)) {
-	    status = _cairo_scaled_font_set_error (scaled_font, status);
+	    if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
+		status = _cairo_scaled_font_set_error (scaled_font, status);
+	    }
 	    goto UNLOCK;
 	}
 
 	/* "Ink" extents should skip "invisible" glyphs */
 	if (scaled_glyph->metrics.width == 0 || scaled_glyph->metrics.height == 0)
 	    continue;
 
 	left = scaled_glyph->metrics.x_bearing + glyphs[i].x;
--- a/gfx/config/gfxFeature.cpp
+++ b/gfx/config/gfxFeature.cpp
@@ -185,16 +185,19 @@ void
 FeatureState::DisableByDefault(FeatureStatus aStatus, const char* aMessage,
                                const nsACString& aFailureId)
 {
   // User/runtime decisions should not have been made yet.
   MOZ_ASSERT(!mUser.IsInitialized());
   MOZ_ASSERT(!mEnvironment.IsInitialized());
   MOZ_ASSERT(!mRuntime.IsInitialized());
 
+  // Make sure that when disabling we actually use a failure status.
+  MOZ_ASSERT(IsFeatureStatusFailure(aStatus));
+
   mDefault.Set(aStatus, aMessage);
   SetFailureId(aFailureId);
 }
 
 void
 FeatureState::SetUser(FeatureStatus aStatus, const char* aMessage)
 {
   // Default decision must have been made, but not runtime or environment.
new file mode 100644
--- /dev/null
+++ b/gfx/layers/composite/AnimationMetricsTracker.cpp
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/layers/AnimationMetricsTracker.h"
+
+#include <algorithm>
+#include <inttypes.h>
+#include "mozilla/Telemetry.h"
+
+#define AMT_LOG(...)
+// #define AMT_LOG(...) printf_stderr("AMT: " __VA_ARGS__)
+
+namespace mozilla {
+namespace layers {
+
+AnimationMetricsTracker::AnimationMetricsTracker()
+{
+}
+
+AnimationMetricsTracker::~AnimationMetricsTracker()
+{
+}
+
+void
+AnimationMetricsTracker::UpdateAnimationInProgress(bool aInProgress,
+                                                   uint64_t aLayerArea)
+{
+  MOZ_ASSERT(aInProgress || aLayerArea == 0);
+  if (mCurrentAnimationStart && !aInProgress) {
+    AnimationEnded();
+    mCurrentAnimationStart = TimeStamp();
+    mMaxLayerAreaAnimated = 0;
+  } else if (aInProgress) {
+    if (!mCurrentAnimationStart) {
+      mCurrentAnimationStart = TimeStamp::Now();
+      mMaxLayerAreaAnimated = aLayerArea;
+      AnimationStarted();
+    } else {
+      mMaxLayerAreaAnimated = std::max(mMaxLayerAreaAnimated, aLayerArea);
+    }
+  }
+}
+
+void
+AnimationMetricsTracker::AnimationStarted()
+{
+}
+
+void
+AnimationMetricsTracker::AnimationEnded()
+{
+  MOZ_ASSERT(mCurrentAnimationStart);
+  Telemetry::AccumulateTimeDelta(Telemetry::COMPOSITOR_ANIMATION_DURATION, mCurrentAnimationStart);
+  Telemetry::Accumulate(Telemetry::COMPOSITOR_ANIMATION_MAX_LAYER_AREA, mMaxLayerAreaAnimated);
+  AMT_LOG("Ended animation; duration: %f ms, area: %" PRIu64 "\n",
+    (TimeStamp::Now() - mCurrentAnimationStart).ToMilliseconds(),
+    mMaxLayerAreaAnimated);
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/composite/AnimationMetricsTracker.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_layers_AnimationMetricsTracker_h
+#define mozilla_layers_AnimationMetricsTracker_h
+
+#include "mozilla/TimeStamp.h"
+
+namespace mozilla {
+namespace layers {
+
+/**
+ * Tracks the start and end of compositor animations.
+ */
+class AnimationMetricsTracker {
+public:
+  AnimationMetricsTracker();
+  ~AnimationMetricsTracker();
+
+  /**
+   * This function should be called per composite, to inform the metrics
+   * tracker if any animation is in progress, and if so, what area is
+   * being animated. The aLayerArea is in Layer pixels squared.
+   */
+  void UpdateAnimationInProgress(bool aInProgress, uint64_t aLayerArea);
+
+private:
+  void AnimationStarted();
+  void AnimationEnded();
+
+  TimeStamp mCurrentAnimationStart;
+  uint64_t mMaxLayerAreaAnimated;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // mozilla_layers_AnimationMetricsTracker_h
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -629,38 +629,41 @@ ApplyAnimatedValue(Layer* aLayer,
       break;
     }
     default:
       MOZ_ASSERT_UNREACHABLE("Unhandled animated property");
   }
 }
 
 static bool
-SampleAnimations(Layer* aLayer, TimeStamp aPoint)
+SampleAnimations(Layer* aLayer, TimeStamp aPoint, uint64_t* aLayerAreaAnimated)
 {
   bool activeAnimations = false;
 
   ForEachNode<ForwardIterator>(
       aLayer,
-      [&activeAnimations, &aPoint] (Layer* layer)
+      [&activeAnimations, &aPoint, &aLayerAreaAnimated] (Layer* layer)
       {
         bool hasInEffectAnimations = false;
         StyleAnimationValue animationValue = layer->GetBaseAnimationStyle();
         activeAnimations |=
           AnimationHelper::SampleAnimationForEachNode(aPoint,
                                                       layer->GetAnimations(),
                                                       layer->GetAnimationData(),
                                                       animationValue,
                                                       hasInEffectAnimations);
         if (hasInEffectAnimations) {
           Animation& animation = layer->GetAnimations().LastElement();
           ApplyAnimatedValue(layer,
                              animation.property(),
                              animation.data(),
                              animationValue);
+          if (aLayerAreaAnimated) {
+            *aLayerAreaAnimated += (layer->GetVisibleRegion().Area());
+          }
         }
       });
   return activeAnimations;
 }
 
 static bool
 SampleAPZAnimations(const LayerMetricsWrapper& aLayer, TimeStamp aSampleTime)
 {
@@ -1306,19 +1309,23 @@ AsyncCompositionManager::TransformShadow
 
   // First, compute and set the shadow transforms from OMT animations.
   // NB: we must sample animations *before* sampling pan/zoom
   // transforms.
   // Use a previous vsync time to make main thread animations and compositor
   // more in sync with each other.
   // On the initial frame we use aVsyncTimestamp here so the timestamp on the
   // second frame are the same as the initial frame, but it does not matter.
+  uint64_t layerAreaAnimated = 0;
   bool wantNextFrame = SampleAnimations(root,
     !mPreviousFrameTimeStamp.IsNull() ?
-      mPreviousFrameTimeStamp : aCurrentFrame);
+      mPreviousFrameTimeStamp : aCurrentFrame,
+    &layerAreaAnimated);
+  mAnimationMetricsTracker.UpdateAnimationInProgress(
+    wantNextFrame, layerAreaAnimated);
 
   // Reset the previous time stamp if we don't already have any running
   // animations to avoid using the time which is far behind for newly
   // started animations.
   mPreviousFrameTimeStamp = wantNextFrame ? aCurrentFrame : TimeStamp();
 
   if (!(aSkip & TransformsToSkip::APZ)) {
     // FIXME/bug 775437: unify this interface with the ~native-fennec
--- a/gfx/layers/composite/AsyncCompositionManager.h
+++ b/gfx/layers/composite/AsyncCompositionManager.h
@@ -9,16 +9,17 @@
 #include "Units.h"                      // for ScreenPoint, etc
 #include "mozilla/layers/LayerManagerComposite.h"  // for LayerManagerComposite
 #include "mozilla/Attributes.h"         // for final, etc
 #include "mozilla/RefPtr.h"             // for RefCounted
 #include "mozilla/TimeStamp.h"          // for TimeStamp
 #include "mozilla/dom/ScreenOrientation.h"  // for ScreenOrientation
 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
 #include "mozilla/gfx/Matrix.h"         // for Matrix4x4
+#include "mozilla/layers/AnimationMetricsTracker.h" // for AnimationMetricsTracker
 #include "mozilla/layers/FrameUniformityData.h" // For FrameUniformityData
 #include "mozilla/layers/LayersMessages.h"  // for TargetConfig
 #include "mozilla/RefPtr.h"                   // for nsRefPtr
 #include "nsISupportsImpl.h"            // for LayerManager::AddRef, etc
 
 namespace mozilla {
 namespace layers {
 
@@ -233,16 +234,17 @@ private:
   int32_t mPaintSyncId;
 
   bool mReadyForCompose;
 
   gfx::Matrix mWorldTransform;
   LayerTransformRecorder mLayerTransformRecorder;
 
   TimeStamp mPreviousFrameTimeStamp;
+  AnimationMetricsTracker mAnimationMetricsTracker;
 
 #ifdef MOZ_WIDGET_ANDROID
   // The following two fields are only needed on Fennec with C++ APZ, because
   // then we need to reposition the gecko scrollbar to deal with the
   // dynamic toolbar shifting content around.
   FrameMetrics::ViewID mRootScrollableId;
   ScreenMargin mFixedLayerMargins;
 #endif
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -137,16 +137,17 @@ EXPORTS.mozilla.layers += [
     'client/GPUVideoTextureClient.h',
     'client/ImageClient.h',
     'client/SingleTiledContentClient.h',
     'client/TextureClient.h',
     'client/TextureClientPool.h',
     'client/TextureClientRecycleAllocator.h',
     'client/TextureClientSharedSurface.h',
     'client/TiledContentClient.h',
+    'composite/AnimationMetricsTracker.h',
     'composite/AsyncCompositionManager.h',
     'composite/CanvasLayerComposite.h',
     'composite/ColorLayerComposite.h',
     'composite/ContainerLayerComposite.h',
     'composite/ContentHost.h',
     'composite/FrameUniformityData.h',
     'composite/GPUVideoTextureHost.h',
     'composite/ImageComposite.h',
@@ -317,16 +318,17 @@ UNIFIED_SOURCES += [
     'client/GPUVideoTextureClient.cpp',
     'client/ImageClient.cpp',
     'client/SingleTiledContentClient.cpp',
     'client/TextureClient.cpp',
     'client/TextureClientPool.cpp',
     'client/TextureClientRecycleAllocator.cpp',
     'client/TextureClientSharedSurface.cpp',
     'client/TiledContentClient.cpp',
+    'composite/AnimationMetricsTracker.cpp',
     'composite/AsyncCompositionManager.cpp',
     'composite/CanvasLayerComposite.cpp',
     'composite/ColorLayerComposite.cpp',
     'composite/CompositableHost.cpp',
     'composite/ContainerLayerComposite.cpp',
     'composite/ContentHost.cpp',
     'composite/FPSCounter.cpp',
     'composite/FrameUniformityData.cpp',
--- a/gfx/src/gfxTelemetry.cpp
+++ b/gfx/src/gfxTelemetry.cpp
@@ -1,59 +1,61 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-#include "gfxTelemetry.h"
-
-namespace mozilla {
-namespace gfx {
-
-const char*
-FeatureStatusToString(FeatureStatus aStatus)
-{
-  switch (aStatus) {
-    case FeatureStatus::Unused:
-      return "unused";
-    case FeatureStatus::Unavailable:
-      return "unavailable";
-    case FeatureStatus::CrashedInHandler:
-      return "crashed";
-    case FeatureStatus::Blocked:
-      return "blocked";
-    case FeatureStatus::Blacklisted:
-      return "blacklisted";
-    case FeatureStatus::Failed:
-      return "failed";
-    case FeatureStatus::Disabled:
-      return "disabled";
-    case FeatureStatus::Available:
-      return "available";
-    case FeatureStatus::ForceEnabled:
-      return "force_enabled";
-    case FeatureStatus::CrashedOnStartup:
-      return "crashed_on_startup";
-    case FeatureStatus::Broken:
-      return "broken";
-    default:
-      MOZ_ASSERT_UNREACHABLE("missing status case");
-      return "unknown";
-  }
-}
-
-bool
-IsFeatureStatusFailure(FeatureStatus aStatus)
-{
-  return !(aStatus == FeatureStatus::Unused ||
-           aStatus == FeatureStatus::Available ||
-           aStatus == FeatureStatus::ForceEnabled);
-}
-
-bool
-IsFeatureStatusSuccess(FeatureStatus aStatus)
-{
-  return aStatus == FeatureStatus::Available ||
-         aStatus == FeatureStatus::ForceEnabled;
-}
-
-} // namespace gfx
-} // namespace mozilla
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "gfxTelemetry.h"
+
+namespace mozilla {
+namespace gfx {
+
+const char*
+FeatureStatusToString(FeatureStatus aStatus)
+{
+  switch (aStatus) {
+    case FeatureStatus::Unused:
+      return "unused";
+    case FeatureStatus::Unavailable:
+      return "unavailable";
+    case FeatureStatus::CrashedInHandler:
+      return "crashed";
+    case FeatureStatus::Blocked:
+      return "blocked";
+    case FeatureStatus::Blacklisted:
+      return "blacklisted";
+    case FeatureStatus::OptIn:
+      return "opt-in";
+    case FeatureStatus::Failed:
+      return "failed";
+    case FeatureStatus::Disabled:
+      return "disabled";
+    case FeatureStatus::Available:
+      return "available";
+    case FeatureStatus::ForceEnabled:
+      return "force_enabled";
+    case FeatureStatus::CrashedOnStartup:
+      return "crashed_on_startup";
+    case FeatureStatus::Broken:
+      return "broken";
+    default:
+      MOZ_ASSERT_UNREACHABLE("missing status case");
+      return "unknown";
+  }
+}
+
+bool
+IsFeatureStatusFailure(FeatureStatus aStatus)
+{
+  return !(aStatus == FeatureStatus::Unused ||
+           aStatus == FeatureStatus::Available ||
+           aStatus == FeatureStatus::ForceEnabled);
+}
+
+bool
+IsFeatureStatusSuccess(FeatureStatus aStatus)
+{
+  return aStatus == FeatureStatus::Available ||
+         aStatus == FeatureStatus::ForceEnabled;
+}
+
+} // namespace gfx
+} // namespace mozilla
--- a/gfx/src/gfxTelemetry.h
+++ b/gfx/src/gfxTelemetry.h
@@ -1,70 +1,74 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-#ifndef gfx_src_gfxTelemetry_h__
-#define gfx_src_gfxTelemetry_h__
-
-namespace mozilla {
-namespace gfx {
-
-// Describes the status of a graphics feature, in terms of whether or not we've
-// attempted to initialize the feature, and if so, whether or not it succeeded
-// (and if not, why).
-enum class FeatureStatus
-{
-  // This feature has not been requested.
-  Unused,
-
-  // This feature is unavailable due to Safe Mode, not being included with
-  // the operating system, or a dependent feature being disabled.
-  Unavailable,
-
-  // This feature crashed immediately when we tried to initialize it, but we
-  // were able to recover via SEH (or something similar).
-  CrashedInHandler,
-
-  // This feature was blocked for reasons outside the blacklist, such as a
-  // runtime test failing.
-  Blocked,
-
-  // This feature has been blocked by the graphics blacklist.
-  Blacklisted,
-
-  // This feature was attempted but failed to activate.
-  Failed,
-
-  // This feature was explicitly disabled by the user.
-  Disabled,
-
-  // This feature is available for use.
-  Available,
-
-  // This feature was explicitly force-enabled by the user.
-  ForceEnabled,
-
-  // This feature was disabled due to the startup crash guard.
-  CrashedOnStartup,
-
-  // This feature was attempted but later determined to be broken.
-  Broken,
-
-  // Add new entries above here.
-  LAST
-};
-
-const char* FeatureStatusToString(FeatureStatus aStatus);
-bool IsFeatureStatusFailure(FeatureStatus aStatus);
-bool IsFeatureStatusSuccess(FeatureStatus aStatus);
-
-enum class TelemetryDeviceCode : uint32_t {
-  Content = 0,
-  Image = 1,
-  D2D1 = 2
-};
-
-} // namespace gfx
-} // namespace mozilla
-
-#endif // gfx_src_gfxTelemetry_h__
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#ifndef gfx_src_gfxTelemetry_h__
+#define gfx_src_gfxTelemetry_h__
+
+namespace mozilla {
+namespace gfx {
+
+// Describes the status of a graphics feature, in terms of whether or not we've
+// attempted to initialize the feature, and if so, whether or not it succeeded
+// (and if not, why).
+enum class FeatureStatus
+{
+  // This feature has not been requested.
+  Unused,
+
+  // This feature is unavailable due to Safe Mode, not being included with
+  // the operating system, or a dependent feature being disabled.
+  Unavailable,
+
+  // This feature crashed immediately when we tried to initialize it, but we
+  // were able to recover via SEH (or something similar).
+  CrashedInHandler,
+
+  // This feature was blocked for reasons outside the blacklist, such as a
+  // runtime test failing.
+  Blocked,
+
+  // This feature has been blocked by the graphics blacklist.
+  Blacklisted,
+
+  // This feature is disabled by default, and so activation isn't attempted
+  // unless something explicitly enables it.
+  OptIn,
+
+  // This feature was attempted but failed to activate.
+  Failed,
+
+  // This feature was explicitly disabled by the user.
+  Disabled,
+
+  // This feature is available for use.
+  Available,
+
+  // This feature was explicitly force-enabled by the user.
+  ForceEnabled,
+
+  // This feature was disabled due to the startup crash guard.
+  CrashedOnStartup,
+
+  // This feature was attempted but later determined to be broken.
+  Broken,
+
+  // Add new entries above here.
+  LAST
+};
+
+const char* FeatureStatusToString(FeatureStatus aStatus);
+bool IsFeatureStatusFailure(FeatureStatus aStatus);
+bool IsFeatureStatusSuccess(FeatureStatus aStatus);
+
+enum class TelemetryDeviceCode : uint32_t {
+  Content = 0,
+  Image = 1,
+  D2D1 = 2
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif // gfx_src_gfxTelemetry_h__
--- a/ipc/mscom/WeakRef.h
+++ b/ipc/mscom/WeakRef.h
@@ -100,30 +100,32 @@ protected:
 
 private:
   RefPtr<detail::SharedRef> mSharedRef;
   ULONG                     mRefCnt;
   Flags                     mFlags;
   CRITICAL_SECTION          mCSForQI;
 };
 
-class WeakRef : public IWeakReference
+class WeakRef final : public IWeakReference
 {
 public:
   // IUnknown
   STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
   STDMETHODIMP_(ULONG) AddRef() override;
   STDMETHODIMP_(ULONG) Release() override;
 
   // IWeakReference
   STDMETHODIMP Resolve(REFIID aIid, void** aOutStrongReference) override;
 
   explicit WeakRef(RefPtr<detail::SharedRef>& aSharedRef);
 
 private:
+  ~WeakRef() = default;
+
   Atomic<ULONG>             mRefCnt;
   RefPtr<detail::SharedRef> mSharedRef;
 };
 
 } // namespace mscom
 } // namespace mozilla
 
 #endif // mozilla_mscom_WeakRef_h
--- a/js/src/builtin/Intl.cpp
+++ b/js/src/builtin/Intl.cpp
@@ -650,16 +650,17 @@ enum UDateFormatField {
 };
 
 enum UDateFormatStyle {
     UDAT_FULL,
     UDAT_LONG,
     UDAT_MEDIUM,
     UDAT_SHORT,
     UDAT_DEFAULT = UDAT_MEDIUM,
+    UDAT_NONE = -1,
     UDAT_PATTERN = -2,
     UDAT_IGNORE = UDAT_PATTERN
 };
 
 enum UDateFormatSymbolType {
     UDAT_ERAS,
     UDAT_MONTHS,
     UDAT_SHORT_MONTHS,
@@ -691,16 +692,23 @@ enum UDateFormatSymbolType {
 };
 
 int32_t
 udat_countAvailable()
 {
     MOZ_CRASH("udat_countAvailable: Intl API disabled");
 }
 
+int32_t
+udat_toPattern(const UDateFormat* fmt, UBool localized, UChar* result,
+               int32_t resultLength, UErrorCode* status)
+{
+    MOZ_CRASH("udat_toPattern: Intl API disabled");
+}
+
 const char*
 udat_getAvailable(int32_t localeIndex)
 {
     MOZ_CRASH("udat_getAvailable: Intl API disabled");
 }
 
 UDateFormat*
 udat_open(UDateFormatStyle timeStyle, UDateFormatStyle dateStyle, const char* locale,
@@ -816,27 +824,34 @@ IntlInitialize(JSContext* cx, HandleObje
     if (!js::CallSelfHostedFunction(cx, initializer, thisv, args, &ignored))
         return false;
 
     MOZ_ASSERT(ignored.isUndefined(),
                "Unexpected return value from non-legacy Intl object initializer");
     return true;
 }
 
+enum class DateTimeFormatOptions
+{
+    Standard,
+    EnableMozExtensions,
+};
+
 static bool
 LegacyIntlInitialize(JSContext* cx, HandleObject obj, Handle<PropertyName*> initializer,
                      HandleValue thisValue, HandleValue locales, HandleValue options,
-                     MutableHandleValue result)
+                     DateTimeFormatOptions dtfOptions, MutableHandleValue result)
 {
-    FixedInvokeArgs<4> args(cx);
+    FixedInvokeArgs<5> args(cx);
 
     args[0].setObject(*obj);
     args[1].set(thisValue);
     args[2].set(locales);
     args[3].set(options);
+    args[4].setBoolean(dtfOptions == DateTimeFormatOptions::EnableMozExtensions);
 
     RootedValue thisv(cx, NullValue());
     if (!js::CallSelfHostedFunction(cx, initializer, thisv, args, result))
         return false;
 
     MOZ_ASSERT(result.isObject(), "Legacy Intl object initializer must return an object");
     return true;
 }
@@ -1486,17 +1501,17 @@ NumberFormat(JSContext* cx, const CallAr
     numberFormat->setReservedSlot(NumberFormatObject::UNUMBER_FORMAT_SLOT, PrivateValue(nullptr));
 
     RootedValue thisValue(cx, construct ? ObjectValue(*numberFormat) : args.thisv());
     RootedValue locales(cx, args.get(0));
     RootedValue options(cx, args.get(1));
 
     // Step 3.
     return LegacyIntlInitialize(cx, numberFormat, cx->names().InitializeNumberFormat, thisValue,
-                                locales, options, args.rval());
+                                locales, options, DateTimeFormatOptions::Standard, args.rval());
 }
 
 static bool
 NumberFormat(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return NumberFormat(cx, args, args.isConstructing());
 }
@@ -2351,17 +2366,17 @@ static const JSPropertySpec dateTimeForm
 };
 
 /**
  * 12.2.1 Intl.DateTimeFormat([ locales [, options]])
  *
  * ES2017 Intl draft rev 94045d234762ad107a3d09bb6f7381a65f1a2f9b
  */
 static bool
-DateTimeFormat(JSContext* cx, const CallArgs& args, bool construct)
+DateTimeFormat(JSContext* cx, const CallArgs& args, bool construct, DateTimeFormatOptions dtfOptions)
 {
     // Step 1 (Handled by OrdinaryCreateFromConstructor fallback code).
 
     // Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
     RootedObject proto(cx);
     if (args.isConstructing() && !GetPrototypeFromCallableConstructor(cx, args, &proto))
         return false;
 
@@ -2381,55 +2396,71 @@ DateTimeFormat(JSContext* cx, const Call
                                     PrivateValue(nullptr));
 
     RootedValue thisValue(cx, construct ? ObjectValue(*dateTimeFormat) : args.thisv());
     RootedValue locales(cx, args.get(0));
     RootedValue options(cx, args.get(1));
 
     // Step 3.
     return LegacyIntlInitialize(cx, dateTimeFormat, cx->names().InitializeDateTimeFormat,
-                                thisValue, locales, options, args.rval());
+                                thisValue, locales, options, dtfOptions, args.rval());
 }
 
 static bool
 DateTimeFormat(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    return DateTimeFormat(cx, args, args.isConstructing());
+    return DateTimeFormat(cx, args, args.isConstructing(), DateTimeFormatOptions::Standard);
+}
+
+static bool
+MozDateTimeFormat(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    // Don't allow to call mozIntl.DateTimeFormat as a function. That way we
+    // don't need to worry how to handle the legacy initialization semantics
+    // when applied on mozIntl.DateTimeFormat.
+    if (!ThrowIfNotConstructing(cx, args, "mozIntl.DateTimeFormat"))
+        return false;
+
+    return DateTimeFormat(cx, args, true, DateTimeFormatOptions::EnableMozExtensions);
 }
 
 bool
 js::intl_DateTimeFormat(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 2);
     MOZ_ASSERT(!args.isConstructing());
     // intl_DateTimeFormat is an intrinsic for self-hosted JavaScript, so it
     // cannot be used with "new", but it still has to be treated as a
     // constructor.
-    return DateTimeFormat(cx, args, true);
+    return DateTimeFormat(cx, args, true, DateTimeFormatOptions::Standard);
 }
 
 void
 DateTimeFormatObject::finalize(FreeOp* fop, JSObject* obj)
 {
     MOZ_ASSERT(fop->onActiveCooperatingThread());
 
     const Value& slot =
         obj->as<DateTimeFormatObject>().getReservedSlot(DateTimeFormatObject::UDATE_FORMAT_SLOT);
     if (UDateFormat* df = static_cast<UDateFormat*>(slot.toPrivate()))
         udat_close(df);
 }
 
 static JSObject*
 CreateDateTimeFormatPrototype(JSContext* cx, HandleObject Intl, Handle<GlobalObject*> global,
-                              MutableHandleObject constructor)
+                              MutableHandleObject constructor, DateTimeFormatOptions dtfOptions)
 {
     RootedFunction ctor(cx);
-    ctor = GlobalObject::createConstructor(cx, &DateTimeFormat, cx->names().DateTimeFormat, 0);
+    ctor = dtfOptions == DateTimeFormatOptions::EnableMozExtensions
+           ? GlobalObject::createConstructor(cx, MozDateTimeFormat, cx->names().DateTimeFormat, 0)
+           : GlobalObject::createConstructor(cx, DateTimeFormat, cx->names().DateTimeFormat, 0);
     if (!ctor)
         return nullptr;
 
     RootedObject proto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global));
     if (!proto)
         return nullptr;
 
     if (!LinkConstructorAndPrototype(cx, ctor, proto))
@@ -2452,16 +2483,27 @@ CreateDateTimeFormatPrototype(JSContext*
     if (!DefineProperty(cx, Intl, cx->names().DateTimeFormat, ctorValue, nullptr, nullptr, 0))
         return nullptr;
 
     constructor.set(ctor);
     return proto;
 }
 
 bool
+js::AddMozDateTimeFormatConstructor(JSContext* cx, JS::Handle<JSObject*> intl)
+{
+    Handle<GlobalObject*> global = cx->global();
+
+    RootedObject mozDateTimeFormat(cx);
+    JSObject* mozDateTimeFormatProto =
+        CreateDateTimeFormatPrototype(cx, intl, global, &mozDateTimeFormat, DateTimeFormatOptions::EnableMozExtensions);
+    return mozDateTimeFormatProto != nullptr;
+}
+
+bool
 js::intl_DateTimeFormat_availableLocales(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 0);
 
     RootedValue result(cx);
     if (!intl_availableLocales(cx, udat_countAvailable, udat_getAvailable, &result))
         return false;
@@ -2969,16 +3011,89 @@ js::intl_patternForSkeleton(JSContext* c
     });
     if (!str)
         return false;
 
     args.rval().setString(str);
     return true;
 }
 
+bool
+js::intl_patternForStyle(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    MOZ_ASSERT(args.length() == 4);
+    MOZ_ASSERT(args[0].isString());
+
+    JSAutoByteString locale(cx, args[0].toString());
+    if (!locale)
+        return false;
+
+    UDateFormatStyle dateStyle = UDAT_NONE;
+    UDateFormatStyle timeStyle = UDAT_NONE;
+
+    if (args[1].isString()) {
+        JSLinearString* dateStyleStr = args[1].toString()->ensureLinear(cx);
+        if (!dateStyleStr)
+            return false;
+
+        if (StringEqualsAscii(dateStyleStr, "full"))
+            dateStyle = UDAT_FULL;
+        else if (StringEqualsAscii(dateStyleStr, "long"))
+            dateStyle = UDAT_LONG;
+        else if (StringEqualsAscii(dateStyleStr, "medium"))
+            dateStyle = UDAT_MEDIUM;
+        else if (StringEqualsAscii(dateStyleStr, "short"))
+            dateStyle = UDAT_SHORT;
+        else
+            MOZ_ASSERT_UNREACHABLE("unexpected dateStyle");
+    }
+
+    if (args[2].isString()) {
+        JSLinearString* timeStyleStr = args[2].toString()->ensureLinear(cx);
+        if (!timeStyleStr)
+            return false;
+
+        if (StringEqualsAscii(timeStyleStr, "full"))
+            timeStyle = UDAT_FULL;
+        else if (StringEqualsAscii(timeStyleStr, "long"))
+            timeStyle = UDAT_LONG;
+        else if (StringEqualsAscii(timeStyleStr, "medium"))
+            timeStyle = UDAT_MEDIUM;
+        else if (StringEqualsAscii(timeStyleStr, "short"))
+            timeStyle = UDAT_SHORT;
+        else
+            MOZ_ASSERT_UNREACHABLE("unexpected timeStyle");
+    }
+
+    AutoStableStringChars timeZone(cx);
+    if (!timeZone.initTwoByte(cx, args[3].toString()))
+        return false;
+
+    mozilla::Range<const char16_t> timeZoneChars = timeZone.twoByteRange();
+
+    UErrorCode status = U_ZERO_ERROR;
+    UDateFormat* df = udat_open(timeStyle, dateStyle, icuLocale(locale.ptr()),
+                                Char16ToUChar(timeZoneChars.begin().get()),
+                                timeZoneChars.length(), nullptr, -1, &status);
+    if (U_FAILURE(status)) {
+        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
+        return false;
+    }
+    ScopedICUObject<UDateFormat, udat_close> toClose(df);
+
+    JSString* str = Call(cx, [df](UChar* chars, uint32_t size, UErrorCode* status) {
+        return udat_toPattern(df, false, chars, size, status);
+    });
+    if (!str)
+        return false;
+    args.rval().setString(str);
+    return true;
+}
+
 /**
  * Returns a new UDateFormat with the locale and date-time formatting options
  * of the given DateTimeFormat.
  */
 static UDateFormat*
 NewUDateFormat(JSContext* cx, Handle<DateTimeFormatObject*> dateTimeFormat)
 {
     RootedValue value(cx);
@@ -4111,17 +4226,17 @@ GlobalObject::initIntlObject(JSContext* 
         return false;
 
     // Add the constructor properties, computing and returning the relevant
     // prototype objects needed below.
     RootedObject collatorProto(cx, CreateCollatorPrototype(cx, intl, global));
     if (!collatorProto)
         return false;
     RootedObject dateTimeFormatProto(cx), dateTimeFormat(cx);
-    dateTimeFormatProto = CreateDateTimeFormatPrototype(cx, intl, global, &dateTimeFormat);
+    dateTimeFormatProto = CreateDateTimeFormatPrototype(cx, intl, global, &dateTimeFormat, DateTimeFormatOptions::Standard);
     if (!dateTimeFormatProto)
         return false;
     RootedObject numberFormatProto(cx), numberFormat(cx);
     numberFormatProto = CreateNumberFormatPrototype(cx, intl, global, &numberFormat);
     if (!numberFormatProto)
         return false;
 
     // The |Intl| object is fully set up now, so define the global property.
--- a/js/src/builtin/Intl.h
+++ b/js/src/builtin/Intl.h
@@ -407,16 +407,45 @@ intl_defaultTimeZoneOffset(JSContext* cx
  * given locale.
  *
  * Usage: pattern = intl_patternForSkeleton(locale, skeleton)
  */
 extern MOZ_MUST_USE bool
 intl_patternForSkeleton(JSContext* cx, unsigned argc, Value* vp);
 
 /**
+ * Return a pattern in the date-time format pattern language of Unicode
+ * Technical Standard 35, Unicode Locale Data Markup Language, for the
+ * best-fit date-time style for the given locale.
+ * The function takes four arguments:
+ *
+ *   locale
+ *     BCP47 compliant locale string
+ *   dateStyle
+ *     A string with values: full or long or medium or short, or `undefined`
+ *   timeStyle
+ *     A string with values: full or long or medium or short, or `undefined`
+ *   timeZone
+ *     IANA time zone name
+ *
+ * Date and time style categories map to CLDR time/date standard
+ * format patterns.
+ *
+ * For the definition of a pattern string, see LDML 4.8:
+ * http://unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns
+ *
+ * If `undefined` is passed to `dateStyle` or `timeStyle`, the respective
+ * portions of the pattern will not be included in the result.
+ *
+ * Usage: pattern = intl_patternForStyle(locale, dateStyle, timeStyle, timeZone)
+ */
+extern MOZ_MUST_USE bool
+intl_patternForStyle(JSContext* cx, unsigned argc, Value* vp);
+
+/**
  * Returns a String value representing x (which must be a Number value)
  * according to the effective locale and the formatting options of the
  * given DateTimeFormat.
  *
  * Spec: ECMAScript Internationalization API Specification, 12.3.2.
  *
  * Usage: formatted = intl_FormatDateTime(dateTimeFormat, x, formatToParts)
  */
--- a/js/src/builtin/Intl.js
+++ b/js/src/builtin/Intl.js
@@ -2192,16 +2192,28 @@ function resolveDateTimeFormatInternals(
     //
     //     formatOpt: // *second* opt computed in InitializeDateTimeFormat
     //       {
     //         // all the properties/values listed in Table 3
     //         // (weekday, era, year, month, day, &c.)
     //       }
     //
     //     formatMatcher: "basic" / "best fit",
+    //
+    //     mozExtensions: true / false,
+    //
+    //
+    //     // If mozExtensions is true:
+    //
+    //     dateStyle: "full" / "long" / "medium" / "short" / undefined,
+    //
+    //     timeStyle: "full" / "long" / "medium" / "short" / undefined,
+    //
+    //     patternOption:
+    //       String representing LDML Date Format pattern or undefined
     //   }
     //
     // Note that lazy data is only installed as a final step of initialization,
     // so every DateTimeFormat lazy data object has *all* these properties,
     // never a subset of them.
 
     var internalProps = std_Object_create(null);
 
@@ -2230,17 +2242,36 @@ function resolveDateTimeFormatInternals(
 
     // Steps 15-17.
     internalProps.timeZone = lazyDateTimeFormatData.timeZone;
 
     // Step 18.
     var formatOpt = lazyDateTimeFormatData.formatOpt;
 
     // Steps 27-28, more or less - see comment after this function.
-    var pattern = toBestICUPattern(dataLocale, formatOpt);
+    var pattern;
+    if (lazyDateTimeFormatData.mozExtensions) {
+        if (lazyDateTimeFormatData.patternOption !== undefined) {
+            pattern = lazyDateTimeFormatData.patternOption;
+
+            internalProps.patternOption = lazyDateTimeFormatData.patternOption;
+        } else if (lazyDateTimeFormatData.dateStyle || lazyDateTimeFormatData.timeStyle) {
+            pattern = intl_patternForStyle(dataLocale,
+              lazyDateTimeFormatData.dateStyle, lazyDateTimeFormatData.timeStyle,
+              lazyDateTimeFormatData.timeZone);
+
+            internalProps.dateStyle = lazyDateTimeFormatData.dateStyle;
+            internalProps.timeStyle = lazyDateTimeFormatData.timeStyle;
+        } else {
+            pattern = toBestICUPattern(dataLocale, formatOpt);
+        }
+        internalProps.mozExtensions = true;
+    } else {
+      pattern = toBestICUPattern(dataLocale, formatOpt);
+    }
 
     // Step 29.
     internalProps.pattern = pattern;
 
     // Step 30.
     internalProps.boundFormat = undefined;
 
     // The caller is responsible for associating |internalProps| with the right
@@ -2296,17 +2327,17 @@ function UnwrapDateTimeFormat(dtf, metho
  * This method is complicated a moderate bit by its implementing initialization
  * as a *lazy* concept.  Everything that must happen now, does -- but we defer
  * all the work we can until the object is actually used as a DateTimeFormat.
  * This later work occurs in |resolveDateTimeFormatInternals|; steps not noted
  * here occur there.
  *
  * Spec: ECMAScript Internationalization API Specification, 12.1.1.
  */
-function InitializeDateTimeFormat(dateTimeFormat, thisValue, locales, options) {
+function InitializeDateTimeFormat(dateTimeFormat, thisValue, locales, options, mozExtensions) {
     assert(IsObject(dateTimeFormat), "InitializeDateTimeFormat called with non-Object");
     assert(IsDateTimeFormat(dateTimeFormat),
            "InitializeDateTimeFormat called with non-DateTimeFormat");
 
     // Steps 1-2 (These steps are no longer required and should be removed
     // from the spec; https://github.com/tc39/ecma402/issues/115).
 
     // Lazy DateTimeFormat data has the following structure:
@@ -2373,16 +2404,28 @@ function InitializeDateTimeFormat(dateTi
         tz = DefaultTimeZone();
     }
     lazyDateTimeFormatData.timeZone = tz;
 
     // Step 18.
     var formatOpt = new Record();
     lazyDateTimeFormatData.formatOpt = formatOpt;
 
+    lazyDateTimeFormatData.mozExtensions = mozExtensions;
+
+    if (mozExtensions) {
+        let pattern = GetOption(options, "pattern", "string", undefined, undefined);
+        lazyDateTimeFormatData.patternOption = pattern;
+
+        let dateStyle = GetOption(options, "dateStyle", "string", ["full", "long", "medium", "short"], undefined);
+        lazyDateTimeFormatData.dateStyle = dateStyle;
+        let timeStyle = GetOption(options, "timeStyle", "string", ["full", "long", "medium", "short"], undefined);
+        lazyDateTimeFormatData.timeStyle = timeStyle;
+    }
+
     // Step 19.
     // 12.1, Table 4: Components of date and time formats.
     formatOpt.weekday = GetOption(options, "weekday", "string", ["narrow", "short", "long"],
                                   undefined);
     formatOpt.era = GetOption(options, "era", "string", ["narrow", "short", "long"], undefined);
     formatOpt.year = GetOption(options, "year", "string", ["2-digit", "numeric"], undefined);
     formatOpt.month = GetOption(options, "month", "string",
                                 ["2-digit", "numeric", "narrow", "short", "long"], undefined);
@@ -2788,18 +2831,28 @@ function Intl_DateTimeFormat_resolvedOpt
     var dtf = UnwrapDateTimeFormat(this, "resolvedOptions");
 
     var internals = getDateTimeFormatInternals(dtf);
 
     var result = {
         locale: internals.locale,
         calendar: internals.calendar,
         numberingSystem: internals.numberingSystem,
-        timeZone: internals.timeZone
+        timeZone: internals.timeZone,
     };
+
+    if (internals.mozExtensions) {
+        if (internals.patternOption !== undefined) {
+            result.pattern = internals.pattern;
+        } else if (internals.dateStyle || internals.timeStyle) {
+            result.dateStyle = internals.dateStyle;
+            result.timeStyle = internals.timeStyle;
+        }
+    }
+
     resolveICUPattern(internals.pattern, result);
     return result;
 }
 
 
 // Table mapping ICU pattern characters back to the corresponding date-time
 // components of DateTimeFormat. See
 // http://unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -2905,16 +2905,31 @@ extern JS_FRIEND_API(JSObject*)
 ToWindowIfWindowProxy(JSObject* obj);
 
 // Create and add the Intl.PluralRules constructor function to the provided
 // object.  This function throws if called more than once per realm/global
 // object.
 extern bool
 AddPluralRulesConstructor(JSContext* cx, JS::Handle<JSObject*> intl);
 
+// Create and add the Intl.MozDateTimeFormat constructor function to the provided
+// object.
+//
+// This custom date/time formatter constructor gives users the ability
+// to specify a custom format pattern. This pattern is passed *directly*
+// to ICU with NO SYNTAX PARSING OR VALIDATION WHATSOEVER. ICU appears to
+// have a a modicum of testing of this, and it won't fall over completely
+// if passed bad input. But the current behavior is entirely under-specified
+// and emphatically not shippable on the web, and it *must* be fixed before
+// this functionality can be exposed in the real world. (There are also some
+// questions about whether the format exposed here is the *right* one to
+// standardize, that will also need to be resolved to ship this.)
+extern bool
+AddMozDateTimeFormatConstructor(JSContext* cx, JS::Handle<JSObject*> intl);
+
 class MOZ_STACK_CLASS JS_FRIEND_API(AutoAssertNoContentJS)
 {
   public:
     explicit AutoAssertNoContentJS(JSContext* cx);
     ~AutoAssertNoContentJS();
 
   private:
     JSContext* context_;
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -957,16 +957,19 @@ AddIntlExtras(JSContext* cx, unsigned ar
     };
 
     if (!JS_DefineFunctions(cx, intl, funcs))
         return false;
 
     if (!js::AddPluralRulesConstructor(cx, intl))
         return false;
 
+    if (!js::AddMozDateTimeFormatConstructor(cx, intl))
+        return false;
+
     args.rval().setUndefined();
     return true;
 }
 #endif // ENABLE_INTL_API
 
 static bool
 EvalAndPrint(JSContext* cx, const char* bytes, size_t length,
              int lineno, bool compileOnly)
new file mode 100644
--- /dev/null
+++ b/js/src/tests/Intl/DateTimeFormat/mozExtensions.js
@@ -0,0 +1,58 @@
+// |reftest| skip-if(!this.hasOwnProperty("Intl")||!this.hasOwnProperty("addIntlExtras"))
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Tests the format function with a diverse set of locales and options.
+// Always use UTC to avoid dependencies on test environment.
+
+let mozIntl = {};
+addIntlExtras(mozIntl);
+
+// Pattern
+
+var dtf = new Intl.DateTimeFormat("en-US", {pattern: "HH:mm MM/dd/YYYY"});
+var mozDtf = new mozIntl.DateTimeFormat("en-US", {pattern: "HH:mm MM/dd/YYYY"});
+
+assertEq(dtf.resolvedOptions().hasOwnProperty('pattern'), false);
+assertEq(mozDtf.resolvedOptions().pattern, "HH:mm MM/dd/YYYY");
+
+// Date style
+
+var dtf = new Intl.DateTimeFormat("en-US", {dateStyle: 'long'});
+assertEq(mozDtf.resolvedOptions().hasOwnProperty('dateStyle'), false);
+
+var mozDtf = new mozIntl.DateTimeFormat("en-US", {dateStyle: 'long'});
+assertEq(mozDtf.resolvedOptions().dateStyle, 'long');
+assertEq(mozDtf.resolvedOptions().hasOwnProperty('year'), true);
+assertEq(mozDtf.resolvedOptions().hasOwnProperty('month'), true);
+assertEq(mozDtf.resolvedOptions().hasOwnProperty('day'), true);
+
+// Time style
+
+var dtf = new Intl.DateTimeFormat("en-US", {timeStyle: 'long'});
+assertEq(dtf.resolvedOptions().hasOwnProperty('dateStyle'), false);
+
+var mozDtf = new mozIntl.DateTimeFormat("en-US", {timeStyle: 'long'});
+assertEq(mozDtf.resolvedOptions().timeStyle, 'long');
+assertEq(mozDtf.resolvedOptions().hasOwnProperty('hour'), true);
+assertEq(mozDtf.resolvedOptions().hasOwnProperty('minute'), true);
+assertEq(mozDtf.resolvedOptions().hasOwnProperty('second'), true);
+
+// Date/Time style
+
+var dtf = new Intl.DateTimeFormat("en-US", {timeStyle: 'medium', dateStyle: 'medium'});
+assertEq(dtf.resolvedOptions().hasOwnProperty('dateStyle'), false);
+assertEq(dtf.resolvedOptions().hasOwnProperty('timeStyle'), false);
+
+var mozDtf = new mozIntl.DateTimeFormat("en-US", {dateStyle: 'medium', timeStyle: 'medium'});
+assertEq(mozDtf.resolvedOptions().timeStyle, 'medium');
+assertEq(mozDtf.resolvedOptions().dateStyle, 'medium');
+assertEq(mozDtf.resolvedOptions().hasOwnProperty('hour'), true);
+assertEq(mozDtf.resolvedOptions().hasOwnProperty('minute'), true);
+assertEq(mozDtf.resolvedOptions().hasOwnProperty('second'), true);
+assertEq(mozDtf.resolvedOptions().hasOwnProperty('year'), true);
+assertEq(mozDtf.resolvedOptions().hasOwnProperty('month'), true);
+assertEq(mozDtf.resolvedOptions().hasOwnProperty('day'), true);
+
+reportCompare(0, 0, 'ok');
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -2617,16 +2617,17 @@ static const JSFunctionSpec intrinsic_fu
     JS_FN("intl_GetCalendarInfo", intl_GetCalendarInfo, 1,0),
     JS_FN("intl_GetLocaleInfo", intl_GetLocaleInfo, 1,0),
     JS_FN("intl_ComputeDisplayNames", intl_ComputeDisplayNames, 3,0),
     JS_FN("intl_IsValidTimeZoneName", intl_IsValidTimeZoneName, 1,0),
     JS_FN("intl_NumberFormat", intl_NumberFormat, 2,0),
     JS_FN("intl_NumberFormat_availableLocales", intl_NumberFormat_availableLocales, 0,0),
     JS_FN("intl_numberingSystem", intl_numberingSystem, 1,0),
     JS_FN("intl_patternForSkeleton", intl_patternForSkeleton, 2,0),
+    JS_FN("intl_patternForStyle", intl_patternForStyle, 3,0),
     JS_FN("intl_PluralRules_availableLocales", intl_PluralRules_availableLocales, 0,0),
     JS_FN("intl_GetPluralCategories", intl_GetPluralCategories, 2, 0),
     JS_FN("intl_SelectPluralRule", intl_SelectPluralRule, 2,0),
 
     JS_INLINABLE_FN("IsCollator",
                     intrinsic_IsInstanceOfBuiltin<CollatorObject>, 1,0,
                     IntlIsCollator),
     JS_INLINABLE_FN("IsDateTimeFormat",
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ServoRestyleManager.h"
 
 #include "mozilla/DocumentStyleRootIterator.h"
 #include "mozilla/ServoBindings.h"
 #include "mozilla/ServoStyleSet.h"
+#include "mozilla/Unused.h"
 #include "mozilla/dom/ChildIterator.h"
 #include "nsContentUtils.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsPrintfCString.h"
 #include "nsRefreshDriver.h"
 #include "nsStyleChangeList.h"
 
 using namespace mozilla::dom;
@@ -112,26 +113,32 @@ ServoRestyleManager::ClearServoDataFromS
     if (n->IsElement()) {
       ClearServoDataFromSubtree(n->AsElement());
     }
   }
 
   aElement->UnsetHasDirtyDescendantsForServo();
 }
 
-/* static */ void
-ServoRestyleManager::ClearDirtyDescendantsFromSubtree(Element* aElement)
+
+// Clears HasDirtyDescendants and RestyleData from all elements in the
+// subtree rooted at aElement.
+static void
+ClearRestyleStateFromSubtree(Element* aElement)
 {
-  StyleChildrenIterator it(aElement);
-  for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
-    if (n->IsElement()) {
-      ClearDirtyDescendantsFromSubtree(n->AsElement());
+  if (aElement->HasDirtyDescendantsForServo()) {
+    StyleChildrenIterator it(aElement);
+    for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
+      if (n->IsElement()) {
+        ClearRestyleStateFromSubtree(n->AsElement());
+      }
     }
   }
 
+  Unused << Servo_TakeChangeHint(aElement);
   aElement->UnsetHasDirtyDescendantsForServo();
 }
 
 static void
 UpdateStyleContextForTableWrapper(nsIFrame* aTableWrapper,
                                   nsStyleContext* aTableStyleContext,
                                   ServoStyleSet* aStyleSet)
 {
@@ -178,17 +185,17 @@ ServoRestyleManager::RecreateStyleContex
   }
 
   // If our change hint is reconstruct, we delegate to the frame constructor,
   // which consumes the new style and expects the old style to be on the frame.
   //
   // XXXbholley: We should teach the frame constructor how to clear the dirty
   // descendants bit to avoid the traversal here.
   if (changeHint & nsChangeHint_ReconstructFrame) {
-    ClearDirtyDescendantsFromSubtree(aElement);
+    ClearRestyleStateFromSubtree(aElement);
     return;
   }
 
   // TODO(emilio): We could avoid some refcount traffic here, specially in the
   // ServoComputedValues case, which uses atomic refcounting.
   //
   // Hold the old style context alive, because it could become a dangling
   // pointer during the replacement. In practice it's not a huge deal (on
--- a/layout/base/ServoRestyleManager.h
+++ b/layout/base/ServoRestyleManager.h
@@ -87,22 +87,16 @@ public:
                                          nsIAtom* aPseudoTagOrNull);
 
   /**
    * Clears the ServoElementData and HasDirtyDescendants from all elements
    * in the subtree rooted at aElement.
    */
   static void ClearServoDataFromSubtree(Element* aElement);
 
-  /**
-   * Clears HasDirtyDescendants from all elements in the subtree rooted at
-   * aElement.
-   */
-  static void ClearDirtyDescendantsFromSubtree(Element* aElement);
-
 protected:
   ~ServoRestyleManager() override
   {
     MOZ_ASSERT(!mReentrantChanges);
   }
 
 private:
   /**
--- a/layout/base/nsFrameManager.cpp
+++ b/layout/base/nsFrameManager.cpp
@@ -722,17 +722,17 @@ nsFrameManagerBase::UndisplayedMap::GetE
   if (parentContent && nsContentUtils::IsContentInsertionPoint(parentContent)) {
     parentContent = parentContent->GetParent();
     // Change the caller's pointer for the parent content to be the insertion parent.
     *aParentContent = parentContent;
   }
 
   PLHashNumber hashCode = NS_PTR_TO_INT32(parentContent);
   PLHashEntry** entry = PL_HashTableRawLookup(mTable, hashCode, parentContent);
-  if (*entry) {
+  if (*entry && !ServoStyleSet::IsInServoTraversal()) {
     mLastLookup = entry;
   }
   return entry;
 }
 
 UndisplayedNode* 
 nsFrameManagerBase::UndisplayedMap::GetFirstNode(nsIContent* aParentContent)
 {
--- a/layout/reftests/backgrounds/reftest-stylo.list
+++ b/layout/reftests/backgrounds/reftest-stylo.list
@@ -147,19 +147,19 @@ fails == table-background-print.html tab
 == background-repeat-1-ref.html background-repeat-1-ref.html
 
 == multi-background-clip-content-border.html multi-background-clip-content-border.html
 
 fails HTTP == background-referrer.html background-referrer.html
 
 == attachment-scroll-positioning-1.html attachment-scroll-positioning-1.html
 == attachment-local-positioning-1.html attachment-local-positioning-1.html
-fails == attachment-local-positioning-2.html attachment-local-positioning-2.html
-fails == attachment-local-positioning-3.html attachment-local-positioning-3.html
-fails == attachment-local-positioning-4.html attachment-local-positioning-4.html
+== attachment-local-positioning-2.html attachment-local-positioning-2.html
+== attachment-local-positioning-3.html attachment-local-positioning-3.html
+== attachment-local-positioning-4.html attachment-local-positioning-4.html
 == attachment-local-positioning-5.html attachment-local-positioning-5.html
 
 == attachment-local-clipping-color-1.html attachment-local-clipping-color-1.html
 == attachment-local-clipping-color-2.html attachment-local-clipping-color-2.html
 == attachment-local-clipping-color-3.html attachment-local-clipping-color-3.html
 == attachment-local-clipping-color-4.html attachment-local-clipping-color-4.html
 == attachment-local-clipping-color-5.html attachment-local-clipping-color-5.html
 == attachment-local-clipping-color-6.html attachment-local-clipping-color-6.html
--- a/layout/reftests/bugs/reftest-stylo.list
+++ b/layout/reftests/bugs/reftest-stylo.list
@@ -87,17 +87,17 @@ fails == 82711-1.html 82711-1.html
 fails == 82711-2.html 82711-2.html
 fails == 82711-3.html 82711-3.html
 fails == 82711-1-ref.html 82711-1-ref.html # Bug 1341697, Bug 1341637
 fails == 82711-1-ref.html 82711-1-ref.html # Bug 1341697, Bug 1341637
 fails == 82711-2-ref.html 82711-2-ref.html
 fails == 84400-1.html 84400-1.html
 fails == 84400-2.html 84400-2.html
 == 97777-1.html 97777-1.html
-fails == 97777-2.html 97777-2.html
+== 97777-2.html 97777-2.html
 == 98223-1.html 98223-1.html
 == 98223-2.html 98223-2.html
 skip-if(stylo) == 99850-1a.html 99850-1a.html # bug 1337695
 skip-if(stylo) == 99850-1b.html 99850-1b.html # bug 1337695
 fails == 99850-1c.html 99850-1c.html
 skip-if(stylo) == 99850-1d.html 99850-1d.html # bug 1337695
 == 105030-1.html 105030-1.html
 == 109735-1.html 109735-1.html
@@ -686,22 +686,22 @@ fails == 378933-1.html 378933-1.html
 fails == 378935-1.html 378935-1.html
 fails == 378937-1.html 378937-1.html
 == 379178-xhtml.xhtml 379178-xhtml.xhtml
 fails == 379178-html.html 379178-html.html
 == 379178-svg.svg 379178-svg.svg
 == 379316-1.html 379316-1.html
 == 379316-2.html 379316-2.html
 == 379328-1.html 379328-1.html
-fails == 379349-1a.xhtml 379349-1a.xhtml
+== 379349-1a.xhtml 379349-1a.xhtml
 # fuzzy because of different border rendering approach in bug 1185636
-fails == 379349-1b.xhtml 379349-1b.xhtml
-fails == 379349-1c.xhtml 379349-1c.xhtml
-fails == 379349-2a.xhtml 379349-2a.xhtml
-fails == 379349-2b.xhtml 379349-2b.xhtml
+== 379349-1b.xhtml 379349-1b.xhtml
+== 379349-1c.xhtml 379349-1c.xhtml
+== 379349-2a.xhtml 379349-2a.xhtml
+== 379349-2b.xhtml 379349-2b.xhtml
 fails == 379349-3a.xhtml 379349-3a.xhtml
 fails == 379349-3b.xhtml 379349-3b.xhtml
 fails == 379361-1.html 379361-1.html
 fails == 379361-2.html 379361-2.html
 fails == 379361-3.html 379361-3.html
 == 379461-1.xhtml 379461-1.xhtml
 == 379461-2.xhtml 379461-2.xhtml
 fails == 379461-3-container-xhtml.html 379461-3-container-xhtml.html # Bug 1341095
@@ -714,22 +714,22 @@ fails == 380825-1.html 380825-1.html
 fails == 381507-1.html 381507-1.html
 == 381746-1.html 381746-1.html
 fails == 382600-1.html 382600-1.html
 fails == 382916-1.html 382916-1.html
 == 383035-1.html 383035-1.html
 == 383035-2.html 383035-2.html
 == 383488-1.html 383488-1.html
 == 383551-1.html 383551-1.html
-fails == 383883-1.html 383883-1.html
-fails == 383883-2.html 383883-2.html
-fails == 383883-3.html 383883-3.html
-fails == 383883-4.html 383883-4.html
-fails == 383884-1.html 383884-1.html
-fails == 383885-1.html 383885-1.html
+== 383883-1.html 383883-1.html
+== 383883-2.html 383883-2.html
+== 383883-3.html 383883-3.html
+== 383883-4.html 383883-4.html
+== 383884-1.html 383884-1.html
+== 383885-1.html 383885-1.html
 fails == 384322-1.html 384322-1.html
 == 384576-1.html 384576-1.html
 == 384762-1.html 384762-1.html
 == 384876-1.html 384876-1.html
 == 385533-1.html 385533-1.html
 fails HTTP(..) == 385569-1a.html 385569-1a.html
 fails HTTP(..) == 385569-1b.html 385569-1b.html
 == 385607-1.html 385607-1.html
@@ -816,17 +816,17 @@ fails == 395107-4.html 395107-4.html
 fails == 395107-5.html 395107-5.html
 fails == 395130-1.html 395130-1.html
 fails == 395130-2.html 395130-2.html
 == 395331-1.xml 395331-1.xml
 fails == 395390-1.html 395390-1.html
 == 396286-1.html 396286-1.html
 fails == 397428-1.html 397428-1.html
 == 397844-1.xhtml 397844-1.xhtml
-fails == 398092-1.html 398092-1.html
+== 398092-1.html 398092-1.html
 fails == 398101-1.html 398101-1.html
 == 398144-1.html 398144-1.html
 == 398682-1.html 398682-1.html
 == 398797-1a.html 398797-1a.html
 == 398797-1b.html 398797-1b.html
 == 398797-1c.html 398797-1c.html
 == 398797-1d.html 398797-1d.html
 == 399209-1.html 399209-1.html
@@ -982,17 +982,17 @@ fails == 413840-pushed-line-bullet.html 
 == 413982.html 413982.html
 fails == 414123.xhtml 414123.xhtml
 == 414638.html 414638.html
 fails == 414851-1.html 414851-1.html
 fails == 416106-1.xhtml 416106-1.xhtml
 == 416752-1.html 416752-1.html
 == 417178-1.html 417178-1.html
 == 417246-1.html 417246-1.html
-fails == 417676.html 417676.html
+== 417676.html 417676.html
 fails asserts(1) == 418574-1.html 418574-1.html
 fails asserts(1) == 418574-2.html 418574-2.html
 == 418766-1a.html 418766-1a.html
 == 418766-1b.html 418766-1b.html
 == 419060.html 419060.html
 == 419285-1.html 419285-1.html
 fails == 419531-1.html 419531-1.html
 == 420069-1.html 420069-1.html
--- a/layout/reftests/columns/reftest-stylo.list
+++ b/layout/reftests/columns/reftest-stylo.list
@@ -1,28 +1,28 @@
 # DO NOT EDIT! This is a auto-generated temporary list for Stylo testing
 == basic-1.html basic-1.html
 == pref-width-1a.html pref-width-1a.html
 == pref-width-1b.html pref-width-1b.html
 == pref-width-1c.html pref-width-1c.html
 fails == min-width-1a.html min-width-1a.html
 == min-width-1b.html min-width-1b.html
 == min-width-1c.html min-width-1c.html
-fails == min-width-2.html min-width-2.html
-fails == column-balancing-overflow-000.html column-balancing-overflow-000.html
-fails == column-balancing-overflow-001.html column-balancing-overflow-001.html
-fails == column-balancing-overflow-002.html column-balancing-overflow-002.html
-fails == column-balancing-overflow-003.html column-balancing-overflow-003.html
+== min-width-2.html min-width-2.html
+== column-balancing-overflow-000.html column-balancing-overflow-000.html
+== column-balancing-overflow-001.html column-balancing-overflow-001.html
+== column-balancing-overflow-002.html column-balancing-overflow-002.html
+== column-balancing-overflow-003.html column-balancing-overflow-003.html
 == column-balancing-overflow-004.html column-balancing-overflow-004.html
 == column-balancing-overflow-005.html column-balancing-overflow-005.html
-fails == column-balancing-000.html column-balancing-000.html
-fails == column-balancing-001.html column-balancing-001.html
-fails == column-balancing-002.html column-balancing-002.html
-fails == column-balancing-003.html column-balancing-003.html
-fails == column-balancing-004.html column-balancing-004.html
+== column-balancing-000.html column-balancing-000.html
+== column-balancing-001.html column-balancing-001.html
+== column-balancing-002.html column-balancing-002.html
+== column-balancing-003.html column-balancing-003.html
+== column-balancing-004.html column-balancing-004.html
 == column-box-alignment-rtl.html column-box-alignment-rtl.html
 fails HTTP(..) == columnfill-balance.html columnfill-balance.html
 fails == columnfill-auto.html columnfill-auto.html
 fails HTTP(..) == columnfill-auto-2.html columnfill-auto-2.html
 fails HTTP(..) == columnfill-auto-3.html columnfill-auto-3.html
 fails == columnrule-basic.html columnrule-basic.html
 fails == columnrule-complex.html columnrule-complex.html
 == columnrule-linestyles.html columnrule-linestyles.html
--- a/layout/reftests/css-break/reftest-stylo.list
+++ b/layout/reftests/css-break/reftest-stylo.list
@@ -5,9 +5,9 @@ fails == box-decoration-break-1.html box
 fails == box-decoration-break-with-inset-box-shadow-1.html box-decoration-break-with-inset-box-shadow-1.html
 fails == box-decoration-break-with-outset-box-shadow-1.html box-decoration-break-with-outset-box-shadow-1.html
 fails == box-decoration-break-border-image.html box-decoration-break-border-image.html
 == box-decoration-break-block-border-padding.html box-decoration-break-block-border-padding.html
 == box-decoration-break-block-margin.html box-decoration-break-block-margin.html
 fails == box-decoration-break-first-letter.html box-decoration-break-first-letter.html
 == box-decoration-break-with-bidi.html box-decoration-break-with-bidi.html
 == box-decoration-break-bug-1235152.html box-decoration-break-bug-1235152.html
-fails == box-decoration-break-bug-1249913.html box-decoration-break-bug-1249913.html
+== box-decoration-break-bug-1249913.html box-decoration-break-bug-1249913.html
--- a/layout/reftests/invalidation/reftest-stylo.list
+++ b/layout/reftests/invalidation/reftest-stylo.list
@@ -83,12 +83,12 @@ fails pref(layers.single-tile.enabled,fa
 fails == mask-invalidation-1a.html mask-invalidation-1a.html
 fails == mask-invalidation-1b.html mask-invalidation-1b.html
 
 fails == mask-invalidation-2a.html mask-invalidation-2a.html
 fails == mask-invalidation-2b.html mask-invalidation-2b.html
 fails == mask-invalidation-2c.html mask-invalidation-2c.html
 fails == mask-invalidation-2d.html mask-invalidation-2d.html
 
-fails == clip-path-invalidation-1a.html clip-path-invalidation-1a.html
-fails == clip-path-invalidation-1b.html clip-path-invalidation-1b.html
+== clip-path-invalidation-1a.html clip-path-invalidation-1a.html
+== clip-path-invalidation-1b.html clip-path-invalidation-1b.html
 == clip-path-invalidation-1c.html clip-path-invalidation-1c.html
 == clip-path-invalidation-1d.html clip-path-invalidation-1d.html
--- a/layout/reftests/pagination/reftest-stylo.list
+++ b/layout/reftests/pagination/reftest-stylo.list
@@ -11,45 +11,45 @@ fails == abspos-breaking-002.xhtml abspo
 == abspos-breaking-006.html abspos-breaking-006.html
 pref(layout.css.box-decoration-break.enabled,true) == abspos-breaking-007.html abspos-breaking-007.html
 pref(layout.css.box-decoration-break.enabled,true) == abspos-breaking-008.html abspos-breaking-008.html
 pref(layout.css.box-decoration-break.enabled,true) == abspos-breaking-009.html abspos-breaking-009.html
 pref(layout.css.box-decoration-break.enabled,true) == abspos-breaking-010.html abspos-breaking-010.html
 == abspos-breaking-011.html abspos-breaking-011.html
 == abspos-overflow-01.xhtml abspos-overflow-01.xhtml
 == abspos-overflow-01-cols.xhtml abspos-overflow-01-cols.xhtml
-fails == border-breaking-000-cols.xhtml border-breaking-000-cols.xhtml
-fails == border-breaking-001-cols.xhtml border-breaking-001-cols.xhtml
-fails == border-breaking-002-cols.xhtml border-breaking-002-cols.xhtml
-fails == border-breaking-003-cols.xhtml border-breaking-003-cols.xhtml
-fails == border-breaking-004-cols.xhtml border-breaking-004-cols.xhtml
+== border-breaking-000-cols.xhtml border-breaking-000-cols.xhtml
+== border-breaking-001-cols.xhtml border-breaking-001-cols.xhtml
+== border-breaking-002-cols.xhtml border-breaking-002-cols.xhtml
+== border-breaking-003-cols.xhtml border-breaking-003-cols.xhtml
+== border-breaking-004-cols.xhtml border-breaking-004-cols.xhtml
 == content-inserted-000.xhtml content-inserted-000.xhtml
 == content-inserted-001.xhtml content-inserted-001.xhtml
 == content-inserted-002.xhtml content-inserted-002.xhtml
 == content-inserted-003.xhtml content-inserted-003.xhtml
 == content-inserted-004.xhtml content-inserted-004.xhtml
 == content-inserted-005.xhtml content-inserted-005.xhtml
 == content-inserted-006.xhtml content-inserted-006.xhtml
 == content-inserted-007.xhtml content-inserted-007.xhtml
 == content-inserted-008.xhtml content-inserted-008.xhtml
 == content-inserted-009.xhtml content-inserted-009.xhtml
 == dynamic-abspos-overflow-01-cols.xhtml dynamic-abspos-overflow-01-cols.xhtml
-fails pref(layout.float-fragments-inside-column.enabled,false) == float-clear-000.html float-clear-000.html
-fails pref(layout.float-fragments-inside-column.enabled,true) == float-clear-000.html float-clear-000.html
+pref(layout.float-fragments-inside-column.enabled,false) == float-clear-000.html float-clear-000.html
+pref(layout.float-fragments-inside-column.enabled,true) == float-clear-000.html float-clear-000.html
 fails == float-clear-001.html float-clear-001.html
-fails pref(layout.float-fragments-inside-column.enabled,false) == float-clear-002.html float-clear-002.html
-fails pref(layout.float-fragments-inside-column.enabled,true) == float-clear-002.html float-clear-002.html
-fails == float-clear-003.html float-clear-003.html
-fails == float-clear-000-print.html float-clear-000-print.html
-fails == float-clear-001-print.html float-clear-001-print.html
-fails == float-clear-002-print.html float-clear-002-print.html
-fails == float-clear-003-print.html float-clear-003-print.html
-fails == float-continuations-000.html float-continuations-000.html
-fails == resize-reflow-000.html resize-reflow-000.html
-fails == resize-reflow-001.html resize-reflow-001.html
+pref(layout.float-fragments-inside-column.enabled,false) == float-clear-002.html float-clear-002.html
+pref(layout.float-fragments-inside-column.enabled,true) == float-clear-002.html float-clear-002.html
+== float-clear-003.html float-clear-003.html
+== float-clear-000-print.html float-clear-000-print.html
+== float-clear-001-print.html float-clear-001-print.html
+== float-clear-002-print.html float-clear-002-print.html
+== float-clear-003-print.html float-clear-003-print.html
+== float-continuations-000.html float-continuations-000.html
+== resize-reflow-000.html resize-reflow-000.html
+== resize-reflow-001.html resize-reflow-001.html
 == table-page-break-before-auto-1.html table-page-break-before-auto-1.html
 fails == table-page-break-before-auto-2.html table-page-break-before-auto-2-ref.html
 == table-page-break-before-always-1.html table-page-break-before-always-1.html
 == table-page-break-before-left-1.html table-page-break-before-left-1.html
 == table-page-break-before-right-1.html table-page-break-before-right-1.html
 == table-page-break-after-always-1.html table-page-break-after-always-1.html
 == table-page-break-after-left-1.html table-page-break-after-left-1.html
 == table-page-break-after-right-1.html table-page-break-after-right-1.html
--- a/layout/reftests/printing/reftest-stylo.list
+++ b/layout/reftests/printing/reftest-stylo.list
@@ -25,12 +25,12 @@ fails == 115199-1.html 115199-1.html
 == 115199-2a.html 115199-2a.html
 == 115199-2b.html 115199-2b.html
 == 652178-1.html 652178-1.html
 == 745025-1.html 745025-1.html
 fails == 820496-1.html 820496-1.html
 
 # NOTE: These tests don't yet rigorously test what they're
 # trying to test (shrink-to-fit behavior), due to bug 967311.
-fails == 960822.html 960822.html
-fails == 966419-1.html 966419-1.html
-fails == 966419-2.html 966419-2.html
+== 960822.html 960822.html
+== 966419-1.html 966419-1.html
+== 966419-2.html 966419-2.html
 fails HTTP(..) == 1108104.html 1108104-ref.html
--- a/layout/reftests/table-anonymous-boxes/reftest-stylo.list
+++ b/layout/reftests/table-anonymous-boxes/reftest-stylo.list
@@ -31,17 +31,17 @@
 == 394402-1a.html 394402-1a.html
 == 394402-1b.html 394402-1b.html
 == 398095-1.html 398095-1.html
 == 407115-1.html 407115-1.html
 fails == 443616-1a.xhtml 443616-1a.xhtml
 fails == 443616-1b.html 443616-1b.html
 == 448111-1.html 448111-1.html
 fails == 490174-1.html 490174-1.html
-fails == 695538-1.html 695538-1.html
+== 695538-1.html 695538-1.html
 fails == infer-first-row.html infer-first-row.html
 fails == infer-first-row-and-table.html infer-first-row-and-table.html
 fails == infer-second-row.html infer-second-row.html
 fails == infer-second-row-and-table.html infer-second-row-and-table.html
 fails == infer-table-around-headers-footers-1.html infer-table-around-headers-footers-1.html
 fails == infer-table-around-headers-footers-2.html infer-table-around-headers-footers-2.html
 fails == infer-table-around-headers-footers-3.html infer-table-around-headers-footers-3.html
 fails == infer-rows-inside-rowgroups.html infer-rows-inside-rowgroups.html
--- a/layout/reftests/w3c-css/submitted/multicol3/reftest-stylo.list
+++ b/layout/reftests/w3c-css/submitted/multicol3/reftest-stylo.list
@@ -1,3 +1,3 @@
 # DO NOT EDIT! This is a auto-generated temporary list for Stylo testing
-fails == moz-multicol3-column-balancing-break-inside-avoid-1.html moz-multicol3-column-balancing-break-inside-avoid-1.html
+== moz-multicol3-column-balancing-break-inside-avoid-1.html moz-multicol3-column-balancing-break-inside-avoid-1.html
 fails == multicol-height-002.xht multicol-height-002.xht
--- a/layout/reftests/w3c-css/submitted/variables/reftest-stylo.list
+++ b/layout/reftests/w3c-css/submitted/variables/reftest-stylo.list
@@ -98,17 +98,17 @@ fails == variable-font-face-02.html vari
 == variable-reference-30.html variable-reference-30.html
 == variable-reference-31.html variable-reference-31.html
 == variable-reference-32.html variable-reference-32.html
 == variable-reference-33.html variable-reference-33.html
 == variable-reference-34.html variable-reference-34.html
 == variable-reference-35.html variable-reference-35.html
 fails == variable-reference-36.html variable-reference-36.html
 == variable-reference-37.html variable-reference-37.html
-fails == variable-reference-38.html variable-reference-38.html
+== variable-reference-38.html variable-reference-38.html
 == variable-reference-39.html variable-reference-39.html
 == variable-reference-40.html variable-reference-40.html
 == variable-supports-01.html variable-supports-01.html
 == variable-supports-02.html variable-supports-02.html
 == variable-supports-03.html variable-supports-03.html
 == variable-supports-04.html variable-supports-04.html
 == variable-supports-05.html variable-supports-05.html
 == variable-supports-06.html variable-supports-06.html
--- a/layout/reftests/writing-mode/tables/reftest-stylo.list
+++ b/layout/reftests/writing-mode/tables/reftest-stylo.list
@@ -81,14 +81,14 @@ fails == wm-row-progression-007.xht wm-r
 == table-caption-right-1.html table-caption-right-1.html
 
 fuzzy-if(stylo,1,7400) == border-collapse-bevels-1a.html border-collapse-bevels-1a.html
 fuzzy-if(stylo,1,7400) fuzzy-if(cocoaWidget,23,162) == border-collapse-bevels-1b.html border-collapse-bevels-1b.html
 fuzzy-if(stylo,1,7400) fuzzy-if(cocoaWidget,23,162) == border-collapse-bevels-1c.html border-collapse-bevels-1c.html
 fuzzy-if(stylo,1,7400) fuzzy-if(cocoaWidget,23,162) == border-collapse-bevels-1d.html border-collapse-bevels-1d.html
 fuzzy-if(stylo,1,7400) fuzzy-if(cocoaWidget,23,162) == border-collapse-bevels-1e.html border-collapse-bevels-1e.html
 
-fails == vertical-rl-row-progression-1a.html vertical-rl-row-progression-1a.html
-fails == vertical-rl-row-progression-1b.html vertical-rl-row-progression-1b.html
+== vertical-rl-row-progression-1a.html vertical-rl-row-progression-1a.html
+== vertical-rl-row-progression-1b.html vertical-rl-row-progression-1b.html
 fails == sideways-lr-row-progression-1a.html sideways-lr-row-progression-1a.html
 fails == sideways-lr-row-progression-1b.html sideways-lr-row-progression-1b.html
 fails == sideways-rl-row-progression-1a.html sideways-rl-row-progression-1a.html
 fails == sideways-rl-row-progression-1b.html sideways-rl-row-progression-1b.html
--- a/layout/style/Declaration.cpp
+++ b/layout/style/Declaration.cpp
@@ -7,16 +7,17 @@
  * representation of a declaration block (or style attribute) in a CSS
  * stylesheet
  */
 
 #include "mozilla/css/Declaration.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/MemoryReporting.h"
+#include "mozilla/ServoStyleSet.h"
 
 #include "mozilla/css/Rule.h"
 #include "nsPrintfCString.h"
 #include "gfxFontConstants.h"
 #include "nsStyleUtil.h"
 
 namespace mozilla {
 namespace css {
@@ -1697,16 +1698,20 @@ Declaration::AppendVariableAndValueToStr
     aResult.AppendLiteral("!important");
   }
   aResult.AppendLiteral("; ");
 }
 
 void
 Declaration::ToString(nsAString& aString) const
 {
+  // Tell the static analysis not to worry about thread-unsafe things here
+  // because because this function isn't reached during parallel style traversal.
+  MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal());
+
   nsCSSCompressedDataBlock *systemFontData =
     GetPropertyIsImportantByID(eCSSProperty__x_system_font) ? mImportantData
                                                             : mData;
   const nsCSSValue *systemFont =
     systemFontData->ValueFor(eCSSProperty__x_system_font);
   const bool haveSystemFont = systemFont &&
                                 systemFont->GetUnit() != eCSSUnit_None &&
                                 systemFont->GetUnit() != eCSSUnit_Null;
--- a/layout/style/nsCSSPseudoClassList.h
+++ b/layout/style/nsCSSPseudoClassList.h
@@ -115,17 +115,18 @@ CSS_PSEUDO_CLASS(mozLWThemeBrightText, "
 // -moz-lwtheme-darktext matches a document that has a bright lightweight theme
 CSS_PSEUDO_CLASS(mozLWThemeDarkText, ":-moz-lwtheme-darktext", 0, "")
 
 // Matches anything when the containing window is inactive
 CSS_PSEUDO_CLASS(mozWindowInactive, ":-moz-window-inactive", 0, "")
 
 // Matches any table elements that have a nonzero border attribute,
 // according to HTML integer attribute parsing rules.
-CSS_PSEUDO_CLASS(mozTableBorderNonzero, ":-moz-table-border-nonzero", 0, "")
+CSS_PSEUDO_CLASS(mozTableBorderNonzero, ":-moz-table-border-nonzero",
+                 CSS_PSEUDO_CLASS_ENABLED_IN_UA_SHEETS, "")
 
 // Matches HTML frame/iframe elements which are mozbrowser.
 CSS_PSEUDO_CLASS(mozBrowserFrame, ":-moz-browser-frame",
                  CSS_PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME, "")
 
 // Matches whatever the contextual reference elements are for the
 // matching operation.
 CSS_PSEUDO_CLASS(scope, ":scope", 0, "layout.css.scope-pseudo.enabled")
--- a/layout/style/nsStyleContext.cpp
+++ b/layout/style/nsStyleContext.cpp
@@ -1197,16 +1197,21 @@ nsStyleContext::CalcStyleDifferenceInter
   // call GetVisitedDependentColor.
   nsStyleContext *thisVis = GetStyleIfVisited(),
                 *otherVis = aNewContext->GetStyleIfVisited();
   if (!thisVis != !otherVis) {
     // One style context has a style-if-visited and the other doesn't.
     // Presume a difference.
     hint |= nsChangeHint_RepaintFrame;
   } else if (thisVis && !NS_IsHintSubset(nsChangeHint_RepaintFrame, hint)) {
+    // We'll handle visited style differently in servo. Assert against being
+    // in the parallel traversal to avoid static analysis hazards when calling
+    // StyleFoo() below.
+    MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal());
+
     // Both style contexts have a style-if-visited.
     bool change = false;
 
     // NB: Calling Peek on |this|, not |thisVis|, since callers may look
     // at a struct on |this| without looking at the same struct on
     // |thisVis| (including this function if we skip one of these checks
     // due to change being true already or due to the old style context
     // not having a style-if-visited), but not the other way around.
--- a/layout/style/nsStyleStructInlines.h
+++ b/layout/style/nsStyleStructInlines.h
@@ -146,17 +146,17 @@ nsStyleDisplay::HasTransform(const nsIFr
 
 template<class StyleContextLike>
 bool
 nsStyleDisplay::HasFixedPosContainingBlockStyleInternal(
                   StyleContextLike* aStyleContext) const
 {
   // NOTE: Any CSS properties that influence the output of this function
   // should have the CSS_PROPERTY_FIXPOS_CB set on them.
-  NS_ASSERTION(aStyleContext->StyleDisplay() == this,
+  NS_ASSERTION(aStyleContext->ThreadsafeStyleDisplay() == this,
                "unexpected aStyleContext");
 
   if (IsContainPaint() || HasPerspectiveStyle()) {
     return true;
   }
 
   if (mWillChangeBitField & NS_STYLE_WILL_CHANGE_FIXPOS_CB) {
     return true;
--- a/layout/style/test/mochitest.ini
+++ b/layout/style/test/mochitest.ini
@@ -297,20 +297,21 @@ support-files = file_transitions_with_di
 [test_unicode_range_loading.html]
 skip-if = stylo # timeout bug 1328507
 support-files = ../../reftests/fonts/markA.woff ../../reftests/fonts/markB.woff ../../reftests/fonts/markC.woff ../../reftests/fonts/markD.woff
 [test_units_angle.html]
 [test_units_frequency.html]
 [test_units_length.html]
 [test_units_time.html]
 [test_value_cloning.html]
-skip-if = toolkit == 'android' # bug 775227 for android
+skip-if = (toolkit == 'android' || stylo) # bug 775227 for android, bug 1343168 for stylo
 [test_value_computation.html]
-skip-if = toolkit == 'android'
+skip-if = (toolkit == 'android' || stylo) # bug 1343168 for stylo
 [test_value_storage.html]
+skip-if = stylo # bug 1343168
 [test_variable_serialization_computed.html]
 [test_variable_serialization_specified.html]
 [test_variables.html]
 support-files = support/external-variable-url.css
 [test_video_object_fit.html]
 [test_viewport_units.html]
 [test_visited_image_loading.html]
 skip-if = (toolkit == 'android' || stylo) # TIMED_OUT for android, timeout bug 1328511 for stylo
--- a/layout/style/test/test_selectors.html
+++ b/layout/style/test/test_selectors.html
@@ -1068,16 +1068,17 @@ function run() {
     test_unbalanced_unparseable(":-moz-handler-vulnerable-updatable");
     test_unbalanced_unparseable(":-moz-handler-vulnerable-no-update");
     test_unbalanced_unparseable(":-moz-handler-disabled");
     test_unbalanced_unparseable(":-moz-handler-blocked");
     test_unbalanced_unparseable(":-moz-handler-crashed");
 
     // We're not in a UA sheet, so this should be invalid.
     test_balanced_unparseable(":-moz-native-anonymous");
+    test_balanced_unparseable(":-moz-table-border-nonzero");
 
     // Case sensitivity of tag selectors
     function setup_cased_spans(body) {
       var data = [
         { tag: "span" },
         { tag: "sPaN" },
         { tag: "Span" },
         { tag: "SPAN" },
@@ -1202,29 +1203,16 @@ function run() {
     test_selector_in_html(":-moz-any(:link,:not(a))", any_elts,
                           bodychildset([0, 1, 2]), bodychildset([3]));
     test_selector_in_html(":-moz-any([href],input[type],input[name])", any_elts,
                           bodychildset([0, 1]), bodychildset([2, 3]));
     test_selector_in_html(":-moz-any(div,a):-moz-any([type],[href],[name])",
                           any_elts,
                           bodychildset([1, 3]), bodychildset([0, 2]));
 
-    test_selector_in_html(":-moz-table-border-nonzero",
-                          "<p></p>" +
-                          "<p border='2'></p>" +
-                          "<table border='2'></table>" +
-                          "<table border></table>" +
-                          "<table></table>" +
-                          "<table frame='border'></table>" +
-                          "<table border='0'></table>" +
-                          "<table border='0pt'></table>" +
-                          "<table border='3pt'></table>",
-                          bodychildset([2, 3, 8]),
-                          bodychildset([0, 1, 4, 5, 6, 7]));
-
     // Test that we don't tokenize an empty HASH.
     test_balanced_unparseable("#");
     test_balanced_unparseable("# ");
     test_balanced_unparseable("#, p");
     test_balanced_unparseable("# , p");
     test_balanced_unparseable("p #");
     test_balanced_unparseable("p # ");
     test_balanced_unparseable("p #, p");
--- a/media/libstagefright/binding/MP4Metadata.cpp
+++ b/media/libstagefright/binding/MP4Metadata.cpp
@@ -76,17 +76,16 @@ private:
 };
 
 class MP4MetadataStagefright
 {
 public:
   explicit MP4MetadataStagefright(Stream* aSource);
   ~MP4MetadataStagefright();
 
-  static bool HasCompleteMetadata(Stream* aSource);
   static already_AddRefed<mozilla::MediaByteBuffer> Metadata(Stream* aSource);
   uint32_t GetNumberTracks(mozilla::TrackInfo::TrackType aType) const;
   mozilla::UniquePtr<mozilla::TrackInfo> GetTrackInfo(mozilla::TrackInfo::TrackType aType,
                                                       size_t aTrackNumber) const;
   bool CanSeek() const;
 
   const CryptoFile& Crypto() const;
 
@@ -126,17 +125,16 @@ private:
 };
 
 class MP4MetadataRust
 {
 public:
   explicit MP4MetadataRust(Stream* aSource);
   ~MP4MetadataRust();
 
-  static bool HasCompleteMetadata(Stream* aSource);
   static already_AddRefed<mozilla::MediaByteBuffer> Metadata(Stream* aSource);
   uint32_t GetNumberTracks(mozilla::TrackInfo::TrackType aType) const;
   mozilla::UniquePtr<mozilla::TrackInfo> GetTrackInfo(mozilla::TrackInfo::TrackType aType,
                                                       size_t aTrackNumber) const;
   bool CanSeek() const;
 
   const CryptoFile& Crypto() const;
 
@@ -166,22 +164,16 @@ MP4Metadata::MP4Metadata(Stream* aSource
 #endif
 {
 }
 
 MP4Metadata::~MP4Metadata()
 {
 }
 
-/*static*/ bool
-MP4Metadata::HasCompleteMetadata(Stream* aSource)
-{
-  return MP4MetadataStagefright::HasCompleteMetadata(aSource);
-}
-
 /*static*/ already_AddRefed<mozilla::MediaByteBuffer>
 MP4Metadata::Metadata(Stream* aSource)
 {
   return MP4MetadataStagefright::Metadata(aSource);
 }
 
 static const char *
 TrackTypeToString(mozilla::TrackInfo::TrackType aType)
@@ -608,23 +600,16 @@ MP4MetadataStagefright::GetTrackNumber(m
     int32_t value;
     if (metaData->findInt32(kKeyTrackID, &value) && value == aTrackID) {
       return i;
     }
   }
   return -1;
 }
 
-/*static*/ bool
-MP4MetadataStagefright::HasCompleteMetadata(Stream* aSource)
-{
-  auto parser = mozilla::MakeUnique<MoofParser>(aSource, 0, false);
-  return parser->HasMetadata();
-}
-
 /*static*/ already_AddRefed<mozilla::MediaByteBuffer>
 MP4MetadataStagefright::Metadata(Stream* aSource)
 {
   auto parser = mozilla::MakeUnique<MoofParser>(aSource, 0, false);
   return parser->Metadata();
 }
 
 #ifdef MOZ_RUST_MP4PARSE
@@ -882,23 +867,16 @@ MP4MetadataRust::ReadTrackIndice(mp4pars
   rv = mp4parse_get_indice_table(mRustParser.get(), aTrackID, aIndices);
   if (rv != MP4PARSE_OK) {
     return false;
   }
 
   return true;
 }
 
-/*static*/ bool
-MP4MetadataRust::HasCompleteMetadata(Stream* aSource)
-{
-  MOZ_ASSERT(false, "Not yet implemented");
-  return false;
-}
-
 /*static*/ already_AddRefed<mozilla::MediaByteBuffer>
 MP4MetadataRust::Metadata(Stream* aSource)
 {
   MOZ_ASSERT(false, "Not yet implemented");
   return nullptr;
 }
 #endif
 
--- a/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h
@@ -19,17 +19,16 @@ class MP4MetadataStagefright;
 class MP4MetadataRust;
 
 class MP4Metadata
 {
 public:
   explicit MP4Metadata(Stream* aSource);
   ~MP4Metadata();
 
-  static bool HasCompleteMetadata(Stream* aSource);
   static already_AddRefed<mozilla::MediaByteBuffer> Metadata(Stream* aSource);
   uint32_t GetNumberTracks(mozilla::TrackInfo::TrackType aType) const;
   mozilla::UniquePtr<mozilla::TrackInfo> GetTrackInfo(mozilla::TrackInfo::TrackType aType,
                                                       size_t aTrackNumber) const;
   bool CanSeek() const;
 
   const CryptoFile& Crypto() const;
 
--- a/media/libstagefright/gtest/TestParser.cpp
+++ b/media/libstagefright/gtest/TestParser.cpp
@@ -67,17 +67,16 @@ protected:
   const uint8_t* mBuffer;
   size_t mSize;
 };
 
 TEST(stagefright_MP4Metadata, EmptyStream)
 {
   RefPtr<Stream> stream = new TestStream(nullptr, 0);
 
-  EXPECT_FALSE(MP4Metadata::HasCompleteMetadata(stream));
   RefPtr<MediaByteBuffer> metadataBuffer = MP4Metadata::Metadata(stream);
   EXPECT_FALSE(metadataBuffer);
 
   MP4Metadata metadata(stream);
   EXPECT_EQ(0u, metadata.GetNumberTracks(TrackInfo::kUndefinedTrack));
   EXPECT_EQ(0u, metadata.GetNumberTracks(TrackInfo::kAudioTrack));
   EXPECT_EQ(0u, metadata.GetNumberTracks(TrackInfo::kVideoTrack));
   EXPECT_EQ(0u, metadata.GetNumberTracks(TrackInfo::kTextTrack));
@@ -208,17 +207,16 @@ static const TestFileData testFiles[] = 
 
 TEST(stagefright_MPEG4Metadata, test_case_mp4)
 {
   for (size_t test = 0; test < ArrayLength(testFiles); ++test) {
     nsTArray<uint8_t> buffer = ReadTestFile(testFiles[test].mFilename);
     ASSERT_FALSE(buffer.IsEmpty());
     RefPtr<Stream> stream = new TestStream(buffer.Elements(), buffer.Length());
 
-    EXPECT_TRUE(MP4Metadata::HasCompleteMetadata(stream));
     RefPtr<MediaByteBuffer> metadataBuffer = MP4Metadata::Metadata(stream);
     EXPECT_TRUE(metadataBuffer);
 
     MP4Metadata metadata(stream);
     EXPECT_EQ(0u, metadata.GetNumberTracks(TrackInfo::kUndefinedTrack));
     EXPECT_EQ(testFiles[test].mNumberAudioTracks,
               metadata.GetNumberTracks(TrackInfo::kAudioTrack));
     EXPECT_EQ(testFiles[test].mNumberVideoTracks,
@@ -284,17 +282,16 @@ TEST(stagefright_MPEG4Metadata, test_cas
     // making sure it doesn't crash.
     // No checks because results would differ for each position.
     for (size_t offset = 0; offset < buffer.Length() - step; offset += step) {
       size_t size = buffer.Length() - offset;
       while (size > 0) {
         RefPtr<TestStream> stream =
           new TestStream(buffer.Elements() + offset, size);
 
-        MP4Metadata::HasCompleteMetadata(stream);
         RefPtr<MediaByteBuffer> metadataBuffer = MP4Metadata::Metadata(stream);
         MP4Metadata metadata(stream);
 
         if (stream->mHighestSuccessfulEndOffset <= 0) {
           // No successful reads -> Cutting down the size won't change anything.
           break;
         }
         if (stream->mHighestSuccessfulEndOffset < size) {
@@ -460,17 +457,16 @@ uint8_t media_libstagefright_gtest_video
 const uint32_t media_libstagefright_gtest_video_init_mp4_len = 745;
 
 TEST(stagefright_MP4Metadata, EmptyCTTS)
 {
   RefPtr<MediaByteBuffer> buffer = new MediaByteBuffer(media_libstagefright_gtest_video_init_mp4_len);
   buffer->AppendElements(media_libstagefright_gtest_video_init_mp4, media_libstagefright_gtest_video_init_mp4_len);
   RefPtr<BufferStream> stream = new BufferStream(buffer);
 
-  EXPECT_TRUE(MP4Metadata::HasCompleteMetadata(stream));
   RefPtr<MediaByteBuffer> metadataBuffer = MP4Metadata::Metadata(stream);
   EXPECT_TRUE(metadataBuffer);
 
   MP4Metadata metadata(stream);
 
   EXPECT_EQ(1u, metadata.GetNumberTracks(TrackInfo::kVideoTrack));
   mozilla::UniquePtr<mozilla::TrackInfo> track =
     metadata.GetTrackInfo(TrackInfo::kVideoTrack, 0);
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -3425,20 +3425,16 @@ nsBrowserAccess.prototype = {
 
 
 function Tab(aURL, aParams) {
   this.filter = null;
   this.browser = null;
   this.id = 0;
   this._parentId = -1;
   this.lastTouchedAt = Date.now();
-  this._zoom = 1.0;
-  this._drawZoom = 1.0;
-  this._restoreZoom = false;
-  this.userScrollPos = { x: 0, y: 0 };
   this.contentDocumentIsDisplayed = true;
   this.pluginDoorhangerTimeout = null;
   this.shouldShowPluginDoorhanger = true;
   this.clickToPlayPluginsActivated = false;
   this.desktopMode = false;
   this.originalURI = null;
   this.hasTouchListener = false;
   this.playingAudio = false;
@@ -4504,68 +4500,37 @@ Tab.prototype = {
     // notifications using nsBrowserStatusFilter.
   },
 
   onStatusChange: function(aBrowser, aWebProgress, aRequest, aStatus, aMessage) {
     // Note: aWebProgess and aRequest will be NULL since we are filtering webprogress
     // notifications using nsBrowserStatusFilter.
   },
 
-  _getGeckoZoom: function() {
-    let res = {};
-    let cwu = this.browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
-    cwu.getResolution(res);
-    let zoom = res.value * window.devicePixelRatio;
-    return zoom;
-  },
-
-  saveSessionZoom: function(aZoom) {
-    let cwu = this.browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
-    cwu.setResolutionAndScaleTo(aZoom / window.devicePixelRatio);
-  },
-
-  restoredSessionZoom: function() {
-    let cwu = this.browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
-
-    if (this._restoreZoom && cwu.isResolutionSet) {
-      return this._getGeckoZoom();
-    }
-    return null;
-  },
-
-  _updateZoomFromHistoryEvent: function(aHistoryEventName) {
-    // Restore zoom only when moving in session history, not for new page loads.
-    this._restoreZoom = aHistoryEventName !== "New";
-  },
-
   OnHistoryNewEntry: function(newURI, oldIndex) {
     Services.obs.notifyObservers(this.browser, "Content:HistoryChange", null);
-    this._updateZoomFromHistoryEvent("New");
   },
 
   OnHistoryGoBack: function(backURI) {
     Services.obs.notifyObservers(this.browser, "Content:HistoryChange", null);
-    this._updateZoomFromHistoryEvent("Back");
     return true;
   },
 
   OnHistoryGoForward: function(forwardURI) {
     Services.obs.notifyObservers(this.browser, "Content:HistoryChange", null);
-    this._updateZoomFromHistoryEvent("Forward");
     return true;
   },
 
   OnHistoryReload: function(reloadURI, reloadFlags) {
     Services.obs.notifyObservers(this.browser, "Content:HistoryChange", null);
     return true;
   },
 
   OnHistoryGotoIndex: function(index, gotoURI) {
     Services.obs.notifyObservers(this.browser, "Content:HistoryChange", null);
-    this._updateZoomFromHistoryEvent("Goto");
     return true;
   },
 
   OnHistoryPurge: function(numEntries) {
     Services.obs.notifyObservers(this.browser, "Content:HistoryChange", null);
     return true;
   },
 
@@ -4651,20 +4616,16 @@ Tab.prototype = {
 
   // nsIBrowserTab
   get window() {
     if (!this.browser)
       return null;
     return this.browser.contentWindow;
   },
 
-  get scale() {
-    return this._zoom;
-  },
-
   QueryInterface: XPCOMUtils.generateQI([
     Ci.nsIWebProgressListener,
     Ci.nsISHistoryListener,
     Ci.nsIObserver,
     Ci.nsISupportsWeakReference,
     Ci.nsIBrowserTab
   ])
 };
--- a/services/sync/tests/unit/test_bookmark_duping.js
+++ b/services/sync/tests/unit/test_bookmark_duping.js
@@ -153,17 +153,17 @@ add_task(async function test_dupe_bookma
       id: newGUID,
       bmkUri: "http://getfirefox.com/",
       type: "bookmark",
       title: "Get Firefox!",
       parentName: "Folder 1",
       parentid: folder1_guid,
     };
 
-    collection.insert(newGUID, encryptPayload(to_apply), Date.now() / 1000 + 10);
+    collection.insert(newGUID, encryptPayload(to_apply), Date.now() / 1000 + 500);
     _("Syncing so new dupe record is processed");
     engine.lastSync = engine.lastSync - 0.01;
     engine.sync();
 
     // We should have logically deleted the dupe record.
     equal(collection.count(), 7);
     ok(getServerRecord(collection, bmk1_guid).deleted);
     // and physically removed from the local store.
@@ -210,17 +210,17 @@ add_task(async function test_dupe_repare
       id: newGUID,
       bmkUri: "http://getfirefox.com/",
       type: "bookmark",
       title: "Get Firefox!",
       parentName: "Folder 1",
       parentid: folder2_guid,
     };
 
-    collection.insert(newGUID, encryptPayload(to_apply), Date.now() / 1000 + 10);
+    collection.insert(newGUID, encryptPayload(to_apply), Date.now() / 1000 + 500);
 
     _("Syncing so new dupe record is processed");
     engine.lastSync = engine.lastSync - 0.01;
     engine.sync();
 
     // We should have logically deleted the dupe record.
     equal(collection.count(), 8);
     ok(getServerRecord(collection, bmk1_guid).deleted);
@@ -276,26 +276,27 @@ add_task(async function test_dupe_repare
       id: newGUID,
       bmkUri: "http://getfirefox.com/",
       type: "bookmark",
       title: "Get Firefox!",
       parentName: "Folder 1",
       parentid: folder2_guid,
     };
 
-    collection.insert(newGUID, encryptPayload(to_apply), Date.now() / 1000 + 10);
+    let deltaSeconds = 500;
+    collection.insert(newGUID, encryptPayload(to_apply), Date.now() / 1000 + deltaSeconds);
 
     // Make a change to the bookmark that's a dupe, and set the modification
     // time further in the future than the incoming record. This will cause
     // us to issue the infamous "DATA LOSS" warning in the logs but cause us
     // to *not* apply the incoming record.
     await PlacesTestUtils.setBookmarkSyncFields({
       guid: bmk1_guid,
       syncChangeCounter: 1,
-      lastModified: Date.now() + 60000,
+      lastModified: Date.now() + (deltaSeconds + 10) * 1000,
     });
 
     _("Syncing so new dupe record is processed");
     engine.lastSync = engine.lastSync - 0.01;
     engine.sync();
 
     // We should have logically deleted the dupe record.
     equal(collection.count(), 8);
@@ -352,41 +353,41 @@ add_task(async function test_dupe_repare
     collection.insert(newParentGUID, encryptPayload({
       id: newParentGUID,
       type: "folder",
       title: "Folder 1",
       parentName: "A second folder",
       parentid: folder2_guid,
       children: [newGUID],
       tags: [],
-    }), Date.now() / 1000 + 10);
+    }), Date.now() / 1000 + 500);
 
     // And also the update to "folder 2" that references the new parent.
     collection.insert(folder2_guid, encryptPayload({
       id: folder2_guid,
       type: "folder",
       title: "A second folder",
       parentName: "Bookmarks Toolbar",
       parentid: "toolbar",
       children: [newParentGUID],
       tags: [],
-    }), Date.now() / 1000 + 10);
+    }), Date.now() / 1000 + 500);
 
     // Now create a new incoming record that looks alot like a dupe of the
     // item in folder1_guid, with a record that points to a parent with the
     // same name which appeared earlier in this sync.
     collection.insert(newGUID, encryptPayload({
       id: newGUID,
       bmkUri: "http://getfirefox.com/",
       type: "bookmark",
       title: "Get Firefox!",
       parentName: "Folder 1",
       parentid: newParentGUID,
       tags: [],
-    }), Date.now() / 1000 + 10);
+    }), Date.now() / 1000 + 500);
 
 
     _("Syncing so new records are processed.");
     engine.lastSync = engine.lastSync - 0.01;
     engine.sync();
 
     // Everything should be parented correctly.
     equal((await getFolderChildrenIDs(folder1_id)).length, 0);
@@ -431,39 +432,39 @@ add_task(async function test_dupe_repare
     collection.insert(newGUID, encryptPayload({
       id: newGUID,
       bmkUri: "http://getfirefox.com/",
       type: "bookmark",
       title: "Get Firefox!",
       parentName: "Folder 1",
       parentid: newParentGUID,
       tags: [],
-    }), Date.now() / 1000 + 10);
+    }), Date.now() / 1000 + 500);
 
     // Now have the parent appear after (so when the record above is processed
     // this is still unknown.)
     collection.insert(newParentGUID, encryptPayload({
       id: newParentGUID,
       type: "folder",
       title: "Folder 1",
       parentName: "A second folder",
       parentid: folder2_guid,
       children: [newGUID],
       tags: [],
-    }), Date.now() / 1000 + 10);
+    }), Date.now() / 1000 + 500);
     // And also the update to "folder 2" that references the new parent.
     collection.insert(folder2_guid, encryptPayload({
       id: folder2_guid,
       type: "folder",
       title: "A second folder",
       parentName: "Bookmarks Toolbar",
       parentid: "toolbar",
       children: [newParentGUID],
       tags: [],
-    }), Date.now() / 1000 + 10);
+    }), Date.now() / 1000 + 500);
 
     _("Syncing so out-of-order records are processed.");
     engine.lastSync = engine.lastSync - 0.01;
     engine.sync();
 
     // The intended parent did end up existing, so it should be parented
     // correctly after de-duplication.
     equal((await getFolderChildrenIDs(folder1_id)).length, 0);
@@ -508,17 +509,17 @@ add_task(async function test_dupe_repare
     collection.insert(newGUID, encryptPayload({
       id: newGUID,
       bmkUri: "http://getfirefox.com/",
       type: "bookmark",
       title: "Get Firefox!",
       parentName: "Folder 1",
       parentid: newParentGUID,
       tags: [],
-    }), Date.now() / 1000 + 10);
+    }), Date.now() / 1000 + 500);
 
     _("Syncing so new dupe record is processed");
     engine.lastSync = engine.lastSync - 0.01;
     engine.sync();
 
     // We should have logically deleted the dupe record.
     equal(collection.count(), 8);
     ok(getServerRecord(collection, bmk1_guid).deleted);
@@ -551,27 +552,27 @@ add_task(async function test_dupe_repare
     collection.insert(newParentGUID, encryptPayload({
       id: newParentGUID,
       type: "folder",
       title: "Folder 1",
       parentName: "A second folder",
       parentid: folder2_guid,
       children: [newGUID],
       tags: [],
-    }), Date.now() / 1000 + 10);
+    }), Date.now() / 1000 + 500);
     // We also queue an update to "folder 2" that references the new parent.
     collection.insert(folder2_guid, encryptPayload({
       id: folder2_guid,
       type: "folder",
       title: "A second folder",
       parentName: "Bookmarks Toolbar",
       parentid: "toolbar",
       children: [newParentGUID],
       tags: [],
-    }), Date.now() / 1000 + 10);
+    }), Date.now() / 1000 + 500);
 
     _("Syncing so missing parent appears");
     engine.lastSync = engine.lastSync - 0.01;
     engine.sync();
 
     // The intended parent now does exist, so it should have been reparented.
     equal((await getFolderChildrenIDs(folder1_id)).length, 0);
     let newParentID = store.idForGUID(newParentGUID);
@@ -617,17 +618,17 @@ add_task(async function test_dupe_empty_
     let newFolderGUID = Utils.makeGUID();
     collection.insert(newFolderGUID, encryptPayload({
       id: newFolderGUID,
       type: "folder",
       title: "Folder 1",
       parentName: "Bookmarks Toolbar",
       parentid: "toolbar",
       children: [],
-    }), Date.now() / 1000 + 10);
+    }), Date.now() / 1000 + 500);
 
     _("Syncing so new dupe records are processed");
     engine.lastSync = engine.lastSync - 0.01;
     engine.sync();
 
     await validate(collection);
 
     // Collection now has one additional record - the logically deleted dupe.
--- a/servo/Cargo.lock
+++ b/servo/Cargo.lock
@@ -270,39 +270,39 @@ version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "canvas"
 version = "0.0.1"
 dependencies = [
  "azure 0.14.0 (git+https://github.com/servo/rust-azure)",
  "canvas_traits 0.0.1",
- "cssparser 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
  "offscreen_gl_context 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_config 0.0.1",
- "webrender_traits 0.20.0 (git+https://github.com/servo/webrender)",
+ "webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "canvas_traits"
 version = "0.0.1"
 dependencies = [
- "cssparser 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "webrender_traits 0.20.0 (git+https://github.com/servo/webrender)",
+ "webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "caseless"
 version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -413,18 +413,18 @@ dependencies = [
  "net_traits 0.0.1",
  "profile_traits 0.0.1",
  "script_traits 0.0.1",
  "servo_config 0.0.1",
  "servo_geometry 0.0.1",
  "servo_url 0.0.1",
  "style_traits 0.0.1",
  "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
- "webrender 0.19.0 (git+https://github.com/servo/webrender)",
- "webrender_traits 0.20.0 (git+https://github.com/servo/webrender)",
+ "webrender 0.21.0 (git+https://github.com/servo/webrender)",
+ "webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "constellation"
 version = "0.0.1"
 dependencies = [
  "backtrace 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bluetooth_traits 0.0.1",
@@ -447,17 +447,17 @@ dependencies = [
  "script_traits 0.0.1",
  "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_config 0.0.1",
  "servo_rand 0.0.1",
  "servo_remutex 0.0.1",
  "servo_url 0.0.1",
  "style_traits 0.0.1",
- "webrender_traits 0.20.0 (git+https://github.com/servo/webrender)",
+ "webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
  "webvr_traits 0.0.1",
 ]
 
 [[package]]
 name = "content-blocker"
 version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
@@ -511,36 +511,38 @@ source = "registry+https://github.com/ru
 dependencies = [
  "core-foundation 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "cssparser"
-version = "0.11.0"
+version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cssparser-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser-macros 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "procedural-masquerade 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.11.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "cssparser-macros"
-version = "0.1.0"
+version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.11.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "procedural-masquerade 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "dbghelp-sys"
 version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -580,17 +582,17 @@ dependencies = [
  "adler32 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "deny_public_fields"
 version = "0.0.1"
 dependencies = [
- "syn 0.11.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "synstructure 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "deque"
 version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
@@ -640,25 +642,25 @@ dependencies = [
  "servo_url 0.0.1",
  "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "dom_struct"
 version = "0.0.1"
 dependencies = [
- "quote 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "domobject_derive"
 version = "0.0.1"
 dependencies = [
- "quote 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.11.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "dtoa"
 version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -666,16 +668,30 @@ name = "dwmapi-sys"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "dwrote"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "embedding"
 version = "0.0.1"
 dependencies = [
  "cocoa 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "compositing 0.0.1",
  "devtools 0.0.1",
  "euclid 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -686,17 +702,17 @@ dependencies = [
  "msg 0.0.1",
  "net_traits 0.0.1",
  "objc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "script_traits 0.0.1",
  "servo_config 0.0.1",
  "servo_geometry 0.0.1",
  "servo_url 0.0.1",
  "style_traits 0.0.1",
- "webrender_traits 0.20.0 (git+https://github.com/servo/webrender)",
+ "webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
  "x11 2.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "encoding"
 version = "0.2.33"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
@@ -912,17 +928,17 @@ dependencies = [
 ]
 
 [[package]]
 name = "geckoservo"
 version = "0.0.1"
 dependencies = [
  "app_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cssparser 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -943,16 +959,17 @@ name = "gfx"
 version = "0.0.1"
 dependencies = [
  "app_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-text 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dwrote 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "fontsan 0.3.2 (git+https://github.com/servo/fontsan)",
  "freetype 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gfx_traits 0.0.1",
  "harfbuzz-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -961,29 +978,28 @@ dependencies = [
  "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "range 0.0.1",
  "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "servo-dwrote 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-fontconfig 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_atoms 0.0.1",
  "servo_geometry 0.0.1",
  "servo_url 0.0.1",
  "simd 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "style 0.0.1",
  "style_traits 0.0.1",
  "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
  "truetype 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-script 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "webrender_traits 0.20.0 (git+https://github.com/servo/webrender)",
+ "webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
  "xi-unicode 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "gfx_tests"
 version = "0.0.1"
 dependencies = [
  "gfx 0.0.1",
@@ -1052,17 +1068,17 @@ dependencies = [
  "script_traits 0.0.1",
  "servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo-glutin 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_config 0.0.1",
  "servo_geometry 0.0.1",
  "servo_url 0.0.1",
  "style_traits 0.0.1",
  "user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "webrender_traits 0.20.0 (git+https://github.com/servo/webrender)",
+ "webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "x11 2.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "glx"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1090,18 +1106,18 @@ dependencies = [
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "heapsize_derive"
 version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "quote 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.11.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "synstructure 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "heartbeats-simple"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
@@ -1134,19 +1150,19 @@ source = "registry+https://github.com/ru
 dependencies = [
  "heapsize 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "html5ever-atoms 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
  "phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.11.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "tendril 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "html5ever-atoms"
 version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
@@ -1291,18 +1307,18 @@ dependencies = [
  "mozjs_sys 0.0.0 (git+https://github.com/servo/mozjs)",
  "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "jstraceable_derive"
 version = "0.0.1"
 dependencies = [
- "quote 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.11.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "synstructure 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "kernel32-sys"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
@@ -1323,17 +1339,17 @@ source = "registry+https://github.com/ru
 [[package]]
 name = "layout"
 version = "0.0.1"
 dependencies = [
  "app_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "canvas_traits 0.0.1",
- "cssparser 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "gfx 0.0.1",
  "gfx_traits 0.0.1",
  "heapsize 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "html5ever-atoms 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1354,17 +1370,17 @@ dependencies = [
  "servo_config 0.0.1",
  "servo_geometry 0.0.1",
  "servo_url 0.0.1",
  "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "style 0.0.1",
  "style_traits 0.0.1",
  "unicode-bidi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-script 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "webrender_traits 0.20.0 (git+https://github.com/servo/webrender)",
+ "webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "layout_tests"
 version = "0.0.1"
 dependencies = [
  "layout 0.0.1",
 ]
@@ -1394,31 +1410,31 @@ dependencies = [
  "script_traits 0.0.1",
  "selectors 0.18.0",
  "serde_derive 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_config 0.0.1",
  "servo_geometry 0.0.1",
  "servo_url 0.0.1",
  "style 0.0.1",
- "webrender_traits 0.20.0 (git+https://github.com/servo/webrender)",
+ "webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "layout_traits"
 version = "0.0.1"
 dependencies = [
  "gfx 0.0.1",
  "ipc-channel 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "net_traits 0.0.1",
  "profile_traits 0.0.1",
  "script_traits 0.0.1",
  "servo_url 0.0.1",
- "webrender_traits 0.20.0 (git+https://github.com/servo/webrender)",
+ "webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "lazy_static"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -1493,18 +1509,18 @@ dependencies = [
  "script_layout_interface 0.0.1",
  "script_traits 0.0.1",
  "servo_config 0.0.1",
  "servo_geometry 0.0.1",
  "servo_url 0.0.1",
  "style 0.0.1",
  "style_traits 0.0.1",
  "webdriver_server 0.0.1",
- "webrender 0.19.0 (git+https://github.com/servo/webrender)",
- "webrender_traits 0.20.0 (git+https://github.com/servo/webrender)",
+ "webrender 0.21.0 (git+https://github.com/servo/webrender)",
+ "webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
  "webvr 0.0.1",
  "webvr_traits 0.0.1",
 ]
 
 [[package]]
 name = "libz-sys"
 version = "1.0.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1636,22 +1652,22 @@ dependencies = [
  "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "msg"
 version = "0.0.1"
 dependencies = [
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cssparser 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "webrender_traits 0.20.0 (git+https://github.com/servo/webrender)",
+ "webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "net"
 version = "0.0.1"
 dependencies = [
  "brotli 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "content-blocker 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1679,17 +1695,17 @@ dependencies = [
  "servo_config 0.0.1",
  "servo_url 0.0.1",
  "threadpool 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
  "tinyfiledialogs 2.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "uuid 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "webrender_traits 0.20.0 (git+https://github.com/servo/webrender)",
+ "webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
  "websocket 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "net2"
 version = "0.2.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
@@ -1738,17 +1754,17 @@ dependencies = [
  "msg 0.0.1",
  "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_config 0.0.1",
  "servo_url 0.0.1",
  "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "uuid 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "webrender_traits 0.20.0 (git+https://github.com/servo/webrender)",
+ "webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
  "websocket 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "net_traits_tests"
 version = "0.0.1"
 dependencies = [
  "net_traits 0.0.1",
@@ -2028,16 +2044,21 @@ source = "registry+https://github.com/ru
 dependencies = [
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "deflate 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "inflate 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "procedural-masquerade"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "profile"
 version = "0.0.1"
 dependencies = [
  "heartbeats-simple 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "profile_traits 0.0.1",
@@ -2091,17 +2112,17 @@ dependencies = [
  "aster 0.38.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "syntex 0.54.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "syntex_errors 0.54.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "syntex_syntax 0.54.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "quote"
-version = "0.3.13"
+version = "0.3.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "rand"
 version = "0.3.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2215,18 +2236,17 @@ dependencies = [
  "audio-video-metadata 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bluetooth_traits 0.0.1",
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "canvas_traits 0.0.1",
  "caseless 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "cmake 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
  "cookie 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "cssparser 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cssparser-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "deny_public_fields 0.0.1",
  "devtools_traits 0.0.1",
  "dom_struct 0.0.1",
  "domobject_derive 0.0.1",
  "encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "gfx_traits 0.0.1",
@@ -2272,31 +2292,31 @@ dependencies = [
  "servo_url 0.0.1",
  "smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "style 0.0.1",
  "style_traits 0.0.1",
  "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
  "tinyfiledialogs 2.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "uuid 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "webrender_traits 0.20.0 (git+https://github.com/servo/webrender)",
+ "webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
  "websocket 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "webvr 0.0.1",
  "webvr_traits 0.0.1",
  "xml5ever 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "script_layout_interface"
 version = "0.0.1"
 dependencies = [
  "app_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "canvas_traits 0.0.1",
- "cssparser 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gfx_traits 0.0.1",
  "heapsize 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "html5ever-atoms 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2355,68 +2375,47 @@ dependencies = [
  "webvr_traits 0.0.1",
 ]
 
 [[package]]
 name = "selectors"
 version = "0.18.0"
 dependencies = [
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cssparser 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cssparser-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "semver"
 version = "0.1.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "serde"
 version = "0.9.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
-name = "serde_codegen"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "quote 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_codegen_internals 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.10.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "syntex 0.54.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "syntex_syntax 0.54.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "serde_codegen_internals"
-version = "0.11.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "syn 0.10.8 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
 name = "serde_codegen_internals"
 version = "0.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "syn 0.11.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "serde_derive"
 version = "0.9.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "quote 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_codegen_internals 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.11.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "serde_json"
 version = "0.9.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2445,30 +2444,16 @@ dependencies = [
  "script_tests 0.0.1",
  "servo_config_tests 0.0.1",
  "servo_remutex_tests 0.0.1",
  "sig 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "style_tests 0.0.1",
 ]
 
 [[package]]
-name = "servo-dwrote"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_codegen 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
 name = "servo-egl"
 version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -2725,18 +2710,17 @@ source = "registry+https://github.com/ru
 name = "style"
 version = "0.0.1"
 dependencies = [
  "app_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bindgen 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cssparser 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cssparser-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "html5ever-atoms 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2744,17 +2728,16 @@ dependencies = [
  "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "nsstring_vendor 0.1.0",
  "num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
  "ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "owning_ref 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "pdqsort 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "selectors 0.18.0",
  "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "servo_atoms 0.0.1",
  "servo_config 0.0.1",
  "servo_url 0.0.1",
@@ -2765,20 +2748,19 @@ dependencies = [
  "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "style_tests"
 version = "0.0.1"
 dependencies = [
  "app_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cssparser 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "html5ever-atoms 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "owning_ref 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
  "selectors 0.18.0",
  "servo_atoms 0.0.1",
  "servo_config 0.0.1",
  "servo_url 0.0.1",
@@ -2786,32 +2768,31 @@ dependencies = [
  "style_traits 0.0.1",
 ]
 
 [[package]]
 name = "style_traits"
 version = "0.0.1"
 dependencies = [
  "app_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cssparser 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cssparser-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "stylo_tests"
 version = "0.0.1"
 dependencies = [
  "app_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cssparser 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "geckoservo 0.0.1",
  "lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2819,29 +2800,20 @@ dependencies = [
  "selectors 0.18.0",
  "servo_url 0.0.1",
  "style 0.0.1",
  "style_traits 0.0.1",
 ]
 
 [[package]]
 name = "syn"
-version = "0.10.8"
+version = "0.11.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "quote 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "syn"
-version = "0.11.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "quote 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "synom 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "synom"
 version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2849,18 +2821,18 @@ dependencies = [
  "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "synstructure"
 version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "quote 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.11.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "syntex"
 version = "0.54.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "syntex_errors 0.54.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3182,58 +3154,58 @@ dependencies = [
  "servo_url 0.0.1",
  "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "uuid 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "webdriver 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "webrender"
-version = "0.19.0"
-source = "git+https://github.com/servo/webrender#fc720d070f4af24a1def4a6510cee10aaad0a280"
+version = "0.21.0"
+source = "git+https://github.com/servo/webrender#9565e58d2636108415009ba76690a5dff9019c52"
 dependencies = [
  "app_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bincode 1.0.0-alpha2 (registry+https://github.com/rust-lang/crates.io-index)",
  "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-text 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dwrote 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "freetype 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gamma-lut 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
  "offscreen_gl_context 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "servo-dwrote 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "threadpool 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
- "webrender_traits 0.20.0 (git+https://github.com/servo/webrender)",
+ "webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
 ]
 
 [[package]]
 name = "webrender_traits"
-version = "0.20.0"
-source = "git+https://github.com/servo/webrender#fc720d070f4af24a1def4a6510cee10aaad0a280"
+version = "0.22.0"
+source = "git+https://github.com/servo/webrender#9565e58d2636108415009ba76690a5dff9019c52"
 dependencies = [
  "app_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dwrote 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "offscreen_gl_context 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "servo-dwrote 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "websocket"
 version = "0.17.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3251,17 +3223,17 @@ dependencies = [
 name = "webvr"
 version = "0.0.1"
 dependencies = [
  "ipc-channel 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msg 0.0.1",
  "script_traits 0.0.1",
  "servo_config 0.0.1",
- "webrender_traits 0.20.0 (git+https://github.com/servo/webrender)",
+ "webrender_traits 0.22.0 (git+https://github.com/servo/webrender)",
  "webvr_traits 0.0.1",
 ]
 
 [[package]]
 name = "winapi"
 version = "0.2.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
@@ -3387,26 +3359,27 @@ dependencies = [
 "checksum color_quant 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a475fc4af42d83d28adf72968d9bcfaf035a1a9381642d8e85d8a04957767b0d"
 "checksum compiletest_rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f3f344389765ad7bec166f64c1b39ed6dd2b54d81c4c5dd8af789169351d380c"
 "checksum content-blocker 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "44dfb2f06e219a5bdec05c5811dde4d893c34c49ffed384c9d0a2e9caca9c154"
 "checksum cookie 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0e3d6405328b6edb412158b3b7710e2634e23f3614b9bb1c412df7952489a626"
 "checksum core-foundation 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f51ce3b8ebe311c56de14231eb57572c15abebd2d32b3bcb99bcdb9c101f5ac3"
 "checksum core-foundation-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "41115a6aa5d3e1e5ef98148373f25971d1fad53818553f216495f9e67e90a624"
 "checksum core-graphics 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ead017dcf77f503dc991f6b52de6084eeea60a94b0a652baa9bf88654a28e83f"
 "checksum core-text 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0e9719616a10f717628e074744f8c55df7b450f7a34d29c196d14f4498aad05d"
-"checksum cssparser 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d8352ccd22c5ebab558d179e32f6d3dd26eed30252f8420d636bfae5052eb50e"
-"checksum cssparser-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a85e1452f40a50777c8424fa7fcaa7dd7074c7bc5419014fbffe7ea3d750dee8"
+"checksum cssparser 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "112b0e846ce6b441564c908a2e74d98a2c6f2cbe838b0f32d037d5bfb9e982ca"
+"checksum cssparser-macros 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f0415de0bdbce823c0db204e00a62c8240fa2d3e04cd13ff7c6396e4446b95"
 "checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850"
 "checksum dbus 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "94d266a872aaf68b50d02083c429a3686935ab6ab54824290509cdc422673eaf"
 "checksum debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9a032eac705ca39214d169f83e3d3da290af06d8d1d344d1baad2fd002dca4b3"
 "checksum deflate 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "24c5f3de3a8e183ab9a169654b652407e5e80bed40986bcca92c2b088b9bfa80"
 "checksum deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1614659040e711785ed8ea24219140654da1729f3ec8a47a9719d041112fe7bf"
 "checksum device 0.0.1 (git+https://github.com/servo/devices)" = "<none>"
 "checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90"
 "checksum dwmapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07c4c7cc7b396419bc0a4d90371d0cee16cb5053b53647d287c0b728000c41fe"
+"checksum dwrote 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74114b6b49d6731835da7a28a3642651451e315f7f9b9d04e907e65a45681796"
 "checksum encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec"
 "checksum encoding-index-japanese 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91"
 "checksum encoding-index-korean 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81"
 "checksum encoding-index-simpchinese 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d87a7194909b9118fc707194baa434a4e3b0fb6a5a757c73c3adb07aa25031f7"
 "checksum encoding-index-singlebyte 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a"
 "checksum encoding-index-tradchinese 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18"
 "checksum encoding_index_tests 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569"
 "checksum energy-monitor 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fe872d0664f1cc60db36349af245d892ee67d3c8f78055df0ebc43271fd4e05c"
@@ -3507,40 +3480,38 @@ dependencies = [
 "checksum pdqsort 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ceca1642c89148ca05611cc775a0c383abef355fc4907c4e95f49f7b09d6287c"
 "checksum phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "cb325642290f28ee14d8c6201159949a872f220c62af6e110a56ea914fbe42fc"
 "checksum phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d62594c0bb54c464f633175d502038177e90309daf2e0158be42ed5f023ce88f"
 "checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03"
 "checksum phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "07e24b0ca9643bdecd0632f2b3da6b1b89bbb0030e0b992afc1113b23a7bc2f2"
 "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
 "checksum pnacl-build-helper 1.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "61c9231d31aea845007443d62fcbb58bb6949ab9c18081ee1e09920e0cf1118b"
 "checksum png 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3cb773e9a557edb568ce9935cf783e3cdcabe06a9449d41b3e5506d88e582c82"
+"checksum procedural-masquerade 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f566249236c6ca4340f7ca78968271f0ed2b0f234007a61b66f9ecd0af09260"
 "checksum quasi 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dcbf815446dc6a0afbc72d88f9a8aa71b608d10b168e09437c80c0fd6fd410c9"
 "checksum quasi_codegen 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b06172e92ab0099427609854ffb1512c377be5fc4beaf572ae5d5a01b8359596"
-"checksum quote 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "08de3f12e670f83f61e450443cbae34496a35b665691fd8e99b24ec662f75865"
+"checksum quote 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7375cf7ad34a92e8fd18dd9c42f58b9a11def59ab48bec955bf359a788335592"
 "checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d"
 "checksum rayon 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50c575b58c2b109e2fbc181820cbe177474f35610ff9e357dc75f6bac854ffbf"
 "checksum redox_syscall 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd35cc9a8bdec562c757e3d43c1526b5c6d2653e23e2315065bc25556550753"
 "checksum ref_filter_map 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2b5ceb840e4009da4841ed22a15eb49f64fdd00a2138945c5beacf506b2fb5ed"
 "checksum ref_slice 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "825740057197b7d43025e7faf6477eaabc03434e153233da02d1f44602f71527"
 "checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01"
 "checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457"
 "checksum rust-webvr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ae0560bf176cd49f08d3df2784f9bfe74df6f6346b71b98ca3358160316e271"
 "checksum rustc-demangle 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1430d286cadb237c17c885e25447c982c97113926bb579f4379c0eca8d9586dc"
 "checksum rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "237546c689f20bb44980270c73c3b9edd0891c1be49cc1274406134a66d3957b"
 "checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084"
 "checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7"
 "checksum scoped_threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3ef399c8893e8cb7aa9696e895427fab3a6bf265977bb96e126f24ddd2cda85a"
 "checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac"
 "checksum serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1e0ed773960f90a78567fcfbe935284adf50c5d7cf119aa2cf43bb0b4afa69bb"
-"checksum serde_codegen 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f94de585a73dfc312ca77194209278a587bf90d3edc6c2d0fc479b0ed71d1f0"
-"checksum serde_codegen_internals 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "afad7924a009f859f380e4a2e3a509a845c2ac66435fcead74a4d983b21ae806"
 "checksum serde_codegen_internals 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c3172bf2940b975c0e4f6ab42a511c0a4407d4f46ccef87a9d3615db5c26fa96"
 "checksum serde_derive 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6af30425c5161deb200aac4803c62b903eb3be7e889c5823d0e16c4ce0ce989c"
 "checksum serde_json 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb96d30e4e6f9fc52e08f51176d078b6f79b981dc3ed4134f7b850be9f446a8"
-"checksum servo-dwrote 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f013da79c3fb2a9653534b064cd2ca62e10f8b6d19ed8fdc885cb2873412789"
 "checksum servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "21069a884c33fe6ee596975e1f3849ed88c4ec857fbaf11d33672d8ebe051217"
 "checksum servo-fontconfig 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "93f799b649b4a2bf362398910eca35240704c7e765e780349b2bb1070d892262"
 "checksum servo-fontconfig-sys 4.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a0af4a4d7746467921486e5c5420f815cc016a6bf5574210d8e9c00f4afae224"
 "checksum servo-freetype-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9232032c2e85118c0282c6562c84cab12316e655491ba0a5d1905b2320060d1b"
 "checksum servo-glutin 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b682e1eef598db6048b64face7ea79fd55fe70d171cb92d2a44a89db7bdf34"
 "checksum servo-skia 0.30000003.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e7107296909e71f69a7e8b95becf3efe3e1838e556430b3efc9dc91aea65ddf2"
 "checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c"
 "checksum shared_library 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fb04126b6fcfd2710fb5b6d18f4207b6c535f2850a7e1a43bcd526d44f30a79a"
@@ -3551,18 +3522,17 @@ dependencies = [
 "checksum siphasher 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ffc669b726f2bc9a3bcff66e5e23b56ba6bf70e22a34c3d7b6d0b3450b65b84"
 "checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23"
 "checksum smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "fcc8d19212aacecf95e4a7a2179b26f7aeb9732a915cf01f05b0d3e044865410"
 "checksum solicit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "172382bac9424588d7840732b250faeeef88942e37b6e35317dce98cafdd75b2"
 "checksum string_cache 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c19dbe4d2552673a8c4ec0e91523670ee2b73ba3560d935703ce5d64a40f864c"
 "checksum string_cache_codegen 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0c9dfe1a7c8bba1ecb90730d269fdc08afe93d23c28dd6c4aa5cabd79a05a05e"
 "checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc"
 "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
-"checksum syn 0.10.8 (registry+https://github.com/rust-lang/crates.io-index)" = "58fd09df59565db3399efbba34ba8a2fec1307511ebd245d0061ff9d42691673"
-"checksum syn 0.11.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0e28da8d02d75d1e58b89258e0741128f0b0d8a8309fb5c627be0fbd37a76c67"
+"checksum syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)" = "37c279fb816210c9bb28b2c292664581e7b87b4561e86b94df462664d8620bb8"
 "checksum synom 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8fece1853fb872b0acdc3ff88f37c474018e125ef81cd4cb8c0ca515746b62ed"
 "checksum synstructure 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ccc9780bf1aa601943988c2876ab22413c01ad1739689aa6af18d0aa0b3f38b"
 "checksum syntex 0.54.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb3f52553a966675982404dc34028291b347e0c9a9c0b0b34f2da6be8a0443f8"
 "checksum syntex_errors 0.54.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dee2f6e49c075f71332bb775219d5982bee6732d26227fa1ae1b53cdb12f5cc5"
 "checksum syntex_pos 0.54.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8df3921c7945dfb9ffc53aa35adb2cf4313b5ab5f079c3619b3d4eb82a0efc2b"
 "checksum syntex_syntax 0.54.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dc960085bae44591e22d01f6c0e82a8aec832f8659aca556cdf8ecbdac2bb47b"
 "checksum target_build_utils 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f42dc058080c19c6a58bdd1bf962904ee4f5ef1fe2a81b529f31dacc750c679f"
 "checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6"
@@ -3592,18 +3562,18 @@ dependencies = [
 "checksum user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ef4711d107b21b410a3a974b1204d9accc8b10dad75d8324b5d755de1617d47"
 "checksum utf-8 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9aee9ba280438b56d1ebc5329f2094f0ff457f811eeeff0b278d75aa99db400"
 "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
 "checksum uuid 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7cfec50b0842181ba6e713151b72f4ec84a6a7e2c9c8a8a3ffc37bb1cd16b231"
 "checksum vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cac5efe5cb0fa14ec2f84f83c701c562ee63f6dcc680861b21d65c682adfb05f"
 "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
 "checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff"
 "checksum webdriver 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cdc28802daddee94267a657ffeac2593a33881fb7a3a44fedd320b1319efcaf6"
-"checksum webrender 0.19.0 (git+https://github.com/servo/webrender)" = "<none>"
-"checksum webrender_traits 0.20.0 (git+https://github.com/servo/webrender)" = "<none>"
+"checksum webrender 0.21.0 (git+https://github.com/servo/webrender)" = "<none>"
+"checksum webrender_traits 0.22.0 (git+https://github.com/servo/webrender)" = "<none>"
 "checksum websocket 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a1a6ea5ed0367f32eb3d94dcc58859ef4294b5f75ba983dbf56ac314af45d"
 "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
 "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
 "checksum ws 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "04614a58714f3fd4a8b1da4bcae9f031c532d35988c3d39627619248113f8be8"
 "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
 "checksum x11 2.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "124eb405bf0262a54e1a982d4ffe4cd1c24261bdb306e49996e2ce7d492284a8"
 "checksum x11-dl 2.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bf1f9986368c9bbdd8191a783a7ceb42e0c9c6d3348616c873f829b3288a139c"
 "checksum xdg 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77b831a5ba77110f438f0ac5583aafeb087f70432998ba6b7dcb1d32185db453"
--- a/servo/components/canvas/Cargo.toml
+++ b/servo/components/canvas/Cargo.toml
@@ -7,21 +7,17 @@ publish = false
 
 [lib]
 name = "canvas"
 path = "lib.rs"
 
 [dependencies]
 azure = {git = "https://github.com/servo/rust-azure"}
 canvas_traits = {path = "../canvas_traits"}
-cssparser = {version = "0.11", features = ["heapsize", "serde"]}
+cssparser = "0.12"
 euclid = "0.11"
 gleam = "0.2.8"
 ipc-channel = "0.7"
 log = "0.3.5"
 num-traits = "0.1.32"
 offscreen_gl_context = "0.6"
 servo_config = {path = "../config"}
-
-[dependencies.webrender_traits]
-git = "https://github.com/servo/webrender"
-default-features = false
-features = ["serde_derive"]
+webrender_traits = {git = "https://github.com/servo/webrender", features = ["ipc"]}
--- a/servo/components/canvas_traits/Cargo.toml
+++ b/servo/components/canvas_traits/Cargo.toml
@@ -5,20 +5,16 @@ authors = ["The Servo Project Developers
 license = "MPL-2.0"
 publish = false
 
 [lib]
 name = "canvas_traits"
 path = "lib.rs"
 
 [dependencies]
-cssparser = {version = "0.11", features = ["heapsize", "serde"]}
+cssparser = "0.12"
 euclid = "0.11"
 heapsize = "0.3.0"
 heapsize_derive = "0.1"
 ipc-channel = "0.7"
 serde = {version = "0.9", features = ["unstable"]}
 serde_derive = "0.9"
-
-[dependencies.webrender_traits]
-git = "https://github.com/servo/webrender"
-default-features = false
-features = ["serde_derive", "ipc"]
+webrender_traits = {git = "https://github.com/servo/webrender", features = ["ipc"]}
--- a/servo/components/compositing/Cargo.toml
+++ b/servo/components/compositing/Cargo.toml
@@ -20,18 +20,10 @@ msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
 profile_traits = {path = "../profile_traits"}
 script_traits = {path = "../script_traits"}
 servo_config = {path = "../config", features = ["servo"]}
 servo_geometry = {path = "../geometry", features = ["servo"]}
 servo_url = {path = "../url", features = ["servo"]}
 style_traits = {path = "../style_traits"}
 time = "0.1.17"
-
-[dependencies.webrender]
-git = "https://github.com/servo/webrender"
-default-features = false
-features = ["serde_derive"]
-
-[dependencies.webrender_traits]
-git = "https://github.com/servo/webrender"
-default-features = false
-features = ["serde_derive", "ipc"]
+webrender = {git = "https://github.com/servo/webrender"}
+webrender_traits = {git = "https://github.com/servo/webrender", features = ["ipc"]}
--- a/servo/components/constellation/Cargo.toml
+++ b/servo/components/constellation/Cargo.toml
@@ -31,16 +31,12 @@ script_traits = {path = "../script_trait
 serde = "0.9"
 serde_derive = "0.9"
 style_traits = {path = "../style_traits"}
 servo_config = {path = "../config", features = ["servo"]}
 servo_rand = {path = "../rand"}
 servo_remutex = {path = "../remutex"}
 servo_url = {path = "../url", features = ["servo"]}
 webvr_traits = {path = "../webvr_traits"}
-
-[dependencies.webrender_traits]
-git = "https://github.com/servo/webrender"
-default-features = false
-features = ["serde_derive", "ipc"]
+webrender_traits = {git = "https://github.com/servo/webrender", features = ["ipc"]}
 
 [target.'cfg(not(target_os = "windows"))'.dependencies]
 gaol = {git = "https://github.com/servo/gaol"}
--- a/servo/components/gfx/Cargo.toml
+++ b/servo/components/gfx/Cargo.toml
@@ -33,31 +33,27 @@ serde_derive = "0.9"
 servo_atoms = {path = "../atoms"}
 servo_geometry = {path = "../geometry"}
 servo_url = {path = "../url"}
 smallvec = "0.1"
 style = {path = "../style"}
 style_traits = {path = "../style_traits"}
 time = "0.1.12"
 unicode-script = {version = "0.1", features = ["harfbuzz"]}
+webrender_traits = {git = "https://github.com/servo/webrender", features = ["ipc"]}
 xi-unicode = "0.1.0"
 
-[dependencies.webrender_traits]
-git = "https://github.com/servo/webrender"
-default-features = false
-features = ["serde_derive", "ipc"]
-
 [target.'cfg(target_os = "macos")'.dependencies]
 byteorder = "1.0"
 core-foundation = "0.3"
 core-graphics = "0.7"
 core-text = "4.0"
 
 [target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies]
 freetype = "0.2"
 servo-fontconfig = "0.2.1"
 
 [target.'cfg(any(target_feature = "sse2", target_feature = "neon"))'.dependencies]
 simd = "0.2.0"
 
 [target.'cfg(target_os = "windows")'.dependencies]
-servo-dwrote = "0.2"
+dwrote = "0.3"
 truetype = "0.26"
--- a/servo/components/layout/Cargo.toml
+++ b/servo/components/layout/Cargo.toml
@@ -9,17 +9,17 @@ publish = false
 name = "layout"
 path = "lib.rs"
 
 [dependencies]
 app_units = "0.4"
 atomic_refcell = "0.1"
 bitflags = "0.7"
 canvas_traits = {path = "../canvas_traits"}
-cssparser = {version = "0.11", features = ["heapsize", "serde"]}
+cssparser = "0.12"
 euclid = "0.11"
 fnv = "1.0"
 gfx = {path = "../gfx"}
 gfx_traits = {path = "../gfx_traits"}
 heapsize = "0.3.0"
 html5ever-atoms = "0.2"
 ipc-channel = "0.7"
 libc = "0.2"
@@ -40,13 +40,9 @@ servo_geometry = {path = "../geometry"}
 serde_json = "0.9"
 servo_config = {path = "../config"}
 servo_url = {path = "../url"}
 smallvec = "0.1"
 style = {path = "../style"}
 style_traits = {path = "../style_traits"}
 unicode-bidi = "0.2"
 unicode-script = {version = "0.1", features = ["harfbuzz"]}
-
-[dependencies.webrender_traits]
-git = "https://github.com/servo/webrender"
-default-features = false
-features = ["serde_derive", "ipc"]
+webrender_traits = {git = "https://github.com/servo/webrender", features = ["ipc"]}
--- a/servo/components/layout_thread/Cargo.toml
+++ b/servo/components/layout_thread/Cargo.toml
@@ -31,13 +31,9 @@ script_layout_interface = {path = "../sc
 script_traits = {path = "../script_traits"}
 selectors = { path = "../selectors" }
 serde_derive = "0.9"
 serde_json = "0.9"
 servo_config = {path = "../config"}
 servo_geometry = {path = "../geometry"}
 servo_url = {path = "../url"}
 style = {path = "../style"}
-
-[dependencies.webrender_traits]
-git = "https://github.com/servo/webrender"
-default-features = false
-features = ["serde_derive", "ipc"]
+webrender_traits = {git = "https://github.com/servo/webrender", features = ["ipc"]}
--- a/servo/components/layout_traits/Cargo.toml
+++ b/servo/components/layout_traits/Cargo.toml
@@ -12,13 +12,9 @@ path = "lib.rs"
 [dependencies]
 gfx = {path = "../gfx"}
 ipc-channel = "0.7"
 msg = {path = "../msg"}
 net_traits = {path = "../net_traits"}
 profile_traits = {path = "../profile_traits"}
 script_traits = {path = "../script_traits"}
 servo_url = {path = "../url"}
-
-[dependencies.webrender_traits]
-git = "https://github.com/servo/webrender"
-default-features = false
-features = ["serde_derive", "ipc"]
+webrender_traits = {git = "https://github.com/servo/webrender", features = ["ipc"]}
--- a/servo/components/msg/Cargo.toml
+++ b/servo/components/msg/Cargo.toml
@@ -6,18 +6,14 @@ license = "MPL-2.0"
 publish = false
 
 [lib]
 name = "msg"
 path = "lib.rs"
 
 [dependencies]
 bitflags = "0.7"
-cssparser = {version = "0.11", features = ["heapsize", "serde"]}
+cssparser = "0.12"
 heapsize = "0.3.0"
 heapsize_derive = "0.1"
 serde = "0.9"
 serde_derive = "0.9"
-
-[dependencies.webrender_traits]
-git = "https://github.com/servo/webrender"
-default-features = false
-features = ["serde_derive", "ipc"]
+webrender_traits = {git = "https://github.com/servo/webrender", features = ["ipc"]}
--- a/servo/components/net/Cargo.toml
+++ b/servo/components/net/Cargo.toml
@@ -35,17 +35,13 @@ serde_derive = "0.9"
 serde_json = "0.9"
 servo_config = {path = "../config"}
 servo_url = {path = "../url"}
 threadpool = "1.0"
 time = "0.1.17"
 unicase = "1.4.0"
 url = {version = "1.2", features = ["heap_size"]}
 uuid = {version = "0.4", features = ["v4"]}
+webrender_traits = {git = "https://github.com/servo/webrender", features = ["ipc"]}
 websocket = "0.17"
 
-[dependencies.webrender_traits]
-git = "https://github.com/servo/webrender"
-default-features = false
-features = ["serde_derive", "ipc"]
-
 [target.'cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))'.dependencies]
 tinyfiledialogs = "2.5.9"
--- a/servo/components/net_traits/Cargo.toml
+++ b/servo/components/net_traits/Cargo.toml
@@ -22,14 +22,10 @@ log = "0.3.5"
 msg = {path = "../msg"}
 num-traits = "0.1.32"
 serde = "0.9"
 serde_derive = "0.9"
 servo_config = {path = "../config", features = ["servo"]}
 servo_url = {path = "../url", features = ["servo"]}
 url = {version = "1.2", features = ["heap_size"]}
 uuid = {version = "0.4", features = ["v4", "serde"]}
+webrender_traits = {git = "https://github.com/servo/webrender", features = ["ipc"]}
 websocket = "0.17"
-
-[dependencies.webrender_traits]
-git = "https://github.com/servo/webrender"
-default-features = false
-features = ["serde_derive", "ipc"]
--- a/servo/components/script/Cargo.toml
+++ b/servo/components/script/Cargo.toml
@@ -29,18 +29,17 @@ app_units = "0.4"
 audio-video-metadata = "0.1.2"
 atomic_refcell = "0.1"
 bitflags = "0.7"
 bluetooth_traits = {path = "../bluetooth_traits"}
 byteorder = "1.0"
 canvas_traits = {path = "../canvas_traits"}
 caseless = "0.1.0"
 cookie = "0.2.5"
-cssparser = {version = "0.11", features = ["heapsize", "serde"]}
-cssparser-macros = "0.1.0"
+cssparser = "0.12"
 deny_public_fields = {path = "../deny_public_fields"}
 devtools_traits = {path = "../devtools_traits"}
 dom_struct = {path = "../dom_struct"}
 domobject_derive = {path = "../domobject_derive"}
 encoding = "0.2"
 euclid = "0.11"
 fnv = "1.0"
 gfx_traits = {path = "../gfx_traits"}
@@ -84,15 +83,11 @@ servo_url = {path = "../url", features =
 smallvec = "0.1"
 style = {path = "../style"}
 style_traits = {path = "../style_traits"}
 time = "0.1.12"
 url = {version = "1.2", features = ["heap_size", "query_encoding"]}
 uuid = {version = "0.4", features = ["v4"]}
 websocket = "0.17"
 xml5ever = {version = "0.4", features = ["unstable"]}
+webrender_traits = {git = "https://github.com/servo/webrender", features = ["ipc"]}
 webvr = {path = "../webvr"}
 webvr_traits = {path = "../webvr_traits"}
-
-[dependencies.webrender_traits]
-git = "https://github.com/servo/webrender"
-default-features = false
-features = ["nightly", "serde_derive", "ipc"]
--- a/servo/components/script/dom/element.rs
+++ b/servo/components/script/dom/element.rs
@@ -98,25 +98,25 @@ use std::rc::Rc;
 use std::sync::Arc;
 use style::attr::{AttrValue, LengthOrPercentageOrAuto};
 use style::context::{QuirksMode, ReflowGoal};
 use style::element_state::*;
 use style::matching::{common_style_affecting_attributes, rare_style_affecting_attributes};
 use style::parser::ParserContextExtraData;
 use style::properties::{DeclaredValue, Importance};
 use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, parse_style_attribute};
-use style::properties::longhands::{background_image, border_spacing, font_family, font_size, overflow_x};
+use style::properties::longhands::{self, background_image, border_spacing, font_family, font_size, overflow_x};
 use style::restyle_hints::RESTYLE_SELF;
 use style::rule_tree::CascadeLevel;
 use style::selector_parser::{NonTSPseudoClass, RestyleDamage, SelectorImpl, SelectorParser};
 use style::sink::Push;
 use style::stylist::ApplicableDeclarationBlock;
 use style::thread_state;
 use style::values::CSSFloat;
-use style::values::specified::{self, CSSColor, CSSRGBA};
+use style::values::specified::{self, CSSColor};
 use stylesheet_loader::StylesheetOwner;
 
 // TODO: Update focus state when the top-level browsing context gains or loses system focus,
 // and when the element enters or leaves a browsing context container.
 // https://html.spec.whatwg.org/multipage/#selector-focus
 
 #[dom_struct]
 pub struct Element {
@@ -437,20 +437,23 @@ impl LayoutElementHelpers for LayoutJS<E
             // https://html.spec.whatwg.org/multipage/#the-hr-element-2:presentational-hints-5
             this.get_color()
         } else {
             None
         };
 
         if let Some(color) = color {
             hints.push(from_declaration(
-                PropertyDeclaration::Color(DeclaredValue::Value(CSSRGBA {
-                    parsed: color,
-                    authored: None,
-                }))));
+                PropertyDeclaration::Color(DeclaredValue::Value(
+                    longhands::color::SpecifiedValue(CSSColor {
+                        parsed: Color::RGBA(color),
+                        authored: None,
+                    })
+                ))
+            ));
         }
 
         let font_family = if let Some(this) = self.downcast::<HTMLFontElement>() {
             this.get_face()
         } else {
             None
         };
 
--- a/servo/components/script/lib.rs
+++ b/servo/components/script/lib.rs
@@ -32,17 +32,16 @@ extern crate audio_video_metadata;
 extern crate bitflags;
 extern crate bluetooth_traits;
 extern crate byteorder;
 extern crate canvas_traits;
 extern crate caseless;
 extern crate cookie as cookie_rs;
 extern crate core;
 #[macro_use] extern crate cssparser;
-#[macro_use] extern crate cssparser_macros;
 #[macro_use] extern crate deny_public_fields;
 extern crate devtools_traits;
 extern crate dom_struct;
 #[macro_use]
 extern crate domobject_derive;
 extern crate encoding;
 extern crate euclid;
 extern crate fnv;
--- a/servo/components/script_layout_interface/Cargo.toml
+++ b/servo/components/script_layout_interface/Cargo.toml
@@ -8,17 +8,17 @@ publish = false
 [lib]
 name = "script_layout_interface"
 path = "lib.rs"
 
 [dependencies]
 app_units = "0.4"
 atomic_refcell = "0.1"
 canvas_traits = {path = "../canvas_traits"}
-cssparser = {version = "0.11", features = ["heapsize", "serde"]}
+cssparser = "0.12"
 euclid = "0.11"
 gfx_traits = {path = "../gfx_traits"}
 heapsize = "0.3.0"
 heapsize_derive = "0.1"
 html5ever-atoms = "0.2"
 ipc-channel = "0.7"
 libc = "0.2"
 log = "0.3.5"
--- a/servo/components/selectors/Cargo.toml
+++ b/servo/components/selectors/Cargo.toml
@@ -13,11 +13,10 @@ license = "MPL-2.0"
 
 [lib]
 name = "selectors"
 path = "lib.rs"
 
 [dependencies]
 bitflags = "0.7"
 matches = "0.1"
-cssparser = "0.11"
-cssparser-macros = "0.1.0"
+cssparser = "0.12"
 fnv = "1.0"
--- a/servo/components/selectors/lib.rs
+++ b/servo/components/selectors/lib.rs
@@ -1,15 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #[macro_use] extern crate bitflags;
 #[macro_use] extern crate cssparser;
-#[macro_use] extern crate cssparser_macros;
 #[macro_use] extern crate matches;
 extern crate fnv;
 
 pub mod bloom;
 pub mod matching;
 pub mod parser;
 mod tree;
 
--- a/servo/components/servo/Cargo.toml
+++ b/servo/components/servo/Cargo.toml
@@ -44,24 +44,16 @@ profile_traits = {path = "../profile_tra
 script = {path = "../script"}
 script_layout_interface = {path = "../script_layout_interface"}
 script_traits = {path = "../script_traits"}
 servo_config = {path = "../config"}
 servo_geometry = {path = "../geometry"}
 servo_url = {path = "../url"}
 style = {path = "../style", features = ["servo"]}
 style_traits = {path = "../style_traits", features = ["servo"]}
+webrender = {git = "https://github.com/servo/webrender"}
+webrender_traits = {git = "https://github.com/servo/webrender", features = ["ipc"]}
+webdriver_server = {path = "../webdriver_server", optional = true}
 webvr = {path = "../webvr"}
 webvr_traits = {path = "../webvr_traits"}
-webdriver_server = {path = "../webdriver_server", optional = true}
-
-[dependencies.webrender]
-git = "https://github.com/servo/webrender"
-default-features = false
-features = ["serde_derive"]
-
-[dependencies.webrender_traits]
-git = "https://github.com/servo/webrender"
-default-features = false
-features = ["serde_derive", "ipc"]
 
 [target.'cfg(not(target_os = "windows"))'.dependencies]
 gaol = {git = "https://github.com/servo/gaol"}
--- a/servo/components/style/Cargo.toml
+++ b/servo/components/style/Cargo.toml
@@ -21,34 +21,32 @@ servo = ["serde/unstable", "serde", "ser
          "rayon/unstable", "servo_url/servo"]
 testing = []
 
 [dependencies]
 app_units = "0.4"
 atomic_refcell = "0.1"
 bitflags = "0.7"
 cfg-if = "0.1.0"
-cssparser = "0.11"
-cssparser-macros = "0.1.0"
+cssparser = "0.12"
 encoding = "0.2"
 euclid = "0.11"
 fnv = "1.0"
 heapsize = "0.3.0"
 heapsize_derive = {version = "0.1", optional = true}
 html5ever-atoms = {version = "0.2", optional = true}
 lazy_static = "0.2"
 log = "0.3.5"
 matches = "0.1"
 nsstring_vendor = {path = "gecko_bindings/nsstring_vendor", optional = true}
 num-integer = "0.1.32"
 num-traits = "0.1.32"
 ordered-float = "0.4"
 owning_ref = "0.2.2"
 parking_lot = "0.3.3"
-phf = "0.7.20"
 pdqsort = "0.1.0"
 rayon = "0.6"
 selectors = { path = "../selectors" }
 serde = {version = "0.9", optional = true}
 serde_derive = {version = "0.9", optional = true}
 servo_atoms = {path = "../atoms", optional = true}
 servo_config = {path = "../config"}
 smallvec = "0.1"
--- a/servo/components/style/lib.rs
+++ b/servo/components/style/lib.rs
@@ -38,17 +38,16 @@
 #![recursion_limit = "500"]  // For define_css_keyword_enum! in -moz-appearance
 
 extern crate app_units;
 extern crate atomic_refcell;
 #[macro_use]
 extern crate bitflags;
 #[cfg(feature = "gecko")] #[macro_use] #[no_link] extern crate cfg_if;
 #[macro_use] extern crate cssparser;
-#[macro_use] extern crate cssparser_macros;
 extern crate encoding;
 extern crate euclid;
 extern crate fnv;
 #[cfg(feature = "gecko")] #[macro_use] pub mod gecko_string_cache;
 extern crate heapsize;
 #[cfg(feature = "servo")] #[macro_use] extern crate heapsize_derive;
 #[cfg(feature = "servo")] #[macro_use] extern crate html5ever_atoms;
 #[macro_use]
@@ -60,17 +59,16 @@ extern crate log;
 extern crate matches;
 #[cfg(feature = "gecko")] extern crate nsstring_vendor as nsstring;
 extern crate num_integer;
 extern crate num_traits;
 extern crate ordered_float;
 extern crate owning_ref;
 extern crate parking_lot;
 extern crate pdqsort;
-extern crate phf;
 extern crate rayon;
 extern crate selectors;
 #[cfg(feature = "servo")] #[macro_use] extern crate serde_derive;
 #[cfg(feature = "servo")] #[macro_use] extern crate servo_atoms;
 extern crate servo_config;
 extern crate servo_url;
 extern crate smallvec;
 #[macro_use]
--- a/servo/components/style/properties/helpers.mako.rs
+++ b/servo/components/style/properties/helpers.mako.rs
@@ -1,42 +1,28 @@
 /* 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/. */
 
 <%! from data import Keyword, to_rust_ident, to_camel_case, LOGICAL_SIDES, PHYSICAL_SIDES, LOGICAL_SIZES %>
 
-<%def name="longhand(name, **kwargs)">
-    <%call expr="raw_longhand(name, **kwargs)">
-        ${caller.body()}
-        % if not data.longhands_by_name[name].derived_from:
-            pub fn parse_specified(context: &ParserContext, input: &mut Parser)
-                % if data.longhands_by_name[name].boxed:
-                                   -> Result<DeclaredValue<Box<SpecifiedValue>>, ()> {
-                    parse(context, input).map(|result| DeclaredValue::Value(Box::new(result)))
-                % else:
-                                   -> Result<DeclaredValue<SpecifiedValue>, ()> {
-                    parse(context, input).map(DeclaredValue::Value)
-                % endif
-            }
-        % endif
-    </%call>
-</%def>
-
 <%def name="predefined_type(name, type, initial_value, parse_method='parse',
-            needs_context=True, vector=False, **kwargs)">
+            needs_context=True, vector=False, initial_specified_value=None, **kwargs)">
     <%def name="predefined_type_inner(name, type, initial_value, parse_method)">
         #[allow(unused_imports)]
         use app_units::Au;
         use cssparser::{Color as CSSParserColor, RGBA};
         pub use values::specified::${type} as SpecifiedValue;
         pub mod computed_value {
             pub use values::computed::${type} as T;
         }
         #[inline] pub fn get_initial_value() -> computed_value::T { ${initial_value} }
+        % if initial_specified_value:
+        #[inline] pub fn get_initial_specified_value() -> SpecifiedValue { ${initial_specified_value} }
+        % endif
         #[allow(unused_variables)]
         #[inline] pub fn parse(context: &ParserContext, input: &mut Parser)
                                -> Result<SpecifiedValue, ()> {
             % if needs_context:
             specified::${type}::${parse_method}(context, input)
             % else:
             specified::${type}::${parse_method}(input)
             % endif
@@ -207,17 +193,17 @@
                 }
             }
         % else:
             ${caller.body()}
         % endif
     </%call>
 </%def>
 
-<%def name="raw_longhand(*args, **kwargs)">
+<%def name="longhand(*args, **kwargs)">
     <%
         property = data.declare_longhand(*args, **kwargs)
         if property is None:
             return ""
     %>
     /// ${property.spec}
     pub mod ${property.ident} {
         #![allow(unused_imports)]
@@ -317,16 +303,25 @@
                                             cacheable,
                                             error_reporter);
                 % endif
             % else:
                 // Do not allow stylesheets to set derived properties.
             % endif
         }
         % if not property.derived_from:
+            pub fn parse_specified(context: &ParserContext, input: &mut Parser)
+                % if property.boxed:
+                                   -> Result<DeclaredValue<Box<SpecifiedValue>>, ()> {
+                    parse(context, input).map(|result| DeclaredValue::Value(Box::new(result)))
+                % else:
+                                   -> Result<DeclaredValue<SpecifiedValue>, ()> {
+                    parse(context, input).map(DeclaredValue::Value)
+                % endif
+            }
             pub fn parse_declared(context: &ParserContext, input: &mut Parser)
                                % if property.boxed:
                                    -> Result<DeclaredValue<Box<SpecifiedValue>>, ()> {
                                % else:
                                    -> Result<DeclaredValue<SpecifiedValue>, ()> {
                                % endif
                 match input.try(|i| CSSWideKeyword::parse(context, i)) {
                     Ok(CSSWideKeyword::InheritKeyword) => Ok(DeclaredValue::Inherit),
@@ -492,18 +487,17 @@
         use properties::{ShorthandId, longhands};
         use properties::declaration_block::Importance;
         use std::fmt;
         use style_traits::ToCss;
         use super::{SerializeFlags, ALL_INHERIT, ALL_INITIAL, ALL_UNSET};
 
         pub struct Longhands {
             % for sub_property in shorthand.sub_properties:
-                pub ${sub_property.ident}:
-                    Option<longhands::${sub_property.ident}::SpecifiedValue>,
+                pub ${sub_property.ident}: longhands::${sub_property.ident}::SpecifiedValue,
             % endfor
         }
 
         /// Represents a serializable set of all of the longhand properties that
         /// correspond to a shorthand.
         pub struct LonghandsToSerialize<'a> {
             % for sub_property in shorthand.sub_properties:
                 % if sub_property.boxed:
@@ -606,24 +600,21 @@
             let value = input.parse_entirely(|input| parse_value(context, input));
             if value.is_err() {
                 while let Ok(_) = input.next() {}  // Look for var() after the error.
             }
             let var = input.seen_var_functions();
             if let Ok(value) = value {
                 % for sub_property in shorthand.sub_properties:
                     declarations.push((PropertyDeclaration::${sub_property.camel_case}(
-                        match value.${sub_property.ident} {
-                            % if sub_property.boxed:
-                                Some(value) => DeclaredValue::Value(Box::new(value)),
-                            % else:
-                                Some(value) => DeclaredValue::Value(value),
-                            % endif
-                            None => DeclaredValue::Initial,
-                        }
+                        % if sub_property.boxed:
+                            DeclaredValue::Value(Box::new(value.${sub_property.ident}))
+                        % else:
+                            DeclaredValue::Value(value.${sub_property.ident})
+                        % endif
                     ), Importance::Normal));
                 % endfor
                 Ok(())
             } else if var {
                 input.reset(start);
                 let (first_token_type, css) = try!(
                     ::custom_properties::parse_non_custom_with_var(input));
                 % for sub_property in shorthand.sub_properties:
@@ -660,17 +651,17 @@
             % if needs_context:
                 try!(parse_four_sides(input, |i| ${parser_function}(context, i)));
             % else:
                 try!(parse_four_sides(input, ${parser_function}));
                 let _unused = context;
             % endif
             Ok(Longhands {
                 % for side in ["top", "right", "bottom", "left"]:
-                    ${to_rust_ident(sub_property_pattern % side)}: Some(${side}),
+                    ${to_rust_ident(sub_property_pattern % side)}: ${side},
                 % endfor
             })
         }
 
         impl<'a> LonghandsToSerialize<'a> {
             fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
                 super::serialize_four_sides(
                     dest,
--- a/servo/components/style/properties/longhand/background.mako.rs
+++ b/servo/components/style/properties/longhand/background.mako.rs
@@ -3,16 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 <%namespace name="helpers" file="/helpers.mako.rs" />
 
 <% data.new_style_struct("Background", inherited=False) %>
 
 ${helpers.predefined_type("background-color", "CSSColor",
     "::cssparser::Color::RGBA(::cssparser::RGBA::transparent())",
+    initial_specified_value="SpecifiedValue::transparent()",
     spec="https://drafts.csswg.org/css-backgrounds/#background-color",
     animatable=True, complex_color=True)}
 
 <%helpers:vector_longhand name="background-image" animatable="False"
                           spec="https://drafts.csswg.org/css-backgrounds/#the-background-image"
                           has_uncacheable_values="${product == 'gecko'}">
     use std::fmt;
     use style_traits::ToCss;
--- a/servo/components/style/properties/longhand/color.mako.rs
+++ b/servo/components/style/properties/longhand/color.mako.rs
@@ -1,53 +1,60 @@
 /* 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/. */
 
 <%namespace name="helpers" file="/helpers.mako.rs" />
 
 <% data.new_style_struct("Color", inherited=True) %>
 
-<%helpers:raw_longhand name="color" need_clone="True" animatable="True"
-                       spec="https://drafts.csswg.org/css-color/#color">
+<%helpers:longhand name="color" need_clone="True" animatable="True"
+                   spec="https://drafts.csswg.org/css-color/#color">
     use cssparser::Color as CSSParserColor;
     use cssparser::RGBA;
+    use std::fmt;
+    use style_traits::ToCss;
+    use values::HasViewportPercentage;
     use values::specified::{CSSColor, CSSRGBA};
 
     impl ToComputedValue for SpecifiedValue {
         type ComputedValue = computed_value::T;
 
         #[inline]
-        fn to_computed_value(&self, _context: &Context) -> computed_value::T {
-            self.parsed
+        fn to_computed_value(&self, context: &Context) -> computed_value::T {
+            match self.0.parsed {
+                CSSParserColor::RGBA(rgba) => rgba,
+                CSSParserColor::CurrentColor => context.inherited_style.get_color().clone_color(),
+            }
         }
 
         #[inline]
         fn from_computed_value(computed: &computed_value::T) -> Self {
-            CSSRGBA {
-                parsed: *computed,
+            SpecifiedValue(CSSColor {
+                parsed: CSSParserColor::RGBA(*computed),
                 authored: None,
-            }
+            })
         }
     }
 
-    pub type SpecifiedValue = CSSRGBA;
+    #[derive(Clone, PartialEq, Debug)]
+    #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+    pub struct SpecifiedValue(pub CSSColor);
+    no_viewport_percentage!(SpecifiedValue);
+
+    impl ToCss for SpecifiedValue {
+        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+            self.0.to_css(dest)
+        }
+    }
+
     pub mod computed_value {
         use cssparser;
         pub type T = cssparser::RGBA;
     }
     #[inline]
     pub fn get_initial_value() -> computed_value::T {
         RGBA::new(0, 0, 0, 255) // black
     }
-    pub fn parse_specified(context: &ParserContext, input: &mut Parser)
-                           -> Result<DeclaredValue<SpecifiedValue>, ()> {
-        let value = try!(CSSColor::parse(context, input));
-        let rgba = match value.parsed {
-            CSSParserColor::RGBA(rgba) => rgba,
-            CSSParserColor::CurrentColor => return Ok(DeclaredValue::Inherit)
-        };
-        Ok(DeclaredValue::Value(CSSRGBA {
-            parsed: rgba,
-            authored: value.authored,
-        }))
+    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
+        CSSColor::parse(context, input).map(SpecifiedValue)
     }
-</%helpers:raw_longhand>
+</%helpers:longhand>
--- a/servo/components/style/properties/longhand/column.mako.rs
+++ b/servo/components/style/properties/longhand/column.mako.rs
@@ -5,16 +5,17 @@
 <%namespace name="helpers" file="/helpers.mako.rs" />
 
 <% data.new_style_struct("Column", inherited=False) %>
 
 // FIXME: This prop should be animatable.
 ${helpers.predefined_type("column-width",
                           "length::LengthOrAuto",
                           "Either::Second(Auto)",
+                          initial_specified_value="Either::Second(Auto)",
                           parse_method="parse_non_negative_length",
                           extra_prefixes="moz",
                           animatable=False,
                           experimental=True,
                           spec="https://drafts.csswg.org/css-multicol/#propdef-column-width")}
 
 
 // FIXME: This prop should be animatable.
@@ -57,16 +58,21 @@
         }
     }
 
     #[inline]
     pub fn get_initial_value() -> computed_value::T {
         computed_value::T(None)
     }
 
+    #[inline]
+    pub fn get_initial_specified_value() -> SpecifiedValue {
+        SpecifiedValue::Auto
+    }
+
     impl ToComputedValue for SpecifiedValue {
         type ComputedValue = computed_value::T;
 
         #[inline]
         fn to_computed_value(&self, _context: &Context) -> computed_value::T {
             match *self {
                 SpecifiedValue::Auto => computed_value::T(None),
                 SpecifiedValue::Specified(count) =>
@@ -141,16 +147,17 @@
     pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
         BorderWidth::parse(context, input)
     }
 </%helpers:longhand>
 
 // https://drafts.csswg.org/css-multicol-1/#crc
 ${helpers.predefined_type("column-rule-color", "CSSColor",
                           "::cssparser::Color::CurrentColor",
+                          initial_specified_value="specified::CSSColor::currentcolor()",
                           products="gecko", animatable=True, extra_prefixes="moz",
                           complex_color=True, need_clone=True,
                           spec="https://drafts.csswg.org/css-multicol/#propdef-column-rule-color")}
 
 // It's not implemented in servo or gecko yet.
 ${helpers.single_keyword("column-span", "none all",
                          products="none", animatable=False,
                          spec="https://drafts.csswg.org/css-multicol/#propdef-column-span")}
--- a/servo/components/style/properties/longhand/font.mako.rs
+++ b/servo/components/style/properties/longhand/font.mako.rs
@@ -321,16 +321,21 @@
             }
         }
     }
     #[inline]
     pub fn get_initial_value() -> computed_value::T {
         computed_value::T::Weight400  // normal
     }
 
+    #[inline]
+    pub fn get_initial_specified_value() -> SpecifiedValue {
+        SpecifiedValue::Normal
+    }
+
     impl ToComputedValue for SpecifiedValue {
         type ComputedValue = computed_value::T;
 
         #[inline]
         fn to_computed_value(&self, context: &Context) -> computed_value::T {
             match *self {
                 % for weight in range(100, 901, 100):
                     SpecifiedValue::Weight${weight} => computed_value::T::Weight${weight},
@@ -402,16 +407,21 @@
     }
 
     #[inline]
     #[allow(missing_docs)]
     pub fn get_initial_value() -> computed_value::T {
         Au::from_px(FONT_MEDIUM_PX)
     }
 
+    #[inline]
+    pub fn get_initial_specified_value() -> SpecifiedValue {
+        SpecifiedValue(specified::LengthOrPercentage::Length(NoCalcLength::medium()))
+    }
+
     impl ToComputedValue for SpecifiedValue {
         type ComputedValue = computed_value::T;
 
         #[inline]
         fn to_computed_value(&self, context: &Context) -> computed_value::T {
             match self.0 {
                 LengthOrPercentage::Length(NoCalcLength::FontRelative(value)) => {
                     value.to_computed_value(context, /* use inherited */ true)
@@ -497,16 +507,21 @@
             }
         }
     }
 
     #[inline] pub fn get_initial_value() -> computed_value::T {
         computed_value::T::None
     }
 
+    #[inline]
+    pub fn get_initial_specified_value() -> SpecifiedValue {
+        SpecifiedValue::None
+    }
+
     /// none | <number>
     pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
         use values::specified::Number;
 
         if input.try(|input| input.expect_ident_matching("none")).is_ok() {
             return Ok(SpecifiedValue::None);
         }
 
@@ -745,16 +760,21 @@
         }
     }
 
     #[inline]
     pub fn get_initial_value() -> computed_value::T {
         computed_value::T::Normal
     }
 
+    #[inline]
+    pub fn get_initial_specified_value() -> SpecifiedValue {
+        SpecifiedValue::Normal
+    }
+
     pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
         if input.try(|input| input.expect_ident_matching("normal")).is_ok() {
             Ok(SpecifiedValue::Normal)
         } else {
             input.expect_string().map(|cow| {
                 SpecifiedValue::Override(cow.into_owned())
             })
         }
--- a/servo/components/style/properties/longhand/inherited_text.mako.rs
+++ b/servo/components/style/properties/longhand/inherited_text.mako.rs
@@ -96,16 +96,21 @@
                 computed_value::T::Length(length) => length.to_css(dest),
                 computed_value::T::Number(number) => write!(dest, "{}", number),
             }
         }
     }
      #[inline]
     pub fn get_initial_value() -> computed_value::T { computed_value::T::Normal }
 
+    #[inline]
+    pub fn get_initial_specified_value() -> SpecifiedValue {
+        SpecifiedValue::Normal
+    }
+
     impl ToComputedValue for SpecifiedValue {
         type ComputedValue = computed_value::T;
 
         #[inline]
         fn to_computed_value(&self, context: &Context) -> computed_value::T {
             match *self {
                 SpecifiedValue::Normal => computed_value::T::Normal,
                 % if product == "gecko":
@@ -1026,16 +1031,17 @@
             try!(dest.write_char(' '));
             vertical.to_css(dest)
         }
     }
 </%helpers:longhand>
 
 ${helpers.predefined_type("text-emphasis-color", "CSSColor",
                           "::cssparser::Color::CurrentColor",
+                          initial_specified_value="specified::CSSColor::currentcolor()",
                           products="gecko", animatable=True,
                           complex_color=True, need_clone=True,
                           spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-color")}
 
 
 ${helpers.predefined_type(
     "-moz-tab-size", "LengthOrNumber",
     "::values::Either::Second(8.0)",
@@ -1051,42 +1057,47 @@
     "CSSParserColor::CurrentColor",
     products="gecko", animatable=True,
     complex_color=True, need_clone=True,
     spec="https://compat.spec.whatwg.org/#the-webkit-text-fill-color")}
 
 ${helpers.predefined_type(
     "-webkit-text-stroke-color", "CSSColor",
     "CSSParserColor::CurrentColor",
+    initial_specified_value="specified::CSSColor::currentcolor()",
     products="gecko", animatable=True,
     complex_color=True, need_clone=True,
     spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-color")}
 
 <%helpers:longhand products="gecko" name="-webkit-text-stroke-width" animatable="False"
                    spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-width">
     use app_units::Au;
     use std::fmt;
     use style_traits::ToCss;
     use values::HasViewportPercentage;
-    use values::specified::BorderWidth;
+    use values::specified::{BorderWidth, Length};
 
     pub type SpecifiedValue = BorderWidth;
 
     #[inline]
     pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
         BorderWidth::parse(context, input)
     }
 
     pub mod computed_value {
         use app_units::Au;
         pub type T = Au;
     }
     #[inline] pub fn get_initial_value() -> computed_value::T {
         Au::from_px(0)
     }
+    #[inline]
+    pub fn get_initial_specified_value() -> SpecifiedValue {
+        BorderWidth::from_length(Length::zero())
+    }
 </%helpers:longhand>
 
 
 // CSS Ruby Layout Module Level 1
 // https://drafts.csswg.org/css-ruby/
 ${helpers.single_keyword("ruby-align", "start center space-between space-around",
                          products="gecko", animatable=False,
                          spec="https://drafts.csswg.org/css-ruby/#ruby-align-property")}
--- a/servo/components/style/properties/longhand/list.mako.rs
+++ b/servo/components/style/properties/longhand/list.mako.rs
@@ -33,17 +33,17 @@
     trad-chinese-informal trad-chinese-formal ethiopic-numeric upper-roman lower-roman
     """,
     gecko_constant_prefix="NS_STYLE_LIST_STYLE",
     needs_conversion="True",
     animatable=False,
     spec="https://drafts.csswg.org/css-lists/#propdef-list-style-type")}
 
 ${helpers.predefined_type("list-style-image", "UrlOrNone", "Either::Second(None_)",
-                          animatable=False,
+                          initial_specified_value="Either::Second(None_)", animatable=False,
                           spec="https://drafts.csswg.org/css-lists/#propdef-list-style-image")}
 
 <%helpers:longhand name="quotes" animatable="False"
                    spec="https://drafts.csswg.org/css-content/#propdef-quotes">
     use cssparser::Token;
     use std::borrow::Cow;
     use std::fmt;
     use style_traits::ToCss;
--- a/servo/components/style/properties/longhand/outline.mako.rs
+++ b/servo/components/style/properties/longhand/outline.mako.rs
@@ -6,16 +6,17 @@
 <% from data import Method %>
 
 <% data.new_style_struct("Outline",
                          inherited=False,
                          additional_methods=[Method("outline_has_nonzero_width", "bool")]) %>
 
 // TODO(pcwalton): `invert`
 ${helpers.predefined_type("outline-color", "CSSColor", "::cssparser::Color::CurrentColor",
+                          initial_specified_value="specified::CSSColor::currentcolor()",
                           animatable=True, complex_color=True, need_clone=True,
                           spec="https://drafts.csswg.org/css-ui/#propdef-outline-color")}
 
 <%helpers:longhand name="outline-style" need_clone="True" animatable="False"
                    spec="https://drafts.csswg.org/css-ui/#propdef-outline-style">
 
     use std::fmt;
     use style_traits::ToCss;
@@ -34,16 +35,21 @@
         }
     }
 
     #[inline]
     pub fn get_initial_value() -> computed_value::T {
         Either::Second(BorderStyle::none)
     }
 
+    #[inline]
+    pub fn get_initial_specified_value() -> SpecifiedValue {
+        Either::Second(BorderStyle::none)
+    }
+
     pub mod computed_value {
         pub type T = super::SpecifiedValue;
     }
 
     pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
         SpecifiedValue::parse(context, input)
             .and_then(|result| {
                 if let Either::Second(BorderStyle::hidden) = result {
@@ -83,17 +89,23 @@
 
     #[derive(Debug, Clone, PartialEq)]
     #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
     pub struct SpecifiedValue(pub specified::Length);
     pub mod computed_value {
         use app_units::Au;
         pub type T = Au;
     }
+
     pub use super::border_top_width::get_initial_value;
+    #[inline]
+    pub fn get_initial_specified_value() -> SpecifiedValue {
+        SpecifiedValue(specified::Length::NoCalc(specified::NoCalcLength::medium()))
+    }
+
     impl ToComputedValue for SpecifiedValue {
         type ComputedValue = computed_value::T;
 
         #[inline]
         fn to_computed_value(&self, context: &Context) -> computed_value::T {
             self.0.to_computed_value(context)
         }
 
--- a/servo/components/style/properties/longhand/text.mako.rs
+++ b/servo/components/style/properties/longhand/text.mako.rs
@@ -164,16 +164,20 @@
         #[allow(non_upper_case_globals)]
         pub const none: T = super::SpecifiedValue {
             bits: 0
         };
     }
     #[inline] pub fn get_initial_value() -> computed_value::T {
         computed_value::none
     }
+    #[inline]
+    pub fn get_initial_specified_value() -> SpecifiedValue {
+        SpecifiedValue::empty()
+    }
     /// none | [ underline || overline || line-through || blink ]
     pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
         let mut result = SpecifiedValue::empty();
         if input.try(|input| input.expect_ident_matching("none")).is_ok() {
             return Ok(result)
         }
         let mut empty = true;
 
@@ -214,13 +218,14 @@
 ${helpers.single_keyword("text-decoration-style",
                          "solid double dotted dashed wavy -moz-none",
                          products="gecko",
                          animatable=False,
                          spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-style")}
 
 ${helpers.predefined_type(
     "text-decoration-color", "CSSColor",
-    "CSSParserColor::RGBA(RGBA::new(0, 0, 0, 255))",
+    "::cssparser::Color::CurrentColor",
+    initial_specified_value="specified::CSSColor::currentcolor()",
     complex_color=True,
     products="gecko",
     animatable=True,
     spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-color")}
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -83,16 +83,22 @@ pub mod longhands {
     <%include file="/longhand/table.mako.rs" />
     <%include file="/longhand/text.mako.rs" />
     <%include file="/longhand/ui.mako.rs" />
     <%include file="/longhand/inherited_svg.mako.rs" />
     <%include file="/longhand/svg.mako.rs" />
     <%include file="/longhand/xul.mako.rs" />
 }
 
+macro_rules! unwrap_or_initial {
+    ($prop: ident) => (unwrap_or_initial!($prop, $prop));
+    ($prop: ident, $expr: expr) =>
+        ($expr.unwrap_or_else(|| $prop::get_initial_specified_value()));
+}
+
 /// A module with code for all the shorthand css properties, and a few
 /// serialization helpers.
 #[allow(missing_docs)]
 pub mod shorthands {
     use cssparser::Parser;
     use parser::{Parse, ParserContext};
     use values::specified;
 
@@ -338,23 +344,22 @@ impl PropertyDeclarationIdSet {
                         match from_shorthand {
                             None => {
                                 longhands::${property.ident}::parse_specified(&context, input)
                             }
                             % for shorthand in data.shorthands:
                                 % if property in shorthand.sub_properties:
                                     Some(ShorthandId::${shorthand.camel_case}) => {
                                         shorthands::${shorthand.ident}::parse_value(&context, input)
-                                        .map(|result| match result.${property.ident} {
+                                        .map(|result| {
                                             % if property.boxed:
-                                                Some(value) => DeclaredValue::Value(Box::new(value)),
+                                                DeclaredValue::Value(Box::new(result.${property.ident}))
                                             % else:
-                                                Some(value) => DeclaredValue::Value(value),
+                                                DeclaredValue::Value(result.${property.ident})
                                             % endif
-                                            None => DeclaredValue::Initial,
                                         })
                                     }
                                 % endif
                             % endfor
                             _ => unreachable!()
                         }
                     })
                 })
@@ -688,27 +693,27 @@ impl PropertyId {
 
         // FIXME(https://github.com/rust-lang/rust/issues/33156): remove this enum and use PropertyId
         // when stable Rust allows destructors in statics.
         enum StaticId {
             Longhand(LonghandId),
             Shorthand(ShorthandId),
         }
         ascii_case_insensitive_phf_map! {
-            StaticIds: Map<StaticId> = {
+            static_id -> StaticId = {
                 % for (kind, properties) in [("Longhand", data.longhands), ("Shorthand", data.shorthands)]:
                     % for property in properties:
                         % for name in [property.name] + property.alias:
-                            "${name}" => "StaticId::${kind}(${kind}Id::${property.camel_case})",
+                            "${name}" => StaticId::${kind}(${kind}Id::${property.camel_case}),
                         % endfor
                     % endfor
                 % endfor
             }
         }
-        match StaticIds::get(&property_name) {
+        match static_id(&property_name) {
             Some(&StaticId::Longhand(id)) => Ok(PropertyId::Longhand(id)),
             Some(&StaticId::Shorthand(id)) => Ok(PropertyId::Shorthand(id)),
             None => Err(()),
         }
     }
 
     /// Returns a property id from Gecko's nsCSSPropertyID.
     #[cfg(feature = "gecko")]
--- a/servo/components/style/properties/shorthand/background.mako.rs
+++ b/servo/components/style/properties/shorthand/background.mako.rs
@@ -110,25 +110,25 @@
                 % endfor
                 Ok(())
             } else {
                 Err(())
             }
         }));
 
         Ok(Longhands {
-             background_color: background_color,
-             background_image: Some(background_image),
-             background_position_x: Some(background_position_x),
-             background_position_y: Some(background_position_y),
-             background_repeat: Some(background_repeat),
-             background_attachment: Some(background_attachment),
-             background_size: Some(background_size),
-             background_origin: Some(background_origin),
-             background_clip: Some(background_clip),
+             background_color: unwrap_or_initial!(background_color),
+             background_image: background_image,
+             background_position_x: background_position_x,
+             background_position_y: background_position_y,
+             background_repeat: background_repeat,
+             background_attachment: background_attachment,
+             background_size: background_size,
+             background_origin: background_origin,
+             background_clip: background_clip,
          })
     }
 
     impl<'a> LonghandsToSerialize<'a>  {
         fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
             // mako doesn't like ampersands following `<`
             fn extract_value<T>(x: &DeclaredValue<T>) -> Option< &T> {
                 match *x {
@@ -241,18 +241,18 @@
             }
             Ok(())
         }));
         if any == false {
             return Err(());
         }
 
         Ok(Longhands {
-            background_position_x: Some(position_x),
-            background_position_y: Some(position_y),
+            background_position_x: position_x,
+            background_position_y: position_y,
         })
     }
 
     impl<'a> LonghandsToSerialize<'a>  {
         fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
             // mako doesn't like ampersands following `<`
             fn extract_value<T>(x: &DeclaredValue<T>) -> Option< &T> {
                 match *x {
--- a/servo/components/style/properties/shorthand/border.mako.rs
+++ b/servo/components/style/properties/shorthand/border.mako.rs
@@ -19,17 +19,17 @@
     use super::parse_four_sides;
     use parser::Parse;
     use values::specified;
 
     pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
         let (top, right, bottom, left) = try!(parse_four_sides(input, |i| specified::BorderWidth::parse(context, i)));
         Ok(Longhands {
             % for side in ["top", "right", "bottom", "left"]:
-                ${to_rust_ident('border-%s-width' % side)}: Some(${side}),
+                ${to_rust_ident('border-%s-width' % side)}: ${side},
             % endfor
         })
     }
 
     impl<'a> LonghandsToSerialize<'a>  {
         fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
             % for side in ["top", "right", "bottom", "left"]:
                 let ${side} = self.border_${side}_width.clone();
@@ -37,50 +37,56 @@
 
             super::serialize_four_sides(dest, &top, &right, &bottom, &left)
         }
     }
 </%helpers:shorthand>
 
 
 pub fn parse_border(context: &ParserContext, input: &mut Parser)
-                 -> Result<(Option<specified::CSSColor>,
-                            Option<specified::BorderStyle>,
-                            Option<specified::BorderWidth>), ()> {
-    use values::specified;
+                 -> Result<(specified::CSSColor,
+                            specified::BorderStyle,
+                            specified::BorderWidth), ()> {
+    use values::specified::{CSSColor, BorderStyle, BorderWidth};
     let _unused = context;
     let mut color = None;
     let mut style = None;
     let mut width = None;
     let mut any = false;
     loop {
         if color.is_none() {
-            if let Ok(value) = input.try(|i| specified::CSSColor::parse(context, i)) {
+            if let Ok(value) = input.try(|i| CSSColor::parse(context, i)) {
                 color = Some(value);
                 any = true;
                 continue
             }
         }
         if style.is_none() {
-            if let Ok(value) = input.try(|i| specified::BorderStyle::parse(context, i)) {
+            if let Ok(value) = input.try(|i| BorderStyle::parse(context, i)) {
                 style = Some(value);
                 any = true;
                 continue
             }
         }
         if width.is_none() {
-            if let Ok(value) = input.try(|i| specified::BorderWidth::parse(context, i)) {
+            if let Ok(value) = input.try(|i| BorderWidth::parse(context, i)) {
                 width = Some(value);
                 any = true;
                 continue
             }
         }
         break
     }
-    if any { Ok((color, style, width)) } else { Err(()) }
+    if any {
+        Ok((color.unwrap_or_else(|| CSSColor::currentcolor()),
+            style.unwrap_or(BorderStyle::none),
+            width.unwrap_or(BorderWidth::Medium)))
+    } else {
+        Err(())
+    }
 }
 
 % for side, logical in ALL_SIDES:
     <%
         spec = "https://drafts.csswg.org/css-backgrounds/#border-%s" % side
         if logical:
             spec = "https://drafts.csswg.org/css-logical-props/#propdef-border-%s" % side
     %>
@@ -153,20 +159,20 @@ pub fn parse_border(context: &ParserCont
      for corner in ['top-left', 'top-right', 'bottom-right', 'bottom-left']
 )}" extra_prefixes="webkit" spec="https://drafts.csswg.org/css-backgrounds/#border-radius">
     use values::specified::basic_shape::BorderRadius;
     use parser::Parse;
 
     pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
         let radii = try!(BorderRadius::parse(context, input));
         Ok(Longhands {
-            border_top_left_radius: Some(radii.top_left),
-            border_top_right_radius: Some(radii.top_right),
-            border_bottom_right_radius: Some(radii.bottom_right),
-            border_bottom_left_radius: Some(radii.bottom_left),
+            border_top_left_radius: radii.top_left,
+            border_top_right_radius: radii.top_right,
+            border_bottom_right_radius: radii.bottom_right,
+            border_bottom_left_radius: radii.bottom_left,
         })
     }
 
     // TODO: I do not understand how border radius works with respect to the slashes /,
     // so putting a default generic impl for now
     // https://developer.mozilla.org/en-US/docs/Web/CSS/border-radius
     impl<'a> LonghandsToSerialize<'a>  {
         fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
@@ -249,17 +255,17 @@ pub fn parse_border(context: &ParserCont
                 Ok(())
             } else {
                 Err(())
             }
         }));
 
         Ok(Longhands {
             % for name in "outset repeat slice source width".split():
-                border_image_${name}: Some(border_image_${name}),
+                border_image_${name}: border_image_${name},
             % endfor
          })
     }
 
     impl<'a> LonghandsToSerialize<'a>  {
         fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
             % for name in "outset repeat slice source width".split():
                 let ${name} = if let DeclaredValue::Value(ref value) = *self.border_image_${name} {
--- a/servo/components/style/properties/shorthand/box.mako.rs
+++ b/servo/components/style/properties/shorthand/box.mako.rs
@@ -6,18 +6,18 @@
 
 <%helpers:shorthand name="overflow" sub_properties="overflow-x overflow-y"
                     spec="https://drafts.csswg.org/css-overflow/#propdef-overflow">
     use properties::longhands::{overflow_x, overflow_y};
 
     pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
         let overflow = try!(overflow_x::parse(context, input));
         Ok(Longhands {
-            overflow_x: Some(overflow),
-            overflow_y: Some(overflow_y::SpecifiedValue(overflow)),
+            overflow_x: overflow,
+            overflow_y: overflow_y::SpecifiedValue(overflow),
         })
     }
 
     impl<'a> LonghandsToSerialize<'a>  {
         fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
             let x_and_y_equal = match (self.overflow_x, self.overflow_y) {
                 (&DeclaredValue::Value(ref x_value), &DeclaredValue::Value(ref y_container)) => {
                     *x_value == y_container.0
@@ -98,41 +98,35 @@ macro_rules! try_parse_one {
                     transition_delay:
                         delay.unwrap_or_else(transition_delay::single_value::get_initial_value),
                 })
             } else {
                 Err(())
             }
         }
 
-        if input.try(|input| input.expect_ident_matching("none")).is_ok() {
-            return Ok(Longhands {
-                transition_property: None,
-                transition_duration: None,
-                transition_timing_function: None,
-                transition_delay: None,
-            })
-        }
-
-        let results = try!(input.parse_comma_separated(|i| parse_one_transition(context, i)));
         let (mut properties, mut durations) = (Vec::new(), Vec::new());
         let (mut timing_functions, mut delays) = (Vec::new(), Vec::new());
-        for result in results {
-            properties.push(result.transition_property);
-            durations.push(result.transition_duration);
-            timing_functions.push(result.transition_timing_function);
-            delays.push(result.transition_delay);
+
+        if input.try(|input| input.expect_ident_matching("none")).is_err() {
+            let results = try!(input.parse_comma_separated(|i| parse_one_transition(context, i)));
+            for result in results {
+                properties.push(result.transition_property);
+                durations.push(result.transition_duration);
+                timing_functions.push(result.transition_timing_function);
+                delays.push(result.transition_delay);
+            }
         }
 
         Ok(Longhands {
-            transition_property: Some(transition_property::SpecifiedValue(properties)),
-            transition_duration: Some(transition_duration::SpecifiedValue(durations)),
+            transition_property: transition_property::SpecifiedValue(properties),
+            transition_duration: transition_duration::SpecifiedValue(durations),
             transition_timing_function:
-                Some(transition_timing_function::SpecifiedValue(timing_functions)),
-            transition_delay: Some(transition_delay::SpecifiedValue(delays)),
+                transition_timing_function::SpecifiedValue(timing_functions),
+            transition_delay: transition_delay::SpecifiedValue(delays),
         })
     }
 
     impl<'a> LonghandsToSerialize<'a>  {
         fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
             fn extract_value<T>(x: &DeclaredValue<T>) -> Option< &T> {
                 match *x {
                     DeclaredValue::Value(ref val) => Some(val),
@@ -253,60 +247,48 @@ macro_rules! try_parse_one {
                     animation_play_state:
                         play_state.unwrap_or_else(animation_play_state::single_value::get_initial_value),
                 })
             } else {
                 Err(())
             }
         }
 
-        if input.try(|input| input.expect_ident_matching("none")).is_ok() {
-            return Ok(Longhands {
-                animation_name: None,
-                animation_duration: None,
-                animation_timing_function: None,
-                animation_delay: None,
-                animation_iteration_count: None,
-                animation_direction: None,
-                animation_fill_mode: None,
-                animation_play_state: None,
-            })
-        }
-
-        let results = try!(input.parse_comma_separated(|i| parse_one_animation(context, i)));
-
         let mut names = vec![];
         let mut durations = vec![];
         let mut timing_functions = vec![];
         let mut delays = vec![];
         let mut iteration_counts = vec![];
         let mut directions = vec![];
         let mut fill_modes = vec![];
         let mut play_states = vec![];
 
-        for result in results.into_iter() {
-            names.push(result.animation_name);
-            durations.push(result.animation_duration);
-            timing_functions.push(result.animation_timing_function);
-            delays.push(result.animation_delay);
-            iteration_counts.push(result.animation_iteration_count);
-            directions.push(result.animation_direction);
-            fill_modes.push(result.animation_fill_mode);
-            play_states.push(result.animation_play_state);
+        if input.try(|input| input.expect_ident_matching("none")).is_err() {
+            let results = try!(input.parse_comma_separated(|i| parse_one_animation(context, i)));
+            for result in results.into_iter() {
+                names.push(result.animation_name);
+                durations.push(result.animation_duration);
+                timing_functions.push(result.animation_timing_function);
+                delays.push(result.animation_delay);
+                iteration_counts.push(result.animation_iteration_count);
+                directions.push(result.animation_direction);
+                fill_modes.push(result.animation_fill_mode);
+                play_states.push(result.animation_play_state);
+            }
         }
 
         Ok(Longhands {
-            animation_name: Some(animation_name::SpecifiedValue(names)),
-            animation_duration: Some(animation_duration::SpecifiedValue(durations)),
-            animation_timing_function: Some(animation_timing_function::SpecifiedValue(timing_functions)),
-            animation_delay: Some(animation_delay::SpecifiedValue(delays)),
-            animation_iteration_count: Some(animation_iteration_count::SpecifiedValue(iteration_counts)),
-            animation_direction: Some(animation_direction::SpecifiedValue(directions)),
-            animation_fill_mode: Some(animation_fill_mode::SpecifiedValue(fill_modes)),
-            animation_play_state: Some(animation_play_state::SpecifiedValue(play_states)),
+            animation_name: animation_name::SpecifiedValue(names),
+            animation_duration: animation_duration::SpecifiedValue(durations),
+            animation_timing_function: animation_timing_function::SpecifiedValue(timing_functions),
+            animation_delay: animation_delay::SpecifiedValue(delays),
+            animation_iteration_count: animation_iteration_count::SpecifiedValue(iteration_counts),
+            animation_direction: animation_direction::SpecifiedValue(directions),
+            animation_fill_mode: animation_fill_mode::SpecifiedValue(fill_modes),
+            animation_play_state: animation_play_state::SpecifiedValue(play_states),
         })
     }
 
     impl<'a> LonghandsToSerialize<'a>  {
         fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
             fn extract_value<T>(x: &DeclaredValue<T>) -> Option< &T> {
                 match *x {
                     DeclaredValue::Value(ref val) => Some(val),
@@ -359,18 +341,18 @@ macro_rules! try_parse_one {
 <%helpers:shorthand name="scroll-snap-type" products="gecko"
                     sub_properties="scroll-snap-type-x scroll-snap-type-y"
                     spec="https://drafts.csswg.org/css-scroll-snap/#propdef-scroll-snap-type">
     use properties::longhands::scroll_snap_type_x;
 
     pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
         let result = try!(scroll_snap_type_x::parse(context, input));
         Ok(Longhands {
-            scroll_snap_type_x: Some(result),
-            scroll_snap_type_y: Some(result),
+            scroll_snap_type_x: result,
+            scroll_snap_type_y: result,
         })
     }
 
     impl<'a> LonghandsToSerialize<'a>  {
         // Serializes into the single keyword value if both scroll-snap-type and scroll-snap-type-y are same.
         // Otherwise into an empty string. This is done to match Gecko's behaviour.
         fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
             let x_and_y_equal = match (self.scroll_snap_type_x, self.scroll_snap_type_y) {
--- a/servo/components/style/properties/shorthand/column.mako.rs
+++ b/servo/components/style/properties/shorthand/column.mako.rs
@@ -38,18 +38,18 @@
             break
         }
 
         let values = autos + column_count.iter().len() + column_width.iter().len();
         if values == 0 || values > 2 {
             Err(())
         } else {
             Ok(Longhands {
-                column_count: column_count,
-                column_width: column_width,
+                column_count: unwrap_or_initial!(column_count),
+                column_width: unwrap_or_initial!(column_width),
             })
         }
     }
 
     impl<'a> LonghandsToSerialize<'a>  {
         fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
             try!(self.column_width.to_css(dest));
             try!(write!(dest, " "));
@@ -82,21 +82,19 @@
                 }
             }
             % endfor
 
             break
         }
         if any {
             Ok(Longhands {
-                % for name in "width style".split():
-                    column_rule_${name}: column_rule_${name}
-                        .or(Some(column_rule_${name}::get_initial_specified_value())),
-                % endfor
-                column_rule_color: column_rule_color,
+                column_rule_width: unwrap_or_initial!(column_rule_width),
+                column_rule_style: unwrap_or_initial!(column_rule_style),
+                column_rule_color: unwrap_or_initial!(column_rule_color),
             })
         } else {
             Err(())
         }
     }
 
     impl<'a> LonghandsToSerialize<'a>  {
         fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
--- a/servo/components/style/properties/shorthand/font.mako.rs
+++ b/servo/components/style/properties/shorthand/font.mako.rs
@@ -9,16 +9,22 @@
                                                 ${'font-size-adjust' if product == 'gecko' else ''}
                                                 ${'font-kerning' if product == 'gecko' else ''}
                                                 ${'font-variant-caps' if product == 'gecko' else ''}
                                                 ${'font-variant-position' if product == 'gecko' else ''}
                                                 ${'font-language-override' if product == 'none' else ''}"
                     spec="https://drafts.csswg.org/css-fonts-3/#propdef-font">
     use properties::longhands::{font_style, font_variant, font_weight, font_stretch};
     use properties::longhands::{font_size, line_height};
+    % if product == "gecko":
+    use properties::longhands::{font_size_adjust, font_kerning, font_variant_caps, font_variant_position};
+    % endif
+    % if product == "none":
+    use properties::longhands::font_language_override;
+    % endif
     use properties::longhands::font_family::SpecifiedValue as FontFamily;
 
     pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
         let mut nb_normals = 0;
         let mut style = None;
         let mut variant = None;
         let mut weight = None;
         let mut stretch = None;
@@ -67,32 +73,29 @@
         }
         let line_height = if input.try(|input| input.expect_delim('/')).is_ok() {
             Some(try!(line_height::parse(context, input)))
         } else {
             None
         };
         let family = FontFamily::parse(input)?;
         Ok(Longhands {
-            font_style: style,
-            font_variant: variant,
-            font_weight: weight,
-            font_stretch: stretch,
-            font_size: size,
-            line_height: line_height,
-            font_family: Some(family),
-    % if product == "gecko":
-            font_size_adjust: None,
-            font_kerning: None,
-            font_variant_caps: None,
-            font_variant_position: None,
-    % endif
-    % if product == "none":
-            font_language_override: None,
-    % endif
+            % for name in "style variant weight stretch size".split():
+                font_${name}: unwrap_or_initial!(font_${name}, ${name}),
+            % endfor
+            line_height: unwrap_or_initial!(line_height),
+            font_family: family,
+            % if product == "gecko":
+                % for name in "size_adjust kerning variant_caps variant_position".split():
+                    font_${name}: font_${name}::get_initial_specified_value(),
+                % endfor
+            % endif
+            % if product == "none":
+                font_language_override: font_language_override::get_initial_specified_value(),
+            % endif
         })
     }
 
     // This may be a bit off, unsure, possibly needs changes
     impl<'a> LonghandsToSerialize<'a>  {
         fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
             if let DeclaredValue::Value(ref style) = *self.font_style {
                 try!(style.to_css(dest));
--- a/servo/components/style/properties/shorthand/inherited_svg.mako.rs
+++ b/servo/components/style/properties/shorthand/inherited_svg.mako.rs
@@ -9,19 +9,19 @@
     spec="https://www.w3.org/TR/SVG2/painting.html#MarkerShorthand">
     use values::specified::UrlOrNone;
 
     pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
         use parser::Parse;
         let url = UrlOrNone::parse(context, input)?;
 
         Ok(Longhands {
-            marker_start: Some(url.clone()),
-            marker_mid: Some(url.clone()),
-            marker_end: Some(url),
+            marker_start: url.clone(),
+            marker_mid: url.clone(),
+            marker_end: url,
         })
     }
 
     impl<'a> LonghandsToSerialize<'a>  {
         fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
             if let DeclaredValue::Value(ref start) = *self.marker_start {
                 if let DeclaredValue::Value(ref mid) = *self.marker_mid {
                     if let DeclaredValue::Value(ref end) = *self.marker_end {
--- a/servo/components/style/properties/shorthand/inherited_text.mako.rs
+++ b/servo/components/style/properties/shorthand/inherited_text.mako.rs
@@ -24,23 +24,19 @@
                 if let Ok(value) = input.try(|input| text_emphasis_style::parse(context, input)) {
                     style = Some(value);
                     continue
                 }
             }
             break
         }
         if color.is_some() || style.is_some() {
-            if style.is_none() {
-                style = Some(text_emphasis_style::get_initial_specified_value());
-            }
-
             Ok(Longhands {
-                text_emphasis_color: color,
-                text_emphasis_style: style,
+                text_emphasis_color: unwrap_or_initial!(text_emphasis_color, color),
+                text_emphasis_style: unwrap_or_initial!(text_emphasis_style, style),
             })
         } else {
             Err(())
         }
     }
 
     impl<'a> LonghandsToSerialize<'a>  {
         fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
@@ -63,23 +59,19 @@
 
 // CSS Compatibility
 // https://compat.spec.whatwg.org/
 <%helpers:shorthand name="-webkit-text-stroke"
                     sub_properties="-webkit-text-stroke-color
                                     -webkit-text-stroke-width"
                     products="gecko"
                     spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke">
-    use cssparser::Color as CSSParserColor;
     use properties::longhands::{_webkit_text_stroke_color, _webkit_text_stroke_width};
-    use values::specified::CSSColor;
 
     pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
-        use values::specified::{BorderWidth, Length};
-
         let mut color = None;
         let mut width = None;
         loop {
             if color.is_none() {
                 if let Ok(value) = input.try(|input| _webkit_text_stroke_color::parse(context, input)) {
                     color = Some(value);
                     continue
                 }
@@ -91,19 +83,18 @@
                     continue
                 }
             }
             break
         }
 
         if color.is_some() || width.is_some() {
             Ok(Longhands {
-                _webkit_text_stroke_color: color.or(Some(CSSColor { parsed: CSSParserColor::CurrentColor,
-                    authored: None })),
-                _webkit_text_stroke_width: width.or(Some(BorderWidth::from_length(Length::zero()))),
+                _webkit_text_stroke_color: unwrap_or_initial!(_webkit_text_stroke_color, color),
+                _webkit_text_stroke_width: unwrap_or_initial!(_webkit_text_stroke_width, width),
             })
         } else {
             Err(())
         }
     }
 
     impl<'a> LonghandsToSerialize<'a>  {
         fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
--- a/servo/components/style/properties/shorthand/list.mako.rs
+++ b/servo/components/style/properties/shorthand/list.mako.rs
@@ -46,53 +46,55 @@
                     position = Some(value);
                     any = true;
                     continue
                 }
             }
             break
         }
 
+        let position = unwrap_or_initial!(list_style_position, position);
+
         // If there are two `none`s, then we can't have a type or image; if there is one `none`,
         // then we can't have both a type *and* an image; if there is no `none` then we're fine as
         // long as we parsed something.
         match (any, nones, list_style_type, image) {
             (true, 2, None, None) => {
                 Ok(Longhands {
                     list_style_position: position,
-                    list_style_image: Some(Either::Second(None_)),
-                    list_style_type: Some(list_style_type::SpecifiedValue::none),
+                    list_style_image: Either::Second(None_),
+                    list_style_type: list_style_type::SpecifiedValue::none,
                 })
             }
             (true, 1, None, Some(image)) => {
                 Ok(Longhands {
                     list_style_position: position,
-                    list_style_image: Some(image),
-                    list_style_type: Some(list_style_type::SpecifiedValue::none),
+                    list_style_image: image,
+                    list_style_type: list_style_type::SpecifiedValue::none,
                 })
             }
             (true, 1, Some(list_style_type), None) => {
                 Ok(Longhands {
                     list_style_position: position,
-                    list_style_image: Some(Either::Second(None_)),
-                    list_style_type: Some(list_style_type),
+                    list_style_image: Either::Second(None_),
+                    list_style_type: list_style_type,
                 })
             }
             (true, 1, None, None) => {
                 Ok(Longhands {
                     list_style_position: position,
-                    list_style_image: Some(Either::Second(None_)),
-                    list_style_type: Some(list_style_type::SpecifiedValue::none),
+                    list_style_image: Either::Second(None_),
+                    list_style_type: list_style_type::SpecifiedValue::none,
                 })
             }
             (true, 0, list_style_type, image) => {
                 Ok(Longhands {
                     list_style_position: position,
-                    list_style_image: image,
-                    list_style_type: list_style_type,
+                    list_style_image: unwrap_or_initial!(list_style_image, image),
+                    list_style_type: unwrap_or_initial!(list_style_type),
                 })
             }
             _ => Err(()),
         }
     }
 
     impl<'a> LonghandsToSerialize<'a>  {
         fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
--- a/servo/components/style/properties/shorthand/mask.mako.rs
+++ b/servo/components/style/properties/shorthand/mask.mako.rs
@@ -110,17 +110,17 @@
                 Ok(())
             } else {
                 Err(())
             }
         }));
 
         Ok(Longhands {
             % for name in "image mode position_x position_y size repeat origin clip composite".split():
-                mask_${name}: Some(mask_${name}),
+                mask_${name}: mask_${name},
             % endfor
          })
     }
 
     impl<'a> LonghandsToSerialize<'a>  {
         fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
             // mako doesn't like ampersands following `<`
             fn extract_value<T>(x: &DeclaredValue<T>) -> Option< &T> {
@@ -258,18 +258,18 @@
             }
             Ok(())
         }));
         if any == false {
             return Err(());
         }
 
         Ok(Longhands {
-            mask_position_x: Some(position_x),
-            mask_position_y: Some(position_y),
+            mask_position_x: position_x,
+            mask_position_y: position_y,
         })
     }
 
     impl<'a> LonghandsToSerialize<'a>  {
         fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
             // mako doesn't like ampersands following `<`
             fn extract_value<T>(x: &DeclaredValue<T>) -> Option< &T> {
                 match *x {
--- a/servo/components/style/properties/shorthand/outline.mako.rs
+++ b/servo/components/style/properties/shorthand/outline.mako.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/. */
 
 <%namespace name="helpers" file="/helpers.mako.rs" />
 
 <%helpers:shorthand name="outline" sub_properties="outline-color outline-style outline-width"
                     spec="https://drafts.csswg.org/css-ui/#propdef-outline">
-    use properties::longhands::{outline_width, outline_style};
+    use properties::longhands::{outline_color, outline_width, outline_style};
     use values::specified;
     use parser::Parse;
 
     pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
         let _unused = context;
         let mut color = None;
         let mut style = None;
         let mut width = None;
@@ -37,19 +37,19 @@
                     any = true;
                     continue
                 }
             }
             break
         }
         if any {
             Ok(Longhands {
-                outline_color: color,
-                outline_style: style,
-                outline_width: width,
+                outline_color: unwrap_or_initial!(outline_color, color),
+                outline_style: unwrap_or_initial!(outline_style, style),
+                outline_width: unwrap_or_initial!(outline_width, width),
             })
         } else {
             Err(())
         }
     }
 
     impl<'a> LonghandsToSerialize<'a>  {
         fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
--- a/servo/components/style/properties/shorthand/position.mako.rs
+++ b/servo/components/style/properties/shorthand/position.mako.rs
@@ -26,18 +26,18 @@
             }
             break
         }
 
         if direction.is_none() && wrap.is_none() {
             return Err(())
         }
         Ok(Longhands {
-            flex_direction: direction,
-            flex_wrap: wrap,
+            flex_direction: unwrap_or_initial!(flex_direction, direction),
+            flex_wrap: unwrap_or_initial!(flex_wrap, wrap),
         })
     }
 
 
     impl<'a> LonghandsToSerialize<'a>  {
         fn to_css_declared<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
             match *self.flex_direction {
                 DeclaredValue::Initial => try!(write!(dest, "row")),
@@ -68,19 +68,19 @@
 
     pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
         let mut grow = None;
         let mut shrink = None;
         let mut basis = None;
 
         if input.try(|input| input.expect_ident_matching("none")).is_ok() {
             return Ok(Longhands {
-                flex_grow: Some(Number(0.0)),
-                flex_shrink: Some(Number(0.0)),
-                flex_basis: Some(LengthOrPercentageOrAutoOrContent::Auto)
+                flex_grow: Number(0.0),