Merge autoland to mozilla-central. a=merge
authorAndreea Pavel <apavel@mozilla.com>
Fri, 22 Mar 2019 11:55:04 +0200
changeset 465634 6332e136b825c0203318aedd24a080f1be6e72e2
parent 465629 2c49e736571bdcf4d8897eab3c3ad6d4a079f664 (current diff)
parent 465563 a06641525adc519013e0b51ae564cd3b387647b2 (diff)
child 465635 74a70a90e68a40b9d33286ab253f9d7083756b5c
push id81179
push userapavel@mozilla.com
push dateFri, 22 Mar 2019 10:03:49 +0000
treeherderautoland@f65d0b7ddc15 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone68.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 autoland to mozilla-central. a=merge
browser/components/urlbar/tests/browser/browser_autoFill_preserveCase.js
browser/locales/en-US/chrome/browser/aboutPrivateBrowsing.dtd
build/win64/cargo-linker.bat.in
layout/style/BorrowedTypeList.h
servo/ports/geckolib/tests/build.rs
servo/ports/geckolib/tests/servo_function_signatures.rs
taskcluster/scripts/comm-task-env
testing/web-platform/meta/domxpath/xml_xpath_runner.html.ini
testing/web-platform/meta/html/semantics/embedded-content/media-elements/track/track-element/track-api-texttracks.html.ini
--- a/.taskcluster.yml
+++ b/.taskcluster.yml
@@ -208,24 +208,24 @@ tasks:
             level-${repository.level}-checkouts-sparse-v2: /builds/worker/checkouts
 
           features:
             taskclusterProxy: true
             chainOfTrust: true
 
           # Note: This task is built server side without the context or tooling that
           # exist in tree so we must hard code the hash
-          image: 'taskcluster/decision:2.1.0@sha256:6db3b697d7a3c7aba440d72f04199331b872111cefff57206b8b8b1d53230360'
+          image: 'taskcluster/decision:2.2.0@sha256:0e9689e94605eb8395f5b49141a48148416b0d825f6f7be04c29642d1a85ee3d'
 
           maxRunTime: 1800
 
           command:
             - /builds/worker/bin/run-task
-            - '--vcs-checkout=/builds/worker/checkouts/gecko'
-            - '--sparse-profile=build/sparse-profiles/taskgraph'
+            - '--gecko-checkout=/builds/worker/checkouts/gecko'
+            - '--gecko-sparse-profile=build/sparse-profiles/taskgraph'
             - '--'
             - bash
             - -cx
             - $let:
                 extraArgs: {$if: 'tasks_for == "cron"', then: '${cron.quoted_args}', else: ''}
               in:
                 $if: 'tasks_for == "action"'
                 then: >
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2641,17 +2641,16 @@ dependencies = [
  "cssparser 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "geckoservo 0.0.1",
  "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "malloc_size_of 0.0.1",
  "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "selectors 0.21.0",
  "size_of_test 0.0.1",
  "smallvec 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "style 0.0.1",
  "style_traits 0.0.1",
 ]
 
 [[package]]
--- a/accessible/jsat/EventManager.jsm
+++ b/accessible/jsat/EventManager.jsm
@@ -76,16 +76,28 @@ this.EventManager.prototype = {
         // NS_ERROR_FAILURE. Checking for aEvent.accessibleDocument.docType ==
         // 'window' does not currently work.
         (aEvent.accessibleDocument.DOMDocument.doctype &&
          aEvent.accessibleDocument.DOMDocument.doctype.name === "window")) {
       return;
     }
 
     switch (aEvent.eventType) {
+      case Events.TEXT_CARET_MOVED:
+      {
+        if (aEvent.accessible != aEvent.accessibleDocument &&
+            !aEvent.isFromUserInput) {
+          // If caret moves in document without direct user
+          // we are probably stepping through results in find-in-page.
+          let acc = Utils.getTextLeafForOffset(aEvent.accessible,
+            aEvent.QueryInterface(Ci.nsIAccessibleCaretMoveEvent).caretOffset);
+          this.contentControl.autoMove(acc);
+        }
+        break;
+      }
       case Events.NAME_CHANGE:
       {
         // XXX: Port to Android
         break;
       }
       case Events.SCROLLING_START:
       {
         this.contentControl.autoMove(aEvent.accessible);
--- a/accessible/jsat/Utils.jsm
+++ b/accessible/jsat/Utils.jsm
@@ -334,16 +334,36 @@ var Utils = { // jshint ignore:line
     let parent = aStaticText.parent;
     if (aExcludeOrdered && parent.parent.DOMNode.nodeName === "OL") {
       return false;
     }
 
     return parent.role === Roles.LISTITEM && parent.childCount > 1 &&
       aStaticText.indexInParent === 0;
   },
+
+  getTextLeafForOffset: function getTextLeafForOffset(aAccessible, aOffset) {
+    let ht = aAccessible.QueryInterface(Ci.nsIAccessibleHyperText);
+    let offset = 0;
+    for (let child = aAccessible.firstChild; child; child = child.nextSibling) {
+      if (ht.getLinkIndexAtOffset(offset) != -1) {
+        // This is an embedded character, increment by one.
+        offset++;
+      } else {
+        offset += child.name.length;
+      }
+
+      if (offset >= aOffset) {
+        return child;
+      }
+    }
+
+    // This is probably a single child.
+    return aAccessible.lastChild;
+  },
 };
 
 /**
  * State object used internally to process accessible's states.
  * @param {Number} aBase     Base state.
  * @param {Number} aExtended Extended state.
  */
 function State(aBase, aExtended) {
--- a/browser/base/content/browser-contentblocking.js
+++ b/browser/base/content/browser-contentblocking.js
@@ -816,18 +816,22 @@ var ContentBlocking = {
     get appMenuTitle() {
       delete this.appMenuTitle;
       return this.appMenuTitle =
         gNavigatorBundle.getString("contentBlocking.title");
     },
 
     get appMenuTooltip() {
       delete this.appMenuTooltip;
+      if (AppConstants.platform == "win") {
+        return this.appMenuTooltip =
+          gNavigatorBundle.getString("contentBlocking.tooltipWin");
+      }
       return this.appMenuTooltip =
-        gNavigatorBundle.getString("contentBlocking.tooltip");
+        gNavigatorBundle.getString("contentBlocking.tooltipOther");
     },
 
     get activeTooltipText() {
       delete this.activeTooltipText;
       return this.activeTooltipText =
         gNavigatorBundle.getString("trackingProtection.icon.activeTooltip");
     },
 
--- a/browser/base/content/browser-sync.js
+++ b/browser/base/content/browser-sync.js
@@ -284,17 +284,17 @@ var gSync = {
       Services.prefs.setBoolPref("identity.fxaccounts.toolbar.accessed", true);
       document.documentElement.removeAttribute("fxa_avatar_badged");
     }
 
     const anchor = document.getElementById("fxa-toolbar-menu-button");
     if (anchor.getAttribute("open") == "true") {
       PanelUI.hide();
     } else {
-      PanelUI.showSubView(viewId, anchor);
+      PanelUI.showSubView(viewId, anchor, aEvent);
     }
   },
 
   updateFxAToolbarPanel(state = {}) {
     if (!gFxaToolbarEnabled) {
       return;
     }
 
--- a/browser/components/places/tests/chrome/chrome.ini
+++ b/browser/components/places/tests/chrome/chrome.ini
@@ -1,9 +1,10 @@
 [DEFAULT]
 support-files = head.js
 
 [test_0_bug510634.xul]
 [test_bug1163447_selectItems_through_shortcut.xul]
+skip-if = (os == 'win' && processor == 'aarch64') # bug 1532775
 [test_bug549192.xul]
 [test_bug549491.xul]
 [test_selectItems_on_nested_tree.xul]
 [test_treeview_date.xul]
\ No newline at end of file
--- a/browser/components/privatebrowsing/content/aboutPrivateBrowsing.xhtml
+++ b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.xhtml
@@ -1,94 +1,81 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 -->
-<!DOCTYPE html [
-  <!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
-  %htmlDTD;
-  <!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
-  %globalDTD;
-  <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
-  %brandDTD;
-  <!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
-  %browserDTD;
-  <!ENTITY % aboutPrivateBrowsingDTD SYSTEM "chrome://browser/locale/aboutPrivateBrowsing.dtd">
-  %aboutPrivateBrowsingDTD;
-]>
+<!DOCTYPE html>
 
 <html xmlns="http://www.w3.org/1999/xhtml" class="private no-search-ui">
   <head>
     <meta http-equiv="Content-Security-Policy" content="default-src chrome: blob:"/>
     <link rel="icon" type="image/png" href="chrome://browser/skin/privatebrowsing/favicon.svg"/>
     <link rel="stylesheet" href="chrome://browser/content/aboutPrivateBrowsing.css" type="text/css" media="all"/>
     <link rel="stylesheet" href="chrome://browser/skin/privatebrowsing/aboutPrivateBrowsing.css" type="text/css" media="all"/>
+    <link rel="localization" href="branding/brand.ftl"/>
+    <link rel="localization" href="browser/aboutPrivateBrowsing.ftl"/>
     <script type="application/javascript" src="chrome://browser/content/aboutPrivateBrowsing.js"></script>
     <script type="application/javascript" src="chrome://browser/content/contentSearchUI.js"></script>
   </head>
 
-  <body dir="&locale.dir;">
-    <p class="showNormal">&aboutPrivateBrowsing.notPrivate;</p>
+  <body>
+    <p class="showNormal" data-l10n-id="about-private-browsing-not-private"></p>
     <button id="startPrivateBrowsing"
-            class="showNormal"
-            accesskey="&privatebrowsingpage.openPrivateWindow.accesskey;">&privatebrowsingpage.openPrivateWindow.label;</button>
+            class="showNormal" data-l10n-id="privatebrowsingpage-open-private-window-label"></button>
     <div class="showPrivate dontShowSearch container">
       <h1 class="title">
-        <span id="title">&privateBrowsing.title;</span>
+        <span id="title" data-l10n-id="private-browsing-title"></span>
       </h1>
       <section class="section-main">
-        <p>&aboutPrivateBrowsing.info.notsaved.before;<strong>&aboutPrivateBrowsing.info.notsaved.emphasize;</strong>&aboutPrivateBrowsing.info.notsaved.after;</p>
+        <p data-l10n-id="about-private-browsing-info-notsaved"></p>
         <ul class="list-row">
-          <li>&aboutPrivateBrowsing.info.visited;</li>
-          <li>&aboutPrivateBrowsing.info.cookies;</li>
-          <li>&aboutPrivateBrowsing.info.searches;</li>
-          <li>&aboutPrivateBrowsing.info.temporaryFiles;</li>
+          <li data-l10n-id="about-private-browsing-info-visited"></li>
+          <li data-l10n-id="about-private-browsing-info-cookies"></li>
+          <li data-l10n-id="about-private-browsing-info-searches"></li>
+          <li data-l10n-id="about-private-browsing-info-temporary-files"></li>
         </ul>
-        <p>&aboutPrivateBrowsing.info.saved.before;<strong>&aboutPrivateBrowsing.info.saved.emphasize;</strong>&aboutPrivateBrowsing.info.saved.after2;</p>
+        <p data-l10n-id="about-private-browsing-info-saved"></p>
         <ul class="list-row">
-          <li>&aboutPrivateBrowsing.info.bookmarks;</li>
-          <li>&aboutPrivateBrowsing.info.downloads;</li>
-          <li>&aboutPrivateBrowsing.info.clipboard;</li>
+          <li data-l10n-id="about-private-browsing-info-bookmarks"></li>
+          <li data-l10n-id="about-private-browsing-info-downloads"></li>
+          <li data-l10n-id="about-private-browsing-info-clipboard"></li>
         </ul>
-        <p>&aboutPrivateBrowsing.note.before;<strong>&aboutPrivateBrowsing.note.emphasize;</strong>&aboutPrivateBrowsing.note.after;</p>
+        <p data-l10n-id="about-private-browsing-note"></p>
       </section>
 
       <h2 id="tpSubHeader" class="about-subheader">
-        <span id="cbTitle">&contentBlocking.title;</span>
+        <span id="cbTitle" data-l10n-id="content-blocking-title"></span>
       </h2>
 
       <section id="tpSection" class="section-main">
-        <p id="cbDescription">&contentBlocking.description;</p>
+        <p id="cbDescription" data-l10n-id="content-blocking-description"></p>
         <p>
-          <a id="startTour" class="button">&trackingProtection.startTour1;</a>
+          <a id="startTour" class="button" data-l10n-id="tracking-protection-start-tour"></a>
         </p>
       </section>
 
       <section class="section-main">
-        <p class="about-info">&aboutPrivateBrowsing.learnMore3.before;<a id="learnMore" target="_blank">&aboutPrivateBrowsing.learnMore3.title;</a>&aboutPrivateBrowsing.learnMore3.after;</p>
+        <p class="about-info" data-l10n-id="about-private-browsing-learn-more"><a id="learnMore" target="_blank" data-l10n-name="learn-more"></a></p>
       </section>
     </div>
     <div class="showPrivate showSearch container">
       <div class="logo-and-wordmark">
         <div class="logo" />
         <div class="wordmark" />
       </div>
       <div class="search-inner-wrapper">
-        <button id="search-handoff-button" class="search-handoff-button" title="&aboutPrivateBrowsing.search.placeholder;" tabindex="-1">
-          <div class="fake-textbox">&aboutPrivateBrowsing.search.placeholder;</div>
+        <button id="search-handoff-button" class="search-handoff-button" tabindex="-1" data-l10n-id="about-private-browsing">
+          <div class="fake-textbox" data-l10n-id="about-private-browsing-search-placeholder"></div>
           <input id="fake-editable" class="fake-editable" tabindex="-1" aria-hidden="true" />
           <div class="fake-caret" />
         </button>
         <input id="dummy-input" class="dummy-input" type="search" />
       </div>
       <div class="info">
-        <h1>&aboutPrivateBrowsing.info.title;</h1>
-        <p>
-          &aboutPrivateBrowsing.info.description;
-          <br/>
-          <a id="private-browsing-myths">&aboutPrivateBrowsing.info.myths;</a>
-        </p>
+        <h1 data-l10n-id="about-private-browsing-info-title"></h1>
+        <p data-l10n-id="about-private-browsing-info-description"></p>
+        <a id="private-browsing-myths" data-l10n-id="about-private-browsing-info-myths"></a>
       </div>
     </div>
   </body>
 </html>
--- a/browser/components/urlbar/UrlbarView.jsm
+++ b/browser/components/urlbar/UrlbarView.jsm
@@ -435,16 +435,20 @@ class UrlbarView {
         element.className = "urlbarView-tag";
         this._addTextContentWithHighlights(
           element, tag, result.payloadHighlights.tags[i]);
         return element;
       }));
       content.appendChild(tagsContainer);
     }
 
+    let titleSeparator = this._createElement("span");
+    titleSeparator.className = "urlbarView-title-separator";
+    content.appendChild(titleSeparator);
+
     let action;
     let url;
     let setAction = text => {
       action = this._createElement("span");
       action.className = "urlbarView-secondary urlbarView-action";
       action.textContent = text;
     };
     let setURL = () => {
--- a/browser/components/urlbar/tests/UrlbarTestUtils.jsm
+++ b/browser/components/urlbar/tests/UrlbarTestUtils.jsm
@@ -48,27 +48,26 @@ var UrlbarTestUtils = {
     await new Promise(resolve => waitForFocus(resolve, win));
     let lastSearchString = urlbar.lastSearchString;
     urlbar.focus();
     urlbar.value = inputText;
     if (fireInputEvent) {
       // This is necessary to get the urlbar to set gBrowser.userTypedValue.
       urlbar.fireInputEvent();
     }
-    // With awesomebar, we must call startSearch to start the search.  With
-    // quantumbar, we can either fire an input event or call start search, so be
-    // careful not to do both since that would start two searches.  However,
-    // there's one wrinkle with quantumbar: If the new search and old search are
-    // the same, the input event will *not* start a new search, by design.  Many
-    // existing tests do consecutive searches with the same string and expect
-    // new searches to start.  To keep those tests running, call startSearch
-    // directly in those cases.
-    if (!urlbar.quantumbar ||
-        !fireInputEvent ||
-        inputText == lastSearchString) {
+    // An input event will start a new search, with a couple of exceptions, so
+    // be careful not to call startSearch if we fired an input event since that
+    // would start two searches.  The first exception is when the new search and
+    // old search are the same.  Many tests do consecutive searches with the
+    // same string and expect new searches to start, so call startSearch
+    // directly then.  The second exception is when searching with the legacy
+    // urlbar and an empty string.
+    if (!fireInputEvent ||
+        inputText == lastSearchString ||
+        (!urlbar.quantumbar && !inputText)) {
       urlbar.startSearch(inputText);
     }
     return this.promiseSearchComplete(win, restoreAnimationsFn);
   },
 
   /**
    * Waits for a result to be added at a certain index. Since we implement lazy
    * results replacement, even if we have a result at an index, it may be
@@ -319,16 +318,19 @@ class UrlbarAbstraction {
     return this.oneOffSearchButtons.style.display != "none";
   }
 
   startSearch(text) {
     if (this.quantumbar) {
       this.urlbar.value = text;
       this.urlbar.startQuery();
     } else {
+      // Force the controller to do consecutive searches for the same string by
+      // calling resetInternalState.
+      this.urlbar.controller.resetInternalState();
       this.urlbar.controller.startSearch(text);
     }
   }
 
   promiseSearchComplete() {
     if (this.quantumbar) {
       return this.urlbar.lastQueryContextPromise;
     }
@@ -463,17 +465,17 @@ class UrlbarAbstraction {
         typeIcon: typeIconStyle.listStyleImage,
       };
       details.element = {
         action: element._actionText,
         row: element,
         separator: element._separator,
         url: element._urlText,
       };
-      if (details.type == UrlbarUtils.RESULT_TYPE.SEARCH) {
+      if (details.type == UrlbarUtils.RESULT_TYPE.SEARCH && action) {
         // Strip restriction tokens from input.
         let query = action.params.input;
         let restrictTokens = Object.values(UrlbarTokenizer.RESTRICT);
         if (restrictTokens.includes(query[0])) {
           query = query.substring(1).trim();
         }
         details.searchParams = {
           engine: action.params.engineName,
--- a/browser/components/urlbar/tests/browser/browser.ini
+++ b/browser/components/urlbar/tests/browser/browser.ini
@@ -21,17 +21,17 @@ skip-if = true # Bug 1524539 - need to f
 [browser_autocomplete_enter_race.js]
 [browser_autocomplete_no_title.js]
 [browser_autocomplete_readline_navigation.js]
 skip-if = os != "mac" # Mac only feature
 [browser_autocomplete_tag_star_visibility.js]
 [browser_autoFill_backspaced.js]
 [browser_autoFill_canonize.js]
 [browser_autoFill_caretNotAtEnd.js]
-[browser_autoFill_preserveCase.js]
+[browser_autoFill_preserve.js]
 [browser_autoFill_trimURLs.js]
 [browser_canonizeURL.js]
 [browser_caret_navigation.js]
 [browser_dragdropURL.js]
 [browser_keepStateAcrossTabSwitches.js]
 [browser_keyword_override.js]
 [browser_keyword_select_and_type.js]
 [browser_keyword.js]
rename from browser/components/urlbar/tests/browser/browser_autoFill_preserveCase.js
rename to browser/components/urlbar/tests/browser/browser_autoFill_preserve.js
--- a/browser/components/urlbar/tests/browser/browser_autoFill_preserveCase.js
+++ b/browser/components/urlbar/tests/browser/browser_autoFill_preserve.js
@@ -1,77 +1,236 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-// This test makes sure that when the user starts typing origins and URLs, the
-// case of the user's search string is preserved inside the origin part of the
-// autofilled string.
+// This test makes sure that a few of aspects of autofill are correctly
+// preserved:
+//
+// * Autofill should preserve the user's case.  If you type ExA, it should be
+//   autofilled to ExAmple.com/, not example.com/.
+// * When you key down and then back up to the autofill result, autofill should
+//   be restored, with the text selection and the user's case both preserved.
+// * When you key down/up so that no result is selected, the value that the
+//   user typed to trigger autofill should be restored in the input.
 
 "use strict";
 
 add_task(async function init() {
   await cleanUp();
 });
 
 add_task(async function origin() {
-  await PlacesTestUtils.addVisits([{
-    uri: "http://example.com/",
-  }]);
-  await promiseAutocompleteResultPopup("ExA");
-  await waitForAutocompleteResultAt(0);
+  await PlacesTestUtils.addVisits([
+    "http://example.com/",
+    "http://mozilla.org/example",
+  ]);
+  await promiseAutocompleteResultPopup("ExA", window, true);
+  let details = await UrlbarTestUtils.getDetailsOfResultAt(window, 0);
+  Assert.ok(details.autofill);
   Assert.equal(gURLBar.value, "ExAmple.com/");
+  Assert.equal(gURLBar.selectionStart, "ExA".length);
+  Assert.equal(gURLBar.selectionEnd, "ExAmple.com/".length);
+  checkKeys([
+    ["KEY_ArrowDown", "http://mozilla.org/example", 1],
+    ["KEY_ArrowDown", "ExA", -1],
+    ["KEY_ArrowUp", "http://mozilla.org/example", 1],
+    ["KEY_ArrowUp", "ExAmple.com/", 0],
+    ["KEY_ArrowUp", "ExA", -1],
+    ["KEY_ArrowDown", "ExAmple.com/", 0],
+  ]);
   await cleanUp();
 });
 
 add_task(async function originPort() {
-  await PlacesTestUtils.addVisits([{
-    uri: "http://example.com:8888/",
-  }]);
-  await promiseAutocompleteResultPopup("ExA");
-  await waitForAutocompleteResultAt(0);
+  await PlacesTestUtils.addVisits([
+    "http://example.com:8888/",
+    "http://mozilla.org/example",
+  ]);
+  await promiseAutocompleteResultPopup("ExA", window, true);
+  let details = await UrlbarTestUtils.getDetailsOfResultAt(window, 0);
+  Assert.ok(details.autofill);
   Assert.equal(gURLBar.value, "ExAmple.com:8888/");
+  Assert.equal(gURLBar.selectionStart, "ExA".length);
+  Assert.equal(gURLBar.selectionEnd, "ExAmple.com:8888/".length);
+  checkKeys([
+    ["KEY_ArrowDown", "http://mozilla.org/example", 1],
+    ["KEY_ArrowDown", "ExA", -1],
+    ["KEY_ArrowUp", "http://mozilla.org/example", 1],
+    ["KEY_ArrowUp", "ExAmple.com:8888/", 0],
+    ["KEY_ArrowUp", "ExA", -1],
+    ["KEY_ArrowDown", "ExAmple.com:8888/", 0],
+  ]);
   await cleanUp();
 });
 
 add_task(async function originScheme() {
-  await PlacesTestUtils.addVisits([{
-    uri: "http://example.com/",
-  }]);
-  await promiseAutocompleteResultPopup("http://ExA");
-  await waitForAutocompleteResultAt(0);
+  await PlacesTestUtils.addVisits([
+    "http://example.com/",
+    "http://mozilla.org/example",
+  ]);
+  await promiseAutocompleteResultPopup("http://ExA", window, true);
+  let details = await UrlbarTestUtils.getDetailsOfResultAt(window, 0);
+  Assert.ok(details.autofill);
   Assert.equal(gURLBar.value, "http://ExAmple.com/");
+  Assert.equal(gURLBar.selectionStart, "http://ExA".length);
+  Assert.equal(gURLBar.selectionEnd, "http://ExAmple.com/".length);
+  checkKeys([
+    ["KEY_ArrowDown", "http://mozilla.org/example", 1],
+    ["KEY_ArrowDown", "http://ExA", -1],
+    ["KEY_ArrowUp", "http://mozilla.org/example", 1],
+    ["KEY_ArrowUp", "http://ExAmple.com/", 0],
+    ["KEY_ArrowUp", "http://ExA", -1],
+    ["KEY_ArrowDown", "http://ExAmple.com/", 0],
+  ]);
   await cleanUp();
 });
 
 add_task(async function originPortScheme() {
-  await PlacesTestUtils.addVisits([{
-    uri: "http://example.com:8888/",
-  }]);
-  await promiseAutocompleteResultPopup("http://ExA");
-  await waitForAutocompleteResultAt(0);
+  await PlacesTestUtils.addVisits([
+    "http://example.com:8888/",
+    "http://mozilla.org/example",
+  ]);
+  await promiseAutocompleteResultPopup("http://ExA", window, true);
+  let details = await UrlbarTestUtils.getDetailsOfResultAt(window, 0);
+  Assert.ok(details.autofill);
   Assert.equal(gURLBar.value, "http://ExAmple.com:8888/");
+  Assert.equal(gURLBar.selectionStart, "http://ExA".length);
+  Assert.equal(gURLBar.selectionEnd, "http://ExAmple.com:8888/".length);
+  checkKeys([
+    ["KEY_ArrowDown", "http://mozilla.org/example", 1],
+    ["KEY_ArrowDown", "http://ExA", -1],
+    ["KEY_ArrowUp", "http://mozilla.org/example", 1],
+    ["KEY_ArrowUp", "http://ExAmple.com:8888/", 0],
+    ["KEY_ArrowUp", "http://ExA", -1],
+    ["KEY_ArrowDown", "http://ExAmple.com:8888/", 0],
+  ]);
   await cleanUp();
 });
 
 add_task(async function url() {
-  await PlacesTestUtils.addVisits([{
-    uri: "http://example.com/foo",
-  }]);
-  await promiseAutocompleteResultPopup("ExAmple.com/f");
+  await PlacesTestUtils.addVisits([
+    "http://example.com/foo",
+    "http://example.com/foo",
+    "http://example.com/fff",
+  ]);
+  await promiseAutocompleteResultPopup("ExAmple.com/f", window, true);
+  let details = await UrlbarTestUtils.getDetailsOfResultAt(window, 0);
+  Assert.ok(details.autofill);
   Assert.equal(gURLBar.value, "ExAmple.com/foo");
+  Assert.equal(gURLBar.selectionStart, "ExAmple.com/f".length);
+  Assert.equal(gURLBar.selectionEnd, "ExAmple.com/foo".length);
+  checkKeys([
+    ["KEY_ArrowDown", "http://example.com/fff", 1],
+    ["KEY_ArrowDown", "ExAmple.com/f", -1],
+    ["KEY_ArrowUp", "http://example.com/fff", 1],
+    ["KEY_ArrowUp", "ExAmple.com/foo", 0],
+    ["KEY_ArrowUp", "ExAmple.com/f", -1],
+    ["KEY_ArrowDown", "ExAmple.com/foo", 0],
+  ]);
   await cleanUp();
 });
 
 add_task(async function urlPort() {
-  await PlacesTestUtils.addVisits([{
-    uri: "http://example.com:8888/foo",
-  }]);
-  await promiseAutocompleteResultPopup("ExAmple.com:8888/f");
+  await PlacesTestUtils.addVisits([
+    "http://example.com:8888/foo",
+    "http://example.com:8888/foo",
+    "http://example.com:8888/fff",
+  ]);
+  await promiseAutocompleteResultPopup("ExAmple.com:8888/f", window, true);
+  let details = await UrlbarTestUtils.getDetailsOfResultAt(window, 0);
+  Assert.ok(details.autofill);
   Assert.equal(gURLBar.value, "ExAmple.com:8888/foo");
+  Assert.equal(gURLBar.selectionStart, "ExAmple.com:8888/f".length);
+  Assert.equal(gURLBar.selectionEnd, "ExAmple.com:8888/foo".length);
+  checkKeys([
+    ["KEY_ArrowDown", "http://example.com:8888/fff", 1],
+    ["KEY_ArrowDown", "ExAmple.com:8888/f", -1],
+    ["KEY_ArrowUp", "http://example.com:8888/fff", 1],
+    ["KEY_ArrowUp", "ExAmple.com:8888/foo", 0],
+    ["KEY_ArrowUp", "ExAmple.com:8888/f", -1],
+    ["KEY_ArrowDown", "ExAmple.com:8888/foo", 0],
+  ]);
+  await cleanUp();
+});
+
+add_task(async function tokenAlias() {
+  await Services.search.addEngineWithDetails("Test", {
+    alias: "@example",
+    template: "http://example.com/?search={searchTerms}",
+  });
+  registerCleanupFunction(async function() {
+    let engine = Services.search.getEngineByName("Test");
+    await Services.search.removeEngine(engine);
+  });
+  await promiseAutocompleteResultPopup("@ExA", window, true);
+  let details = await UrlbarTestUtils.getDetailsOfResultAt(window, 0);
+  Assert.ok(details.autofill);
+  Assert.equal(gURLBar.value, "@ExAmple ");
+  Assert.equal(gURLBar.selectionStart, "@ExA".length);
+  Assert.equal(gURLBar.selectionEnd, "@ExAmple ".length);
+  // Token aliases (1) hide the one-off buttons and (2) show only a single
+  // result, the "Search with" result for the alias's engine, so there's no way
+  // to key up/down to change the selection, so this task doesn't check key
+  // presses like the others do.
   await cleanUp();
 });
 
+// This test is a little different from the others.  It backspaces over the
+// autofilled substring and checks that autofill is *not* preserved.
+add_task(async function backspaceNoAutofill() {
+  await PlacesTestUtils.addVisits([
+    "http://example.com/",
+    "http://example.com/",
+    "http://mozilla.org/example",
+  ]);
+  await promiseAutocompleteResultPopup("ExA", window, true);
+  let details = await UrlbarTestUtils.getDetailsOfResultAt(window, 0);
+  Assert.ok(details.autofill);
+  Assert.equal(gURLBar.value, "ExAmple.com/");
+  Assert.equal(gURLBar.selectionStart, "ExA".length);
+  Assert.equal(gURLBar.selectionEnd, "ExAmple.com/".length);
+
+  EventUtils.synthesizeKey("KEY_Backspace");
+  await UrlbarTestUtils.promiseSearchComplete(window);
+  details = await UrlbarTestUtils.getDetailsOfResultAt(window, 0);
+  Assert.ok(!details.autofill);
+  Assert.equal(gURLBar.value, "ExA");
+  Assert.equal(gURLBar.selectionStart, "ExA".length);
+  Assert.equal(gURLBar.selectionEnd, "ExA".length);
+
+  let heuristicValue = "ExA";
+  if (!UrlbarPrefs.get("quantumbar")) {
+    heuristicValue = PlacesUtils.mozActionURI("searchengine", {
+      engineName: "Google",
+      searchQuery: "ExA",
+      input: "ExA",
+    });
+  }
+
+  checkKeys([
+    ["KEY_ArrowDown", "http://example.com/", 1],
+    ["KEY_ArrowDown", "http://mozilla.org/example", 2],
+    ["KEY_ArrowDown", "ExA", -1],
+    ["KEY_ArrowUp", "http://mozilla.org/example", 2],
+    ["KEY_ArrowUp", "http://example.com/", 1],
+    ["KEY_ArrowUp", heuristicValue, 0],
+    ["KEY_ArrowUp", "ExA", -1],
+    ["KEY_ArrowDown", heuristicValue, 0],
+  ]);
+
+  await cleanUp();
+});
+
+
+function checkKeys(testTuples) {
+  for (let [key, value, selectedIndex] of testTuples) {
+    EventUtils.synthesizeKey(key);
+    Assert.equal(UrlbarTestUtils.getSelectedIndex(window), selectedIndex);
+    Assert.equal(gURLBar.value, value);
+  }
+}
+
 async function cleanUp() {
   EventUtils.synthesizeKey("KEY_Escape");
   await UrlbarTestUtils.promisePopupClose(window);
   await PlacesUtils.bookmarks.eraseEverything();
   await PlacesUtils.history.clear();
 }
--- a/browser/components/urlbar/tests/legacy/browser.ini
+++ b/browser/components/urlbar/tests/legacy/browser.ini
@@ -44,17 +44,17 @@ skip-if = (verify && !debug && (os == 'w
 [../browser/browser_autocomplete_cursor.js]
 [../browser/browser_autocomplete_edit_completed.js]
 [../browser/browser_autocomplete_enter_race.js]
 [../browser/browser_autocomplete_no_title.js]
 [../browser/browser_autocomplete_readline_navigation.js]
 skip-if = os != "mac" # Mac only feature
 [../browser/browser_autoFill_backspaced.js]
 [../browser/browser_autoFill_canonize.js]
-[../browser/browser_autoFill_preserveCase.js]
+[../browser/browser_autoFill_preserve.js]
 [../browser/browser_autoFill_trimURLs.js]
 [../browser/browser_autocomplete_tag_star_visibility.js]
 [../browser/browser_canonizeURL.js]
 [../browser/browser_dragdropURL.js]
 [../browser/browser_keepStateAcrossTabSwitches.js]
 [../browser/browser_keyword_override.js]
 [../browser/browser_keyword_select_and_type.js]
 [../browser/browser_keyword.js]
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -82,17 +82,17 @@
 @BINPATH@/@DLL_PREFIX@xul@DLL_SUFFIX@
 #endif
 #ifdef XP_MACOSX
 @BINPATH@/@MOZ_CHILD_PROCESS_NAME@.app/
 @BINPATH@/@DLL_PREFIX@plugin_child_interpose@DLL_SUFFIX@
 #else
 @BINPATH@/@MOZ_CHILD_PROCESS_NAME@
 #endif
-#ifdef XP_WIN32
+#ifdef XP_WIN
 @BINPATH@/plugin-hang-ui@BIN_SUFFIX@
 #if MOZ_PACKAGE_MSVC_DLLS
 @BINPATH@/@MSVC_C_RUNTIME_DLL@
 @BINPATH@/@MSVC_CXX_RUNTIME_DLL@
 #endif
 #if MOZ_PACKAGE_WIN_UCRT_DLLS
 @BINPATH@/api-ms-win-*.dll
 @BINPATH@/ucrtbase.dll
@@ -146,17 +146,17 @@
 @BINPATH@/@DLL_PREFIX@qipcap64@DLL_SUFFIX@
 #else
 @BINPATH@/@DLL_PREFIX@qipcap@DLL_SUFFIX@
 #endif
 #endif
 
 ; [Components]
 #ifdef ACCESSIBILITY
-#ifdef XP_WIN32
+#ifdef XP_WIN
 @BINPATH@/Accessible.tlb
 @BINPATH@/AccessibleHandler.dll
 @BINPATH@/AccessibleMarshal.dll
 @BINPATH@/IA2Marshal.dll
 #endif
 #endif
 
 ; JavaScript components
new file mode 100644
--- /dev/null
+++ b/browser/locales/en-US/browser/aboutPrivateBrowsing.ftl
@@ -0,0 +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/.
+
+about-private-browsing-learn-more = Learn more about <a data-l10n-name="learn-more">Private Browsing</a>.
+about-private-browsing-info-visited = visited pages
+privatebrowsingpage-open-private-window-label = Open a Private Window
+    .accesskey = P
+about-private-browsing-info-notsaved = When you browse in a Private Window, { -brand-short-name } <strong>does not save</strong>:
+about-private-browsing-search-placeholder = Search the Web
+about-private-browsing-info-bookmarks = bookmarks
+about-private-browsing-info-title = You’re in a Private Window
+about-private-browsing-info-searches = searches
+about-private-browsing-info-downloads = downloads
+private-browsing-title = Private Browsing
+about-private-browsing-info-saved = { -brand-short-name } <strong>will save</strong> your:
+about-private-browsing-info-myths = Common myths about private browsing
+about-private-browsing-info-clipboard = copied text
+about-private-browsing-info-temporary-files = temporary files
+about-private-browsing-info-cookies = cookies
+tracking-protection-start-tour = See how it works
+about-private-browsing-note = Private Browsing <strong>doesn’t make you anonymous</strong> on the Internet. Your employer or Internet service provider can still know what page you visit.
+about-private-browsing =
+    .title = Search the Web
+about-private-browsing-not-private = You are currently not in a private window.
+content-blocking-title = Content Blocking
+content-blocking-description = Some websites use trackers that can monitor your activity across the Internet. In private windows, { -brand-short-name } Content Blocking automatically blocks many trackers that can collect information about your browsing behavior.
+about-private-browsing-info-description = { -brand-short-name } clears your search and browsing history when you quit the app or close all Private Browsing tabs and windows. While this doesn’t make you anonymous to websites or your internet service provider, it makes it easier to keep what you do online private from anyone else who uses this computer.
deleted file mode 100644
--- a/browser/locales/en-US/chrome/browser/aboutPrivateBrowsing.dtd
+++ /dev/null
@@ -1,43 +0,0 @@
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-
-<!ENTITY aboutPrivateBrowsing.notPrivate                 "You are currently not in a private window.">
-<!ENTITY privatebrowsingpage.openPrivateWindow.label     "Open a Private Window">
-<!ENTITY privatebrowsingpage.openPrivateWindow.accesskey "P">
-
-<!ENTITY privateBrowsing.title                           "Private Browsing">
-<!ENTITY aboutPrivateBrowsing.info.notsaved.before       "When you browse in a Private Window, Firefox ">
-<!ENTITY aboutPrivateBrowsing.info.notsaved.emphasize    "does not save">
-<!ENTITY aboutPrivateBrowsing.info.notsaved.after        ":">
-<!ENTITY aboutPrivateBrowsing.info.visited               "visited pages">
-<!ENTITY aboutPrivateBrowsing.info.searches              "searches">
-<!ENTITY aboutPrivateBrowsing.info.cookies               "cookies">
-<!ENTITY aboutPrivateBrowsing.info.temporaryFiles        "temporary files">
-<!ENTITY aboutPrivateBrowsing.info.saved.before          "Firefox ">
-<!ENTITY aboutPrivateBrowsing.info.saved.emphasize       "will save">
-<!ENTITY aboutPrivateBrowsing.info.saved.after2          " your:">
-<!ENTITY aboutPrivateBrowsing.info.downloads             "downloads">
-<!ENTITY aboutPrivateBrowsing.info.bookmarks             "bookmarks">
-<!ENTITY aboutPrivateBrowsing.info.clipboard             "copied text">
-<!ENTITY aboutPrivateBrowsing.note.before                "Private Browsing ">
-<!ENTITY aboutPrivateBrowsing.note.emphasize             "doesn’t make you anonymous">
-<!ENTITY aboutPrivateBrowsing.note.after                 " on the Internet. Your employer or Internet service provider can still know what page you visit.">
-<!ENTITY aboutPrivateBrowsing.learnMore3.before          "Learn more about ">
-<!ENTITY aboutPrivateBrowsing.learnMore3.title           "Private Browsing">
-<!ENTITY aboutPrivateBrowsing.learnMore3.after           ".">
-
-<!ENTITY trackingProtection.startTour1                   "See how it works">
-
-<!ENTITY contentBlocking.title                           "Content Blocking">
-<!ENTITY contentBlocking.description                     "Some websites use trackers that can monitor your activity across the Internet. In private windows, Firefox Content Blocking automatically blocks many trackers that can collect information about your browsing behavior.">
-
-<!-- Strings for new Private Browsing with Search -->
-<!-- LOCALIZATION NOTE (aboutPrivateBrowsing.search.placeholder): This is the placeholder
-                       text for the search box.   -->
-<!ENTITY aboutPrivateBrowsing.search.placeholder         "Search the Web">
-<!ENTITY aboutPrivateBrowsing.info.title                 "You’re in a Private Window">
-<!ENTITY aboutPrivateBrowsing.info.description           "&brandShortName; clears your search and browsing history when you quit the app or close all Private Browsing tabs and windows. While this doesn’t make you anonymous to websites or your internet service provider, it makes it easier to keep what you do online private from anyone else who uses this computer.">
-<!-- LOCALIZATION NOTE (aboutPrivateBrowsing.info.myths): This is a link to a SUMO article
-                       about private browsing myths.   -->
-<!ENTITY aboutPrivateBrowsing.info.myths                 "Common myths about private browsing">
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -472,17 +472,18 @@ identity.identified.state_and_country=%S
 identity.notSecure.label=Not Secure
 
 identity.icon.tooltip=Show site information
 identity.extension.label=Extension (%S)
 identity.extension.tooltip=Loaded by extension: %S
 identity.showDetails.tooltip=Show connection details
 
 contentBlocking.title=Content Blocking
-contentBlocking.tooltip=Open Content Blocking Preferences
+contentBlocking.tooltipWin=Open Content Blocking Options
+contentBlocking.tooltipOther=Open Content Blocking Preferences
 
 # LOCALIZATION NOTE (contentBlocking.category.*):
 # The terminology used to refer to levels of Content Blocking is also used
 # in preferences and should be translated consistently.
 # LOCALIZATION NOTE (contentBlocking.category.standard):
 # "Standard" in this case is an adjective, meaning "default" or "normal"
 contentBlocking.category.standard=Standard
 contentBlocking.category.strict=Strict
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -9,17 +9,17 @@
 
 [localization] @AB_CD@.jar:
   browser                                          (%browser/**/*.ftl)
 
 @AB_CD@.jar:
 % locale browser @AB_CD@ %locale/browser/
 # bookmarks.html is produced by LOCALIZED_GENERATED_FILES.
     locale/browser/bookmarks.html                  (bookmarks.html)
-    locale/browser/aboutPrivateBrowsing.dtd        (%chrome/browser/aboutPrivateBrowsing.dtd)
+
     locale/browser/accounts.properties             (%chrome/browser/accounts.properties)
     locale/browser/browser.dtd                     (%chrome/browser/browser.dtd)
     locale/browser/baseMenuOverlay.dtd             (%chrome/browser/baseMenuOverlay.dtd)
     locale/browser/browser.properties              (%chrome/browser/browser.properties)
     locale/browser/customizableui/customizableWidgets.properties (%chrome/browser/customizableui/customizableWidgets.properties)
     locale/browser/lightweightThemes.properties    (%chrome/browser/lightweightThemes.properties)
     locale/browser/uiDensity.properties            (%chrome/browser/uiDensity.properties)
     locale/browser/pocket.properties               (%chrome/browser/pocket.properties)
--- a/browser/themes/shared/incontentprefs/privacy.css
+++ b/browser/themes/shared/incontentprefs/privacy.css
@@ -13,16 +13,21 @@
 }
 
 .content-blocking-checkbox .checkbox-icon {
   margin-inline-end: 8px;
   margin-inline-start: 4px;
   width: 16px;
 }
 
+.content-blocking-category .checkbox-label-box {
+  -moz-context-properties: fill;
+  fill: currentColor;
+}
+
 #contentBlockingTrackingProtectionCheckbox > .checkbox-label-box {
   list-style-image: url("chrome://browser/skin/controlcenter/trackers.svg");
 }
 
 #contentBlockingTrackingProtectionCheckbox[checked] > .checkbox-label-box {
   list-style-image: url("chrome://browser/skin/controlcenter/trackers-disabled.svg");
 }
 
@@ -92,23 +97,21 @@
   margin-top: 10px;
 }
 
 #contentBlockingCategories {
   margin-top: 16px;
 }
 
 #trackingProtectionShield {
-  background-image: url("chrome://browser/skin/controlcenter/tracking-protection.svg");
+  list-style-image: url("chrome://browser/skin/controlcenter/tracking-protection.svg");
   -moz-context-properties: fill;
   fill: #737373;
   width: 64px;
   height: 64px;
-  background-repeat: no-repeat;
-  background-size: contain;
   margin-inline-end: 10px;
 }
 
 .content-blocking-category {
   border-radius: 4px;
   margin: 3px 0;
   padding: 9px;
   border: 1px solid #D7D7DB;
--- a/browser/themes/shared/urlbar-autocomplete.inc.css
+++ b/browser/themes/shared/urlbar-autocomplete.inc.css
@@ -115,54 +115,60 @@
   display: inline-block;
   vertical-align: text-bottom;
   overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis;
   max-width: calc(var(--item-content-width) * .7 - 2 * (16px + @urlbarViewIconMarginEnd@));
 }
 
-.urlbarView-secondary::before {
+.urlbarView-title-separator::before {
   content: "\2014";
   color: var(--panel-disabled-color);
   margin: 0 .4em;
 }
 
-.urlbarView-title:empty + .urlbarView-secondary::before {
+.urlbarView-title:empty + .urlbarView-title-separator {
   display: none;
 }
 
 .urlbarView-tags,
 .urlbarView-secondary {
   font-size: .85em;
 }
 
 .urlbarView-title > strong,
 .urlbarView-url > strong,
 .urlbarView-tag > strong {
   font-weight: 600;
 }
 
 .urlbarView-secondary {
+  display: inline-block;
   color: var(--urlbar-popup-action-color);
 }
 
 .urlbarView-url {
   color: var(--urlbar-popup-url-color);
 }
 
-.urlbarView-row[selected] > .urlbarView-row-inner > .urlbarView-secondary::before,
+.urlbarView-url:-moz-locale-dir(rtl) {
+  direction: ltr !important;
+}
+
+.urlbarView-row[selected] > .urlbarView-row-inner > .urlbarView-title-separator::before,
 .urlbarView-row[selected] > .urlbarView-row-inner > .urlbarView-secondary {
   color: inherit;
 }
 
 .urlbarView-row[type=remotetab][selected] > .urlbarView-row-inner > .urlbarView-action,
 .urlbarView-row[type=remotetab]:hover > .urlbarView-row-inner > .urlbarView-action,
 .urlbarView-row[type=remotetab]:not([selected]):not(:hover) > .urlbarView-row-inner > .urlbarView-url,
 .urlbarView-row[type=search]:not([selected]):not(:hover) > .urlbarView-row-inner > .urlbarView-action,
+.urlbarView-row[type=search]:not([selected]):not(:hover) > .urlbarView-row-inner > .urlbarView-title-separator,
 #urlbar-results[actionoverride] .urlbarView-row[type=switchtab] > .urlbarView-row-inner > .urlbarView-action,
 #urlbar-results:not([actionoverride]) .urlbarView-row[type=switchtab] > .urlbarView-row-inner > .urlbarView-url {
   display: none;
 }
 
 .urlbarView-tags {
   display: inline-block;
 }
--- a/build/moz.configure/init.configure
+++ b/build/moz.configure/init.configure
@@ -984,17 +984,16 @@ add_old_configure_assignment('HOST_OS_AR
 def target_is_windows(target):
     if target.kernel == 'WINNT':
         return True
 
 
 set_define('_WINDOWS', target_is_windows)
 set_define('WIN32', target_is_windows)
 set_define('XP_WIN', target_is_windows)
-set_define('XP_WIN32', target_is_windows)
 
 
 @depends(target)
 def target_is_unix(target):
     if target.kernel != 'WINNT':
         return True
 
 
--- a/build/moz.configure/rust.configure
+++ b/build/moz.configure/rust.configure
@@ -118,55 +118,61 @@ def rust_supported_targets(rustc):
     out = check_cmd_output(rustc, '--print', 'target-list').splitlines()
     # The os in the triplets used by rust may match the same OSes, in which
     # case we need to check the raw_os instead.
     per_os = {}
     ambiguous = set()
     per_raw_os = {}
     for t in out:
         t = split_triplet(t, allow_unknown=True)
-        key = (t.cpu, t.endianness, t.os)
+        endianness = t.endianness
+        if t.cpu.startswith('thumb') and endianness not in ('big', 'little'):
+            endianness = 'little'
+        key = (t.cpu, endianness, t.os)
         if key in per_os:
             previous = per_os[key]
             per_raw_os[(previous.cpu, previous.endianness,
                         previous.raw_os)] = previous
             del per_os[key]
             ambiguous.add(key)
         if key in ambiguous:
             raw_os = t.raw_os
             # split_triplet will return a raw_os of 'androideabi' for
             # rust targets in the form cpu-linux-androideabi, but what
             # we get from the build system is linux-androideabi, so
             # normalize.
             if raw_os == 'androideabi':
                 raw_os = 'linux-androideabi'
-            per_raw_os[(t.cpu, t.endianness, raw_os)] = t
+            per_raw_os[(t.cpu, endianness, raw_os)] = t
         else:
             per_os[key] = t
     return namespace(per_os=per_os, per_raw_os=per_raw_os)
 
 
 @template
 def rust_triple_alias(host_or_target):
     """Template defining the alias used for rustc's --target flag.
     `host_or_target` is either `host` or `target` (the @depends functions
     from init.configure).
     """
     assert host_or_target in {host, target}
 
+    host_or_target_str = {host: 'host', target: 'target'}[host_or_target]
+
     @depends(rustc, host_or_target, c_compiler, rust_supported_targets,
-             when=rust_compiler)
+             arm_target, when=rust_compiler)
+    @checking('for rust %s triplet' % host_or_target_str)
     @imports('os')
     @imports('subprocess')
     @imports(_from='mozbuild.configure.util', _import='LineIO')
     @imports(_from='mozbuild.shellutil', _import='quote')
     @imports(_from='tempfile', _import='mkstemp')
     @imports(_from='textwrap', _import='dedent')
     def rust_target(rustc, host_or_target, compiler_info,
-                    rust_supported_targets):
+                    rust_supported_targets, arm_target):
         # Rust's --target options are similar to, but not exactly the same
         # as, the autoconf-derived targets we use.  An example would be that
         # Rust uses distinct target triples for targetting the GNU C++ ABI
         # and the MSVC C++ ABI on Win32, whereas autoconf has a single
         # triple and relies on the user to ensure that everything is
         # compiled for the appropriate ABI.  We need to perform appropriate
         # munging to get the correct option to rustc.
         # We correlate the autoconf-derived targets with the list of targets
@@ -176,23 +182,33 @@ def rust_triple_alias(host_or_target):
                 host_or_target_os = 'windows-gnu'
             else:
                 host_or_target_os = 'windows-msvc'
             host_or_target_raw_os = host_or_target_os
         else:
             host_or_target_os = host_or_target.os
             host_or_target_raw_os = host_or_target.raw_os
 
-        rustc_target = rust_supported_targets.per_os.get(
-            (host_or_target.cpu, host_or_target.endianness, host_or_target_os))
+        if host_or_target.cpu == 'arm' and arm_target.arm_arch == 7 and \
+                arm_target.fpu == 'neon' and arm_target.thumb2:
+            host_or_target_cpus = ('thumbv7neon', host_or_target.cpu)
+        else:
+            host_or_target_cpus = (host_or_target.cpu,)
 
-        if rustc_target is None:
+        for host_or_target_cpu in host_or_target_cpus:
+            rustc_target = rust_supported_targets.per_os.get(
+                (host_or_target_cpu, host_or_target.endianness, host_or_target_os))
+            if rustc_target:
+                break
+
             rustc_target = rust_supported_targets.per_raw_os.get(
-                (host_or_target.cpu, host_or_target.endianness,
+                (host_or_target_cpu, host_or_target.endianness,
                  host_or_target_raw_os))
+            if rustc_target:
+                break
 
         if rustc_target is None:
             die("Don't know how to translate {} for rustc".format(
                 host_or_target.alias))
 
         # Check to see whether our rustc has a reasonably functional stdlib
         # for our chosen target.
         target_arg = '--target=' + rustc_target.alias
--- a/devtools/client/debugger/new/dist/debugger.css
+++ b/devtools/client/debugger/new/dist/debugger.css
@@ -4071,17 +4071,17 @@ html[dir="rtl"] .object-node {
 .objectLink-regexp,
 .objectLink-object,
 .objectLink-Date,
 .theme-dark .objectBox-object,
 .theme-light .objectBox-object {
   white-space: nowrap;
 }
 
-.scopes-pane {
+.scopes-pane ._content {
   overflow: auto;
 }
 
 .scopes-list .function-signature {
   display: inline-block;
 }
 
 .scopes-list .scope-type-toggle {
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Scopes.css
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Scopes.css
@@ -47,17 +47,17 @@ html[dir="rtl"] .object-node {
 .objectLink-regexp,
 .objectLink-object,
 .objectLink-Date,
 .theme-dark .objectBox-object,
 .theme-light .objectBox-object {
   white-space: nowrap;
 }
 
-.scopes-pane {
+.scopes-pane ._content {
   overflow: auto;
 }
 
 .scopes-list .function-signature {
   display: inline-block;
 }
 
 .scopes-list .scope-type-toggle {
--- a/devtools/client/netmonitor/src/reducers/timing-markers.js
+++ b/devtools/client/netmonitor/src/reducers/timing-markers.js
@@ -1,27 +1,39 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {
+  ADD_REQUEST,
   ADD_TIMING_MARKER,
   CLEAR_TIMING_MARKERS,
   CLEAR_REQUESTS,
 } = require("../constants");
 
 function TimingMarkers() {
   return {
     firstDocumentDOMContentLoadedTimestamp: -1,
     firstDocumentLoadTimestamp: -1,
+    firstDocumentRequestStartTimestamp: +Infinity,
   };
 }
 
+function addRequest(state, action) {
+  const nextState = { ...state };
+  const { startedMillis } = action.data;
+  if (startedMillis < state.firstDocumentRequestStartTimestamp) {
+    nextState.firstDocumentRequestStartTimestamp = startedMillis;
+  }
+
+  return nextState;
+}
+
 function addTimingMarker(state, action) {
   state = { ...state };
 
   if (action.marker.name === "dom-interactive" &&
       state.firstDocumentDOMContentLoadedTimestamp === -1) {
     state.firstDocumentDOMContentLoadedTimestamp = action.marker.time;
     return state;
   }
@@ -36,16 +48,19 @@ function addTimingMarker(state, action) 
 }
 
 function clearTimingMarkers(state) {
   return new TimingMarkers();
 }
 
 function timingMarkers(state = new TimingMarkers(), action) {
   switch (action.type) {
+    case ADD_REQUEST:
+      return addRequest(state, action);
+
     case ADD_TIMING_MARKER:
       return addTimingMarker(state, action);
 
     case CLEAR_REQUESTS:
     case CLEAR_TIMING_MARKERS:
       return clearTimingMarkers(state);
 
     default:
--- a/devtools/client/netmonitor/src/selectors/timing-markers.js
+++ b/devtools/client/netmonitor/src/selectors/timing-markers.js
@@ -5,14 +5,14 @@
 "use strict";
 
 function getDisplayedTimingMarker(state, marker) {
   const value = state.timingMarkers[marker];
   if (value == -1) {
     return value;
   }
 
-  return value - state.requests.firstStartedMillis;
+  return value - state.timingMarkers.firstDocumentRequestStartTimestamp;
 }
 
 module.exports = {
   getDisplayedTimingMarker,
 };
--- a/devtools/server/actors/source.js
+++ b/devtools/server/actors/source.js
@@ -287,31 +287,29 @@ const SourceActor = ActorClassWithSpec(s
         column: startColumn = 0,
       } = {},
       end: {
         line: endLine = Infinity,
         column: endColumn = Infinity,
       } = {},
     } = query || {};
 
-    let scripts;
-    if (Number.isFinite(endLine)) {
-      const found = new Set();
-      for (let line = startLine; line <= endLine; line++) {
-        for (const script of this._findDebuggeeScripts({ line })) {
-          found.add(script);
-        }
-      }
-      scripts = Array.from(found);
-    } else {
-      scripts = this._findDebuggeeScripts();
-    }
+    const scripts = this._findDebuggeeScripts();
 
     const positions = [];
     for (const script of scripts) {
+      // This purely a performance boost to avoid needing to build an array
+      // of breakable points for scripts when we know we don't need it.
+      if (
+        script.startLine > endLine ||
+        script.startLine + script.lineCount < startLine
+      ) {
+        continue;
+      }
+
       const offsets = script.getPossibleBreakpoints();
       for (const { lineNumber, columnNumber } of offsets) {
         if (
           lineNumber < startLine ||
           (lineNumber === startLine && columnNumber < startColumn) ||
           lineNumber > endLine ||
           (lineNumber === endLine && columnNumber > endColumn)
         ) {
--- a/docshell/test/chrome/chrome.ini
+++ b/docshell/test/chrome/chrome.ini
@@ -52,21 +52,23 @@ support-files =
 [test_bug112564.xul]
 [test_bug113934.xul]
 [test_bug215405.xul]
 [test_bug293235.xul]
 skip-if = true # bug 1393441
 [test_bug294258.xul]
 [test_bug298622.xul]
 [test_bug301397.xul]
+skip-if = (os == 'win' && processor == 'aarch64') # bug 1533819
 [test_bug303267.xul]
 [test_bug311007.xul]
 [test_bug321671.xul]
 [test_bug360511.xul]
 [test_bug364461.xul]
+skip-if = (os == 'win' && processor == 'aarch64') # bug 1533814
 [test_bug396519.xul]
 [test_bug396649.xul]
 [test_bug428288.html]
 [test_bug449778.xul]
 [test_bug449780.xul]
 [test_bug453650.xul]
 [test_bug454235.xul]
 [test_bug456980.xul]
--- a/dom/animation/EffectCompositor.cpp
+++ b/dom/animation/EffectCompositor.cpp
@@ -145,25 +145,18 @@ bool FindAnimationsForCompositor(
       effects->PropertiesForAnimationsLevel().Intersects(aPropertySet)) {
     return false;
   }
 
   AnimationPerformanceWarning::Type warning =
       AnimationPerformanceWarning::Type::None;
   if (!EffectCompositor::AllowCompositorAnimationsOnFrame(aFrame, warning)) {
     if (warning != AnimationPerformanceWarning::Type::None) {
-      // FIXME: Bug 1425837: We should set performance warning by a property set
-      // and write some test cases for this.
-      for (nsCSSPropertyID property : COMPOSITOR_ANIMATABLE_PROPERTY_LIST) {
-        if (!aPropertySet.HasProperty(property)) {
-          continue;
-        }
-        EffectCompositor::SetPerformanceWarning(
-            aFrame, property, AnimationPerformanceWarning(warning));
-      }
+      EffectCompositor::SetPerformanceWarning(
+          aFrame, aPropertySet, AnimationPerformanceWarning(warning));
     }
     return false;
   }
 
   // The animation cascade will almost always be up-to-date by this point
   // but there are some cases such as when we are restoring the refresh driver
   // from test control after seeking where it might not be the case.
   //
@@ -182,25 +175,18 @@ bool FindAnimationsForCompositor(
   bool foundRunningAnimations = false;
   for (KeyframeEffect* effect : *effects) {
     AnimationPerformanceWarning::Type effectWarning =
         AnimationPerformanceWarning::Type::None;
     KeyframeEffect::MatchForCompositor matchResult =
         effect->IsMatchForCompositor(aPropertySet, aFrame, *effects,
                                      effectWarning);
     if (effectWarning != AnimationPerformanceWarning::Type::None) {
-      // FIXME: Bug 1425837: We should set performance warning by a property set
-      // and write some test cases for this.
-      for (nsCSSPropertyID property : COMPOSITOR_ANIMATABLE_PROPERTY_LIST) {
-        if (!aPropertySet.HasProperty(property)) {
-          continue;
-        }
-        EffectCompositor::SetPerformanceWarning(
-            aFrame, property, AnimationPerformanceWarning(effectWarning));
-      }
+      EffectCompositor::SetPerformanceWarning(
+          aFrame, aPropertySet, AnimationPerformanceWarning(effectWarning));
     }
 
     if (matchResult ==
         KeyframeEffect::MatchForCompositor::NoAndBlockThisProperty) {
       // For a given |aFrame|, we don't want some animations of |aPropertySet|
       // to run on the compositor and others to run on the main thread, so if
       // any need to be synchronized with the main thread, run them all there.
       if (aMatches) {
@@ -401,18 +387,17 @@ class EffectCompositeOrderComparator {
             b->GetAnimation()->HasLowerCompositeOrderThan(*a->GetAnimation()));
     return a->GetAnimation()->HasLowerCompositeOrderThan(*b->GetAnimation());
   }
 };
 }  // namespace
 
 bool EffectCompositor::GetServoAnimationRule(
     const dom::Element* aElement, PseudoStyleType aPseudoType,
-    CascadeLevel aCascadeLevel,
-    RawServoAnimationValueMapBorrowedMut aAnimationValues) {
+    CascadeLevel aCascadeLevel, RawServoAnimationValueMap* aAnimationValues) {
   MOZ_ASSERT(aAnimationValues);
   MOZ_ASSERT(mPresContext && mPresContext->IsDynamic(),
              "Should not be in print preview");
   // Gecko_GetAnimationRule should have already checked this
   MOZ_ASSERT(nsContentUtils::GetPresShellForContent(aElement),
              "Should not be trying to run animations on elements in documents"
              " without a pres shell (e.g. XMLHttpRequest documents)");
 
@@ -704,26 +689,25 @@ void EffectCompositor::UpdateCascadeResu
     presContext->EffectCompositor()->RequestRestyle(
         aElement, aPseudoType, restyleType,
         EffectCompositor::CascadeLevel::Transitions);
   }
 }
 
 /* static */
 void EffectCompositor::SetPerformanceWarning(
-    const nsIFrame* aFrame, nsCSSPropertyID aProperty,
+    const nsIFrame* aFrame, const nsCSSPropertyIDSet& aPropertySet,
     const AnimationPerformanceWarning& aWarning) {
-  EffectSet* effects =
-      EffectSet::GetEffectSetForFrame(aFrame, nsCSSPropertyIDSet{aProperty});
+  EffectSet* effects = EffectSet::GetEffectSetForFrame(aFrame, aPropertySet);
   if (!effects) {
     return;
   }
 
   for (KeyframeEffect* effect : *effects) {
-    effect->SetPerformanceWarning(aProperty, aWarning);
+    effect->SetPerformanceWarning(aPropertySet, aWarning);
   }
 }
 
 bool EffectCompositor::PreTraverse(ServoTraversalFlags aFlags) {
   return PreTraverseInSubtree(aFlags, nullptr);
 }
 
 bool EffectCompositor::PreTraverseInSubtree(ServoTraversalFlags aFlags,
--- a/dom/animation/EffectCompositor.h
+++ b/dom/animation/EffectCompositor.h
@@ -20,17 +20,16 @@
 #include "nsTArray.h"
 
 class nsCSSPropertyIDSet;
 class nsAtom;
 class nsIFrame;
 class nsPresContext;
 enum class DisplayItemType : uint32_t;
 struct RawServoAnimationValueMap;
-typedef RawServoAnimationValueMap* RawServoAnimationValueMapBorrowedMut;
 
 namespace mozilla {
 
 class ComputedStyle;
 class EffectSet;
 class RestyleTracker;
 class StyleAnimationValue;
 struct AnimationProperty;
@@ -113,23 +112,23 @@ class EffectCompositor {
   // animation effects (e.g. em-based endpoints used in keyframe effects)
   // can be re-resolved to computed values.
   void UpdateEffectProperties(const ComputedStyle* aStyle,
                               dom::Element* aElement,
                               PseudoStyleType aPseudoType);
 
   // Get animation rule for stylo. This is an equivalent of GetAnimationRule
   // and will be called from servo side.
-  // The animation rule is stored in |RawServoAnimationValueMapBorrowed|.
+  // The animation rule is stored in |RawServoAnimationValueMap|.
   // We need to be careful while doing any modification because it may cause
   // some thread-safe issues.
-  bool GetServoAnimationRule(
-      const dom::Element* aElement, PseudoStyleType aPseudoType,
-      CascadeLevel aCascadeLevel,
-      RawServoAnimationValueMapBorrowedMut aAnimationValues);
+  bool GetServoAnimationRule(const dom::Element* aElement,
+                             PseudoStyleType aPseudoType,
+                             CascadeLevel aCascadeLevel,
+                             RawServoAnimationValueMap* aAnimationValues);
 
   bool HasPendingStyleUpdates() const;
 
   static bool HasAnimationsForCompositor(const nsIFrame* aFrame,
                                          DisplayItemType aType);
 
   static nsTArray<RefPtr<dom::Animation>> GetAnimationsForCompositor(
       const nsIFrame* aFrame, const nsCSSPropertyIDSet& aPropertySet);
@@ -178,19 +177,19 @@ class EffectCompositor {
   //
   // Returns an empty result when a suitable element cannot be found including
   // when the frame represents a pseudo-element on which we do not support
   // animations.
   static Maybe<NonOwningAnimationTarget> GetAnimationElementAndPseudoForFrame(
       const nsIFrame* aFrame);
 
   // Associates a performance warning with effects on |aFrame| that animate
-  // |aProperty|.
+  // properties in |aPropertySet|.
   static void SetPerformanceWarning(
-      const nsIFrame* aFrame, nsCSSPropertyID aProperty,
+      const nsIFrame* aFrame, const nsCSSPropertyIDSet& aPropertySet,
       const AnimationPerformanceWarning& aWarning);
 
   // Do a bunch of stuff that we should avoid doing during the parallel
   // traversal (e.g. changing member variables) for all elements that we expect
   // to restyle on the next traversal.
   //
   // Returns true if there are elements needing a restyle for animation.
   bool PreTraverse(ServoTraversalFlags aFlags);
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -32,16 +32,32 @@
 #include "nsDOMMutationObserver.h"  // For nsAutoAnimationMutationBatch
 #include "nsIFrame.h"
 #include "nsIPresShell.h"
 #include "nsIScriptError.h"
 #include "nsRefreshDriver.h"
 
 namespace mozilla {
 
+void AnimationProperty::SetPerformanceWarning(
+    const AnimationPerformanceWarning& aWarning, const Element* aElement) {
+  if (mPerformanceWarning && *mPerformanceWarning == aWarning) {
+    return;
+  }
+
+  mPerformanceWarning = Some(aWarning);
+
+  nsAutoString localizedString;
+  if (nsLayoutUtils::IsAnimationLoggingEnabled() &&
+      mPerformanceWarning->ToLocalizedString(localizedString)) {
+    nsAutoCString logMessage = NS_ConvertUTF16toUTF8(localizedString);
+    AnimationUtils::LogAsyncAnimationFailure(logMessage, aElement);
+  }
+}
+
 bool PropertyValuePair::operator==(const PropertyValuePair& aOther) const {
   if (mProperty != aOther.mProperty) {
     return false;
   }
   if (mServoDeclarationBlock == aOther.mServoDeclarationBlock) {
     return true;
   }
   if (!mServoDeclarationBlock || !aOther.mServoDeclarationBlock) {
@@ -490,17 +506,19 @@ void KeyframeEffect::WillComposeStyle() 
   mCurrentIterationOnLastCompose = computedTiming.mCurrentIteration;
 }
 
 void KeyframeEffect::ComposeStyleRule(
     RawServoAnimationValueMap& aAnimationValues,
     const AnimationProperty& aProperty,
     const AnimationPropertySegment& aSegment,
     const ComputedTiming& aComputedTiming) {
-  Servo_AnimationCompose(&aAnimationValues, &mBaseValues, aProperty.mProperty,
+  auto* opaqueTable =
+      reinterpret_cast<RawServoAnimationValueTable*>(&mBaseValues);
+  Servo_AnimationCompose(&aAnimationValues, opaqueTable, aProperty.mProperty,
                          &aSegment, &aProperty.mSegments.LastElement(),
                          &aComputedTiming, mEffectOptions.mIterationComposite);
 }
 
 void KeyframeEffect::ComposeStyle(RawServoAnimationValueMap& aComposeResult,
                                   const nsCSSPropertyIDSet& aPropertiesToSkip) {
   ComputedTiming computedTiming = GetComputedTiming();
 
@@ -1507,29 +1525,26 @@ bool KeyframeEffect::HasGeometricPropert
       return true;
     }
   }
 
   return false;
 }
 
 void KeyframeEffect::SetPerformanceWarning(
-    nsCSSPropertyID aProperty, const AnimationPerformanceWarning& aWarning) {
+    const nsCSSPropertyIDSet& aPropertySet,
+    const AnimationPerformanceWarning& aWarning) {
+  nsCSSPropertyIDSet curr = aPropertySet;
   for (AnimationProperty& property : mProperties) {
-    if (property.mProperty == aProperty &&
-        (!property.mPerformanceWarning ||
-         *property.mPerformanceWarning != aWarning)) {
-      property.mPerformanceWarning = Some(aWarning);
-
-      nsAutoString localizedString;
-      if (nsLayoutUtils::IsAnimationLoggingEnabled() &&
-          property.mPerformanceWarning->ToLocalizedString(localizedString)) {
-        nsAutoCString logMessage = NS_ConvertUTF16toUTF8(localizedString);
-        AnimationUtils::LogAsyncAnimationFailure(logMessage, mTarget->mElement);
-      }
+    if (!curr.HasProperty(property.mProperty)) {
+      continue;
+    }
+    property.SetPerformanceWarning(aWarning, mTarget->mElement);
+    curr.RemoveProperty(property.mProperty);
+    if (curr.IsEmpty()) {
       return;
     }
   }
 }
 
 already_AddRefed<ComputedStyle>
 KeyframeEffect::CreateComputedStyleForAnimationValue(
     nsCSSPropertyID aProperty, const AnimationValue& aValue,
--- a/dom/animation/KeyframeEffect.h
+++ b/dom/animation/KeyframeEffect.h
@@ -93,16 +93,19 @@ struct AnimationProperty {
   // the mIsRunningOnCompositor will not have been set on the new objects so
   // we ignore this member to avoid generating spurious change records.
   bool operator==(const AnimationProperty& aOther) const {
     return mProperty == aOther.mProperty && mSegments == aOther.mSegments;
   }
   bool operator!=(const AnimationProperty& aOther) const {
     return !(*this == aOther);
   }
+
+  void SetPerformanceWarning(const AnimationPerformanceWarning& aWarning,
+                             const Element* aElement);
 };
 
 struct ElementPropertyTransition;
 
 namespace dom {
 
 class Animation;
 class Document;
@@ -277,21 +280,21 @@ class KeyframeEffect : public AnimationE
   bool HasGeometricProperties() const;
   bool AffectsGeometry() const override {
     return GetTarget() && HasGeometricProperties();
   }
 
   Document* GetRenderedDocument() const;
   nsIPresShell* GetPresShell() const;
 
-  // Associates a warning with the animated property on the specified frame
+  // Associates a warning with the animated property set on the specified frame
   // indicating why, for example, the property could not be animated on the
   // compositor. |aParams| and |aParamsLength| are optional parameters which
   // will be used to generate a localized message for devtools.
-  void SetPerformanceWarning(nsCSSPropertyID aProperty,
+  void SetPerformanceWarning(const nsCSSPropertyIDSet& aPropertySet,
                              const AnimationPerformanceWarning& aWarning);
 
   // Cumulative change hint on each segment for each property.
   // This is used for deciding the animation is paint-only.
   void CalculateCumulativeChangeHint(const ComputedStyle* aStyle);
 
   // Returns true if all of animation properties' change hints
   // can ignore painting if the animation is not visible.
--- a/dom/animation/test/chrome/test_animation_performance_warning.html
+++ b/dom/animation/test/chrome/test_animation_performance_warning.html
@@ -160,16 +160,33 @@ function testBasicOperation() {
         },
         {
           property: 'transform',
           runningOnCompositor: true
         }
       ]
     },
     {
+      desc: 'two transform-like animation properties on compositor thread',
+      frames: {
+        transform: ['translate(0px)', 'translate(100px)'],
+        translate: ['0px', '100px']
+      },
+      expected: [
+        {
+          property: 'transform',
+          runningOnCompositor: true
+        },
+        {
+          property: 'translate',
+          runningOnCompositor: true
+        }
+      ]
+    },
+    {
       desc: 'opacity on compositor with animation of geometric properties',
       frames: {
         width: ['100px', '200px'],
         opacity: [0, 1]
       },
       expected: [
         {
           property: 'width',
@@ -217,45 +234,80 @@ function testKeyframesWithGeometricPrope
             property: 'transform',
             runningOnCompositor: false,
             warning: 'CompositorAnimationWarningTransformWithGeometricProperties'
           }
         ]
       }
     },
     {
-      desc: 'opacity and transform',
+      desc: 'translate',
+      frames: {
+        translate: ['0px', '100px']
+      },
+      expected: {
+        withoutGeometric: [
+          {
+            property: 'translate',
+            runningOnCompositor: true
+          }
+        ],
+        withGeometric: [
+          {
+            property: 'width',
+            runningOnCompositor: false
+          },
+          {
+            property: 'translate',
+            runningOnCompositor: false,
+            warning: 'CompositorAnimationWarningTransformWithGeometricProperties'
+          }
+        ]
+      }
+    },
+    {
+      desc: 'opacity and transform-like properties',
       frames: {
         opacity: [0, 1],
-        transform: ['translate(0px)', 'translate(100px)']
+        transform: ['translate(0px)', 'translate(100px)'],
+        translate: ['0px', '100px']
       },
       expected: {
         withoutGeometric: [
           {
             property: 'opacity',
             runningOnCompositor: true
           },
           {
             property: 'transform',
             runningOnCompositor: true
+          },
+          {
+            property: 'translate',
+            runningOnCompositor: true
           }
         ],
         withGeometric: [
           {
             property: 'width',
             runningOnCompositor: false
           },
           {
             property: 'opacity',
             runningOnCompositor: true
           },
           {
             property: 'transform',
             runningOnCompositor: false,
             warning: 'CompositorAnimationWarningTransformWithGeometricProperties'
+          },
+          {
+            property: 'translate',
+            runningOnCompositor: false,
+            warning: 'CompositorAnimationWarningTransformWithGeometricProperties'
           }
         ]
       }
     },
   ].forEach(subtest => {
     promise_test(async t => {
       var animation = addDivAndAnimate(t, { class: 'compositable' },
                                        subtest.frames, 100 * MS_PER_SEC);
@@ -348,64 +400,105 @@ function testStyleChanges() {
         {
           property: 'transform',
           runningOnCompositor: false,
           warning: 'CompositorAnimationWarningTransformPreserve3D'
         }
       ]
     },
     {
+      desc: 'preserve-3d translate',
+      frames: {
+        translate: ['0px', '100px']
+      },
+      style: 'transform-style: preserve-3d',
+      expected: [
+        {
+          property: 'translate',
+          runningOnCompositor: false,
+          warning: 'CompositorAnimationWarningTransformPreserve3D'
+        }
+      ]
+    },
+    {
       desc: 'transform with backface-visibility:hidden',
       frames: {
         transform: ['translate(0px)', 'translate(100px)']
       },
       style: 'backface-visibility: hidden;',
       expected: [
         {
           property: 'transform',
           runningOnCompositor: false,
           warning: 'CompositorAnimationWarningTransformBackfaceVisibilityHidden'
         }
       ]
     },
     {
-      desc: 'opacity and transform with preserve-3d',
+      desc: 'translate with backface-visibility:hidden',
+      frames: {
+        translate: ['0px', '100px']
+      },
+      style: 'backface-visibility: hidden;',
+      expected: [
+        {
+          property: 'translate',
+          runningOnCompositor: false,
+          warning: 'CompositorAnimationWarningTransformBackfaceVisibilityHidden'
+        }
+      ]
+    },
+    {
+      desc: 'opacity and transform-like properties with preserve-3d',
       frames: {
         opacity: [0, 1],
-        transform: ['translate(0px)', 'translate(100px)']
+        transform: ['translate(0px)', 'translate(100px)'],
+        translate: ['0px', '100px']
       },
       style: 'transform-style: preserve-3d',
       expected: [
         {
           property: 'opacity',
           runningOnCompositor: true
         },
         {
           property: 'transform',
           runningOnCompositor: false,
           warning: 'CompositorAnimationWarningTransformPreserve3D'
+        },
+        {
+          property: 'translate',
+          runningOnCompositor: false,
+          warning: 'CompositorAnimationWarningTransformPreserve3D'
         }
       ]
     },
     {
-      desc: 'opacity and transform with backface-visibility:hidden',
+      desc: 'opacity and transform-like properties with ' +
+            'backface-visibility:hidden',
       frames: {
         opacity: [0, 1],
-        transform: ['translate(0px)', 'translate(100px)']
+        transform: ['translate(0px)', 'translate(100px)'],
+        translate: ['0px', '100px']
       },
       style: 'backface-visibility: hidden;',
       expected: [
         {
           property: 'opacity',
           runningOnCompositor: true
         },
         {
           property: 'transform',
           runningOnCompositor: false,
           warning: 'CompositorAnimationWarningTransformBackfaceVisibilityHidden'
+        },
+        {
+          property: 'translate',
+          runningOnCompositor: false,
+          warning: 'CompositorAnimationWarningTransformBackfaceVisibilityHidden'
         }
       ]
     },
   ].forEach(subtest => {
     promise_test(async t => {
       var animation = addDivAndAnimate(t, { class: 'compositable' },
                                        subtest.frames, 100 * MS_PER_SEC);
       await waitForPaints();
@@ -441,16 +534,52 @@ function testIdChanges() {
       expected: [
         {
           property: 'transform',
           runningOnCompositor: false,
           warning: 'CompositorAnimationWarningHasRenderingObserver'
         }
       ]
     },
+    {
+      desc: 'moz-element referencing a translate',
+      frames: {
+        translate: ['0px', '100px']
+      },
+      id: 'transformed',
+      createelement: 'width:100px; height:100px; background: -moz-element(#transformed)',
+      expected: [
+        {
+          property: 'translate',
+          runningOnCompositor: false,
+          warning: 'CompositorAnimationWarningHasRenderingObserver'
+        }
+      ]
+    },
+    {
+      desc: 'moz-element referencing a translate and transform',
+      frames: {
+        transform: ['translate(0px)', 'translate(100px)'],
+        translate: ['0px', '100px']
+      },
+      id: 'transformed',
+      createelement: 'width:100px; height:100px; background: -moz-element(#transformed)',
+      expected: [
+        {
+          property: 'translate',
+          runningOnCompositor: false,
+          warning: 'CompositorAnimationWarningHasRenderingObserver'
+        },
+        {
+          property: 'transform',
+          runningOnCompositor: false,
+          warning: 'CompositorAnimationWarningHasRenderingObserver'
+        }
+      ]
+    },
   ].forEach(subtest => {
     promise_test(async t => {
       if (subtest.createelement) {
         addDiv(t, { style: subtest.createelement });
       }
 
       var animation = addDivAndAnimate(t, { class: 'compositable' },
                                        subtest.frames, 100 * MS_PER_SEC);
@@ -473,62 +602,87 @@ function testIdChanges() {
         subtest.expected);
     }, subtest.desc);
   });
 }
 
 function testMultipleAnimations() {
   [
     {
-      desc: 'opacity and transform with preserve-3d',
+      desc: 'opacity and transform-like properties with preserve-3d',
       style: 'transform-style: preserve-3d',
       animations: [
         {
           frames: {
             transform: ['translate(0px)', 'translate(100px)']
           },
           expected: [
             {
               property: 'transform',
               runningOnCompositor: false,
               warning: 'CompositorAnimationWarningTransformPreserve3D'
             }
           ]
         },
         {
           frames: {
+            translate: ['0px', '100px']
+          },
+          expected: [
+            {
+              property: 'translate',
+              runningOnCompositor: false,
+              warning: 'CompositorAnimationWarningTransformPreserve3D'
+            }
+          ]
+        },
+        {
+          frames: {
             opacity: [0, 1]
           },
           expected: [
             {
               property: 'opacity',
               runningOnCompositor: true,
             }
           ]
         }
       ],
     },
     {
-      desc: 'opacity and transform with backface-visibility:hidden',
+      desc: 'opacity and transform-like properties with ' +
+            'backface-visibility:hidden',
       style: 'backface-visibility: hidden;',
       animations: [
         {
           frames: {
             transform: ['translate(0px)', 'translate(100px)']
           },
           expected: [
             {
               property: 'transform',
               runningOnCompositor: false,
               warning: 'CompositorAnimationWarningTransformBackfaceVisibilityHidden'
             }
           ]
         },
         {
           frames: {
+            translate: ['0px', '100px']
+          },
+          expected: [
+            {
+              property: 'translate',
+              runningOnCompositor: false,
+              warning: 'CompositorAnimationWarningTransformBackfaceVisibilityHidden'
+            }
+          ]
+        },
+        {
+          frames: {
             opacity: [0, 1]
           },
           expected: [
             {
               property: 'opacity',
               runningOnCompositor: true,
             }
           ]
@@ -668,16 +822,64 @@ function testMultipleAnimationsWithGeome
                 runningOnCompositor: false,
                 warning: 'CompositorAnimationWarningTransformWithGeometricProperties'
               }
             ]
           }
         }
       ]
     },
+    {
+      desc: 'opacity and translate with geometric keyframes',
+      animations: [
+        {
+          frames: {
+            opacity: [0, 1]
+          },
+          expected: {
+            withoutGeometric: [
+              {
+                property: 'opacity',
+                runningOnCompositor: true,
+              }
+            ],
+            withGeometric: [
+              {
+                property: 'opacity',
+                runningOnCompositor: true,
+              }
+            ]
+          }
+        },
+        {
+          frames: {
+            translate: ['0px', '100px']
+          },
+          expected: {
+            withoutGeometric: [
+              {
+                property: 'translate',
+                runningOnCompositor: true
+              }
+            ],
+            withGeometric: [
+              {
+                property: 'width',
+                runningOnCompositor: false,
+              },
+              {
+                property: 'translate',
+                runningOnCompositor: false,
+                warning: 'CompositorAnimationWarningTransformWithGeometricProperties'
+              }
+            ]
+          }
+        }
+      ]
+    },
   ].forEach(subtest => {
     promise_test(async t => {
       var div = addDiv(t, { class: 'compositable' });
       var animations = subtest.animations.map(anim => {
         var animation = div.animate(anim.frames, 100 * MS_PER_SEC);
 
         // Bind expected values to animation object.
         animation.expected = anim.expected;
@@ -744,48 +946,77 @@ function testMultipleAnimationsWithGeome
               runningOnCompositor: false,
               warning: 'CompositorAnimationWarningTransformWithGeometricProperties'
             }
           ]
         },
       ]
     },
     {
+      desc: 'translate',
+      animations: [
+        {
+          frames: {
+            translate: ['0px', '100px']
+          },
+          expected: [
+            {
+              property: 'translate',
+              runningOnCompositor: false,
+              warning: 'CompositorAnimationWarningTransformWithGeometricProperties'
+            }
+          ]
+        },
+      ]
+    },
+    {
       desc: 'opacity',
       animations: [
         {
           frames: {
             opacity: [0, 1]
           },
           expected: [
             {
               property: 'opacity',
               runningOnCompositor: true
             }
           ]
         },
       ]
     },
     {
-      desc: 'opacity and transform',
+      desc: 'opacity, transform, and translate',
       animations: [
         {
           frames: {
             transform: ['translate(0px)', 'translate(100px)']
           },
           expected: [
             {
               property: 'transform',
               runningOnCompositor: false,
               warning: 'CompositorAnimationWarningTransformWithGeometricProperties'
             }
           ]
         },
         {
           frames: {
+            translate: ['0px', '100px']
+          },
+          expected: [
+            {
+              property: 'translate',
+              runningOnCompositor: false,
+              warning: 'CompositorAnimationWarningTransformWithGeometricProperties'
+            }
+          ]
+        },
+        {
+          frames: {
             opacity: [0, 1]
           },
           expected: [
             {
               property: 'opacity',
               runningOnCompositor: true,
             }
           ]
@@ -868,16 +1099,29 @@ function testSmallElements() {
       style: { style: 'width: 8px; height: 8px; background-color: red;' },
       expected: [
         {
           property: 'transform',
           runningOnCompositor: true
         }
       ]
     },
+    {
+      desc: 'translate on small element',
+      frames: {
+        translate: ['0px', '100px']
+      },
+      style: { style: 'width: 8px; height: 8px; background-color: red;' },
+      expected: [
+        {
+          property: 'translate',
+          runningOnCompositor: true
+        }
+      ]
+    },
   ].forEach(subtest => {
     promise_test(async t => {
     var div = addDiv(t, subtest.style);
     var animation = div.animate(subtest.frames, 100 * MS_PER_SEC);
     await waitForPaints();
 
     assert_animation_property_state_equals(
       animation.effect.getProperties(),
@@ -906,33 +1150,75 @@ function testSynchronizedAnimations() {
           warning: 'CompositorAnimationWarningTransformWithSyncGeometricAnimations'
       } ]);
   }, 'Animations created within the same tick are synchronized'
      + ' (compositor animation created first)');
 
   promise_test(async t => {
     const elemA = addDiv(t, { class: 'compositable' });
     const elemB = addDiv(t, { class: 'compositable' });
+    const elemC = addDiv(t, { class: 'compositable' });
+
+    const animA = elemA.animate({ transform: [ 'translate(0px)',
+                                               'translate(100px)' ] },
+                                100 * MS_PER_SEC);
+    const animB = elemB.animate({ translate: [ '0px', '100px' ] },
+                                100 * MS_PER_SEC);
+    const animC = elemC.animate({ marginLeft: [ '0px', '100px' ] },
+                                100 * MS_PER_SEC);
+
+    await waitForPaints();
+
+    assert_animation_property_state_equals(
+      animA.effect.getProperties(),
+      [
+        { property: 'transform',
+          runningOnCompositor: false,
+          warning: 'CompositorAnimationWarningTransformWithSyncGeometricAnimations'
+      } ]);
+    assert_animation_property_state_equals(
+      animB.effect.getProperties(),
+      [
+        { property: 'translate',
+          runningOnCompositor: false,
+          warning: 'CompositorAnimationWarningTransformWithSyncGeometricAnimations'
+      } ]);
+  }, 'Animations created within the same tick are synchronized'
+     + ' (compositor animation created first/second)');
+
+  promise_test(async t => {
+    const elemA = addDiv(t, { class: 'compositable' });
+    const elemB = addDiv(t, { class: 'compositable' });
+    const elemC = addDiv(t, { class: 'compositable' });
 
     const animA = elemA.animate({ marginLeft: [ '0px', '100px' ] },
                                 100 * MS_PER_SEC);
     const animB = elemB.animate({ transform: [ 'translate(0px)',
                                                'translate(100px)' ] },
                                 100 * MS_PER_SEC);
+    const animC = elemC.animate({ translate: [ '0px', '100px' ] },
+                                100 * MS_PER_SEC);
 
     await waitForPaints();
 
     assert_animation_property_state_equals(
       animB.effect.getProperties(),
       [ { property: 'transform',
           runningOnCompositor: false,
           warning: 'CompositorAnimationWarningTransformWithSyncGeometricAnimations'
       } ]);
+    assert_animation_property_state_equals(
+      animC.effect.getProperties(),
+      [
+        { property: 'translate',
+          runningOnCompositor: false,
+          warning: 'CompositorAnimationWarningTransformWithSyncGeometricAnimations'
+      } ]);
   }, 'Animations created within the same tick are synchronized'
-     + ' (compositor animation created second)');
+     + ' (compositor animation created second/third)');
 
   promise_test(async t => {
     const attrs = { class: 'compositable',
                     style: 'transition: all 100s' };
     const elemA = addDiv(t, attrs);
     const elemB = addDiv(t, attrs);
     elemA.style.transform = 'translate(0px)';
     elemB.style.marginLeft = '0px';
@@ -1154,158 +1440,191 @@ function testSynchronizedAnimations() {
 
     assert_animation_property_state_equals(
       animA.effect.getProperties(),
       [ { property: 'transform',
           runningOnCompositor: true } ]);
   }, 'A geometric animation with no target element is not synchronized');
 }
 
+function testTooLargeFrame() {
+  [
+    {
+      property: 'transform',
+      frames: { transform: ['translate(0px)', 'translate(100px)'] },
+    },
+    {
+      property: 'translate',
+      frames: { translate: ['0px', '100px'] },
+    },
+  ].forEach(subtest => {
+    promise_test(async t => {
+      var animation = addDivAndAnimate(t,
+                                       { class: 'compositable' },
+                                       subtest.frames,
+                                       100 * MS_PER_SEC);
+      await waitForPaints();
+
+      assert_animation_property_state_equals(
+        animation.effect.getProperties(),
+        [ { property: subtest.property, runningOnCompositor: true } ]);
+      animation.effect.target.style = 'width: 10000px; height: 10000px';
+      await waitForFrame();
+
+      // viewport depends on test environment.
+      const isWebRender =
+        SpecialPowers.DOMWindowUtils.layerManagerType == 'WebRender';
+      var expectedWarning = new RegExp(
+        "Animation cannot be run on the compositor because the area of the frame " +
+        "\\(\\d+\\) is too large relative to the viewport " +
+        "\\(larger than \\d+\\)");
+      if (isWebRender) {
+        // With WebRender, the large size frame could run on compositor.
+        assert_animation_property_state_equals(
+          animation.effect.getProperties(),
+          [ { property: subtest.property, runningOnCompositor: true } ]);
+      } else {
+        assert_animation_property_state_equals(
+          animation.effect.getProperties(),
+          [ {
+            property: subtest.property,
+            runningOnCompositor: false,
+            warning: expectedWarning
+          } ]);
+      }
+      animation.effect.target.style = 'width: 100px; height: 100px';
+      await waitForFrame();
+
+      assert_animation_property_state_equals(
+        animation.effect.getProperties(),
+        [ { property: subtest.property, runningOnCompositor: true } ]);
+    }, subtest.property + ' on too big element - area');
+
+    promise_test(async t => {
+      var animation = addDivAndAnimate(t,
+                                       { class: 'compositable' },
+                                       subtest.frames,
+                                       100 * MS_PER_SEC);
+      await waitForPaints();
+
+      assert_animation_property_state_equals(
+        animation.effect.getProperties(),
+        [ { property: subtest.property, runningOnCompositor: true } ]);
+      animation.effect.target.style = 'width: 20000px; height: 1px';
+      await waitForFrame();
+
+      // viewport depends on test environment.
+      const isWebRender =
+        SpecialPowers.DOMWindowUtils.layerManagerType == 'WebRender';
+      var expectedWarning = new RegExp(
+        "Animation cannot be run on the compositor because the frame size " +
+        "\\(20000, 1\\) is too large relative to the viewport " +
+        "\\(larger than \\(\\d+, \\d+\\)\\) or larger than the " +
+        "maximum allowed value \\(\\d+, \\d+\\)");
+      if (isWebRender) {
+        // With WebRender, the large size frame could run on compositor.
+        assert_animation_property_state_equals(
+          animation.effect.getProperties(),
+          [ { property: subtest.property, runningOnCompositor: true } ]);
+      } else {
+        assert_animation_property_state_equals(
+          animation.effect.getProperties(),
+          [ {
+            property: subtest.property,
+            runningOnCompositor: false,
+            warning: expectedWarning
+          } ]);
+      }
+      animation.effect.target.style = 'width: 100px; height: 100px';
+      await waitForFrame();
+
+      assert_animation_property_state_equals(
+        animation.effect.getProperties(),
+        [ { property: subtest.property, runningOnCompositor: true } ]);
+    }, subtest.property + ' on too big element - dimensions');
+  });
+}
+
+function testTransformSVG() {
+  [
+    {
+      property: 'transform',
+      frames: { transform: ['translate(0px)', 'translate(100px)'] },
+    },
+    {
+      property: 'translate',
+      frames: { translate: ['0px', '100px'] },
+    },
+    {
+      property: 'rotate',
+      frames: { rotate: ['0deg', '45deg'] },
+    },
+    {
+      property: 'scale',
+      frames: { scale: ['1', '2'] },
+    },
+  ].forEach(subtest => {
+    promise_test(async t => {
+      var svg  = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
+      svg.setAttribute('width', '100');
+      svg.setAttribute('height', '100');
+      var rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
+      rect.setAttribute('width', '100');
+      rect.setAttribute('height', '100');
+      rect.setAttribute('fill', 'red');
+      svg.appendChild(rect);
+      document.body.appendChild(svg);
+      t.add_cleanup(() => {
+        svg.remove();
+      });
+
+      var animation = svg.animate(subtest.frames, 100 * MS_PER_SEC);
+      await waitForPaints();
+
+      assert_animation_property_state_equals(
+        animation.effect.getProperties(),
+        [ { property: subtest.property, runningOnCompositor: true } ]);
+      svg.setAttribute('transform', 'translate(10, 20)');
+      await waitForFrame();
+
+      assert_animation_property_state_equals(
+        animation.effect.getProperties(),
+        [ {
+          property: subtest.property,
+          runningOnCompositor: false,
+          warning: 'CompositorAnimationWarningTransformSVG'
+        } ]);
+      svg.removeAttribute('transform');
+      await waitForFrame();
+
+      assert_animation_property_state_equals(
+        animation.effect.getProperties(),
+        [ { property: subtest.property, runningOnCompositor: true } ]);
+    }, subtest.property + ' of nsIFrame with SVG transform');
+  });
+}
+
 function start() {
   var bundleService = SpecialPowers.Cc['@mozilla.org/intl/stringbundle;1']
     .getService(SpecialPowers.Ci.nsIStringBundleService);
   gStringBundle = bundleService
     .createBundle("chrome://global/locale/layout_errors.properties");
 
   testBasicOperation();
   testKeyframesWithGeometricProperties();
   testSetOfGeometricProperties();
   testStyleChanges();
   testIdChanges();
   testMultipleAnimations();
   testMultipleAnimationsWithGeometricKeyframes();
   testMultipleAnimationsWithGeometricAnimations();
   testSmallElements();
   testSynchronizedAnimations();
-
-  promise_test(async t => {
-    var animation = addDivAndAnimate(t,
-                                     { class: 'compositable' },
-                                     { transform: [ 'translate(0px)',
-                                                    'translate(100px)'] },
-                                     100 * MS_PER_SEC);
-    await waitForPaints();
-
-    assert_animation_property_state_equals(
-      animation.effect.getProperties(),
-      [ { property: 'transform', runningOnCompositor: true } ]);
-    animation.effect.target.style = 'width: 10000px; height: 10000px';
-    await waitForFrame();
-
-    // viewport depends on test environment.
-    const isWebRender =
-      SpecialPowers.DOMWindowUtils.layerManagerType == 'WebRender';
-    var expectedWarning = new RegExp(
-      "Animation cannot be run on the compositor because the area of the frame " +
-      "\\(\\d+\\) is too large relative to the viewport " +
-      "\\(larger than \\d+\\)");
-    if (isWebRender) {
-      // With WebRender, the large size frame could run on compositor.
-      assert_animation_property_state_equals(
-        animation.effect.getProperties(),
-        [ { property: 'transform', runningOnCompositor: true } ]);
-    } else {
-      assert_animation_property_state_equals(
-        animation.effect.getProperties(),
-        [ {
-          property: 'transform',
-          runningOnCompositor: false,
-          warning: expectedWarning
-        } ]);
-    }
-    animation.effect.target.style = 'width: 100px; height: 100px';
-    await waitForFrame();
-
-    assert_animation_property_state_equals(
-      animation.effect.getProperties(),
-      [ { property: 'transform', runningOnCompositor: true } ]);
-  }, 'transform on too big element - area');
-
-  promise_test(async t => {
-    var animation = addDivAndAnimate(t,
-                                     { class: 'compositable' },
-                                     { transform: [ 'translate(0px)',
-                                                    'translate(100px)'] },
-                                     100 * MS_PER_SEC);
-    await waitForPaints();
-
-    assert_animation_property_state_equals(
-      animation.effect.getProperties(),
-      [ { property: 'transform', runningOnCompositor: true } ]);
-    animation.effect.target.style = 'width: 20000px; height: 1px';
-    await waitForFrame();
-
-    // viewport depends on test environment.
-    const isWebRender =
-      SpecialPowers.DOMWindowUtils.layerManagerType == 'WebRender';
-    var expectedWarning = new RegExp(
-      "Animation cannot be run on the compositor because the frame size " +
-      "\\(20000, 1\\) is too large relative to the viewport " +
-      "\\(larger than \\(\\d+, \\d+\\)\\) or larger than the " +
-      "maximum allowed value \\(\\d+, \\d+\\)");
-    if (isWebRender) {
-      // With WebRender, the large size frame could run on compositor.
-      assert_animation_property_state_equals(
-        animation.effect.getProperties(),
-        [ { property: 'transform', runningOnCompositor: true } ]);
-    } else {
-      assert_animation_property_state_equals(
-        animation.effect.getProperties(),
-        [ {
-          property: 'transform',
-          runningOnCompositor: false,
-          warning: expectedWarning
-        } ]);
-    }
-    animation.effect.target.style = 'width: 100px; height: 100px';
-    await waitForFrame();
-
-    assert_animation_property_state_equals(
-      animation.effect.getProperties(),
-      [ { property: 'transform', runningOnCompositor: true } ]);
-  }, 'transform on too big element - dimensions');
-
-  promise_test(async t => {
-    var svg  = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
-    svg.setAttribute('width', '100');
-    svg.setAttribute('height', '100');
-    var rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
-    rect.setAttribute('width', '100');
-    rect.setAttribute('height', '100');
-    rect.setAttribute('fill', 'red');
-    svg.appendChild(rect);
-    document.body.appendChild(svg);
-    t.add_cleanup(() => {
-      svg.remove();
-    });
-
-    var animation = svg.animate(
-      { transform: ['translate(0px)', 'translate(100px)'] }, 100 * MS_PER_SEC);
-    await waitForPaints();
-
-    assert_animation_property_state_equals(
-      animation.effect.getProperties(),
-      [ { property: 'transform', runningOnCompositor: true } ]);
-    svg.setAttribute('transform', 'translate(10, 20)');
-    await waitForFrame();
-
-    assert_animation_property_state_equals(
-      animation.effect.getProperties(),
-      [ {
-        property: 'transform',
-        runningOnCompositor: false,
-        warning: 'CompositorAnimationWarningTransformSVG'
-      } ]);
-    svg.removeAttribute('transform');
-    await waitForFrame();
-
-    assert_animation_property_state_equals(
-      animation.effect.getProperties(),
-      [ { property: 'transform', runningOnCompositor: true } ]);
-  }, 'transform of nsIFrame with SVG transform');
+  testTooLargeFrame();
+  testTransformSVG();
 
   promise_test(async t => {
     var div = addDiv(t, { class: 'compositable',
                           style: 'animation: fade 100s' });
     var cssAnimation = div.getAnimations()[0];
     var scriptAnimation = div.animate({ opacity: [ 1, 0 ] }, 100 * MS_PER_SEC);
 
     await waitForPaints();
--- a/dom/base/DOMMatrix.cpp
+++ b/dom/base/DOMMatrix.cpp
@@ -645,17 +645,17 @@ DOMMatrixReadOnly* DOMMatrixReadOnly::Se
   // An empty string is a no-op.
   if (aTransformList.IsEmpty()) {
     return this;
   }
 
   gfx::Matrix4x4 transform;
   bool contains3dTransform = false;
   if (!ServoCSSParser::ParseTransformIntoMatrix(
-          aTransformList, contains3dTransform, transform.components)) {
+          aTransformList, contains3dTransform, transform)) {
     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
     return nullptr;
   }
 
   if (!contains3dTransform) {
     mMatrix3D = nullptr;
     mMatrix2D = new gfx::Matrix();
 
--- a/dom/cache/AutoUtils.cpp
+++ b/dom/cache/AutoUtils.cpp
@@ -15,38 +15,38 @@
 #include "mozilla/dom/cache/SavedTypes.h"
 #include "mozilla/dom/cache/StreamList.h"
 #include "mozilla/dom/cache/TypeUtils.h"
 #include "mozilla/ipc/IPCStreamUtils.h"
 #include "mozilla/ipc/PBackgroundParent.h"
 #include "nsCRT.h"
 #include "nsHttp.h"
 
+using mozilla::Maybe;
 using mozilla::Unused;
 using mozilla::dom::cache::CacheReadStream;
-using mozilla::dom::cache::CacheReadStreamOrVoid;
 using mozilla::ipc::AutoIPCStream;
 using mozilla::ipc::PBackgroundParent;
 
 namespace {
 
 enum CleanupAction { Forget, Delete };
 
 void CleanupChild(CacheReadStream& aReadStream, CleanupAction aAction) {
   // fds cleaned up by mStreamCleanupList
   // PChildToParentStream actors cleaned up by mStreamCleanupList
 }
 
-void CleanupChild(CacheReadStreamOrVoid& aReadStreamOrVoid,
+void CleanupChild(Maybe<CacheReadStream>& aMaybeReadStream,
                   CleanupAction aAction) {
-  if (aReadStreamOrVoid.type() == CacheReadStreamOrVoid::Tvoid_t) {
+  if (aMaybeReadStream.isNothing()) {
     return;
   }
 
-  CleanupChild(aReadStreamOrVoid.get_CacheReadStream(), aAction);
+  CleanupChild(aMaybeReadStream.ref(), aAction);
 }
 
 }  // namespace
 
 namespace mozilla {
 namespace dom {
 namespace cache {
 
@@ -78,20 +78,20 @@ AutoChildOpArgs::~AutoChildOpArgs() {
   switch (mOpArgs.type()) {
     case CacheOpArgs::TCacheMatchArgs: {
       CacheMatchArgs& args = mOpArgs.get_CacheMatchArgs();
       CleanupChild(args.request().body(), action);
       break;
     }
     case CacheOpArgs::TCacheMatchAllArgs: {
       CacheMatchAllArgs& args = mOpArgs.get_CacheMatchAllArgs();
-      if (args.requestOrVoid().type() == CacheRequestOrVoid::Tvoid_t) {
+      if (args.maybeRequest().isNothing()) {
         break;
       }
-      CleanupChild(args.requestOrVoid().get_CacheRequest().body(), action);
+      CleanupChild(args.maybeRequest().ref().body(), action);
       break;
     }
     case CacheOpArgs::TCachePutAllArgs: {
       CachePutAllArgs& args = mOpArgs.get_CachePutAllArgs();
       auto& list = args.requestResponseList();
       for (uint32_t i = 0; i < list.Length(); ++i) {
         CleanupChild(list[i].request().body(), action);
         CleanupChild(list[i].response().body(), action);
@@ -100,20 +100,20 @@ AutoChildOpArgs::~AutoChildOpArgs() {
     }
     case CacheOpArgs::TCacheDeleteArgs: {
       CacheDeleteArgs& args = mOpArgs.get_CacheDeleteArgs();
       CleanupChild(args.request().body(), action);
       break;
     }
     case CacheOpArgs::TCacheKeysArgs: {
       CacheKeysArgs& args = mOpArgs.get_CacheKeysArgs();
-      if (args.requestOrVoid().type() == CacheRequestOrVoid::Tvoid_t) {
+      if (args.maybeRequest().isNothing()) {
         break;
       }
-      CleanupChild(args.requestOrVoid().get_CacheRequest().body(), action);
+      CleanupChild(args.maybeRequest().ref().body(), action);
       break;
     }
     case CacheOpArgs::TStorageMatchArgs: {
       StorageMatchArgs& args = mOpArgs.get_StorageMatchArgs();
       CleanupChild(args.request().body(), action);
       break;
     }
     default:
@@ -132,38 +132,36 @@ void AutoChildOpArgs::Add(InternalReques
     case CacheOpArgs::TCacheMatchArgs: {
       CacheMatchArgs& args = mOpArgs.get_CacheMatchArgs();
       mTypeUtils->ToCacheRequest(args.request(), aRequest, aBodyAction,
                                  aSchemeAction, mStreamCleanupList, aRv);
       break;
     }
     case CacheOpArgs::TCacheMatchAllArgs: {
       CacheMatchAllArgs& args = mOpArgs.get_CacheMatchAllArgs();
-      MOZ_DIAGNOSTIC_ASSERT(args.requestOrVoid().type() ==
-                            CacheRequestOrVoid::Tvoid_t);
-      args.requestOrVoid() = CacheRequest();
-      mTypeUtils->ToCacheRequest(args.requestOrVoid().get_CacheRequest(),
-                                 aRequest, aBodyAction, aSchemeAction,
-                                 mStreamCleanupList, aRv);
+      MOZ_DIAGNOSTIC_ASSERT(args.maybeRequest().isNothing());
+      args.maybeRequest().emplace(CacheRequest());
+      mTypeUtils->ToCacheRequest(args.maybeRequest().ref(), aRequest,
+                                 aBodyAction, aSchemeAction, mStreamCleanupList,
+                                 aRv);
       break;
     }
     case CacheOpArgs::TCacheDeleteArgs: {
       CacheDeleteArgs& args = mOpArgs.get_CacheDeleteArgs();
       mTypeUtils->ToCacheRequest(args.request(), aRequest, aBodyAction,
                                  aSchemeAction, mStreamCleanupList, aRv);
       break;
     }
     case CacheOpArgs::TCacheKeysArgs: {
       CacheKeysArgs& args = mOpArgs.get_CacheKeysArgs();
-      MOZ_DIAGNOSTIC_ASSERT(args.requestOrVoid().type() ==
-                            CacheRequestOrVoid::Tvoid_t);
-      args.requestOrVoid() = CacheRequest();
-      mTypeUtils->ToCacheRequest(args.requestOrVoid().get_CacheRequest(),
-                                 aRequest, aBodyAction, aSchemeAction,
-                                 mStreamCleanupList, aRv);
+      MOZ_DIAGNOSTIC_ASSERT(args.maybeRequest().isNothing());
+      args.maybeRequest().emplace(CacheRequest());
+      mTypeUtils->ToCacheRequest(args.maybeRequest().ref(), aRequest,
+                                 aBodyAction, aSchemeAction, mStreamCleanupList,
+                                 aRv);
       break;
     }
     case CacheOpArgs::TStorageMatchArgs: {
       StorageMatchArgs& args = mOpArgs.get_StorageMatchArgs();
       mTypeUtils->ToCacheRequest(args.request(), aRequest, aBodyAction,
                                  aSchemeAction, mStreamCleanupList, aRv);
       break;
     }
@@ -292,18 +290,18 @@ void AutoChildOpArgs::Add(JSContext* aCx
       // The FileDescriptorSetChild asserts in its destructor that all fds have
       // been removed.  The copy constructor, however, simply duplicates the
       // fds without removing any.  This means each temporary and copy must be
       // explicitly cleaned up.
       //
       // Avoid a lot of this hassle by making sure we only create one here.  On
       // error we remove it.
       CacheRequestResponse& pair = *args.requestResponseList().AppendElement();
-      pair.request().body() = void_t();
-      pair.response().body() = void_t();
+      pair.request().body() = Nothing();
+      pair.response().body() = Nothing();
 
       mTypeUtils->ToCacheRequest(pair.request(), aRequest, aBodyAction,
                                  aSchemeAction, mStreamCleanupList, aRv);
       if (!aRv.Failed()) {
         mTypeUtils->ToCacheResponse(aCx, pair.response(), aResponse,
                                     mStreamCleanupList, aRv);
       }
 
@@ -392,21 +390,20 @@ void AutoParentOpResult::Add(CacheId aOp
 
 void AutoParentOpResult::Add(const SavedResponse& aSavedResponse,
                              StreamList* aStreamList) {
   MOZ_DIAGNOSTIC_ASSERT(!mSent);
 
   switch (mOpResult.type()) {
     case CacheOpResult::TCacheMatchResult: {
       CacheMatchResult& result = mOpResult.get_CacheMatchResult();
-      MOZ_DIAGNOSTIC_ASSERT(result.responseOrVoid().type() ==
-                            CacheResponseOrVoid::Tvoid_t);
-      result.responseOrVoid() = aSavedResponse.mValue;
+      MOZ_DIAGNOSTIC_ASSERT(result.maybeResponse().isNothing());
+      result.maybeResponse().emplace(aSavedResponse.mValue);
       SerializeResponseBody(aSavedResponse, aStreamList,
-                            &result.responseOrVoid().get_CacheResponse());
+                            &result.maybeResponse().ref());
       break;
     }
     case CacheOpResult::TCacheMatchAllResult: {
       CacheMatchAllResult& result = mOpResult.get_CacheMatchAllResult();
       // Ensure that we don't realloc the array since this can result
       // in our AutoIPCStream objects to reference the wrong memory
       // location.  This should never happen and is a UAF if it does.
       // Therefore make this a release assertion.
@@ -414,21 +411,20 @@ void AutoParentOpResult::Add(const Saved
                          result.responseList().Capacity());
       result.responseList().AppendElement(aSavedResponse.mValue);
       SerializeResponseBody(aSavedResponse, aStreamList,
                             &result.responseList().LastElement());
       break;
     }
     case CacheOpResult::TStorageMatchResult: {
       StorageMatchResult& result = mOpResult.get_StorageMatchResult();
-      MOZ_DIAGNOSTIC_ASSERT(result.responseOrVoid().type() ==
-                            CacheResponseOrVoid::Tvoid_t);
-      result.responseOrVoid() = aSavedResponse.mValue;
+      MOZ_DIAGNOSTIC_ASSERT(result.maybeResponse().isNothing());
+      result.maybeResponse().emplace(aSavedResponse.mValue);
       SerializeResponseBody(aSavedResponse, aStreamList,
-                            &result.responseOrVoid().get_CacheResponse());
+                            &result.maybeResponse().ref());
       break;
     }
     default:
       MOZ_CRASH("Cache result type cannot handle returning a Response!");
   }
 }
 
 void AutoParentOpResult::Add(const SavedRequest& aSavedRequest,
@@ -443,23 +439,23 @@ void AutoParentOpResult::Add(const Saved
       // location.  This should never happen and is a UAF if it does.
       // Therefore make this a release assertion.
       MOZ_RELEASE_ASSERT(result.requestList().Length() <
                          result.requestList().Capacity());
       result.requestList().AppendElement(aSavedRequest.mValue);
       CacheRequest& request = result.requestList().LastElement();
 
       if (!aSavedRequest.mHasBodyId) {
-        request.body() = void_t();
+        request.body() = Nothing();
         break;
       }
 
-      request.body() = CacheReadStream();
+      request.body().emplace(CacheReadStream());
       SerializeReadStream(aSavedRequest.mBodyId, aStreamList,
-                          &request.body().get_CacheReadStream());
+                          &request.body().ref());
       break;
     }
     default:
       MOZ_CRASH("Cache result type cannot handle returning a Request!");
   }
 }
 
 const CacheOpResult& AutoParentOpResult::SendAsOpResult() {
@@ -472,23 +468,23 @@ const CacheOpResult& AutoParentOpResult:
 }
 
 void AutoParentOpResult::SerializeResponseBody(
     const SavedResponse& aSavedResponse, StreamList* aStreamList,
     CacheResponse* aResponseOut) {
   MOZ_DIAGNOSTIC_ASSERT(aResponseOut);
 
   if (!aSavedResponse.mHasBodyId) {
-    aResponseOut->body() = void_t();
+    aResponseOut->body() = Nothing();
     return;
   }
 
-  aResponseOut->body() = CacheReadStream();
+  aResponseOut->body().emplace(CacheReadStream());
   SerializeReadStream(aSavedResponse.mBodyId, aStreamList,
-                      &aResponseOut->body().get_CacheReadStream());
+                      &aResponseOut->body().ref());
 }
 
 void AutoParentOpResult::SerializeReadStream(const nsID& aId,
                                              StreamList* aStreamList,
                                              CacheReadStream* aReadStreamOut) {
   MOZ_DIAGNOSTIC_ASSERT(aStreamList);
   MOZ_DIAGNOSTIC_ASSERT(aReadStreamOut);
   MOZ_DIAGNOSTIC_ASSERT(!mSent);
--- a/dom/cache/Cache.cpp
+++ b/dom/cache/Cache.cpp
@@ -287,18 +287,18 @@ already_AddRefed<Promise> Cache::MatchAl
     return nullptr;
   }
 
   CacheChild::AutoLock actorLock(mActor);
 
   CacheQueryParams params;
   ToCacheQueryParams(params, aOptions);
 
-  AutoChildOpArgs args(this, CacheMatchAllArgs(void_t(), params, GetOpenMode()),
-                       1);
+  AutoChildOpArgs args(this,
+                       CacheMatchAllArgs(Nothing(), params, GetOpenMode()), 1);
 
   if (aRequest.WasPassed()) {
     RefPtr<InternalRequest> ir =
         ToInternalRequest(aCx, aRequest.Value(), IgnoreBody, aRv);
     if (aRv.Failed()) {
       return nullptr;
     }
 
@@ -463,17 +463,18 @@ already_AddRefed<Promise> Cache::Keys(
     return nullptr;
   }
 
   CacheChild::AutoLock actorLock(mActor);
 
   CacheQueryParams params;
   ToCacheQueryParams(params, aOptions);
 
-  AutoChildOpArgs args(this, CacheKeysArgs(void_t(), params, GetOpenMode()), 1);
+  AutoChildOpArgs args(this, CacheKeysArgs(Nothing(), params, GetOpenMode()),
+                       1);
 
   if (aRequest.WasPassed()) {
     RefPtr<InternalRequest> ir =
         ToInternalRequest(aCx, aRequest.Value(), IgnoreBody, aRv);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
 
--- a/dom/cache/CacheOpChild.cpp
+++ b/dom/cache/CacheOpChild.cpp
@@ -31,34 +31,32 @@ void AddWorkerHolderToStreamChild(const 
     cacheControl->SetWorkerHolder(aWorkerHolder);
   }
 }
 
 void AddWorkerHolderToStreamChild(const CacheResponse& aResponse,
                                   CacheWorkerHolder* aWorkerHolder) {
   MOZ_ASSERT_IF(!NS_IsMainThread(), aWorkerHolder);
 
-  if (aResponse.body().type() == CacheReadStreamOrVoid::Tvoid_t) {
+  if (aResponse.body().isNothing()) {
     return;
   }
 
-  AddWorkerHolderToStreamChild(aResponse.body().get_CacheReadStream(),
-                               aWorkerHolder);
+  AddWorkerHolderToStreamChild(aResponse.body().ref(), aWorkerHolder);
 }
 
 void AddWorkerHolderToStreamChild(const CacheRequest& aRequest,
                                   CacheWorkerHolder* aWorkerHolder) {
   MOZ_ASSERT_IF(!NS_IsMainThread(), aWorkerHolder);
 
-  if (aRequest.body().type() == CacheReadStreamOrVoid::Tvoid_t) {
+  if (aRequest.body().isNothing()) {
     return;
   }
 
-  AddWorkerHolderToStreamChild(aRequest.body().get_CacheReadStream(),
-                               aWorkerHolder);
+  AddWorkerHolderToStreamChild(aRequest.body().ref(), aWorkerHolder);
 }
 
 }  // namespace
 
 CacheOpChild::CacheOpChild(CacheWorkerHolder* aWorkerHolder,
                            nsIGlobalObject* aGlobal, nsISupports* aParent,
                            Promise* aPromise)
     : mGlobal(aGlobal), mParent(aParent), mPromise(aPromise) {
@@ -103,17 +101,17 @@ mozilla::ipc::IPCResult CacheOpChild::Re
     // and is thrown into the trash afterwards.
     mPromise->MaybeReject(const_cast<ErrorResult&>(aRv));
     mPromise = nullptr;
     return IPC_OK();
   }
 
   switch (aResult.type()) {
     case CacheOpResult::TCacheMatchResult: {
-      HandleResponse(aResult.get_CacheMatchResult().responseOrVoid());
+      HandleResponse(aResult.get_CacheMatchResult().maybeResponse());
       break;
     }
     case CacheOpResult::TCacheMatchAllResult: {
       HandleResponseList(aResult.get_CacheMatchAllResult().responseList());
       break;
     }
     case CacheOpResult::TCachePutAllResult: {
       mPromise->MaybeResolveWithUndefined();
@@ -123,17 +121,17 @@ mozilla::ipc::IPCResult CacheOpChild::Re
       mPromise->MaybeResolve(aResult.get_CacheDeleteResult().success());
       break;
     }
     case CacheOpResult::TCacheKeysResult: {
       HandleRequestList(aResult.get_CacheKeysResult().requestList());
       break;
     }
     case CacheOpResult::TStorageMatchResult: {
-      HandleResponse(aResult.get_StorageMatchResult().responseOrVoid());
+      HandleResponse(aResult.get_StorageMatchResult().maybeResponse());
       break;
     }
     case CacheOpResult::TStorageHasResult: {
       mPromise->MaybeResolve(aResult.get_StorageHasResult().success());
       break;
     }
     case CacheOpResult::TStorageOpenResult: {
       auto result = aResult.get_StorageOpenResult();
@@ -189,23 +187,23 @@ void CacheOpChild::AssertOwningThread() 
   NS_ASSERT_OWNINGTHREAD(CacheOpChild);
 }
 #endif
 
 PBackgroundChild* CacheOpChild::GetIPCManager() {
   MOZ_CRASH("CacheOpChild does not implement TypeUtils::GetIPCManager()");
 }
 
-void CacheOpChild::HandleResponse(const CacheResponseOrVoid& aResponseOrVoid) {
-  if (aResponseOrVoid.type() == CacheResponseOrVoid::Tvoid_t) {
+void CacheOpChild::HandleResponse(const Maybe<CacheResponse>& aMaybeResponse) {
+  if (aMaybeResponse.isNothing()) {
     mPromise->MaybeResolveWithUndefined();
     return;
   }
 
-  const CacheResponse& cacheResponse = aResponseOrVoid.get_CacheResponse();
+  const CacheResponse& cacheResponse = aMaybeResponse.ref();
 
   AddWorkerHolderToStreamChild(cacheResponse, GetWorkerHolder());
   RefPtr<Response> response = ToResponse(cacheResponse);
 
   mPromise->MaybeResolve(response);
 }
 
 void CacheOpChild::HandleResponseList(
--- a/dom/cache/CacheOpChild.h
+++ b/dom/cache/CacheOpChild.h
@@ -49,17 +49,17 @@ class CacheOpChild final : public PCache
 
 #ifdef DEBUG
   virtual void AssertOwningThread() const override;
 #endif
 
   virtual mozilla::ipc::PBackgroundChild* GetIPCManager() override;
 
   // Utility methods
-  void HandleResponse(const CacheResponseOrVoid& aResponseOrVoid);
+  void HandleResponse(const Maybe<CacheResponse>& aMaybeResponse);
 
   void HandleResponseList(const nsTArray<CacheResponse>& aResponseList);
 
   void HandleRequestList(const nsTArray<CacheRequest>& aRequestList);
 
   nsCOMPtr<nsIGlobalObject> mGlobal;
   // Hold the parent Cache or CacheStorage object alive until this async
   // operation completes.
--- a/dom/cache/CacheOpParent.cpp
+++ b/dom/cache/CacheOpParent.cpp
@@ -180,23 +180,23 @@ void CacheOpParent::OnOpComplete(
   for (uint32_t i = 0; i < aSavedRequestList.Length(); ++i) {
     result.Add(aSavedRequestList[i], aStreamList);
   }
 
   Unused << Send__delete__(this, aRv, result.SendAsOpResult());
 }
 
 already_AddRefed<nsIInputStream> CacheOpParent::DeserializeCacheStream(
-    const CacheReadStreamOrVoid& aStreamOrVoid) {
-  if (aStreamOrVoid.type() == CacheReadStreamOrVoid::Tvoid_t) {
+    const Maybe<CacheReadStream>& aMaybeStream) {
+  if (aMaybeStream.isNothing()) {
     return nullptr;
   }
 
   nsCOMPtr<nsIInputStream> stream;
-  const CacheReadStream& readStream = aStreamOrVoid.get_CacheReadStream();
+  const CacheReadStream& readStream = aMaybeStream.ref();
 
   // Option 1: One of our own ReadStreams was passed back to us with a stream
   //           control actor.
   stream = ReadStream::Create(readStream);
   if (stream) {
     return stream.forget();
   }
 
--- a/dom/cache/CacheOpParent.h
+++ b/dom/cache/CacheOpParent.h
@@ -50,17 +50,17 @@ class CacheOpParent final : public PCach
   virtual void OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
                             CacheId aOpenedCacheId,
                             const nsTArray<SavedResponse>& aSavedResponseList,
                             const nsTArray<SavedRequest>& aSavedRequestList,
                             StreamList* aStreamList) override;
 
   // utility methods
   already_AddRefed<nsIInputStream> DeserializeCacheStream(
-      const CacheReadStreamOrVoid& aStreamOrVoid);
+      const Maybe<CacheReadStream>& aMaybeStream);
 
   mozilla::ipc::PBackgroundParent* mIpcManager;
   const CacheId mCacheId;
   const Namespace mNamespace;
   const CacheOpArgs mOpArgs;
   RefPtr<cache::Manager> mManager;
   RefPtr<PrincipalVerifier> mVerifier;
 
--- a/dom/cache/CacheTypes.ipdlh
+++ b/dom/cache/CacheTypes.ipdlh
@@ -36,22 +36,16 @@ struct CacheQueryParams
 
 struct CacheReadStream
 {
   nsID id;
   nullable PCacheStreamControl control;
   IPCStream? stream;
 };
 
-union CacheReadStreamOrVoid
-{
-  void_t;
-  CacheReadStream;
-};
-
 struct HeadersEntry
 {
   nsCString name;
   nsCString value;
 };
 struct CacheRequest
 {
   nsCString method;
@@ -59,66 +53,54 @@ struct CacheRequest
   nsCString urlQuery;
   nsCString urlFragment;
   HeadersEntry[] headers;
   HeadersGuardEnum headersGuard;
   nsString referrer;
   ReferrerPolicy referrerPolicy;
   RequestMode mode;
   RequestCredentials credentials;
-  CacheReadStreamOrVoid body;
+  CacheReadStream? body;
   uint32_t contentPolicyType;
   RequestCache requestCache;
   RequestRedirect requestRedirect;
   nsString integrity;
 };
 
-union CacheRequestOrVoid
-{
-  void_t;
-  CacheRequest;
-};
-
 struct CacheResponse
 {
   ResponseType type;
   nsCString[] urlList;
   uint32_t status;
   nsCString statusText;
   HeadersEntry[] headers;
   HeadersGuardEnum headersGuard;
-  CacheReadStreamOrVoid body;
+  CacheReadStream? body;
   IPCChannelInfo channelInfo;
   PrincipalInfo? principalInfo;
   uint32_t paddingInfo;
   int64_t paddingSize;
 };
 
-union CacheResponseOrVoid
-{
-  void_t;
-  CacheResponse;
-};
-
 struct CacheRequestResponse
 {
   CacheRequest request;
   CacheResponse response;
 };
 
 struct CacheMatchArgs
 {
   CacheRequest request;
   CacheQueryParams params;
   OpenMode openMode;
 };
 
 struct CacheMatchAllArgs
 {
-  CacheRequestOrVoid requestOrVoid;
+  CacheRequest? maybeRequest;
   CacheQueryParams params;
   OpenMode openMode;
 };
 
 struct CachePutAllArgs
 {
   CacheRequestResponse[] requestResponseList;
 };
@@ -126,17 +108,17 @@ struct CachePutAllArgs
 struct CacheDeleteArgs
 {
   CacheRequest request;
   CacheQueryParams params;
 };
 
 struct CacheKeysArgs
 {
-  CacheRequestOrVoid requestOrVoid;
+  CacheRequest? maybeRequest;
   CacheQueryParams params;
   OpenMode openMode;
 };
 
 struct StorageMatchArgs
 {
   CacheRequest request;
   CacheQueryParams params;
@@ -173,17 +155,17 @@ union CacheOpArgs
   StorageHasArgs;
   StorageOpenArgs;
   StorageDeleteArgs;
   StorageKeysArgs;
 };
 
 struct CacheMatchResult
 {
-  CacheResponseOrVoid responseOrVoid;
+  CacheResponse? maybeResponse;
 };
 
 struct CacheMatchAllResult
 {
   CacheResponse[] responseList;
 };
 
 struct CachePutAllResult
@@ -197,17 +179,17 @@ struct CacheDeleteResult
 
 struct CacheKeysResult
 {
   CacheRequest[] requestList;
 };
 
 struct StorageMatchResult
 {
-  CacheResponseOrVoid responseOrVoid;
+  CacheResponse? maybeResponse;
 };
 
 struct StorageHasResult
 {
   bool success;
 };
 
 struct StorageOpenResult
--- a/dom/cache/DBSchema.cpp
+++ b/dom/cache/DBSchema.cpp
@@ -911,31 +911,31 @@ nsresult CacheMatch(mozIStorageConnectio
 
   aSavedResponseOut->mCacheId = aCacheId;
   *aFoundResponseOut = true;
 
   return rv;
 }
 
 nsresult CacheMatchAll(mozIStorageConnection* aConn, CacheId aCacheId,
-                       const CacheRequestOrVoid& aRequestOrVoid,
+                       const Maybe<CacheRequest>& aMaybeRequest,
                        const CacheQueryParams& aParams,
                        nsTArray<SavedResponse>& aSavedResponsesOut) {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_DIAGNOSTIC_ASSERT(aConn);
   nsresult rv;
 
   AutoTArray<EntryId, 256> matches;
-  if (aRequestOrVoid.type() == CacheRequestOrVoid::Tvoid_t) {
+  if (aMaybeRequest.isNothing()) {
     rv = QueryAll(aConn, aCacheId, matches);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   } else {
-    rv = QueryCache(aConn, aCacheId, aRequestOrVoid, aParams, matches);
+    rv = QueryCache(aConn, aCacheId, aMaybeRequest.ref(), aParams, matches);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
   // TODO: replace this with a bulk load using SQL IN clause (bug 1110458)
   for (uint32_t i = 0; i < matches.Length(); ++i) {
     SavedResponse savedResponse;
@@ -1030,31 +1030,31 @@ nsresult CacheDelete(mozIStorageConnecti
   }
 
   *aSuccessOut = true;
 
   return rv;
 }
 
 nsresult CacheKeys(mozIStorageConnection* aConn, CacheId aCacheId,
-                   const CacheRequestOrVoid& aRequestOrVoid,
+                   const Maybe<CacheRequest>& aMaybeRequest,
                    const CacheQueryParams& aParams,
                    nsTArray<SavedRequest>& aSavedRequestsOut) {
   MOZ_ASSERT(!NS_IsMainThread());
   MOZ_DIAGNOSTIC_ASSERT(aConn);
   nsresult rv;
 
   AutoTArray<EntryId, 256> matches;
-  if (aRequestOrVoid.type() == CacheRequestOrVoid::Tvoid_t) {
+  if (aMaybeRequest.isNothing()) {
     rv = QueryAll(aConn, aCacheId, matches);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   } else {
-    rv = QueryCache(aConn, aCacheId, aRequestOrVoid, aParams, matches);
+    rv = QueryCache(aConn, aCacheId, aMaybeRequest.ref(), aParams, matches);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
   // TODO: replace this with a bulk load using SQL IN clause (bug 1110458)
   for (uint32_t i = 0; i < matches.Length(); ++i) {
     SavedRequest savedRequest;
--- a/dom/cache/DBSchema.h
+++ b/dom/cache/DBSchema.h
@@ -17,17 +17,16 @@ class mozIStorageConnection;
 struct nsID;
 
 namespace mozilla {
 namespace dom {
 namespace cache {
 
 class CacheQueryParams;
 class CacheRequest;
-class CacheRequestOrVoid;
 class CacheResponse;
 struct SavedRequest;
 struct SavedResponse;
 
 namespace db {
 
 // Note, this cannot be executed within a transaction.
 nsresult CreateOrMigrateSchema(mozIStorageConnection* aConn);
@@ -56,34 +55,34 @@ nsresult GetKnownBodyIds(mozIStorageConn
                          nsTArray<nsID>& aBodyIdListOut);
 
 nsresult CacheMatch(mozIStorageConnection* aConn, CacheId aCacheId,
                     const CacheRequest& aRequest,
                     const CacheQueryParams& aParams, bool* aFoundResponseOut,
                     SavedResponse* aSavedResponseOut);
 
 nsresult CacheMatchAll(mozIStorageConnection* aConn, CacheId aCacheId,
-                       const CacheRequestOrVoid& aRequestOrVoid,
+                       const Maybe<CacheRequest>& aMaybeRequest,
                        const CacheQueryParams& aParams,
                        nsTArray<SavedResponse>& aSavedResponsesOut);
 
 nsresult CachePut(mozIStorageConnection* aConn, CacheId aCacheId,
                   const CacheRequest& aRequest, const nsID* aRequestBodyId,
                   const CacheResponse& aResponse, const nsID* aResponseBodyId,
                   nsTArray<nsID>& aDeletedBodyIdListOut,
                   int64_t* aDeletedPaddingSizeOut);
 
 nsresult CacheDelete(mozIStorageConnection* aConn, CacheId aCacheId,
                      const CacheRequest& aRequest,
                      const CacheQueryParams& aParams,
                      nsTArray<nsID>& aDeletedBodyIdListOut,
                      int64_t* aDeletedPaddingSizeOut, bool* aSuccessOut);
 
 nsresult CacheKeys(mozIStorageConnection* aConn, CacheId aCacheId,
-                   const CacheRequestOrVoid& aRequestOrVoid,
+                   const Maybe<CacheRequest>& aMaybeRequest,
                    const CacheQueryParams& aParams,
                    nsTArray<SavedRequest>& aSavedRequestsOut);
 
 nsresult StorageMatch(mozIStorageConnection* aConn, Namespace aNamespace,
                       const CacheRequest& aRequest,
                       const CacheQueryParams& aParams, bool* aFoundResponseOut,
                       SavedResponse* aSavedResponseOut);
 
--- a/dom/cache/Manager.cpp
+++ b/dom/cache/Manager.cpp
@@ -180,21 +180,21 @@ class DeleteOrphanedBodyAction final : p
 };
 
 bool IsHeadRequest(const CacheRequest& aRequest,
                    const CacheQueryParams& aParams) {
   return !aParams.ignoreMethod() &&
          aRequest.method().LowerCaseEqualsLiteral("head");
 }
 
-bool IsHeadRequest(const CacheRequestOrVoid& aRequest,
+bool IsHeadRequest(const Maybe<CacheRequest>& aRequest,
                    const CacheQueryParams& aParams) {
-  if (aRequest.type() == CacheRequestOrVoid::TCacheRequest) {
+  if (aRequest.isSome()) {
     return !aParams.ignoreMethod() &&
-           aRequest.get_CacheRequest().method().LowerCaseEqualsLiteral("head");
+           aRequest.ref().method().LowerCaseEqualsLiteral("head");
   }
   return false;
 }
 
 }  // namespace
 
 // ----------------------------------------------------------------------------
 
@@ -546,20 +546,20 @@ class Manager::CacheMatchAction final : 
 
     mStreamList->Add(mResponse.mBodyId, std::move(stream));
 
     return rv;
   }
 
   virtual void Complete(Listener* aListener, ErrorResult&& aRv) override {
     if (!mFoundResponse) {
-      aListener->OnOpComplete(std::move(aRv), CacheMatchResult(void_t()));
+      aListener->OnOpComplete(std::move(aRv), CacheMatchResult(Nothing()));
     } else {
       mStreamList->Activate(mCacheId);
-      aListener->OnOpComplete(std::move(aRv), CacheMatchResult(void_t()),
+      aListener->OnOpComplete(std::move(aRv), CacheMatchResult(Nothing()),
                               mResponse, mStreamList);
     }
     mStreamList = nullptr;
   }
 
   virtual bool MatchesCacheId(CacheId aCacheId) const override {
     return aCacheId == mCacheId;
   }
@@ -582,25 +582,25 @@ class Manager::CacheMatchAllAction final
       : BaseAction(aManager, aListenerId),
         mCacheId(aCacheId),
         mArgs(aArgs),
         mStreamList(aStreamList) {}
 
   virtual nsresult RunSyncWithDBOnTarget(
       const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
       mozIStorageConnection* aConn) override {
-    nsresult rv = db::CacheMatchAll(aConn, mCacheId, mArgs.requestOrVoid(),
+    nsresult rv = db::CacheMatchAll(aConn, mCacheId, mArgs.maybeRequest(),
                                     mArgs.params(), mSavedResponses);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     for (uint32_t i = 0; i < mSavedResponses.Length(); ++i) {
       if (!mSavedResponses[i].mHasBodyId ||
-          IsHeadRequest(mArgs.requestOrVoid(), mArgs.params())) {
+          IsHeadRequest(mArgs.maybeRequest(), mArgs.params())) {
         mSavedResponses[i].mHasBodyId = false;
         continue;
       }
 
       nsCOMPtr<nsIInputStream> stream;
       if (mArgs.openMode() == OpenMode::Eager) {
         rv = BodyOpen(aQuotaInfo, aDBDir, mSavedResponses[i].mBodyId,
                       getter_AddRefs(stream));
@@ -1115,25 +1115,25 @@ class Manager::CacheKeysAction final : p
       : BaseAction(aManager, aListenerId),
         mCacheId(aCacheId),
         mArgs(aArgs),
         mStreamList(aStreamList) {}
 
   virtual nsresult RunSyncWithDBOnTarget(
       const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
       mozIStorageConnection* aConn) override {
-    nsresult rv = db::CacheKeys(aConn, mCacheId, mArgs.requestOrVoid(),
+    nsresult rv = db::CacheKeys(aConn, mCacheId, mArgs.maybeRequest(),
                                 mArgs.params(), mSavedRequests);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     for (uint32_t i = 0; i < mSavedRequests.Length(); ++i) {
       if (!mSavedRequests[i].mHasBodyId ||
-          IsHeadRequest(mArgs.requestOrVoid(), mArgs.params())) {
+          IsHeadRequest(mArgs.maybeRequest(), mArgs.params())) {
         mSavedRequests[i].mHasBodyId = false;
         continue;
       }
 
       nsCOMPtr<nsIInputStream> stream;
       if (mArgs.openMode() == OpenMode::Eager) {
         rv = BodyOpen(aQuotaInfo, aDBDir, mSavedRequests[i].mBodyId,
                       getter_AddRefs(stream));
@@ -1212,20 +1212,20 @@ class Manager::StorageMatchAction final 
 
     mStreamList->Add(mSavedResponse.mBodyId, std::move(stream));
 
     return rv;
   }
 
   virtual void Complete(Listener* aListener, ErrorResult&& aRv) override {
     if (!mFoundResponse) {
-      aListener->OnOpComplete(std::move(aRv), StorageMatchResult(void_t()));
+      aListener->OnOpComplete(std::move(aRv), StorageMatchResult(Nothing()));
     } else {
       mStreamList->Activate(mSavedResponse.mCacheId);
-      aListener->OnOpComplete(std::move(aRv), StorageMatchResult(void_t()),
+      aListener->OnOpComplete(std::move(aRv), StorageMatchResult(Nothing()),
                               mSavedResponse, mStreamList);
     }
     mStreamList = nullptr;
   }
 
  private:
   const Namespace mNamespace;
   const StorageMatchArgs mArgs;
--- a/dom/cache/ReadStream.cpp
+++ b/dom/cache/ReadStream.cpp
@@ -28,17 +28,17 @@ using mozilla::ipc::IPCStream;
 
 // The inner stream class.  This is where all of the real work is done.  As
 // an invariant Inner::Close() must be called before ~Inner().  This is
 // guaranteed by our outer ReadStream class.
 class ReadStream::Inner final : public ReadStream::Controllable {
  public:
   Inner(StreamControl* aControl, const nsID& aId, nsIInputStream* aStream);
 
-  void Serialize(CacheReadStreamOrVoid* aReadStreamOut,
+  void Serialize(Maybe<CacheReadStream>* aReadStreamOut,
                  nsTArray<UniquePtr<AutoIPCStream>>& aStreamCleanupList,
                  ErrorResult& aRv);
 
   void Serialize(CacheReadStream* aReadStreamOut,
                  nsTArray<UniquePtr<AutoIPCStream>>& aStreamCleanupList,
                  ErrorResult& aRv);
 
   // ReadStream::Controllable methods
@@ -188,22 +188,22 @@ ReadStream::Inner::Inner(StreamControl* 
       mStream(aStream),
       mSnappyStream(aStream ? new SnappyUncompressInputStream(aStream)
                             : nullptr) {
   MOZ_DIAGNOSTIC_ASSERT(mControl);
   mControl->AddReadStream(this);
 }
 
 void ReadStream::Inner::Serialize(
-    CacheReadStreamOrVoid* aReadStreamOut,
+    Maybe<CacheReadStream>* aReadStreamOut,
     nsTArray<UniquePtr<AutoIPCStream>>& aStreamCleanupList, ErrorResult& aRv) {
   MOZ_ASSERT(mOwningEventTarget->IsOnCurrentThread());
   MOZ_DIAGNOSTIC_ASSERT(aReadStreamOut);
-  *aReadStreamOut = CacheReadStream();
-  Serialize(&aReadStreamOut->get_CacheReadStream(), aStreamCleanupList, aRv);
+  aReadStreamOut->emplace(CacheReadStream());
+  Serialize(&aReadStreamOut->ref(), aStreamCleanupList, aRv);
 }
 
 void ReadStream::Inner::Serialize(
     CacheReadStream* aReadStreamOut,
     nsTArray<UniquePtr<AutoIPCStream>>& aStreamCleanupList, ErrorResult& aRv) {
   MOZ_ASSERT(mOwningEventTarget->IsOnCurrentThread());
   MOZ_DIAGNOSTIC_ASSERT(aReadStreamOut);
 
@@ -497,22 +497,22 @@ void ReadStream::Inner::OpenStreamFailed
 }
 
 // ----------------------------------------------------------------------------
 
 NS_IMPL_ISUPPORTS(cache::ReadStream, nsIInputStream, ReadStream);
 
 // static
 already_AddRefed<ReadStream> ReadStream::Create(
-    const CacheReadStreamOrVoid& aReadStreamOrVoid) {
-  if (aReadStreamOrVoid.type() == CacheReadStreamOrVoid::Tvoid_t) {
+    const Maybe<CacheReadStream>& aMaybeReadStream) {
+  if (aMaybeReadStream.isNothing()) {
     return nullptr;
   }
 
-  return Create(aReadStreamOrVoid.get_CacheReadStream());
+  return Create(aMaybeReadStream.ref());
 }
 
 // static
 already_AddRefed<ReadStream> ReadStream::Create(
     const CacheReadStream& aReadStream) {
   // The parameter may or may not be for a Cache created stream.  The way we
   // tell is by looking at the stream control actor.  If the actor exists,
   // then we know the Cache created it.
@@ -563,17 +563,17 @@ already_AddRefed<ReadStream> ReadStream:
   MOZ_DIAGNOSTIC_ASSERT(aControl);
   auto actor = static_cast<CacheStreamControlParent*>(aControl);
   RefPtr<Inner> inner = new Inner(actor, aId, aStream);
   RefPtr<ReadStream> ref = new ReadStream(inner);
   return ref.forget();
 }
 
 void ReadStream::Serialize(
-    CacheReadStreamOrVoid* aReadStreamOut,
+    Maybe<CacheReadStream>* aReadStreamOut,
     nsTArray<UniquePtr<AutoIPCStream>>& aStreamCleanupList, ErrorResult& aRv) {
   mInner->Serialize(aReadStreamOut, aStreamCleanupList, aRv);
 }
 
 void ReadStream::Serialize(
     CacheReadStream* aReadStreamOut,
     nsTArray<UniquePtr<AutoIPCStream>>& aStreamCleanupList, ErrorResult& aRv) {
   mInner->Serialize(aReadStreamOut, aStreamCleanupList, aRv);
--- a/dom/cache/ReadStream.h
+++ b/dom/cache/ReadStream.h
@@ -19,17 +19,16 @@
 namespace mozilla {
 namespace ipc {
 class AutoIPCStream;
 }  // namespace ipc
 namespace dom {
 namespace cache {
 
 class CacheReadStream;
-class CacheReadStreamOrVoid;
 class PCacheStreamControlParent;
 
 // IID for the dom::cache::ReadStream interface
 #define NS_DOM_CACHE_READSTREAM_IID                  \
   {                                                  \
     0x8e5da7c9, 0x0940, 0x4f1d, {                    \
       0x97, 0x25, 0x5c, 0x59, 0x38, 0xdd, 0xb9, 0x9f \
     }                                                \
@@ -63,27 +62,27 @@ class ReadStream final : public nsIInput
     virtual bool MatchId(const nsID& aId) const = 0;
 
     virtual bool HasEverBeenRead() const = 0;
 
     NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
   };
 
   static already_AddRefed<ReadStream> Create(
-      const CacheReadStreamOrVoid& aReadStreamOrVoid);
+      const Maybe<CacheReadStream>& aMaybeReadStream);
 
   static already_AddRefed<ReadStream> Create(
       const CacheReadStream& aReadStream);
 
   static already_AddRefed<ReadStream> Create(
       PCacheStreamControlParent* aControl, const nsID& aId,
       nsIInputStream* aStream);
 
   void Serialize(
-      CacheReadStreamOrVoid* aReadStreamOut,
+      Maybe<CacheReadStream>* aReadStreamOut,
       nsTArray<UniquePtr<mozilla::ipc::AutoIPCStream>>& aStreamCleanupList,
       ErrorResult& aRv);
   void Serialize(
       CacheReadStream* aReadStreamOut,
       nsTArray<UniquePtr<mozilla::ipc::AutoIPCStream>>& aStreamCleanupList,
       ErrorResult& aRv);
 
  private:
--- a/dom/cache/SavedTypes.h
+++ b/dom/cache/SavedTypes.h
@@ -21,31 +21,31 @@ namespace dom {
 namespace cache {
 
 struct SavedRequest {
   SavedRequest() : mHasBodyId(false), mCacheId(0) {
     mBodyId.m0 = 0;
     mBodyId.m1 = 0;
     mBodyId.m2 = 0;
     memset(mBodyId.m3, 0, sizeof(mBodyId.m3));
-    mValue.body() = void_t();
+    mValue.body() = Nothing();
   }
   CacheRequest mValue;
   bool mHasBodyId;
   nsID mBodyId;
   CacheId mCacheId;
 };
 
 struct SavedResponse {
   SavedResponse() : mHasBodyId(false), mCacheId(0) {
     mBodyId.m0 = 0;
     mBodyId.m1 = 0;
     mBodyId.m2 = 0;
     memset(mBodyId.m3, 0, sizeof(mBodyId.m3));
-    mValue.body() = void_t();
+    mValue.body() = Nothing();
   }
   CacheResponse mValue;
   bool mHasBodyId;
   nsID mBodyId;
   CacheId mCacheId;
 };
 
 }  // namespace cache
--- a/dom/cache/TypeUtils.cpp
+++ b/dom/cache/TypeUtils.cpp
@@ -145,17 +145,17 @@ void TypeUtils::ToCacheRequest(
   aOut.credentials() = aIn->GetCredentialsMode();
   aOut.contentPolicyType() = aIn->ContentPolicyType();
   aOut.requestCache() = aIn->GetCacheMode();
   aOut.requestRedirect() = aIn->GetRedirectMode();
 
   aOut.integrity() = aIn->GetIntegrity();
 
   if (aBodyAction == IgnoreBody) {
-    aOut.body() = void_t();
+    aOut.body() = Nothing();
     return;
   }
 
   // BodyUsed flag is checked and set previously in ToInternalRequest()
 
   nsCOMPtr<nsIInputStream> stream;
   aIn->GetBody(getter_AddRefs(stream));
   SerializeCacheStream(stream, &aOut.body(), aStreamCleanupList, aRv);
@@ -470,31 +470,31 @@ already_AddRefed<InternalRequest> TypeUt
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   return request->GetInternalRequest();
 }
 
 void TypeUtils::SerializeCacheStream(
-    nsIInputStream* aStream, CacheReadStreamOrVoid* aStreamOut,
+    nsIInputStream* aStream, Maybe<CacheReadStream>* aStreamOut,
     nsTArray<UniquePtr<AutoIPCStream>>& aStreamCleanupList, ErrorResult& aRv) {
-  *aStreamOut = void_t();
+  *aStreamOut = Nothing();
   if (!aStream) {
     return;
   }
 
   RefPtr<ReadStream> controlled = do_QueryObject(aStream);
   if (controlled) {
     controlled->Serialize(aStreamOut, aStreamCleanupList, aRv);
     return;
   }
 
-  *aStreamOut = CacheReadStream();
-  CacheReadStream& cacheStream = aStreamOut->get_CacheReadStream();
+  aStreamOut->emplace(CacheReadStream());
+  CacheReadStream& cacheStream = aStreamOut->ref();
 
   cacheStream.controlChild() = nullptr;
   cacheStream.controlParent() = nullptr;
 
   UniquePtr<AutoIPCStream> autoStream(new AutoIPCStream(cacheStream.stream()));
   autoStream->Serialize(aStream, GetIPCManager());
 
   aStreamCleanupList.AppendElement(std::move(autoStream));
--- a/dom/cache/TypeUtils.h
+++ b/dom/cache/TypeUtils.h
@@ -32,17 +32,16 @@ class OwningRequestOrUSVString;
 class Request;
 class RequestOrUSVString;
 class Response;
 
 namespace cache {
 
 class CacheQueryParams;
 class CacheReadStream;
-class CacheReadStreamOrVoid;
 class CacheRequest;
 class CacheResponse;
 class HeadersEntry;
 
 class TypeUtils {
  public:
   enum BodyAction { IgnoreBody, ReadBody };
 
@@ -118,17 +117,17 @@ class TypeUtils {
  private:
   void CheckAndSetBodyUsed(JSContext* aCx, Request* aRequest,
                            BodyAction aBodyAction, ErrorResult& aRv);
 
   already_AddRefed<InternalRequest> ToInternalRequest(const nsAString& aIn,
                                                       ErrorResult& aRv);
 
   void SerializeCacheStream(
-      nsIInputStream* aStream, CacheReadStreamOrVoid* aStreamOut,
+      nsIInputStream* aStream, Maybe<CacheReadStream>* aStreamOut,
       nsTArray<UniquePtr<mozilla::ipc::AutoIPCStream>>& aStreamCleanupList,
       ErrorResult& aRv);
 
   void SerializeSendStream(nsIInputStream* aStream,
                            CacheReadStream& aReadStreamOut, ErrorResult& aRv);
 };
 
 }  // namespace cache
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -1229,17 +1229,17 @@ void EventStateManager::DispatchCrossPro
   if (aEvent->mLayersId.IsValid()) {
     TabParent* preciseRemote =
         TabParent::GetTabParentFromLayersId(aEvent->mLayersId);
     if (preciseRemote) {
       remote = preciseRemote;
     }
     // else there is a race between APZ and the LayersId to TabParent mapping,
     // so fall back to delivering the event to the topmost child process.
-  } else {
+  } else if (aEvent->mClass == eKeyboardEventClass) {
     // APZ attaches a LayersId to hit-testable events, for keyboard events,
     // we use focus.
     TabParent* preciseRemote = TabParent::GetFocused();
     if (preciseRemote) {
       remote = preciseRemote;
     }
     // else there is a race between layout and focus tracking,
     // so fall back to delivering the event to the topmost child process.
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1660,17 +1660,17 @@ void ContentParent::ActorDestroy(ActorDe
 
   // Unregister all the BlobURLs registered by the ContentChild.
   for (uint32_t i = 0; i < mBlobURLs.Length(); ++i) {
     BlobURLProtocolHandler::RemoveDataEntry(mBlobURLs[i]);
   }
 
   mBlobURLs.Clear();
 
-#if defined(XP_WIN32) && defined(ACCESSIBILITY)
+#if defined(XP_WIN) && defined(ACCESSIBILITY)
   a11y::AccessibleWrap::ReleaseContentProcessIdFor(ChildID());
 #endif
 
   nsTHashtable<nsRefPtrHashKey<BrowsingContextGroup>> groups;
   mGroups.SwapElements(groups);
 
   for (auto iter = groups.Iter(); !iter.Done(); iter.Next()) {
     iter.Get()->GetKey()->Unsubscribe(this);
@@ -5192,28 +5192,28 @@ ContentParent::RecvUnstoreAndBroadcastBl
   BroadcastBlobURLUnregistration(aURI, this);
   mBlobURLs.RemoveElement(aURI);
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult ContentParent::RecvGetA11yContentId(
     uint32_t* aContentId) {
-#if defined(XP_WIN32) && defined(ACCESSIBILITY)
+#if defined(XP_WIN) && defined(ACCESSIBILITY)
   *aContentId = a11y::AccessibleWrap::GetContentProcessIdFor(ChildID());
   MOZ_ASSERT(*aContentId);
   return IPC_OK();
 #else
   return IPC_FAIL_NO_REASON(this);
 #endif
 }
 
 mozilla::ipc::IPCResult ContentParent::RecvA11yHandlerControl(
     const uint32_t& aPid, const IHandlerControlHolder& aHandlerControl) {
-#if defined(XP_WIN32) && defined(ACCESSIBILITY)
+#if defined(XP_WIN) && defined(ACCESSIBILITY)
   MOZ_ASSERT(!aHandlerControl.IsNull());
   RefPtr<IHandlerControl> proxy(aHandlerControl.Get());
   a11y::AccessibleWrap::SetHandlerControl(aPid, std::move(proxy));
   return IPC_OK();
 #else
   return IPC_FAIL_NO_REASON(this);
 #endif
 }
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -83,16 +83,18 @@ PointerLockDeniedMovedDocument=Request f
 PointerLockDeniedNotInputDriven=Request for pointer lock was denied because Element.requestPointerLock() was not called from inside a short running user-generated event handler, and the document is not in full screen.
 PointerLockDeniedFailedToLock=Request for pointer lock was denied because the browser failed to lock the pointer.
 HTMLSyncXHRWarning=HTML parsing in XMLHttpRequest is not supported in the synchronous mode.
 InvalidRedirectChannelWarning=Unable to redirect to %S because the channel doesn’t implement nsIWritablePropertyBag2.
 # LOCALIZATION NOTE: %S is the name of the header in question
 ForbiddenHeaderWarning=Attempt to set a forbidden header was denied: %S
 ResponseTypeSyncXHRWarning=Use of XMLHttpRequest’s responseType attribute is no longer supported in the synchronous mode in window context.
 TimeoutSyncXHRWarning=Use of XMLHttpRequest’s timeout attribute is not supported in the synchronous mode in window context.
+# LOCALIZATION NOTE: Do not translate navigator.sendBeacon, unload, pagehide, or XMLHttpRequest.
+UseSendBeaconDuringUnloadAndPagehideWarning=Use of navigator.sendBeacon instead of synchronous XMLHttpRequest during unload and pagehide improves user experience.
 JSONCharsetWarning=An attempt was made to declare a non-UTF-8 encoding for JSON retrieved using XMLHttpRequest. Only UTF-8 is supported for decoding JSON.
 # LOCALIZATION NOTE: Do not translate AudioBufferSourceNode
 MediaBufferSourceNodeResampleOutOfMemory=Insufficient memory to resample the AudioBufferSourceNode for playback.
 # LOCALIZATION NOTE: Do not translate decodeAudioData.
 MediaDecodeAudioDataUnknownContentType=The buffer passed to decodeAudioData contains an unknown content type.
 # LOCALIZATION NOTE: Do not translate decodeAudioData.
 MediaDecodeAudioDataUnknownError=An unknown error occurred while processing decodeAudioData.
 # LOCALIZATION NOTE: Do not translate decodeAudioData.
--- a/dom/media/platforms/agnostic/DAV1DDecoder.cpp
+++ b/dom/media/platforms/agnostic/DAV1DDecoder.cpp
@@ -26,16 +26,21 @@ RefPtr<MediaDataDecoder::InitPromise> DA
   size_t decoder_threads = 2;
   if (mInfo.mDisplay.width >= 2048) {
     decoder_threads = 8;
   } else if (mInfo.mDisplay.width >= 1024) {
     decoder_threads = 4;
   }
   settings.n_frame_threads =
       static_cast<int>(std::min(decoder_threads, GetNumberOfProcessors()));
+  // There is not much improvement with more than 2 tile threads at least with
+  // the content being currently served. The ideal number of tile thread would
+  // much the tile count of the content. Maybe dav1d can help to do that in the
+  // future.
+  settings.n_tile_threads = 2;
 
   int res = dav1d_open(&mContext, &settings);
   if (res < 0) {
     return DAV1DDecoder::InitPromise::CreateAndReject(
         MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
                     RESULT_DETAIL("Couldn't get dAV1d decoder interface.")),
         __func__);
   }
--- a/dom/media/platforms/agnostic/DAV1DDecoder.h
+++ b/dom/media/platforms/agnostic/DAV1DDecoder.h
@@ -33,17 +33,17 @@ class DAV1DDecoder : public MediaDataDec
   void ReleaseDataBuffer(const uint8_t* buf);
 
  private:
   ~DAV1DDecoder() = default;
   RefPtr<DecodePromise> InvokeDecode(MediaRawData* aSample);
   int GetPicture(DecodedData& aData, MediaResult& aResult);
   already_AddRefed<VideoData> ConstructImage(const Dav1dPicture& aPicture);
 
-  Dav1dContext* mContext;
+  Dav1dContext* mContext = nullptr;
 
   const VideoInfo& mInfo;
   const RefPtr<TaskQueue> mTaskQueue;
   const RefPtr<layers::ImageContainer> mImageContainer;
 
   // Keep the buffers alive until dav1d
   // does not need them any more.
   MediaRawDataHashtable mDecodingBuffers;
--- a/dom/vr/VRDisplay.cpp
+++ b/dom/vr/VRDisplay.cpp
@@ -241,17 +241,19 @@ VRPose::VRPose(nsISupports* aParent) : P
 
 VRPose::~VRPose() { mozilla::DropJSObjects(this); }
 
 void VRPose::GetPosition(JSContext* aCx, JS::MutableHandle<JSObject*> aRetval,
                          ErrorResult& aRv) {
   SetFloat32Array(
       aCx, aRetval, mPosition, mVRState.pose.position, 3,
       !mPosition &&
-          bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Position),
+          (bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Position) ||
+           bool(mVRState.flags &
+                gfx::VRDisplayCapabilityFlags::Cap_PositionEmulated)),
       aRv);
 }
 
 void VRPose::GetLinearVelocity(JSContext* aCx,
                                JS::MutableHandle<JSObject*> aRetval,
                                ErrorResult& aRv) {
   SetFloat32Array(
       aCx, aRetval, mLinearVelocity, mVRState.pose.linearVelocity, 3,
--- a/dom/xhr/XMLHttpRequestMainThread.cpp
+++ b/dom/xhr/XMLHttpRequestMainThread.cpp
@@ -1365,16 +1365,31 @@ nsresult XMLHttpRequestMainThread::Open(
     // non-window context...
     nsresult rv = CheckInnerWindowCorrectness();
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return NS_ERROR_DOM_INVALID_STATE_XHR_HAS_INVALID_CONTEXT;
     }
   }
   NS_ENSURE_TRUE(mPrincipal, NS_ERROR_NOT_INITIALIZED);
 
+  // Gecko-specific
+  if (!aAsync && responsibleDocument && GetOwner()) {
+    // We have no extant document during unload, so the above general
+    // syncXHR warning will not display. But we do want to display a
+    // recommendation to use sendBeacon instead of syncXHR during unload.
+    nsCOMPtr<nsIDocShell> shell = responsibleDocument->GetDocShell();
+    if (shell) {
+      bool inUnload = false;
+      shell->GetIsInUnload(&inUnload);
+      if (inUnload) {
+        LogMessage("UseSendBeaconDuringUnloadAndPagehideWarning", GetOwner());
+      }
+    }
+  }
+
   // Steps 2-4
   nsAutoCString method;
   nsresult rv = FetchUtil::GetValidRequestMethod(aMethod, method);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   // Steps 5-6
--- a/gfx/layers/RepaintRequest.h
+++ b/gfx/layers/RepaintRequest.h
@@ -27,18 +27,22 @@ namespace layers {
 
 struct RepaintRequest {
   friend struct IPC::ParamTraits<mozilla::layers::RepaintRequest>;
 
  public:
   // clang-format off
   MOZ_DEFINE_ENUM_WITH_BASE_AT_CLASS_SCOPE(
     ScrollOffsetUpdateType, uint8_t, (
-      eNone,             // The default; the scroll offset was not updated.
-      eUserAction        // The scroll offset was updated by APZ.
+        eNone,             // The default; the scroll offset was not updated.
+        eUserAction,       // The scroll offset was updated by APZ in response
+                           // to user action.
+        eVisualUpdate      // The scroll offset was updated by APZ in response
+                           // to a visual scroll update request from the
+                           // main thread.
   ));
   // clang-format on
 
   RepaintRequest()
       : mScrollId(ScrollableLayerGuid::NULL_SCROLL_ID),
         mPresShellResolution(1),
         mCompositionBounds(0, 0, 0, 0),
         mCumulativeResolution(),
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -4643,17 +4643,27 @@ void AsyncPanZoomController::NotifyLayer
     // |if (scrollOffsetUpdated)| branch above.
     Metrics().RecalculateLayoutViewportOffset();
     mCompositedLayoutViewport = Metrics().GetLayoutViewport();
     mCompositedScrollOffset = Metrics().GetScrollOffset();
     mExpectedGeckoMetrics = aLayerMetrics;
     if (!mAnimation || !mAnimation->HandleScrollOffsetUpdate(Nothing())) {
       CancelAnimation();
     }
+    // The main thread did not actually paint a displayport at the target
+    // visual offset, so we need to ask it to repaint. We need to set the
+    // contentRepaintType to something other than eNone, otherwise the main
+    // thread will short-circuit the repaint request.
+    // Don't do this for eRestore visual updates as a repaint coming from APZ
+    // breaks the scroll offset restoration mechanism.
     needContentRepaint = true;
+    if (aLayerMetrics.GetVisualScrollUpdateType() ==
+        FrameMetrics::eMainThread) {
+      contentRepaintType = RepaintUpdateType::eVisualUpdate;
+    }
     ScheduleComposite();
   }
 
   if (viewportUpdated) {
     // While we want to accept the main thread's layout viewport _size_,
     // its position may be out of date in light of async scrolling, to
     // adjust it if necessary to make sure it continues to enclose the
     // visual viewport.
--- a/gfx/moz.build
+++ b/gfx/moz.build
@@ -1,16 +1,18 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 with Files('**'):
     BUG_COMPONENT = ('Core', 'Graphics')
+with Files('wr/**'):
+    BUG_COMPONENT = ('Core', 'Graphics: WebRender')
 
 if CONFIG['MOZ_TREE_CAIRO']:
     DIRS += ['cairo']
 
 DIRS += [
     '2d',
     'ycbcr',
     'angle',
--- a/gfx/src/nsCoord.h
+++ b/gfx/src/nsCoord.h
@@ -67,31 +67,31 @@ inline nscoord NSCoordMulDiv(nscoord aMu
 #ifdef NS_COORD_IS_FLOAT
   return (aMult1 * aMult2 / aDiv);
 #else
   return (int64_t(aMult1) * int64_t(aMult2) / int64_t(aDiv));
 #endif
 }
 
 inline nscoord NSToCoordRound(float aValue) {
-#if defined(XP_WIN32) && defined(_M_IX86) && !defined(__GNUC__) && \
+#if defined(XP_WIN) && defined(_M_IX86) && !defined(__GNUC__) && \
     !defined(__clang__)
   return NS_lroundup30(aValue);
 #else
   return nscoord(floorf(aValue + 0.5f));
-#endif /* XP_WIN32 && _M_IX86 && !__GNUC__ */
+#endif /* XP_WIN && _M_IX86 && !__GNUC__ */
 }
 
 inline nscoord NSToCoordRound(double aValue) {
-#if defined(XP_WIN32) && defined(_M_IX86) && !defined(__GNUC__) && \
+#if defined(XP_WIN) && defined(_M_IX86) && !defined(__GNUC__) && \
     !defined(__clang__)
   return NS_lroundup30((float)aValue);
 #else
   return nscoord(floor(aValue + 0.5f));
-#endif /* XP_WIN32 && _M_IX86 && !__GNUC__ */
+#endif /* XP_WIN && _M_IX86 && !__GNUC__ */
 }
 
 inline nscoord NSToCoordRoundWithClamp(float aValue) {
 #ifndef NS_COORD_IS_FLOAT
   // Bounds-check before converting out of float, to avoid overflow
   if (aValue >= nscoord_MAX) {
     return nscoord_MAX;
   }
--- a/gfx/src/nsRegion.cpp
+++ b/gfx/src/nsRegion.cpp
@@ -989,17 +989,17 @@ nsRect nsRegion::GetLargestRectangle(con
 std::ostream& operator<<(std::ostream& stream, const nsRegion& m) {
   stream << "[";
 
   bool first = true;
   for (auto iter = m.RectIter(); !iter.Done(); iter.Next()) {
     if (!first) {
       stream << "; ";
     } else {
-      first = true;
+      first = false;
     }
     const nsRect& rect = iter.Get();
     stream << rect.X() << "," << rect.Y() << "," << rect.XMost() << ","
            << rect.YMost();
   }
 
   stream << "]";
   return stream;
--- a/gfx/vr/external_api/moz_external_vr.h
+++ b/gfx/vr/external_api/moz_external_vr.h
@@ -29,17 +29,17 @@ namespace mozilla {
 #ifdef MOZILLA_INTERNAL_API
 namespace dom {
 enum class GamepadHand : uint8_t;
 enum class GamepadCapabilityFlags : uint16_t;
 }  // namespace dom
 #endif  //  MOZILLA_INTERNAL_API
 namespace gfx {
 
-static const int32_t kVRExternalVersion = 6;
+static const int32_t kVRExternalVersion = 7;
 
 // We assign VR presentations to groups with a bitmask.
 // Currently, we will only display either content or chrome.
 // Later, we will have more groups to support VR home spaces and
 // multitasking environments.
 // These values are not exposed to regular content and only affect
 // chrome-only API's.  They may be changed at any time.
 static const uint32_t kVRGroupNone = 0;
@@ -155,19 +155,24 @@ enum class VRDisplayCapabilityFlags : ui
    */
   Cap_StageParameters = 1 << 7,
   /**
    * Cap_MountDetection is set if the VRDisplay is capable of sensing when the
    * user is wearing the device.
    */
   Cap_MountDetection = 1 << 8,
   /**
+   * Cap_PositionEmulated is set if the VRDisplay is capable of setting a
+   * emulated position (e.g. neck model) even if still doesn't support 6DOF tracking.
+   */
+  Cap_PositionEmulated = 1 << 9,
+  /**
    * Cap_All used for validity checking during IPC serialization
    */
-  Cap_All = (1 << 9) - 1
+  Cap_All = (1 << 10) - 1
 };
 
 #ifdef MOZILLA_INTERNAL_API
 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(VRDisplayCapabilityFlags)
 #endif  // MOZILLA_INTERNAL_API
 
 struct VRPose {
   float orientation[4];
--- a/gfx/wr/webrender/res/brush.glsl
+++ b/gfx/wr/webrender/res/brush.glsl
@@ -4,17 +4,18 @@
 
 #ifdef WR_VERTEX_SHADER
 
 void brush_vs(
     VertexInfo vi,
     int prim_address,
     RectWithSize local_rect,
     RectWithSize segment_rect,
-    ivec4 user_data,
+    ivec4 prim_user_data,
+    int segment_user_data,
     mat4 transform,
     PictureTask pic_task,
     int brush_flags,
     vec4 segment_data
 );
 
 #define VECS_PER_SEGMENT                    2
 
@@ -113,17 +114,18 @@ void main(void) {
 #endif
 
     // Run the specific brush VS code to write interpolators.
     brush_vs(
         vi,
         ph.specific_prim_address,
         ph.local_rect,
         segment_rect,
-        ivec4(ph.user_data, segment_user_data),
+        ph.user_data,
+        segment_user_data,
         transform.m,
         pic_task,
         brush_flags,
         segment_data
     );
 }
 #endif
 
--- a/gfx/wr/webrender/res/brush_blend.glsl
+++ b/gfx/wr/webrender/res/brush_blend.glsl
@@ -27,61 +27,61 @@ flat varying int vFuncs[4];
 
 #ifdef WR_VERTEX_SHADER
 
 void brush_vs(
     VertexInfo vi,
     int prim_address,
     RectWithSize local_rect,
     RectWithSize segment_rect,
-    ivec4 user_data,
+    ivec4 prim_user_data,
+    int segment_user_data,
     mat4 transform,
     PictureTask pic_task,
     int brush_flags,
     vec4 unused
 ) {
-    ImageResource res = fetch_image_resource(user_data.x);
+    ImageResource res = fetch_image_resource(prim_user_data.x);
     vec2 uv0 = res.uv_rect.p0;
     vec2 uv1 = res.uv_rect.p1;
 
-    // PictureTask src_task = fetch_picture_task(user_data.x);
     vec2 texture_size = vec2(textureSize(sColor0, 0).xy);
     vec2 f = (vi.local_pos - local_rect.p0) / local_rect.size;
-    f = get_image_quad_uv(user_data.x, f);
+    f = get_image_quad_uv(prim_user_data.x, f);
     vec2 uv = mix(uv0, uv1, f);
     float perspective_interpolate = (brush_flags & BRUSH_FLAG_PERSPECTIVE_INTERPOLATION) != 0 ? 1.0 : 0.0;
 
     vUv = uv / texture_size * mix(vi.world_pos.w, 1.0, perspective_interpolate);
     vLayerAndPerspective = vec2(res.layer, perspective_interpolate);
     vUvClipBounds = vec4(uv0, uv1) / texture_size.xyxy;
 
     float lumR = 0.2126;
     float lumG = 0.7152;
     float lumB = 0.0722;
     float oneMinusLumR = 1.0 - lumR;
     float oneMinusLumG = 1.0 - lumG;
     float oneMinusLumB = 1.0 - lumB;
 
-    float amount = float(user_data.z) / 65536.0;
+    float amount = float(prim_user_data.z) / 65536.0;
     float invAmount = 1.0 - amount;
 
-    vOp = user_data.y & 0xffff;
+    vOp = prim_user_data.y & 0xffff;
     vAmount = amount;
 
     // This assignment is only used for component transfer filters but this
     // assignment has to be done here and not in the component transfer case
     // below because it doesn't get executed on Windows because of a suspected
     // miscompile of this shader on Windows. See
     // https://github.com/servo/webrender/wiki/Driver-issues#bug-1505871---assignment-to-varying-flat-arrays-inside-switch-statement-of-vertex-shader-suspected-miscompile-on-windows
     // default: just to satisfy angle_shader_validation.rs which needs one
     // default: for every switch, even in comments.
-    vFuncs[0] = (user_data.y >> 28) & 0xf; // R
-    vFuncs[1] = (user_data.y >> 24) & 0xf; // G
-    vFuncs[2] = (user_data.y >> 20) & 0xf; // B
-    vFuncs[3] = (user_data.y >> 16) & 0xf; // A
+    vFuncs[0] = (prim_user_data.y >> 28) & 0xf; // R
+    vFuncs[1] = (prim_user_data.y >> 24) & 0xf; // G
+    vFuncs[2] = (prim_user_data.y >> 20) & 0xf; // B
+    vFuncs[3] = (prim_user_data.y >> 16) & 0xf; // A
 
     switch (vOp) {
         case 2: {
             // Grayscale
             vColorMat = mat3(
                 vec3(lumR + oneMinusLumR * invAmount, lumR - lumR * invAmount, lumR - lumR * invAmount),
                 vec3(lumG - lumG * invAmount, lumG + oneMinusLumG * invAmount, lumG - lumG * invAmount),
                 vec3(lumB - lumB * invAmount, lumB - lumB * invAmount, lumB + oneMinusLumB * invAmount)
@@ -118,25 +118,25 @@ void brush_vs(
                 vec3(0.769 - 0.769 * invAmount, 0.686 + 0.314 * invAmount, 0.534 - 0.534 * invAmount),
                 vec3(0.189 - 0.189 * invAmount, 0.168 - 0.168 * invAmount, 0.131 + 0.869 * invAmount)
             );
             vColorOffset = vec3(0.0);
             break;
         }
         case 10: {
             // Color Matrix
-            vec4 mat_data[3] = fetch_from_gpu_cache_3(user_data.z);
-            vec4 offset_data = fetch_from_gpu_cache_1(user_data.z + 4);
+            vec4 mat_data[3] = fetch_from_gpu_cache_3(prim_user_data.z);
+            vec4 offset_data = fetch_from_gpu_cache_1(prim_user_data.z + 4);
             vColorMat = mat3(mat_data[0].xyz, mat_data[1].xyz, mat_data[2].xyz);
             vColorOffset = offset_data.rgb;
             break;
         }
         case 13: {
             // Component Transfer
-            vTableAddress = user_data.z;
+            vTableAddress = prim_user_data.z;
             break;
         }
         default: break;
     }
 }
 #endif
 
 #ifdef WR_FRAGMENT_SHADER
--- a/gfx/wr/webrender/res/brush_image.glsl
+++ b/gfx/wr/webrender/res/brush_image.glsl
@@ -48,33 +48,34 @@ ImageBrushData fetch_image_data(int addr
     return data;
 }
 
 void brush_vs(
     VertexInfo vi,
     int prim_address,
     RectWithSize prim_rect,
     RectWithSize segment_rect,
-    ivec4 user_data,
+    ivec4 prim_user_data,
+    int segment_user_data,
     mat4 transform,
     PictureTask pic_task,
     int brush_flags,
     vec4 segment_data
 ) {
     ImageBrushData image_data = fetch_image_data(prim_address);
 
     // If this is in WR_FEATURE_TEXTURE_RECT mode, the rect and size use
     // non-normalized texture coordinates.
 #ifdef WR_FEATURE_TEXTURE_RECT
     vec2 texture_size = vec2(1, 1);
 #else
     vec2 texture_size = vec2(textureSize(sColor0, 0));
 #endif
 
-    ImageResource res = fetch_image_resource(user_data.w);
+    ImageResource res = fetch_image_resource(segment_user_data);
     vec2 uv0 = res.uv_rect.p0;
     vec2 uv1 = res.uv_rect.p1;
 
     RectWithSize local_rect = prim_rect;
     vec2 stretch_size = image_data.stretch_size;
     if (stretch_size.x < 0.0) {
         stretch_size = local_rect.size;
     }
@@ -117,33 +118,33 @@ void brush_vs(
     vUvSampleBounds = vec4(
         min_uv + vec2(0.5),
         max_uv - vec2(0.5)
     ) / texture_size.xyxy;
 
     vec2 f = (vi.local_pos - local_rect.p0) / local_rect.size;
 
 #ifdef WR_FEATURE_ALPHA_PASS
-    int color_mode = user_data.x & 0xffff;
-    int blend_mode = user_data.x >> 16;
-    int raster_space = user_data.y;
+    int color_mode = prim_user_data.x & 0xffff;
+    int blend_mode = prim_user_data.x >> 16;
+    int raster_space = prim_user_data.y;
 
     if (color_mode == COLOR_MODE_FROM_PASS) {
         color_mode = uMode;
     }
 
     // Derive the texture coordinates for this image, based on
     // whether the source image is a local-space or screen-space
     // image.
     switch (raster_space) {
         case RASTER_SCREEN: {
             // Since the screen space UVs specify an arbitrary quad, do
             // a bilinear interpolation to get the correct UV for this
             // local position.
-            f = get_image_quad_uv(user_data.w, f);
+            f = get_image_quad_uv(segment_user_data, f);
             break;
         }
         default:
             break;
     }
 #endif
 
     // Offset and scale vUv here to avoid doing it in the fragment shader.
@@ -159,17 +160,17 @@ void brush_vs(
     vUvBounds = vec4(0.0, 0.0, vec2(textureSize(sColor0)));
 #else
     vUvBounds = vec4(min_uv, max_uv) / texture_size.xyxy;
 #endif
 
 #ifdef WR_FEATURE_ALPHA_PASS
     vTileRepeat = repeat.xy;
 
-    float opacity = float(user_data.z) / 65535.0;
+    float opacity = float(prim_user_data.z) / 65535.0;
     switch (blend_mode) {
         case BLEND_MODE_ALPHA:
             image_data.color.a *= opacity;
             break;
         case BLEND_MODE_PREMUL_ALPHA:
         default:
             image_data.color *= opacity;
             break;
--- a/gfx/wr/webrender/res/brush_linear_gradient.glsl
+++ b/gfx/wr/webrender/res/brush_linear_gradient.glsl
@@ -40,17 +40,18 @@ Gradient fetch_gradient(int address) {
     );
 }
 
 void brush_vs(
     VertexInfo vi,
     int prim_address,
     RectWithSize local_rect,
     RectWithSize segment_rect,
-    ivec4 user_data,
+    ivec4 prim_user_data,
+    int segment_user_data,
     mat4 transform,
     PictureTask pic_task,
     int brush_flags,
     vec4 texel_rect
 ) {
     Gradient gradient = fetch_gradient(prim_address);
 
     if ((brush_flags & BRUSH_FLAG_SEGMENT_RELATIVE) != 0) {
@@ -66,17 +67,17 @@ void brush_vs(
     vec2 dir = end_point - start_point;
 
     vStartPoint = start_point;
     vScaledDir = dir / dot(dir, dir);
 
     vec2 tile_repeat = local_rect.size / gradient.stretch_size;
     vRepeatedSize = gradient.stretch_size;
 
-    vGradientAddress = user_data.x;
+    vGradientAddress = prim_user_data.x;
 
     // Whether to repeat the gradient along the line instead of clamping.
     vGradientRepeat = float(gradient.extend_mode != EXTEND_MODE_CLAMP);
 
 #ifdef WR_FEATURE_ALPHA_PASS
     vTileRepeat = tile_repeat;
     vLocalPos = vi.local_pos;
 #endif
--- a/gfx/wr/webrender/res/brush_mix_blend.glsl
+++ b/gfx/wr/webrender/res/brush_mix_blend.glsl
@@ -17,33 +17,34 @@ vec2 snap_device_pos(VertexInfo vi, floa
     return vi.world_pos.xy * device_pixel_scale / max(0.0, vi.world_pos.w) + vi.snap_offset;
 }
 
 void brush_vs(
     VertexInfo vi,
     int prim_address,
     RectWithSize local_rect,
     RectWithSize segment_rect,
-    ivec4 user_data,
+    ivec4 prim_user_data,
+    int segment_user_data,
     mat4 transform,
     PictureTask pic_task,
     int brush_flags,
     vec4 unused
 ) {
     vec2 snapped_device_pos = snap_device_pos(vi, pic_task.device_pixel_scale);
     vec2 texture_size = vec2(textureSize(sPrevPassColor, 0));
-    vOp = user_data.x;
+    vOp = prim_user_data.x;
 
-    PictureTask src_task = fetch_picture_task(user_data.z);
+    PictureTask src_task = fetch_picture_task(prim_user_data.z);
     vec2 src_uv = snapped_device_pos +
                   src_task.common_data.task_rect.p0 -
                   src_task.content_origin;
     vSrcUv = vec3(src_uv / texture_size, src_task.common_data.texture_layer_index);
 
-    RenderTaskCommonData backdrop_task = fetch_render_task_common_data(user_data.y);
+    RenderTaskCommonData backdrop_task = fetch_render_task_common_data(prim_user_data.y);
     vec2 backdrop_uv = snapped_device_pos +
                        backdrop_task.task_rect.p0 -
                        src_task.content_origin;
     vBackdropUv = vec3(backdrop_uv / texture_size, backdrop_task.texture_layer_index);
 }
 #endif
 
 #ifdef WR_FRAGMENT_SHADER
--- a/gfx/wr/webrender/res/brush_radial_gradient.glsl
+++ b/gfx/wr/webrender/res/brush_radial_gradient.glsl
@@ -40,17 +40,18 @@ RadialGradient fetch_radial_gradient(int
     );
 }
 
 void brush_vs(
     VertexInfo vi,
     int prim_address,
     RectWithSize local_rect,
     RectWithSize segment_rect,
-    ivec4 user_data,
+    ivec4 prim_user_data,
+    int segment_user_data,
     mat4 transform,
     PictureTask pic_task,
     int brush_flags,
     vec4 texel_rect
 ) {
     RadialGradient gradient = fetch_radial_gradient(prim_address);
 
     if ((brush_flags & BRUSH_FLAG_SEGMENT_RELATIVE) != 0) {
@@ -68,17 +69,17 @@ void brush_vs(
     // Transform all coordinates by the y scale so the
     // fragment shader can work with circles
     vec2 tile_repeat = local_rect.size / gradient.stretch_size;
     vPos.y *= gradient.ratio_xy;
     vCenter.y *= gradient.ratio_xy;
     vRepeatedSize = gradient.stretch_size;
     vRepeatedSize.y *=  gradient.ratio_xy;
 
-    vGradientAddress = user_data.x;
+    vGradientAddress = prim_user_data.x;
 
     // Whether to repeat the gradient instead of clamping.
     vGradientRepeat = float(gradient.extend_mode != EXTEND_MODE_CLAMP);
 
 #ifdef WR_FEATURE_ALPHA_PASS
     vTileRepeat = tile_repeat.xy;
     vLocalPos = vi.local_pos;
 #endif
--- a/gfx/wr/webrender/res/brush_solid.glsl
+++ b/gfx/wr/webrender/res/brush_solid.glsl
@@ -23,25 +23,26 @@ SolidBrush fetch_solid_primitive(int add
     return SolidBrush(data);
 }
 
 void brush_vs(
     VertexInfo vi,
     int prim_address,
     RectWithSize local_rect,
     RectWithSize segment_rect,
-    ivec4 user_data,
+    ivec4 prim_user_data,
+    int segment_user_data,
     mat4 transform,
     PictureTask pic_task,
     int brush_flags,
     vec4 unused
 ) {
     SolidBrush prim = fetch_solid_primitive(prim_address);
 
-    float opacity = float(user_data.x) / 65535.0;
+    float opacity = float(prim_user_data.x) / 65535.0;
     vColor = prim.color * opacity;
 
 #ifdef WR_FEATURE_ALPHA_PASS
     vLocalPos = vi.local_pos;
 #endif
 }
 #endif
 
--- a/gfx/wr/webrender/res/brush_yuv_image.glsl
+++ b/gfx/wr/webrender/res/brush_yuv_image.glsl
@@ -105,17 +105,18 @@ YuvPrimitive fetch_yuv_primitive(int add
     return YuvPrimitive(data.x, int(data.y), int(data.z));
 }
 
 void brush_vs(
     VertexInfo vi,
     int prim_address,
     RectWithSize local_rect,
     RectWithSize segment_rect,
-    ivec4 user_data,
+    ivec4 prim_user_data,
+    int segment_user_data,
     mat4 transform,
     PictureTask pic_task,
     int brush_flags,
     vec4 unused
 ) {
     vec2 f = (vi.local_pos - local_rect.p0) / local_rect.size;
 
     YuvPrimitive prim = fetch_yuv_primitive(prim_address);
@@ -128,24 +129,24 @@ void brush_vs(
     }
     vFormat = prim.yuv_format;
 
 #ifdef WR_FEATURE_ALPHA_PASS
     vLocalPos = vi.local_pos;
 #endif
 
     if (vFormat == YUV_FORMAT_PLANAR) {
-        write_uv_rect(user_data.x, f, TEX_SIZE(sColor0), vUv_Y, vUvBounds_Y);
-        write_uv_rect(user_data.y, f, TEX_SIZE(sColor1), vUv_U, vUvBounds_U);
-        write_uv_rect(user_data.z, f, TEX_SIZE(sColor2), vUv_V, vUvBounds_V);
+        write_uv_rect(prim_user_data.x, f, TEX_SIZE(sColor0), vUv_Y, vUvBounds_Y);
+        write_uv_rect(prim_user_data.y, f, TEX_SIZE(sColor1), vUv_U, vUvBounds_U);
+        write_uv_rect(prim_user_data.z, f, TEX_SIZE(sColor2), vUv_V, vUvBounds_V);
     } else if (vFormat == YUV_FORMAT_NV12) {
-        write_uv_rect(user_data.x, f, TEX_SIZE(sColor0), vUv_Y, vUvBounds_Y);
-        write_uv_rect(user_data.y, f, TEX_SIZE(sColor1), vUv_U, vUvBounds_U);
+        write_uv_rect(prim_user_data.x, f, TEX_SIZE(sColor0), vUv_Y, vUvBounds_Y);
+        write_uv_rect(prim_user_data.y, f, TEX_SIZE(sColor1), vUv_U, vUvBounds_U);
     } else if (vFormat == YUV_FORMAT_INTERLEAVED) {
-        write_uv_rect(user_data.x, f, TEX_SIZE(sColor0), vUv_Y, vUvBounds_Y);
+        write_uv_rect(prim_user_data.x, f, TEX_SIZE(sColor0), vUv_Y, vUvBounds_Y);
     }
 }
 #endif
 
 #ifdef WR_FRAGMENT_SHADER
 
 Fragment brush_fs() {
     vec3 yuv_value;
--- a/gfx/wr/webrender/res/prim_shared.glsl
+++ b/gfx/wr/webrender/res/prim_shared.glsl
@@ -51,19 +51,18 @@ in ivec4 aData;
 #define VECS_PER_PRIM_HEADER_I 2U
 
 struct PrimitiveHeader {
     RectWithSize local_rect;
     RectWithSize local_clip_rect;
     float z;
     int specific_prim_address;
     int render_task_index;
-    int clip_task_index;
     int transform_id;
-    ivec3 user_data;
+    ivec4 user_data;
 };
 
 PrimitiveHeader fetch_prim_header(int index) {
     PrimitiveHeader ph;
 
     ivec2 uv_f = get_fetch_uv(index, VECS_PER_PRIM_HEADER_F);
     vec4 local_rect = TEXEL_FETCH(sPrimitiveHeadersF, uv_f, 0, ivec2(0, 0));
     vec4 local_clip_rect = TEXEL_FETCH(sPrimitiveHeadersF, uv_f, 0, ivec2(1, 0));
@@ -71,19 +70,18 @@ PrimitiveHeader fetch_prim_header(int in
     ph.local_clip_rect = RectWithSize(local_clip_rect.xy, local_clip_rect.zw);
 
     ivec2 uv_i = get_fetch_uv(index, VECS_PER_PRIM_HEADER_I);
     ivec4 data0 = TEXEL_FETCH(sPrimitiveHeadersI, uv_i, 0, ivec2(0, 0));
     ivec4 data1 = TEXEL_FETCH(sPrimitiveHeadersI, uv_i, 0, ivec2(1, 0));
     ph.z = float(data0.x);
     ph.render_task_index = data0.y;
     ph.specific_prim_address = data0.z;
-    ph.clip_task_index = data0.w;
-    ph.transform_id = data1.x;
-    ph.user_data = data1.yzw;
+    ph.transform_id = data0.w;
+    ph.user_data = data1;
 
     return ph;
 }
 
 struct VertexInfo {
     vec2 local_pos;
     vec2 snap_offset;
     vec4 world_pos;
--- a/gfx/wr/webrender/res/ps_split_composite.glsl
+++ b/gfx/wr/webrender/res/ps_split_composite.glsl
@@ -56,17 +56,17 @@ SplitCompositeInstance fetch_composite_i
 
 void main(void) {
     SplitCompositeInstance ci = fetch_composite_instance();
     SplitGeometry geometry = fetch_split_geometry(ci.polygons_address);
     PrimitiveHeader ph = fetch_prim_header(ci.prim_header_index);
     PictureTask dest_task = fetch_picture_task(ph.render_task_index);
     Transform transform = fetch_transform(ph.transform_id);
     ImageResource res = fetch_image_resource(ph.user_data.x);
-    ClipArea clip_area = fetch_clip_area(ph.clip_task_index);
+    ClipArea clip_area = fetch_clip_area(ph.user_data.w);
 
     vec2 dest_origin = dest_task.common_data.task_rect.p0 -
                        dest_task.content_origin;
 
     vec2 local_pos = bilerp(geometry.local[0], geometry.local[1],
                             geometry.local[3], geometry.local[2],
                             aPosition.y, aPosition.x);
     vec4 world_pos = transform.m * vec4(local_pos, 0.0, 1.0);
--- a/gfx/wr/webrender/res/ps_text_run.glsl
+++ b/gfx/wr/webrender/res/ps_text_run.glsl
@@ -164,17 +164,17 @@ void main(void) {
     int glyph_index = aData.y & 0xffff;
     int raster_space = aData.y >> 16;
     int resource_address = aData.z;
     int subpx_dir = aData.w >> 16;
     int color_mode = aData.w & 0xffff;
 
     PrimitiveHeader ph = fetch_prim_header(prim_header_address);
     Transform transform = fetch_transform(ph.transform_id);
-    ClipArea clip_area = fetch_clip_area(ph.clip_task_index);
+    ClipArea clip_area = fetch_clip_area(ph.user_data.w);
     PictureTask task = fetch_picture_task(ph.render_task_index);
 
     TextRun text = fetch_text_run(ph.specific_prim_address);
     vec2 text_offset = vec2(ph.user_data.xy) / 256.0;
 
     if (color_mode == COLOR_MODE_FROM_PASS) {
         color_mode = uMode;
     }
--- a/gfx/wr/webrender/src/batch.rs
+++ b/gfx/wr/webrender/src/batch.rs
@@ -615,69 +615,62 @@ impl AlphaBatchBuilder {
             );
 
         // TODO(gw): Calculating this for every primitive is a bit
         //           wasteful. We should probably cache this in
         //           the scroll node...
         let transform_kind = transform_id.transform_kind();
         let prim_info = &ctx.scratch.prim_info[prim_instance.visibility_info.0 as usize];
         let bounding_rect = &prim_info.clip_chain.pic_clip_rect;
-
         let z_id = z_generator.next();
 
-        // Get the clip task address for the global primitive, if one was set.
-        let clip_task_address = get_clip_task_address(
-            &ctx.scratch.clip_mask_instances,
-            prim_info.clip_task_index,
-            0,
-            render_tasks,
-        ).unwrap_or(OPAQUE_TASK_ADDRESS);
-
         let prim_common_data = &ctx.data_stores.as_common_data(&prim_instance);
         let prim_rect = LayoutRect::new(
             prim_instance.prim_origin,
             prim_common_data.prim_size,
         );
 
         if is_chased {
-            println!("\tbatch {:?} with clip {:?} and bound {:?}",
-                prim_rect, clip_task_address, bounding_rect);
+            println!("\tbatch {:?} with bound {:?}", prim_rect, bounding_rect);
         }
 
-
         match prim_instance.kind {
             PrimitiveInstanceKind::Clear { data_handle } => {
                 let prim_data = &ctx.data_stores.prim[data_handle];
                 let prim_cache_address = gpu_cache.get_address(&prim_data.gpu_cache_handle);
 
                 // TODO(gw): We can abstract some of the common code below into
                 //           helper methods, as we port more primitives to make
                 //           use of interning.
 
                 let prim_header = PrimitiveHeader {
                     local_rect: prim_rect,
                     local_clip_rect: prim_info.combined_local_clip_rect,
                     task_address,
                     specific_prim_address: prim_cache_address,
-                    clip_task_address,
                     transform_id,
                 };
 
                 let prim_header_index = prim_headers.push(
                     &prim_header,
                     z_id,
-                    [get_shader_opacity(1.0), 0, 0],
+                    [get_shader_opacity(1.0), 0, 0, 0],
                 );
 
                 let batch_key = BatchKey {
                     blend_mode: BlendMode::PremultipliedDestOut,
                     kind: BatchKind::Brush(BrushBatchKind::Solid),
                     textures: BatchTextures::no_texture(),
                 };
 
+                let clip_task_address = ctx.get_prim_clip_task_address(
+                    prim_info.clip_task_index,
+                    render_tasks,
+                ).unwrap_or(OPAQUE_TASK_ADDRESS);
+
                 let instance = PrimitiveInstanceData::from(BrushInstance {
                     segment_index: INVALID_SEGMENT_INDEX,
                     edge_flags: EdgeAaSegmentMask::all(),
                     clip_task_address,
                     brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
                     prim_header_index,
                     user_data: 0,
                 });
@@ -722,26 +715,26 @@ impl AlphaBatchBuilder {
                     BlendMode::None
                 };
 
                 let prim_header = PrimitiveHeader {
                     local_rect: prim_rect,
                     local_clip_rect: prim_info.combined_local_clip_rect,
                     task_address,
                     specific_prim_address: prim_cache_address,
-                    clip_task_address,
                     transform_id,
                 };
 
                 let batch_params = BrushBatchParameters::instanced(
                     BrushBatchKind::Image(ImageBufferKind::Texture2DArray),
                     [
                         ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16),
                         RasterizationSpace::Local as i32,
                         get_shader_opacity(1.0),
+                        0,
                     ],
                     segment_data,
                 );
 
                 let prim_header_index = prim_headers.push(
                     &prim_header,
                     z_id,
                     batch_params.prim_user_data,
@@ -750,17 +743,16 @@ impl AlphaBatchBuilder {
                 let border_data = &prim_data.kind;
                 self.add_segmented_prim_to_batch(
                     Some(border_data.brush_segments.as_slice()),
                     common_data.opacity,
                     &batch_params,
                     specified_blend_mode,
                     non_segmented_blend_mode,
                     prim_header_index,
-                    clip_task_address,
                     bounding_rect,
                     transform_kind,
                     render_tasks,
                     z_id,
                     prim_info.clip_task_index,
                     ctx,
                 );
             }
@@ -775,20 +767,24 @@ impl AlphaBatchBuilder {
                 let alpha_batch_list = &mut self.batch_lists.last_mut().unwrap().alpha_batch_list;
                 let prim_cache_address = gpu_cache.get_address(&prim_data.gpu_cache_handle);
 
                 let prim_header = PrimitiveHeader {
                     local_rect: prim_rect,
                     local_clip_rect: prim_info.combined_local_clip_rect,
                     task_address,
                     specific_prim_address: prim_cache_address,
-                    clip_task_address,
                     transform_id,
                 };
 
+                let clip_task_address = ctx.get_prim_clip_task_address(
+                    prim_info.clip_task_index,
+                    render_tasks,
+                ).unwrap_or(OPAQUE_TASK_ADDRESS);
+
                 let glyph_keys = &ctx.scratch.glyph_keys[run.glyph_keys_range];
 
                 ctx.resource_cache.fetch_glyphs(
                     run.used_font.clone(),
                     &glyph_keys,
                     glyph_fetch_buffer,
                     gpu_cache,
                     |texture_id, mut glyph_format, glyphs| {
@@ -855,16 +851,17 @@ impl AlphaBatchBuilder {
                         let raster_scale = run.raster_space.local_scale().unwrap_or(1.0).max(0.001);
                         let prim_header_index = prim_headers.push(
                             &prim_header,
                             z_id,
                             [
                                 (run.reference_frame_relative_offset.x * 256.0) as i32,
                                 (run.reference_frame_relative_offset.y * 256.0) as i32,
                                 (raster_scale * 65535.0).round() as i32,
+                                clip_task_address.0 as i32,
                             ],
                         );
                         let key = BatchKey::new(kind, blend_mode, textures);
                         let base_instance = GlyphInstance::new(
                             prim_header_index,
                         );
                         let batch = alpha_batch_list.set_params_and_get_batch(
                             key,
@@ -905,25 +902,26 @@ impl AlphaBatchBuilder {
                         let textures = BatchTextures::color(cache_item.texture_id);
                         (
                             BrushBatchKind::Image(get_buffer_kind(cache_item.texture_id)),
                             textures,
                             [
                                 ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16),
                                 RasterizationSpace::Local as i32,
                                 get_shader_opacity(1.0),
+                                0,
                             ],
                             cache_item.uv_rect_handle.as_int(gpu_cache),
                         )
                     }
                     None => {
                         (
                             BrushBatchKind::Solid,
                             BatchTextures::no_texture(),
-                            [get_shader_opacity(1.0), 0, 0],
+                            [get_shader_opacity(1.0), 0, 0, 0],
                             0,
                         )
                     }
                 };
 
                 // TODO(gw): We can abstract some of the common code below into
                 //           helper methods, as we port more primitives to make
                 //           use of interning.
@@ -936,32 +934,36 @@ impl AlphaBatchBuilder {
                     BlendMode::None
                 };
 
                 let prim_header = PrimitiveHeader {
                     local_rect: prim_rect,
                     local_clip_rect: prim_info.combined_local_clip_rect,
                     task_address,
                     specific_prim_address: prim_cache_address,
-                    clip_task_address,
                     transform_id,
                 };
 
                 let prim_header_index = prim_headers.push(
                     &prim_header,
                     z_id,
                     prim_user_data,
                 );
 
                 let batch_key = BatchKey {
                     blend_mode,
                     kind: BatchKind::Brush(batch_kind),
                     textures: textures,
                 };
 
+                let clip_task_address = ctx.get_prim_clip_task_address(
+                    prim_info.clip_task_index,
+                    render_tasks,
+                ).unwrap_or(OPAQUE_TASK_ADDRESS);
+
                 let instance = PrimitiveInstanceData::from(BrushInstance {
                     segment_index: INVALID_SEGMENT_INDEX,
                     edge_flags: EdgeAaSegmentMask::all(),
                     clip_task_address,
                     brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
                     prim_header_index,
                     user_data: segment_user_data,
                 });
@@ -978,17 +980,16 @@ impl AlphaBatchBuilder {
                 let non_segmented_blend_mode = BlendMode::PremultipliedAlpha;
                 let prim_cache_address = gpu_cache.get_address(&ctx.globals.default_image_handle);
 
                 let prim_header = PrimitiveHeader {
                     local_rect: picture.local_rect,
                     local_clip_rect: prim_info.combined_local_clip_rect,
                     task_address,
                     specific_prim_address: prim_cache_address,
-                    clip_task_address,
                     transform_id,
                 };
 
                 match picture.context_3d {
                     // Convert all children of the 3D hierarchy root into batches.
                     Picture3DContext::In { root_data: Some(ref list), .. } => {
                         for child in list {
                             let prim_instance = &picture.prim_list.prim_instances[child.anchor];
@@ -1006,31 +1007,27 @@ impl AlphaBatchBuilder {
                                 PrimitiveInstanceKind::LinearGradient { .. } |
                                 PrimitiveInstanceKind::RadialGradient { .. } |
                                 PrimitiveInstanceKind::Clear { .. } => {
                                     unreachable!();
                                 }
                             };
                             let pic = &ctx.prim_store.pictures[child_pic_index.0];
 
-
                             // Get clip task, if set, for the picture primitive.
-                            let clip_task_address = get_clip_task_address(
-                                &ctx.scratch.clip_mask_instances,
+                            let clip_task_address = ctx.get_prim_clip_task_address(
                                 prim_info.clip_task_index,
-                                0,
                                 render_tasks,
                             ).unwrap_or(OPAQUE_TASK_ADDRESS);
 
                             let prim_header = PrimitiveHeader {
                                 local_rect: pic.local_rect,
                                 local_clip_rect: prim_info.combined_local_clip_rect,
                                 task_address,
                                 specific_prim_address: GpuCacheAddress::invalid(),
-                                clip_task_address,
                                 transform_id: transforms
                                     .get_id(
                                         child.spatial_node_index,
                                         root_spatial_node_index,
                                         ctx.clip_scroll_tree,
                                     ),
                             };
 
@@ -1048,16 +1045,17 @@ impl AlphaBatchBuilder {
                                     ctx.resource_cache,
                                     gpu_cache,
                                 );
 
                             let prim_header_index = prim_headers.push(&prim_header, z_id, [
                                 uv_rect_address.as_int(),
                                 if raster_config.establishes_raster_root { 1 } else { 0 },
                                 0,
+                                clip_task_address.0 as i32,
                             ]);
 
                             let key = BatchKey::new(
                                 BatchKind::SplitComposite,
                                 BlendMode::PremultipliedAlpha,
                                 BatchTextures::no_texture(),
                             );
 
@@ -1094,16 +1092,21 @@ impl AlphaBatchBuilder {
                         let mut brush_flags = BrushFlags::SNAP_TO_PRIMITIVE;
 
                         // If the child picture was rendered in local space, we can safely
                         // interpolate the UV coordinates with perspective correction.
                         if raster_config.establishes_raster_root {
                             brush_flags |= BrushFlags::PERSPECTIVE_INTERPOLATION;
                         };
 
+                        let clip_task_address = ctx.get_prim_clip_task_address(
+                            prim_info.clip_task_index,
+                            render_tasks,
+                        ).unwrap_or(OPAQUE_TASK_ADDRESS);
+
                         match raster_config.composite_mode {
                             PictureCompositeMode::TileCache { .. } => {
                                 let tile_cache = picture.tile_cache.as_ref().unwrap();
 
                                 // If the tile cache is disabled, just recurse into the
                                 // picture like a normal pass-through picture, adding
                                 // any child primitives into the parent surface batches.
                                 if !tile_cache.is_enabled {
@@ -1146,24 +1149,24 @@ impl AlphaBatchBuilder {
                                         // Get the local rect of the tile.
                                         let tile_rect = tile.local_rect;
 
                                         let prim_header = PrimitiveHeader {
                                             local_rect: tile_rect,
                                             local_clip_rect,
                                             task_address,
                                             specific_prim_address: prim_cache_address,
-                                            clip_task_address,
                                             transform_id,
                                         };
 
                                         let prim_header_index = prim_headers.push(&prim_header, z_id, [
                                             ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16),
                                             RasterizationSpace::Local as i32,
                                             get_shader_opacity(1.0),
+                                            0,
                                         ]);
 
                                         let cache_item = ctx
                                             .resource_cache
                                             .get_texture_cache_item(&tile.handle);
 
                                         let key = BatchKey::new(
                                             kind,
@@ -1273,16 +1276,17 @@ impl AlphaBatchBuilder {
                                             kind,
                                             non_segmented_blend_mode,
                                             textures,
                                         );
                                         let prim_header_index = prim_headers.push(&prim_header, z_id, [
                                             ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16),
                                             RasterizationSpace::Screen as i32,
                                             get_shader_opacity(1.0),
+                                            0,
                                         ]);
 
                                         let instance = BrushInstance {
                                             prim_header_index,
                                             segment_index: INVALID_SEGMENT_INDEX,
                                             edge_flags: EdgeAaSegmentMask::empty(),
                                             brush_flags,
                                             clip_task_address,
@@ -1338,30 +1342,32 @@ impl AlphaBatchBuilder {
 
                                         let z_id_shadow = z_id;
                                         let z_id_content = z_generator.next();
 
                                         let content_prim_header_index = prim_headers.push(&prim_header, z_id_content, [
                                             ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16),
                                             RasterizationSpace::Screen as i32,
                                             get_shader_opacity(1.0),
+                                            0,
                                         ]);
 
                                         let shadow_rect = prim_header.local_rect.translate(&offset);
 
                                         let shadow_prim_header = PrimitiveHeader {
                                             local_rect: shadow_rect,
                                             specific_prim_address: shadow_prim_address,
                                             ..prim_header
                                         };
 
                                         let shadow_prim_header_index = prim_headers.push(&shadow_prim_header, z_id_shadow, [
                                             ShaderColorMode::Alpha as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16),
                                             RasterizationSpace::Screen as i32,
                                             get_shader_opacity(1.0),
+                                            0,
                                         ]);
 
                                         let shadow_instance = BrushInstance {
                                             prim_header_index: shadow_prim_header_index,
                                             clip_task_address,
                                             segment_index: INVALID_SEGMENT_INDEX,
                                             edge_flags: EdgeAaSegmentMask::empty(),
                                             brush_flags,
@@ -1448,16 +1454,17 @@ impl AlphaBatchBuilder {
                                             BlendMode::PremultipliedAlpha,
                                             textures,
                                         );
 
                                         let prim_header_index = prim_headers.push(&prim_header, z_id, [
                                             uv_rect_address.as_int(),
                                             filter_mode,
                                             user_data,
+                                            0,
                                         ]);
 
                                         let instance = BrushInstance {
                                             prim_header_index,
                                             clip_task_address,
                                             segment_index: INVALID_SEGMENT_INDEX,
                                             edge_flags: EdgeAaSegmentMask::empty(),
                                             brush_flags,
@@ -1504,16 +1511,17 @@ impl AlphaBatchBuilder {
                                     BlendMode::PremultipliedAlpha,
                                     textures,
                                 );
 
                                 let prim_header_index = prim_headers.push(&prim_header, z_id, [
                                     uv_rect_address.as_int(),
                                     filter_mode,
                                     user_data,
+                                    0,
                                 ]);
 
                                 let instance = BrushInstance {
                                     prim_header_index,
                                     clip_task_address,
                                     segment_index: INVALID_SEGMENT_INDEX,
                                     edge_flags: EdgeAaSegmentMask::empty(),
                                     brush_flags,
@@ -1547,16 +1555,17 @@ impl AlphaBatchBuilder {
                                     BatchTextures::no_texture(),
                                 );
                                 let backdrop_task_address = render_tasks.get_task_address(backdrop_id);
                                 let source_task_address = render_tasks.get_task_address(cache_task_id);
                                 let prim_header_index = prim_headers.push(&prim_header, z_id, [
                                     mode as u32 as i32,
                                     backdrop_task_address.0 as i32,
                                     source_task_address.0 as i32,
+                                    0,
                                 ]);
 
                                 let instance = BrushInstance {
                                     prim_header_index,
                                     clip_task_address,
                                     segment_index: INVALID_SEGMENT_INDEX,
                                     edge_flags: EdgeAaSegmentMask::empty(),
                                     brush_flags,
@@ -1587,16 +1596,17 @@ impl AlphaBatchBuilder {
 
                                 let uv_rect_address = render_tasks[cache_task_id]
                                     .get_texture_address(gpu_cache)
                                     .as_int();
                                 let prim_header_index = prim_headers.push(&prim_header, z_id, [
                                     ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16),
                                     RasterizationSpace::Screen as i32,
                                     get_shader_opacity(1.0),
+                                    0,
                                 ]);
 
                                 let instance = BrushInstance {
                                     prim_header_index,
                                     clip_task_address,
                                     segment_index: INVALID_SEGMENT_INDEX,
                                     edge_flags: EdgeAaSegmentMask::empty(),
                                     brush_flags,
@@ -1657,27 +1667,27 @@ impl AlphaBatchBuilder {
                     BlendMode::None
                 };
 
                 let prim_header = PrimitiveHeader {
                     local_rect: prim_rect,
                     local_clip_rect: prim_info.combined_local_clip_rect,
                     task_address,
                     specific_prim_address: prim_cache_address,
-                    clip_task_address,
                     transform_id,
                 };
 
                 let batch_params = BrushBatchParameters::shared(
                     BrushBatchKind::Image(get_buffer_kind(cache_item.texture_id)),
                     textures,
                     [
                         ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16),
                         RasterizationSpace::Local as i32,
                         get_shader_opacity(1.0),
+                        0,
                     ],
                     cache_item.uv_rect_handle.as_int(gpu_cache),
                 );
 
                 let prim_header_index = prim_headers.push(
                     &prim_header,
                     z_id,
                     batch_params.prim_user_data,
@@ -1685,17 +1695,16 @@ impl AlphaBatchBuilder {
 
                 self.add_segmented_prim_to_batch(
                     Some(border_data.brush_segments.as_slice()),
                     common_data.opacity,
                     &batch_params,
                     specified_blend_mode,
                     non_segmented_blend_mode,
                     prim_header_index,
-                    clip_task_address,
                     bounding_rect,
                     transform_kind,
                     render_tasks,
                     z_id,
                     prim_info.clip_task_index,
                     ctx,
                 );
             }
@@ -1714,51 +1723,49 @@ impl AlphaBatchBuilder {
                     specified_blend_mode
                 } else {
                     BlendMode::None
                 };
 
                 let batch_params = BrushBatchParameters::shared(
                     BrushBatchKind::Solid,
                     BatchTextures::no_texture(),
-                    [get_shader_opacity(opacity_binding), 0, 0],
+                    [get_shader_opacity(opacity_binding), 0, 0, 0],
                     0,
                 );
 
                 let (prim_cache_address, segments) = if segment_instance_index == SegmentInstanceIndex::UNUSED {
                     (gpu_cache.get_address(&prim_data.gpu_cache_handle), None)
                 } else {
                     let segment_instance = &ctx.scratch.segment_instances[segment_instance_index];
                     let segments = Some(&ctx.scratch.segments[segment_instance.segments_range]);
                     (gpu_cache.get_address(&segment_instance.gpu_cache_handle), segments)
                 };
 
                 let prim_header = PrimitiveHeader {
                     local_rect: prim_rect,
                     local_clip_rect: prim_info.combined_local_clip_rect,
                     task_address,
                     specific_prim_address: prim_cache_address,
-                    clip_task_address,
                     transform_id,
                 };
 
                 let prim_header_index = prim_headers.push(
                     &prim_header,
                     z_id,
                     batch_params.prim_user_data,
                 );
 
                 self.add_segmented_prim_to_batch(
                     segments,
                     opacity,
                     &batch_params,
                     specified_blend_mode,
                     non_segmented_blend_mode,
                     prim_header_index,
-                    clip_task_address,
                     bounding_rect,
                     transform_kind,
                     render_tasks,
                     z_id,
                     prim_info.clip_task_index,
                     ctx,
                 );
             }
@@ -1810,16 +1817,17 @@ impl AlphaBatchBuilder {
 
                 let batch_params = BrushBatchParameters::shared(
                     kind,
                     textures,
                     [
                         uv_rect_addresses[0],
                         uv_rect_addresses[1],
                         uv_rect_addresses[2],
+                        0,
                     ],
                     0,
                 );
 
                 let specified_blend_mode = BlendMode::PremultipliedAlpha;
 
                 let non_segmented_blend_mode = if !prim_common_data.opacity.is_opaque ||
                     prim_info.clip_task_index != ClipTaskIndex::INVALID ||
@@ -1839,34 +1847,32 @@ impl AlphaBatchBuilder {
                     (gpu_cache.get_address(&segment_instance.gpu_cache_handle), segments)
                 };
 
                 let prim_header = PrimitiveHeader {
                     local_rect: prim_rect,
                     local_clip_rect: prim_info.combined_local_clip_rect,
                     task_address,
                     specific_prim_address: prim_cache_address,
-                    clip_task_address,
                     transform_id,
                 };
 
                 let prim_header_index = prim_headers.push(
                     &prim_header,
                     z_id,
                     batch_params.prim_user_data,
                 );
 
                 self.add_segmented_prim_to_batch(
                     segments,
                     prim_common_data.opacity,
                     &batch_params,
                     specified_blend_mode,
                     non_segmented_blend_mode,
                     prim_header_index,
-                    clip_task_address,
                     bounding_rect,
                     transform_kind,
                     render_tasks,
                     z_id,
                     prim_info.clip_task_index,
                     ctx,
                 );
             }
@@ -1883,16 +1889,17 @@ impl AlphaBatchBuilder {
                     key: image_data.key,
                     rendering: image_data.image_rendering,
                     tile: None,
                 };
                 let prim_user_data = [
                     ShaderColorMode::Image as i32 | ((image_data.alpha_type as i32) << 16),
                     RasterizationSpace::Local as i32,
                     get_shader_opacity(opacity_binding),
+                    0,
                 ];
 
                 if image_instance.visible_tiles.is_empty() {
                     let cache_item = match image_data.source {
                         ImageSource::Default => {
                             resolve_image(
                                 request,
                                 ctx.resource_cache,
@@ -1944,45 +1951,48 @@ impl AlphaBatchBuilder {
                         (gpu_cache.get_address(&segment_instance.gpu_cache_handle), segments)
                     };
 
                     let prim_header = PrimitiveHeader {
                         local_rect: prim_rect,
                         local_clip_rect: prim_info.combined_local_clip_rect,
                         task_address,
                         specific_prim_address: prim_cache_address,
-                        clip_task_address,
                         transform_id,
                     };
 
                     let prim_header_index = prim_headers.push(
                         &prim_header,
                         z_id,
                         batch_params.prim_user_data,
                     );
 
                     self.add_segmented_prim_to_batch(
                         segments,
                         opacity,
                         &batch_params,
                         specified_blend_mode,
                         non_segmented_blend_mode,
                         prim_header_index,
-                        clip_task_address,
                         bounding_rect,
                         transform_kind,
                         render_tasks,
                         z_id,
                         prim_info.clip_task_index,
                         ctx,
                     );
                 } else {
                     const VECS_PER_SPECIFIC_BRUSH: usize = 3;
                     let max_tiles_per_header = (MAX_VERTEX_TEXTURE_WIDTH - VECS_PER_SPECIFIC_BRUSH) / VECS_PER_SEGMENT;
 
+                    let clip_task_address = ctx.get_prim_clip_task_address(
+                        prim_info.clip_task_index,
+                        render_tasks,
+                    ).unwrap_or(OPAQUE_TASK_ADDRESS);
+
                     // use temporary block storage since we don't know the number of visible tiles beforehand
                     let mut gpu_blocks = Vec::<GpuBlockData>::new();
                     for chunk in image_instance.visible_tiles.chunks(max_tiles_per_header) {
                         gpu_blocks.clear();
                         gpu_blocks.push(PremultipliedColorF::WHITE.into()); //color
                         gpu_blocks.push(PremultipliedColorF::WHITE.into()); //bg color
                         gpu_blocks.push([-1.0, 0.0, 0.0, 0.0].into()); //stretch size
                         // negative first value makes the shader code ignore it and use the local size instead
@@ -1993,17 +2003,16 @@ impl AlphaBatchBuilder {
                         }
 
                         let gpu_handle = gpu_cache.push_per_frame_blocks(&gpu_blocks);
                         let prim_header = PrimitiveHeader {
                             local_rect: prim_rect,
                             local_clip_rect: image_instance.tight_local_clip_rect,
                             task_address,
                             specific_prim_address: gpu_cache.get_address(&gpu_handle),
-                            clip_task_address,
                             transform_id,
                         };
                         let prim_header_index = prim_headers.push(&prim_header, z_id, prim_user_data);
 
                         for (i, tile) in chunk.iter().enumerate() {
                             if let Some((batch_kind, textures, uv_rect_address)) = get_image_tile_params(
                                 ctx.resource_cache,
                                 gpu_cache,
@@ -2039,17 +2048,16 @@ impl AlphaBatchBuilder {
                 let prim_data = &ctx.data_stores.linear_grad[data_handle];
                 let specified_blend_mode = BlendMode::PremultipliedAlpha;
 
                 let mut prim_header = PrimitiveHeader {
                     local_rect: prim_rect,
                     local_clip_rect: prim_info.combined_local_clip_rect,
                     task_address,
                     specific_prim_address: GpuCacheAddress::invalid(),
-                    clip_task_address,
                     transform_id,
                 };
 
                 let non_segmented_blend_mode = if !prim_data.opacity.is_opaque ||
                     prim_info.clip_task_index != ClipTaskIndex::INVALID ||
                     transform_kind == TransformedRectKind::Complex
                 {
                     specified_blend_mode
@@ -2068,32 +2076,38 @@ impl AlphaBatchBuilder {
                     }
 
                     let textures = BatchTextures::color(cache_item.texture_id);
                     let batch_kind = BrushBatchKind::Image(get_buffer_kind(cache_item.texture_id));
                     let prim_user_data = [
                         ShaderColorMode::Image as i32 | ((AlphaType::PremultipliedAlpha as i32) << 16),
                         RasterizationSpace::Local as i32,
                         get_shader_opacity(1.0),
+                        0,
                     ];
                     let segment_user_data = cache_item.uv_rect_handle.as_int(gpu_cache);
                     prim_header.specific_prim_address = gpu_cache.get_address(&ctx.globals.default_image_handle);
 
                     let prim_header_index = prim_headers.push(
                         &prim_header,
                         z_id,
                         prim_user_data,
                     );
 
                     let batch_key = BatchKey {
                         blend_mode: non_segmented_blend_mode,
                         kind: BatchKind::Brush(batch_kind),
                         textures: textures,
                     };
 
+                    let clip_task_address = ctx.get_prim_clip_task_address(
+                        prim_info.clip_task_index,
+                        render_tasks,
+                    ).unwrap_or(OPAQUE_TASK_ADDRESS);
+
                     let instance = PrimitiveInstanceData::from(BrushInstance {
                         segment_index: INVALID_SEGMENT_INDEX,
                         edge_flags: EdgeAaSegmentMask::all(),
                         clip_task_address,
                         brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
                         prim_header_index,
                         user_data: segment_user_data,
                     });
@@ -2107,16 +2121,17 @@ impl AlphaBatchBuilder {
                 } else if gradient.visible_tiles_range.is_empty() {
                     let batch_params = BrushBatchParameters::shared(
                         BrushBatchKind::LinearGradient,
                         BatchTextures::no_texture(),
                         [
                             prim_data.stops_handle.as_int(gpu_cache),
                             0,
                             0,
+                            0,
                         ],
                         0,
                     );
 
                     prim_header.specific_prim_address = gpu_cache.get_address(&prim_data.gpu_cache_handle);
 
                     let prim_header_index = prim_headers.push(
                         &prim_header,
@@ -2132,27 +2147,31 @@ impl AlphaBatchBuilder {
 
                     self.add_segmented_prim_to_batch(
                         segments,
                         prim_data.opacity,
                         &batch_params,
                         specified_blend_mode,
                         non_segmented_blend_mode,
                         prim_header_index,
-                        clip_task_address,
                         bounding_rect,
                         transform_kind,
                         render_tasks,
                         z_id,
                         prim_info.clip_task_index,
                         ctx,
                     );
                 } else {
                     let visible_tiles = &ctx.scratch.gradient_tiles[gradient.visible_tiles_range];
 
+                    let clip_task_address = ctx.get_prim_clip_task_address(
+                        prim_info.clip_task_index,
+                        render_tasks,
+                    ).unwrap_or(OPAQUE_TASK_ADDRESS);
+
                     add_gradient_tiles(
                         visible_tiles,
                         &prim_data.stops_handle,
                         BrushBatchKind::LinearGradient,
                         specified_blend_mode,
                         bounding_rect,
                         clip_task_address,
                         gpu_cache,
@@ -2167,17 +2186,16 @@ impl AlphaBatchBuilder {
                 let prim_data = &ctx.data_stores.radial_grad[data_handle];
                 let specified_blend_mode = BlendMode::PremultipliedAlpha;
 
                 let mut prim_header = PrimitiveHeader {
                     local_rect: prim_rect,
                     local_clip_rect: prim_info.combined_local_clip_rect,
                     task_address,
                     specific_prim_address: GpuCacheAddress::invalid(),
-                    clip_task_address,
                     transform_id,
                 };
 
                 if visible_tiles_range.is_empty() {
                     let non_segmented_blend_mode = if !prim_data.opacity.is_opaque ||
                         prim_info.clip_task_index != ClipTaskIndex::INVALID ||
                         transform_kind == TransformedRectKind::Complex
                     {
@@ -2188,16 +2206,17 @@ impl AlphaBatchBuilder {
 
                     let batch_params = BrushBatchParameters::shared(
                         BrushBatchKind::RadialGradient,
                         BatchTextures::no_texture(),
                         [
                             prim_data.stops_handle.as_int(gpu_cache),
                             0,
                             0,
+                            0,
                         ],
                         0,
                     );
 
                     prim_header.specific_prim_address = gpu_cache.get_address(&prim_data.gpu_cache_handle);
 
                     let prim_header_index = prim_headers.push(
                         &prim_header,
@@ -2213,27 +2232,31 @@ impl AlphaBatchBuilder {
 
                     self.add_segmented_prim_to_batch(
                         segments,
                         prim_data.opacity,
                         &batch_params,
                         specified_blend_mode,
                         non_segmented_blend_mode,
                         prim_header_index,
-                        clip_task_address,
                         bounding_rect,
                         transform_kind,
                         render_tasks,
                         z_id,
                         prim_info.clip_task_index,
                         ctx,
                     );
                 } else {
                     let visible_tiles = &ctx.scratch.gradient_tiles[*visible_tiles_range];
 
+                    let clip_task_address = ctx.get_prim_clip_task_address(
+                        prim_info.clip_task_index,
+                        render_tasks,
+                    ).unwrap_or(OPAQUE_TASK_ADDRESS);
+
                     add_gradient_tiles(
                         visible_tiles,
                         &prim_data.stops_handle,
                         BrushBatchKind::RadialGradient,
                         specified_blend_mode,
                         bounding_rect,
                         clip_task_address,
                         gpu_cache,
@@ -2263,18 +2286,17 @@ impl AlphaBatchBuilder {
         prim_opacity: PrimitiveOpacity,
         clip_task_index: ClipTaskIndex,
         ctx: &RenderTargetContext,
     ) {
         debug_assert!(clip_task_index != ClipTaskIndex::INVALID);
 
         // Get GPU address of clip task for this segment, or None if
         // the entire segment is clipped out.
-        let clip_task_address = match get_clip_task_address(
-            &ctx.scratch.clip_mask_instances,
+        let clip_task_address = match ctx.get_clip_task_address(
             clip_task_index,
             segment_index,
             render_tasks,
         ) {
             Some(clip_task_address) => clip_task_address,
             None => return,
         };
 
@@ -2311,17 +2333,16 @@ impl AlphaBatchBuilder {
     fn add_segmented_prim_to_batch(
         &mut self,
         brush_segments: Option<&[BrushSegment]>,
         prim_opacity: PrimitiveOpacity,
         params: &BrushBatchParameters,
         alpha_blend_mode: BlendMode,
         non_segmented_blend_mode: BlendMode,
         prim_header_index: PrimitiveHeaderIndex,
-        clip_task_address: RenderTaskAddress,
         bounding_rect: &PictureRect,
         transform_kind: TransformedRectKind,
         render_tasks: &RenderTaskTree,
         z_id: ZBufferId,
         clip_task_index: ClipTaskIndex,
         ctx: &RenderTargetContext,
     ) {
         match (brush_segments, &params.segment_data) {
@@ -2378,16 +2399,20 @@ impl AlphaBatchBuilder {
             (None, SegmentDataKind::Shared(ref segment_data)) => {
                 // No segments, and thus no per-segment instance data.
                 // Note: the blend mode already takes opacity into account
                 let batch_key = BatchKey {
                     blend_mode: non_segmented_blend_mode,
                     kind: BatchKind::Brush(params.batch_kind),
                     textures: segment_data.textures,
                 };
+                let clip_task_address = ctx.get_prim_clip_task_address(
+                    clip_task_index,
+                    render_tasks,
+                ).unwrap_or(OPAQUE_TASK_ADDRESS);
                 let instance = PrimitiveInstanceData::from(BrushInstance {
                     segment_index: INVALID_SEGMENT_INDEX,
                     edge_flags: EdgeAaSegmentMask::all(),
                     clip_task_address,
                     brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
                     prim_header_index,
                     user_data: segment_data.user_data,
                 });
@@ -2425,17 +2450,17 @@ fn add_gradient_tiles(
             blend_mode: blend_mode,
             kind: BatchKind::Brush(kind),
             textures: BatchTextures::no_texture(),
         },
         bounding_rect,
         z_id,
     );
 
-    let user_data = [stops_handle.as_int(gpu_cache), 0, 0];
+    let user_data = [stops_handle.as_int(gpu_cache), 0, 0, 0];
 
     for tile in visible_tiles {
         let prim_header = PrimitiveHeader {
             specific_prim_address: gpu_cache.get_address(&tile.handle),
             local_rect: tile.local_rect,
             local_clip_rect: tile.local_clip_rect,
             ..*base_prim_header
         };
@@ -2486,41 +2511,41 @@ enum SegmentDataKind {
     Shared(SegmentInstanceData),
     Instanced(SmallVec<[SegmentInstanceData; 8]>),
 }
 
 /// The parameters that are specific to a kind of brush,
 /// used by the common method to add a brush to batches.
 struct BrushBatchParameters {
     batch_kind: BrushBatchKind,
-    prim_user_data: [i32; 3],
+    prim_user_data: [i32; 4],
     segment_data: SegmentDataKind,
 }
 
 impl BrushBatchParameters {
     /// This brush instance has a list of per-segment
     /// instance data.
     fn instanced(
         batch_kind: BrushBatchKind,
-        prim_user_data: [i32; 3],
+        prim_user_data: [i32; 4],
         segment_data: SmallVec<[SegmentInstanceData; 8]>,
     ) -> Self {
         BrushBatchParameters {
             batch_kind,
             prim_user_data,
             segment_data: SegmentDataKind::Instanced(segment_data),
         }
     }
 
     /// This brush instance shares the per-segment data
     /// across all segments.
     fn shared(
         batch_kind: BrushBatchKind,
         textures: BatchTextures,
-        prim_user_data: [i32; 3],
+        prim_user_data: [i32; 4],
         segment_user_data: i32,
     ) -> Self {
         BrushBatchParameters {
             batch_kind,
             prim_user_data,
             segment_data: SegmentDataKind::Shared(
                 SegmentInstanceData {
                     textures,
@@ -3050,32 +3075,48 @@ fn get_buffer_kind(texture: TextureSourc
         _ => ImageBufferKind::Texture2DArray,
     }
 }
 
 fn get_shader_opacity(opacity: f32) -> i32 {
     (opacity * 65535.0).round() as i32
 }
 
-/// Retrieve the GPU task address for a given clip task instance.
-/// Returns None if the segment was completely clipped out.
-/// Returns Some(OPAQUE_TASK_ADDRESS) if no clip mask is needed.
-/// Returns Some(task_address) if there was a valid clip mask.
-fn get_clip_task_address(
-    clip_mask_instances: &[ClipMaskKind],
-    clip_task_index: ClipTaskIndex,
-    offset: i32,
-    render_tasks: &RenderTaskTree,
-) -> Option<RenderTaskAddress> {
-    let address = match clip_mask_instances[clip_task_index.0 as usize + offset as usize] {
-        ClipMaskKind::Mask(task_id) => {
-            render_tasks.get_task_address(task_id)
-        }
-        ClipMaskKind::None => {
-            OPAQUE_TASK_ADDRESS
-        }
-        ClipMaskKind::Clipped => {
-            return None;
-        }
-    };
+impl<'a, 'rc> RenderTargetContext<'a, 'rc> {
+    /// Retrieve the GPU task address for a given clip task instance.
+    /// Returns None if the segment was completely clipped out.
+    /// Returns Some(OPAQUE_TASK_ADDRESS) if no clip mask is needed.
+    /// Returns Some(task_address) if there was a valid clip mask.
+    fn get_clip_task_address(
+        &self,
+        clip_task_index: ClipTaskIndex,
+        offset: i32,
+        render_tasks: &RenderTaskTree,
+    ) -> Option<RenderTaskAddress> {
+        let address = match self.scratch.clip_mask_instances[clip_task_index.0 as usize + offset as usize] {
+            ClipMaskKind::Mask(task_id) => {
+                render_tasks.get_task_address(task_id)
+            }
+            ClipMaskKind::None => {
+                OPAQUE_TASK_ADDRESS
+            }
+            ClipMaskKind::Clipped => {
+                return None;
+            }
+        };
 
-    Some(address)
+        Some(address)
+    }
+
+    /// Helper function to get the clip task address for a
+    /// non-segmented primitive.
+    fn get_prim_clip_task_address(
+        &self,
+        clip_task_index: ClipTaskIndex,
+        render_tasks: &RenderTaskTree,
+    ) -> Option<RenderTaskAddress> {
+        self.get_clip_task_address(
+            clip_task_index,
+            0,
+            render_tasks,
+        )
+    }
 }
--- a/gfx/wr/webrender/src/gpu_types.rs
+++ b/gfx/wr/webrender/src/gpu_types.rs
@@ -208,48 +208,46 @@ impl PrimitiveHeaders {
         }
     }
 
     // Add a new primitive header.
     pub fn push(
         &mut self,
         prim_header: &PrimitiveHeader,
         z: ZBufferId,
-        user_data: [i32; 3],
+        user_data: [i32; 4],
     ) -> PrimitiveHeaderIndex {
         debug_assert_eq!(self.headers_int.len(), self.headers_float.len());
         let id = self.headers_float.len();
 
         self.headers_float.push(PrimitiveHeaderF {
             local_rect: prim_header.local_rect,
             local_clip_rect: prim_header.local_clip_rect,
         });
 
         self.headers_int.push(PrimitiveHeaderI {
             z,
             task_address: prim_header.task_address,
             specific_prim_address: prim_header.specific_prim_address.as_int(),
-            clip_task_address: prim_header.clip_task_address,
             transform_id: prim_header.transform_id,
             user_data,
         });
 
         PrimitiveHeaderIndex(id as i32)
     }
 }
 
 // This is a convenience type used to make it easier to pass
 // the common parts around during batching.
 #[derive(Debug)]
 pub struct PrimitiveHeader {
     pub local_rect: LayoutRect,
     pub local_clip_rect: LayoutRect,
     pub task_address: RenderTaskAddress,
     pub specific_prim_address: GpuCacheAddress,
-    pub clip_task_address: RenderTaskAddress,
     pub transform_id: TransformPaletteId,
 }
 
 // f32 parts of a primitive header
 #[derive(Debug)]
 #[repr(C)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
@@ -263,19 +261,18 @@ pub struct PrimitiveHeaderF {
 #[derive(Debug)]
 #[repr(C)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct PrimitiveHeaderI {
     pub z: ZBufferId,
     pub task_address: RenderTaskAddress,
     pub specific_prim_address: i32,
-    pub clip_task_address: RenderTaskAddress,
     pub transform_id: TransformPaletteId,
-    pub user_data: [i32; 3],
+    pub user_data: [i32; 4],
 }
 
 pub struct GlyphInstance {
     pub prim_header_index: PrimitiveHeaderIndex,
 }
 
 impl GlyphInstance {
     pub fn new(
--- a/gfx/wr/webrender/src/renderer.rs
+++ b/gfx/wr/webrender/src/renderer.rs
@@ -5251,18 +5251,18 @@ pub trait AsyncPropertySampler {
     /// (i.e. that will trigger a render). The list of frame messages returned
     /// are processed as though they were part of the original transaction.
     fn sample(&self) -> Vec<FrameMsg>;
     /// This is called exactly once, when the render backend thread is about to
     /// terminate.
     fn deregister(&self);
 }
 
-/// Flags that control how shaders are pre-cached, if at all.
 bitflags! {
+    /// Flags that control how shaders are pre-cached, if at all.
     #[derive(Default)]
     pub struct ShaderPrecacheFlags: u32 {
         /// Needed for const initialization
         const EMPTY                 = 0;
 
         /// Only start async compile
         const ASYNC_COMPILE         = 1 << 2;
 
--- a/ipc/mscom/Registration.cpp
+++ b/ipc/mscom/Registration.cpp
@@ -297,57 +297,82 @@ RegisteredProxy::RegisteredProxy(ITypeLi
       ,
       mIsRegisteredInMTA(false)
 #endif  // defined(MOZILLA_INTERNAL_API)
 {
   MOZ_ASSERT(aTypeLib);
   AddToRegistry(this);
 }
 
-RegisteredProxy::~RegisteredProxy() {
-  DeleteFromRegistry(this);
+void RegisteredProxy::Clear() {
   if (mTypeLib) {
     mTypeLib->lpVtbl->Release(mTypeLib);
+    mTypeLib = nullptr;
   }
   if (mClassObject) {
     // NB: mClassObject and mRegCookie must be freed from inside the apartment
     // which they were created in.
     auto cleanupFn = [&]() -> void {
       ::CoRevokeClassObject(mRegCookie);
+      mRegCookie = 0;
       mClassObject->lpVtbl->Release(mClassObject);
+      mClassObject = nullptr;
     };
 #if defined(MOZILLA_INTERNAL_API)
     // This code only supports MTA when built internally
     if (mIsRegisteredInMTA) {
       EnsureMTA mta(cleanupFn);
     } else {
       cleanupFn();
     }
 #else
     cleanupFn();
 #endif  // defined(MOZILLA_INTERNAL_API)
   }
   if (mModule) {
     ::FreeLibrary(reinterpret_cast<HMODULE>(mModule));
+    mModule = 0;
   }
 }
 
-RegisteredProxy::RegisteredProxy(RegisteredProxy&& aOther) {
+RegisteredProxy::~RegisteredProxy() {
+  DeleteFromRegistry(this);
+  Clear();
+}
+
+RegisteredProxy::RegisteredProxy(RegisteredProxy&& aOther)
+    : mModule(0),
+      mClassObject(nullptr),
+      mRegCookie(0),
+      mTypeLib(nullptr)
+#if defined(MOZILLA_INTERNAL_API)
+      ,
+      mIsRegisteredInMTA(false)
+#endif  // defined(MOZILLA_INTERNAL_API)
+{
   *this = std::forward<RegisteredProxy>(aOther);
+  AddToRegistry(this);
 }
 
 RegisteredProxy& RegisteredProxy::operator=(RegisteredProxy&& aOther) {
+  Clear();
+
   mModule = aOther.mModule;
   aOther.mModule = 0;
   mClassObject = aOther.mClassObject;
   aOther.mClassObject = nullptr;
   mRegCookie = aOther.mRegCookie;
   aOther.mRegCookie = 0;
   mTypeLib = aOther.mTypeLib;
   aOther.mTypeLib = nullptr;
+
+#if defined(MOZILLA_INTERNAL_API)
+  mIsRegisteredInMTA = aOther.mIsRegisteredInMTA;
+#endif  // defined(MOZILLA_INTERNAL_API)
+
   return *this;
 }
 
 HRESULT
 RegisteredProxy::GetTypeInfoForGuid(REFGUID aGuid,
                                     ITypeInfo** aOutTypeInfo) const {
   if (!aOutTypeInfo) {
     return E_INVALIDARG;
--- a/ipc/mscom/Registration.h
+++ b/ipc/mscom/Registration.h
@@ -39,16 +39,18 @@ class RegisteredProxy {
 
   static bool Find(REFIID aIid, ITypeInfo** aOutTypeInfo);
 
  private:
   RegisteredProxy() = delete;
   RegisteredProxy(RegisteredProxy&) = delete;
   RegisteredProxy& operator=(RegisteredProxy&) = delete;
 
+  void Clear();
+
   static void AddToRegistry(RegisteredProxy* aProxy);
   static void DeleteFromRegistry(RegisteredProxy* aProxy);
 
  private:
   // Not using Windows types here: We shouldn't #include windows.h
   // since it might pull in COM code which we want to do very carefully in
   // Registration.cpp.
   uintptr_t mModule;
--- a/js/public/GCAPI.h
+++ b/js/public/GCAPI.h
@@ -86,16 +86,19 @@ typedef enum JSGCParamKey {
    * Pref: javascript.options.mem.high_water_mark
    * Default: TuningDefaults::MaxMallocBytes
    */
   JSGC_MAX_MALLOC_BYTES = 1,
 
   /**
    * Maximum size of the generational GC nurseries.
    *
+   * This will be rounded to the nearest gc::ChunkSize.  The special value 0
+   * will disable generational GC.
+   *
    * Pref: javascript.options.mem.nursery.max_kb
    * Default: JS::DefaultNurseryBytes
    */
   JSGC_MAX_NURSERY_BYTES = 2,
 
   /** Amount of bytes allocated by the GC. */
   JSGC_BYTES = 3,
 
@@ -288,16 +291,27 @@ typedef enum JSGCParamKey {
    * Attempt to run a minor GC in the idle time if the free space falls
    * below this percentage (from 0 to 99).
    *
    * Default: 25
    * Pref: None
    */
   JSGC_NURSERY_FREE_THRESHOLD_FOR_IDLE_COLLECTION_PERCENT = 30,
 
+  /**
+   * Minimum size of the generational GC nurseries.
+   *
+   * This value will be rounded to the nearest Nursery::SubChunkStep if below
+   * gc::ChunkSize, otherwise it'll be rounded to the nearest gc::ChunkSize.
+   *
+   * Default: Nursery::SubChunkLimit
+   * Pref: None
+   */
+  JSGC_MIN_NURSERY_BYTES = 31,
+
 } JSGCParamKey;
 
 /*
  * Generic trace operation that calls JS::TraceEdge on each traceable thing's
  * location reachable from data.
  */
 typedef void (*JSTraceDataOp)(JSTracer* trc, void* data);
 
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -460,16 +460,17 @@ static bool MinorGC(JSContext* cx, unsig
   cx->minorGC(JS::GCReason::API);
   args.rval().setUndefined();
   return true;
 }
 
 #define FOR_EACH_GC_PARAM(_)                                                 \
   _("maxBytes", JSGC_MAX_BYTES, true)                                        \
   _("maxMallocBytes", JSGC_MAX_MALLOC_BYTES, true)                           \
+  _("minNurseryBytes", JSGC_MIN_NURSERY_BYTES, true)                         \
   _("maxNurseryBytes", JSGC_MAX_NURSERY_BYTES, true)                         \
   _("gcBytes", JSGC_BYTES, false)                                            \
   _("gcNumber", JSGC_NUMBER, false)                                          \
   _("mode", JSGC_MODE, true)                                                 \
   _("unusedChunks", JSGC_UNUSED_CHUNKS, false)                               \
   _("totalChunks", JSGC_TOTAL_CHUNKS, false)                                 \
   _("sliceTimeBudget", JSGC_SLICE_TIME_BUDGET, true)                         \
   _("markStackLimit", JSGC_MARK_STACK_LIMIT, true)                           \
--- a/js/src/devtools/rootAnalysis/analyzeHeapWrites.js
+++ b/js/src/devtools/rootAnalysis/analyzeHeapWrites.js
@@ -23,17 +23,16 @@ function checkExternalFunction(entry)
         "memcmp",
         "strcmp",
         "fmod",
         "floor",
         "ceil",
         "atof",
         /memchr/,
         "strlen",
-        "Servo_ComputedValues_EqualCustomProperties",
         /Servo_DeclarationBlock_GetCssText/,
         "Servo_GetArcStringData",
         "Servo_IsWorkerThread",
         /nsIFrame::AppendOwnedAnonBoxes/,
         // Assume that atomic accesses are threadsafe.
         /^__atomic_/,
     ];
     if (entry.matches(whitelist))
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -281,16 +281,24 @@ namespace gc {
 namespace TuningDefaults {
 
 /* JSGC_ALLOCATION_THRESHOLD */
 static const size_t GCZoneAllocThresholdBase = 30 * 1024 * 1024;
 
 /* JSGC_MAX_MALLOC_BYTES */
 static const size_t MaxMallocBytes = 128 * 1024 * 1024;
 
+/*
+ * JSGC_MIN_NURSERY_BYTES
+ *
+ * 192K is conservative, not too low that root marking dominates. The Limit
+ * should be a multiple of Nursery::SubChunkStep.
+ */
+static const size_t GCMinNurseryBytes = 192 * 1024;
+
 /* JSGC_ALLOCATION_THRESHOLD_FACTOR */
 static const float AllocThresholdFactor = 0.9f;
 
 /* JSGC_ALLOCATION_THRESHOLD_FACTOR_AVOID_INTERRUPT */
 static const float AllocThresholdFactorAvoidInterrupt = 0.9f;
 
 /* no parameter */
 static const float MallocThresholdGrowFactor = 1.5f;
@@ -1389,17 +1397,29 @@ bool GCSchedulingTunables::setParameter(
                                         const AutoLockGC& lock) {
   // Limit heap growth factor to one hundred times size of current heap.
   const float MaxHeapGrowthFactor = 100;
 
   switch (key) {
     case JSGC_MAX_BYTES:
       gcMaxBytes_ = value;
       break;
+    case JSGC_MIN_NURSERY_BYTES:
+      if (value > gcMaxNurseryBytes_ && gcMaxNurseryBytes_ != 0) {
+        // We make an exception for gcMaxNurseryBytes_ == 0 since that special
+        // value is used to disable generational GC.
+        return false;
+      }
+      gcMinNurseryBytes_ = value;
+      break;
     case JSGC_MAX_NURSERY_BYTES:
+      if ((value < gcMinNurseryBytes_) && (value != 0)) {
+        // Note that we make an exception for value == 0 as above.
+        return false;
+      }
       gcMaxNurseryBytes_ = value;
       break;
     case JSGC_HIGH_FREQUENCY_TIME_LIMIT:
       highFrequencyThreshold_ = TimeDuration::FromMilliseconds(value);
       break;
     case JSGC_HIGH_FREQUENCY_LOW_LIMIT: {
       CheckedInt<size_t> newLimit = CheckedInt<size_t>(value) * 1024 * 1024;
       if (!newLimit.isValid()) {
@@ -1564,16 +1584,17 @@ void GCSchedulingTunables::setMaxEmptyCh
     minEmptyChunkCount_ = maxEmptyChunkCount_;
   }
   MOZ_ASSERT(maxEmptyChunkCount_ >= minEmptyChunkCount_);
 }
 
 GCSchedulingTunables::GCSchedulingTunables()
     : gcMaxBytes_(0),
       maxMallocBytes_(TuningDefaults::MaxMallocBytes),
+      gcMinNurseryBytes_(TuningDefaults::GCMinNurseryBytes),
       gcMaxNurseryBytes_(0),
       gcZoneAllocThresholdBase_(TuningDefaults::GCZoneAllocThresholdBase),
       allocThresholdFactor_(TuningDefaults::AllocThresholdFactor),
       allocThresholdFactorAvoidInterrupt_(
           TuningDefaults::AllocThresholdFactorAvoidInterrupt),
       zoneAllocDelayBytes_(TuningDefaults::ZoneAllocDelayBytes),
       dynamicHeapGrowthEnabled_(TuningDefaults::DynamicHeapGrowthEnabled),
       highFrequencyThreshold_(
@@ -1620,17 +1641,20 @@ void GCRuntime::resetParameter(JSGCParam
 }
 
 void GCSchedulingTunables::resetParameter(JSGCParamKey key,
                                           const AutoLockGC& lock) {
   switch (key) {
     case JSGC_MAX_BYTES:
       gcMaxBytes_ = 0xffffffff;
       break;
+    case JSGC_MIN_NURSERY_BYTES:
     case JSGC_MAX_NURSERY_BYTES:
+      // Reset these togeather to maintain their min <= max invariant.
+      gcMinNurseryBytes_ = TuningDefaults::GCMinNurseryBytes;
       gcMaxNurseryBytes_ = JS::DefaultNurseryBytes;
       break;
     case JSGC_HIGH_FREQUENCY_TIME_LIMIT:
       highFrequencyThreshold_ =
           TimeDuration::FromSeconds(TuningDefaults::HighFrequencyThreshold);
       break;
     case JSGC_HIGH_FREQUENCY_LOW_LIMIT:
       setHighFrequencyLowLimit(TuningDefaults::HighFrequencyLowLimitBytes);
@@ -1689,18 +1713,26 @@ void GCSchedulingTunables::resetParamete
 }
 
 uint32_t GCRuntime::getParameter(JSGCParamKey key, const AutoLockGC& lock) {
   switch (key) {
     case JSGC_MAX_BYTES:
       return uint32_t(tunables.gcMaxBytes());
     case JSGC_MAX_MALLOC_BYTES:
       return mallocCounter.maxBytes();
+    case JSGC_MIN_NURSERY_BYTES:
+      MOZ_ASSERT(tunables.gcMinNurseryBytes() < UINT32_MAX);
+      return uint32_t(tunables.gcMinNurseryBytes());
+    case JSGC_MAX_NURSERY_BYTES:
+      MOZ_ASSERT(tunables.gcMaxNurseryBytes() < UINT32_MAX);
+      return uint32_t(tunables.gcMaxNurseryBytes());
     case JSGC_BYTES:
       return uint32_t(heapSize.gcBytes());
+    case JSGC_NUMBER:
+      return uint32_t(number);
     case JSGC_MODE:
       return uint32_t(mode);
     case JSGC_UNUSED_CHUNKS:
       return uint32_t(emptyChunks(lock).count());
     case JSGC_TOTAL_CHUNKS:
       return uint32_t(fullChunks(lock).count() + availableChunks(lock).count() +
                       emptyChunks(lock).count());
     case JSGC_SLICE_TIME_BUDGET:
@@ -1736,23 +1768,27 @@ uint32_t GCRuntime::getParameter(JSGCPar
     case JSGC_ALLOCATION_THRESHOLD_FACTOR_AVOID_INTERRUPT:
       return uint32_t(tunables.allocThresholdFactorAvoidInterrupt() * 100);
     case JSGC_MIN_EMPTY_CHUNK_COUNT:
       return tunables.minEmptyChunkCount(lock);
     case JSGC_MAX_EMPTY_CHUNK_COUNT:
       return tunables.maxEmptyChunkCount();
     case JSGC_COMPACTING_ENABLED:
       return compactingEnabled;
+    case JSGC_NURSERY_FREE_THRESHOLD_FOR_IDLE_COLLECTION:
+      return tunables.nurseryFreeThresholdForIdleCollection();
+    case JSGC_NURSERY_FREE_THRESHOLD_FOR_IDLE_COLLECTION_PERCENT:
+      return uint32_t(tunables.nurseryFreeThresholdForIdleCollectionFraction() *
+                      100.0f);
     case JSGC_PRETENURE_THRESHOLD:
       return uint32_t(tunables.pretenureThreshold() * 100);
     case JSGC_PRETENURE_GROUP_THRESHOLD:
       return tunables.pretenureGroupThreshold();
     default:
-      MOZ_ASSERT(key == JSGC_NUMBER);
-      return uint32_t(number);
+      MOZ_CRASH("Unknown parameter key");
   }
 }
 
 void GCRuntime::setMarkStackLimit(size_t limit, AutoLockGC& lock) {
   MOZ_ASSERT(!JS::RuntimeHeapIsBusy());
   AutoUnlockGC unlock(lock);
   AutoStopVerifyingBarriers pauseVerification(rt, false);
   marker.setMaxCapacity(limit);
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -137,17 +137,17 @@ bool js::Nursery::init(uint32_t maxNurse
   /* If no chunks are specified then the nursery is permanently disabled. */
   if (chunkCountLimit_ == 0) {
     return true;
   }
 
   if (!allocateNextChunk(0, lock)) {
     return false;
   }
-  capacity_ = SubChunkLimit;
+  capacity_ = roundSize(tunables().gcMinNurseryBytes());
   /* After this point the Nursery has been enabled */
 
   setCurrentChunk(0, true);
   setStartPosition();
 
   char* env = getenv("JS_GC_PROFILE_NURSERY");
   if (env) {
     if (0 == strcmp(env, "help")) {
@@ -189,17 +189,17 @@ void js::Nursery::enable() {
     return;
   }
 
   {
     AutoLockGCBgAlloc lock(runtime());
     if (!allocateNextChunk(0, lock)) {
       return;
     }
-    capacity_ = SubChunkLimit;
+    capacity_ = roundSize(tunables().gcMinNurseryBytes());
   }
 
   setCurrentChunk(0, true);
   setStartPosition();
 #ifdef JS_GC_ZEAL
   if (runtime()->hasZealMode(ZealMode::GenerationalGC)) {
     enterZealMode();
   }
@@ -247,17 +247,17 @@ bool js::Nursery::isEmpty() const {
     MOZ_ASSERT(currentStartPosition_ == chunk(0).start());
   }
   return position() == currentStartPosition_;
 }
 
 #ifdef JS_GC_ZEAL
 void js::Nursery::enterZealMode() {
   if (isEnabled()) {
-    capacity_ = chunkCountLimit() * NurseryChunkUsableSize;
+    capacity_ = chunkCountLimit() * ChunkSize;
     setCurrentEnd();
   }
 }
 
 void js::Nursery::leaveZealMode() {
   if (isEnabled()) {
     MOZ_ASSERT(isEmpty());
     setCurrentChunk(0, true);
@@ -1090,24 +1090,24 @@ size_t js::Nursery::spaceToEnd(unsigned 
   if (chunkCount != 1) {
     // In the general case we have to add:
     //  + the bytes used in the first
     //    chunk which may be less than the total size of a chunk since in some
     //    zeal modes we start the first chunk at some later position
     //    (currentStartPosition_).
     //  + the size of all the other chunks.
     bytes = (chunk(currentStartChunk_).end() - currentStartPosition_) +
-            ((lastChunk - currentStartChunk_) * NurseryChunkUsableSize);
+            ((lastChunk - currentStartChunk_) * ChunkSize);
   } else {
     // In sub-chunk mode, but it also works whenever chunkCount == 1, we need to
     // use currentEnd_ since it may not refer to a full chunk.
     bytes = currentEnd_ - currentStartPosition_;
   }
 
-  MOZ_ASSERT(bytes <= maxChunkCount() * NurseryChunkUsableSize);
+  MOZ_ASSERT(bytes <= maxChunkCount() * ChunkSize);
 
   return bytes;
 }
 
 MOZ_ALWAYS_INLINE void js::Nursery::setCurrentChunk(unsigned chunkno,
                                                     bool fullPoison) {
   MOZ_ASSERT(chunkno < chunkCountLimit());
   MOZ_ASSERT(chunkno < allocatedChunkCount());
@@ -1167,105 +1167,122 @@ bool js::Nursery::allocateNextChunk(cons
 }
 
 MOZ_ALWAYS_INLINE void js::Nursery::setStartPosition() {
   currentStartChunk_ = currentChunk_;
   currentStartPosition_ = position();
 }
 
 void js::Nursery::maybeResizeNursery(JS::GCReason reason) {
-  static const float GrowThreshold = 0.03f;
-  static const float ShrinkThreshold = 0.01f;
-  static const float PromotionGoal = (GrowThreshold + ShrinkThreshold) / 2.0f;
-
-  unsigned newMaxNurseryChunks;
-
-  // Shrink the nursery to its minimum size of we ran out of memory or
-  // received a memory pressure event.
-  if (gc::IsOOMReason(reason)) {
-    minimizeAllocableSpace();
+  if (maybeResizeExact(reason)) {
     return;
   }
 
-#ifdef JS_GC_ZEAL
-  // This zeal mode disabled nursery resizing.
-  if (runtime()->hasZealMode(ZealMode::GenerationalGC)) {
-    return;
-  }
-#endif
-
-  newMaxNurseryChunks = tunables().gcMaxNurseryBytes() >> ChunkShift;
-  if (newMaxNurseryChunks != chunkCountLimit_) {
-    chunkCountLimit_ = newMaxNurseryChunks;
-    /* The configured maximum nursery size is changing */
-    if (maxChunkCount() > newMaxNurseryChunks) {
-      /* We need to shrink the nursery */
-      static_assert(NurseryChunkUsableSize < ChunkSize,
-                    "Usable size must be smaller than total size or this "
-                    "calculation might overflow");
-      shrinkAllocableSpace(newMaxNurseryChunks * NurseryChunkUsableSize);
-      return;
-    }
-  }
-
   /*
    * This incorrect promotion rate results in better nursery sizing
    * decisions, however we should to better tuning based on the real
    * promotion rate in the future.
    */
   const float promotionRate =
       float(previousGC.tenuredBytes) / float(previousGC.nurseryCapacity);
 
   /*
    * Object lifetimes aren't going to behave linearly, but a better
    * relationship that works for all programs and can be predicted in
    * advance doesn't exist.
    */
+  static const float GrowThreshold = 0.03f;
+  static const float ShrinkThreshold = 0.01f;
+  static const float PromotionGoal = (GrowThreshold + ShrinkThreshold) / 2.0f;
   const float factor = promotionRate / PromotionGoal;
   MOZ_ASSERT(factor >= 0.0f);
 
   MOZ_ASSERT((float(capacity()) * factor) <= SIZE_MAX);
-  const size_t newCapacity = size_t(float(capacity()) * factor);
+  size_t newCapacity = size_t(float(capacity()) * factor);
+
+  const size_t minNurseryBytes = roundSize(tunables().gcMinNurseryBytes());
 
   // If one of these conditions is true then we always shrink or grow the
   // nursery.  This way the thresholds still have an effect even if the goal
   // seeking says the current size is ideal.
-  if (maxChunkCount() < chunkCountLimit() && promotionRate > GrowThreshold) {
-    size_t lowLimit = (CheckedInt<size_t>(capacity()) + SubChunkStep).value();
-    size_t highLimit =
-        Min((CheckedInt<size_t>(chunkCountLimit()) * NurseryChunkUsableSize)
-                .value(),
-            (CheckedInt<size_t>(capacity()) * 2).value());
+  size_t lowLimit = Max(minNurseryBytes, capacity() / 2);
+  size_t highLimit =
+      Min((CheckedInt<size_t>(chunkCountLimit()) * ChunkSize).value(),
+          (CheckedInt<size_t>(capacity()) * 2).value());
+  newCapacity = roundSize(mozilla::Clamp(newCapacity, lowLimit, highLimit));
 
-    growAllocableSpace(mozilla::Clamp(newCapacity, lowLimit, highLimit));
-  } else if (capacity() >= SubChunkLimit + SubChunkStep &&
-             promotionRate < ShrinkThreshold) {
-    size_t lowLimit = Max(SubChunkLimit, capacity() / 2);
-    size_t highLimit = (CheckedInt<size_t>(capacity()) - SubChunkStep).value();
+  if (maxChunkCount() < chunkCountLimit() && promotionRate > GrowThreshold &&
+      newCapacity > capacity()) {
+    growAllocableSpace(newCapacity);
+  } else if (capacity() >= minNurseryBytes + SubChunkStep &&
+             promotionRate < ShrinkThreshold && newCapacity < capacity()) {
+    shrinkAllocableSpace(newCapacity);
+  }
+}
 
-    shrinkAllocableSpace(mozilla::Clamp(newCapacity, lowLimit, highLimit));
+bool js::Nursery::maybeResizeExact(JS::GCReason reason) {
+  // Shrink the nursery to its minimum size of we ran out of memory or
+  // received a memory pressure event.
+  if (gc::IsOOMReason(reason)) {
+    minimizeAllocableSpace();
+    return true;
   }
 
-  // Assert that the limits are set such that we can shrink the nursery below
-  // one chunk.
-  static_assert(
-      SubChunkLimit + SubChunkStep < NurseryChunkUsableSize,
-      "Nursery limit must be at least one step from the full chunk size");
+#ifdef JS_GC_ZEAL
+  // This zeal mode disabled nursery resizing.
+  if (runtime()->hasZealMode(ZealMode::GenerationalGC)) {
+    return true;
+  }
+#endif
+
+  unsigned newMaxNurseryChunks =
+      JS_ROUND(tunables().gcMaxNurseryBytes(), ChunkSize) / ChunkSize;
+  MOZ_ASSERT(newMaxNurseryChunks > 0);
+  if (newMaxNurseryChunks != chunkCountLimit_) {
+    chunkCountLimit_ = newMaxNurseryChunks;
+    /* The configured maximum nursery size is changing */
+    if (JS_HOWMANY(capacity_, gc::ChunkSize) > newMaxNurseryChunks) {
+      /* We need to shrink the nursery */
+      static_assert(NurseryChunkUsableSize < ChunkSize,
+                    "Usable size must be smaller than total size or this "
+                    "calculation might overflow");
+      shrinkAllocableSpace(newMaxNurseryChunks * ChunkSize);
+      return true;
+    }
+  }
+
+  const size_t minNurseryBytes = roundSize(tunables().gcMinNurseryBytes());
+
+  if (minNurseryBytes > capacity()) {
+    /*
+     * the configured minimum nursery size is changing and we need to grow the
+     * nursery
+     */
+    MOZ_ASSERT(minNurseryBytes <= roundSize(tunables().gcMaxNurseryBytes()));
+    growAllocableSpace(minNurseryBytes);
+    return true;
+  }
+
+  return false;
+}
+
+size_t js::Nursery::roundSize(size_t size) const {
+  if (size >= ChunkSize) {
+    size = JS_ROUND(size, ChunkSize);
+  } else {
+    size = Min(JS_ROUND(size, SubChunkStep),
+               JS_ROUNDDOWN(NurseryChunkUsableSize, SubChunkStep));
+  }
+  return size;
 }
 
 void js::Nursery::growAllocableSpace(size_t newCapacity) {
-  MOZ_ASSERT_IF(!isSubChunkMode(),
-                newCapacity > currentChunk_ * NurseryChunkUsableSize);
-  if (isSubChunkMode()) {
-    capacity_ =
-        Min(JS_ROUNDUP(newCapacity, SubChunkStep), NurseryChunkUsableSize);
-  } else {
-    capacity_ = JS_ROUNDUP(newCapacity, NurseryChunkUsableSize);
-  }
-  MOZ_ASSERT(capacity_ <= chunkCountLimit_ * NurseryChunkUsableSize);
+  MOZ_ASSERT_IF(!isSubChunkMode(), newCapacity > currentChunk_ * ChunkSize);
+  MOZ_ASSERT(newCapacity <= chunkCountLimit_ * ChunkSize);
+  capacity_ = newCapacity;
   setCurrentEnd();
 }
 
 void js::Nursery::freeChunksFrom(unsigned firstFreeChunk) {
   MOZ_ASSERT(firstFreeChunk < chunks_.length());
   {
     AutoLockGC lock(runtime());
     for (unsigned i = firstFreeChunk; i < chunks_.length(); i++) {
@@ -1277,70 +1294,65 @@ void js::Nursery::freeChunksFrom(unsigne
 
 void js::Nursery::shrinkAllocableSpace(size_t newCapacity) {
 #ifdef JS_GC_ZEAL
   if (runtime()->hasZealMode(ZealMode::GenerationalGC)) {
     return;
   }
 #endif
 
-  size_t stepSize = newCapacity < NurseryChunkUsableSize
-                        ? SubChunkStep
-                        : NurseryChunkUsableSize;
-  newCapacity -= newCapacity % stepSize;
   // Don't shrink the nursery to zero (use Nursery::disable() instead)
   // This can't happen due to the rounding-down performed above because of the
   // clamping in maybeResizeNursery().
   MOZ_ASSERT(newCapacity != 0);
   // Don't attempt to shrink it to the same size.
-  if (newCapacity == capacity()) {
+  if (newCapacity == capacity_) {
     return;
   }
-  MOZ_ASSERT(newCapacity < capacity());
+  MOZ_ASSERT(newCapacity < capacity_);
 
-  unsigned newCount =
-      (newCapacity + NurseryChunkUsableSize - 1) / NurseryChunkUsableSize;
+  unsigned newCount = JS_HOWMANY(newCapacity, ChunkSize);
   if (newCount < allocatedChunkCount()) {
     freeChunksFrom(newCount);
   }
 
   capacity_ = newCapacity;
   setCurrentEnd();
 }
 
 void js::Nursery::minimizeAllocableSpace() {
-  shrinkAllocableSpace(SubChunkLimit);
+  shrinkAllocableSpace(tunables().gcMinNurseryBytes());
 }
 
 bool js::Nursery::queueDictionaryModeObjectToSweep(NativeObject* obj) {
   MOZ_ASSERT(IsInsideNursery(obj));
   return dictionaryModeObjects_.append(obj);
 }
 
 uintptr_t js::Nursery::currentEnd() const {
   // These are separate asserts because it can be useful to see which one
   // failed.
   MOZ_ASSERT_IF(isSubChunkMode(), currentChunk_ == 0);
-  MOZ_ASSERT_IF(isSubChunkMode(), currentEnd_ < chunk(currentChunk_).end());
+  MOZ_ASSERT_IF(isSubChunkMode(), currentEnd_ <= chunk(currentChunk_).end());
   MOZ_ASSERT_IF(!isSubChunkMode(), currentEnd_ == chunk(currentChunk_).end());
   MOZ_ASSERT(currentEnd_ != chunk(currentChunk_).start());
   return currentEnd_;
 }
 
 gcstats::Statistics& js::Nursery::stats() const {
   return runtime()->gc.stats();
 }
 
 MOZ_ALWAYS_INLINE const js::gc::GCSchedulingTunables& js::Nursery::tunables()
     const {
   return runtime()->gc.tunables;
 }
 
 bool js::Nursery::isSubChunkMode() const {
-  return capacity() < NurseryChunkUsableSize;
+  return capacity() <= NurseryChunkUsableSize;
 }
 
 void js::Nursery::sweepDictionaryModeObjects() {
   for (auto obj : dictionaryModeObjects_) {
     if (!IsForwarded(obj)) {
       obj->sweepDictionaryListPointer();
     } else {
       Forwarded(obj)->updateDictionaryListPointerAfterMinorGC(obj);
--- a/js/src/gc/Nursery.h
+++ b/js/src/gc/Nursery.h
@@ -141,24 +141,16 @@ class Nursery {
   static const size_t Alignment = gc::ChunkSize;
   static const size_t ChunkShift = gc::ChunkShift;
 
   /*
    * SubChunkStep is the minimum amount to adjust the nursery's size by.
    */
   static const size_t SubChunkStep = gc::ArenaSize;
 
-  /*
-   * 192K is conservative, not too low that root marking dominates.  The Limit
-   * should be a multiple of the Step.
-   */
-  static const size_t SubChunkLimit = 192 * 1024;
-  static_assert(SubChunkLimit % SubChunkStep == 0,
-                "The limit should be a multiple of the step");
-
   struct alignas(gc::CellAlignBytes) CellAlignedByte {
     char byte;
   };
 
   struct StringLayout {
     JS::Zone* zone;
     CellAlignedByte cell;
   };
@@ -176,17 +168,17 @@ class Nursery {
   unsigned allocatedChunkCount() const { return chunks_.length(); }
 
   // Total number of chunks and the capacity of the nursery. Chunks will be
   // lazilly allocated and added to the chunks array up to this limit, after
   // that the nursery must be collected, this limit may be raised during
   // collection.
   unsigned maxChunkCount() const {
     MOZ_ASSERT(capacity());
-    return JS_HOWMANY(capacity(), NurseryChunkUsableSize);
+    return JS_HOWMANY(capacity(), gc::ChunkSize);
   }
 
   bool exists() const { return chunkCountLimit() != 0; }
 
   void enable();
   void disable();
   bool isEnabled() const { return capacity() != 0; }
 
@@ -334,35 +326,35 @@ class Nursery {
 
   // The number of bytes from the start position to the end of the nursery.
   // pass maxChunkCount(), allocatedChunkCount() or chunkCountLimit()
   // to calculate the nursery size, current lazy-allocated size or nursery
   // limit respectively.
   size_t spaceToEnd(unsigned chunkCount) const;
 
   size_t capacity() const {
-    MOZ_ASSERT(capacity_ >= SubChunkLimit || capacity_ == 0);
-    MOZ_ASSERT(capacity_ <= chunkCountLimit() * NurseryChunkUsableSize);
+    MOZ_ASSERT(capacity_ <= chunkCountLimit() * gc::ChunkSize);
     return capacity_;
   }
   size_t committed() const { return spaceToEnd(allocatedChunkCount()); }
 
-  // Used and free space, not counting chunk trailers.
+  // Used and free space both include chunk trailers for that part of the
+  // nursery.
   //
   // usedSpace() + freeSpace() == capacity()
   //
   MOZ_ALWAYS_INLINE size_t usedSpace() const {
     return capacity() - freeSpace();
   }
   MOZ_ALWAYS_INLINE size_t freeSpace() const {
     MOZ_ASSERT(isEnabled());
     MOZ_ASSERT(currentEnd_ - position_ <= NurseryChunkUsableSize);
     MOZ_ASSERT(currentChunk_ < maxChunkCount());
     return (currentEnd_ - position_) +
-           (maxChunkCount() - currentChunk_ - 1) * NurseryChunkUsableSize;
+           (maxChunkCount() - currentChunk_ - 1) * gc::ChunkSize;
   }
 
 #ifdef JS_GC_ZEAL
   void enterZealMode();
   void leaveZealMode();
 #endif
 
   /* Write profile time JSON on JSONPrinter. */
@@ -625,16 +617,18 @@ class Nursery {
    */
   void clear();
 
   void sweepDictionaryModeObjects();
   void sweepMapAndSetObjects();
 
   /* Change the allocable space provided by the nursery. */
   void maybeResizeNursery(JS::GCReason reason);
+  bool maybeResizeExact(JS::GCReason reason);
+  size_t roundSize(size_t size) const;
   void growAllocableSpace(size_t newCapacity);
   void shrinkAllocableSpace(size_t newCapacity);
   void minimizeAllocableSpace();
 
   // Free the chunks starting at firstFreeChunk until the end of the chunks
   // vector. Shrinks the vector but does not update maxChunkCount().
   void freeChunksFrom(unsigned firstFreeChunk);
 
--- a/js/src/gc/Scheduling.h
+++ b/js/src/gc/Scheduling.h
@@ -329,20 +329,22 @@ class GCSchedulingTunables {
   /*
    * JSGC_MAX_MALLOC_BYTES
    *
    * Initial malloc bytes threshold.
    */
   UnprotectedData<size_t> maxMallocBytes_;
 
   /*
+   * JSGC_MIN_NURSERY_BYTES
    * JSGC_MAX_NURSERY_BYTES
    *
-   * Maximum nursery size for each runtime.
+   * Minimum and maximum nursery size for each runtime.
    */
+  MainThreadData<size_t> gcMinNurseryBytes_;
   MainThreadData<size_t> gcMaxNurseryBytes_;
 
   /*
    * JSGC_ALLOCATION_THRESHOLD
    *
    * The base value used to compute zone->threshold.gcTriggerBytes(). When
    * usage.gcBytes() surpasses threshold.gcTriggerBytes() for a zone, the
    * zone may be scheduled for a GC, depending on the exact circumstances.
@@ -454,16 +456,17 @@ class GCSchedulingTunables {
    */
   UnprotectedData<uint32_t> pretenureGroupThreshold_;
 
  public:
   GCSchedulingTunables();
 
   size_t gcMaxBytes() const { return gcMaxBytes_; }
   size_t maxMallocBytes() const { return maxMallocBytes_; }
+  size_t gcMinNurseryBytes() const { return gcMinNurseryBytes_; }
   size_t gcMaxNurseryBytes() const { return gcMaxNurseryBytes_; }
   size_t gcZoneAllocThresholdBase() const { return gcZoneAllocThresholdBase_; }
   double allocThresholdFactor() const { return allocThresholdFactor_; }
   double allocThresholdFactorAvoidInterrupt() const {
     return allocThresholdFactorAvoidInterrupt_;
   }
   size_t zoneAllocDelayBytes() const { return zoneAllocDelayBytes_; }
   bool isDynamicHeapGrowthEnabled() const { return dynamicHeapGrowthEnabled_; }
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1531626.js
@@ -0,0 +1,43 @@
+// Test that setting the nursery size works as expected.
+
+load(libdir + "asserts.js");
+
+var testSizesKB = [128, 129, 255, 256, 1023, 1024, 3*1024, 4*1024+1, 16*1024];
+
+// Valid maximum sizes must be >= 1MB.
+var testMaxSizesKB = testSizesKB.filter(x => x >= 1024);
+
+for (var max of testMaxSizesKB) {
+  // Don't test minimums greater than the maximum.
+  for (var min of testSizesKB.filter(x => x <= max)) {
+    setMinMax(min, max);
+  }
+}
+
+// The above loops raised the nursery size.  Now reduce it to ensure that
+// forcibly-reducing it works correctly.
+gcparam('minNurseryBytes', 256*1024); // need to avoid min > max;
+setMinMax(256, 1024);
+
+// try an invalid configuration.
+assertErrorMessage(
+  () => setMinMax(2*1024, 1024),
+  Object,
+  "Parameter value out of range");
+
+function setMinMax(min, max) {
+  // Set the maximum first so that we don't hit a case where max < min.
+  gcparam('maxNurseryBytes', max * 1024);
+  gcparam('minNurseryBytes', min * 1024);
+  assertEq(max * 1024, gcparam('maxNurseryBytes'));
+  assertEq(min * 1024, gcparam('minNurseryBytes'));
+  allocateSomeThings();
+  gc();
+}
+
+function allocateSomeThings() {
+  for (var i = 0; i < 1000; i++) {
+    var obj = { an: 'object', with: 'fields' };
+  }
+}
+
--- a/js/src/jsapi-tests/testGCOutOfMemory.cpp
+++ b/js/src/jsapi-tests/testGCOutOfMemory.cpp
@@ -53,17 +53,17 @@ BEGIN_TEST(testGCOutOfMemory) {
 virtual JSContext* createContext() override {
   // Note that the max nursery size must be less than the whole heap size, or
   // the test will fail because 'max' (the number of allocations required for
   // OOM) will be based on the nursery size, and that will overflow the
   // tenured heap, which will cause the second pass with max/4 allocations to
   // OOM. (Actually, this only happens with nursery zeal, because normally
   // the nursery will start out with only a single chunk before triggering a
   // major GC.)
-  JSContext* cx = JS_NewContext(1024 * 1024, 128 * 1024);
+  JSContext* cx = JS_NewContext(1024 * 1024, js::gc::ChunkSize);
   if (!cx) {
     return nullptr;
   }
   setNativeStackQuota(cx);
   return cx;
 }
 
 virtual void destroyContext() override { JS_DestroyContext(cx); }
--- a/js/src/jstypes.h
+++ b/js/src/jstypes.h
@@ -105,16 +105,18 @@
 /***********************************************************************
 ** MACROS:      JS_HOWMANY
 **              JS_ROUNDUP
 ** DESCRIPTION:
 **      Commonly used macros for operations on compatible types.
 ***********************************************************************/
 #define JS_HOWMANY(x, y) (((x) + (y)-1) / (y))
 #define JS_ROUNDUP(x, y) (JS_HOWMANY(x, y) * (y))
+#define JS_ROUNDDOWN(x, y) (((x) / (y)) * (y))
+#define JS_ROUND(x, y) ((((x) + (y) / 2) / (y)) * (y))
 
 #if defined(JS_64BIT)
 #  define JS_BITS_PER_WORD 64
 #else
 #  define JS_BITS_PER_WORD 32
 #endif
 
 /***********************************************************************
--- a/js/src/old-configure.in
+++ b/js/src/old-configure.in
@@ -407,17 +407,17 @@ dnl System overrides of the defaults for
 dnl ========================================================
 case "$host" in
 *mingw*)
     if test -n "$_WIN32_MSVC"; then
         HOST_CFLAGS="$HOST_CFLAGS -nologo"
     else
         HOST_CFLAGS="$HOST_CFLAGS -mwindows"
     fi
-    HOST_CFLAGS="$HOST_CFLAGS -DXP_WIN32 -DXP_WIN -DWIN32 -D_WIN32 -D_CRT_SECURE_NO_WARNINGS"
+    HOST_CFLAGS="$HOST_CFLAGS -DXP_WIN -DWIN32 -D_WIN32 -D_CRT_SECURE_NO_WARNINGS"
     HOST_OPTIMIZE_FLAGS="${HOST_OPTIMIZE_FLAGS=-O2}"
     HOST_BIN_SUFFIX=.exe
 
     case "${host_cpu}" in
     i*86)
         if test -n "$_WIN32_MSVC"; then
             HOST_LDFLAGS="$HOST_LDFLAGS -MACHINE:X86"
         fi
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -11172,17 +11172,17 @@ int main(int argc, char** argv, char** e
   if (cpuCount >= 0) {
     SetFakeCPUCount(cpuCount);
   }
 
   size_t nurseryBytes = JS::DefaultNurseryBytes;
   nurseryBytes = op.getIntOption("nursery-size") * 1024L * 1024L;
 
   /* Use the same parameters as the browser in xpcjsruntime.cpp. */
-  JSContext* cx = JS_NewContext(JS::DefaultHeapMaxBytes, nurseryBytes);
+  JSContext* const cx = JS_NewContext(JS::DefaultHeapMaxBytes, nurseryBytes);
   if (!cx) {
     return 1;
   }
   auto destroyCx = MakeScopeExit([cx] { JS_DestroyContext(cx); });
 
   UniquePtr<ShellContext> sc = MakeUnique<ShellContext>(cx);
   if (!sc) {
     return 1;
--- a/js/src/tests/jstests.list
+++ b/js/src/tests/jstests.list
@@ -26,16 +26,26 @@ include test262/jstests.list
 # Tests disabled due to intentional alternative implementations #
 #################################################################
 
 # Legacy "caller" and "arguments" implemented as accessor properties on Function.prototype.
 skip script test262/built-ins/Function/prototype/restricted-property-arguments.js
 skip script test262/built-ins/Function/prototype/restricted-property-caller.js
 skip script test262/built-ins/ThrowTypeError/unique-per-realm-function-proto.js
 
+# https://github.com/tc39/ecma262/issues/1049
+# The "name" property is present on all functions. V8 and JSC agree, but the
+# spec and tests say anonymous functions simply have no own .name property. The
+# spec should change.
+skip script test262/built-ins/Proxy/revocable/revocation-function-name.js
+skip script test262/built-ins/Promise/reject-function-name.js
+skip script test262/built-ins/Promise/resolve-function-name.js
+skip script test262/built-ins/Promise/executor-function-name.js
+skip script test262/built-ins/Promise/all/resolve-element-function-name.js
+
 
 #########################################################################
 # Test262 tests disabled when features are only conditionally available #
 #########################################################################
 
 skip-if(!Array.prototype.values) script test262/built-ins/Array/prototype/Symbol.iterator.js
 skip-if(!Array.prototype.values) include test262/built-ins/Array/prototype/values/jstests.list
 skip-if(!String.prototype.normalize) include test262/built-ins/String/prototype/normalize/jstests.list
@@ -992,25 +1002,16 @@ skip script test262/language/expressions
 skip script test262/language/expressions/prefix-decrement/S11.4.5_A6_T2.js
 skip script test262/language/expressions/prefix-increment/S11.4.4_A5_T5.js
 skip script test262/language/expressions/prefix-increment/S11.4.4_A6_T1.js
 skip script test262/language/expressions/prefix-increment/S11.4.4_A6_T2.js
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1288457
 skip script test262/built-ins/Function/internals/Construct/base-ctor-revoked-proxy.js
 
-# https://bugzilla.mozilla.org/show_bug.cgi?id=1296236
-skip script test262/built-ins/Proxy/revocable/revocation-function-name.js
-
-# https://bugzilla.mozilla.org/show_bug.cgi?id=1296235
-skip script test262/built-ins/Promise/all/resolve-element-function-name.js
-skip script test262/built-ins/Promise/executor-function-name.js
-skip script test262/built-ins/Promise/reject-function-name.js
-skip script test262/built-ins/Promise/resolve-function-name.js
-
 # https://bugzilla.mozilla.org/show_bug.cgi?id=944846
 skip script test262/built-ins/Number/prototype/toExponential/return-values.js
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1225839
 skip script test262/built-ins/Function/internals/Call/class-ctor-realm.js
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1288457
 skip script test262/built-ins/Function/internals/Construct/base-ctor-revoked-proxy-realm.js
--- a/js/src/vm/Printer.cpp
+++ b/js/src/vm/Printer.cpp
@@ -429,17 +429,17 @@ void Fprinter::finish() {
 
 bool Fprinter::put(const char* s, size_t len) {
   MOZ_ASSERT(file_);
   int i = fwrite(s, /*size=*/1, /*nitems=*/len, file_);
   if (size_t(i) != len) {
     reportOutOfMemory();
     return false;
   }
-#ifdef XP_WIN32
+#ifdef XP_WIN
   if ((file_ == stderr) && (IsDebuggerPresent())) {
     UniqueChars buf = DuplicateString(s, len);
     if (!buf) {
       reportOutOfMemory();
       return false;
     }
     OutputDebugStringA(buf.get());
   }
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -10694,16 +10694,29 @@ bool nsIPresShell::SetVisualViewportOffs
             GetRootScrollFrameAsScrollable()) {
       ScrollAnchorContainer* container = rootScrollFrame->Anchor();
       container->UserScrolled();
     }
   }
   return didChange;
 }
 
+void nsIPresShell::SetPendingVisualScrollUpdate(
+    const nsPoint& aVisualViewportOffset,
+    FrameMetrics::ScrollOffsetUpdateType aUpdateType) {
+  mPendingVisualScrollUpdate =
+      mozilla::Some(VisualScrollUpdate{aVisualViewportOffset, aUpdateType});
+
+  // The pending update is picked up during the next paint.
+  // Schedule a paint to make sure one will happen.
+  if (nsIFrame* rootFrame = GetRootFrame()) {
+    rootFrame->SchedulePaint();
+  }
+}
+
 nsPoint nsIPresShell::GetVisualViewportOffsetRelativeToLayoutViewport() const {
   return GetVisualViewportOffset() - GetLayoutViewportOffset();
 }
 
 nsPoint nsIPresShell::GetLayoutViewportOffset() const {
   nsPoint result;
   if (nsIScrollableFrame* sf = GetRootScrollFrameAsScrollable()) {
     result = sf->GetScrollPosition();
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -1033,17 +1033,17 @@ static void DoApplyRenderingChangeToTree
       // (due to our caller ApplyRendingChangeToTree() discarding the
       // nsChangeHint_RepaintFrame hint).  If you add handling for any other
       // hints within this block, be sure that they too should be ignored when
       // painting is suppressed.
       needInvalidatingPaint = true;
       aFrame->InvalidateFrameSubtree();
       if ((aChange & nsChangeHint_UpdateEffects) &&
           aFrame->IsFrameOfType(nsIFrame::eSVG) &&
-          !(aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG)) {
+          !aFrame->IsSVGOuterSVGFrame()) {
         // Need to update our overflow rects:
         nsSVGUtils::ScheduleReflowSVG(aFrame);
       }
 
       ActiveLayerTracker::NotifyNeedsRepaint(aFrame);
     }
     if (aChange & nsChangeHint_UpdateTextPath) {
       if (nsSVGUtils::IsInSVGTextSubtree(aFrame)) {
@@ -1661,17 +1661,17 @@ void RestyleManager::ProcessRestyledFram
 
       if ((hint & nsChangeHint_UpdateEffects) &&
           frame == nsLayoutUtils::FirstContinuationOrIBSplitSibling(frame)) {
         SVGObserverUtils::UpdateEffects(frame);
       }
       if ((hint & nsChangeHint_InvalidateRenderingObservers) ||
           ((hint & nsChangeHint_UpdateOpacityLayer) &&
            frame->IsFrameOfType(nsIFrame::eSVG) &&
-           !(frame->GetStateBits() & NS_STATE_IS_OUTER_SVG))) {
+           !frame->IsSVGOuterSVGFrame())) {
         SVGObserverUtils::InvalidateRenderingObservers(frame);
         frame->SchedulePaint();
       }
       if (hint & nsChangeHint_NeedReflow) {
         StyleChangeReflow(frame, hint);
         didReflowThisFrame = true;
       }
 
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -1689,23 +1689,24 @@ class nsIPresShell : public nsStubDocume
     FrameMetrics::ScrollOffsetUpdateType mUpdateType;
   };
 
   // Ask APZ in the next transaction to scroll to the given visual viewport
   // offset (relative to the document).
   // Use this sparingly, as it will clobber JS-driven scrolling that happens
   // in the same frame. This is mostly intended to be used in special
   // situations like "first paint" or session restore.
+  // If scrolling "far away", i.e. not just within the existing layout
+  // viewport, it's recommended to use both nsIScrollableFrame.ScrollTo*()
+  // (via window.scrollTo if calling from JS) *and* this function; otherwise,
+  // temporary checkerboarding may result.
   // Please request APZ review if adding a new call site.
   void SetPendingVisualScrollUpdate(
       const nsPoint& aVisualViewportOffset,
-      FrameMetrics::ScrollOffsetUpdateType aUpdateType) {
-    mPendingVisualScrollUpdate =
-        mozilla::Some(VisualScrollUpdate{aVisualViewportOffset, aUpdateType});
-  }
+      FrameMetrics::ScrollOffsetUpdateType aUpdateType);
   void ClearPendingVisualScrollUpdate() {
     mPendingVisualScrollUpdate = mozilla::Nothing();
   }
   const mozilla::Maybe<VisualScrollUpdate>& GetPendingVisualScrollUpdate()
       const {
     return mPendingVisualScrollUpdate;
   }
 
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -455,26 +455,30 @@ bool nsLayoutUtils::IsAnimationLoggingEn
     Preferences::AddBoolVarCache(
         &sShouldLog, "layers.offmainthreadcomposition.log-animations");
   }
 
   return sShouldLog;
 }
 
 bool nsLayoutUtils::AreRetainedDisplayListsEnabled() {
+#ifdef MOZ_WIDGET_ANDROID
+  return gfxPrefs::LayoutRetainDisplayList();;
+#else
   if (XRE_IsContentProcess()) {
     return gfxPrefs::LayoutRetainDisplayList();
   }
 
   if (XRE_IsE10sParentProcess()) {
     return gfxPrefs::LayoutRetainDisplayListChrome();
   }
 
   // Retained display lists require e10s.
   return false;
+#endif
 }
 
 bool nsLayoutUtils::DisplayRootHasRetainedDisplayListBuilder(nsIFrame* aFrame) {
   const nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(aFrame);
   MOZ_ASSERT(displayRoot);
   return displayRoot->HasProperty(RetainedDisplayListBuilder::Cached());
 }
 
--- a/layout/generic/nsFrameStateBits.h
+++ b/layout/generic/nsFrameStateBits.h
@@ -388,30 +388,28 @@ FRAME_STATE_BIT(GridContainer, 27, NS_ST
 FRAME_STATE_BIT(GridContainer, 28, NS_STATE_GRID_HAS_CHILD_NIFS)
 
 // == Frame state bits that apply to SVG frames ===============================
 
 FRAME_STATE_GROUP_NAME(SVG)
 FRAME_STATE_GROUP_CLASS(SVG, nsSVGDisplayableFrame)
 FRAME_STATE_GROUP_CLASS(SVG, nsSVGContainerFrame)
 
-FRAME_STATE_BIT(SVG, 20, NS_STATE_IS_OUTER_SVG)
-
 // If this bit is set, we are a <clipPath> element or descendant.
-FRAME_STATE_BIT(SVG, 21, NS_STATE_SVG_CLIPPATH_CHILD)
+FRAME_STATE_BIT(SVG, 20, NS_STATE_SVG_CLIPPATH_CHILD)
 
 // For SVG text, the NS_FRAME_IS_DIRTY and NS_FRAME_HAS_DIRTY_CHILDREN bits
 // indicate that our anonymous block child needs to be reflowed, and that
 // mPositions will likely need to be updated as a consequence. These are set,
 // for example, when the font-family changes. Sometimes we only need to
 // update mPositions though. For example if the x/y attributes change.
 // mPositioningDirty is used to indicate this latter "things are dirty" case
 // to allow us to avoid reflowing the anonymous block when it is not
 // necessary.
-FRAME_STATE_BIT(SVG, 22, NS_STATE_SVG_POSITIONING_DIRTY)
+FRAME_STATE_BIT(SVG, 21, NS_STATE_SVG_POSITIONING_DIRTY)
 
 // For text, whether the values from x/y/dx/dy attributes have any percentage
 // values that are used in determining the positions of glyphs.  The value will
 // be true even if a positioning value is overridden by a descendant element's
 // attribute with a non-percentage length.  For example,
 // NS_STATE_SVG_POSITIONING_MAY_USE_PERCENTAGES would be set for:
 //
 //   <text x="10%"><tspan x="0">abc</tspan></text>
@@ -424,24 +422,24 @@ FRAME_STATE_BIT(SVG, 22, NS_STATE_SVG_PO
 //
 // NS_STATE_SVG_POSITIONING_MAY_USE_PERCENTAGES is used to determine whether
 // to recompute mPositions when the viewport size changes.  So although the
 // first example above shows that NS_STATE_SVG_POSITIONING_MAY_USE_PERCENTAGES
 // can be true even if a viewport size change will not affect mPositions,
 // determining a completley accurate value for
 // NS_STATE_SVG_POSITIONING_MAY_USE_PERCENTAGES would require extra work that is
 // probably not worth it.
-FRAME_STATE_BIT(SVG, 23, NS_STATE_SVG_POSITIONING_MAY_USE_PERCENTAGES)
+FRAME_STATE_BIT(SVG, 22, NS_STATE_SVG_POSITIONING_MAY_USE_PERCENTAGES)
 
-FRAME_STATE_BIT(SVG, 24, NS_STATE_SVG_TEXT_IN_REFLOW)
+FRAME_STATE_BIT(SVG, 23, NS_STATE_SVG_TEXT_IN_REFLOW)
 
 // Set on SVGTextFrame frames when they need a
 // TextNodeCorrespondenceRecorder::RecordCorrespondence call
 // to update the cached nsTextNode indexes that they correspond to.
-FRAME_STATE_BIT(SVG, 25, NS_STATE_SVG_TEXT_CORRESPONDENCE_DIRTY)
+FRAME_STATE_BIT(SVG, 24, NS_STATE_SVG_TEXT_CORRESPONDENCE_DIRTY)
 
 // == Frame state bits that apply to text frames ==============================
 
 FRAME_STATE_GROUP(Text, nsTextFrame)
 
 // -- Flags set during reflow -------------------------------------------------
 
 // nsTextFrame.cpp defines TEXT_REFLOW_FLAGS to be all of these bits.
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -4010,22 +4010,18 @@ class nsIFrame : public nsQueryFrame {
   }
 
   /**
    * Return whether this frame keeps track of overflow areas. (Frames for
    * non-display SVG elements -- e.g. <clipPath> -- do not maintain overflow
    * areas, because they're never painted.)
    */
   bool FrameMaintainsOverflow() const {
-    // The IsSVGElement() check below is necessary, because the
-    // NS_STATE_IS_OUTER_SVG bit has conflict in other frames due to lack
-    // of bits.
     return !HasAllStateBits(NS_FRAME_SVG_LAYOUT | NS_FRAME_IS_NONDISPLAY) &&
-           !(HasAllStateBits(NS_STATE_IS_OUTER_SVG | NS_FRAME_IS_NONDISPLAY) &&
-             GetContent()->IsSVGElement(nsGkAtoms::svg));
+           !(IsSVGOuterSVGFrame() && HasAnyStateBits(NS_FRAME_IS_NONDISPLAY));
   }
 
   /*
    * @param aStyleDisplay:  If the caller has this->StyleDisplay(), providing
    *   it here will improve performance.
    */
   bool BackfaceIsHidden(const nsStyleDisplay* aStyleDisplay) const {
     MOZ_ASSERT(aStyleDisplay == StyleDisplay());
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -7738,23 +7738,24 @@ Matrix4x4 nsDisplayTransform::GetResulti
     nsLayoutUtils::PostTranslate(result, aOrigin, aAppUnitsPerPixel,
                                  !hasSVGTransforms);
   }
 
   return result;
 }
 
 bool nsDisplayOpacity::CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) {
-  if (ActiveLayerTracker::IsStyleAnimated(
-          aBuilder, mFrame, nsCSSPropertyIDSet::OpacityProperties())) {
+  static constexpr nsCSSPropertyIDSet opacitySet =
+      nsCSSPropertyIDSet::OpacityProperties();
+  if (ActiveLayerTracker::IsStyleAnimated(aBuilder, mFrame, opacitySet)) {
     return true;
   }
 
   EffectCompositor::SetPerformanceWarning(
-      mFrame, eCSSProperty_opacity,
+      mFrame, opacitySet,
       AnimationPerformanceWarning(
           AnimationPerformanceWarning::Type::OpacityFrameInactive));
 
   return false;
 }
 
 bool nsDisplayTransform::CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) {
   return mAllowAsyncAnimation;
@@ -7770,21 +7771,23 @@ bool nsDisplayBackgroundColor::CanUseAsy
 /* static */
 auto nsDisplayTransform::ShouldPrerenderTransformedContent(
     nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsRect* aDirtyRect)
     -> PrerenderDecision {
   // Elements whose transform has been modified recently, or which
   // have a compositor-animated transform, can be prerendered. An element
   // might have only just had its transform animated in which case
   // the ActiveLayerManager may not have been notified yet.
+  static constexpr nsCSSPropertyIDSet transformSet =
+      nsCSSPropertyIDSet::TransformLikeProperties();
   if (!ActiveLayerTracker::IsTransformMaybeAnimated(aFrame) &&
       !EffectCompositor::HasAnimationsForCompositor(
           aFrame, DisplayItemType::TYPE_TRANSFORM)) {
     EffectCompositor::SetPerformanceWarning(
-        aFrame, eCSSProperty_transform,
+        aFrame, transformSet,
         AnimationPerformanceWarning(
             AnimationPerformanceWarning::Type::TransformFrameInactive));
 
     return NoPrerender;
   }
 
   // We should not allow prerender if any ancestor container element has
   // mask/clip-path effects.
@@ -7862,26 +7865,26 @@ auto nsDisplayTransform::ShouldPrerender
     *aDirtyRect = nsLayoutUtils::ComputePartialPrerenderArea(*aDirtyRect,
                                                              overflow, maxSize);
     return PartialPrerender;
   }
 
   if (frameArea > maxLimitArea) {
     uint64_t appUnitsPerPixel = AppUnitsPerCSSPixel();
     EffectCompositor::SetPerformanceWarning(
-        aFrame, eCSSProperty_transform,
+        aFrame, transformSet,
         AnimationPerformanceWarning(
             AnimationPerformanceWarning::Type::ContentTooLargeArea,
             {
                 int(frameArea / (appUnitsPerPixel * appUnitsPerPixel)),
                 int(maxLimitArea / (appUnitsPerPixel * appUnitsPerPixel)),
             }));
   } else {
     EffectCompositor::SetPerformanceWarning(
-        aFrame, eCSSProperty_transform,
+        aFrame, transformSet,
         AnimationPerformanceWarning(
             AnimationPerformanceWarning::Type::ContentTooLarge,
             {
                 nsPresContext::AppUnitsToIntCSSPixels(frameSize.width),
                 nsPresContext::AppUnitsToIntCSSPixels(frameSize.height),
                 nsPresContext::AppUnitsToIntCSSPixels(relativeLimit.width),
                 nsPresContext::AppUnitsToIntCSSPixels(relativeLimit.height),
                 nsPresContext::AppUnitsToIntCSSPixels(absoluteLimit.width),
--- a/layout/reftests/svg/svg-integration/clip-path/reftest.list
+++ b/layout/reftests/svg/svg-integration/clip-path/reftest.list
@@ -31,17 +31,17 @@ fuzzy-if(webrender,35-35,699-708) == cli
 fuzzy-if(webrender,35-35,699-708) == clip-path-circle-013.html clip-path-circle-002-ref.html
 fuzzy-if(webrender,35-35,699-708) == clip-path-circle-014.html clip-path-circle-007-ref.html
 fuzzy-if(webrender,35-35,699-708) == clip-path-circle-015.html clip-path-circle-008-ref.html
 fuzzy-if(webrender,35-35,699-708) == clip-path-circle-016.html clip-path-circle-009-ref.html
 fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-16,0-9) fuzzy-if(webrender,35-35,699-708) == clip-path-circle-017.html clip-path-circle-007-ref.html
 fuzzy-if(webrender,35-35,699-708) == clip-path-circle-018.html clip-path-circle-010-ref.html
 fuzzy-if(webrender,35-35,699-708) == clip-path-circle-019.html clip-path-circle-002-ref.html
 fuzzy-if(webrender,35-35,699-708) == clip-path-circle-020.html clip-path-circle-002-ref.html
-fuzzy-if(webrender&&winWidget,0-1,0-5) == clip-path-circle-021.html clip-path-circle-021-ref.html
+fuzzy-if(webrender&&(winWidget||cocoaWidget),0-1,0-5) == clip-path-circle-021.html clip-path-circle-021-ref.html
 
 fuzzy-if(webrender,36-36,1099-1100) == clip-path-ellipse-001.html clip-path-ellipse-001-ref.html
 fuzzy-if(webrender,36-36,1099-1100) == clip-path-ellipse-002.html clip-path-ellipse-001-ref.html
 fuzzy-if(webrender,36-36,1099-1100) == clip-path-ellipse-003.html clip-path-ellipse-001-ref.html
 fuzzy-if(webrender,36-36,1099-1100) == clip-path-ellipse-004.html clip-path-ellipse-001-ref.html
 fuzzy-if(webrender,36-36,1099-1100) == clip-path-ellipse-005.html clip-path-ellipse-001-ref.html
 fuzzy-if(webrender,36-36,1099-1100) == clip-path-ellipse-006.html clip-path-ellipse-001-ref.html
 fuzzy-if(webrender,36-36,1099-1100) == clip-path-ellipse-007.html clip-path-ellipse-001-ref.html
deleted file mode 100644
--- a/layout/style/BorrowedTypeList.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/* a list of Gecko types used across bindings, for preprocessing */
-
-// There are two macros:
-//
-//   GECKO_BORROWED_TYPE(gecko_type, ffi_type_name)
-//   GECKO_BORROWED_MUT_TYPE(gecko_type, ffi_type_name)
-//
-// GECKO_BORROWED_TYPE will generated Borrowed and BorrowedOrNull types.
-//
-// GECKO_BORROWED_MUT_TYPE will generate those and the BorrowedMut &
-// BorrowedMutOrNull types.
-//
-// The first argument is the Gecko C++ type name.  This must be a type
-// that is in scope in ServoBindingTypes.h; forward declarations may need
-// to be added there.
-//
-// The second argument is the name of a typedef that will be generated,
-// equivalent to the actual C++ type.  This name will be used as the basis
-// for the generated borrowed type names to be used in FFI signatures in
-// C++ and Rust.  The convention for this name is "RawGecko{Type}", where
-// {Type} is the name of the C++ type or something close to it.
-//
-// See the comment at the top of ServoBindingTypes.h for how to use these.
-
-// clang-format off
-// Needs to be a on single line
-GECKO_BORROWED_TYPE(mozilla::dom::Element, RawGeckoElement)
-GECKO_BORROWED_TYPE(mozilla::dom::Document, RawGeckoDocument)
-GECKO_BORROWED_TYPE(nsINode, RawGeckoNode)
-GECKO_BORROWED_TYPE(nsPresContext, RawGeckoPresContext)
-GECKO_BORROWED_TYPE(nsXBLBinding, RawGeckoXBLBinding)
-GECKO_BORROWED_TYPE_MUT(mozilla::AnimationPropertySegment, RawGeckoAnimationPropertySegment)
-GECKO_BORROWED_TYPE_MUT(mozilla::ComputedTiming, RawGeckoComputedTiming)
-GECKO_BORROWED_TYPE_MUT(mozilla::dom::StyleChildrenIterator, RawGeckoStyleChildrenIterator)
-GECKO_BORROWED_TYPE_MUT(mozilla::GfxMatrix4x4, RawGeckoGfxMatrix4x4)
-GECKO_BORROWED_TYPE_MUT(mozilla::URLExtraData, RawGeckoURLExtraData)
-GECKO_BORROWED_TYPE_MUT(nsCSSPropertyIDSet, nsCSSPropertyIDSet)
-GECKO_BORROWED_TYPE_MUT(nsCSSValue, nsCSSValue)
-GECKO_BORROWED_TYPE_MUT(nsStyleAutoArray<mozilla::StyleAnimation>, RawGeckoStyleAnimationList)
-GECKO_BORROWED_TYPE_MUT(nsTArray<const RawServoStyleRule*>, RawGeckoServoStyleRuleList)
-GECKO_BORROWED_TYPE_MUT(nsTArray<mozilla::ComputedKeyframeValues>, RawGeckoComputedKeyframeValuesList)
-GECKO_BORROWED_TYPE_MUT(nsTArray<mozilla::Keyframe>, RawGeckoKeyframeList)
-GECKO_BORROWED_TYPE_MUT(nsTArray<mozilla::PropertyValuePair>, RawGeckoPropertyValuePairList)
-GECKO_BORROWED_TYPE_MUT(nsTArray<nsCSSPropertyID>, RawGeckoCSSPropertyIDList)
-GECKO_BORROWED_TYPE_MUT(nsTArray<nsFontFaceRuleContainer>, RawGeckoFontFaceRuleList)
-GECKO_BORROWED_TYPE_MUT(nsTArray<RefPtr<RawServoAnimationValue>>, RawGeckoServoAnimationValueList)
-GECKO_BORROWED_TYPE_MUT(nsTimingFunction, nsTimingFunction)
-// clang-format on
--- a/layout/style/GeckoBindings.cpp
+++ b/layout/style/GeckoBindings.cpp
@@ -126,64 +126,62 @@ static const nsFont* ThreadSafeGetDefaul
   return retval;
 }
 
 /*
  * Does this child count as significant for selector matching?
  *
  * See nsStyleUtil::IsSignificantChild for details.
  */
-bool Gecko_IsSignificantChild(RawGeckoNodeBorrowed aNode,
+bool Gecko_IsSignificantChild(const nsINode* aNode,
                               bool aWhitespaceIsSignificant) {
   return nsStyleUtil::ThreadSafeIsSignificantChild(aNode->AsContent(),
                                                    aWhitespaceIsSignificant);
 }
 
-RawGeckoNodeBorrowedOrNull Gecko_GetLastChild(RawGeckoNodeBorrowed aNode) {
+const nsINode* Gecko_GetLastChild(const nsINode* aNode) {
   return aNode->GetLastChild();
 }
 
-RawGeckoNodeBorrowedOrNull Gecko_GetPreviousSibling(
-    RawGeckoNodeBorrowed aNode) {
+const nsINode* Gecko_GetPreviousSibling(const nsINode* aNode) {
   return aNode->GetPreviousSibling();
 }
 
-RawGeckoNodeBorrowedOrNull Gecko_GetFlattenedTreeParentNode(
-    RawGeckoNodeBorrowed aNode) {
+const nsINode* Gecko_GetFlattenedTreeParentNode(const nsINode* aNode) {
   return aNode->GetFlattenedTreeParentNodeForStyle();
 }
 
-RawGeckoElementBorrowedOrNull Gecko_GetBeforeOrAfterPseudo(
-    RawGeckoElementBorrowed aElement, bool aIsBefore) {
+const Element* Gecko_GetBeforeOrAfterPseudo(const Element* aElement,
+                                            bool aIsBefore) {
   MOZ_ASSERT(aElement);
   MOZ_ASSERT(aElement->HasProperties());
 
   return aIsBefore ? nsLayoutUtils::GetBeforePseudo(aElement)
                    : nsLayoutUtils::GetAfterPseudo(aElement);
 }
 
 nsTArray<nsIContent*>* Gecko_GetAnonymousContentForElement(
-    RawGeckoElementBorrowed aElement) {
+    const Element* aElement) {
   nsIAnonymousContentCreator* ac = do_QueryFrame(aElement->GetPrimaryFrame());
   if (!ac) {
     return nullptr;
   }
 
   auto* array = new nsTArray<nsIContent*>();
   nsContentUtils::AppendNativeAnonymousChildren(aElement, *array, 0);
   return array;
 }
 
 void Gecko_DestroyAnonymousContentList(nsTArray<nsIContent*>* aAnonContent) {
   MOZ_ASSERT(aAnonContent);
   delete aAnonContent;
 }
 
 const nsTArray<RefPtr<nsINode>>* Gecko_GetAssignedNodes(
-    RawGeckoElementBorrowed aElement) {
+    const Element* aElement) {
   MOZ_ASSERT(HTMLSlotElement::FromNode(aElement));
   return &static_cast<const HTMLSlotElement*>(aElement)->AssignedNodes();
 }
 
 void Gecko_ComputedStyle_Init(ComputedStyle* aStyle,
                               const ServoComputedData* aValues,
                               PseudoStyleType aPseudoType) {
   new (KnownNotNull, aStyle)
@@ -225,33 +223,30 @@ void ServoComputedData::AddSizeOfExcludi
   // - rules
   // - font_computation_data
 }
 
 void Gecko_ComputedStyle_Destroy(ComputedStyle* aStyle) {
   aStyle->~ComputedStyle();
 }
 
-void Gecko_ConstructStyleChildrenIterator(
-    RawGeckoElementBorrowed aElement,
-    RawGeckoStyleChildrenIteratorBorrowedMut aIterator) {
+void Gecko_ConstructStyleChildrenIterator(const Element* aElement,
+                                          StyleChildrenIterator* aIterator) {
   MOZ_ASSERT(aElement);
   MOZ_ASSERT(aIterator);
   new (aIterator) StyleChildrenIterator(aElement);
 }
 
-void Gecko_DestroyStyleChildrenIterator(
-    RawGeckoStyleChildrenIteratorBorrowedMut aIterator) {
+void Gecko_DestroyStyleChildrenIterator(StyleChildrenIterator* aIterator) {
   MOZ_ASSERT(aIterator);
 
   aIterator->~StyleChildrenIterator();
 }
 
-RawGeckoNodeBorrowed Gecko_GetNextStyleChild(
-    RawGeckoStyleChildrenIteratorBorrowedMut aIterator) {
+const nsINode* Gecko_GetNextStyleChild(StyleChildrenIterator* aIterator) {
   MOZ_ASSERT(aIterator);
   return aIterator->GetNextChild();
 }
 
 bool Gecko_VisitedStylesEnabled(const Document* aDoc) {
   MOZ_ASSERT(aDoc);
   MOZ_ASSERT(NS_IsMainThread());
 
@@ -266,60 +261,60 @@ bool Gecko_VisitedStylesEnabled(const Do
   nsILoadContext* loadContext = aDoc->GetLoadContext();
   if (loadContext && loadContext->UsePrivateBrowsing()) {
     return false;
   }
 
   return true;
 }
 
-EventStates::ServoType Gecko_ElementState(RawGeckoElementBorrowed aElement) {
+EventStates::ServoType Gecko_ElementState(const Element* aElement) {
   return aElement->StyleState().ServoValue();
 }
 
-bool Gecko_IsRootElement(RawGeckoElementBorrowed aElement) {
+bool Gecko_IsRootElement(const Element* aElement) {
   return aElement->OwnerDoc()->GetRootElement() == aElement;
 }
 
 // Dirtiness tracking.
-void Gecko_SetNodeFlags(RawGeckoNodeBorrowed aNode, uint32_t aFlags) {
+void Gecko_SetNodeFlags(const nsINode* aNode, uint32_t aFlags) {
   const_cast<nsINode*>(aNode)->SetFlags(aFlags);
 }
 
-void Gecko_UnsetNodeFlags(RawGeckoNodeBorrowed aNode, uint32_t aFlags) {
+void Gecko_UnsetNodeFlags(const nsINode* aNode, uint32_t aFlags) {
   const_cast<nsINode*>(aNode)->UnsetFlags(aFlags);
 }
 
-void Gecko_NoteDirtyElement(RawGeckoElementBorrowed aElement) {
+void Gecko_NoteDirtyElement(const Element* aElement) {
   MOZ_ASSERT(NS_IsMainThread());
   const_cast<Element*>(aElement)->NoteDirtyForServo();
 }
 
-void Gecko_NoteDirtySubtreeForInvalidation(RawGeckoElementBorrowed aElement) {
+void Gecko_NoteDirtySubtreeForInvalidation(const Element* aElement) {
   MOZ_ASSERT(NS_IsMainThread());
   const_cast<Element*>(aElement)->NoteDirtySubtreeForServo();
 }
 
-void Gecko_NoteAnimationOnlyDirtyElement(RawGeckoElementBorrowed aElement) {
+void Gecko_NoteAnimationOnlyDirtyElement(const Element* aElement) {
   MOZ_ASSERT(NS_IsMainThread());
   const_cast<Element*>(aElement)->NoteAnimationOnlyDirtyForServo();
 }
 
 bool Gecko_AnimationNameMayBeReferencedFromStyle(
-    RawGeckoPresContextBorrowed aPresContext, nsAtom* aName) {
+    const nsPresContext* aPresContext, nsAtom* aName) {
   MOZ_ASSERT(aPresContext);
   return aPresContext->AnimationManager()->AnimationMayBeReferenced(aName);
 }
 
-PseudoStyleType Gecko_GetImplementedPseudo(RawGeckoElementBorrowed aElement) {
+PseudoStyleType Gecko_GetImplementedPseudo(const Element* aElement) {
   return aElement->GetPseudoElementType();
 }
 
-uint32_t Gecko_CalcStyleDifference(ComputedStyleBorrowed aOldStyle,
-                                   ComputedStyleBorrowed aNewStyle,
+uint32_t Gecko_CalcStyleDifference(const ComputedStyle* aOldStyle,
+                                   const ComputedStyle* aNewStyle,
                                    bool* aAnyStyleStructChanged,
                                    bool* aOnlyResetStructsChanged) {
   MOZ_ASSERT(aOldStyle);
   MOZ_ASSERT(aNewStyle);
 
   uint32_t equalStructs;
   nsChangeHint result =
       aOldStyle->CalcStyleDifference(*aNewStyle, &equalStructs);
@@ -348,74 +343,73 @@ bool Gecko_HaveSeenPtr(SeenPtrs* aTable,
   MOZ_ASSERT(aTable);
   // Empty Rust allocations are indicated by small values up to the alignment
   // of the relevant type. We shouldn't see anything like that here.
   MOZ_ASSERT(uintptr_t(aPtr) > 16);
 
   return aTable->HaveSeenPtr(aPtr);
 }
 
-RawServoDeclarationBlockStrongBorrowedOrNull Gecko_GetStyleAttrDeclarationBlock(
-    RawGeckoElementBorrowed aElement) {
+const RawServoDeclarationBlockStrong* Gecko_GetStyleAttrDeclarationBlock(
+    const Element* aElement) {
   DeclarationBlock* decl = aElement->GetInlineStyleDeclaration();
   if (!decl) {
     return nullptr;
   }
   return decl->RefRawStrong();
 }
 
-void Gecko_UnsetDirtyStyleAttr(RawGeckoElementBorrowed aElement) {
+void Gecko_UnsetDirtyStyleAttr(const Element* aElement) {
   DeclarationBlock* decl = aElement->GetInlineStyleDeclaration();
   if (!decl) {
     return;
   }
   decl->UnsetDirty();
 }
 
 static const RawServoDeclarationBlockStrong* AsRefRawStrong(
     const RefPtr<RawServoDeclarationBlock>& aDecl) {
   static_assert(sizeof(RefPtr<RawServoDeclarationBlock>) ==
                     sizeof(RawServoDeclarationBlockStrong),
                 "RefPtr should just be a pointer");
   return reinterpret_cast<const RawServoDeclarationBlockStrong*>(&aDecl);
 }
 
-RawServoDeclarationBlockStrongBorrowedOrNull
-Gecko_GetHTMLPresentationAttrDeclarationBlock(
-    RawGeckoElementBorrowed aElement) {
+const RawServoDeclarationBlockStrong*
+Gecko_GetHTMLPresentationAttrDeclarationBlock(const Element* aElement) {
   const nsMappedAttributes* attrs = aElement->GetMappedAttributes();
   if (!attrs) {
     auto* svg = SVGElement::FromNodeOrNull(aElement);
     if (svg) {
       if (auto decl = svg->GetContentDeclarationBlock()) {
         return decl->RefRawStrong();
       }
     }
     return nullptr;
   }
 
   return AsRefRawStrong(attrs->GetServoStyle());
 }
 
-RawServoDeclarationBlockStrongBorrowedOrNull
-Gecko_GetExtraContentStyleDeclarations(RawGeckoElementBorrowed aElement) {
+const RawServoDeclarationBlockStrong* Gecko_GetExtraContentStyleDeclarations(
+    const Element* aElement) {
   if (!aElement->IsAnyOfHTMLElements(nsGkAtoms::td, nsGkAtoms::th)) {
     return nullptr;
   }
   const HTMLTableCellElement* cell =
       static_cast<const HTMLTableCellElement*>(aElement);
   if (nsMappedAttributes* attrs =
           cell->GetMappedAttributesInheritedFromTable()) {
     return AsRefRawStrong(attrs->GetServoStyle());
   }
   return nullptr;
 }
 
-RawServoDeclarationBlockStrongBorrowedOrNull
-Gecko_GetUnvisitedLinkAttrDeclarationBlock(RawGeckoElementBorrowed aElement) {
+const RawServoDeclarationBlockStrong*
+Gecko_GetUnvisitedLinkAttrDeclarationBlock(const Element* aElement) {
   nsHTMLStyleSheet* sheet = aElement->OwnerDoc()->GetAttributeStyleSheet();
   if (!sheet) {
     return nullptr;
   }
 
   return AsRefRawStrong(sheet->GetServoUnvisitedLinkDecl());
 }
 
@@ -442,28 +436,28 @@ void Gecko_StyleSheet_AddRef(const Style
   const_cast<StyleSheet*>(aSheet)->AddRef();
 }
 
 void Gecko_StyleSheet_Release(const StyleSheet* aSheet) {
   MOZ_ASSERT(NS_IsMainThread());
   const_cast<StyleSheet*>(aSheet)->Release();
 }
 
-RawServoDeclarationBlockStrongBorrowedOrNull
-Gecko_GetVisitedLinkAttrDeclarationBlock(RawGeckoElementBorrowed aElement) {
+const RawServoDeclarationBlockStrong* Gecko_GetVisitedLinkAttrDeclarationBlock(
+    const Element* aElement) {
   nsHTMLStyleSheet* sheet = aElement->OwnerDoc()->GetAttributeStyleSheet();
   if (!sheet) {
     return nullptr;
   }
 
   return AsRefRawStrong(sheet->GetServoVisitedLinkDecl());
 }
 
-RawServoDeclarationBlockStrongBorrowedOrNull
-Gecko_GetActiveLinkAttrDeclarationBlock(RawGeckoElementBorrowed aElement) {
+const RawServoDeclarationBlockStrong* Gecko_GetActiveLinkAttrDeclarationBlock(
+    const Element* aElement) {
   nsHTMLStyleSheet* sheet = aElement->OwnerDoc()->GetAttributeStyleSheet();
   if (!sheet) {
     return nullptr;
   }
 
   return AsRefRawStrong(sheet->GetServoActiveLinkDecl());
 }
 
@@ -477,20 +471,19 @@ static PseudoStyleType GetPseudoTypeFrom
   if (aElementOrPseudo->IsGeneratedContentContainerForAfter()) {
     aElementOrPseudo = aElementOrPseudo->GetParent()->AsElement();
     return PseudoStyleType::after;
   }
 
   return PseudoStyleType::NotPseudo;
 }
 
-bool Gecko_GetAnimationRule(
-    RawGeckoElementBorrowed aElement,
-    EffectCompositor::CascadeLevel aCascadeLevel,
-    RawServoAnimationValueMapBorrowedMut aAnimationValues) {
+bool Gecko_GetAnimationRule(const Element* aElement,
+                            EffectCompositor::CascadeLevel aCascadeLevel,
+                            RawServoAnimationValueMap* aAnimationValues) {
   MOZ_ASSERT(aElement);
 
   Document* doc = aElement->GetComposedDoc();
   if (!doc) {
     return false;
   }
   nsPresContext* presContext = doc->GetPresContext();
   if (!presContext || !presContext->IsDynamic()) {
@@ -499,40 +492,39 @@ bool Gecko_GetAnimationRule(
   }
 
   PseudoStyleType pseudoType = GetPseudoTypeFromElementForAnimation(aElement);
 
   return presContext->EffectCompositor()->GetServoAnimationRule(
       aElement, pseudoType, aCascadeLevel, aAnimationValues);
 }
 
-bool Gecko_StyleAnimationsEquals(RawGeckoStyleAnimationListBorrowed aA,
-                                 RawGeckoStyleAnimationListBorrowed aB) {
+bool Gecko_StyleAnimationsEquals(const nsStyleAutoArray<StyleAnimation>* aA,
+                                 const nsStyleAutoArray<StyleAnimation>* aB) {
   return *aA == *aB;
 }
 
-void Gecko_CopyAnimationNames(RawGeckoStyleAnimationListBorrowedMut aDest,
-                              RawGeckoStyleAnimationListBorrowed aSrc) {
+void Gecko_CopyAnimationNames(nsStyleAutoArray<StyleAnimation>* aDest,
+                              const nsStyleAutoArray<StyleAnimation>* aSrc) {
   size_t srcLength = aSrc->Length();
   aDest->EnsureLengthAtLeast(srcLength);
 
   for (size_t index = 0; index < srcLength; index++) {
     (*aDest)[index].SetName((*aSrc)[index].GetName());
   }
 }
 
 void Gecko_SetAnimationName(StyleAnimation* aStyleAnimation, nsAtom* aAtom) {
   MOZ_ASSERT(aStyleAnimation);
-
   aStyleAnimation->SetName(already_AddRefed<nsAtom>(aAtom));
 }
 
-void Gecko_UpdateAnimations(RawGeckoElementBorrowed aElement,
-                            ComputedStyleBorrowedOrNull aOldComputedData,
-                            ComputedStyleBorrowedOrNull aComputedData,
+void Gecko_UpdateAnimations(const Element* aElement,
+                            const ComputedStyle* aOldComputedData,
+                            const ComputedStyle* aComputedData,
                             UpdateAnimationsTasks aTasks) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aElement);
 
   if (!aElement->IsInComposedDoc()) {
     return;
   }
 
@@ -542,39 +534,39 @@ void Gecko_UpdateAnimations(RawGeckoElem
   }
 
   nsAutoAnimationMutationBatch mb(aElement->OwnerDoc());
 
   PseudoStyleType pseudoType = GetPseudoTypeFromElementForAnimation(aElement);
 
   if (aTasks & UpdateAnimationsTasks::CSSAnimations) {
     presContext->AnimationManager()->UpdateAnimations(
-        const_cast<dom::Element*>(aElement), pseudoType, aComputedData);
+        const_cast<Element*>(aElement), pseudoType, aComputedData);
   }
 
   // aComputedData might be nullptr if the target element is now in a
   // display:none subtree. We still call Gecko_UpdateAnimations in this case
   // because we need to stop CSS animations in the display:none subtree.
   // However, we don't need to update transitions since they are stopped by
   // RestyleManager::AnimationsWithDestroyedFrame so we just return early
   // here.
   if (!aComputedData) {
     return;
   }
 
   if (aTasks & UpdateAnimationsTasks::CSSTransitions) {
     MOZ_ASSERT(aOldComputedData);
     presContext->TransitionManager()->UpdateTransitions(
-        const_cast<dom::Element*>(aElement), pseudoType, *aOldComputedData,
+        const_cast<Element*>(aElement), pseudoType, *aOldComputedData,
         *aComputedData);
   }
 
   if (aTasks & UpdateAnimationsTasks::EffectProperties) {
     presContext->EffectCompositor()->UpdateEffectProperties(
-        aComputedData, const_cast<dom::Element*>(aElement), pseudoType);
+        aComputedData, const_cast<Element*>(aElement), pseudoType);
   }
 
   if (aTasks & UpdateAnimationsTasks::CascadeResults) {
     EffectSet* effectSet = EffectSet::GetEffectSet(aElement, pseudoType);
     // CSS animations/transitions might have been destroyed as part of the above
     // steps so before updating cascade results, we check if there are still any
     // animations to update.
     if (effectSet) {
@@ -591,131 +583,130 @@ void Gecko_UpdateAnimations(RawGeckoElem
   if (aTasks & UpdateAnimationsTasks::DisplayChangedFromNone) {
     presContext->EffectCompositor()->RequestRestyle(
         const_cast<Element*>(aElement), pseudoType,
         EffectCompositor::RestyleType::Standard,
         EffectCompositor::CascadeLevel::Animations);
   }
 }
 
-size_t Gecko_GetAnimationEffectCount(RawGeckoElementBorrowed aElementOrPseudo) {
+size_t Gecko_GetAnimationEffectCount(const Element* aElementOrPseudo) {
   PseudoStyleType pseudoType =
       GetPseudoTypeFromElementForAnimation(aElementOrPseudo);
 
   EffectSet* effectSet = EffectSet::GetEffectSet(aElementOrPseudo, pseudoType);
   return effectSet ? effectSet->Count() : 0;
 }
 
-bool Gecko_ElementHasAnimations(RawGeckoElementBorrowed aElement) {
+bool Gecko_ElementHasAnimations(const Element* aElement) {
   PseudoStyleType pseudoType = GetPseudoTypeFromElementForAnimation(aElement);
 
   return !!EffectSet::GetEffectSet(aElement, pseudoType);
 }
 
-bool Gecko_ElementHasCSSAnimations(RawGeckoElementBorrowed aElement) {
+bool Gecko_ElementHasCSSAnimations(const Element* aElement) {
   PseudoStyleType pseudoType = GetPseudoTypeFromElementForAnimation(aElement);
   nsAnimationManager::CSSAnimationCollection* collection =
       nsAnimationManager::CSSAnimationCollection ::GetAnimationCollection(
           aElement, pseudoType);
 
   return collection && !collection->mAnimations.IsEmpty();
 }
 
-bool Gecko_ElementHasCSSTransitions(RawGeckoElementBorrowed aElement) {
+bool Gecko_ElementHasCSSTransitions(const Element* aElement) {
   PseudoStyleType pseudoType = GetPseudoTypeFromElementForAnimation(aElement);
   nsTransitionManager::CSSTransitionCollection* collection =
       nsTransitionManager::CSSTransitionCollection ::GetAnimationCollection(
           aElement, pseudoType);
 
   return collection && !collection->mAnimations.IsEmpty();
 }
 
-size_t Gecko_ElementTransitions_Length(RawGeckoElementBorrowed aElement) {
+size_t Gecko_ElementTransitions_Length(const Element* aElement) {
   PseudoStyleType pseudoType = GetPseudoTypeFromElementForAnimation(aElement);
   nsTransitionManager::CSSTransitionCollection* collection =
       nsTransitionManager::CSSTransitionCollection ::GetAnimationCollection(
           aElement, pseudoType);
 
   return collection ? collection->mAnimations.Length() : 0;
 }
 
-static CSSTransition* GetCurrentTransitionAt(RawGeckoElementBorrowed aElement,
+static CSSTransition* GetCurrentTransitionAt(const Element* aElement,
                                              size_t aIndex) {
   PseudoStyleType pseudoType = GetPseudoTypeFromElementForAnimation(aElement);
   nsTransitionManager::CSSTransitionCollection* collection =
       nsTransitionManager::CSSTransitionCollection ::GetAnimationCollection(
           aElement, pseudoType);
   if (!collection) {
     return nullptr;
   }
   nsTArray<RefPtr<CSSTransition>>& transitions = collection->mAnimations;
   return aIndex < transitions.Length() ? transitions[aIndex].get() : nullptr;
 }
 
-nsCSSPropertyID Gecko_ElementTransitions_PropertyAt(
-    RawGeckoElementBorrowed aElement, size_t aIndex) {
+nsCSSPropertyID Gecko_ElementTransitions_PropertyAt(const Element* aElement,
+                                                    size_t aIndex) {
   CSSTransition* transition = GetCurrentTransitionAt(aElement, aIndex);
   return transition ? transition->TransitionProperty()
                     : nsCSSPropertyID::eCSSProperty_UNKNOWN;
 }
 
-RawServoAnimationValueBorrowedOrNull Gecko_ElementTransitions_EndValueAt(
-    RawGeckoElementBorrowed aElement, size_t aIndex) {
+const RawServoAnimationValue* Gecko_ElementTransitions_EndValueAt(
+    const Element* aElement, size_t aIndex) {
   CSSTransition* transition = GetCurrentTransitionAt(aElement, aIndex);
   return transition ? transition->ToValue().mServo.get() : nullptr;
 }
 
-double Gecko_GetProgressFromComputedTiming(
-    RawGeckoComputedTimingBorrowed aComputedTiming) {
-  return aComputedTiming->mProgress.Value();
+double Gecko_GetProgressFromComputedTiming(const ComputedTiming* aTiming) {
+  return aTiming->mProgress.Value();
 }
 
 double Gecko_GetPositionInSegment(
-    RawGeckoAnimationPropertySegmentBorrowed aSegment, double aProgress,
+    const AnimationPropertySegment* aSegment, double aProgress,
     ComputedTimingFunction::BeforeFlag aBeforeFlag) {
   MOZ_ASSERT(aSegment->mFromKey < aSegment->mToKey,
              "The segment from key should be less than to key");
 
   double positionInSegment = (aProgress - aSegment->mFromKey) /
                              // To avoid floating precision inaccuracies, make
                              // sure we calculate both the numerator and
                              // denominator using double precision.
                              (double(aSegment->mToKey) - aSegment->mFromKey);
 
   return ComputedTimingFunction::GetPortion(aSegment->mTimingFunction,
                                             positionInSegment, aBeforeFlag);
 }
 
-RawServoAnimationValueBorrowedOrNull Gecko_AnimationGetBaseStyle(
-    void* aBaseStyles, nsCSSPropertyID aProperty) {
-  auto base =
-      static_cast<nsRefPtrHashtable<nsUint32HashKey, RawServoAnimationValue>*>(
-          aBaseStyles);
+const RawServoAnimationValue* Gecko_AnimationGetBaseStyle(
+    const RawServoAnimationValueTable* aBaseStyles, nsCSSPropertyID aProperty) {
+  auto base = reinterpret_cast<
+      const nsRefPtrHashtable<nsUint32HashKey, RawServoAnimationValue>*>(
+      aBaseStyles);
   return base->GetWeak(aProperty);
 }
 
 void Gecko_FillAllImageLayers(nsStyleImageLayers* aLayers, uint32_t aMaxLen) {
   aLayers->FillAllLayers(aMaxLen);
 }
 
-bool Gecko_IsDocumentBody(RawGeckoElementBorrowed aElement) {
+bool Gecko_IsDocumentBody(const Element* aElement) {
   Document* doc = aElement->GetUncomposedDoc();
   return doc && doc->GetBodyElement() == aElement;
 }
 
 nscolor Gecko_GetLookAndFeelSystemColor(int32_t aId, const Document* aDoc) {
   bool useStandinsForNativeColors = !nsContentUtils::IsChromeDoc(aDoc);
   nscolor result;
   LookAndFeel::ColorID colorId = static_cast<LookAndFeel::ColorID>(aId);
   AutoWriteLock guard(*sServoFFILock);
   LookAndFeel::GetColor(colorId, useStandinsForNativeColors, &result);
   return result;
 }
 
-bool Gecko_MatchLang(RawGeckoElementBorrowed aElement, nsAtom* aOverrideLang,
+bool Gecko_MatchLang(const Element* aElement, nsAtom* aOverrideLang,
                      bool aHasOverrideLang, const char16_t* aValue) {
   MOZ_ASSERT(!(aOverrideLang && !aHasOverrideLang),
              "aHasOverrideLang should only be set when aOverrideLang is null");
   MOZ_ASSERT(aValue, "null lang parameter");
   if (!aValue || !*aValue) {
     return false;
   }
 
@@ -742,17 +733,17 @@ bool Gecko_MatchLang(RawGeckoElementBorr
     if (nsStyleUtil::DashMatchCompare(
             lang, langString, nsASCIICaseInsensitiveStringComparator())) {
       return true;
     }
   }
   return false;
 }
 
-nsAtom* Gecko_GetXMLLangValue(RawGeckoElementBorrowed aElement) {
+nsAtom* Gecko_GetXMLLangValue(const Element* aElement) {
   const nsAttrValue* attr =
       aElement->GetParsedAttr(nsGkAtoms::lang, kNameSpaceID_XML);
 
   if (!attr) {
     return nullptr;
   }
 
   MOZ_ASSERT(attr->Type() == nsAttrValue::eAtom);
@@ -764,26 +755,26 @@ nsAtom* Gecko_GetXMLLangValue(RawGeckoEl
 Document::DocumentTheme Gecko_GetDocumentLWTheme(const Document* aDocument) {
   return aDocument->ThreadSafeGetDocumentLWTheme();
 }
 
 const PreferenceSheet::Prefs* Gecko_GetPrefSheetPrefs(const Document* aDoc) {
   return &PreferenceSheet::PrefsFor(*aDoc);
 }
 
-bool Gecko_IsTableBorderNonzero(RawGeckoElementBorrowed aElement) {
+bool Gecko_IsTableBorderNonzero(const Element* aElement) {
   if (!aElement->IsHTMLElement(nsGkAtoms::table)) {
     return false;
   }
   const nsAttrValue* val = aElement->GetParsedAttr(nsGkAtoms::border);
   return val &&
          (val->Type() != nsAttrValue::eInteger || val->GetIntegerValue() != 0);
 }
 
-bool Gecko_IsBrowserFrame(RawGeckoElementBorrowed aElement) {
+bool Gecko_IsBrowserFrame(const Element* aElement) {
   nsIMozBrowserFrame* browserFrame =
       const_cast<Element*>(aElement)->GetAsMozBrowserFrame();
   return browserFrame && browserFrame->GetReallyIsBrowser();
 }
 
 template <typename Implementor>
 static nsAtom* LangValue(Implementor* aElement) {
   // TODO(emilio): Deduplicate a bit with nsIContent::GetLang().
@@ -946,17 +937,17 @@ static bool AttrHasSuffix(Implementor* a
                               nsAtom* aName, nsAtom* aStr, bool aIgnoreCase) { \
     return AttrHasPrefix(aElement, aNS, aName, aStr, aIgnoreCase);             \
   }                                                                            \
   bool prefix_##AttrHasSuffix(implementor_ aElement, nsAtom* aNS,              \
                               nsAtom* aName, nsAtom* aStr, bool aIgnoreCase) { \
     return AttrHasSuffix(aElement, aNS, aName, aStr, aIgnoreCase);             \
   }
 
-SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_, RawGeckoElementBorrowed)
+SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_, const Element*)
 SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_Snapshot,
                                            const ServoElementSnapshot*)
 
 #undef SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS
 
 nsAtom* Gecko_Atomize(const char* aString, uint32_t aLength) {
   return NS_Atomize(nsDependentCSubstring(aString, aLength)).take();
 }
@@ -994,17 +985,17 @@ size_t Gecko_SharedFontList_SizeOfInclud
       GeckoSharedFontListMallocSizeOf);
 }
 
 size_t Gecko_SharedFontList_SizeOfIncludingThis(SharedFontList* aFontlist) {
   MOZ_ASSERT(NS_IsMainThread());
   return aFontlist->SizeOfIncludingThis(GeckoSharedFontListMallocSizeOf);
 }
 
-NS_IMPL_THREADSAFE_FFI_REFCOUNTING(mozilla::SharedFontList, SharedFontList);
+NS_IMPL_THREADSAFE_FFI_REFCOUNTING(SharedFontList, SharedFontList);
 
 void Gecko_CopyFontFamilyFrom(nsFont* dst, const nsFont* src) {
   dst->fontlist = src->fontlist;
 }
 
 void Gecko_nsFont_InitSystem(nsFont* aDest, int32_t aFontId,
                              const nsStyleFont* aFont,
                              const Document* aDocument) {
@@ -1023,18 +1014,18 @@ void Gecko_nsFont_InitSystem(nsFont* aDe
   nsLayoutUtils::ComputeSystemFont(aDest, fontID, defaultVariableFont);
 }
 
 void Gecko_nsFont_Destroy(nsFont* aDest) { aDest->~nsFont(); }
 
 FontFamilyType Gecko_nsStyleFont_ComputeDefaultFontType(const Document* aDoc,
                                                         uint8_t aGenericId,
                                                         nsAtom* aLanguage) {
-  const nsFont* defaultFont = ThreadSafeGetDefaultFontHelper(*aDoc, aLanguage,
-                                                             aGenericId);
+  const nsFont* defaultFont =
+      ThreadSafeGetDefaultFontHelper(*aDoc, aLanguage, aGenericId);
   return defaultFont->fontlist.GetDefaultFontType();
 }
 
 gfxFontFeatureValueSet* Gecko_ConstructFontFeatureValueSet() {
   return new gfxFontFeatureValueSet();
 }
 
 nsTArray<unsigned int>* Gecko_AppendFeatureValueHashEntry(
@@ -1042,57 +1033,55 @@ nsTArray<unsigned int>* Gecko_AppendFeat
     uint32_t aAlternate, nsAtom* aName) {
   MOZ_ASSERT(NS_IsMainThread());
   static_assert(sizeof(unsigned int) == sizeof(uint32_t),
                 "sizeof unsigned int and uint32_t must be the same");
   return aFontFeatureValues->AppendFeatureValueHashEntry(
       nsAtomCString(aFamily), nsDependentAtomString(aName), aAlternate);
 }
 
-float Gecko_FontStretch_ToFloat(mozilla::FontStretch aStretch) {
+float Gecko_FontStretch_ToFloat(FontStretch aStretch) {
   // Servo represents percentages with 1. being 100%.
   return aStretch.Percentage() / 100.0f;
 }
 
-void Gecko_FontStretch_SetFloat(mozilla::FontStretch* aStretch, float aFloat) {
+void Gecko_FontStretch_SetFloat(FontStretch* aStretch, float aFloat) {
   // Servo represents percentages with 1. being 100%.
   //
   // Also, the font code assumes a given maximum that style doesn't really need
   // to know about. So clamp here at the boundary.
   *aStretch = FontStretch(std::min(aFloat * 100.0f, float(FontStretch::kMax)));
 }
 
-void Gecko_FontSlantStyle_SetNormal(mozilla::FontSlantStyle* aStyle) {
-  *aStyle = mozilla::FontSlantStyle::Normal();
+void Gecko_FontSlantStyle_SetNormal(FontSlantStyle* aStyle) {
+  *aStyle = FontSlantStyle::Normal();
 }
 
-void Gecko_FontSlantStyle_SetItalic(mozilla::FontSlantStyle* aStyle) {
-  *aStyle = mozilla::FontSlantStyle::Italic();
+void Gecko_FontSlantStyle_SetItalic(FontSlantStyle* aStyle) {
+  *aStyle = FontSlantStyle::Italic();
 }
 
-void Gecko_FontSlantStyle_SetOblique(mozilla::FontSlantStyle* aStyle,
+void Gecko_FontSlantStyle_SetOblique(FontSlantStyle* aStyle,
                                      float aAngleInDegrees) {
-  *aStyle = mozilla::FontSlantStyle::Oblique(aAngleInDegrees);
+  *aStyle = FontSlantStyle::Oblique(aAngleInDegrees);
 }
 
-void Gecko_FontSlantStyle_Get(mozilla::FontSlantStyle aStyle, bool* aNormal,
+void Gecko_FontSlantStyle_Get(FontSlantStyle aStyle, bool* aNormal,
                               bool* aItalic, float* aObliqueAngle) {
   *aNormal = aStyle.IsNormal();
   *aItalic = aStyle.IsItalic();
   if (aStyle.IsOblique()) {
     *aObliqueAngle = aStyle.ObliqueAngle();
   }
 }
 
-float Gecko_FontWeight_ToFloat(mozilla::FontWeight aWeight) {
-  return aWeight.ToFloat();
-}
+float Gecko_FontWeight_ToFloat(FontWeight aWeight) { return aWeight.ToFloat(); }
 
-void Gecko_FontWeight_SetFloat(mozilla::FontWeight* aWeight, float aFloat) {
-  *aWeight = mozilla::FontWeight(aFloat);
+void Gecko_FontWeight_SetFloat(FontWeight* aWeight, float aFloat) {
+  *aWeight = FontWeight(aFloat);
 }
 
 void Gecko_ClearAlternateValues(nsFont* aFont, size_t aLength) {
   aFont->alternateValues.Clear();
   aFont->alternateValues.SetCapacity(aLength);
 }
 
 void Gecko_AppendAlternateValues(nsFont* aFont, uint32_t aAlternateName,
@@ -1532,58 +1521,57 @@ void Gecko_SetStyleCoordCalcValue(nsStyl
   calcRef->mLength = aCalc.mLength;
   calcRef->mPercent = aCalc.mPercent;
   calcRef->mHasPercent = aCalc.mHasPercent;
   *aUnit = nsStyleUnit::eStyleUnit_Calc;
   aValue->mPointer = calcRef;
   calcRef->AddRef();
 }
 
-void Gecko_CopyShapeSourceFrom(mozilla::StyleShapeSource* aDst,
-                               const mozilla::StyleShapeSource* aSrc) {
+void Gecko_CopyShapeSourceFrom(StyleShapeSource* aDst,
+                               const StyleShapeSource* aSrc) {
   MOZ_ASSERT(aDst);
   MOZ_ASSERT(aSrc);
 
   *aDst = *aSrc;
 }
 
-void Gecko_DestroyShapeSource(mozilla::StyleShapeSource* aShape) {
+void Gecko_DestroyShapeSource(StyleShapeSource* aShape) {
   aShape->~StyleShapeSource();
 }
 
 void Gecko_StyleShapeSource_SetURLValue(StyleShapeSource* aShape,
                                         URLValue* aURL) {
   aShape->SetURL(*aURL);
 }
 
-void Gecko_NewBasicShape(mozilla::StyleShapeSource* aShape,
-                         mozilla::StyleBasicShapeType aType) {
-  aShape->SetBasicShape(MakeUnique<mozilla::StyleBasicShape>(aType),
+void Gecko_NewBasicShape(StyleShapeSource* aShape, StyleBasicShapeType aType) {
+  aShape->SetBasicShape(MakeUnique<StyleBasicShape>(aType),
                         StyleGeometryBox::NoBox);
 }
 
-void Gecko_NewShapeImage(mozilla::StyleShapeSource* aShape) {
+void Gecko_NewShapeImage(StyleShapeSource* aShape) {
   aShape->SetShapeImage(MakeUnique<nsStyleImage>());
 }
 
-void Gecko_NewStyleSVGPath(mozilla::StyleShapeSource* aShape) {
+void Gecko_NewStyleSVGPath(StyleShapeSource* aShape) {
   MOZ_ASSERT(aShape);
-  aShape->SetPath(MakeUnique<mozilla::StyleSVGPath>());
+  aShape->SetPath(MakeUnique<StyleSVGPath>());
 }
 
-void Gecko_SetStyleMotion(UniquePtr<mozilla::StyleMotion>* aMotion,
-                          mozilla::StyleMotion* aValue) {
+void Gecko_SetStyleMotion(UniquePtr<StyleMotion>* aMotion,
+                          StyleMotion* aValue) {
   MOZ_ASSERT(aMotion);
   aMotion->reset(aValue);
 }
 
-mozilla::StyleMotion* Gecko_NewStyleMotion() { return new StyleMotion(); }
+StyleMotion* Gecko_NewStyleMotion() { return new StyleMotion(); }
 
-void Gecko_CopyStyleMotions(mozilla::UniquePtr<mozilla::StyleMotion>* aMotion,
-                            const mozilla::StyleMotion* aOther) {
+void Gecko_CopyStyleMotions(UniquePtr<StyleMotion>* aMotion,
+                            const StyleMotion* aOther) {
   MOZ_ASSERT(aMotion);
   *aMotion = aOther ? MakeUnique<StyleMotion>(*aOther) : nullptr;
 }
 
 void Gecko_ResetFilters(nsStyleEffects* effects, size_t new_len) {
   effects->mFilters.Clear();
   effects->mFilters.SetLength(new_len);
 }
@@ -1624,19 +1612,19 @@ void Gecko_nsStyleSVG_SetContextProperti
 }
 
 void Gecko_nsStyleSVG_CopyContextProperties(nsStyleSVG* aDst,
                                             const nsStyleSVG* aSrc) {
   aDst->mContextProps = aSrc->mContextProps;
   aDst->mContextPropsBits = aSrc->mContextPropsBits;
 }
 
-css::URLValue* Gecko_URLValue_Create(RawServoCssUrlDataStrong aCssUrl,
-                                     CORSMode aCORSMode) {
-  RefPtr<css::URLValue> url = new css::URLValue(aCssUrl.Consume(), aCORSMode);
+URLValue* Gecko_URLValue_Create(RawServoCssUrlDataStrong aCssUrl,
+                                CORSMode aCORSMode) {
+  RefPtr<URLValue> url = new URLValue(aCssUrl.Consume(), aCORSMode);
   return url.forget().take();
 }
 
 MOZ_DEFINE_MALLOC_SIZE_OF(GeckoURLValueMallocSizeOf)
 
 size_t Gecko_URLValue_SizeOfIncludingThis(URLValue* aURL) {
   MOZ_ASSERT(NS_IsMainThread());
   return aURL->SizeOfIncludingThis(GeckoURLValueMallocSizeOf);
@@ -1694,27 +1682,27 @@ void DebugListAttributes(const ElementLi
       value.Truncate(kMaxAttributeLength - 3);
       value.AppendLiteral("...");
     }
     aOut.Append(NS_ConvertUTF16toUTF8(value));
     aOut.AppendLiteral("\"");
   }
 }
 
-void Gecko_Element_DebugListAttributes(RawGeckoElementBorrowed aElement,
+void Gecko_Element_DebugListAttributes(const Element* aElement,
                                        nsCString* aOut) {
   DebugListAttributes(*aElement, *aOut);
 }
 
 void Gecko_Snapshot_DebugListAttributes(const ServoElementSnapshot* aSnapshot,
                                         nsCString* aOut) {
   DebugListAttributes(*aSnapshot, *aOut);
 }
 
-NS_IMPL_THREADSAFE_FFI_REFCOUNTING(css::URLValue, CSSURLValue);
+NS_IMPL_THREADSAFE_FFI_REFCOUNTING(URLValue, CSSURLValue);
 
 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(URLExtraData, URLExtraData);
 
 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(nsStyleCoord::Calc, Calc);
 
 nsCSSShadowArray* Gecko_NewCSSShadowArray(uint32_t aLen) {
   RefPtr<nsCSSShadowArray> arr = new (aLen) nsCSSShadowArray(aLen);
   return arr.forget().take();
@@ -1744,152 +1732,141 @@ nsCSSValueSharedList* Gecko_NewNoneTrans
   list->mHead->mValue.SetNoneValue();
   return list.forget().take();
 }
 
 void Gecko_StyleDisplay_GenerateCombinedTransform(nsStyleDisplay* aDisplay) {
   aDisplay->GenerateCombinedIndividualTransform();
 }
 
-void Gecko_CSSValue_SetNumber(nsCSSValueBorrowedMut aCSSValue, float aNumber) {
+void Gecko_CSSValue_SetNumber(nsCSSValue* aCSSValue, float aNumber) {
   aCSSValue->SetFloatValue(aNumber, eCSSUnit_Number);
 }
 
-float Gecko_CSSValue_GetNumber(nsCSSValueBorrowed aCSSValue) {
+float Gecko_CSSValue_GetNumber(const nsCSSValue* aCSSValue) {
   return aCSSValue->GetFloatValue();
 }
 
-void Gecko_CSSValue_SetKeyword(nsCSSValueBorrowedMut aCSSValue,
-                               nsCSSKeyword aKeyword) {
+void Gecko_CSSValue_SetKeyword(nsCSSValue* aCSSValue, nsCSSKeyword aKeyword) {
   aCSSValue->SetEnumValue(aKeyword);
 }
 
-nsCSSKeyword Gecko_CSSValue_GetKeyword(nsCSSValueBorrowed aCSSValue) {
+nsCSSKeyword Gecko_CSSValue_GetKeyword(const nsCSSValue* aCSSValue) {
   return aCSSValue->GetKeywordValue();
 }
 
-void Gecko_CSSValue_SetPercentage(nsCSSValueBorrowedMut aCSSValue,
-                                  float aPercent) {
+void Gecko_CSSValue_SetPercentage(nsCSSValue* aCSSValue, float aPercent) {
   aCSSValue->SetPercentValue(aPercent);
 }
 
-float Gecko_CSSValue_GetPercentage(nsCSSValueBorrowed aCSSValue) {
+float Gecko_CSSValue_GetPercentage(const nsCSSValue* aCSSValue) {
   return aCSSValue->GetPercentValue();
 }
 
-void Gecko_CSSValue_SetPixelLength(nsCSSValueBorrowedMut aCSSValue,
-                                   float aLen) {
+void Gecko_CSSValue_SetPixelLength(nsCSSValue* aCSSValue, float aLen) {
   MOZ_ASSERT(aCSSValue->GetUnit() == eCSSUnit_Null ||
              aCSSValue->GetUnit() == eCSSUnit_Pixel);
   aCSSValue->SetFloatValue(aLen, eCSSUnit_Pixel);
 }
 
-void Gecko_CSSValue_SetCalc(nsCSSValueBorrowedMut aCSSValue,
+void Gecko_CSSValue_SetCalc(nsCSSValue* aCSSValue,
                             nsStyleCoord::CalcValue aCalc) {
   aCSSValue->SetCalcValue(aCalc);
 }
 
-nsStyleCoord::CalcValue Gecko_CSSValue_GetCalc(nsCSSValueBorrowed aCSSValue) {
+nsStyleCoord::CalcValue Gecko_CSSValue_GetCalc(const nsCSSValue* aCSSValue) {
   return aCSSValue->GetCalcValue();
 }
 
-void Gecko_CSSValue_SetFunction(nsCSSValueBorrowedMut aCSSValue, int32_t aLen) {
+void Gecko_CSSValue_SetFunction(nsCSSValue* aCSSValue, int32_t aLen) {
   nsCSSValue::Array* arr = nsCSSValue::Array::Create(aLen);
   aCSSValue->SetArrayValue(arr, eCSSUnit_Function);
 }
 
-void Gecko_CSSValue_SetString(nsCSSValueBorrowedMut aCSSValue,
-                              const uint8_t* aString, uint32_t aLength,
-                              nsCSSUnit aUnit) {
+void Gecko_CSSValue_SetString(nsCSSValue* aCSSValue, const uint8_t* aString,
+                              uint32_t aLength, nsCSSUnit aUnit) {
   MOZ_ASSERT(aCSSValue->GetUnit() == eCSSUnit_Null);
   nsString string;
   nsDependentCSubstring slice(reinterpret_cast<const char*>(aString), aLength);
   AppendUTF8toUTF16(slice, string);
   aCSSValue->SetStringValue(string, aUnit);
 }
 
-void Gecko_CSSValue_SetStringFromAtom(nsCSSValueBorrowedMut aCSSValue,
-                                      nsAtom* aAtom, nsCSSUnit aUnit) {
+void Gecko_CSSValue_SetStringFromAtom(nsCSSValue* aCSSValue, nsAtom* aAtom,
+                                      nsCSSUnit aUnit) {
   aCSSValue->SetStringValue(nsDependentAtomString(aAtom), aUnit);
 }
 
-void Gecko_CSSValue_SetAtomIdent(nsCSSValueBorrowedMut aCSSValue,
-                                 nsAtom* aAtom) {
+void Gecko_CSSValue_SetAtomIdent(nsCSSValue* aCSSValue, nsAtom* aAtom) {
   aCSSValue->SetAtomIdentValue(already_AddRefed<nsAtom>(aAtom));
 }
 
-void Gecko_CSSValue_SetArray(nsCSSValueBorrowedMut aCSSValue, int32_t aLength) {
+void Gecko_CSSValue_SetArray(nsCSSValue* aCSSValue, int32_t aLength) {
   MOZ_ASSERT(aCSSValue->GetUnit() == eCSSUnit_Null);
   RefPtr<nsCSSValue::Array> array = nsCSSValue::Array::Create(aLength);
   aCSSValue->SetArrayValue(array, eCSSUnit_Array);
 }
 
-void Gecko_CSSValue_SetInt(nsCSSValueBorrowedMut aCSSValue, int32_t aInteger,
+void Gecko_CSSValue_SetInt(nsCSSValue* aCSSValue, int32_t aInteger,
                            nsCSSUnit aUnit) {
   aCSSValue->SetIntValue(aInteger, aUnit);
 }
 
-void Gecko_CSSValue_SetFloat(nsCSSValueBorrowedMut aCSSValue, float aValue,
+void Gecko_CSSValue_SetFloat(nsCSSValue* aCSSValue, float aValue,
                              nsCSSUnit aUnit) {
   aCSSValue->SetFloatValue(aValue, aUnit);
 }
 
-nsCSSValueBorrowedMut Gecko_CSSValue_GetArrayItem(
-    nsCSSValueBorrowedMut aCSSValue, int32_t aIndex) {
+nsCSSValue* Gecko_CSSValue_GetArrayItem(nsCSSValue* aCSSValue, int32_t aIndex) {
   return &aCSSValue->GetArrayValue()->Item(aIndex);
 }
 
-nsCSSValueBorrowed Gecko_CSSValue_GetArrayItemConst(
-    nsCSSValueBorrowed aCSSValue, int32_t aIndex) {
+const nsCSSValue* Gecko_CSSValue_GetArrayItemConst(const nsCSSValue* aCSSValue,
+                                                   int32_t aIndex) {
   return &aCSSValue->GetArrayValue()->Item(aIndex);
 }
 
-void Gecko_CSSValue_SetPair(nsCSSValueBorrowedMut aCSSValue,
-                            nsCSSValueBorrowed aXValue,
-                            nsCSSValueBorrowed aYValue) {
+void Gecko_CSSValue_SetPair(nsCSSValue* aCSSValue, const nsCSSValue* aXValue,
+                            const nsCSSValue* aYValue) {
   MOZ_ASSERT(NS_IsMainThread());
   aCSSValue->SetPairValue(*aXValue, *aYValue);
 }
 
-void Gecko_CSSValue_SetList(nsCSSValueBorrowedMut aCSSValue, uint32_t aLen) {
+void Gecko_CSSValue_SetList(nsCSSValue* aCSSValue, uint32_t aLen) {
   MOZ_ASSERT(NS_IsMainThread());
   nsCSSValueList* item = aCSSValue->SetListValue();
   for (uint32_t i = 1; i < aLen; ++i) {
     item->mNext = new nsCSSValueList;
     item = item->mNext;
   }
 }
 
-void Gecko_CSSValue_SetPairList(nsCSSValueBorrowedMut aCSSValue,
-                                uint32_t aLen) {
+void Gecko_CSSValue_SetPairList(nsCSSValue* aCSSValue, uint32_t aLen) {
   MOZ_ASSERT(NS_IsMainThread());
   nsCSSValuePairList* item = aCSSValue->SetPairListValue();
   for (uint32_t i = 1; i < aLen; ++i) {
     item->mNext = new nsCSSValuePairList;
     item = item->mNext;
   }
 }
 
-void Gecko_CSSValue_InitSharedList(nsCSSValueBorrowedMut aCSSValue,
-                                   uint32_t aLen) {
+void Gecko_CSSValue_InitSharedList(nsCSSValue* aCSSValue, uint32_t aLen) {
   MOZ_ASSERT(aLen > 0, "Must create at least one nsCSSValueList (mHead)");
 
   nsCSSValueSharedList* list = new nsCSSValueSharedList;
   aCSSValue->SetSharedListValue(list);
   list->mHead = new nsCSSValueList;
   nsCSSValueList* cur = list->mHead;
   for (uint32_t i = 1; i < aLen; ++i) {
     cur->mNext = new nsCSSValueList;
     cur = cur->mNext;
   }
 }
 
-void Gecko_CSSValue_Drop(nsCSSValueBorrowedMut aCSSValue) {
-  aCSSValue->~nsCSSValue();
-}
+void Gecko_CSSValue_Drop(nsCSSValue* aCSSValue) { aCSSValue->~nsCSSValue(); }
 
 void Gecko_nsStyleFont_SetLang(nsStyleFont* aFont, nsAtom* aAtom) {
   aFont->mLanguage = dont_AddRef(aAtom);
   aFont->mExplicitLanguage = true;
 }
 
 void Gecko_nsStyleFont_CopyLangFrom(nsStyleFont* aFont,
                                     const nsStyleFont* aSource) {
@@ -1970,28 +1947,27 @@ FontSizePrefs Gecko_GetBaseSize(nsAtom* 
   nsStaticAtom* langGroupAtom =
       StaticPresData::Get()->GetUncachedLangGroup(aLanguage);
   prefs.Initialize(langGroupAtom);
   FontSizePrefs sizes;
   sizes.CopyFrom(prefs);
   return sizes;
 }
 
-RawGeckoElementBorrowedOrNull Gecko_GetBindingParent(
-    RawGeckoElementBorrowed aElement) {
+const Element* Gecko_GetBindingParent(const Element* aElement) {
   nsIContent* parent = aElement->GetBindingParent();
   return parent ? parent->AsElement() : nullptr;
 }
 
-RawServoAuthorStylesBorrowedOrNull Gecko_XBLBinding_GetRawServoStyles(
-    RawGeckoXBLBindingBorrowed aXBLBinding) {
+const RawServoAuthorStyles* Gecko_XBLBinding_GetRawServoStyles(
+    const nsXBLBinding* aXBLBinding) {
   return aXBLBinding->GetServoStyles();
 }
 
-bool Gecko_XBLBinding_InheritsStyle(RawGeckoXBLBindingBorrowed aXBLBinding) {
+bool Gecko_XBLBinding_InheritsStyle(const nsXBLBinding* aXBLBinding) {
   return aXBLBinding->InheritsStyle();
 }
 
 static StaticRefPtr<UACacheReporter> gUACacheReporter;
 
 namespace mozilla {
 
 void InitializeServo() {
@@ -2018,17 +1994,17 @@ void AssertIsMainThreadOrServoFontMetric
   if (!NS_IsMainThread()) {
     MOZ_ASSERT(sServoFFILock &&
                sServoFFILock->LockedForWritingByCurrentThread());
   }
 }
 
 }  // namespace mozilla
 
-GeckoFontMetrics Gecko_GetFontMetrics(RawGeckoPresContextBorrowed aPresContext,
+GeckoFontMetrics Gecko_GetFontMetrics(const nsPresContext* aPresContext,
                                       bool aIsVertical,
                                       const nsStyleFont* aFont,
                                       nscoord aFontSize, bool aUseUserFontSet) {
   AutoWriteLock guard(*sServoFFILock);
   GeckoFontMetrics ret;
 
   // Getting font metrics can require some main thread only work to be
   // done, such as work that needs to touch non-threadsafe refcounted
@@ -2076,25 +2052,25 @@ void Gecko_StyleSheet_FinishAsyncParse(
             Servo_UseCounters_Merge(docCounters, counters.get());
           }
         }
         data->mSheet->FinishAsyncParse(contents.forget());
       }));
 }
 
 static already_AddRefed<StyleSheet> LoadImportSheet(
-    css::Loader* aLoader, StyleSheet* aParent, SheetLoadData* aParentLoadData,
-    css::LoaderReusableStyleSheets* aReusableSheets, css::URLValue* aURL,
+    Loader* aLoader, StyleSheet* aParent, SheetLoadData* aParentLoadData,
+    LoaderReusableStyleSheets* aReusableSheets, URLValue* aURL,
     already_AddRefed<RawServoMediaList> aMediaList) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aLoader, "Should've catched this before");
   MOZ_ASSERT(aParent, "Only used for @import, so parent should exist!");
   MOZ_ASSERT(aURL, "Invalid URLs shouldn't be loaded!");
 
-  RefPtr<dom::MediaList> media = new MediaList(std::move(aMediaList));
+  RefPtr<MediaList> media = new MediaList(std::move(aMediaList));
   nsCOMPtr<nsIURI> uri = aURL->GetURI();
   nsresult rv = uri ? NS_OK : NS_ERROR_FAILURE;
 
   StyleSheet* previousFirstChild = aParent->GetFirstChild();
   if (NS_SUCCEEDED(rv)) {
     rv = aLoader->LoadChildSheet(aParent, aParentLoadData, uri, media,
                                  aReusableSheets);
   }
@@ -2120,39 +2096,39 @@ static already_AddRefed<StyleSheet> Load
     aParent->PrependStyleSheet(emptySheet);
     return emptySheet.forget();
   }
 
   RefPtr<StyleSheet> sheet = static_cast<StyleSheet*>(aParent->GetFirstChild());
   return sheet.forget();
 }
 
-StyleSheet* Gecko_LoadStyleSheet(
-    css::Loader* aLoader, StyleSheet* aParent, SheetLoadData* aParentLoadData,
-    css::LoaderReusableStyleSheets* aReusableSheets,
-    RawServoCssUrlDataStrong aCssUrl, RawServoMediaListStrong aMediaList) {
+StyleSheet* Gecko_LoadStyleSheet(Loader* aLoader, StyleSheet* aParent,
+                                 SheetLoadData* aParentLoadData,
+                                 LoaderReusableStyleSheets* aReusableSheets,
+                                 RawServoCssUrlDataStrong aCssUrl,
+                                 RawServoMediaListStrong aMediaList) {
   MOZ_ASSERT(NS_IsMainThread());
 
   // The CORS mode in the URLValue is irrelevant here.
   // (CORS_NONE is used for all imported sheets in Load::LoadChildSheet.)
-  RefPtr<css::URLValue> url = new css::URLValue(aCssUrl.Consume(), CORS_NONE);
+  RefPtr<URLValue> url = new URLValue(aCssUrl.Consume(), CORS_NONE);
   return LoadImportSheet(aLoader, aParent, aParentLoadData, aReusableSheets,
                          url, aMediaList.Consume())
       .take();
 }
 
-void Gecko_LoadStyleSheetAsync(css::SheetLoadDataHolder* aParentData,
+void Gecko_LoadStyleSheetAsync(SheetLoadDataHolder* aParentData,
                                RawServoCssUrlDataStrong aCssUrl,
                                RawServoMediaListStrong aMediaList,
                                RawServoImportRuleStrong aImportRule) {
   RefPtr<SheetLoadDataHolder> loadData = aParentData;
   // The CORS mode in the URLValue is irrelevant here.
   // (CORS_NONE is used for all imported sheets in Load::LoadChildSheet.)
-  RefPtr<css::URLValue> urlVal =
-      new css::URLValue(aCssUrl.Consume(), CORS_NONE);
+  RefPtr<URLValue> urlVal = new URLValue(aCssUrl.Consume(), CORS_NONE);
   RefPtr<RawServoMediaList> mediaList = aMediaList.Consume();
   RefPtr<RawServoImportRule> importRule = aImportRule.Consume();
   NS_DispatchToMainThread(NS_NewRunnableFunction(
       __func__,
       [data = std::move(loadData), url = std::move(urlVal),
        media = std::move(mediaList), import = std::move(importRule)]() mutable {
         MOZ_ASSERT(NS_IsMainThread());
         SheetLoadData* d = data->get();
@@ -2171,17 +2147,17 @@ nsCSSKeyword Gecko_LookupCSSKeyword(cons
 const char* Gecko_CSSKeywordString(nsCSSKeyword aKeyword, uint32_t* aLength) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aLength);
   const nsCString& value = nsCSSKeywords::GetStringValue(aKeyword);
   *aLength = value.Length();
   return value.get();
 }
 
-void Gecko_AddPropertyToSet(nsCSSPropertyIDSetBorrowedMut aPropertySet,
+void Gecko_AddPropertyToSet(nsCSSPropertyIDSet* aPropertySet,
                             nsCSSPropertyID aProperty) {
   aPropertySet->AddProperty(aProperty);
 }
 
 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(nsCSSValueSharedList, CSSValueSharedList);
 
 #define STYLE_STRUCT(name)                                             \
                                                                        \
@@ -2202,17 +2178,17 @@ NS_IMPL_THREADSAFE_FFI_REFCOUNTING(nsCSS
 void Gecko_RegisterProfilerThread(const char* name) {
   PROFILER_REGISTER_THREAD(name);
 }
 
 void Gecko_UnregisterProfilerThread() { PROFILER_UNREGISTER_THREAD(); }
 
 bool Gecko_DocumentRule_UseForPresentation(
     const Document* aDocument, const nsACString* aPattern,
-    css::DocumentMatchingFunction aMatchingFunction) {
+    DocumentMatchingFunction aMatchingFunction) {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsIURI* docURI = aDocument->GetDocumentURI();
   nsAutoCString docURISpec;
   if (docURI) {
     // If GetSpec fails (due to OOM) just skip these URI-specific CSS rules.
     nsresult rv = docURI->GetSpec(docURISpec);
     NS_ENSURE_SUCCESS(rv, false);
@@ -2308,17 +2284,17 @@ bool Gecko_GetBoolPrefValue(const char* 
   MOZ_ASSERT(NS_IsMainThread());
   return Preferences::GetBool(aPrefName);
 }
 
 bool Gecko_IsInServoTraversal() { return ServoStyleSet::IsInServoTraversal(); }
 
 bool Gecko_IsMainThread() { return NS_IsMainThread(); }
 
-const nsAttrValue* Gecko_GetSVGAnimatedClass(RawGeckoElementBorrowed aElement) {
+const nsAttrValue* Gecko_GetSVGAnimatedClass(const Element* aElement) {
   MOZ_ASSERT(aElement->IsSVGElement());
   return static_cast<const SVGElement*>(aElement)->GetAnimatedClassName();
 }
 
 bool Gecko_AssertClassAttrValueIsSane(const nsAttrValue* aValue) {
   MOZ_ASSERT(aValue->Type() == nsAttrValue::eAtom ||
              aValue->Type() == nsAttrValue::eString ||
              aValue->Type() == nsAttrValue::eAtomArray);
--- a/layout/style/GeckoBindings.h
+++ b/layout/style/GeckoBindings.h
@@ -58,97 +58,91 @@ const bool GECKO_IS_NIGHTLY = false;
                 "NS_DECL_THREADSAFE_FFI_REFCOUNTING can only be used with "    \
                 "classes that have thread-safe refcounting");                  \
   void Gecko_AddRef##name_##ArbitraryThread(class_* aPtr) { NS_ADDREF(aPtr); } \
   void Gecko_Release##name_##ArbitraryThread(class_* aPtr) { NS_RELEASE(aPtr); }
 
 extern "C" {
 
 // Debugging stuff.
-void Gecko_Element_DebugListAttributes(RawGeckoElementBorrowed, nsCString*);
+void Gecko_Element_DebugListAttributes(const mozilla::dom::Element*,
+                                       nsCString*);
 
 void Gecko_Snapshot_DebugListAttributes(const mozilla::ServoElementSnapshot*,
                                         nsCString*);
 
-bool Gecko_IsSignificantChild(RawGeckoNodeBorrowed node,
-                              bool whitespace_is_significant);
-
-RawGeckoNodeBorrowedOrNull Gecko_GetLastChild(RawGeckoNodeBorrowed node);
-RawGeckoNodeBorrowedOrNull Gecko_GetPreviousSibling(RawGeckoNodeBorrowed node);
+bool Gecko_IsSignificantChild(const nsINode*, bool whitespace_is_significant);
 
-RawGeckoNodeBorrowedOrNull Gecko_GetFlattenedTreeParentNode(
-    RawGeckoNodeBorrowed node);
+const nsINode* Gecko_GetLastChild(const nsINode*);
+const nsINode* Gecko_GetPreviousSibling(const nsINode*);
 
-RawGeckoElementBorrowedOrNull Gecko_GetBeforeOrAfterPseudo(
-    RawGeckoElementBorrowed element, bool is_before);
+const nsINode* Gecko_GetFlattenedTreeParentNode(const nsINode*);
+const mozilla::dom::Element* Gecko_GetBeforeOrAfterPseudo(
+    const mozilla::dom::Element*, bool is_before);
 
 nsTArray<nsIContent*>* Gecko_GetAnonymousContentForElement(
-    RawGeckoElementBorrowed element);
+    const mozilla::dom::Element*);
+void Gecko_DestroyAnonymousContentList(nsTArray<nsIContent*>* anon_content);
 
 const nsTArray<RefPtr<nsINode>>* Gecko_GetAssignedNodes(
-    RawGeckoElementBorrowed element);
-
-void Gecko_DestroyAnonymousContentList(nsTArray<nsIContent*>* anon_content);
+    const mozilla::dom::Element*);
 
 void Gecko_ComputedStyle_Init(mozilla::ComputedStyle* context,
-                              ServoComputedDataBorrowed values,
+                              const ServoComputedData* values,
                               mozilla::PseudoStyleType pseudo_type);
 
 void Gecko_ComputedStyle_Destroy(mozilla::ComputedStyle* context);
 
 // By default, Servo walks the DOM by traversing the siblings of the DOM-view
 // first child. This generally works, but misses anonymous children, which we
 // want to traverse during styling. To support these cases, we create an
 // optional stack-allocated iterator in aIterator for nodes that need it.
-void Gecko_ConstructStyleChildrenIterator(
-    RawGeckoElementBorrowed aElement,
-    RawGeckoStyleChildrenIteratorBorrowedMut aIterator);
+void Gecko_ConstructStyleChildrenIterator(const mozilla::dom::Element*,
+                                          mozilla::dom::StyleChildrenIterator*);
 
-void Gecko_DestroyStyleChildrenIterator(
-    RawGeckoStyleChildrenIteratorBorrowedMut aIterator);
+void Gecko_DestroyStyleChildrenIterator(mozilla::dom::StyleChildrenIterator*);
 
-RawGeckoNodeBorrowedOrNull Gecko_GetNextStyleChild(
-    RawGeckoStyleChildrenIteratorBorrowedMut it);
+const nsINode* Gecko_GetNextStyleChild(mozilla::dom::StyleChildrenIterator*);
 
 NS_DECL_THREADSAFE_FFI_REFCOUNTING(mozilla::css::SheetLoadDataHolder,
                                    SheetLoadDataHolder);
 
 void Gecko_StyleSheet_FinishAsyncParse(
     mozilla::css::SheetLoadDataHolder* data,
     RawServoStyleSheetContentsStrong sheet_contents,
     StyleUseCountersOwnedOrNull use_counters);
 
 mozilla::StyleSheet* Gecko_LoadStyleSheet(
     mozilla::css::Loader* loader, mozilla::StyleSheet* parent,
     mozilla::css::SheetLoadData* parent_load_data,
     mozilla::css::LoaderReusableStyleSheets* reusable_sheets,
     RawServoCssUrlDataStrong url, RawServoMediaListStrong media_list);
 
 void Gecko_LoadStyleSheetAsync(mozilla::css::SheetLoadDataHolder* parent_data,
-                               RawServoCssUrlDataStrong url,
-                               RawServoMediaListStrong media_list,
-                               RawServoImportRuleStrong import_rule);
+                               RawServoCssUrlDataStrong,
+                               RawServoMediaListStrong,
+                               RawServoImportRuleStrong);
 
 // Selector Matching.
-uint64_t Gecko_ElementState(RawGeckoElementBorrowed element);
-bool Gecko_IsRootElement(RawGeckoElementBorrowed element);
+uint64_t Gecko_ElementState(const mozilla::dom::Element*);
+bool Gecko_IsRootElement(const mozilla::dom::Element*);
 
-bool Gecko_MatchLang(RawGeckoElementBorrowed element, nsAtom* override_lang,
+bool Gecko_MatchLang(const mozilla::dom::Element*, nsAtom* override_lang,
                      bool has_override_lang, const char16_t* value);
 
-nsAtom* Gecko_GetXMLLangValue(RawGeckoElementBorrowed element);
+nsAtom* Gecko_GetXMLLangValue(const mozilla::dom::Element*);
 
 mozilla::dom::Document::DocumentTheme Gecko_GetDocumentLWTheme(
     const mozilla::dom::Document*);
 
 const mozilla::PreferenceSheet::Prefs* Gecko_GetPrefSheetPrefs(
     const mozilla::dom::Document*);
 
-bool Gecko_IsTableBorderNonzero(RawGeckoElementBorrowed element);
-bool Gecko_IsBrowserFrame(RawGeckoElementBorrowed element);
+bool Gecko_IsTableBorderNonzero(const mozilla::dom::Element* element);
+bool Gecko_IsBrowserFrame(const mozilla::dom::Element* element);
 
 // Attributes.
 #define SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS(prefix_, implementor_)   \
   nsAtom* prefix_##LangValue(implementor_ element);                            \
   bool prefix_##HasAttr(implementor_ element, nsAtom* ns, nsAtom* name);       \
   bool prefix_##AttrEquals(implementor_ element, nsAtom* ns, nsAtom* name,     \
                            nsAtom* str, bool ignoreCase);                      \
   bool prefix_##AttrDashEquals(implementor_ element, nsAtom* ns, nsAtom* name, \
@@ -158,100 +152,108 @@ bool Gecko_IsBrowserFrame(RawGeckoElemen
   bool prefix_##AttrHasSubstring(implementor_ element, nsAtom* ns,             \
                                  nsAtom* name, nsAtom* str, bool ignore_case); \
   bool prefix_##AttrHasPrefix(implementor_ element, nsAtom* ns, nsAtom* name,  \
                               nsAtom* str, bool ignore_case);                  \
   bool prefix_##AttrHasSuffix(implementor_ element, nsAtom* ns, nsAtom* name,  \
                               nsAtom* str, bool ignore_case);
 
 bool Gecko_AssertClassAttrValueIsSane(const nsAttrValue*);
-const nsAttrValue* Gecko_GetSVGAnimatedClass(RawGeckoElementBorrowed);
+const nsAttrValue* Gecko_GetSVGAnimatedClass(const mozilla::dom::Element*);
 
-SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_, RawGeckoElementBorrowed)
+SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_,
+                                              const mozilla::dom::Element*)
 
 SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS(
     Gecko_Snapshot, const mozilla::ServoElementSnapshot*)
 
 #undef SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS
 
 // Style attributes.
-RawServoDeclarationBlockStrongBorrowedOrNull Gecko_GetStyleAttrDeclarationBlock(
-    RawGeckoElementBorrowed element);
+const RawServoDeclarationBlockStrong* Gecko_GetStyleAttrDeclarationBlock(
+    const mozilla::dom::Element* element);
 
-void Gecko_UnsetDirtyStyleAttr(RawGeckoElementBorrowed element);
+void Gecko_UnsetDirtyStyleAttr(const mozilla::dom::Element* element);
 
-RawServoDeclarationBlockStrongBorrowedOrNull
-Gecko_GetHTMLPresentationAttrDeclarationBlock(RawGeckoElementBorrowed element);
+const RawServoDeclarationBlockStrong*
+Gecko_GetHTMLPresentationAttrDeclarationBlock(
+    const mozilla::dom::Element* element);
 
-RawServoDeclarationBlockStrongBorrowedOrNull
-Gecko_GetExtraContentStyleDeclarations(RawGeckoElementBorrowed element);
-
-RawServoDeclarationBlockStrongBorrowedOrNull
-Gecko_GetUnvisitedLinkAttrDeclarationBlock(RawGeckoElementBorrowed element);
+const RawServoDeclarationBlockStrong* Gecko_GetExtraContentStyleDeclarations(
+    const mozilla::dom::Element* element);
 
-RawServoDeclarationBlockStrongBorrowedOrNull
-Gecko_GetVisitedLinkAttrDeclarationBlock(RawGeckoElementBorrowed element);
+const RawServoDeclarationBlockStrong*
+Gecko_GetUnvisitedLinkAttrDeclarationBlock(
+    const mozilla::dom::Element* element);
 
-RawServoDeclarationBlockStrongBorrowedOrNull
-Gecko_GetActiveLinkAttrDeclarationBlock(RawGeckoElementBorrowed element);
+const RawServoDeclarationBlockStrong* Gecko_GetVisitedLinkAttrDeclarationBlock(
+    const mozilla::dom::Element* element);
+
+const RawServoDeclarationBlockStrong* Gecko_GetActiveLinkAttrDeclarationBlock(
+    const mozilla::dom::Element* element);
 
 // Visited handling.
 
 // Returns whether visited styles are enabled for a given document.
 bool Gecko_VisitedStylesEnabled(const mozilla::dom::Document*);
 
 // Animations
 bool Gecko_GetAnimationRule(
-    RawGeckoElementBorrowed aElementOrPseudo,
+    const mozilla::dom::Element* aElementOrPseudo,
     mozilla::EffectCompositor::CascadeLevel aCascadeLevel,
-    RawServoAnimationValueMapBorrowedMut aAnimationValues);
+    RawServoAnimationValueMap* aAnimationValues);
 
-bool Gecko_StyleAnimationsEquals(RawGeckoStyleAnimationListBorrowed,
-                                 RawGeckoStyleAnimationListBorrowed);
+bool Gecko_StyleAnimationsEquals(
+    const nsStyleAutoArray<mozilla::StyleAnimation>*,
+    const nsStyleAutoArray<mozilla::StyleAnimation>*);
 
-void Gecko_CopyAnimationNames(RawGeckoStyleAnimationListBorrowedMut aDest,
-                              RawGeckoStyleAnimationListBorrowed aSrc);
+void Gecko_CopyAnimationNames(
+    nsStyleAutoArray<mozilla::StyleAnimation>* aDest,
+    const nsStyleAutoArray<mozilla::StyleAnimation>* aSrc);
 
 // This function takes an already addrefed nsAtom
 void Gecko_SetAnimationName(mozilla::StyleAnimation* aStyleAnimation,
                             nsAtom* aAtom);
 
-void Gecko_UpdateAnimations(RawGeckoElementBorrowed aElementOrPseudo,
-                            ComputedStyleBorrowedOrNull aOldComputedValues,
-                            ComputedStyleBorrowedOrNull aComputedValues,
+void Gecko_UpdateAnimations(const mozilla::dom::Element* aElementOrPseudo,
+                            const mozilla::ComputedStyle* aOldComputedValues,
+                            const mozilla::ComputedStyle* aComputedValues,
                             mozilla::UpdateAnimationsTasks aTasks);
 
-size_t Gecko_GetAnimationEffectCount(RawGeckoElementBorrowed aElementOrPseudo);
-bool Gecko_ElementHasAnimations(RawGeckoElementBorrowed aElementOrPseudo);
-bool Gecko_ElementHasCSSAnimations(RawGeckoElementBorrowed aElementOrPseudo);
-bool Gecko_ElementHasCSSTransitions(RawGeckoElementBorrowed aElementOrPseudo);
-bool Gecko_ElementHasWebAnimations(RawGeckoElementBorrowed aElementOrPseudo);
+size_t Gecko_GetAnimationEffectCount(
+    const mozilla::dom::Element* aElementOrPseudo);
+bool Gecko_ElementHasAnimations(const mozilla::dom::Element* aElementOrPseudo);
+bool Gecko_ElementHasCSSAnimations(
+    const mozilla::dom::Element* aElementOrPseudo);
+bool Gecko_ElementHasCSSTransitions(
+    const mozilla::dom::Element* aElementOrPseudo);
+bool Gecko_ElementHasWebAnimations(
+    const mozilla::dom::Element* aElementOrPseudo);
 size_t Gecko_ElementTransitions_Length(
-    RawGeckoElementBorrowed aElementOrPseudo);
+    const mozilla::dom::Element* aElementOrPseudo);
 
 nsCSSPropertyID Gecko_ElementTransitions_PropertyAt(
-    RawGeckoElementBorrowed aElementOrPseudo, size_t aIndex);
+    const mozilla::dom::Element* aElementOrPseudo, size_t aIndex);
 
-RawServoAnimationValueBorrowedOrNull Gecko_ElementTransitions_EndValueAt(
-    RawGeckoElementBorrowed aElementOrPseudo, size_t aIndex);
+const RawServoAnimationValue* Gecko_ElementTransitions_EndValueAt(
+    const mozilla::dom::Element* aElementOrPseudo, size_t aIndex);
 
-double Gecko_GetProgressFromComputedTiming(
-    RawGeckoComputedTimingBorrowed aComputedTiming);
+double Gecko_GetProgressFromComputedTiming(const mozilla::ComputedTiming*);
 
 double Gecko_GetPositionInSegment(
-    RawGeckoAnimationPropertySegmentBorrowed aSegment, double aProgress,
+    const mozilla::AnimationPropertySegment*, double aProgress,
     mozilla::ComputedTimingFunction::BeforeFlag aBeforeFlag);
 
 // Get servo's AnimationValue for |aProperty| from the cached base style
 // |aBaseStyles|.
 // |aBaseStyles| is nsRefPtrHashtable<nsUint32HashKey, RawServoAnimationValue>.
 // We use RawServoAnimationValueTableBorrowed to avoid exposing
 // nsRefPtrHashtable in FFI.
-RawServoAnimationValueBorrowedOrNull Gecko_AnimationGetBaseStyle(
-    RawServoAnimationValueTableBorrowed aBaseStyles, nsCSSPropertyID aProperty);
+const RawServoAnimationValue* Gecko_AnimationGetBaseStyle(
+    const RawServoAnimationValueTable* aBaseStyles, nsCSSPropertyID aProperty);
 
 void Gecko_StyleTransition_SetUnsupportedProperty(
     mozilla::StyleTransition* aTransition, nsAtom* aAtom);
 
 // Atoms.
 nsAtom* Gecko_Atomize(const char* aString, uint32_t aLength);
 nsAtom* Gecko_Atomize16(const nsAString* aString);
 void Gecko_AddRefAtom(nsAtom* aAtom);
@@ -367,41 +369,41 @@ void Gecko_CopyCursorArrayFrom(nsStyleUI
 
 void Gecko_SetContentDataImageValue(nsStyleContentData* aList,
                                     mozilla::css::URLValue* aImageValue);
 
 nsStyleContentData::CounterFunction* Gecko_SetCounterFunction(
     nsStyleContentData* content_data, mozilla::StyleContentType);
 
 // Dirtiness tracking.
-void Gecko_SetNodeFlags(RawGeckoNodeBorrowed node, uint32_t flags);
-void Gecko_UnsetNodeFlags(RawGeckoNodeBorrowed node, uint32_t flags);
-void Gecko_NoteDirtyElement(RawGeckoElementBorrowed element);
-void Gecko_NoteDirtySubtreeForInvalidation(RawGeckoElementBorrowed element);
-void Gecko_NoteAnimationOnlyDirtyElement(RawGeckoElementBorrowed element);
+void Gecko_SetNodeFlags(const nsINode* node, uint32_t flags);
+void Gecko_UnsetNodeFlags(const nsINode* node, uint32_t flags);
+void Gecko_NoteDirtyElement(const mozilla::dom::Element*);
+void Gecko_NoteDirtySubtreeForInvalidation(const mozilla::dom::Element*);
+void Gecko_NoteAnimationOnlyDirtyElement(const mozilla::dom::Element*);
 
-bool Gecko_AnimationNameMayBeReferencedFromStyle(
-    RawGeckoPresContextBorrowed pres_context, nsAtom* name);
+bool Gecko_AnimationNameMayBeReferencedFromStyle(const nsPresContext*,
+                                                 nsAtom* name);
 
 // Incremental restyle.
 mozilla::PseudoStyleType Gecko_GetImplementedPseudo(
-    RawGeckoElementBorrowed element);
+    const mozilla::dom::Element*);
 
 // We'd like to return `nsChangeHint` here, but bindgen bitfield enums don't
 // work as return values with the Linux 32-bit ABI at the moment because
 // they wrap the value in a struct.
-uint32_t Gecko_CalcStyleDifference(ComputedStyleBorrowed old_style,
-                                   ComputedStyleBorrowed new_style,
+uint32_t Gecko_CalcStyleDifference(const mozilla::ComputedStyle* old_style,
+                                   const mozilla::ComputedStyle* new_style,
                                    bool* any_style_struct_changed,
                                    bool* reset_only_changed);
 
 // Get an element snapshot for a given element from the table.
 const mozilla::ServoElementSnapshot* Gecko_GetElementSnapshot(
     const mozilla::ServoElementSnapshotTable* table,
-    RawGeckoElementBorrowed element);
+    const mozilla::dom::Element*);
 
 // Have we seen this pointer before?
 bool Gecko_HaveSeenPtr(mozilla::SeenPtrs* table, const void* ptr);
 
 // `array` must be an nsTArray
 // If changing this signature, please update the
 // friend function declaration in nsTArray.h
 void Gecko_EnsureTArrayCapacity(void* array, size_t capacity, size_t elem_size);
@@ -472,42 +474,41 @@ void Gecko_CopyWillChangeFrom(nsStyleDis
 // @param offset  The offset to search for, or, if no suitable Keyframe is
 //                found, the offset to use for the created Keyframe.
 //                Must be a floating point number in the range [0.0, 1.0].
 // @param timingFunction  The timing function to match, or, if no suitable
 //                        Keyframe is found, to set on the created Keyframe.
 //
 // @returns  The matching or created Keyframe.
 mozilla::Keyframe* Gecko_GetOrCreateKeyframeAtStart(
-    RawGeckoKeyframeListBorrowedMut keyframes, float offset,
+    nsTArray<mozilla::Keyframe>* keyframes, float offset,
     const nsTimingFunction* timingFunction);
 
 // As with Gecko_GetOrCreateKeyframeAtStart except that this method will search
 // from the beginning of |keyframes| for a Keyframe with matching timing
 // function and an offset of 0.0.
 // Furthermore, if a matching Keyframe is not found, a new Keyframe will be
 // inserted after the *last* Keyframe in |keyframes| with offset 0.0.
 mozilla::Keyframe* Gecko_GetOrCreateInitialKeyframe(
-    RawGeckoKeyframeListBorrowedMut keyframes,
+    nsTArray<mozilla::Keyframe>* keyframes,
     const nsTimingFunction* timingFunction);
 
 // As with Gecko_GetOrCreateKeyframeAtStart except that this method will search
 // from the *end* of |keyframes| for a Keyframe with matching timing function
 // and an offset of 1.0. If a matching Keyframe is not found, a new Keyframe
 // will be appended to the end of |keyframes|.
 mozilla::Keyframe* Gecko_GetOrCreateFinalKeyframe(
-    RawGeckoKeyframeListBorrowedMut keyframes,
+    nsTArray<mozilla::Keyframe>* keyframes,
     const nsTimingFunction* timingFunction);
 
 // Appends and returns a new PropertyValuePair to |aProperties| initialized with
 // its mProperty member set to |aProperty| and all other members initialized to
 // their default values.
 mozilla::PropertyValuePair* Gecko_AppendPropertyValuePair(
-    RawGeckoPropertyValuePairListBorrowedMut aProperties,
-    nsCSSPropertyID aProperty);
+    nsTArray<mozilla::PropertyValuePair>*, nsCSSPropertyID aProperty);
 
 // Clean up pointer-based coordinates
 void Gecko_ResetStyleCoord(nsStyleUnit* unit, nsStyleUnion* value);
 
 // Set an nsStyleCoord to a computed `calc()` value
 void Gecko_SetStyleCoordCalcValue(nsStyleUnit* unit, nsStyleUnion* value,
                                   nsStyleCoord::CalcValue calc);
 
@@ -567,85 +568,79 @@ void Gecko_GetComputedURLSpec(const mozi
                               nsCString* spec);
 
 void Gecko_GetComputedImageURLSpec(const mozilla::css::URLValue* url,
                                    nsCString* spec);
 
 void Gecko_nsIURI_Debug(nsIURI*, nsCString* spec);
 
 NS_DECL_THREADSAFE_FFI_REFCOUNTING(mozilla::css::URLValue, CSSURLValue);
-NS_DECL_THREADSAFE_FFI_REFCOUNTING(RawGeckoURLExtraData, URLExtraData);
+NS_DECL_THREADSAFE_FFI_REFCOUNTING(mozilla::URLExtraData, URLExtraData);
 
 void Gecko_FillAllImageLayers(nsStyleImageLayers* layers, uint32_t max_len);
 
 NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsStyleCoord::Calc, Calc);
 
 nsCSSShadowArray* Gecko_NewCSSShadowArray(uint32_t len);
 
 NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsCSSShadowArray, CSSShadowArray);
 
 nsCSSValueSharedList* Gecko_NewCSSValueSharedList(uint32_t len);
 nsCSSValueSharedList* Gecko_NewNoneTransform();
 void Gecko_StyleDisplay_GenerateCombinedTransform(nsStyleDisplay*);
 
 // Getter for nsCSSValue
-nsCSSValueBorrowedMut Gecko_CSSValue_GetArrayItem(
-    nsCSSValueBorrowedMut css_value, int32_t index);
+nsCSSValue* Gecko_CSSValue_GetArrayItem(nsCSSValue*, int32_t index);
 
 // const version of the above function.
-nsCSSValueBorrowed Gecko_CSSValue_GetArrayItemConst(
-    nsCSSValueBorrowed css_value, int32_t index);
-
-nsCSSKeyword Gecko_CSSValue_GetKeyword(nsCSSValueBorrowed aCSSValue);
-float Gecko_CSSValue_GetNumber(nsCSSValueBorrowed css_value);
-float Gecko_CSSValue_GetPercentage(nsCSSValueBorrowed css_value);
-nsStyleCoord::CalcValue Gecko_CSSValue_GetCalc(nsCSSValueBorrowed aCSSValue);
-void Gecko_CSSValue_SetNumber(nsCSSValueBorrowedMut css_value, float number);
+const nsCSSValue* Gecko_CSSValue_GetArrayItemConst(const nsCSSValue*,
+                                                   int32_t index);
 
-void Gecko_CSSValue_SetKeyword(nsCSSValueBorrowedMut css_value,
-                               nsCSSKeyword keyword);
+nsCSSKeyword Gecko_CSSValue_GetKeyword(const nsCSSValue*);
+float Gecko_CSSValue_GetNumber(const nsCSSValue* css_value);
+float Gecko_CSSValue_GetPercentage(const nsCSSValue* css_value);
+nsStyleCoord::CalcValue Gecko_CSSValue_GetCalc(const nsCSSValue* aCSSValue);
+void Gecko_CSSValue_SetNumber(nsCSSValue* css_value, float number);
 
-void Gecko_CSSValue_SetPercentage(nsCSSValueBorrowedMut css_value,
-                                  float percent);
+void Gecko_CSSValue_SetKeyword(nsCSSValue* css_value, nsCSSKeyword keyword);
+
+void Gecko_CSSValue_SetPercentage(nsCSSValue* css_value, float percent);
 
-void Gecko_CSSValue_SetPixelLength(nsCSSValueBorrowedMut aCSSValue, float aLen);
+void Gecko_CSSValue_SetPixelLength(nsCSSValue* aCSSValue, float aLen);
 
-void Gecko_CSSValue_SetCalc(nsCSSValueBorrowedMut css_value,
+void Gecko_CSSValue_SetCalc(nsCSSValue* css_value,
                             nsStyleCoord::CalcValue calc);
 
-void Gecko_CSSValue_SetFunction(nsCSSValueBorrowedMut css_value, int32_t len);
+void Gecko_CSSValue_SetFunction(nsCSSValue* css_value, int32_t len);
 
-void Gecko_CSSValue_SetString(nsCSSValueBorrowedMut css_value,
-                              const uint8_t* string, uint32_t len,
-                              nsCSSUnit unit);
+void Gecko_CSSValue_SetString(nsCSSValue* css_value, const uint8_t* string,
+                              uint32_t len, nsCSSUnit unit);
 
-void Gecko_CSSValue_SetStringFromAtom(nsCSSValueBorrowedMut css_value,
-                                      nsAtom* atom, nsCSSUnit unit);
+void Gecko_CSSValue_SetStringFromAtom(nsCSSValue* css_value, nsAtom* atom,
+                                      nsCSSUnit unit);
 
 // Take an addrefed nsAtom and set it to the nsCSSValue
-void Gecko_CSSValue_SetAtomIdent(nsCSSValueBorrowedMut css_value, nsAtom* atom);
-void Gecko_CSSValue_SetArray(nsCSSValueBorrowedMut css_value, int32_t len);
+void Gecko_CSSValue_SetAtomIdent(nsCSSValue* css_value, nsAtom* atom);
+void Gecko_CSSValue_SetArray(nsCSSValue* css_value, int32_t len);
 
-void Gecko_CSSValue_SetInt(nsCSSValueBorrowedMut css_value, int32_t integer,
+void Gecko_CSSValue_SetInt(nsCSSValue* css_value, int32_t integer,
                            nsCSSUnit unit);
 
-void Gecko_CSSValue_SetFloat(nsCSSValueBorrowedMut css_value, float value,
+void Gecko_CSSValue_SetFloat(nsCSSValue* css_value, float value,
                              nsCSSUnit unit);
 
-void Gecko_CSSValue_SetPair(nsCSSValueBorrowedMut css_value,
-                            nsCSSValueBorrowed xvalue,
-                            nsCSSValueBorrowed yvalue);
+void Gecko_CSSValue_SetPair(nsCSSValue* css_value, const nsCSSValue* xvalue,
+                            const nsCSSValue* yvalue);
 
-void Gecko_CSSValue_SetList(nsCSSValueBorrowedMut css_value, uint32_t len);
-void Gecko_CSSValue_SetPairList(nsCSSValueBorrowedMut css_value, uint32_t len);
+void Gecko_CSSValue_SetList(nsCSSValue* css_value, uint32_t len);
+void Gecko_CSSValue_SetPairList(nsCSSValue* css_value, uint32_t len);
 
-void Gecko_CSSValue_InitSharedList(nsCSSValueBorrowedMut css_value,
-                                   uint32_t len);
+void Gecko_CSSValue_InitSharedList(nsCSSValue* css_value, uint32_t len);
 
-void Gecko_CSSValue_Drop(nsCSSValueBorrowedMut css_value);
+void Gecko_CSSValue_Drop(nsCSSValue* css_value);
 
 NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsCSSValueSharedList, CSSValueSharedList);
 
 float Gecko_FontStretch_ToFloat(mozilla::FontStretch aStretch);
 
 void Gecko_FontStretch_SetFloat(mozilla::FontStretch* aStretch,
                                 float aFloatValue);
 
@@ -675,57 +670,54 @@ void Gecko_nsStyleFont_PrefillDefaultFor
                                                 const mozilla::dom::Document*,
                                                 uint8_t generic_id);
 
 nscoord Gecko_nsStyleFont_ComputeMinSize(const nsStyleFont*,
                                          const mozilla::dom::Document*);
 
 // Computes the default generic font for a generic family and language.
 mozilla::FontFamilyType Gecko_nsStyleFont_ComputeDefaultFontType(
-    const mozilla::dom::Document*,
-    uint8_t generic_family,
-    nsAtom* language);
+    const mozilla::dom::Document*, uint8_t generic_family, nsAtom* language);
 
 mozilla::FontSizePrefs Gecko_GetBaseSize(nsAtom* lang);
 
 // XBL related functions.
-RawGeckoElementBorrowedOrNull Gecko_GetBindingParent(
-    RawGeckoElementBorrowed aElement);
+const mozilla::dom::Element* Gecko_GetBindingParent(
+    const mozilla::dom::Element*);
 
-RawServoAuthorStylesBorrowedOrNull Gecko_XBLBinding_GetRawServoStyles(
-    RawGeckoXBLBindingBorrowed aXBLBinding);
-
-bool Gecko_XBLBinding_InheritsStyle(RawGeckoXBLBindingBorrowed aXBLBinding);
+const RawServoAuthorStyles* Gecko_XBLBinding_GetRawServoStyles(
+    const nsXBLBinding*);
+bool Gecko_XBLBinding_InheritsStyle(const nsXBLBinding* aXBLBinding);
 
 struct GeckoFontMetrics {
   nscoord mChSize;  // -1.0 indicates not found
   nscoord mXSize;
 };
 
-GeckoFontMetrics Gecko_GetFontMetrics(RawGeckoPresContextBorrowed pres_context,
-                                      bool is_vertical, const nsStyleFont* font,
+GeckoFontMetrics Gecko_GetFontMetrics(const nsPresContext*, bool is_vertical,
+                                      const nsStyleFont* font,
                                       nscoord font_size,
                                       bool use_user_font_set);
 
 mozilla::StyleSheet* Gecko_StyleSheet_Clone(
     const mozilla::StyleSheet* aSheet,
     const mozilla::StyleSheet* aNewParentSheet);
 
 void Gecko_StyleSheet_AddRef(const mozilla::StyleSheet* aSheet);
 void Gecko_StyleSheet_Release(const mozilla::StyleSheet* aSheet);
 nsCSSKeyword Gecko_LookupCSSKeyword(const uint8_t* string, uint32_t len);
 const char* Gecko_CSSKeywordString(nsCSSKeyword keyword, uint32_t* len);
-bool Gecko_IsDocumentBody(RawGeckoElementBorrowed element);
+bool Gecko_IsDocumentBody(const mozilla::dom::Element* element);
 
 // We use an int32_t here instead of a LookAndFeel::ColorID
 // because forward-declaring a nested enum/struct is impossible
 nscolor Gecko_GetLookAndFeelSystemColor(int32_t color_id,
                                         const mozilla::dom::Document*);
 
-void Gecko_AddPropertyToSet(nsCSSPropertyIDSetBorrowedMut, nsCSSPropertyID);
+void Gecko_AddPropertyToSet(nsCSSPropertyIDSet*, nsCSSPropertyID);
 
 // Style-struct management.
 #define STYLE_STRUCT(name)                                                   \
   void Gecko_Construct_Default_nsStyle##name(nsStyle##name* ptr,             \
                                              const mozilla::dom::Document*); \
   void Gecko_CopyConstruct_nsStyle##name(nsStyle##name* ptr,                 \
                                          const nsStyle##name* other);        \
   void Gecko_Destroy_nsStyle##name(nsStyle##name* ptr);
@@ -757,17 +749,17 @@ void Gecko_ReportUnexpectedCSSError(cons
                                     const char* param, uint32_t paramLen,
                                     const char* prefix, const char* prefixParam,
                                     uint32_t prefixParamLen, const char* suffix,
                                     const char* source, uint32_t sourceLen,
                                     uint32_t lineNumber, uint32_t colNumber);
 
 // DOM APIs.
 void Gecko_ContentList_AppendAll(nsSimpleContentList* aContentList,
-                                 const RawGeckoElement** aElements,
+                                 const mozilla::dom::Element** aElements,
                                  size_t aLength);
 
 // FIXME(emilio): These two below should be a single function that takes a
 // `const DocumentOrShadowRoot*`, but that doesn't make MSVC builds happy for a
 // reason I haven't really dug into.
 const nsTArray<mozilla::dom::Element*>* Gecko_Document_GetElementsWithId(
     const mozilla::dom::Document*, nsAtom* aId);
 
--- a/layout/style/ServoBindingTypes.h
+++ b/layout/style/ServoBindingTypes.h
@@ -2,127 +2,93 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* C++ types corresponding to Servo and Gecko types used across bindings,
    with some annotations to indicate ownership expectations */
 
-// This file defines a number of C++ types used to represent borrowed,
-// strong, and owning references to Servo and Gecko objects that might
-// be used across bindings and FFI.
+// This file defines a number of C++ types used to represent strong, and owning
+// references to Servo and Gecko objects that might be used across bindings and
+// FFI.
 //
 // By convention, the types defined here are named "RawServo{Type}" and
 // "RawGecko{Type}".  The {Type} should be something close to the real Rust or
 // C++ name of the type, but need not be.  The "Raw" is really just used to
 // avoid clashing with other names.
 //
 // For Servo types, each "RawServo{ServoTypeName}" is generated as an opaque,
 // declared but not defined struct.
 //
 // For Gecko types, each "RawGecko{GeckoTypeName}" is a typedef that aliases
 // the actual C++ type.
 //
 // Each of these types can have a number of different typedefs generated for
 // them, representing different notions of ownership when passing or receiving
 // these values across bindings and FFI:
 //
-//   Raw{Gecko,Servo}{Type}Borrowed
-//   Raw{Gecko,Servo}{Type}BorrowedOrNull
-//     immutable, borrowed reference (or null)
-//
-//   Raw{Gecko,Servo}{Type}BorrowedMut
-//   Raw{Gecko,Servo}{Type}BorrowedMutOrNull
-//     mutable, borrowed reference (or null)
-//
 //   RawServo{Type}Strong
 //     strong reference to an Arc-managed value
 //
 //   RawServo{Type}Owned
 //   RawServo{Type}OwnedOrNull
 //     owned reference to a Box-managed value (or null)
 //
-// All of these borrowed, strong, and owned types are generated by adding
+// All of these strong, and owned types are generated by adding
 // entries to one of these files:
 //
-//   BorrowedTypeList.h
-//     generates some or all of the Borrowed types
-//
 //   ServoArcTypeList.h
-//     generates all of the Borrowed types and the Strong type
+//     generates the Strong type
 //
 //   ServoBoxedTypeList.h
-//     generates all of the Borrowed types and the Owned & OwnedNull types
+//     generates the Owned & OwnedOrNull types
 //
-// The borrowed, strong, and owned reference types should be used in FFI
-// function signatures where possible, to help indicate the ownership properties
-// that both sides of the function call must adhere to.
+// The strong, and owned reference types should be used in FFI function
+// signatures where possible, to help indicate the ownership properties that
+// both sides of the function call must adhere to.
 //
 // There are some special cases defined at the bottom of this file that don't
 // fit neatly into these three categories.
 //
 //
-// Using these types in C++
-// ========================
+// Using these types in C++ ========================
 //
-// All of the Borrowed types are C++ typedefs for raw pointers, and can be used
-// directly.  Since the types they point to are opaque, there isn't much that
-// can be done with these apart from passing them around, holding on to them,
-// checking them for equality, etc.  If they are Arc-managed or Box-managed
-// Servo types, they can be assigned to a RefPtr<> or UniquePtr<>.
-//
-// The Strong types are a C++ struct that wraps a raw pointer.  When receiving
-// a Strong value from a Servo_* FFI function, you must call Consume() on it
-// to convert it into an already_AddRefed<RawServo{Type}>, otherwise it will
-// leak.
+// The Strong types are a C++ struct that wraps a raw pointer.  When receiving a
+// Strong value from a Servo_* FFI function, you must call Consume() on it to
+// convert it into an already_AddRefed<RawServo{Type}>, otherwise it will leak.
 //
 // We don't currently have any cases where we pass a Strong value to Servo; this
 // could be done by creating a RawServo{Type}Strong struct value whose mPtr is
 // initialized to the result of calling `.forget().take()` on a
-// RefPtr<RawServo{Type}>, but it's probably easier just to pass a Borrowed
-// value and let the Rust code turn it into an Arc.
+// RefPtr<RawServo{Type}>, but it's probably easier just to pass a raw pointer
+// and let the Rust code turn it into an Arc.
 //
 // The Owned types are C++ typedefs for raw pointers.  When receiving an Owned
 // value from a Servo_* FFI function, it should be assigned to a UniquePtr<>,
 // otherwise it will leak.
 //
 // To pass an Owned value to Servo, call `release()` on the UniquePtr<> it's
 // living in (to take ownership of it), and pass that pointer in directly.
 //
-// TODO(heycam): We should perhaps have a similar struct for Owned types with
-// a Consume() method to convert them into a UniquePtr.  The struct for Strong
+// TODO(heycam): We should perhaps have a similar struct for Owned types with a
+// Consume() method to convert them into a UniquePtr.  The struct for Strong
 // types at least have MOZ_MUST_USE_TYPE on them.
 //
 //
-// Using these types in Rust
-// =========================
+// Using these types in Rust =========================
 //
 // The FFI type names are available in Rust in the gecko_bindings::bindings mod,
 // which is generated by servo/components/style/build_gecko.rs.
 //
-// The Borrowed types are defined as Rust reference types.
-//
-// Borrowed types for Gecko values are references to the bindgened versions of
-// the C++ types, so when receiving references over FFI into a Servo_* function,
-// they can be used directly, and when returning them back to Gecko, the
-// reference can be returned directly.
-//
-// Borrowed types for Servo values are references to an opaque type, which must
-// be converted to or from the appropriate Rust type:
+// Borrowed types in rust are represented by &T, Option<&T>, &mut T, and
+// Option<&mut T>.
 //
-//   For an Arc-owned value, a RawServoFooBorrowed received from FFI can be
-//   converted into a `&Arc<Foo>` by calling `Foo::as_arc(&raw_servo_foo)`.
-//   Returning a RawServoFooBorrowed over FFI back to Gecko can be done by
-//   calling `as_borrowed()` on the `Arc<Foo>`.
-//
-//   For a Box-owned value, a RawServoFooBorrowed received from FFI can be
-//   converted into a `&Foo` by calling `Foo::from_ffi(&raw_servo_foo)`.
-//   Returning a RawServoFooBorrowed over FFI back to Gecko can be done by
-//   calling `as_ffi()` on the `Foo`.
+// In C++ you should write them as const pointers (for &T and Option<&T>) or
+// non-const pointers (for &mut T and Option<&mut T>).
 //
 // The Strong types are defined as gecko_bindings::sugar::ownership::Strong<T>.
 //
 // This is an FFI safe type that represents the value with a strong reference
 // already added to it.  Dropping a Strong<T> will leak the strong reference.
 //
 // A RawServoFooStrong received from FFI can be converted into a
 // `RawOffsetArc<Foo>` by calling `into_arc()` or `into_arc_opt()` on it.
@@ -189,56 +155,29 @@ using GfxMatrix4x4 = mozilla::gfx::Float
 
 namespace dom {
 class StyleChildrenIterator;
 class Document;
 class Element;
 }  // namespace dom
 }  // namespace mozilla
 
-#define DECL_BORROWED_REF_TYPE_FOR(type_) typedef type_ const* type_##Borrowed;
-#define DECL_NULLABLE_BORROWED_REF_TYPE_FOR(type_) \
-  typedef type_ const* type_##BorrowedOrNull;
-#define DECL_BORROWED_MUT_REF_TYPE_FOR(type_) typedef type_* type_##BorrowedMut;
-#define DECL_NULLABLE_BORROWED_MUT_REF_TYPE_FOR(type_) \
-  typedef type_* type_##BorrowedMutOrNull;
-
-#define DECL_OWNED_REF_TYPE_FOR(type_) \
-  typedef type_* type_##Owned;         \
-  DECL_BORROWED_REF_TYPE_FOR(type_)    \
-  DECL_BORROWED_MUT_REF_TYPE_FOR(type_)
+#define DECL_OWNED_REF_TYPE_FOR(type_) typedef type_* type_##Owned;
 
 #define DECL_NULLABLE_OWNED_REF_TYPE_FOR(type_) \
-  typedef type_* type_##OwnedOrNull;            \
-  DECL_NULLABLE_BORROWED_REF_TYPE_FOR(type_)    \
-  DECL_NULLABLE_BORROWED_MUT_REF_TYPE_FOR(type_)
-
-#define GECKO_BORROWED_TYPE(geckotype_, ffitype_) \
-  using ffitype_ = geckotype_;                    \
-  using ffitype_##Borrowed = const ffitype_*;     \
-  using ffitype_##BorrowedOrNull = const ffitype_*;
-#define GECKO_BORROWED_TYPE_MUT(geckotype_, ffitype_) \
-  GECKO_BORROWED_TYPE(geckotype_, ffitype_)           \
-  using ffitype_##BorrowedMut = ffitype_*;            \
-  using ffitype_##BorrowedMutOrNull = ffitype_*;
-#include "mozilla/BorrowedTypeList.h"
-#undef GECKO_BORROWED_TYPE_MUT
-#undef GECKO_BORROWED_TYPE
+  typedef type_* type_##OwnedOrNull;
 
 #define SERVO_ARC_TYPE(name_, type_)                                    \
-  DECL_NULLABLE_BORROWED_REF_TYPE_FOR(type_)                            \
-  DECL_BORROWED_REF_TYPE_FOR(type_)                                     \
-  DECL_BORROWED_MUT_REF_TYPE_FOR(type_)                                 \
   struct MOZ_MUST_USE_TYPE type_##Strong {                              \
     type_* mPtr;                                                        \
     already_AddRefed<type_> Consume();                                  \
   };                                                                    \
   extern "C" {                                                          \
-  void Servo_##name_##_AddRef(type_##Borrowed ptr);                     \
-  void Servo_##name_##_Release(type_##Borrowed ptr);                    \
+  void Servo_##name_##_AddRef(const type_*);                            \
+  void Servo_##name_##_Release(const type_*);                           \
   }                                                                     \
   namespace mozilla {                                                   \
   template <>                                                           \
   struct RefPtrTraits<type_> {                                          \
     static void AddRef(type_* aPtr) { Servo_##name_##_AddRef(aPtr); }   \
     static void Release(type_* aPtr) { Servo_##name_##_Release(aPtr); } \
   };                                                                    \
   }
@@ -254,49 +193,24 @@ class Element;
   class DefaultDelete<type_> {                                         \
    public:                                                             \
     void operator()(type_* aPtr) const { Servo_##name_##_Drop(aPtr); } \
   };                                                                   \
   }
 #include "mozilla/ServoBoxedTypeList.h"
 #undef SERVO_BOXED_TYPE
 
-#define DEFINE_ARRAY_TYPE_FOR(type_)                               \
-  struct nsTArrayBorrowed_##type_ {                                \
-    nsTArray<type_>* mArray;                                       \
-    MOZ_IMPLICIT nsTArrayBorrowed_##type_(nsTArray<type_>* aArray) \
-        : mArray(aArray) {}                                        \
-  }
-DEFINE_ARRAY_TYPE_FOR(uintptr_t);
-#undef DEFINE_ARRAY_TYPE_FOR
-
 // Other special cases.
 
-typedef void* RawServoAnimationValueTableBorrowed;
-
 // TODO(heycam): Handle these elsewhere.
+struct RawServoAnimationValueTable;
 struct RawServoAnimationValueMap;
-DECL_NULLABLE_BORROWED_REF_TYPE_FOR(RawServoAnimationValueMap)
-DECL_BORROWED_REF_TYPE_FOR(RawServoAnimationValueMap)
-DECL_BORROWED_MUT_REF_TYPE_FOR(RawServoAnimationValueMap)
-
-typedef mozilla::ComputedStyle const* ComputedStyleBorrowed;
-typedef mozilla::ComputedStyle const* ComputedStyleBorrowedOrNull;
-typedef ServoComputedData const* ServoComputedDataBorrowed;
 
 struct MOZ_MUST_USE_TYPE ComputedStyleStrong {
   mozilla::ComputedStyle* mPtr;
   already_AddRefed<mozilla::ComputedStyle> Consume();
 };
 
-// This is a reference to a reference of RawServoDeclarationBlock, which
-// corresponds to Option<&Arc<Locked<RawServoDeclarationBlock>>> in Servo side.
-DECL_NULLABLE_BORROWED_REF_TYPE_FOR(RawServoDeclarationBlockStrong)
-
 #undef DECL_ARC_REF_TYPE_FOR
 #undef DECL_OWNED_REF_TYPE_FOR
 #undef DECL_NULLABLE_OWNED_REF_TYPE_FOR
-#undef DECL_BORROWED_REF_TYPE_FOR
-#undef DECL_NULLABLE_BORROWED_REF_TYPE_FOR
-#undef DECL_BORROWED_MUT_REF_TYPE_FOR
-#undef DECL_NULLABLE_BORROWED_MUT_REF_TYPE_FOR
 
 #endif  // mozilla_ServoBindingTypes_h
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -48,256 +48,248 @@ enum class IterationCompositeOperation :
 
 namespace nsStyleTransformMatrix {
 enum class MatrixTransformOperator : uint8_t;
 }
 
 extern "C" {
 
 // Element data
-void Servo_Element_ClearData(RawGeckoElementBorrowed node);
+void Servo_Element_ClearData(const mozilla::dom::Element* node);
 
 size_t Servo_Element_SizeOfExcludingThisAndCVs(
     mozilla::MallocSizeOf malloc_size_of,
     mozilla::MallocSizeOf malloc_enclosing_size_of,
-    mozilla::SeenPtrs* seen_ptrs, RawGeckoElementBorrowed node);
+    mozilla::SeenPtrs* seen_ptrs, const mozilla::dom::Element* node);
 
-bool Servo_Element_HasPrimaryComputedValues(RawGeckoElementBorrowed node);
+bool Servo_Element_HasPrimaryComputedValues(const mozilla::dom::Element* node);
 
 ComputedStyleStrong Servo_Element_GetPrimaryComputedValues(
-    RawGeckoElementBorrowed node);
+    const mozilla::dom::Element* node);
 
-bool Servo_Element_HasPseudoComputedValues(RawGeckoElementBorrowed node,
+bool Servo_Element_HasPseudoComputedValues(const mozilla::dom::Element* node,
                                            size_t index);
 
 ComputedStyleStrong Servo_Element_GetPseudoComputedValues(
-    RawGeckoElementBorrowed node, size_t index);
+    const mozilla::dom::Element* node, size_t index);
 
-bool Servo_Element_IsDisplayNone(RawGeckoElementBorrowed element);
-bool Servo_Element_IsDisplayContents(RawGeckoElementBorrowed element);
+bool Servo_Element_IsDisplayNone(const mozilla::dom::Element* element);
+bool Servo_Element_IsDisplayContents(const mozilla::dom::Element* element);
 
 bool Servo_Element_IsPrimaryStyleReusedViaRuleNode(
-    RawGeckoElementBorrowed element);
+    const mozilla::dom::Element* element);
 
 void Servo_InvalidateStyleForDocStateChanges(
-    RawGeckoElementBorrowed root, RawServoStyleSetBorrowed doc_styles,
-    const nsTArray<RawServoAuthorStylesBorrowed>* non_document_styles,
+    const mozilla::dom::Element* root, const RawServoStyleSet* doc_styles,
+    const nsTArray<const RawServoAuthorStyles*>* non_document_styles,
     uint64_t aStatesChanged);
 
 // Styleset and Stylesheet management
 
 RawServoStyleSheetContentsStrong Servo_StyleSheet_FromUTF8Bytes(
     mozilla::css::Loader* loader, mozilla::StyleSheet* gecko_stylesheet,
     mozilla::css::SheetLoadData* load_data, const nsACString* bytes,
     mozilla::css::SheetParsingMode parsing_mode,
-    RawGeckoURLExtraData* extra_data, uint32_t line_number_offset,
+    mozilla::URLExtraData* extra_data, uint32_t line_number_offset,
     nsCompatibility quirks_mode,
     mozilla::css::LoaderReusableStyleSheets* reusable_sheets,
-    StyleUseCountersBorrowedOrNull use_counters);
+    const StyleUseCounters* use_counters);
 
 void Servo_StyleSheet_FromUTF8BytesAsync(
     mozilla::css::SheetLoadDataHolder* load_data,
-    RawGeckoURLExtraData* extra_data, const nsACString* bytes,
+    mozilla::URLExtraData* extra_data, const nsACString* bytes,
     mozilla::css::SheetParsingMode parsing_mode, uint32_t line_number_offset,
     nsCompatibility quirks_mode, bool should_record_use_counters);
 
 RawServoStyleSheetContentsStrong Servo_StyleSheet_Empty(
     mozilla::css::SheetParsingMode parsing_mode);
 
-bool Servo_StyleSheet_HasRules(RawServoStyleSheetContentsBorrowed sheet);
+bool Servo_StyleSheet_HasRules(const RawServoStyleSheetContents* sheet);
 
 ServoCssRulesStrong Servo_StyleSheet_GetRules(
-    RawServoStyleSheetContentsBorrowed sheet);
+    const RawServoStyleSheetContents* sheet);
 
 RawServoStyleSheetContentsStrong Servo_StyleSheet_Clone(
-    RawServoStyleSheetContentsBorrowed sheet,
+    const RawServoStyleSheetContents* sheet,
     const mozilla::StyleSheet* reference_sheet);
 
 size_t Servo_StyleSheet_SizeOfIncludingThis(
     mozilla::MallocSizeOf malloc_size_of,
     mozilla::MallocSizeOf malloc_enclosing_size_of,
-    RawServoStyleSheetContentsBorrowed sheet);
+    const RawServoStyleSheetContents* sheet);
 
-void Servo_StyleSheet_GetSourceMapURL(RawServoStyleSheetContentsBorrowed sheet,
+void Servo_StyleSheet_GetSourceMapURL(const RawServoStyleSheetContents* sheet,
                                       nsAString* result);
 
-void Servo_StyleSheet_GetSourceURL(RawServoStyleSheetContentsBorrowed sheet,
+void Servo_StyleSheet_GetSourceURL(const RawServoStyleSheetContents* sheet,
                                    nsAString* result);
 
 // We'd like to return `OriginFlags` here, but bindgen bitfield enums don't
 // work as return values with the Linux 32-bit ABI at the moment because
 // they wrap the value in a struct.
-uint8_t Servo_StyleSheet_GetOrigin(RawServoStyleSheetContentsBorrowed sheet);
+uint8_t Servo_StyleSheet_GetOrigin(const RawServoStyleSheetContents* sheet);
 
-RawServoStyleSet* Servo_StyleSet_Init(RawGeckoPresContextBorrowed pres_context);
-void Servo_StyleSet_RebuildCachedData(RawServoStyleSetBorrowed set);
+RawServoStyleSet* Servo_StyleSet_Init(const nsPresContext* pres_context);
+void Servo_StyleSet_RebuildCachedData(const RawServoStyleSet* set);
 
 // We'd like to return `OriginFlags` here, but bindgen bitfield enums don't
 // work as return values with the Linux 32-bit ABI at the moment because
 // they wrap the value in a struct.
 mozilla::MediumFeaturesChangedResult Servo_StyleSet_MediumFeaturesChanged(
-    RawServoStyleSetBorrowed document_set,
-    nsTArray<RawServoAuthorStylesBorrowedMut>* non_document_sets,
+    const RawServoStyleSet* document_set,
+    nsTArray<RawServoAuthorStyles*>* non_document_sets,
     bool may_affect_default_style);
 
 void Servo_StyleSet_Drop(RawServoStyleSetOwned set);
-void Servo_StyleSet_CompatModeChanged(RawServoStyleSetBorrowed raw_data);
+void Servo_StyleSet_CompatModeChanged(const RawServoStyleSet* raw_data);
 
-void Servo_StyleSet_AppendStyleSheet(RawServoStyleSetBorrowed set,
+void Servo_StyleSet_AppendStyleSheet(const RawServoStyleSet* set,
                                      const mozilla::StyleSheet* gecko_sheet);
 
-void Servo_StyleSet_RemoveStyleSheet(RawServoStyleSetBorrowed set,
+void Servo_StyleSet_RemoveStyleSheet(const RawServoStyleSet* set,
                                      const mozilla::StyleSheet* gecko_sheet);
 
 void Servo_StyleSet_InsertStyleSheetBefore(
-    RawServoStyleSetBorrowed set, const mozilla::StyleSheet* gecko_sheet,
+    const RawServoStyleSet* set, const mozilla::StyleSheet* gecko_sheet,
     const mozilla::StyleSheet* before);
 
 void Servo_StyleSet_FlushStyleSheets(
-    RawServoStyleSetBorrowed set, RawGeckoElementBorrowedOrNull doc_elem,
+    const RawServoStyleSet* set, const mozilla::dom::Element* doc_elem,
     const mozilla::ServoElementSnapshotTable* snapshots);
 
-void Servo_StyleSet_SetAuthorStyleDisabled(RawServoStyleSetBorrowed set,
+void Servo_StyleSet_SetAuthorStyleDisabled(const RawServoStyleSet* set,
                                            bool author_style_disabled);
 
 void Servo_StyleSet_NoteStyleSheetsChanged(
-    RawServoStyleSetBorrowed set, mozilla::OriginFlags changed_origins);
+    const RawServoStyleSet* set, mozilla::OriginFlags changed_origins);
 
 bool Servo_StyleSet_GetKeyframesForName(
-    RawServoStyleSetBorrowed set, RawGeckoElementBorrowed element,
-    ComputedStyleBorrowed style, nsAtom* name,
-    nsTimingFunctionBorrowed timing_function,
-    RawGeckoKeyframeListBorrowedMut keyframe_list);
+    const RawServoStyleSet* set, const mozilla::dom::Element* element,
+    const mozilla::ComputedStyle* style, nsAtom* name,
+    const nsTimingFunction* timing_function,
+    nsTArray<mozilla::Keyframe>* keyframe_list);
 
-void Servo_StyleSet_GetFontFaceRules(RawServoStyleSetBorrowed set,
-                                     RawGeckoFontFaceRuleListBorrowedMut list);
+void Servo_StyleSet_GetFontFaceRules(const RawServoStyleSet* set,
+                                     nsTArray<nsFontFaceRuleContainer>*);
 
 const RawServoCounterStyleRule* Servo_StyleSet_GetCounterStyleRule(
-    RawServoStyleSetBorrowed set, nsAtom* name);
+    const RawServoStyleSet* set, nsAtom* name);
 
 // This function may return nullptr or gfxFontFeatureValueSet with zero
 // references.
 gfxFontFeatureValueSet* Servo_StyleSet_BuildFontFeatureValueSet(
-    RawServoStyleSetBorrowed set);
+    const RawServoStyleSet* set);
 
 ComputedStyleStrong Servo_StyleSet_ResolveForDeclarations(
-    RawServoStyleSetBorrowed set, ComputedStyleBorrowedOrNull parent_style,
-    RawServoDeclarationBlockBorrowed declarations);
+    const RawServoStyleSet* set, const mozilla::ComputedStyle* parent_style,
+    const RawServoDeclarationBlock* declarations);
 
-void Servo_SelectorList_Drop(RawServoSelectorListOwned selector_list);
+void Servo_SelectorList_Drop(RawServoSelectorList*);
 RawServoSelectorList* Servo_SelectorList_Parse(const nsACString* selector_list);
 RawServoSourceSizeList* Servo_SourceSizeList_Parse(const nsACString* value);
 
-int32_t Servo_SourceSizeList_Evaluate(RawServoStyleSetBorrowed set,
-                                      RawServoSourceSizeListBorrowedOrNull);
+int32_t Servo_SourceSizeList_Evaluate(const RawServoStyleSet* set,
+                                      const RawServoSourceSizeList*);
 
-void Servo_SourceSizeList_Drop(RawServoSourceSizeListOwned);
+void Servo_SourceSizeList_Drop(RawServoSourceSizeList*);
 
-bool Servo_SelectorList_Matches(RawGeckoElementBorrowed,
-                                RawServoSelectorListBorrowed);
+bool Servo_SelectorList_Matches(const mozilla::dom::Element*,
+                                const RawServoSelectorList*);
 
-const RawGeckoElement* Servo_SelectorList_Closest(RawGeckoElementBorrowed,
-                                                  RawServoSelectorListBorrowed);
+const mozilla::dom::Element* Servo_SelectorList_Closest(
+    const mozilla::dom::Element*, const RawServoSelectorList*);
 
-const RawGeckoElement* Servo_SelectorList_QueryFirst(
-    RawGeckoNodeBorrowed, RawServoSelectorListBorrowed,
-    bool may_use_invalidation);
+const mozilla::dom::Element* Servo_SelectorList_QueryFirst(
+    const nsINode*, const RawServoSelectorList*, bool may_use_invalidation);
 
-void Servo_SelectorList_QueryAll(RawGeckoNodeBorrowed,
-                                 RawServoSelectorListBorrowed,
+void Servo_SelectorList_QueryAll(const nsINode*, const RawServoSelectorList*,
                                  nsSimpleContentList* content_list,
                                  bool may_use_invalidation);
 
 void Servo_StyleSet_AddSizeOfExcludingThis(
     mozilla::MallocSizeOf malloc_size_of,
     mozilla::MallocSizeOf malloc_enclosing_size_of,
-    mozilla::ServoStyleSetSizes* sizes, RawServoStyleSetBorrowed set);
+    mozilla::ServoStyleSetSizes* sizes, const RawServoStyleSet* set);
 
 void Servo_UACache_AddSizeOf(mozilla::MallocSizeOf malloc_size_of,
                              mozilla::MallocSizeOf malloc_enclosing_size_of,
                              mozilla::ServoStyleSetSizes* sizes);
 
 // AuthorStyles
 
 RawServoAuthorStyles* Servo_AuthorStyles_Create();
-void Servo_AuthorStyles_Drop(RawServoAuthorStylesOwned self);
+void Servo_AuthorStyles_Drop(RawServoAuthorStyles*);
 
-// TODO(emilio): These will need to take a master style set to implement
-// invalidation for Shadow DOM.
-void Servo_AuthorStyles_AppendStyleSheet(
-    RawServoAuthorStylesBorrowedMut self,
-    const mozilla::StyleSheet* gecko_sheet);
+void Servo_AuthorStyles_AppendStyleSheet(RawServoAuthorStyles*,
+                                         const mozilla::StyleSheet*);
 
-void Servo_AuthorStyles_RemoveStyleSheet(
-    RawServoAuthorStylesBorrowedMut self,
-    const mozilla::StyleSheet* gecko_sheet);
+void Servo_AuthorStyles_RemoveStyleSheet(RawServoAuthorStyles*,
+                                         const mozilla::StyleSheet*);
 
 void Servo_AuthorStyles_InsertStyleSheetBefore(
-    RawServoAuthorStylesBorrowedMut self,
-    const mozilla::StyleSheet* gecko_sheet, const mozilla::StyleSheet* before);
+    RawServoAuthorStyles*, const mozilla::StyleSheet* sheet,
+    const mozilla::StyleSheet* before);
 
-void Servo_AuthorStyles_ForceDirty(RawServoAuthorStylesBorrowedMut self);
+void Servo_AuthorStyles_ForceDirty(RawServoAuthorStyles*);
 
 // TODO(emilio): This will need to take an element and a master style set to
 // implement invalidation for Shadow DOM.
-void Servo_AuthorStyles_Flush(RawServoAuthorStylesBorrowedMut self,
-                              RawServoStyleSetBorrowed document_styles);
+void Servo_AuthorStyles_Flush(RawServoAuthorStyles*,
+                              const RawServoStyleSet* document_styles);
 
 size_t Servo_AuthorStyles_SizeOfIncludingThis(
     mozilla::MallocSizeOf malloc_size_of,
     mozilla::MallocSizeOf malloc_enclosing_size_of,
-    RawServoAuthorStylesBorrowed self);
+    const RawServoAuthorStyles* self);
 
-void Servo_ComputedStyle_AddRef(ComputedStyleBorrowed ctx);
+void Servo_ComputedStyle_AddRef(const mozilla::ComputedStyle* ctx);
 
-void Servo_ComputedStyle_Release(ComputedStyleBorrowed ctx);
+void Servo_ComputedStyle_Release(const mozilla::ComputedStyle* ctx);
 
 bool Servo_StyleSet_MightHaveAttributeDependency(
-    RawServoStyleSetBorrowed set, RawGeckoElementBorrowed element,
+    const RawServoStyleSet* set, const mozilla::dom::Element* element,
     nsAtom* local_name);
 
-bool Servo_StyleSet_HasStateDependency(RawServoStyleSetBorrowed set,
-                                       RawGeckoElementBorrowed element,
+bool Servo_StyleSet_HasStateDependency(const RawServoStyleSet* set,
+                                       const mozilla::dom::Element* element,
                                        uint64_t state);
 
-bool Servo_StyleSet_HasDocumentStateDependency(RawServoStyleSetBorrowed set,
+bool Servo_StyleSet_HasDocumentStateDependency(const RawServoStyleSet* set,
                                                uint64_t state);
 
 // CSSRuleList
 
-void Servo_CssRules_ListTypes(ServoCssRulesBorrowed rules,
-                              nsTArrayBorrowed_uintptr_t result);
+void Servo_CssRules_ListTypes(const ServoCssRules*,
+                              const nsTArray<uintptr_t>* result);
 
-nsresult Servo_CssRules_InsertRule(ServoCssRulesBorrowed rules,
-                                   RawServoStyleSheetContentsBorrowed sheet,
+nsresult Servo_CssRules_InsertRule(const ServoCssRules*,
+                                   const RawServoStyleSheetContents* sheet,
                                    const nsACString* rule, uint32_t index,
                                    bool nested, mozilla::css::Loader* loader,
                                    mozilla::StyleSheet* gecko_stylesheet,
                                    uint16_t* rule_type);
 
-nsresult Servo_CssRules_DeleteRule(ServoCssRulesBorrowed rules, uint32_t index);
+nsresult Servo_CssRules_DeleteRule(const ServoCssRules* rules, uint32_t index);
 
 // CSS Rules
 
-#define BASIC_RULE_FUNCS_WITHOUT_GETTER(type_)                    \
-  void Servo_##type_##_Debug(RawServo##type_##Borrowed rule,      \
-                             nsACString* result);                 \
-  void Servo_##type_##_GetCssText(RawServo##type_##Borrowed rule, \
-                                  nsAString* result);
+#define BASIC_RULE_FUNCS_WITHOUT_GETTER(type_)                            \
+  void Servo_##type_##_Debug(const RawServo##type_*, nsACString* result); \
+  void Servo_##type_##_GetCssText(const RawServo##type_*, nsAString* result);
 
-#define BASIC_RULE_FUNCS(type_)                                    \
-  RawServo##type_##RuleStrong Servo_CssRules_Get##type_##RuleAt(   \
-      ServoCssRulesBorrowed rules, uint32_t index, uint32_t* line, \
-      uint32_t* column);                                           \
+#define BASIC_RULE_FUNCS(type_)                                   \
+  RawServo##type_##RuleStrong Servo_CssRules_Get##type_##RuleAt(  \
+      const ServoCssRules* rules, uint32_t index, uint32_t* line, \
+      uint32_t* column);                                          \
   BASIC_RULE_FUNCS_WITHOUT_GETTER(type_##Rule)
 
 #define GROUP_RULE_FUNCS(type_)                     \
   BASIC_RULE_FUNCS(type_)                           \
   ServoCssRulesStrong Servo_##type_##Rule_GetRules( \
-      RawServo##type_##RuleBorrowed rule);
+      const RawServo##type_##Rule* rule);
 
 BASIC_RULE_FUNCS(Style)
 BASIC_RULE_FUNCS(Import)
 BASIC_RULE_FUNCS_WITHOUT_GETTER(Keyframe)
 BASIC_RULE_FUNCS(Keyframes)
 GROUP_RULE_FUNCS(Media)
 GROUP_RULE_FUNCS(MozDocument)
 BASIC_RULE_FUNCS(Namespace)
@@ -306,660 +298,660 @@ GROUP_RULE_FUNCS(Supports)
 BASIC_RULE_FUNCS(FontFeatureValues)
 BASIC_RULE_FUNCS(FontFace)
 BASIC_RULE_FUNCS(CounterStyle)
 
 #undef GROUP_RULE_FUNCS
 #undef BASIC_RULE_FUNCS
 #undef BASIC_RULE_FUNCS_WITHOUT_GETTER
 
+using Matrix4x4Components = float[16];
+
 RawServoDeclarationBlockStrong Servo_StyleRule_GetStyle(
-    RawServoStyleRuleBorrowed rule);
+    const RawServoStyleRule*);
 
-void Servo_StyleRule_SetStyle(RawServoStyleRuleBorrowed rule,
-                              RawServoDeclarationBlockBorrowed declarations);
+void Servo_StyleRule_SetStyle(const RawServoStyleRule* rule,
+                              const RawServoDeclarationBlock* declarations);
 
-void Servo_StyleRule_GetSelectorText(RawServoStyleRuleBorrowed rule,
+void Servo_StyleRule_GetSelectorText(const RawServoStyleRule* rule,
                                      nsAString* result);
 
-void Servo_StyleRule_GetSelectorTextAtIndex(RawServoStyleRuleBorrowed rule,
+void Servo_StyleRule_GetSelectorTextAtIndex(const RawServoStyleRule* rule,
                                             uint32_t index, nsAString* result);
 
-void Servo_StyleRule_GetSpecificityAtIndex(RawServoStyleRuleBorrowed rule,
+void Servo_StyleRule_GetSpecificityAtIndex(const RawServoStyleRule* rule,
                                            uint32_t index,
                                            uint64_t* specificity);
 
-void Servo_StyleRule_GetSelectorCount(RawServoStyleRuleBorrowed rule,
+void Servo_StyleRule_GetSelectorCount(const RawServoStyleRule* rule,
                                       uint32_t* count);
 
 bool Servo_StyleRule_SelectorMatchesElement(
-    RawServoStyleRuleBorrowed, RawGeckoElementBorrowed, uint32_t index,
+    const RawServoStyleRule*, const mozilla::dom::Element*, uint32_t index,
     mozilla::PseudoStyleType pseudo_type);
 
-bool Servo_StyleRule_SetSelectorText(RawServoStyleSheetContentsBorrowed sheet,
-                                     RawServoStyleRuleBorrowed rule,
+bool Servo_StyleRule_SetSelectorText(const RawServoStyleSheetContents* sheet,
+                                     const RawServoStyleRule* rule,
                                      const nsAString* text);
 
-void Servo_ImportRule_GetHref(RawServoImportRuleBorrowed rule,
+void Servo_ImportRule_GetHref(const RawServoImportRule* rule,
                               nsAString* result);
 
 const mozilla::StyleSheet* Servo_ImportRule_GetSheet(
-    RawServoImportRuleBorrowed rule);
+    const RawServoImportRule* rule);
 
-void Servo_ImportRule_SetSheet(RawServoImportRuleBorrowed rule,
+void Servo_ImportRule_SetSheet(const RawServoImportRule* rule,
                                mozilla::StyleSheet* sheet);
 
-void Servo_Keyframe_GetKeyText(RawServoKeyframeBorrowed keyframe,
+void Servo_Keyframe_GetKeyText(const RawServoKeyframe* keyframe,
                                nsAString* result);
 
 // Returns whether it successfully changes the key text.
-bool Servo_Keyframe_SetKeyText(RawServoKeyframeBorrowed keyframe,
+bool Servo_Keyframe_SetKeyText(const RawServoKeyframe* keyframe,
                                const nsACString* text);
 
 RawServoDeclarationBlockStrong Servo_Keyframe_GetStyle(
-    RawServoKeyframeBorrowed keyframe);
+    const RawServoKeyframe* keyframe);
 
-void Servo_Keyframe_SetStyle(RawServoKeyframeBorrowed keyframe,
-                             RawServoDeclarationBlockBorrowed declarations);
+void Servo_Keyframe_SetStyle(const RawServoKeyframe* keyframe,
+                             const RawServoDeclarationBlock* declarations);
 
-nsAtom* Servo_KeyframesRule_GetName(RawServoKeyframesRuleBorrowed rule);
+nsAtom* Servo_KeyframesRule_GetName(const RawServoKeyframesRule* rule);
 
 // This method takes an addrefed nsAtom.
-void Servo_KeyframesRule_SetName(RawServoKeyframesRuleBorrowed rule,
+void Servo_KeyframesRule_SetName(const RawServoKeyframesRule* rule,
                                  nsAtom* name);
 
-uint32_t Servo_KeyframesRule_GetCount(RawServoKeyframesRuleBorrowed rule);
+uint32_t Servo_KeyframesRule_GetCount(const RawServoKeyframesRule* rule);
 
 RawServoKeyframeStrong Servo_KeyframesRule_GetKeyframeAt(
-    RawServoKeyframesRuleBorrowed rule, uint32_t index, uint32_t* line,
+    const RawServoKeyframesRule* rule, uint32_t index, uint32_t* line,
     uint32_t* column);
 
 // Returns the index of the rule, max value of uint32_t if nothing found.
-uint32_t Servo_KeyframesRule_FindRule(RawServoKeyframesRuleBorrowed rule,
+uint32_t Servo_KeyframesRule_FindRule(const RawServoKeyframesRule* rule,
                                       const nsACString* key);
 
 // Returns whether it successfully appends the rule.
-bool Servo_KeyframesRule_AppendRule(RawServoKeyframesRuleBorrowed rule,
-                                    RawServoStyleSheetContentsBorrowed sheet,
+bool Servo_KeyframesRule_AppendRule(const RawServoKeyframesRule* rule,
+                                    const RawServoStyleSheetContents* sheet,
                                     const nsACString* css);
 
-void Servo_KeyframesRule_DeleteRule(RawServoKeyframesRuleBorrowed rule,
+void Servo_KeyframesRule_DeleteRule(const RawServoKeyframesRule* rule,
                                     uint32_t index);
 
-RawServoMediaListStrong Servo_MediaRule_GetMedia(
-    RawServoMediaRuleBorrowed rule);
+RawServoMediaListStrong Servo_MediaRule_GetMedia(const RawServoMediaRule* rule);
 
-nsAtom* Servo_NamespaceRule_GetPrefix(RawServoNamespaceRuleBorrowed rule);
-nsAtom* Servo_NamespaceRule_GetURI(RawServoNamespaceRuleBorrowed rule);
+nsAtom* Servo_NamespaceRule_GetPrefix(const RawServoNamespaceRule* rule);
+nsAtom* Servo_NamespaceRule_GetURI(const RawServoNamespaceRule* rule);
 
 RawServoDeclarationBlockStrong Servo_PageRule_GetStyle(
-    RawServoPageRuleBorrowed rule);
+    const RawServoPageRule* rule);
 
-void Servo_PageRule_SetStyle(RawServoPageRuleBorrowed rule,
-                             RawServoDeclarationBlockBorrowed declarations);
+void Servo_PageRule_SetStyle(const RawServoPageRule* rule,
+                             const RawServoDeclarationBlock* declarations);
 
-void Servo_SupportsRule_GetConditionText(RawServoSupportsRuleBorrowed rule,
+void Servo_SupportsRule_GetConditionText(const RawServoSupportsRule* rule,
                                          nsAString* result);
 
-void Servo_MozDocumentRule_GetConditionText(
-    RawServoMozDocumentRuleBorrowed rule, nsAString* result);
+void Servo_MozDocumentRule_GetConditionText(const RawServoMozDocumentRule* rule,
+                                            nsAString* result);
 
 void Servo_FontFeatureValuesRule_GetFontFamily(
-    RawServoFontFeatureValuesRuleBorrowed rule, nsAString* result);
+    const RawServoFontFeatureValuesRule* rule, nsAString* result);
 
 void Servo_FontFeatureValuesRule_GetValueText(
-    RawServoFontFeatureValuesRuleBorrowed rule, nsAString* result);
+    const RawServoFontFeatureValuesRule* rule, nsAString* result);
 
 RawServoFontFaceRuleStrong Servo_FontFaceRule_CreateEmpty();
 
 RawServoFontFaceRuleStrong Servo_FontFaceRule_Clone(
-    RawServoFontFaceRuleBorrowed rule);
+    const RawServoFontFaceRule* rule);
 
-void Servo_FontFaceRule_GetSourceLocation(RawServoFontFaceRuleBorrowed rule,
+void Servo_FontFaceRule_GetSourceLocation(const RawServoFontFaceRule* rule,
                                           uint32_t* line, uint32_t* column);
 
-uint32_t Servo_FontFaceRule_Length(RawServoFontFaceRuleBorrowed rule);
+uint32_t Servo_FontFaceRule_Length(const RawServoFontFaceRule* rule);
 
-nsCSSFontDesc Servo_FontFaceRule_IndexGetter(RawServoFontFaceRuleBorrowed rule,
+nsCSSFontDesc Servo_FontFaceRule_IndexGetter(const RawServoFontFaceRule* rule,
                                              uint32_t index);
 
-void Servo_FontFaceRule_GetDeclCssText(RawServoFontFaceRuleBorrowed rule,
+void Servo_FontFaceRule_GetDeclCssText(const RawServoFontFaceRule* rule,
                                        nsAString* result);
 
 bool Servo_FontFaceRule_GetFontWeight(
-    RawServoFontFaceRuleBorrowed rule,
+    const RawServoFontFaceRule* rule,
     mozilla::StyleComputedFontWeightRange* out);
 
-bool Servo_FontFaceRule_GetFontDisplay(RawServoFontFaceRuleBorrowed rule,
+bool Servo_FontFaceRule_GetFontDisplay(const RawServoFontFaceRule* rule,
                                        mozilla::StyleFontDisplay* out);
 
 bool Servo_FontFaceRule_GetFontStyle(
-    RawServoFontFaceRuleBorrowed rule,
+    const RawServoFontFaceRule* rule,
     mozilla::StyleComputedFontStyleDescriptor* out);
 
 bool Servo_FontFaceRule_GetFontStretch(
-    RawServoFontFaceRuleBorrowed rule,
+    const RawServoFontFaceRule* rule,
     mozilla::StyleComputedFontStretchRange* out);
 
 bool Servo_FontFaceRule_GetFontLanguageOverride(
-    RawServoFontFaceRuleBorrowed rule, mozilla::StyleFontLanguageOverride* out);
+    const RawServoFontFaceRule* rule, mozilla::StyleFontLanguageOverride* out);
 
-nsAtom* Servo_FontFaceRule_GetFamilyName(RawServoFontFaceRuleBorrowed rule);
+nsAtom* Servo_FontFaceRule_GetFamilyName(const RawServoFontFaceRule* rule);
 
 const mozilla::StyleUnicodeRange* Servo_FontFaceRule_GetUnicodeRanges(
-    RawServoFontFaceRuleBorrowed rule, size_t* out_len);
+    const RawServoFontFaceRule* rule, size_t* out_len);
 
 void Servo_FontFaceRule_GetSources(
-    RawServoFontFaceRuleBorrowed rule,
+    const RawServoFontFaceRule* rule,
     nsTArray<mozilla::StyleFontFaceSourceListComponent>* components);
 
 void Servo_FontFaceRule_GetVariationSettings(
-    RawServoFontFaceRuleBorrowed rule,
+    const RawServoFontFaceRule* rule,
     nsTArray<mozilla::gfx::FontVariation>* out);
 
-void Servo_FontFaceRule_GetFeatureSettings(RawServoFontFaceRuleBorrowed rule,
+void Servo_FontFaceRule_GetFeatureSettings(const RawServoFontFaceRule* rule,
                                            nsTArray<gfxFontFeature>* out);
 
-void Servo_FontFaceRule_GetDescriptorCssText(RawServoFontFaceRuleBorrowed rule,
+void Servo_FontFaceRule_GetDescriptorCssText(const RawServoFontFaceRule* rule,
                                              nsCSSFontDesc desc,
                                              nsAString* result);
 
-bool Servo_FontFaceRule_SetDescriptor(RawServoFontFaceRuleBorrowed rule,
+bool Servo_FontFaceRule_SetDescriptor(const RawServoFontFaceRule* rule,
                                       nsCSSFontDesc desc,
                                       const nsACString* value,
-                                      RawGeckoURLExtraData* data);
+                                      mozilla::URLExtraData* data);
 
-void Servo_FontFaceRule_ResetDescriptor(RawServoFontFaceRuleBorrowed rule,
+void Servo_FontFaceRule_ResetDescriptor(const RawServoFontFaceRule* rule,
                                         nsCSSFontDesc desc);
 
-nsAtom* Servo_CounterStyleRule_GetName(RawServoCounterStyleRuleBorrowed rule);
+nsAtom* Servo_CounterStyleRule_GetName(const RawServoCounterStyleRule* rule);
 
-bool Servo_CounterStyleRule_SetName(RawServoCounterStyleRuleBorrowed rule,
+bool Servo_CounterStyleRule_SetName(const RawServoCounterStyleRule* rule,
                                     const nsACString* name);
 
 uint32_t Servo_CounterStyleRule_GetGeneration(
-    RawServoCounterStyleRuleBorrowed rule);
+    const RawServoCounterStyleRule* rule);
 
-uint8_t Servo_CounterStyleRule_GetSystem(RawServoCounterStyleRuleBorrowed rule);
+uint8_t Servo_CounterStyleRule_GetSystem(const RawServoCounterStyleRule* rule);
 
 nsAtom* Servo_CounterStyleRule_GetExtended(
-    RawServoCounterStyleRuleBorrowed rule);
+    const RawServoCounterStyleRule* rule);
 
 int32_t Servo_CounterStyleRule_GetFixedFirstValue(
-    RawServoCounterStyleRuleBorrowed rule);
+    const RawServoCounterStyleRule* rule);
 
 nsAtom* Servo_CounterStyleRule_GetFallback(
-    RawServoCounterStyleRuleBorrowed rule);
+    const RawServoCounterStyleRule* rule);
 
-void Servo_CounterStyleRule_GetDescriptor(RawServoCounterStyleRuleBorrowed rule,
+void Servo_CounterStyleRule_GetDescriptor(const RawServoCounterStyleRule* rule,
                                           nsCSSCounterDesc desc,
-                                          nsCSSValueBorrowedMut result);
+                                          nsCSSValue* result);
 
 void Servo_CounterStyleRule_GetDescriptorCssText(
-    RawServoCounterStyleRuleBorrowed rule, nsCSSCounterDesc desc,
+    const RawServoCounterStyleRule* rule, nsCSSCounterDesc desc,
     nsAString* result);
 
-bool Servo_CounterStyleRule_SetDescriptor(RawServoCounterStyleRuleBorrowed rule,
+bool Servo_CounterStyleRule_SetDescriptor(const RawServoCounterStyleRule* rule,
                                           nsCSSCounterDesc desc,
                                           const nsACString* value);
 
 // Animations API
 
 RawServoDeclarationBlockStrong Servo_ParseProperty(
     nsCSSPropertyID property, const nsACString* value,
-    RawGeckoURLExtraData* data, mozilla::ParsingMode parsing_mode,
+    mozilla::URLExtraData* data, mozilla::ParsingMode parsing_mode,
     nsCompatibility quirks_mode, mozilla::css::Loader* loader);
 
-bool Servo_ParseEasing(const nsAString* easing, RawGeckoURLExtraData* data,
-                       nsTimingFunctionBorrowedMut output);
+bool Servo_ParseEasing(const nsAString* easing, mozilla::URLExtraData* data,
+                       nsTimingFunction* output);
 
-void Servo_SerializeEasing(nsTimingFunctionBorrowed easing, nsAString* output);
+void Servo_SerializeEasing(const nsTimingFunction* easing, nsAString* output);
 
 void Servo_SerializeBorderRadius(const mozilla::StyleBorderRadius*, nsAString*);
 
 void Servo_GetComputedKeyframeValues(
-    RawGeckoKeyframeListBorrowed keyframes, RawGeckoElementBorrowed element,
-    ComputedStyleBorrowed style, RawServoStyleSetBorrowed set,
-    RawGeckoComputedKeyframeValuesListBorrowedMut result);
+    const nsTArray<mozilla::Keyframe>* keyframes,
+    const mozilla::dom::Element* element, const mozilla::ComputedStyle* style,
+    const RawServoStyleSet* set,
+    nsTArray<mozilla::ComputedKeyframeValues>* result);
 
 RawServoAnimationValueStrong Servo_ComputedValues_ExtractAnimationValue(
-    ComputedStyleBorrowed computed_values, nsCSSPropertyID property);
+    const mozilla::ComputedStyle* computed_values, nsCSSPropertyID property);
 
 bool Servo_ComputedValues_SpecifiesAnimationsOrTransitions(
-    ComputedStyleBorrowed computed_values);
+    const mozilla::ComputedStyle* computed_values);
 
 bool Servo_Property_IsAnimatable(nsCSSPropertyID property);
 bool Servo_Property_IsTransitionable(nsCSSPropertyID property);
 bool Servo_Property_IsDiscreteAnimatable(nsCSSPropertyID property);
 
-void Servo_GetProperties_Overriding_Animation(RawGeckoElementBorrowed,
-                                              RawGeckoCSSPropertyIDListBorrowed,
-                                              nsCSSPropertyIDSetBorrowedMut);
+void Servo_GetProperties_Overriding_Animation(const mozilla::dom::Element*,
+                                              const nsTArray<nsCSSPropertyID>*,
+                                              nsCSSPropertyIDSet*);
 
 void Servo_MatrixTransform_Operate(
     nsStyleTransformMatrix::MatrixTransformOperator matrix_operator,
-    const RawGeckoGfxMatrix4x4* from, const RawGeckoGfxMatrix4x4* to,
-    double progress, RawGeckoGfxMatrix4x4* result);
+    const Matrix4x4Components* from, const Matrix4x4Components* to,
+    double progress, Matrix4x4Components* result);
 
 void Servo_GetAnimationValues(
-    RawServoDeclarationBlockBorrowed declarations,
-    RawGeckoElementBorrowed element, ComputedStyleBorrowed style,
-    RawServoStyleSetBorrowed style_set,
-    RawGeckoServoAnimationValueListBorrowedMut animation_values);
+    const RawServoDeclarationBlock* declarations,
+    const mozilla::dom::Element* element, const mozilla::ComputedStyle* style,
+    const RawServoStyleSet* style_set,
+    nsTArray<RefPtr<RawServoAnimationValue>>* animation_values);
 
 // AnimationValues handling
 
 RawServoAnimationValueStrong Servo_AnimationValues_Interpolate(
-    RawServoAnimationValueBorrowed from, RawServoAnimationValueBorrowed to,
+    const RawServoAnimationValue* from, const RawServoAnimationValue* to,
     double progress);
 
-bool Servo_AnimationValues_IsInterpolable(RawServoAnimationValueBorrowed from,
-                                          RawServoAnimationValueBorrowed to);
+bool Servo_AnimationValues_IsInterpolable(const RawServoAnimationValue* from,
+                                          const RawServoAnimationValue* to);
 
 RawServoAnimationValueStrong Servo_AnimationValues_Add(
-    RawServoAnimationValueBorrowed a, RawServoAnimationValueBorrowed b);
+    const RawServoAnimationValue* a, const RawServoAnimationValue* b);
 
 RawServoAnimationValueStrong Servo_AnimationValues_Accumulate(
-    RawServoAnimationValueBorrowed a, RawServoAnimationValueBorrowed b,
+    const RawServoAnimationValue* a, const RawServoAnimationValue* b,
     uint64_t count);
 
 RawServoAnimationValueStrong Servo_AnimationValues_GetZeroValue(
-    RawServoAnimationValueBorrowed value_to_match);
+    const RawServoAnimationValue* value_to_match);
 
-double Servo_AnimationValues_ComputeDistance(
-    RawServoAnimationValueBorrowed from, RawServoAnimationValueBorrowed to);
+double Servo_AnimationValues_ComputeDistance(const RawServoAnimationValue* from,
+                                             const RawServoAnimationValue* to);
 
-void Servo_AnimationValue_Serialize(RawServoAnimationValueBorrowed value,
+void Servo_AnimationValue_Serialize(const RawServoAnimationValue* value,
                                     nsCSSPropertyID property,
                                     nsAString* buffer);
 
-nscolor Servo_AnimationValue_GetColor(RawServoAnimationValueBorrowed value,
+nscolor Servo_AnimationValue_GetColor(const RawServoAnimationValue* value,
                                       nscolor foregroundColor);
 RawServoAnimationValueStrong Servo_AnimationValue_Color(nsCSSPropertyID,
                                                         nscolor);
 
-float Servo_AnimationValue_GetOpacity(RawServoAnimationValueBorrowed value);
+float Servo_AnimationValue_GetOpacity(const RawServoAnimationValue* value);
 RawServoAnimationValueStrong Servo_AnimationValue_Opacity(float);
 
 nsCSSPropertyID Servo_AnimationValue_GetTransform(
-    RawServoAnimationValueBorrowed value, RefPtr<nsCSSValueSharedList>* list);
+    const RawServoAnimationValue* value, RefPtr<nsCSSValueSharedList>* list);
 
 RawServoAnimationValueStrong Servo_AnimationValue_Transform(
     nsCSSPropertyID property, const nsCSSValueSharedList& list);
 
-bool Servo_AnimationValue_DeepEqual(RawServoAnimationValueBorrowed,
-                                    RawServoAnimationValueBorrowed);
+bool Servo_AnimationValue_DeepEqual(const RawServoAnimationValue*,
+                                    const RawServoAnimationValue*);
 
 RawServoDeclarationBlockStrong Servo_AnimationValue_Uncompute(
-    RawServoAnimationValueBorrowed value);
+    const RawServoAnimationValue* value);
 
 RawServoAnimationValueStrong Servo_AnimationValue_Compute(
-    RawGeckoElementBorrowed element,
-    RawServoDeclarationBlockBorrowed declarations, ComputedStyleBorrowed style,
-    RawServoStyleSetBorrowed raw_data);
+    const mozilla::dom::Element* element,
+    const RawServoDeclarationBlock* declarations,
+    const mozilla::ComputedStyle* style, const RawServoStyleSet* raw_data);
 
 // Style attribute
 
 RawServoDeclarationBlockStrong Servo_ParseStyleAttribute(
-    const nsACString* data, RawGeckoURLExtraData* extra_data,
+    const nsACString* data, mozilla::URLExtraData* extra_data,
     nsCompatibility quirks_mode, mozilla::css::Loader* loader);
 
 RawServoDeclarationBlockStrong Servo_DeclarationBlock_CreateEmpty();
 
 RawServoDeclarationBlockStrong Servo_DeclarationBlock_Clone(
-    RawServoDeclarationBlockBorrowed declarations);
+    const RawServoDeclarationBlock* declarations);
 
-bool Servo_DeclarationBlock_Equals(RawServoDeclarationBlockBorrowed a,
-                                   RawServoDeclarationBlockBorrowed b);
+bool Servo_DeclarationBlock_Equals(const RawServoDeclarationBlock* a,
+                                   const RawServoDeclarationBlock* b);
 
 void Servo_DeclarationBlock_GetCssText(
-    RawServoDeclarationBlockBorrowed declarations, nsAString* result);
+    const RawServoDeclarationBlock* declarations, nsAString* result);
 
 void Servo_DeclarationBlock_SerializeOneValue(
-    RawServoDeclarationBlockBorrowed declarations, nsCSSPropertyID property,
-    nsAString* buffer, ComputedStyleBorrowedOrNull computed_values,
-    RawServoDeclarationBlockBorrowedOrNull custom_properties);
+    const RawServoDeclarationBlock* declarations, nsCSSPropertyID property,
+    nsAString* buffer, const mozilla::ComputedStyle* computed_values,
+    const RawServoDeclarationBlock* custom_properties);
 
 uint32_t Servo_DeclarationBlock_Count(
-    RawServoDeclarationBlockBorrowed declarations);
+    const RawServoDeclarationBlock* declarations);
 
 bool Servo_DeclarationBlock_GetNthProperty(
-    RawServoDeclarationBlockBorrowed declarations, uint32_t index,
+    const RawServoDeclarationBlock* declarations, uint32_t index,
     nsAString* result);
 
 void Servo_DeclarationBlock_GetPropertyValue(
-    RawServoDeclarationBlockBorrowed declarations, const nsACString* property,
+    const RawServoDeclarationBlock* declarations, const nsACString* property,
     nsAString* value);
 
 void Servo_DeclarationBlock_GetPropertyValueById(
-    RawServoDeclarationBlockBorrowed declarations, nsCSSPropertyID property,
+    const RawServoDeclarationBlock* declarations, nsCSSPropertyID property,
     nsAString* value);
 
 bool Servo_DeclarationBlock_GetPropertyIsImportant(
-    RawServoDeclarationBlockBorrowed declarations, const nsACString* property);
+    const RawServoDeclarationBlock* declarations, const nsACString* property);
 
 bool Servo_DeclarationBlock_SetProperty(
-    RawServoDeclarationBlockBorrowed declarations, const nsACString* property,
-    const nsACString* value, bool is_important, RawGeckoURLExtraData* data,
+    const RawServoDeclarationBlock* declarations, const nsACString* property,
+    const nsACString* value, bool is_important, mozilla::URLExtraData* data,
     mozilla::ParsingMode parsing_mode, nsCompatibility quirks_mode,
     mozilla::css::Loader* loader, mozilla::DeclarationBlockMutationClosure);
 
 bool Servo_DeclarationBlock_SetPropertyToAnimationValue(
-    RawServoDeclarationBlockBorrowed declarations,
-    RawServoAnimationValueBorrowed animation_value);
+    const RawServoDeclarationBlock* declarations,
+    const RawServoAnimationValue* animation_value);
 
 bool Servo_DeclarationBlock_SetPropertyById(
-    RawServoDeclarationBlockBorrowed declarations, nsCSSPropertyID property,
-    const nsACString* value, bool is_important, RawGeckoURLExtraData* data,
+    const RawServoDeclarationBlock* declarations, nsCSSPropertyID property,
+    const nsACString* value, bool is_important, mozilla::URLExtraData* data,
     mozilla::ParsingMode parsing_mode, nsCompatibility quirks_mode,
     mozilla::css::Loader* loader, mozilla::DeclarationBlockMutationClosure);
 
 bool Servo_DeclarationBlock_RemoveProperty(
-    RawServoDeclarationBlockBorrowed declarations, const nsACString* property,
+    const RawServoDeclarationBlock* declarations, const nsACString* property,
     mozilla::DeclarationBlockMutationClosure);
 
 bool Servo_DeclarationBlock_RemovePropertyById(
-    RawServoDeclarationBlockBorrowed declarations, nsCSSPropertyID property,
+    const RawServoDeclarationBlock* declarations, nsCSSPropertyID property,
     mozilla::DeclarationBlockMutationClosure);
 
 bool Servo_DeclarationBlock_HasCSSWideKeyword(
-    RawServoDeclarationBlockBorrowed declarations, nsCSSPropertyID property);
+    const RawServoDeclarationBlock* declarations, nsCSSPropertyID property);
 
 // Compose animation value for a given property.
 // |base_values| is nsRefPtrHashtable<nsUint32HashKey, RawServoAnimationValue>.
-// We use RawServoAnimationValueTableBorrowed to avoid exposing
+// We use const RawServoAnimationValueTable* to avoid exposing
 // nsRefPtrHashtable in FFI.
 void Servo_AnimationCompose(
-    RawServoAnimationValueMapBorrowedMut animation_values,
-    RawServoAnimationValueTableBorrowed base_values, nsCSSPropertyID property,
-    RawGeckoAnimationPropertySegmentBorrowed animation_segment,
-    RawGeckoAnimationPropertySegmentBorrowed last_segment,
-    RawGeckoComputedTimingBorrowed computed_timing,
+    RawServoAnimationValueMap* animation_values,
+    const RawServoAnimationValueTable* base_values, nsCSSPropertyID property,
+    const mozilla::AnimationPropertySegment* animation_segment,
+    const mozilla::AnimationPropertySegment* last_segment,
+    const mozilla::ComputedTiming* computed_timing,
     mozilla::dom::IterationCompositeOperation iter_composite);
 
 // Calculate the result of interpolating given animation segment at the given
 // progress and current iteration.
 // This includes combining the segment endpoints with the underlying value
 // and/or last value depending the composite modes specified on the
 // segment endpoints and the supplied iteration composite mode.
 // The caller is responsible for providing an underlying value and
 // last value in all situations where there are needed.
 RawServoAnimationValueStrong Servo_ComposeAnimationSegment(
-    RawGeckoAnimationPropertySegmentBorrowed animation_segment,
-    RawServoAnimationValueBorrowedOrNull underlying_value,
-    RawServoAnimationValueBorrowedOrNull last_value,
+    const mozilla::AnimationPropertySegment* animation_segment,
+    const RawServoAnimationValue* underlying_value,
+    const RawServoAnimationValue* last_value,
     mozilla::dom::IterationCompositeOperation iter_composite, double progress,
     uint64_t current_iteration);
 
 // presentation attributes
 
 bool Servo_DeclarationBlock_PropertyIsSet(
-    RawServoDeclarationBlockBorrowed declarations, nsCSSPropertyID property);
+    const RawServoDeclarationBlock* declarations, nsCSSPropertyID property);
 
 void Servo_DeclarationBlock_SetIdentStringValue(
-    RawServoDeclarationBlockBorrowed declarations, nsCSSPropertyID property,
+    const RawServoDeclarationBlock* declarations, nsCSSPropertyID property,
     nsAtom* value);
 
 void Servo_DeclarationBlock_SetKeywordValue(
-    RawServoDeclarationBlockBorrowed declarations, nsCSSPropertyID property,
+    const RawServoDeclarationBlock* declarations, nsCSSPropertyID property,
     int32_t value);
 
 void Servo_DeclarationBlock_SetIntValue(
-    RawServoDeclarationBlockBorrowed declarations, nsCSSPropertyID property,
+    const RawServoDeclarationBlock* declarations, nsCSSPropertyID property,
     int32_t value);
 
 void Servo_DeclarationBlock_SetPixelValue(
-    RawServoDeclarationBlockBorrowed declarations, nsCSSPropertyID property,
+    const RawServoDeclarationBlock* declarations, nsCSSPropertyID property,
     float value);
 
 void Servo_DeclarationBlock_SetLengthValue(
-    RawServoDeclarationBlockBorrowed declarations, nsCSSPropertyID property,
+    const RawServoDeclarationBlock* declarations, nsCSSPropertyID property,
     float value, nsCSSUnit unit);
 
 void Servo_DeclarationBlock_SetNumberValue(
-    RawServoDeclarationBlockBorrowed declarations, nsCSSPropertyID property,
+    const RawServoDeclarationBlock* declarations, nsCSSPropertyID property,
     float value);
 
 void Servo_DeclarationBlock_SetPercentValue(
-    RawServoDeclarationBlockBorrowed declarations, nsCSSPropertyID property,
+    const RawServoDeclarationBlock* declarations, nsCSSPropertyID property,
     float value);
 
 void Servo_DeclarationBlock_SetAutoValue(
-    RawServoDeclarationBlockBorrowed declarations, nsCSSPropertyID property);
+    const RawServoDeclarationBlock* declarations, nsCSSPropertyID property);
 
 void Servo_DeclarationBlock_SetCurrentColor(
-    RawServoDeclarationBlockBorrowed declarations, nsCSSPropertyID property);
+    const RawServoDeclarationBlock* declarations, nsCSSPropertyID property);
 
 void Servo_DeclarationBlock_SetColorValue(
-    RawServoDeclarationBlockBorrowed declarations, nsCSSPropertyID property,
+    const RawServoDeclarationBlock* declarations, nsCSSPropertyID property,
     nscolor value);
 
 void Servo_DeclarationBlock_SetFontFamily(
-    RawServoDeclarationBlockBorrowed declarations, const nsAString& value);
+    const RawServoDeclarationBlock* declarations, const nsAString& value);
 
 void Servo_DeclarationBlock_SetTextDecorationColorOverride(
-    RawServoDeclarationBlockBorrowed declarations);
+    const RawServoDeclarationBlock* declarations);
 
 void Servo_DeclarationBlock_SetBackgroundImage(
-    RawServoDeclarationBlockBorrowed declarations, const nsAString& value,
-    RawGeckoURLExtraData* extra_data);
+    const RawServoDeclarationBlock* declarations, const nsAString& value,
+    mozilla::URLExtraData* extra_data);
 
 // MediaList
 
 RawServoMediaListStrong Servo_MediaList_Create();
 
 RawServoMediaListStrong Servo_MediaList_DeepClone(
-    RawServoMediaListBorrowed list);
+    const RawServoMediaList* list);
 
-bool Servo_MediaList_Matches(RawServoMediaListBorrowed list,
-                             RawServoStyleSetBorrowed set);
+bool Servo_MediaList_Matches(const RawServoMediaList* list,
+                             const RawServoStyleSet* set);
 
-void Servo_MediaList_GetText(RawServoMediaListBorrowed list, nsAString* result);
+void Servo_MediaList_GetText(const RawServoMediaList* list, nsAString* result);
 
-void Servo_MediaList_SetText(RawServoMediaListBorrowed list,
+void Servo_MediaList_SetText(const RawServoMediaList* list,
                              const nsACString* text,
                              mozilla::dom::CallerType aCallerType);
 
-uint32_t Servo_MediaList_GetLength(RawServoMediaListBorrowed list);
+uint32_t Servo_MediaList_GetLength(const RawServoMediaList* list);
 
-bool Servo_MediaList_GetMediumAt(RawServoMediaListBorrowed list, uint32_t index,
+bool Servo_MediaList_GetMediumAt(const RawServoMediaList* list, uint32_t index,
                                  nsAString* result);
 
-void Servo_MediaList_AppendMedium(RawServoMediaListBorrowed list,
+void Servo_MediaList_AppendMedium(const RawServoMediaList* list,
                                   const nsACString* new_medium);
 
-bool Servo_MediaList_DeleteMedium(RawServoMediaListBorrowed list,
+bool Servo_MediaList_DeleteMedium(const RawServoMediaList* list,
                                   const nsACString* old_medium);
 
 size_t Servo_MediaList_SizeOfIncludingThis(
     mozilla::MallocSizeOf malloc_size_of,
     mozilla::MallocSizeOf malloc_enclosing_size_of,
-    RawServoMediaListBorrowed list);
+    const RawServoMediaList* list);
 
 // CSS supports();
 
 bool Servo_CSSSupports2(const nsACString* name, const nsACString* value);
 bool Servo_CSSSupports(const nsACString* cond);
 
 // Computed style data
 
 ComputedStyleStrong Servo_ComputedValues_GetForAnonymousBox(
-    ComputedStyleBorrowedOrNull parent_style_or_null, mozilla::PseudoStyleType,
-    RawServoStyleSetBorrowed set);
+    const mozilla::ComputedStyle* parent_style_or_null,
+    mozilla::PseudoStyleType, const RawServoStyleSet* set);
 
 ComputedStyleStrong Servo_ComputedValues_Inherit(
-    RawServoStyleSetBorrowed, mozilla::PseudoStyleType,
-    ComputedStyleBorrowedOrNull parent_style, mozilla::InheritTarget);
-
-bool Servo_ComputedValues_EqualCustomProperties(
-    ServoComputedDataBorrowed first, ServoComputedDataBorrowed second);
+    const RawServoStyleSet*, mozilla::PseudoStyleType,
+    const mozilla::ComputedStyle* parent_style, mozilla::InheritTarget);
 
 // Gets the source style rules for the computed values. This returns
 // the result via rules, which would include a list of unowned pointers
 // to RawServoStyleRule.
 void Servo_ComputedValues_GetStyleRuleList(
-    ComputedStyleBorrowed values, RawGeckoServoStyleRuleListBorrowedMut rules);
+    const mozilla::ComputedStyle* values,
+    nsTArray<const RawServoStyleRule*>* rules);
 
 // Initialize Servo components. Should be called exactly once at startup.
-void Servo_Initialize(RawGeckoURLExtraData* dummy_url_data);
+void Servo_Initialize(mozilla::URLExtraData* dummy_url_data);
 
 // Initialize Servo on a cooperative Quantum DOM thread.
 void Servo_InitializeCooperativeThread();
 
 // Shut down Servo components. Should be called exactly once at shutdown.
 void Servo_Shutdown();
 
 // Restyle and change hints.
-void Servo_NoteExplicitHints(RawGeckoElementBorrowed, mozilla::RestyleHint,
+void Servo_NoteExplicitHints(const mozilla::dom::Element*, mozilla::RestyleHint,
                              nsChangeHint);
 
 // We'd like to return `nsChangeHint` here, but bindgen bitfield enums don't
 // work as return values with the Linux 32-bit ABI at the moment because
 // they wrap the value in a struct.
-uint32_t Servo_TakeChangeHint(RawGeckoElementBorrowed element,
+uint32_t Servo_TakeChangeHint(const mozilla::dom::Element* element,
                               bool* was_restyled);
 
-ComputedStyleStrong Servo_ResolveStyle(RawGeckoElementBorrowed element,
-                                       RawServoStyleSetBorrowed set);
+ComputedStyleStrong Servo_ResolveStyle(const mozilla::dom::Element* element,
+                                       const RawServoStyleSet* set);
 
 ComputedStyleStrong Servo_ResolvePseudoStyle(
-    RawGeckoElementBorrowed element, mozilla::PseudoStyleType pseudo_type,
-    bool is_probe, ComputedStyleBorrowedOrNull inherited_style,
-    RawServoStyleSetBorrowed set);
+    const mozilla::dom::Element* element, mozilla::PseudoStyleType pseudo_type,
+    bool is_probe, const mozilla::ComputedStyle* inherited_style,