Merge autoland to mozilla-central. a=merge
authorDaniel Varga <dvarga@mozilla.com>
Wed, 10 Oct 2018 13:52:23 +0300
changeset 498870 91b4c3687d7563244fbba0f58075779eb89259fb
parent 498855 2d2dee08739f0293e1ac9e815a9acb80621c3bc4 (current diff)
parent 498869 c9d9dd203994cd2251869d7b470564281d5d995f (diff)
child 498871 8dfeff72def34dea3ee1a59185a73d2840ae77f3
child 498882 08d597127e937fbcb9f2929c6cd772ed93bfd7d9
child 498958 857fb59a720e8f04e5d4f6ba60d4c9428f459751
push id1864
push userffxbld-merge
push dateMon, 03 Dec 2018 15:51:40 +0000
treeherdermozilla-release@f040763d99ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone64.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
--- a/browser/actors/WebRTCChild.jsm
+++ b/browser/actors/WebRTCChild.jsm
@@ -235,17 +235,23 @@ function prompt(aContentWindow, aWindowI
     videoDevices,
   };
 
   let mm = getMessageManagerForWindow(aContentWindow);
   mm.sendAsyncMessage("webrtc:Request", request);
 }
 
 function denyGUMRequest(aData) {
-  Services.obs.notifyObservers(null, "getUserMedia:response:deny", aData.callID);
+  let subject;
+  if (aData.noOSPermission) {
+    subject = "getUserMedia:response:noOSPermission";
+  } else {
+    subject = "getUserMedia:response:deny";
+  }
+  Services.obs.notifyObservers(null, subject, aData.callID);
 
   if (!aData.windowID)
     return;
   let contentWindow = Services.wm.getOuterWindowWithId(aData.windowID);
   if (contentWindow.pendingGetUserMediaRequests)
     forgetGUMRequest(contentWindow, aData.callID);
 }
 
--- a/browser/base/content/test/urlbar/browser.ini
+++ b/browser/base/content/test/urlbar/browser.ini
@@ -94,16 +94,20 @@ skip-if = os == "linux" # Bug 1073339 - 
 [browser_urlbarOneOffs.js]
 support-files =
   searchSuggestionEngine.xml
   searchSuggestionEngine.sjs
 [browser_urlbarOneOffs_searchSuggestions.js]
 support-files =
   searchSuggestionEngine.xml
   searchSuggestionEngine.sjs
+[browser_urlbarOneOffs_settings.js]
+support-files =
+  searchSuggestionEngine.xml
+  searchSuggestionEngine.sjs
 [browser_urlbarPlaceholder.js]
 support-files =
   searchSuggestionEngine.xml
   searchSuggestionEngine.sjs
 [browser_urlbarPrivateBrowsingWindowChange.js]
 [browser_urlbarRaceWithTabs.js]
 [browser_urlbarRevert.js]
 [browser_urlbarSearchFunction.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbarOneOffs_settings.js
@@ -0,0 +1,78 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";
+
+let gMaxResults;
+
+add_task(async function init() {
+  Services.prefs.setBoolPref("browser.urlbar.oneOffSearches", true);
+  gMaxResults = Services.prefs.getIntPref("browser.urlbar.maxRichResults");
+
+  // Add a search suggestion engine and move it to the front so that it appears
+  // as the first one-off.
+  let engine = await SearchTestUtils.promiseNewSearchEngine(
+    getRootDirectory(gTestPath) + TEST_ENGINE_BASENAME);
+  Services.search.moveEngine(engine, 0);
+
+  registerCleanupFunction(async function() {
+    await hidePopup();
+    await PlacesUtils.history.clear();
+  });
+
+  await PlacesUtils.history.clear();
+
+  let visits = [];
+  for (let i = 0; i < gMaxResults; i++) {
+    visits.push({
+      uri: makeURI("http://example.com/browser_urlbarOneOffs.js/?" + i),
+      // TYPED so that the visit shows up when the urlbar's drop-down arrow is
+      // pressed.
+      transition: Ci.nsINavHistoryService.TRANSITION_TYPED,
+    });
+  }
+  await PlacesTestUtils.addVisits(visits);
+});
+
+
+async function selectSettings(activateFn) {
+  await BrowserTestUtils.withNewTab({gBrowser, url: "about:blank"}, async browser => {
+    gURLBar.focus();
+    EventUtils.synthesizeKey("KEY_ArrowDown");
+    await promisePopupShown(gURLBar.popup);
+    await waitForAutocompleteResultAt(gMaxResults - 1);
+
+    let promiseHidden = promisePopupHidden(gURLBar.popup);
+    let prefPaneLoaded = TestUtils.topicObserved("sync-pane-loaded", () => true);
+
+    activateFn();
+
+    await prefPaneLoaded;
+    await promiseHidden;
+
+    Assert.equal(gBrowser.contentWindow.history.state, "paneSearch",
+      "Should have opened the search preferences pane");
+  });
+}
+
+add_task(async function test_open_settings_with_enter() {
+  await selectSettings(() => {
+    EventUtils.synthesizeKey("KEY_ArrowUp");
+
+    Assert.equal(gURLBar.popup.oneOffSearchButtons.selectedButton.getAttribute("anonid"),
+      "search-settings-compact", "Should have selected the settings button");
+
+    EventUtils.synthesizeKey("KEY_Enter");
+  });
+});
+
+add_task(async function test_open_settings_with_click() {
+  await selectSettings(() => {
+    gURLBar.popup.oneOffSearchButtons.settingsButton.click();
+  });
+});
+
+async function hidePopup() {
+  EventUtils.synthesizeKey("KEY_Escape");
+  await promisePopupHidden(gURLBar.popup);
+}
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -647,19 +647,16 @@ file, You can obtain one at http://mozil
         <parameter name="triggeringPrincipal"/>
         <body><![CDATA[
           let isMouseEvent = event instanceof MouseEvent;
           if (isMouseEvent && event.button == 2) {
             // Do nothing for right clicks.
             return;
           }
 
-          BrowserUsageTelemetry.recordUrlbarSelectedResultMethod(
-            event, this.userSelectionBehavior);
-
           // Determine whether to use the selected one-off search button.  In
           // one-off search buttons parlance, "selected" means that the button
           // has been navigated to via the keyboard.  So we want to use it if
           // the triggering event is not a mouse click -- i.e., it's a Return
           // key -- or if the one-off was mouse-clicked.
           let selectedOneOff = this.popup.oneOffSearchButtons.selectedButton;
           if (selectedOneOff &&
               isMouseEvent &&
@@ -668,16 +665,19 @@ file, You can obtain one at http://mozil
           }
 
           // Do the command of the selected one-off if it's not an engine.
           if (selectedOneOff && !selectedOneOff.engine) {
             selectedOneOff.doCommand();
             return;
           }
 
+          BrowserUsageTelemetry.recordUrlbarSelectedResultMethod(
+            event, this.userSelectionBehavior);
+
           let where = openUILinkWhere || this._whereToOpen(event);
 
           let url = this.value;
           if (!url) {
             return;
           }
 
           let mayInheritPrincipal = false;
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -18,16 +18,20 @@ ChromeUtils.defineModuleGetter(this, "Pr
                                "resource://gre/modules/PrivateBrowsingUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "SitePermissions",
                                "resource:///modules/SitePermissions.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "gBrandBundle", function() {
   return Services.strings.createBundle("chrome://branding/locale/brand.properties");
 });
 
+XPCOMUtils.defineLazyServiceGetter(this, "OSPermissions",
+                                   "@mozilla.org/ospermissionrequest;1",
+                                   "nsIOSPermissionRequest");
+
 var webrtcUI = {
   peerConnectionBlockers: new Set(),
   emitter: new EventEmitter(),
 
   init() {
     Services.obs.addObserver(maybeAddMenuIndicator, "browser-delayed-startup-finished");
     Services.ppmm.addMessageListener("child-process-shutdown", this);
   },
@@ -295,16 +299,77 @@ var webrtcUI = {
 };
 
 function denyRequest(aBrowser, aRequest) {
   aBrowser.messageManager.sendAsyncMessage("webrtc:Deny",
                                            {callID: aRequest.callID,
                                             windowID: aRequest.windowID});
 }
 
+//
+// Deny the request because the browser does not have access to the
+// camera or microphone due to OS security restrictions. The user may
+// have granted camera/microphone access to the site, but not have
+// allowed the browser access in OS settings.
+//
+function denyRequestNoPermission(aBrowser, aRequest) {
+  aBrowser.messageManager.sendAsyncMessage("webrtc:Deny",
+                                           {callID: aRequest.callID,
+                                            windowID: aRequest.windowID,
+                                            noOSPermission: true});
+}
+
+//
+// Check if we have permission to access the camera and or microphone at the
+// OS level. Triggers a request to access the device if access is needed and
+// the permission state has not yet been determined.
+//
+async function checkOSPermission(camNeeded, micNeeded) {
+  let camStatus = {}, micStatus = {};
+  OSPermissions.getMediaCapturePermissionState(camStatus, micStatus);
+  if (camNeeded) {
+    let camPermission = camStatus.value;
+    let camAccessible = await checkAndGetOSPermission(camPermission,
+      OSPermissions.requestVideoCapturePermission);
+    if (!camAccessible) {
+      return false;
+    }
+  }
+  if (micNeeded) {
+    let micPermission = micStatus.value;
+    let micAccessible = await checkAndGetOSPermission(micPermission,
+      OSPermissions.requestAudioCapturePermission);
+    if (!micAccessible) {
+      return false;
+    }
+  }
+  return true;
+}
+
+//
+// Given a device's permission, return true if the device is accessible. If
+// the device's permission is not yet determined, request access to the device.
+// |requestPermissionFunc| must return a promise that resolves with true
+// if the device is accessible and false otherwise.
+//
+async function checkAndGetOSPermission(devicePermission,
+                                       requestPermissionFunc) {
+  if (devicePermission == OSPermissions.PERMISSION_STATE_DENIED ||
+      devicePermission == OSPermissions.PERMISSION_STATE_RESTRICTED) {
+    return false;
+  }
+  if (devicePermission == OSPermissions.PERMISSION_STATE_NOTDETERMINED) {
+    let deviceAllowed = await requestPermissionFunc();
+    if (!deviceAllowed) {
+      return false;
+    }
+  }
+  return true;
+}
+
 function getHostOrExtensionName(uri, href) {
   let host;
   try {
     if (!uri) {
       uri = Services.io.newURI(href);
     }
 
     let addonPolicy = WebExtensionPolicy.getByURI(uri);
@@ -512,20 +577,29 @@ function prompt(aBrowser, aRequest) {
           // Remember on which URIs we found persistent permissions so that we
           // can remove them if the user clicks 'Stop Sharing'. There's no
           // other way for the stop sharing code to know the hostnames of frames
           // using devices until bug 1066082 is fixed.
           let browser = this.browser;
           browser._devicePermissionURIs = browser._devicePermissionURIs || [];
           browser._devicePermissionURIs.push(uri);
 
-          let mm = browser.messageManager;
-          mm.sendAsyncMessage("webrtc:Allow", {callID: aRequest.callID,
-                                               windowID: aRequest.windowID,
-                                               devices: allowedDevices});
+          let camNeeded = videoDevices.length > 0;
+          let micNeeded = audioDevices.length > 0;
+          checkOSPermission(camNeeded, micNeeded).then((havePermission) => {
+            if (havePermission) {
+              let mm = browser.messageManager;
+              mm.sendAsyncMessage("webrtc:Allow", {callID: aRequest.callID,
+                                                   windowID: aRequest.windowID,
+                                                   devices: allowedDevices});
+            } else {
+              denyRequestNoPermission(browser, aRequest);
+            }
+          });
+
           this.remove();
           return true;
         }
       }
 
       function listDevices(menupopup, devices) {
         while (menupopup.lastChild)
           menupopup.removeChild(menupopup.lastChild);
@@ -712,17 +786,17 @@ function prompt(aBrowser, aRequest) {
       } else {
         listDevices(camMenupopup, videoDevices);
         doc.getElementById("webRTC-shareDevices-notification").removeAttribute("invalidselection");
       }
 
       if (!sharingAudio)
         listDevices(micMenupopup, audioDevices);
 
-      this.mainAction.callback = function(aState) {
+      this.mainAction.callback = async function(aState) {
         let remember = aState && aState.checkboxChecked;
         let allowedDevices = [];
         let perms = Services.perms;
         if (videoDevices.length) {
           let listId = "webRTC-select" + (sharingScreen ? "Window" : "Camera") + "-menulist";
           let videoDeviceIndex = doc.getElementById(listId).value;
           let allowVideoDevice = videoDeviceIndex != "-1";
           if (allowVideoDevice) {
@@ -779,16 +853,24 @@ function prompt(aBrowser, aRequest) {
 
         if (remember) {
           // Remember on which URIs we set persistent permissions so that we
           // can remove them if the user clicks 'Stop Sharing'.
           aBrowser._devicePermissionURIs = aBrowser._devicePermissionURIs || [];
           aBrowser._devicePermissionURIs.push(uri);
         }
 
+        let camNeeded = videoDevices.length > 0;
+        let micNeeded = audioDevices.length > 0;
+        let havePermission = await checkOSPermission(camNeeded, micNeeded);
+        if (!havePermission) {
+          denyRequestNoPermission(notification.browser, aRequest);
+          return;
+        }
+
         let mm = notification.browser.messageManager;
         mm.sendAsyncMessage("webrtc:Allow", {callID: aRequest.callID,
                                              windowID: aRequest.windowID,
                                              devices: allowedDevices});
       };
       return false;
     },
   };
--- a/devtools/client/netmonitor/src/components/ResponsePanel.js
+++ b/devtools/client/netmonitor/src/components/ResponsePanel.js
@@ -25,17 +25,17 @@ const JSON_FILTER_TEXT = L10N.getStr("js
 const RESPONSE_IMG_NAME = L10N.getStr("netmonitor.response.name");
 const RESPONSE_IMG_DIMENSIONS = L10N.getStr("netmonitor.response.dimensions");
 const RESPONSE_IMG_MIMETYPE = L10N.getStr("netmonitor.response.mime");
 const RESPONSE_PAYLOAD = L10N.getStr("responsePayload");
 const RESPONSE_PREVIEW = L10N.getStr("responsePreview");
 
 const JSON_VIEW_MIME_TYPE = "application/vnd.mozilla.json.view";
 
-/*
+/**
  * Response panel component
  * Displays the GET parameters and POST data of a request
  */
 class ResponsePanel extends Component {
   static get propTypes() {
     return {
       request: PropTypes.object.isRequired,
       openLink: PropTypes.func,
@@ -48,53 +48,77 @@ class ResponsePanel extends Component {
 
     this.state = {
       imageDimensions: {
         width: 0,
         height: 0,
       },
     };
 
-    this.updateImageDimemsions = this.updateImageDimemsions.bind(this);
-    this.isJSON = this.isJSON.bind(this);
+    this.updateImageDimensions = this.updateImageDimensions.bind(this);
   }
 
   componentDidMount() {
     const { request, connector } = this.props;
     fetchNetworkUpdatePacket(connector.requestData, request, ["responseContent"]);
   }
 
   componentWillReceiveProps(nextProps) {
     const { request, connector } = nextProps;
     fetchNetworkUpdatePacket(connector.requestData, request, ["responseContent"]);
   }
 
-  updateImageDimemsions({ target }) {
+  updateImageDimensions({ target }) {
     this.setState({
       imageDimensions: {
         width: target.naturalWidth,
         height: target.naturalHeight,
       },
     });
   }
 
-  // Handle json, which we tentatively identify by checking the MIME type
-  // for "json" after any word boundary. This works for the standard
-  // "application/json", and also for custom types like "x-bigcorp-json".
-  // Additionally, we also directly parse the response text content to
-  // verify whether it's json or not, to handle responses incorrectly
-  // labeled as text/plain instead.
+  /**
+   * This method checks that the response is base64 encoded by
+   * comparing these 2 values:
+   * 1. The original response
+   * 2. The value of doing a base64 decode on the
+   * response and then base64 encoding the result.
+   * If the values are different or an error is thrown,
+   * the method will return false.
+   */
+  isBase64(response) {
+    try {
+      return btoa(atob(response)) == response;
+    } catch (err) {
+      return false;
+    }
+  }
+
+  /**
+   * Handle json, which we tentatively identify by checking the
+   * MIME type for "json" after any word boundary. This works
+   * for the standard "application/json", and also for custom
+   * types like "x-bigcorp-json". Additionally, we also
+   * directly parse the response text content to verify whether
+   * it's json or not, to handle responses incorrectly labeled
+   * as text/plain instead.
+   */
   isJSON(mimeType, response) {
     let json, error;
+
     try {
       json = JSON.parse(response);
     } catch (err) {
-      try {
-        json = JSON.parse(atob(response));
-      } catch (err64) {
+      if (this.isBase64(response)) {
+        try {
+          json = JSON.parse(atob(response));
+        } catch (err64) {
+          error = err;
+        }
+      } else {
         error = err;
       }
     }
 
     if (/\bjson/.test(mimeType) || json) {
       // Extract the actual json substring in case this might be a "JSONP".
       // This regex basically parses a function call and captures the
       // function name and arguments in two separate groups.
@@ -145,17 +169,17 @@ class ResponsePanel extends Component {
     if (mimeType.includes("image/")) {
       const { width, height } = this.state.imageDimensions;
 
       return (
         div({ className: "panel-container response-image-box devtools-monospace" },
           img({
             className: "response-image",
             src: formDataURI(mimeType, encoding, text),
-            onLoad: this.updateImageDimemsions,
+            onLoad: this.updateImageDimensions,
           }),
           div({ className: "response-summary" },
             div({ className: "tabpanel-summary-label" }, RESPONSE_IMG_NAME),
             div({ className: "tabpanel-summary-value" }, getUrlBaseName(url)),
           ),
           div({ className: "response-summary" },
             div({ className: "tabpanel-summary-label" }, RESPONSE_IMG_DIMENSIONS),
             div({ className: "tabpanel-summary-value" }, `${width} × ${height}`),
--- a/devtools/client/netmonitor/test/browser.ini
+++ b/devtools/client/netmonitor/test/browser.ini
@@ -13,16 +13,17 @@ support-files =
   html_cyrillic-test-page.html
   html_frame-test-page.html
   html_frame-subdocument.html
   html_filter-test-page.html
   html_infinite-get-page.html
   html_json-b64.html
   html_json-basic.html
   html_json-custom-mime-test-page.html
+  html_json-empty.html
   html_json-long-test-page.html
   html_json-malformed-test-page.html
   html_json-text-mime-test-page.html
   html_jsonp-test-page.html
   html_maps-test-page.html
   html_navigate-test-page.html
   html_params-test-page.html
   html_pause-test-page.html
@@ -128,16 +129,17 @@ skip-if = (os == 'mac') # Bug 1479782
 [browser_net_filter-autocomplete.js]
 [browser_net_filter-flags.js]
 [browser_net_footer-summary.js]
 [browser_net_headers-alignment.js]
 [browser_net_headers_filter.js]
 [browser_net_headers_sorted.js]
 [browser_net_image-tooltip.js]
 [browser_net_json-b64.js]
+[browser_net_json-empty.js]
 [browser_net_json-null.js]
 [browser_net_json-long.js]
 [browser_net_json-malformed.js]
 [browser_net_json-nogrip.js]
 [browser_net_json_custom_mime.js]
 [browser_net_json_text_mime.js]
 [browser_net_jsonp.js]
 [browser_net_large-response.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/test/browser_net_json-empty.js
@@ -0,0 +1,47 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/**
+ * Tests if empty JSON responses are properly displayed.
+ */
+
+add_task(async function() {
+  const { tab, monitor } = await initNetMonitor(JSON_EMPTY_URL + "?name=empty");
+  info("Starting test... ");
+
+  const { document, store, windowRequire } = monitor.panelWin;
+  const { L10N } = windowRequire("devtools/client/netmonitor/src/utils/l10n");
+  const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
+
+  store.dispatch(Actions.batchEnable(false));
+
+  // Execute requests.
+  await performRequests(monitor, tab, 1);
+
+  const onResponsePanelReady = waitForDOM(document, "#response-panel .CodeMirror-code");
+  store.dispatch(Actions.toggleNetworkDetails());
+  EventUtils.sendMouseEvent({ type: "click" },
+    document.querySelector("#response-tab"));
+  await onResponsePanelReady;
+
+  const tabpanel = document.querySelector("#response-panel");
+  is(tabpanel.querySelectorAll(".tree-section").length, 2,
+    "There should be 2 tree sections displayed in this tabpanel.");
+  is(tabpanel.querySelectorAll(".empty-notice").length, 0,
+    "The empty notice should not be displayed in this tabpanel.");
+
+  is(tabpanel.querySelector(".response-error-header") === null, true,
+    "The response error header doesn't have the intended visibility.");
+  is(tabpanel.querySelector(".CodeMirror-code") === null, false,
+    "The response editor has the intended visibility.");
+  is(tabpanel.querySelector(".response-image-box") === null, true,
+    "The response image box doesn't have the intended visibility.");
+
+  const jsonView = tabpanel.querySelector(".tree-section .treeLabel") || {};
+  is(jsonView.textContent === L10N.getStr("jsonScopeName"), true,
+    "The response json view has the intended visibility.");
+
+  await teardown(monitor);
+});
--- a/devtools/client/netmonitor/test/browser_net_json-null.js
+++ b/devtools/client/netmonitor/test/browser_net_json-null.js
@@ -15,21 +15,21 @@ add_task(async function() {
   const { L10N } = windowRequire("devtools/client/netmonitor/src/utils/l10n");
   const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
 
   store.dispatch(Actions.batchEnable(false));
 
   // Execute requests.
   await performRequests(monitor, tab, 1);
 
-  const onReponsePanelReady = waitForDOM(document, "#response-panel .CodeMirror-code");
+  const onResponsePanelReady = waitForDOM(document, "#response-panel .CodeMirror-code");
   store.dispatch(Actions.toggleNetworkDetails());
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#response-tab"));
-  await onReponsePanelReady;
+  await onResponsePanelReady;
 
   checkResponsePanelDisplaysJSON();
 
   const tabpanel = document.querySelector("#response-panel");
   is(tabpanel.querySelectorAll(".tree-section").length, 2,
     "There should be 2 tree sections displayed in this tabpanel.");
   is(tabpanel.querySelectorAll(".treeRow:not(.tree-section)").length, 1,
     "There should be 1 json properties displayed in this tabpanel.");
--- a/devtools/client/netmonitor/test/head.js
+++ b/devtools/client/netmonitor/test/head.js
@@ -56,16 +56,17 @@ const POST_RAW_WITH_HEADERS_URL = EXAMPL
 const PARAMS_URL = EXAMPLE_URL + "html_params-test-page.html";
 const JSONP_URL = EXAMPLE_URL + "html_jsonp-test-page.html";
 const JSON_LONG_URL = EXAMPLE_URL + "html_json-long-test-page.html";
 const JSON_MALFORMED_URL = EXAMPLE_URL + "html_json-malformed-test-page.html";
 const JSON_CUSTOM_MIME_URL = EXAMPLE_URL + "html_json-custom-mime-test-page.html";
 const JSON_TEXT_MIME_URL = EXAMPLE_URL + "html_json-text-mime-test-page.html";
 const JSON_B64_URL = EXAMPLE_URL + "html_json-b64.html";
 const JSON_BASIC_URL = EXAMPLE_URL + "html_json-basic.html";
+const JSON_EMPTY_URL = EXAMPLE_URL + "html_json-empty.html";
 const SORTING_URL = EXAMPLE_URL + "html_sorting-test-page.html";
 const FILTERING_URL = EXAMPLE_URL + "html_filter-test-page.html";
 const INFINITE_GET_URL = EXAMPLE_URL + "html_infinite-get-page.html";
 const CUSTOM_GET_URL = EXAMPLE_URL + "html_custom-get-page.html";
 const SINGLE_GET_URL = EXAMPLE_URL + "html_single-get-page.html";
 const STATISTICS_URL = EXAMPLE_URL + "html_statistics-test-page.html";
 const CURL_URL = EXAMPLE_URL + "html_copy-as-curl.html";
 const CURL_UTILS_URL = EXAMPLE_URL + "html_curl-utils.html";
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/test/html_json-empty.html
@@ -0,0 +1,42 @@
+<!-- Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!doctype html>
+
+<html>
+  <head>
+    <meta charset="utf-8"/>
+    <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
+    <meta http-equiv="Pragma" content="no-cache" />
+    <meta http-equiv="Expires" content="0" />
+    <title>Network Monitor test page</title>
+  </head>
+
+  <body>
+    <p>Empty JSON test page</p>
+
+    <script type="text/javascript">
+      /* exported performRequests */
+      "use strict";
+
+      function get(address, callback) {
+        const xhr = new XMLHttpRequest();
+        xhr.open("GET", address, true);
+
+        xhr.onreadystatechange = function() {
+          if (this.readyState == this.DONE) {
+            callback();
+          }
+        };
+        xhr.send(null);
+      }
+
+      function performRequests() {
+        // Forward the query parameter for this page to sjs_json-test-server
+        get("sjs_json-test-server.sjs" + window.location.search, function() {
+          // Done.
+        });
+      }
+    </script>
+  </body>
+
+</html>
--- a/devtools/client/netmonitor/test/sjs_json-test-server.sjs
+++ b/devtools/client/netmonitor/test/sjs_json-test-server.sjs
@@ -16,10 +16,13 @@ function handleRequest(request, response
   let name = (params.filter((s) => s.includes("name="))[0] || "").split("=")[1];
   switch (name) {
     case "null":
       response.write("{ \"greeting\": null }");
       break;
     case "nogrip":
       response.write("{\"obj\": {\"type\": \"string\" }}");
       break;
+    case "empty":
+      response.write("{}");
+      break;
   }
 }
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -617,17 +617,17 @@ Element::WrapObject(JSContext *aCx, JS::
     bool ok = GetBindingURL(doc, getter_AddRefs(bindingURL));
     if (!ok) {
       dom::Throw(aCx, NS_ERROR_FAILURE);
       return nullptr;
     }
 
     if (bindingURL) {
       nsCOMPtr<nsIURI> uri = bindingURL->GetURI();
-      nsCOMPtr<nsIPrincipal> principal = bindingURL->mExtraData->GetPrincipal();
+      nsCOMPtr<nsIPrincipal> principal = bindingURL->mExtraData->Principal();
 
       // We have a binding that must be installed.
       bool dummy;
 
       nsXBLService* xblService = nsXBLService::GetInstance();
       if (!xblService) {
         dom::Throw(aCx, NS_ERROR_NOT_AVAILABLE);
         return nullptr;
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -3794,17 +3794,17 @@ nsIDocument::DefaultStyleAttrURLData()
   nsIURI* baseURI = GetDocBaseURI();
   nsIURI* docURI = GetDocumentURI();
   nsIPrincipal* principal = NodePrincipal();
   mozilla::net::ReferrerPolicy policy = GetReferrerPolicy();
   if (!mCachedURLData ||
       mCachedURLData->BaseURI() != baseURI ||
       mCachedURLData->GetReferrer() != docURI ||
       mCachedURLData->GetReferrerPolicy() != policy ||
-      mCachedURLData->GetPrincipal() != principal) {
+      mCachedURLData->Principal() != principal) {
     mCachedURLData = new URLExtraData(baseURI, docURI, principal, policy);
   }
   return mCachedURLData;
 }
 
 void
 nsIDocument::SetDocumentCharacterSet(NotNull<const Encoding*> aEncoding)
 {
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -2255,16 +2255,17 @@ MediaManager::Get() {
 
     nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
     if (obs) {
       obs->AddObserver(sSingleton, "last-pb-context-exited", false);
       obs->AddObserver(sSingleton, "getUserMedia:got-device-permission", false);
       obs->AddObserver(sSingleton, "getUserMedia:privileged:allow", false);
       obs->AddObserver(sSingleton, "getUserMedia:response:allow", false);
       obs->AddObserver(sSingleton, "getUserMedia:response:deny", false);
+      obs->AddObserver(sSingleton, "getUserMedia:response:noOSPermission", false);
       obs->AddObserver(sSingleton, "getUserMedia:revoke", false);
     }
     // else MediaManager won't work properly and will leak (see bug 837874)
     nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
     if (prefs) {
       prefs->AddObserver("media.navigator.video.default_width", sSingleton, false);
       prefs->AddObserver("media.navigator.video.default_height", sSingleton, false);
       prefs->AddObserver("media.navigator.video.default_fps", sSingleton, false);
@@ -3629,16 +3630,17 @@ MediaManager::Shutdown()
   }
 
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
 
   obs->RemoveObserver(this, "last-pb-context-exited");
   obs->RemoveObserver(this, "getUserMedia:privileged:allow");
   obs->RemoveObserver(this, "getUserMedia:response:allow");
   obs->RemoveObserver(this, "getUserMedia:response:deny");
+  obs->RemoveObserver(this, "getUserMedia:response:noOSPermission");
   obs->RemoveObserver(this, "getUserMedia:revoke");
 
   nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
   if (prefs) {
     prefs->RemoveObserver("media.navigator.video.default_width", this);
     prefs->RemoveObserver("media.navigator.video.default_height", this);
     prefs->RemoveObserver("media.navigator.video.default_fps", this);
     prefs->RemoveObserver("media.navigator.audio.fake_frequency", this);
@@ -3764,22 +3766,40 @@ MediaManager::SendPendingGUMRequest()
 {
   if (mPendingGUMRequest.Length() > 0) {
     nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
     obs->NotifyObservers(mPendingGUMRequest[0], "getUserMedia:request", nullptr);
     mPendingGUMRequest.RemoveElementAt(0);
   }
 }
 
+bool
+IsGUMResponseNoAccess(const char* aTopic, MediaMgrError::Name& aErrorName)
+{
+  if (!strcmp(aTopic, "getUserMedia:response:deny")) {
+    aErrorName = MediaMgrError::Name::NotAllowedError;
+    return true;
+  }
+
+  if (!strcmp(aTopic, "getUserMedia:response:noOSPermission")) {
+    aErrorName = MediaMgrError::Name::NotFoundError;
+    return true;
+  }
+
+  return false;
+}
+
 nsresult
 MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
   const char16_t* aData)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
+  MediaMgrError::Name gumNoAccessError = MediaMgrError::Name::NotAllowedError;
+
   if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
     nsCOMPtr<nsIPrefBranch> branch( do_QueryInterface(aSubject) );
     if (branch) {
       GetPrefs(branch,NS_ConvertUTF16toUTF8(aData).get());
       LOG(("%s: %dx%d @%dfps", __FUNCTION__,
            mPrefs.mWidth, mPrefs.mHeight, mPrefs.mFPS));
     }
   } else if (!strcmp(aTopic, "last-pb-context-exited")) {
@@ -3855,22 +3875,22 @@ MediaManager::Observe(nsISupports* aSubj
     if (sHasShutdown) {
       return task->Denied(MediaMgrError::Name::AbortError,
                           NS_LITERAL_STRING("In shutdown"));
     }
     // Reuse the same thread to save memory.
     MediaManager::PostTask(task.forget());
     return NS_OK;
 
-  } else if (!strcmp(aTopic, "getUserMedia:response:deny")) {
+  } else if (IsGUMResponseNoAccess(aTopic, gumNoAccessError)) {
     nsString key(aData);
     RefPtr<GetUserMediaTask> task;
     mActiveCallbacks.Remove(key, getter_AddRefs(task));
     if (task) {
-      task->Denied(MediaMgrError::Name::NotAllowedError);
+      task->Denied(gumNoAccessError);
       nsTArray<nsString>* array;
       if (!mCallIds.Get(task->GetWindowID(), &array)) {
         return NS_OK;
       }
       array->RemoveElement(key);
       SendPendingGUMRequest();
     }
     return NS_OK;
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -3509,17 +3509,16 @@ PluginInstanceChild::PaintRectWithAlphaE
                                                                surfaceAsImage);
         }
     }
 
     RefPtr<gfxImageSurface> whiteImage;
     RefPtr<gfxImageSurface> blackImage;
     gfxRect targetRect(rect.x, rect.y, rect.width, rect.height);
     IntSize targetSize(rect.width, rect.height);
-    gfxPoint deviceOffset = -targetRect.TopLeft();
 
     // We always use a temporary "white image"
     whiteImage = new gfxImageSurface(targetSize, SurfaceFormat::X8R8G8B8_UINT32);
     if (whiteImage->CairoStatus()) {
         return;
     }
 
 #ifdef XP_WIN
@@ -3544,16 +3543,17 @@ PluginInstanceChild::PaintRectWithAlphaE
     PaintRectToSurface(rect, aSurface, Color(0.f, 0.f, 0.f));
 
     // Don't copy the result, just extract a subimage so that we can
     // recover alpha directly into the target
     gfxImageSurface *image = static_cast<gfxImageSurface*>(aSurface);
     blackImage = image->GetSubimage(targetRect);
 
 #else
+    gfxPoint deviceOffset = -targetRect.TopLeft();
     // Paint onto white background
     whiteImage->SetDeviceOffset(deviceOffset);
     PaintRectToSurface(rect, whiteImage, Color(1.f, 1.f, 1.f));
 
     if (useSurfaceSubimageForBlack) {
         gfxImageSurface *surface = static_cast<gfxImageSurface*>(aSurface);
         blackImage = surface->GetSubimage(targetRect);
     } else {
--- a/dom/plugins/ipc/PluginInstanceParent.cpp
+++ b/dom/plugins/ipc/PluginInstanceParent.cpp
@@ -119,17 +119,16 @@ PluginInstanceParent::PluginInstancePare
     , mDrawingModel(kDefaultDrawingModel)
     , mLastRecordedDrawingModel(-1)
     , mFrameID(0)
 #if defined(OS_WIN)
     , mPluginHWND(nullptr)
     , mChildPluginHWND(nullptr)
     , mChildPluginsParentHWND(nullptr)
     , mPluginWndProc(nullptr)
-    , mNestedEventState(false)
 #endif // defined(XP_WIN)
 #if defined(XP_MACOSX)
     , mShWidth(0)
     , mShHeight(0)
     , mShColorSpace(nullptr)
 #endif
 {
 #if defined(OS_WIN)
--- a/dom/plugins/ipc/PluginInstanceParent.h
+++ b/dom/plugins/ipc/PluginInstanceParent.h
@@ -397,17 +397,16 @@ private:
     nsIntRect          mPluginPort;
     nsIntRect          mSharedSize;
     HWND               mPluginHWND;
     // This is used for the normal child plugin HWND for windowed plugins and,
     // if needed, also the child popup surrogate HWND for windowless plugins.
     HWND               mChildPluginHWND;
     HWND               mChildPluginsParentHWND;
     WNDPROC            mPluginWndProc;
-    bool               mNestedEventState;
 #endif // defined(XP_WIN)
 #if defined(MOZ_WIDGET_COCOA)
 private:
     Shmem                  mShSurface;
     uint16_t               mShWidth;
     uint16_t               mShHeight;
     CGColorSpaceRef        mShColorSpace;
     RefPtr<MacIOSurface> mIOSurface;
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -490,17 +490,17 @@ PluginModuleChromeParent::LoadModule(con
     if (NS_FAILED(rv)) {
         parent->mShutdown = true;
         return nullptr;
     }
 
     parent->mBrokerParent =
       FunctionBrokerParent::Create(std::move(brokerParentEnd));
     if (parent->mBrokerParent) {
-      parent->SendInitPluginFunctionBroker(std::move(brokerChildEnd));
+      Unused << parent->SendInitPluginFunctionBroker(std::move(brokerChildEnd));
     }
 #endif
     return parent.forget();
 }
 
 static const char* gCallbackPrefs[] = {
     kChildTimeoutPref,
     kParentTimeoutPref,
--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -470,43 +470,32 @@ struct DIGroup
       GP("else invalidate: %s\n", aItem->Name());
       // this includes situations like reflow changing the position
       aItem->ComputeInvalidationRegion(aBuilder, aData->mGeometry.get(), &combined);
       if (!combined.IsEmpty()) {
         // There might be no point in doing this elaborate tracking here to get
         // smaller areas
         InvalidateRect(aData->mRect.Intersect(imageRect)); // invalidate the old area -- in theory combined should take care of this
         UniquePtr<nsDisplayItemGeometry> geometry(aItem->AllocateGeometry(aBuilder));
-        aData->mClip.AddOffsetAndComputeDifference(nsPoint(), aData->mGeometry->ComputeInvalidationRegion(), clip,
-                                                   geometry ? geometry->ComputeInvalidationRegion() :
-                                                   aData->mGeometry->ComputeInvalidationRegion(),
-                                                   &combined);
-        IntRect transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mLayerBounds.TopLeft());
-        IntRect invalidRect = transformedRect.Intersect(imageRect);
-        GP("combined not empty: mRect %d %d %d %d\n", invalidRect.x, invalidRect.y, invalidRect.width, invalidRect.height);
         // invalidate the invalidated area.
-        InvalidateRect(invalidRect);
 
         aData->mGeometry = std::move(geometry);
 
         combined = clip.ApplyNonRoundedIntersection(aData->mGeometry->ComputeInvalidationRegion());
-        transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mLayerBounds.TopLeft());
+        IntRect transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mLayerBounds.TopLeft());
         aData->mRect = transformedRect.Intersect(imageRect);
+        InvalidateRect(aData->mRect);
 
         // CGC invariant broken
         if (!mInvalidRect.Contains(aData->mRect)) {
           gfxCriticalError() << "CGC-" <<
             "-" << aData->mRect.x <<
             "-" << aData->mRect.y <<
             "-" << aData->mRect.width <<
             "-" << aData->mRect.height <<
-            "," << invalidRect.x <<
-            "-" << invalidRect.y <<
-            "-" << invalidRect.width <<
-            "-" << invalidRect.height <<
             "-ib";
         }
 
         aData->mInvalid = true;
         aData->mInvalidRegion = true;
       } else {
         if (aData->mClip != clip) {
           UniquePtr<nsDisplayItemGeometry> geometry(aItem->AllocateGeometry(aBuilder));
--- a/ipc/mscom/Interceptor.cpp
+++ b/ipc/mscom/Interceptor.cpp
@@ -14,17 +14,17 @@
 #include "mozilla/mscom/InterceptorLog.h"
 #include "mozilla/mscom/MainThreadInvoker.h"
 #include "mozilla/mscom/Objref.h"
 #include "mozilla/mscom/Registration.h"
 #include "mozilla/mscom/Utils.h"
 #include "mozilla/ThreadLocal.h"
 #include "MainThreadUtils.h"
 #include "mozilla/Assertions.h"
-#include "mozilla/DebugOnly.h"
+#include "mozilla/Unused.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsExceptionHandler.h"
 #include "nsPrintfCString.h"
 #include "nsRefPtrHashtable.h"
 #include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
 
@@ -272,16 +272,17 @@ Interceptor::Interceptor(IInterceptorSin
   : WeakReferenceSupport(WeakReferenceSupport::Flags::eDestroyOnMainThread)
   , mEventSink(aSink)
   , mInterceptorMapMutex("mozilla::mscom::Interceptor::mInterceptorMapMutex")
   , mStdMarshalMutex("mozilla::mscom::Interceptor::mStdMarshalMutex")
   , mStdMarshal(nullptr)
 {
   static const bool kHasTls = tlsCreatingStdMarshal.init();
   MOZ_ASSERT(kHasTls);
+  Unused << kHasTls;
 
   MOZ_ASSERT(aSink);
   RefPtr<IWeakReference> weakRef;
   if (SUCCEEDED(GetWeakReference(getter_AddRefs(weakRef)))) {
     aSink->SetInterceptor(weakRef);
   }
 }
 
--- a/ipc/mscom/MainThreadHandoff.cpp
+++ b/ipc/mscom/MainThreadHandoff.cpp
@@ -11,16 +11,17 @@
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Move.h"
 #include "mozilla/mscom/AgileReference.h"
 #include "mozilla/mscom/InterceptorLog.h"
 #include "mozilla/mscom/Registration.h"
 #include "mozilla/mscom/Utils.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/ThreadLocal.h"
+#include "mozilla/Unused.h"
 #include "nsThreadUtils.h"
 #include "nsProxyRelease.h"
 
 using mozilla::DebugOnly;
 using mozilla::mscom::AgileReference;
 
 namespace {
 
@@ -161,16 +162,17 @@ class MOZ_RAII SavedCallFrame final
 public:
   explicit SavedCallFrame(mozilla::NotNull<ICallFrame*> aFrame)
     : mCallFrame(aFrame)
   {
     static const bool sIsInit = tlsFrame.init();
     MOZ_ASSERT(sIsInit);
     MOZ_ASSERT(!tlsFrame.get());
     tlsFrame.set(this);
+    Unused << sIsInit;
   }
 
   ~SavedCallFrame()
   {
     MOZ_ASSERT(tlsFrame.get());
     tlsFrame.set(nullptr);
   }
 
--- a/ipc/mscom/MainThreadInvoker.cpp
+++ b/ipc/mscom/MainThreadInvoker.cpp
@@ -6,20 +6,20 @@
 
 #include "mozilla/mscom/MainThreadInvoker.h"
 
 #include "GeckoProfiler.h"
 #include "MainThreadUtils.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/BackgroundHangMonitor.h"
 #include "mozilla/ClearOnShutdown.h"
-#include "mozilla/DebugOnly.h"
 #include "mozilla/mscom/SpinEvent.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/SystemGroup.h"
+#include "mozilla/Unused.h"
 #include "private/prpriv.h" // For PR_GetThreadID
 #include <winternl.h> // For NTSTATUS and NTAPI
 
 namespace {
 
 typedef NTSTATUS (NTAPI* NtTestAlertPtr)(VOID);
 
 /**
@@ -33,16 +33,17 @@ class SyncRunnable : public mozilla::Run
 {
 public:
   explicit SyncRunnable(already_AddRefed<nsIRunnable> aRunnable)
     : mozilla::Runnable("MainThreadInvoker")
     , mRunnable(aRunnable)
   {
     static const bool gotStatics = InitStatics();
     MOZ_ASSERT(gotStatics);
+    Unused << gotStatics;
   }
 
   ~SyncRunnable() = default;
 
   NS_IMETHOD Run() override
   {
     if (mHasRun) {
       // The APC already ran, so we have nothing to do.
@@ -126,16 +127,17 @@ MainThreadInvoker::InitStatics()
 
   return !!sMainThread;
 }
 
 MainThreadInvoker::MainThreadInvoker()
 {
   static const bool gotStatics = InitStatics();
   MOZ_ASSERT(gotStatics);
+  Unused << gotStatics;
 }
 
 bool
 MainThreadInvoker::Invoke(already_AddRefed<nsIRunnable>&& aRunnable)
 {
   nsCOMPtr<nsIRunnable> runnable(std::move(aRunnable));
   if (!runnable) {
     return false;
--- a/ipc/mscom/ProxyStream.cpp
+++ b/ipc/mscom/ProxyStream.cpp
@@ -291,17 +291,17 @@ ProxyStream::ProxyStream(REFIID aIID, IU
 
   HRESULT createStreamResult = S_OK;
   HRESULT marshalResult = S_OK;
   HRESULT statResult = S_OK;
   HRESULT getHGlobalResult = S_OK;
 
   nsAutoString manifestPath;
 
-  auto marshalFn = [this, &aIID, aObject, mshlFlags, &stream, &streamSize,
+  auto marshalFn = [&aIID, aObject, mshlFlags, &stream, &streamSize,
                     &hglobal, &createStreamResult, &marshalResult, &statResult,
                     &getHGlobalResult, aEnv, &manifestPath]() -> void
   {
     if (aEnv) {
       bool pushOk = aEnv->Push();
       MOZ_DIAGNOSTIC_ASSERT(pushOk);
       if (!pushOk) {
         return;
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -2421,17 +2421,17 @@ nsCSSFrameConstructor::ConstructDocEleme
 
     nsXBLService* xblService = nsXBLService::GetInstance();
     if (!xblService) {
       return nullptr;
     }
 
     RefPtr<nsXBLBinding> binding;
     rv = xblService->LoadBindings(aDocElement, display->mBinding->GetURI(),
-                                  display->mBinding->mExtraData->GetPrincipal(),
+                                  display->mBinding->mExtraData->Principal(),
                                   getter_AddRefs(binding), &resolveStyle);
     if (NS_FAILED(rv) && rv != NS_ERROR_XBL_BLOCKED) {
       // Binding will load asynchronously.
       return nullptr;
     }
 
     if (binding) {
       // For backwards compat, keep firing the root's constructor
@@ -5574,17 +5574,17 @@ nsCSSFrameConstructor::LoadXBLBindingIfN
     return { };
   }
 
   auto newPendingBinding = MakeUnique<PendingBinding>();
 
   bool resolveStyle;
   nsresult rv = xblService->LoadBindings(aContent.AsElement(),
                                          binding->GetURI(),
-                                         binding->mExtraData->GetPrincipal(),
+                                         binding->mExtraData->Principal(),
                                          getter_AddRefs(newPendingBinding->mBinding),
                                          &resolveStyle);
   if (NS_FAILED(rv)) {
     if (rv == NS_ERROR_XBL_BLOCKED) {
       return { aContent, aStyle };
     }
     return { };
   }
--- a/layout/style/FontFaceSet.cpp
+++ b/layout/style/FontFaceSet.cpp
@@ -1100,18 +1100,17 @@ FontFaceSet::FindOrCreateUserFontEntryFr
         case StyleFontFaceSourceListComponent::Tag::Url: {
           face->mSourceType = gfxFontFaceSrc::eSourceType_URL;
           const URLValue* url = component.url._0;
           nsIURI* uri = url->GetURI();
           face->mURI = uri ? new gfxFontSrcURI(uri) : nullptr;
           face->mReferrer = url->mExtraData->GetReferrer();
           face->mReferrerPolicy = url->mExtraData->GetReferrerPolicy();
           face->mOriginPrincipal =
-            new gfxFontSrcPrincipal(url->mExtraData->GetPrincipal());
-          NS_ASSERTION(face->mOriginPrincipal, "null origin principal in @font-face rule");
+            new gfxFontSrcPrincipal(url->mExtraData->Principal());
 
           // agent and user stylesheets are treated slightly differently,
           // the same-site origin check and access control headers are
           // enforced against the sheet principal rather than the document
           // principal to allow user stylesheets to include @font-face rules
           face->mUseOriginPrincipal = (aSheetType == SheetType::User ||
                                        aSheetType == SheetType::Agent);
 
--- a/layout/style/ImageLoader.cpp
+++ b/layout/style/ImageLoader.cpp
@@ -48,17 +48,17 @@ ImageLoader::DropDocumentReference()
   // been destroyed, and it also calls ClearFrames when it is destroyed.
   ClearFrames(GetPresContext());
 
   for (auto it = mRegisteredImages.Iter(); !it.Done(); it.Next()) {
     if (imgRequestProxy* request = it.Data()) {
       request->CancelAndForgetObserver(NS_BINDING_ABORTED);
     }
 
-    // Need to check whether the entry exists, since the css::ImageValue might
+    // Need to check whether the entry exists, since the css::URLValue might
     // go away before ImageLoader::DropDocumentReference is called.
     uint64_t imageLoadID = it.Key();
     if (auto entry = sImages->Lookup(imageLoadID)) {
       entry.Data()->mImageLoaders.RemoveEntry(this);
     }
   }
 
   mRegisteredImages.Clear();
@@ -203,17 +203,17 @@ ImageLoader::AssociateRequestToFrame(img
     didAddToRequestSet = true;
   }
 
   MOZ_ASSERT(didAddToFrameSet == didAddToRequestSet,
              "We should only add to one map iff we also add to the other map.");
 }
 
 imgRequestProxy*
-ImageLoader::RegisterCSSImage(ImageLoader::Image* aImage)
+ImageLoader::RegisterCSSImage(URLValue* aImage)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aImage);
 
   if (aImage->LoadID() == 0) {
     MOZ_ASSERT_UNREACHABLE("Image should have a valid LoadID");
     return nullptr;
   }
@@ -249,17 +249,17 @@ ImageLoader::RegisterCSSImage(ImageLoade
   MOZ_ASSERT(!mRegisteredImages.Contains(aImage->LoadID()));
 
   imgRequestProxy* requestWeak = request;
   mRegisteredImages.Put(aImage->LoadID(), request.forget());
   return requestWeak;
 }
 
 /* static */ void
-ImageLoader::DeregisterCSSImageFromAllLoaders(ImageLoader::Image* aImage)
+ImageLoader::DeregisterCSSImageFromAllLoaders(URLValue* aImage)
 {
   MOZ_ASSERT(aImage);
 
   uint64_t loadID = aImage->LoadID();
 
   if (loadID == 0) {
     MOZ_ASSERT_UNREACHABLE("Image should have a valid LoadID");
     return;
@@ -450,31 +450,31 @@ ImageLoader::ClearFrames(nsPresContext* 
 }
 
 /* static */ void
 ImageLoader::LoadImage(nsIURI* aURI,
                        nsIPrincipal* aOriginPrincipal,
                        nsIURI* aReferrer,
                        mozilla::net::ReferrerPolicy aPolicy,
                        nsIDocument* aDocument,
-                       ImageLoader::Image* aImage,
+                       URLValue* aImage,
                        CORSMode aCorsMode)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aDocument);
   MOZ_ASSERT(aImage);
   MOZ_ASSERT(aImage->LoadID() != 0);
 
   if (aImage->LoadID() == 0) {
     MOZ_ASSERT_UNREACHABLE("Image should have a valid LoadID");
     return;
   }
 
   if (sImages->Contains(aImage->LoadID())) {
-    // This css::ImageValue has already been loaded.
+    // This css::URLValue has already been loaded.
     return;
   }
 
   ImageTableEntry* entry = new ImageTableEntry();
   sImages->Put(aImage->LoadID(), entry);
 
   if (!aURI) {
     return;
--- a/layout/style/ImageLoader.h
+++ b/layout/style/ImageLoader.h
@@ -26,17 +26,17 @@ class nsIFrame;
 class nsIDocument;
 class nsPresContext;
 class nsIURI;
 class nsIPrincipal;
 
 namespace mozilla {
 namespace css {
 
-struct ImageValue;
+struct URLValue;
 
 /**
  * NOTE: All methods must be called from the main thread unless otherwise
  * specified.
  */
 class ImageLoader final : public imgINotificationObserver
 {
 public:
@@ -46,31 +46,29 @@ public:
   // We also associate flags alongside frames in the request-to-frames hashmap.
   // These are used for special handling of events for requests.
   typedef uint32_t FrameFlags;
   enum {
     REQUEST_REQUIRES_REFLOW      = 1u << 0,
     REQUEST_HAS_BLOCKED_ONLOAD   = 1u << 1,
   };
 
-  typedef mozilla::css::ImageValue Image;
-
   explicit ImageLoader(nsIDocument* aDocument)
   : mDocument(aDocument),
     mInClone(false)
   {
     MOZ_ASSERT(mDocument);
   }
 
   NS_DECL_ISUPPORTS
   NS_DECL_IMGINOTIFICATIONOBSERVER
 
   void DropDocumentReference();
 
-  imgRequestProxy* RegisterCSSImage(Image* aImage);
+  imgRequestProxy* RegisterCSSImage(URLValue* aImage);
 
   void AssociateRequestToFrame(imgIRequest* aRequest,
                                nsIFrame* aFrame,
                                FrameFlags aFlags);
 
   void DisassociateRequestFromFrame(imgIRequest* aRequest,
                                     nsIFrame* aFrame);
 
@@ -83,24 +81,24 @@ public:
   // presshell pointer on the document has been cleared.
   void ClearFrames(nsPresContext* aPresContext);
 
   static void LoadImage(nsIURI* aURI,
                         nsIPrincipal* aPrincipal,
                         nsIURI* aReferrer,
                         mozilla::net::ReferrerPolicy aPolicy,
                         nsIDocument* aDocument,
-                        Image* aCSSValue,
+                        URLValue* aImage,
                         CORSMode aCorsMode);
 
-  // Cancels the image load for the given css::ImageValue and deregisters
+  // Cancels the image load for the given css::URLValue and deregisters
   // it from any ImageLoaders it was registered with.
   //
   // May be called from any thread.
-  static void DeregisterCSSImageFromAllLoaders(Image* aImage);
+  static void DeregisterCSSImageFromAllLoaders(URLValue* aImage);
 
   void FlushUseCounters();
 
 private:
   // This callback is used to unblock document onload after a reflow
   // triggered from an image load.
   struct ImageReflowCallback final : public nsIReflowCallback
   {
@@ -182,49 +180,49 @@ private:
   RequestToFrameMap mRequestToFrameMap;
 
   // A map of nsIFrames to the imgIRequests they use.
   FrameToRequestMap mFrameToRequestMap;
 
   // A weak pointer to our document. Nulled out by DropDocumentReference.
   nsIDocument* mDocument;
 
-  // A map of css::ImageValues, keyed by their LoadID(), to the imgRequestProxy
+  // A map of css::URLValues, keyed by their LoadID(), to the imgRequestProxy
   // representing the load of the image for this ImageLoader's document.
   //
   // We use the LoadID() as the key since we can only access mRegisteredImages
-  // on the main thread, but css::ImageValues might be destroyed from other
+  // on the main thread, but css::URLValues might be destroyed from other
   // threads, and we don't want to leave dangling pointers around.
   nsRefPtrHashtable<nsUint64HashKey, imgRequestProxy> mRegisteredImages;
 
   // Are we cloning?  If so, ignore any notifications we get.
   bool mInClone;
 
-  // Data associated with every css::ImageValue object that has had a load
+  // Data associated with every css::URLValue object that has had a load
   // started.
   struct ImageTableEntry
   {
-    // Set of all ImageLoaders that have registered this css::ImageValue.
+    // Set of all ImageLoaders that have registered this css::URLValue.
     nsTHashtable<nsPtrHashKey<ImageLoader>> mImageLoaders;
 
-    // The "canonical" image request for this css::ImageValue.
+    // The "canonical" image request for this css::URLValue.
     //
-    // This request is held on to as long as the specified css::ImageValue
+    // This request is held on to as long as the specified css::URLValue
     // object is, so that any image that has already started loading (or
     // has completed loading) will stay alive even if all computed values
     // referencing the image requesst have gone away.
     RefPtr<imgRequestProxy> mCanonicalRequest;
   };
 
-  // A table of all css::ImageValues that have been loaded, keyed by their
+  // A table of all css::URLValues that have been loaded, keyed by their
   // LoadID(), mapping them to the set of ImageLoaders they have been registered
   // in, and recording their "canonical" image request.
   //
   // We use the LoadID() as the key since we can only access sImages on the
-  // main thread, but css::ImageValues might be destroyed from other threads,
+  // main thread, but css::URLValues might be destroyed from other threads,
   // and we don't want to leave dangling pointers around.
   static nsClassHashtable<nsUint64HashKey, ImageTableEntry>* sImages;
 };
 
 } // namespace css
 } // namespace mozilla
 
 #endif /* mozilla_css_ImageLoader_h___ */
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -1381,31 +1381,20 @@ Gecko_CounterStyle_GetName(const Counter
 
 const AnonymousCounterStyle*
 Gecko_CounterStyle_GetAnonymous(const CounterStylePtr* aPtr)
 {
   return aPtr->AsAnonymous();
 }
 
 already_AddRefed<css::URLValue>
-ServoBundledURI::IntoCssUrl()
+ServoBundledURI::IntoCssUrl(CORSMode aCorsMode)
 {
-  MOZ_ASSERT(mExtraData->GetReferrer());
-  MOZ_ASSERT(mExtraData->GetPrincipal());
-
   RefPtr<css::URLValue> urlValue =
-    new css::URLValue(mURLString, do_AddRef(mExtraData));
-  return urlValue.forget();
-}
-
-already_AddRefed<css::ImageValue>
-ServoBundledURI::IntoCssImage(mozilla::CORSMode aCorsMode)
-{
-  RefPtr<css::ImageValue> urlValue =
-    new css::ImageValue(mURLString, do_AddRef(mExtraData), aCorsMode);
+    new css::URLValue(mURLString, do_AddRef(mExtraData), aCorsMode);
   return urlValue.forget();
 }
 
 void
 Gecko_SetNullImageValue(nsStyleImage* aImage)
 {
   MOZ_ASSERT(aImage);
   aImage->SetNull();
@@ -1413,45 +1402,28 @@ Gecko_SetNullImageValue(nsStyleImage* aI
 
 void
 Gecko_SetGradientImageValue(nsStyleImage* aImage, nsStyleGradient* aGradient)
 {
   MOZ_ASSERT(aImage);
   aImage->SetGradientData(aGradient);
 }
 
-NS_IMPL_THREADSAFE_FFI_REFCOUNTING(mozilla::css::ImageValue, ImageValue);
-
 static already_AddRefed<nsStyleImageRequest>
 CreateStyleImageRequest(nsStyleImageRequest::Mode aModeFlags,
-                        mozilla::css::ImageValue* aImageValue)
+                        URLValue* aImageValue)
 {
   RefPtr<nsStyleImageRequest> req =
     new nsStyleImageRequest(aModeFlags, aImageValue);
   return req.forget();
 }
 
-mozilla::css::ImageValue*
-Gecko_ImageValue_Create(ServoBundledURI aURI, mozilla::CORSMode aCORSMode)
-{
-  return aURI.IntoCssImage(aCORSMode).take();
-}
-
-MOZ_DEFINE_MALLOC_SIZE_OF(GeckoImageValueMallocSizeOf)
-
-size_t
-Gecko_ImageValue_SizeOfIncludingThis(mozilla::css::ImageValue* aImageValue)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  return aImageValue->SizeOfIncludingThis(GeckoImageValueMallocSizeOf);
-}
-
 void
 Gecko_SetLayerImageImageValue(nsStyleImage* aImage,
-                              mozilla::css::ImageValue* aImageValue)
+                              URLValue* aImageValue)
 {
   MOZ_ASSERT(aImage && aImageValue);
 
   RefPtr<nsStyleImageRequest> req =
     CreateStyleImageRequest(nsStyleImageRequest::Mode::Track, aImageValue);
   aImage->SetImageRequest(req.forget());
 }
 
@@ -1481,33 +1453,33 @@ void
 Gecko_SetCursorArrayLength(nsStyleUI* aStyleUI, size_t aLen)
 {
   aStyleUI->mCursorImages.Clear();
   aStyleUI->mCursorImages.SetLength(aLen);
 }
 
 void
 Gecko_SetCursorImageValue(nsCursorImage* aCursor,
-                          mozilla::css::ImageValue* aImageValue)
+                          URLValue* aImageValue)
 {
   MOZ_ASSERT(aCursor && aImageValue);
 
   aCursor->mImage =
     CreateStyleImageRequest(nsStyleImageRequest::Mode::Discard, aImageValue);
 }
 
 void
 Gecko_CopyCursorArrayFrom(nsStyleUI* aDest, const nsStyleUI* aSrc)
 {
   aDest->mCursorImages = aSrc->mCursorImages;
 }
 
 void
 Gecko_SetContentDataImageValue(nsStyleContentData* aContent,
-                               mozilla::css::ImageValue* aImageValue)
+                               URLValue* aImageValue)
 {
   MOZ_ASSERT(aContent && aImageValue);
 
   RefPtr<nsStyleImageRequest> req =
     CreateStyleImageRequest(nsStyleImageRequest::Mode::Track, aImageValue);
   aContent->SetImageRequest(req.forget());
 }
 
@@ -1579,17 +1551,17 @@ Gecko_GetGradientImageValue(const nsStyl
 void
 Gecko_SetListStyleImageNone(nsStyleList* aList)
 {
   aList->mListStyleImage = nullptr;
 }
 
 void
 Gecko_SetListStyleImageImageValue(nsStyleList* aList,
-                             mozilla::css::ImageValue* aImageValue)
+                                  URLValue* aImageValue)
 {
   MOZ_ASSERT(aList && aImageValue);
 
   aList->mListStyleImage =
     CreateStyleImageRequest(nsStyleImageRequest::Mode(0), aImageValue);
 }
 
 void
@@ -1647,27 +1619,27 @@ Gecko_CopyStyleGridTemplateValues(Unique
 {
   if (aOther) {
     *aGridTemplate = MakeUnique<nsStyleGridTemplate>(*aOther);
   } else {
     *aGridTemplate = nullptr;
   }
 }
 
-mozilla::css::GridTemplateAreasValue*
+GridTemplateAreasValue*
 Gecko_NewGridTemplateAreasValue(uint32_t aAreas, uint32_t aTemplates, uint32_t aColumns)
 {
-  RefPtr<mozilla::css::GridTemplateAreasValue> value = new mozilla::css::GridTemplateAreasValue;
+  RefPtr<GridTemplateAreasValue> value = new GridTemplateAreasValue;
   value->mNamedAreas.SetLength(aAreas);
   value->mTemplates.SetLength(aTemplates);
   value->mNColumns = aColumns;
   return value.forget().take();
 }
 
-NS_IMPL_THREADSAFE_FFI_REFCOUNTING(mozilla::css::GridTemplateAreasValue, GridTemplateAreasValue);
+NS_IMPL_THREADSAFE_FFI_REFCOUNTING(GridTemplateAreasValue, GridTemplateAreasValue);
 
 void
 Gecko_ClearAndResizeStyleContents(nsStyleContent* aContent, uint32_t aHowMany)
 {
   aContent->AllocateContents(aHowMany);
 }
 
 void
@@ -2032,45 +2004,45 @@ void
 Gecko_nsStyleSVG_CopyContextProperties(nsStyleSVG* aDst, const nsStyleSVG* aSrc)
 {
   aDst->mContextProps = aSrc->mContextProps;
   aDst->mContextPropsBits = aSrc->mContextPropsBits;
 }
 
 
 css::URLValue*
-Gecko_NewURLValue(ServoBundledURI aURI)
+Gecko_URLValue_Create(ServoBundledURI aURI, mozilla::CORSMode aCORSMode)
 {
-  RefPtr<css::URLValue> url = aURI.IntoCssUrl();
+  RefPtr<css::URLValue> url = aURI.IntoCssUrl(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);
 }
 
 void
-Gecko_GetComputedURLSpec(const URLValueData* aURL, nsCString* aOut)
+Gecko_GetComputedURLSpec(const URLValue* aURL, nsCString* aOut)
 {
   MOZ_ASSERT(aURL);
   MOZ_ASSERT(aOut);
   if (aURL->IsLocalRef()) {
     aOut->Assign(aURL->GetString());
     return;
   }
   Gecko_GetComputedImageURLSpec(aURL, aOut);
 }
 
 void
-Gecko_GetComputedImageURLSpec(const URLValueData* aURL, nsCString* aOut)
+Gecko_GetComputedImageURLSpec(const URLValue* aURL, nsCString* aOut)
 {
   // Image URIs don't serialize local refs as local.
   if (nsIURI* uri = aURL->GetURI()) {
     nsresult rv = uri->GetSpec(*aOut);
     if (NS_SUCCEEDED(rv)) {
       return;
     }
   }
@@ -2602,17 +2574,17 @@ LoadImportSheet(css::Loader* aLoader,
     RefPtr<StyleSheet> emptySheet =
       aParent->CreateEmptyChildSheet(media.forget());
     // Make a dummy URI if we don't have one because some methods assume
     // non-null URIs.
     if (!uri) {
       NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("about:invalid"));
     }
     emptySheet->SetURIs(uri, uri, uri);
-    emptySheet->SetPrincipal(aURL->mExtraData->GetPrincipal());
+    emptySheet->SetPrincipal(aURL->mExtraData->Principal());
     emptySheet->SetComplete();
     aParent->PrependStyleSheet(emptySheet);
     return emptySheet.forget();
   }
 
   RefPtr<StyleSheet> sheet =
     static_cast<StyleSheet*>(aParent->GetFirstChild());
   return sheet.forget();
@@ -2622,29 +2594,34 @@ StyleSheet*
 Gecko_LoadStyleSheet(css::Loader* aLoader,
                      StyleSheet* aParent,
                      SheetLoadData* aParentLoadData,
                      css::LoaderReusableStyleSheets* aReusableSheets,
                      ServoBundledURI aServoURL,
                      RawServoMediaListStrong aMediaList)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  RefPtr<css::URLValue> url = aServoURL.IntoCssUrl();
+
+  // The CORS mode in the URLValue is irrelevant here.
+  // (CORS_NONE is used for all imported sheets in Load::LoadChildSheet.)
+  RefPtr<css::URLValue> url = aServoURL.IntoCssUrl(CORS_NONE);
   return LoadImportSheet(aLoader, aParent, aParentLoadData, aReusableSheets,
                          url, aMediaList.Consume()).take();
 }
 
 void
 Gecko_LoadStyleSheetAsync(css::SheetLoadDataHolder* aParentData,
                           ServoBundledURI aServoURL,
                           RawServoMediaListStrong aMediaList,
                           RawServoImportRuleStrong aImportRule)
 {
   RefPtr<SheetLoadDataHolder> loadData = aParentData;
-  RefPtr<css::URLValue> urlVal = aServoURL.IntoCssUrl();
+  // The CORS mode in the URLValue is irrelevant here.
+  // (CORS_NONE is used for all imported sheets in Load::LoadChildSheet.)
+  RefPtr<css::URLValue> urlVal = aServoURL.IntoCssUrl(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());
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -39,17 +39,16 @@ namespace mozilla {
   enum FontFamilyType : uint8_t;
   class SharedFontList;
   enum class CSSPseudoElementType : uint8_t;
   struct Keyframe;
   struct StyleTransition;
   namespace css {
     class ErrorReporter;
     struct URLValue;
-    struct ImageValue;
     class LoaderReusableStyleSheets;
   };
   namespace dom {
     enum class IterationCompositeOperation : uint8_t;
   };
   enum class UpdateAnimationsTasks : uint8_t;
   struct LangGroupFontPrefs;
   class SeenPtrs;
@@ -109,20 +108,19 @@ const bool GECKO_IS_NIGHTLY = false;
 DEFINE_ARRAY_TYPE_FOR(uintptr_t);
 #undef DEFINE_ARRAY_TYPE_FOR
 
 extern "C" {
 
 class ServoBundledURI
 {
 public:
-  // NOTE(emilio): Not calling IntoCssUrl or IntoCssImage will cause to leak the
+  // NOTE(emilio): Not calling IntoCssUrl will cause to leak the
   // string, so don't do that :)
-  already_AddRefed<mozilla::css::URLValue> IntoCssUrl();
-  already_AddRefed<mozilla::css::ImageValue> IntoCssImage(mozilla::CORSMode);
+  already_AddRefed<mozilla::css::URLValue> IntoCssUrl(mozilla::CORSMode);
   mozilla::ServoRawOffsetArc<RustString> mURLString;
   mozilla::URLExtraData* mExtraData;
 };
 
 struct FontSizePrefs
 {
   void CopyFrom(const mozilla::LangGroupFontPrefs&);
   nscoord mDefaultVariableSize;
@@ -347,22 +345,18 @@ void Gecko_CopyCounterStyle(mozilla::Cou
                             const mozilla::CounterStylePtr* src);
 nsAtom* Gecko_CounterStyle_GetName(const mozilla::CounterStylePtr* ptr);
 const mozilla::AnonymousCounterStyle*
 Gecko_CounterStyle_GetAnonymous(const mozilla::CounterStylePtr* ptr);
 
 // background-image style.
 void Gecko_SetNullImageValue(nsStyleImage* image);
 void Gecko_SetGradientImageValue(nsStyleImage* image, nsStyleGradient* gradient);
-NS_DECL_THREADSAFE_FFI_REFCOUNTING(mozilla::css::ImageValue, ImageValue);
-mozilla::css::ImageValue* Gecko_ImageValue_Create(ServoBundledURI aURI,
-                                                  mozilla::CORSMode aCORSMode);
-size_t Gecko_ImageValue_SizeOfIncludingThis(mozilla::css::ImageValue* aImageValue);
 void Gecko_SetLayerImageImageValue(nsStyleImage* image,
-                                   mozilla::css::ImageValue* aImageValue);
+                                   mozilla::css::URLValue* image_value);
 
 void Gecko_SetImageElement(nsStyleImage* image, nsAtom* atom);
 void Gecko_CopyImageValueFrom(nsStyleImage* image, const nsStyleImage* other);
 void Gecko_InitializeImageCropRect(nsStyleImage* image);
 
 nsStyleGradient* Gecko_CreateGradient(uint8_t shape,
                                       uint8_t size,
                                       bool repeating,
@@ -372,27 +366,27 @@ nsStyleGradient* Gecko_CreateGradient(ui
 
 const nsStyleImageRequest* Gecko_GetImageRequest(const nsStyleImage* image);
 nsAtom* Gecko_GetImageElement(const nsStyleImage* image);
 const nsStyleGradient* Gecko_GetGradientImageValue(const nsStyleImage* image);
 
 // list-style-image style.
 void Gecko_SetListStyleImageNone(nsStyleList* style_struct);
 void Gecko_SetListStyleImageImageValue(nsStyleList* style_struct,
-                                  mozilla::css::ImageValue* aImageValue);
+                                  mozilla::css::URLValue* aImageValue);
 void Gecko_CopyListStyleImageFrom(nsStyleList* dest, const nsStyleList* src);
 
 // cursor style.
 void Gecko_SetCursorArrayLength(nsStyleUI* ui, size_t len);
 void Gecko_SetCursorImageValue(nsCursorImage* aCursor,
-                               mozilla::css::ImageValue* aImageValue);
+                               mozilla::css::URLValue* aImageValue);
 void Gecko_CopyCursorArrayFrom(nsStyleUI* dest, const nsStyleUI* src);
 
 void Gecko_SetContentDataImageValue(nsStyleContentData* aList,
-                                    mozilla::css::ImageValue* aImageValue);
+                                    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);
@@ -542,20 +536,20 @@ void Gecko_nsStyleSVGPaint_CopyFrom(nsSt
 void Gecko_nsStyleSVGPaint_SetURLValue(nsStyleSVGPaint* paint, mozilla::css::URLValue* uri);
 void Gecko_nsStyleSVGPaint_Reset(nsStyleSVGPaint* paint);
 
 void Gecko_nsStyleSVG_SetDashArrayLength(nsStyleSVG* svg, uint32_t len);
 void Gecko_nsStyleSVG_CopyDashArray(nsStyleSVG* dst, const nsStyleSVG* src);
 void Gecko_nsStyleSVG_SetContextPropertiesLength(nsStyleSVG* svg, uint32_t len);
 void Gecko_nsStyleSVG_CopyContextProperties(nsStyleSVG* dst, const nsStyleSVG* src);
 
-mozilla::css::URLValue* Gecko_NewURLValue(ServoBundledURI uri);
+mozilla::css::URLValue* Gecko_URLValue_Create(ServoBundledURI uri, mozilla::CORSMode aCORSMode);
 size_t Gecko_URLValue_SizeOfIncludingThis(mozilla::css::URLValue* url);
-void Gecko_GetComputedURLSpec(const mozilla::css::URLValueData* url, nsCString* spec);
-void Gecko_GetComputedImageURLSpec(const mozilla::css::URLValueData* url, nsCString* spec);
+void Gecko_GetComputedURLSpec(const mozilla::css::URLValue* url, 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);
 
 void Gecko_FillAllImageLayers(nsStyleImageLayers* layers, uint32_t max_len);
 NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsStyleCoord::Calc, Calc);
 
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -475,19 +475,17 @@ raw-lines = [
     "pub type ComputedStyleBorrowed<'a> = &'a ::properties::ComputedValues;",
     "pub type ComputedStyleBorrowedOrNull<'a> = Option<&'a ::properties::ComputedValues>;",
     "pub type ServoComputedDataBorrowed<'a> = &'a ServoComputedData;",
     "pub type RawServoAnimationValueTableBorrowed<'a> = &'a ();"
 ]
 whitelist-functions = ["Servo_.*", "Gecko_.*"]
 structs-types = [
     "mozilla::css::GridTemplateAreasValue",
-    "mozilla::css::ImageValue",
     "mozilla::css::URLValue",
-    "mozilla::css::URLValueData",
     "mozilla::dom::CallerType",
     "mozilla::dom::ShadowRoot",
     "mozilla::AnonymousCounterStyle",
     "mozilla::AtomArray",
     "mozilla::CORSMode",
     "mozilla::FontStretch",
     "mozilla::FontSlantStyle",
     "mozilla::FontWeight",
--- a/layout/style/URLExtraData.h
+++ b/layout/style/URLExtraData.h
@@ -30,31 +30,32 @@ struct URLExtraData
     , mReferrer(std::move(aReferrer))
     , mReferrerPolicy(aReferrerPolicy)
     , mPrincipal(std::move(aPrincipal))
       // When we hold the URI data of a style sheet, mReferrer is always
       // equal to the sheet URI.
     , mIsChrome(mReferrer ? dom::IsChromeURI(mReferrer) : false)
   {
     MOZ_ASSERT(mBaseURI);
+    MOZ_ASSERT(mPrincipal);
   }
 
   URLExtraData(nsIURI* aBaseURI, nsIURI* aReferrer, nsIPrincipal* aPrincipal,
                net::ReferrerPolicy aReferrerPolicy)
     : URLExtraData(do_AddRef(aBaseURI),
                    do_AddRef(aReferrer),
                    do_AddRef(aPrincipal),
                    aReferrerPolicy) {}
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(URLExtraData)
 
   nsIURI* BaseURI() const { return mBaseURI; }
   nsIURI* GetReferrer() const { return mReferrer; }
   net::ReferrerPolicy GetReferrerPolicy() const { return mReferrerPolicy;}
-  nsIPrincipal* GetPrincipal() const { return mPrincipal; }
+  nsIPrincipal* Principal() const { return mPrincipal; }
 
   static URLExtraData* Dummy() {
     MOZ_ASSERT(sDummy);
     return sDummy;
   }
   static void InitDummy();
   static void ReleaseDummy();
 
--- a/layout/style/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -880,96 +880,73 @@ nsCSSValue::Array::SizeOfIncludingThis(m
 {
   size_t n = aMallocSizeOf(this);
   for (size_t i = 0; i < mCount; i++) {
     n += mArray[i].SizeOfExcludingThis(aMallocSizeOf);
   }
   return n;
 }
 
-css::URLValueData::URLValueData(already_AddRefed<nsIURI> aURI,
-                                ServoRawOffsetArc<RustString> aString,
-                                already_AddRefed<URLExtraData> aExtraData,
-                                CORSMode aCORSMode)
-  : mURI(std::move(aURI))
-  , mExtraData(std::move(aExtraData))
-  , mURIResolved(true)
-  , mString(aString)
-  , mCORSMode(aCORSMode)
+css::URLValue::~URLValue()
 {
-  MOZ_ASSERT(mExtraData);
-  MOZ_ASSERT(mExtraData->GetPrincipal());
-}
+  if (mLoadID != 0) {
+    ImageLoader::DeregisterCSSImageFromAllLoaders(this);
+  }
 
-css::URLValueData::URLValueData(ServoRawOffsetArc<RustString> aString,
-                                already_AddRefed<URLExtraData> aExtraData,
-                                CORSMode aCORSMode)
-  : mExtraData(std::move(aExtraData))
-  , mURIResolved(false)
-  , mString(aString)
-  , mCORSMode(aCORSMode)
-{
-  MOZ_ASSERT(mExtraData);
-  MOZ_ASSERT(mExtraData->GetPrincipal());
-}
-
-css::URLValueData::~URLValueData()
-{
   Servo_ReleaseArcStringData(&mString);
 }
 
 bool
-css::URLValueData::Equals(const URLValueData& aOther) const
+css::URLValue::Equals(const URLValue& aOther) const
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   bool eq;
   const URLExtraData* self = mExtraData;
   const URLExtraData* other = aOther.mExtraData;
   return GetString() == aOther.GetString() &&
           (GetURI() == aOther.GetURI() || // handles null == null
            (mURI && aOther.mURI &&
             NS_SUCCEEDED(mURI->Equals(aOther.mURI, &eq)) &&
             eq)) &&
           (self->BaseURI() == other->BaseURI() ||
            (NS_SUCCEEDED(self->BaseURI()->Equals(other->BaseURI(), &eq)) &&
             eq)) &&
-          (self->GetPrincipal() == other->GetPrincipal() ||
-           self->GetPrincipal()->Equals(other->GetPrincipal())) &&
+          self->Principal()->Equals(other->Principal()) &&
           IsLocalRef() == aOther.IsLocalRef();
 }
 
 bool
-css::URLValueData::DefinitelyEqualURIs(const URLValueData& aOther) const
+css::URLValue::DefinitelyEqualURIs(const URLValue& aOther) const
 {
   if (mExtraData->BaseURI() != aOther.mExtraData->BaseURI()) {
     return false;
   }
   return GetString() == aOther.GetString();
 }
 
 bool
-css::URLValueData::DefinitelyEqualURIsAndPrincipal(
-    const URLValueData& aOther) const
+css::URLValue::DefinitelyEqualURIsAndPrincipal(
+    const URLValue& aOther) const
 {
-  return mExtraData->GetPrincipal() == aOther.mExtraData->GetPrincipal() &&
+  return mExtraData->Principal() == aOther.mExtraData->Principal() &&
          DefinitelyEqualURIs(aOther);
 }
 
 nsDependentCSubstring
-css::URLValueData::GetString() const
+css::URLValue::GetString() const
 {
   const uint8_t* chars;
   uint32_t len;
   Servo_GetArcStringData(mString.mPtr, &chars, &len);
   return nsDependentCSubstring(reinterpret_cast<const char*>(chars), len);
 }
 
 nsIURI*
-css::URLValueData::GetURI() const
+css::URLValue::GetURI() const
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!mURIResolved) {
     MOZ_ASSERT(!mURI);
     nsCOMPtr<nsIURI> newURI;
     NS_NewURI(getter_AddRefs(newURI),
               GetString(),
@@ -977,43 +954,43 @@ css::URLValueData::GetURI() const
     mURI = newURI.forget();
     mURIResolved = true;
   }
 
   return mURI;
 }
 
 bool
-css::URLValueData::IsLocalRef() const
+css::URLValue::IsLocalRef() const
 {
   if (mIsLocalRef.isNothing()) {
     // IsLocalRefURL is O(N), use it only when IsLocalRef is called.
     mIsLocalRef.emplace(nsContentUtils::IsLocalRefURL(GetString()));
   }
   return mIsLocalRef.value();
 }
 
 bool
-css::URLValueData::HasRef() const
+css::URLValue::HasRef() const
 {
   if (IsLocalRef()) {
     return true;
   }
 
   if (nsIURI* uri = GetURI()) {
     nsAutoCString ref;
     nsresult rv = uri->GetRef(ref);
     return NS_SUCCEEDED(rv) && !ref.IsEmpty();
   }
 
   return false;
 }
 
 already_AddRefed<nsIURI>
-css::URLValueData::ResolveLocalRef(nsIURI* aURI) const
+css::URLValue::ResolveLocalRef(nsIURI* aURI) const
 {
   nsCOMPtr<nsIURI> result = GetURI();
 
   if (result && IsLocalRef()) {
     nsCString ref;
     mURI->GetRef(ref);
 
     nsresult rv = NS_MutateURI(aURI)
@@ -1025,104 +1002,68 @@ css::URLValueData::ResolveLocalRef(nsIUR
       result = aURI;
     }
   }
 
   return result.forget();
 }
 
 already_AddRefed<nsIURI>
-css::URLValueData::ResolveLocalRef(nsIContent* aContent) const
+css::URLValue::ResolveLocalRef(nsIContent* aContent) const
 {
   nsCOMPtr<nsIURI> url = aContent->GetBaseURI();
   return ResolveLocalRef(url);
 }
 
 void
-css::URLValueData::GetSourceString(nsString& aRef) const
+css::URLValue::GetSourceString(nsString& aRef) const
 {
   nsIURI* uri = GetURI();
   if (!uri) {
     aRef.Truncate();
     return;
   }
 
   nsCString cref;
   if (IsLocalRef()) {
     // XXXheycam It's possible we can just return mString in this case, since
-    // it should be the "#fragment" string the URLValueData was created with.
+    // it should be the "#fragment" string the URLValue was created with.
     uri->GetRef(cref);
     cref.Insert('#', 0);
   } else {
     // It's not entirely clear how to best handle failure here. Ensuring the
     // string is empty seems safest.
     nsresult rv = uri->GetSpec(cref);
     if (NS_FAILED(rv)) {
       cref.Truncate();
     }
   }
 
   aRef = NS_ConvertUTF8toUTF16(cref);
 }
 
-bool
-css::URLValueData::EqualsExceptRef(nsIURI* aURI) const
-{
-  nsIURI* uri = GetURI();
-  if (!uri) {
-    return false;
-  }
-
-  bool ret = false;
-  uri->EqualsExceptRef(aURI, &ret);
-  return ret;
-}
-
 size_t
-css::URLValueData::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
+css::URLValue::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
 {
   // Measurement of the following members may be added later if DMD finds it
   // is worthwhile:
   // - mURI
   // - mString
   // - mExtraData
-  return 0;
-}
 
-size_t
-css::URLValue::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
-{
   // Only measure it if it's unshared, to avoid double-counting.
   size_t n = 0;
   if (mRefCnt <= 1) {
     n += aMallocSizeOf(this);
-    n += URLValueData::SizeOfExcludingThis(aMallocSizeOf);
   }
   return n;
 }
 
-css::ImageValue::ImageValue(nsIURI* aURI,
-                            ServoRawOffsetArc<RustString> aString,
-                            already_AddRefed<URLExtraData> aExtraData,
-                            nsIDocument* aDocument,
-                            CORSMode aCORSMode)
-  : URLValueData(do_AddRef(aURI), aString, std::move(aExtraData), aCORSMode)
-{
-  LoadImage(aDocument);
-}
-
-css::ImageValue::ImageValue(ServoRawOffsetArc<RustString> aString,
-                            already_AddRefed<URLExtraData> aExtraData,
-                            CORSMode aCORSMode)
-  : URLValueData(aString, std::move(aExtraData), aCORSMode)
-{
-}
-
 imgRequestProxy*
-css::ImageValue::LoadImage(nsIDocument* aDocument)
+css::URLValue::LoadImage(nsIDocument* aDocument)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   static uint64_t sNextLoadID = 1;
 
   if (mLoadID == 0) {
     mLoadID = sNextLoadID++;
   }
@@ -1132,42 +1073,27 @@ css::ImageValue::LoadImage(nsIDocument* 
   // and clone it to aDocument.
   nsIDocument* loadingDoc = aDocument->GetOriginalDocument();
   if (!loadingDoc) {
     loadingDoc = aDocument;
   }
 
   // Kick off the load in the loading document.
   ImageLoader::LoadImage(GetURI(),
-                         mExtraData->GetPrincipal(),
+                         mExtraData->Principal(),
                          mExtraData->GetReferrer(),
                          mExtraData->GetReferrerPolicy(),
                          loadingDoc,
                          this,
                          mCORSMode);
 
   // Register the image in the document that's using it.
   return aDocument->StyleImageLoader()->RegisterCSSImage(this);
 }
 
-css::ImageValue::~ImageValue()
-{
-  if (mLoadID != 0) {
-    ImageLoader::DeregisterCSSImageFromAllLoaders(this);
-  }
-}
-
-size_t
-css::ImageValue::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
-{
-  size_t n = aMallocSizeOf(this);
-  n += css::URLValueData::SizeOfExcludingThis(aMallocSizeOf);
-  return n;
-}
-
 size_t
 mozilla::css::GridTemplateAreasValue::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
 {
   // Only measure it if it's unshared, to avoid double-counting.
   size_t n = 0;
   if (mRefCnt <= 1) {
     n += aMallocSizeOf(this);
     n += mNamedAreas.ShallowSizeOfExcludingThis(aMallocSizeOf);
--- a/layout/style/nsCSSValue.h
+++ b/layout/style/nsCSSValue.h
@@ -88,81 +88,77 @@ class CSSStyleSheet;
       dest->member_ = clm_clone;                                               \
       dest = clm_clone;                                                        \
     }                                                                          \
   }
 
 namespace mozilla {
 namespace css {
 
-struct URLValueData
+struct URLValue final
 {
-protected:
-  // Methods are not inline because using an nsIPrincipal means requiring
-  // caps, which leads to REQUIRES hell, since this header is included all
-  // over.
-
-  // aString must not be null.
-  // principal of aExtraData must not be null.
+public:
+  // aString and aExtraData must not be null.
+  //
   // Construct with a base URI; this will create the actual URI lazily from
   // aString and aExtraData.
-  URLValueData(ServoRawOffsetArc<RustString> aString,
-               already_AddRefed<URLExtraData> aExtraData,
-               CORSMode aCORSMode);
-  // Construct with the actual URI.
-  URLValueData(already_AddRefed<nsIURI> aURI,
-               ServoRawOffsetArc<RustString> aString,
-               already_AddRefed<URLExtraData> aExtraData,
-               CORSMode aCORSMode);
+  URLValue(ServoRawOffsetArc<RustString> aString,
+           already_AddRefed<URLExtraData> aExtraData,
+           CORSMode aCORSMode)
+    : mExtraData(std::move(aExtraData))
+    , mURIResolved(false)
+    , mString(aString)
+    , mCORSMode(aCORSMode)
+  {
+    MOZ_ASSERT(mExtraData);
+  }
 
-public:
-  // Returns true iff all fields of the two URLValueData objects are equal.
+  // Returns true iff all fields of the two URLValue objects are equal.
   //
   // Only safe to call on the main thread, since this will call Equals on the
-  // nsIURI and nsIPrincipal objects stored on the URLValueData objects.
-  bool Equals(const URLValueData& aOther) const;
+  // nsIURI and nsIPrincipal objects stored on the URLValue objects.
+  bool Equals(const URLValue& aOther) const;
 
   // Returns true iff we know for sure, by comparing the mBaseURI pointer,
   // the specified url() value mString, and the mIsLocalRef, that these
-  // two URLValueData objects represent the same computed url() value.
+  // two URLValue objects represent the same computed url() value.
   //
   // Doesn't look at mReferrer or mOriginPrincipal.
   //
   // Safe to call from any thread.
-  bool DefinitelyEqualURIs(const URLValueData& aOther) const;
+  bool DefinitelyEqualURIs(const URLValue& aOther) const;
 
   // Smae as DefinitelyEqualURIs but additionally compares the nsIPrincipal
-  // pointers of the two URLValueData objects.
-  bool DefinitelyEqualURIsAndPrincipal(const URLValueData& aOther) const;
+  // pointers of the two URLValue objects.
+  bool DefinitelyEqualURIsAndPrincipal(const URLValue& aOther) const;
 
   nsIURI* GetURI() const;
 
   bool IsLocalRef() const;
 
   bool HasRef() const;
 
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(URLValueData)
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(URLValue)
 
   // When matching a url with mIsLocalRef set, resolve it against aURI;
   // Otherwise, ignore aURL and return mURL directly.
   already_AddRefed<nsIURI> ResolveLocalRef(nsIURI* aURI) const;
   already_AddRefed<nsIURI> ResolveLocalRef(nsIContent* aContent) const;
 
   // Serializes mURI as a computed URI value, taking into account mIsLocalRef
   // and serializing just the fragment if true.
   void GetSourceString(nsString& aRef) const;
 
-  bool EqualsExceptRef(nsIURI* aURI) const;
+  nsDependentCSubstring GetString() const;
+
+  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
-  bool IsStringEmpty() const
-  {
-    return GetString().IsEmpty();
-  }
+  imgRequestProxy* LoadImage(nsIDocument* aDocument);
 
-  nsDependentCSubstring GetString() const;
+  uint64_t LoadID() const { return mLoadID; }
 
 private:
   // mURI stores the lazily resolved URI.  This may be null if the URI is
   // invalid, even once resolved.
   mutable nsCOMPtr<nsIURI> mURI;
 
 public:
   RefPtr<URLExtraData> mExtraData;
@@ -170,96 +166,34 @@ public:
 private:
   mutable bool mURIResolved;
 
   // mIsLocalRef is set when url starts with a U+0023 number sign(#) character.
   mutable Maybe<bool> mIsLocalRef;
 
   mozilla::ServoRawOffsetArc<RustString> mString;
 
-protected:
   const CORSMode mCORSMode;
 
-  virtual ~URLValueData();
-
-  size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
-
-private:
-  URLValueData(const URLValueData& aOther) = delete;
-  URLValueData& operator=(const URLValueData& aOther) = delete;
-
-  friend struct ImageValue;
-};
-
-struct URLValue final : public URLValueData
-{
-  URLValue(ServoRawOffsetArc<RustString> aString,
-           already_AddRefed<URLExtraData> aExtraData)
-    : URLValueData(aString, std::move(aExtraData), CORSMode::CORS_NONE)
-  { }
-
-  URLValue(const URLValue&) = delete;
-  URLValue& operator=(const URLValue&) = delete;
-
-  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
-};
-
-struct ImageValue final : public URLValueData
-{
-  // Not making the constructor and destructor inline because that would
-  // force us to include imgIRequest.h, which leads to REQUIRES hell, since
-  // this header is included all over.
-  //
-  // This constructor is only safe to call from the main thread.
-  ImageValue(nsIURI* aURI, const nsAString& aString,
-             already_AddRefed<URLExtraData> aExtraData,
-             nsIDocument* aDocument,
-             CORSMode aCORSMode);
-
-  // This constructor is only safe to call from the main thread.
-  ImageValue(nsIURI* aURI, ServoRawOffsetArc<RustString> aString,
-             already_AddRefed<URLExtraData> aExtraData,
-             nsIDocument* aDocument,
-             CORSMode aCORSMode);
-
-  // This constructor is safe to call from any thread, but Initialize
-  // must be called later for the object to be useful.
-  ImageValue(const nsAString& aString,
-             already_AddRefed<URLExtraData> aExtraData,
-             CORSMode aCORSMode);
-
-  // This constructor is safe to call from any thread, but Initialize
-  // must be called later for the object to be useful.
-  ImageValue(ServoRawOffsetArc<RustString> aURIString,
-             already_AddRefed<URLExtraData> aExtraData,
-             CORSMode aCORSMode);
-
-  ImageValue(const ImageValue&) = delete;
-  ImageValue& operator=(const ImageValue&) = delete;
-
-  imgRequestProxy* LoadImage(nsIDocument* aDocument);
-
-  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
-
-  uint64_t LoadID() const { return mLoadID; }
-
-protected:
-  ~ImageValue();
-
-private:
-  // A unique, non-reused ID value for this ImageValue over the life of the
+  // A unique, non-reused ID value for this URLValue over the life of the
   // process.  This value is only valid after LoadImage has been called.
   //
   // We use this as a key in some tables in ImageLoader.  This is better than
   // using the pointer value of the ImageValue object, since we can sometimes
   // delete ImageValues OMT but cannot update the ImageLoader tables until
   // we're back on the main thread.  So to avoid dangling pointers that might
   // get re-used by the time we want to update the ImageLoader tables, we use
   // these IDs.
   uint64_t mLoadID = 0;
+
+  ~URLValue();
+
+private:
+  URLValue(const URLValue& aOther) = delete;
+  URLValue& operator=(const URLValue& aOther) = delete;
 };
 
 struct GridNamedArea {
   nsString mName;
   uint32_t mColumnStart;
   uint32_t mColumnEnd;
   uint32_t mRowStart;
   uint32_t mRowEnd;
@@ -435,18 +369,16 @@ struct nsCSSValueSharedList;
 struct nsCSSValuePairList;
 struct nsCSSValuePairList_heap;
 
 class nsCSSValue {
 public:
   struct Array;
   friend struct Array;
 
-  friend struct mozilla::css::ImageValue;
-
   // for valueless units only (null, auto, inherit, none, all, normal)
   explicit nsCSSValue(nsCSSUnit aUnit = eCSSUnit_Null)
     : mUnit(aUnit)
   {
     MOZ_ASSERT(aUnit <= eCSSUnit_DummyInherit, "not a valueless unit");
   }
 
   nsCSSValue(int32_t aValue, nsCSSUnit aUnit);
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -657,17 +657,17 @@ AddImageURL(nsIURI& aURI, nsTArray<nsStr
     return;
   }
 
   aURLs.AppendElement(NS_ConvertUTF8toUTF16(spec));
 }
 
 
 static void
-AddImageURL(const css::URLValueData& aURL, nsTArray<nsString>& aURLs)
+AddImageURL(const css::URLValue& aURL, nsTArray<nsString>& aURLs)
 {
   if (aURL.IsLocalRef()) {
     return;
   }
 
   if (nsIURI* uri = aURL.GetURI()) {
     AddImageURL(*uri, aURLs);
   }
@@ -1691,25 +1691,25 @@ nsComputedDOMStyle::SetValueToPosition(
 
   RefPtr<nsROCSSPrimitiveValue> valY = new nsROCSSPrimitiveValue;
   SetValueToPositionCoord(aPosition.mYPosition, valY);
   aValueList->AppendCSSValue(valY.forget());
 }
 
 
 void
-nsComputedDOMStyle::SetValueToURLValue(const css::URLValueData* aURL,
+nsComputedDOMStyle::SetValueToURLValue(const css::URLValue* aURL,
                                        nsROCSSPrimitiveValue* aValue)
 {
   if (!aURL) {
     aValue->SetIdent(eCSSKeyword_none);
     return;
   }
 
-  // If we have a usable nsIURI in the URLValueData, and the url() wasn't
+  // If we have a usable nsIURI in the URLValue, and the url() wasn't
   // a fragment-only URL, serialize the nsIURI.
   if (!aURL->IsLocalRef()) {
     if (nsIURI* uri = aURL->GetURI()) {
       aValue->SetURI(uri);
       return;
     }
   }
 
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -465,17 +465,17 @@ private:
                                 const mozilla::StyleComplexColor& aColor);
   void SetValueForWidgetColor(nsROCSSPrimitiveValue* aValue,
                               const mozilla::StyleComplexColor& aColor,
                               mozilla::StyleAppearance aWidgetType);
   void SetValueToPositionCoord(const mozilla::Position::Coord& aCoord,
                                nsROCSSPrimitiveValue* aValue);
   void SetValueToPosition(const mozilla::Position& aPosition,
                           nsDOMCSSValueList* aValueList);
-  void SetValueToURLValue(const mozilla::css::URLValueData* aURL,
+  void SetValueToURLValue(const mozilla::css::URLValue* aURL,
                           nsROCSSPrimitiveValue* aValue);
 
   /**
    * A method to get a percentage base for a percentage value.  Returns true
    * if a percentage base value was determined, false otherwise.
    */
   typedef bool (nsComputedDOMStyle::*PercentageBaseGetter)(nscoord&);
 
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -54,26 +54,26 @@ using namespace mozilla::dom;
 static constexpr size_t kStyleStructSizeLimit = 504;
 #define STYLE_STRUCT(name_) \
   static_assert(sizeof(nsStyle##name_) <= kStyleStructSizeLimit, \
                 "nsStyle" #name_ " became larger than the size limit");
 #include "nsStyleStructList.h"
 #undef STYLE_STRUCT
 
 static bool
-DefinitelyEqualURIs(css::URLValueData* aURI1,
-                    css::URLValueData* aURI2)
+DefinitelyEqualURIs(css::URLValue* aURI1,
+                    css::URLValue* aURI2)
 {
   return aURI1 == aURI2 ||
          (aURI1 && aURI2 && aURI1->DefinitelyEqualURIs(*aURI2));
 }
 
 static bool
-DefinitelyEqualURIsAndPrincipal(css::URLValueData* aURI1,
-                                css::URLValueData* aURI2)
+DefinitelyEqualURIsAndPrincipal(css::URLValue* aURI1,
+                                css::URLValue* aURI2)
 {
   return aURI1 == aURI2 ||
          (aURI1 && aURI2 && aURI1->DefinitelyEqualURIsAndPrincipal(*aURI2));
 }
 
 static bool
 DefinitelyEqualImages(nsStyleImageRequest* aRequest1,
                       nsStyleImageRequest* aRequest2)
@@ -1246,17 +1246,17 @@ nsStyleSVGReset::nsStyleSVGReset(const n
 void
 nsStyleSVGReset::FinishStyle(nsPresContext* aPresContext, const nsStyleSVGReset* aOldStyle)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, mMask) {
     nsStyleImage& image = mMask.mLayers[i].mImage;
     if (image.GetType() == eStyleImageType_Image) {
-      css::URLValueData* url = image.GetURLValue();
+      css::URLValue* url = image.GetURLValue();
       // If the url is a local ref, it must be a <mask-resource>, so we don't
       // need to resolve the style image.
       if (url->IsLocalRef()) {
         continue;
       }
 #if 0
       // XXX The old style system also checks whether this is a reference to
       // the current document with reference, but it doesn't seem to be a
@@ -2078,17 +2078,17 @@ private:
   Mode mModeFlags;
   // Since we always dispatch this runnable to the main thread, these will be
   // released on the main thread when the runnable itself is released.
   RefPtr<imgRequestProxy> mRequestProxy;
   RefPtr<ImageTracker> mImageTracker;
 };
 
 nsStyleImageRequest::nsStyleImageRequest(Mode aModeFlags,
-                                         css::ImageValue* aImageValue)
+                                         css::URLValue* aImageValue)
   : mImageValue(aImageValue)
   , mModeFlags(aModeFlags)
   , mResolved(false)
 {
 }
 
 nsStyleImageRequest::~nsStyleImageRequest()
 {
@@ -2660,17 +2660,17 @@ nsStyleImage::GetImageURI() const
   if (mType != eStyleImageType_Image) {
     return nullptr;
   }
 
   nsCOMPtr<nsIURI> uri = mImage->GetImageURI();
   return uri.forget();
 }
 
-css::URLValueData*
+css::URLValue*
 nsStyleImage::GetURLValue() const
 {
   if (mType == eStyleImageType_Image) {
     return mImage->GetImageValue();
   } else if (mType == eStyleImageType_URL) {
     return mURLValue;
   }
 
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -214,25 +214,23 @@ private:
  * This can be called from any thread.  The nsStyleImageRequest is not
  * considered "resolved" at this point, and the Resolve() method must be called
  * later to initiate the image load and make calls to get() valid.
  *
  * Calls to TrackImage(), UntrackImage(), LockImage(), UnlockImage() and
  * RequestDiscard() are made to the imgRequestProxy and ImageTracker as
  * appropriate, according to the mode flags passed in to the constructor.
  *
- * The constructor receives a css::ImageValue to represent the url()
+ * The constructor receives a css::URLValue to represent the url()
  * information, which is held on to for the comparisons done in
  * DefinitelyEquals().
  */
 class nsStyleImageRequest
 {
 public:
-  typedef mozilla::css::URLValueData URLValueData;
-
   // Flags describing whether the imgRequestProxy must be tracked in the
   // ImageTracker, whether LockImage/UnlockImage calls will be made
   // when obtaining and releasing the imgRequestProxy, and whether
   // RequestDiscard will be called on release.
   enum class Mode : uint8_t {
     // The imgRequestProxy will be added to the ImageTracker when resolved
     // Without this flag, the nsStyleImageRequest itself will call LockImage/
     // UnlockImage on the imgRequestProxy, rather than leaving locking to the
@@ -246,47 +244,47 @@ public:
     // the nsStyleImageRequest is going away.
     //
     // This is currently used only for cursor images.
     Discard = 0x2,
   };
 
   // Can be called from any thread, but Resolve() must be called later
   // on the main thread before get() can be used.
-  nsStyleImageRequest(Mode aModeFlags, mozilla::css::ImageValue* aImageValue);
+  nsStyleImageRequest(Mode aModeFlags, mozilla::css::URLValue* aImageValue);
 
   bool Resolve(nsPresContext*, const nsStyleImageRequest* aOldImageRequest);
   bool IsResolved() const { return mResolved; }
 
   imgRequestProxy* get() {
     MOZ_ASSERT(IsResolved(), "Resolve() must be called first");
     MOZ_ASSERT(NS_IsMainThread());
     return mRequestProxy.get();
   }
   const imgRequestProxy* get() const {
     return const_cast<nsStyleImageRequest*>(this)->get();
   }
 
-  // Returns whether the ImageValue objects in the two nsStyleImageRequests
-  // return true from URLValueData::DefinitelyEqualURIs.
+  // Returns whether the URLValue objects in the two nsStyleImageRequests
+  // return true from URLValue::DefinitelyEqualURIs.
   bool DefinitelyEquals(const nsStyleImageRequest& aOther) const;
 
-  mozilla::css::ImageValue* GetImageValue() const { return mImageValue; }
+  mozilla::css::URLValue* GetImageValue() const { return mImageValue; }
 
   already_AddRefed<nsIURI> GetImageURI() const;
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsStyleImageRequest);
 
 private:
   ~nsStyleImageRequest();
   nsStyleImageRequest& operator=(const nsStyleImageRequest& aOther) = delete;
 
   void MaybeTrackAndLock();
 
   RefPtr<imgRequestProxy> mRequestProxy;
-  RefPtr<mozilla::css::ImageValue> mImageValue;
+  RefPtr<mozilla::css::URLValue> mImageValue;
   RefPtr<mozilla::dom::ImageTracker> mImageTracker;
 
   // Cache DocGroup for dispatching events in the destructor.
   RefPtr<mozilla::dom::DocGroup> mDocGroup;
 
   Mode mModeFlags;
   bool mResolved;
 };
@@ -330,18 +328,17 @@ private:
  * (3) An element within a document, or an <img>, <video>, or <canvas> element
  *     not in a document.
  * (*) Optionally a crop rect can be set to paint a partial (rectangular)
  * region of an image. (Currently, this feature is only supported with an
  * image of type (1)).
  */
 struct nsStyleImage
 {
-  typedef mozilla::css::URLValue     URLValue;
-  typedef mozilla::css::URLValueData URLValueData;
+  typedef mozilla::css::URLValue URLValue;
 
   nsStyleImage();
   ~nsStyleImage();
   nsStyleImage(const nsStyleImage& aOther);
   nsStyleImage& operator=(const nsStyleImage& aOther);
 
   void SetNull();
   void SetImageRequest(already_AddRefed<nsStyleImageRequest> aImage);
@@ -385,17 +382,17 @@ struct nsStyleImage
   const mozilla::UniquePtr<nsStyleSides>& GetCropRect() const {
     NS_ASSERTION(mType == eStyleImageType_Image,
                  "Only image data can have a crop rect");
     return mCropRect;
   }
 
   already_AddRefed<nsIURI> GetImageURI() const;
 
-  URLValueData* GetURLValue() const;
+  URLValue* GetURLValue() const;
 
   /**
    * Compute the actual crop rect in pixels, using the source image bounds.
    * The computation involves converting percentage unit to pixel unit and
    * clamping each side value to fit in the source image bounds.
    * @param aActualCropRect the computed actual crop rect.
    * @param aIsEntireImage true iff |aActualCropRect| is identical to the
    * source image bounds.
--- a/layout/svg/SVGObserverUtils.cpp
+++ b/layout/svg/SVGObserverUtils.cpp
@@ -22,17 +22,17 @@
 #include "SVGTextPathElement.h"
 #include "SVGUseElement.h"
 #include "ImageLoader.h"
 #include "mozilla/net/ReferrerPolicy.h"
 
 using namespace mozilla::dom;
 
 static already_AddRefed<URLAndReferrerInfo>
-ResolveURLUsingLocalRef(nsIFrame* aFrame, const css::URLValueData* aURL)
+ResolveURLUsingLocalRef(nsIFrame* aFrame, const css::URLValue* aURL)
 {
   MOZ_ASSERT(aFrame);
 
   if (!aURL) {
     return nullptr;
   }
 
   nsCOMPtr<nsIURI> uri = aURL->GetURI();
@@ -795,17 +795,17 @@ private:
 NS_IMPL_ISUPPORTS(SVGMaskObserverList, nsISupports)
 
 SVGMaskObserverList::SVGMaskObserverList(nsIFrame* aFrame)
   : mFrame(aFrame)
 {
   const nsStyleSVGReset *svgReset = aFrame->StyleSVGReset();
 
   for (uint32_t i = 0; i < svgReset->mMask.mImageCount; i++) {
-    css::URLValueData* data = svgReset->mMask.mLayers[i].mImage.GetURLValue();
+    css::URLValue* data = svgReset->mMask.mLayers[i].mImage.GetURLValue();
     RefPtr<URLAndReferrerInfo> maskUri = ResolveURLUsingLocalRef(aFrame, data);
 
     bool hasRef = false;
     if (maskUri) {
       maskUri->GetURI()->GetHasRef(&hasRef);
     }
 
     // Accrording to maskUri, nsSVGPaintingProperty's ctor may trigger an
--- a/servo/components/style/gecko/conversions.rs
+++ b/servo/components/style/gecko/conversions.rs
@@ -220,23 +220,23 @@ fn line_direction(horizontal: LengthOrPe
 }
 
 impl nsStyleImage {
     /// Set a given Servo `Image` value into this `nsStyleImage`.
     pub fn set(&mut self, image: Image) {
         match image {
             GenericImage::Gradient(boxed_gradient) => self.set_gradient(*boxed_gradient),
             GenericImage::Url(ref url) => unsafe {
-                bindings::Gecko_SetLayerImageImageValue(self, url.0.image_value.get());
+                bindings::Gecko_SetLayerImageImageValue(self, (url.0).0.url_value.get());
             },
             GenericImage::Rect(ref image_rect) => {
                 unsafe {
                     bindings::Gecko_SetLayerImageImageValue(
                         self,
-                        image_rect.url.0.image_value.get(),
+                        (image_rect.url.0).0.url_value.get(),
                     );
                     bindings::Gecko_InitializeImageCropRect(self);
 
                     // Set CropRect
                     let ref mut rect = *self.mCropRect.mPtr;
                     image_rect
                         .top
                         .to_gecko_style_coord(&mut rect.data_at_mut(0));
--- a/servo/components/style/gecko/url.rs
+++ b/servo/components/style/gecko/url.rs
@@ -2,20 +2,19 @@
  * 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/. */
 
 //! Common handling for the specified value CSS url() values.
 
 use cssparser::Parser;
 use gecko_bindings::bindings;
 use gecko_bindings::structs::ServoBundledURI;
-use gecko_bindings::structs::mozilla::css::URLValueData;
 use gecko_bindings::structs::root::{RustString, nsStyleImageRequest};
 use gecko_bindings::structs::root::mozilla::CORSMode;
-use gecko_bindings::structs::root::mozilla::css::{ImageValue, URLValue};
+use gecko_bindings::structs::root::mozilla::css::URLValue;
 use gecko_bindings::sugar::refptr::RefPtr;
 use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
 use nsstring::nsCString;
 use parser::{Parse, ParserContext};
 use servo_arc::{Arc, RawOffsetArc};
 use std::fmt::{self, Write};
 use std::mem;
 use style_traits::{CssWriter, ParseError, ToCss};
@@ -33,34 +32,33 @@ pub struct CssUrl {
     serialization: Arc<String>,
 
     /// The URL extra data.
     #[css(skip)]
     pub extra_data: UrlExtraData,
 }
 
 impl CssUrl {
-    /// Try to parse a URL from a string value that is a valid CSS token for a
-    /// URL.
+    /// Parse a URL from a string value that is a valid CSS token for a URL.
     pub fn parse_from_string(url: String, context: &ParserContext) -> Self {
         CssUrl {
             serialization: Arc::new(url),
             extra_data: context.url_data.clone(),
         }
     }
 
     /// Returns true if the URL is definitely invalid. We don't eagerly resolve
     /// URLs in gecko, so we just return false here.
     /// use its |resolved| status.
     pub fn is_invalid(&self) -> bool {
         false
     }
 
-    /// Convert from URLValueData to SpecifiedUrl.
-    unsafe fn from_url_value_data(url: &URLValueData) -> Self {
+    /// Convert from URLValue to CssUrl.
+    unsafe fn from_url_value(url: &URLValue) -> Self {
         let arc_type = &url.mString as *const _ as *const RawOffsetArc<String>;
         CssUrl {
             serialization: Arc::from_raw_offset((*arc_type).clone()),
             extra_data: UrlExtraData(url.mExtraData.to_safe()),
         }
     }
 
     /// Returns true if this URL looks like a fragment.
@@ -112,234 +110,213 @@ impl MallocSizeOf for CssUrl {
 
         // We ignore `extra_data`, because RefPtr is tricky, and there aren't
         // many of them in practise (sharing is common).
 
         0
     }
 }
 
-/// A specified url() value for general usage.
+/// A specified non-image `url()` value.
 #[derive(Clone, Debug, SpecifiedValueInfo, ToCss)]
 pub struct SpecifiedUrl {
     /// The specified url value.
     pub url: CssUrl,
     /// Gecko's URLValue so that we can reuse it while rematching a
     /// property with this specified value.
     #[css(skip)]
     pub url_value: RefPtr<URLValue>,
 }
 
 impl SpecifiedUrl {
-    fn from_css_url(url: CssUrl) -> Self {
+    /// Parse a URL from a string value.
+    pub fn parse_from_string(url: String, context: &ParserContext) -> Self {
+        Self::from_css_url(CssUrl::parse_from_string(url, context))
+    }
+
+    fn from_css_url_with_cors(url: CssUrl, cors: CORSMode) -> Self {
         let url_value = unsafe {
-            let ptr = bindings::Gecko_NewURLValue(url.for_ffi());
-            // We do not expect Gecko_NewURLValue returns null.
+            let ptr = bindings::Gecko_URLValue_Create(url.for_ffi(), cors);
+            // We do not expect Gecko_URLValue_Create returns null.
             debug_assert!(!ptr.is_null());
             RefPtr::from_addrefed(ptr)
         };
         Self { url, url_value }
     }
+
+    fn from_css_url(url: CssUrl) -> Self {
+        use gecko_bindings::structs::root::mozilla::CORSMode_CORS_NONE;
+        Self::from_css_url_with_cors(url, CORSMode_CORS_NONE)
+    }
+
+    fn from_css_url_with_cors_anonymous(url: CssUrl) -> Self {
+        use gecko_bindings::structs::root::mozilla::CORSMode_CORS_ANONYMOUS;
+        Self::from_css_url_with_cors(url, CORSMode_CORS_ANONYMOUS)
+    }
+}
+
+impl Parse for SpecifiedUrl {
+    fn parse<'i, 't>(
+        context: &ParserContext,
+        input: &mut Parser<'i, 't>,
+    ) -> Result<Self, ParseError<'i>> {
+        CssUrl::parse(context, input).map(Self::from_css_url)
+    }
 }
 
 impl PartialEq for SpecifiedUrl {
     fn eq(&self, other: &Self) -> bool {
         self.url.eq(&other.url)
     }
 }
 
 impl Eq for SpecifiedUrl {}
 
-impl Parse for SpecifiedUrl {
-    fn parse<'i, 't>(
-        context: &ParserContext,
-        input: &mut Parser<'i, 't>,
-    ) -> Result<Self, ParseError<'i>> {
-        CssUrl::parse(context, input).map(Self::from_css_url)
-    }
-}
-
 impl MallocSizeOf for SpecifiedUrl {
     fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
         let mut n = self.url.size_of(ops);
         // Although this is a RefPtr, this is the primary reference because
         // SpecifiedUrl is responsible for creating the url_value. So we
         // measure unconditionally here.
         n += unsafe { bindings::Gecko_URLValue_SizeOfIncludingThis(self.url_value.get()) };
         n
     }
 }
 
-/// A specified url() value for image.
-///
-/// This exists so that we can construct `ImageValue` and reuse it.
-#[derive(Clone, Debug, SpecifiedValueInfo, ToCss)]
-pub struct SpecifiedImageUrl {
-    /// The specified url value.
-    pub url: CssUrl,
-    /// Gecko's ImageValue so that we can reuse it while rematching a
-    /// property with this specified value.
-    #[css(skip)]
-    pub image_value: RefPtr<ImageValue>,
-}
-
-impl SpecifiedImageUrl {
-    /// Parse a URL from a string value. See SpecifiedUrl::parse_from_string.
-    pub fn parse_from_string(url: String, context: &ParserContext) -> Self {
-        Self::from_css_url(CssUrl::parse_from_string(url, context))
-    }
-
-    fn from_css_url_with_cors(url: CssUrl, cors: CORSMode) -> Self {
-        let image_value = unsafe {
-            let ptr = bindings::Gecko_ImageValue_Create(url.for_ffi(), cors);
-            // We do not expect Gecko_ImageValue_Create returns null.
-            debug_assert!(!ptr.is_null());
-            RefPtr::from_addrefed(ptr)
-        };
-        Self { url, image_value }
-    }
-
-    fn from_css_url(url: CssUrl) -> Self {
-        use gecko_bindings::structs::root::mozilla::CORSMode_CORS_NONE;
-        Self::from_css_url_with_cors(url, CORSMode_CORS_NONE)
-    }
-
-    fn from_css_url_with_cors_anonymous(url: CssUrl) -> Self {
-        use gecko_bindings::structs::root::mozilla::CORSMode_CORS_ANONYMOUS;
-        Self::from_css_url_with_cors(url, CORSMode_CORS_ANONYMOUS)
-    }
-
-    /// Provides an alternate method for parsing that associates the URL
-    /// with anonymous CORS headers.
-    pub fn parse_with_cors_anonymous<'i, 't>(
-        context: &ParserContext,
-        input: &mut Parser<'i, 't>,
-    ) -> Result<Self, ParseError<'i>> {
-        CssUrl::parse(context, input).map(Self::from_css_url_with_cors_anonymous)
-    }
-}
-
-impl Parse for SpecifiedImageUrl {
-    fn parse<'i, 't>(
-        context: &ParserContext,
-        input: &mut Parser<'i, 't>,
-    ) -> Result<Self, ParseError<'i>> {
-        CssUrl::parse(context, input).map(Self::from_css_url)
-    }
-}
-
-impl PartialEq for SpecifiedImageUrl {
-    fn eq(&self, other: &Self) -> bool {
-        self.url.eq(&other.url)
-    }
-}
-
-impl Eq for SpecifiedImageUrl {}
-
-impl MallocSizeOf for SpecifiedImageUrl {
-    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
-        let mut n = self.url.size_of(ops);
-        // Although this is a RefPtr, this is the primary reference because
-        // SpecifiedUrl is responsible for creating the image_value. So we
-        // measure unconditionally here.
-        n += unsafe { bindings::Gecko_ImageValue_SizeOfIncludingThis(self.image_value.get()) };
-        n
-    }
-}
-
 impl ToComputedValue for SpecifiedUrl {
     type ComputedValue = ComputedUrl;
 
     #[inline]
     fn to_computed_value(&self, _: &Context) -> Self::ComputedValue {
         ComputedUrl(self.clone())
     }
 
     #[inline]
     fn from_computed_value(computed: &Self::ComputedValue) -> Self {
         computed.0.clone()
     }
 }
 
+/// A specified image `url()` value.
+#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
+pub struct SpecifiedImageUrl(pub SpecifiedUrl);
+
+impl SpecifiedImageUrl {
+    /// Parse a URL from a string value that is a valid CSS token for a URL.
+    pub fn parse_from_string(url: String, context: &ParserContext) -> Self {
+        SpecifiedImageUrl(SpecifiedUrl::parse_from_string(url, context))
+    }
+
+    /// Provides an alternate method for parsing that associates the URL
+    /// with anonymous CORS headers.
+    pub fn parse_with_cors_anonymous<'i, 't>(
+        context: &ParserContext,
+        input: &mut Parser<'i, 't>,
+    ) -> Result<Self, ParseError<'i>> {
+        CssUrl::parse(context, input)
+            .map(SpecifiedUrl::from_css_url_with_cors_anonymous)
+            .map(SpecifiedImageUrl)
+    }
+}
+
+impl Parse for SpecifiedImageUrl {
+    fn parse<'i, 't>(
+        context: &ParserContext,
+        input: &mut Parser<'i, 't>,
+    ) -> Result<Self, ParseError<'i>> {
+        SpecifiedUrl::parse(context, input).map(SpecifiedImageUrl)
+    }
+}
+
 impl ToComputedValue for SpecifiedImageUrl {
     type ComputedValue = ComputedImageUrl;
 
     #[inline]
     fn to_computed_value(&self, _: &Context) -> Self::ComputedValue {
         ComputedImageUrl(self.clone())
     }
 
     #[inline]
     fn from_computed_value(computed: &Self::ComputedValue) -> Self {
         computed.0.clone()
     }
 }
 
 fn serialize_computed_url<W>(
-    url_value_data: &URLValueData,
+    url_value: &URLValue,
     dest: &mut CssWriter<W>,
-    get_url: unsafe extern "C" fn(*const URLValueData, *mut nsCString),
+    get_url: unsafe extern "C" fn(*const URLValue, *mut nsCString) -> (),
 ) -> fmt::Result
 where
     W: Write,
 {
     dest.write_str("url(")?;
     unsafe {
         let mut string = nsCString::new();
-        get_url(url_value_data, &mut string);
+        get_url(url_value, &mut string);
         string.as_str_unchecked().to_css(dest)?;
     }
     dest.write_char(')')
 }
 
-/// The computed value of a CSS `url()`.
+/// The computed value of a CSS non-image `url()`.
 ///
 /// The only difference between specified and computed URLs is the
 /// serialization.
 #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)]
 pub struct ComputedUrl(pub SpecifiedUrl);
 
 impl ToCss for ComputedUrl {
     fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
     where
         W: Write,
     {
         serialize_computed_url(
-            &self.0.url_value._base,
+            &self.0.url_value,
             dest,
             bindings::Gecko_GetComputedURLSpec,
         )
     }
 }
 
 impl ComputedUrl {
     /// Convert from RefPtr<URLValue> to ComputedUrl.
     pub unsafe fn from_url_value(url_value: RefPtr<URLValue>) -> Self {
-        let url = CssUrl::from_url_value_data(&url_value._base);
+        let url = CssUrl::from_url_value(&*url_value);
         ComputedUrl(SpecifiedUrl { url, url_value })
     }
+
+    /// Get a raw pointer to the URLValue held by this ComputedUrl, for FFI.
+    pub fn url_value_ptr(&self) -> *mut URLValue {
+        self.0.url_value.get()
+    }
 }
 
-/// The computed value of a CSS `url()` for image.
+/// The computed value of a CSS image `url()`.
 #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)]
 pub struct ComputedImageUrl(pub SpecifiedImageUrl);
 
 impl ToCss for ComputedImageUrl {
     fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
     where
         W: Write,
     {
         serialize_computed_url(
-            &self.0.image_value._base,
+            &(self.0).0.url_value,
             dest,
             bindings::Gecko_GetComputedImageURLSpec,
         )
     }
 }
 
 impl ComputedImageUrl {
     /// Convert from nsStyleImageReques to ComputedImageUrl.
     pub unsafe fn from_image_request(image_request: &nsStyleImageRequest) -> Self {
-        let image_value = image_request.mImageValue.to_safe();
-        let url = CssUrl::from_url_value_data(&image_value._base);
-        ComputedImageUrl(SpecifiedImageUrl { url, image_value })
+        let url_value = image_request.mImageValue.to_safe();
+        let url = CssUrl::from_url_value(&*url_value);
+        ComputedImageUrl(SpecifiedImageUrl(SpecifiedUrl { url, url_value }))
+    }
+
+    /// Get a raw pointer to the URLValue held by this ComputedImageUrl, for FFI.
+    pub fn url_value_ptr(&self) -> *mut URLValue {
+        (self.0).0.url_value.get()
     }
 }
--- a/servo/components/style/gecko_bindings/sugar/refptr.rs
+++ b/servo/components/style/gecko_bindings/sugar/refptr.rs
@@ -293,21 +293,16 @@ impl_threadsafe_refcount!(
     bindings::Gecko_ReleaseCSSURLValueArbitraryThread
 );
 impl_threadsafe_refcount!(
     structs::mozilla::css::GridTemplateAreasValue,
     bindings::Gecko_AddRefGridTemplateAreasValueArbitraryThread,
     bindings::Gecko_ReleaseGridTemplateAreasValueArbitraryThread
 );
 impl_threadsafe_refcount!(
-    structs::ImageValue,
-    bindings::Gecko_AddRefImageValueArbitraryThread,
-    bindings::Gecko_ReleaseImageValueArbitraryThread
-);
-impl_threadsafe_refcount!(
     structs::SharedFontList,
     bindings::Gecko_AddRefSharedFontListArbitraryThread,
     bindings::Gecko_ReleaseSharedFontListArbitraryThread
 );
 impl_threadsafe_refcount!(
     structs::SheetLoadDataHolder,
     bindings::Gecko_AddRefSheetLoadDataHolderArbitraryThread,
     bindings::Gecko_ReleaseSheetLoadDataHolderArbitraryThread
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -684,17 +684,20 @@ def set_gecko_property(ffi_name, expr):
             SVGPaintKind::ContextFill => {
                 paint.mType = nsStyleSVGPaintType::eStyleSVGPaintType_ContextFill;
             }
             SVGPaintKind::ContextStroke => {
                 paint.mType = nsStyleSVGPaintType::eStyleSVGPaintType_ContextStroke;
             }
             SVGPaintKind::PaintServer(url) => {
                 unsafe {
-                    bindings::Gecko_nsStyleSVGPaint_SetURLValue(paint, url.0.url_value.get());
+                    bindings::Gecko_nsStyleSVGPaint_SetURLValue(
+                        paint,
+                        url.url_value_ptr(),
+                    )
                 }
             }
             SVGPaintKind::Color(color) => {
                 paint.mType = nsStyleSVGPaintType::eStyleSVGPaintType_Color;
                 unsafe {
                     *paint.mPaint.mColor.as_mut() = color.into();
                 }
             }
@@ -4148,17 +4151,20 @@ fn static_assert() {
         match image {
             UrlOrNone::None => {
                 unsafe {
                     Gecko_SetListStyleImageNone(&mut self.gecko);
                 }
             }
             UrlOrNone::Url(ref url) => {
                 unsafe {
-                    Gecko_SetListStyleImageImageValue(&mut self.gecko, url.0.image_value.get());
+                    Gecko_SetListStyleImageImageValue(
+                        &mut self.gecko,
+                        url.url_value_ptr(),
+                    );
                 }
             }
         }
     }
 
     pub fn copy_list_style_image_from(&mut self, other: &Self) {
         unsafe { Gecko_CopyListStyleImageFrom(&mut self.gecko, &other.gecko); }
     }
@@ -5353,17 +5359,17 @@ clip-path
 
         unsafe {
             Gecko_SetCursorArrayLength(&mut self.gecko, v.images.len());
         }
         for i in 0..v.images.len() {
             unsafe {
                 Gecko_SetCursorImageValue(
                     &mut self.gecko.mCursorImages[i],
-                    v.images[i].url.0.image_value.get(),
+                    v.images[i].url.url_value_ptr(),
                 );
             }
 
             match v.images[i].hotspot {
                 Some((x, y)) => {
                     self.gecko.mCursorImages[i].mHaveHotspot = true;
                     self.gecko.mCursorImages[i].mHotspotX = x;
                     self.gecko.mCursorImages[i].mHotspotY = y;
@@ -5654,17 +5660,17 @@ clip-path
                                 style.clone(),
                                 device,
                             );
                         }
                         ContentItem::Url(ref url) => {
                             unsafe {
                                 bindings::Gecko_SetContentDataImageValue(
                                     &mut self.gecko.mContents[i],
-                                    url.0.image_value.get(),
+                                    url.url_value_ptr(),
                                 )
                             }
                         }
                     }
                 }
             }
         }
     }
--- a/toolkit/components/telemetry/core/Telemetry.cpp
+++ b/toolkit/components/telemetry/core/Telemetry.cpp
@@ -1,107 +1,102 @@
 /* -*- 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/. */
 
+#include "Telemetry.h"
+
 #include <algorithm>
-
 #include <prio.h>
 #include <prproces.h>
 #if defined(XP_UNIX) && !defined(XP_DARWIN)
 #include <time.h>
 #else
 #include <chrono>
 #endif
-
+#include "base/pickle.h"
+#if defined(MOZ_TELEMETRY_GECKOVIEW)
+#include "geckoview/TelemetryGeckoViewPersistence.h"
+#endif
+#include "ipc/TelemetryIPCAccumulator.h"
+#include "jsapi.h"
+#include "jsfriendapi.h"
+#include "js/GCAPI.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/BackgroundHangMonitor.h"
 #include "mozilla/DebugOnly.h"
+#include "mozilla/FStream.h"
+#include "mozilla/IOInterposer.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MathAlgorithms.h"
-#include "mozilla/Unused.h"
-
-#include "base/pickle.h"
-#include "other/CombinedStacks.h"
-#include "nsIComponentManager.h"
-#include "nsIServiceManager.h"
-#include "nsThreadManager.h"
-#include "nsXPCOMCIDInternal.h"
-#include "nsCOMArray.h"
-#include "nsCOMPtr.h"
-#include "nsXPCOMPrivate.h"
-#include "nsIXULAppInfo.h"
-#include "nsVersionComparator.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/ModuleUtils.h"
-#include "nsIXPConnect.h"
+#include "mozilla/Mutex.h"
+#include "mozilla/PoisonIOInterposer.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/ProcessedStack.h"
 #include "mozilla/Services.h"
-#include "jsapi.h"
-#include "jsfriendapi.h"
-#include "js/GCAPI.h"
-#include "nsString.h"
-#include "nsITelemetry.h"
+#include "mozilla/StartupTimeline.h"
+#include "mozilla/StaticPtr.h"
+#include "mozilla/Unused.h"
+#if defined(XP_WIN)
+#include "mozilla/WinDllServices.h"
+#endif
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsBaseHashtable.h"
+#include "nsClassHashtable.h"
+#include "nsCOMArray.h"
+#include "nsCOMPtr.h"
+#include "nsDataHashtable.h"
+#include "nsHashKeys.h"
+#include "nsIComponentManager.h"
 #include "nsIDirectoryEnumerator.h"
 #include "nsIFileStreams.h"
-#include "nsLocalFile.h"
 #include "nsIMemoryReporter.h"
 #include "nsISeekableStream.h"
+#include "nsIServiceManager.h"
 #include "nsISimpleEnumerator.h"
-#include "Telemetry.h"
-#include "TelemetryCommon.h"
-#include "TelemetryHistogram.h"
-#include "other/TelemetryIOInterposeObserver.h"
-#include "ipc/TelemetryIPCAccumulator.h"
-#include "TelemetryScalar.h"
-#include "TelemetryEvent.h"
-#include "other/WebrtcTelemetry.h"
+#include "nsITelemetry.h"
+#include "nsIXPConnect.h"
+#include "nsIXULAppInfo.h"
+#include "nsJSUtils.h"
+#include "nsLocalFile.h"
+#include "nsNativeCharsetUtils.h"
+#include "nsNetCID.h"
+#include "nsNetUtil.h"
+#include "nsProxyRelease.h"
+#include "nsReadableUtils.h"
+#include "nsString.h"
 #include "nsTHashtable.h"
-#include "nsHashKeys.h"
-#include "nsBaseHashtable.h"
-#include "nsClassHashtable.h"
-#include "nsDataHashtable.h"
-#include "nsXULAppAPI.h"
-#include "nsReadableUtils.h"
+#include "nsThreadManager.h"
 #include "nsThreadUtils.h"
 #if defined(XP_WIN)
 #include "nsUnicharUtils.h"
 #endif
-#include "nsNetCID.h"
-#include "nsNetUtil.h"
-#include "nsJSUtils.h"
-#include "nsReadableUtils.h"
+#include "nsVersionComparator.h"
+#include "nsXPCOMCIDInternal.h"
+#include "nsXPCOMPrivate.h"
+#include "nsXULAppAPI.h"
+#include "other/CombinedStacks.h"
+#include "other/TelemetryIOInterposeObserver.h"
+#include "other/WebrtcTelemetry.h"
 #include "plstr.h"
-#include "nsAppDirectoryServiceDefs.h"
-#include "mozilla/BackgroundHangMonitor.h"
-#include "mozilla/FStream.h"
-#include "mozilla/ProcessedStack.h"
-#include "mozilla/Mutex.h"
-#include "mozilla/Preferences.h"
-#include "mozilla/StaticPtr.h"
-#include "mozilla/IOInterposer.h"
-#include "mozilla/PoisonIOInterposer.h"
-#include "mozilla/StartupTimeline.h"
-#if defined(XP_WIN)
-#include "mozilla/WinDllServices.h"
-#endif
-#include "nsNativeCharsetUtils.h"
-#include "nsProxyRelease.h"
-
 #if defined(MOZ_GECKO_PROFILER)
 #include "shared-libraries.h"
 #include "other/KeyedStackCapturer.h"
 #endif // MOZ_GECKO_PROFILER
-
-#if defined(MOZ_TELEMETRY_GECKOVIEW)
-#include "geckoview/TelemetryGeckoViewPersistence.h"
-#endif
+#include "TelemetryCommon.h"
+#include "TelemetryEvent.h"
+#include "TelemetryHistogram.h"
+#include "TelemetryScalar.h"
 
 namespace {
 
 using namespace mozilla;
 using Telemetry::Common::AutoHashtable;
 using Telemetry::Common::ToJSString;
 using Telemetry::Common::GetCurrentProduct;
 using Telemetry::Common::SetCurrentProduct;
--- a/toolkit/components/telemetry/core/Telemetry.h
+++ b/toolkit/components/telemetry/core/Telemetry.h
@@ -2,24 +2,23 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef Telemetry_h__
 #define Telemetry_h__
 
 #include "mozilla/GuardObjects.h"
-#include "mozilla/TimeStamp.h"
 #include "mozilla/StartupTimeline.h"
-#include "nsTArray.h"
-#include "nsString.h"
-#include "nsXULAppAPI.h"
-
 #include "mozilla/TelemetryHistogramEnums.h"
 #include "mozilla/TelemetryScalarEnums.h"
+#include "mozilla/TimeStamp.h"
+#include "nsString.h"
+#include "nsTArray.h"
+#include "nsXULAppAPI.h"
 
 /******************************************************************************
  * This implements the Telemetry system.
  * It allows recording into histograms as well some more specialized data
  * points and gives access to the data.
  *
  * For documentation on how to add and use new Telemetry probes, see:
  * https://developer.mozilla.org/en-US/docs/Mozilla/Performance/Adding_a_new_Telemetry_probe
--- a/toolkit/components/telemetry/core/TelemetryCommon.cpp
+++ b/toolkit/components/telemetry/core/TelemetryCommon.cpp
@@ -1,26 +1,25 @@
 /* -*- 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/. */
 
-#include "nsITelemetry.h"
-#include "nsVersionComparator.h"
+#include "TelemetryCommon.h"
+
+#include <cstring>
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Preferences.h"
 #include "nsIConsoleService.h"
+#include "nsITelemetry.h"
 #include "nsThreadUtils.h"
-
-#include "TelemetryCommon.h"
+#include "nsVersionComparator.h"
 #include "TelemetryProcessData.h"
 
-#include <cstring>
-
 namespace mozilla {
 namespace Telemetry {
 namespace Common {
 
 bool
 IsExpiredVersion(const char* aExpiration)
 {
   MOZ_ASSERT(aExpiration);
--- a/toolkit/components/telemetry/core/TelemetryCommon.h
+++ b/toolkit/components/telemetry/core/TelemetryCommon.h
@@ -1,22 +1,22 @@
 /* -*-  Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef TelemetryCommon_h__
 #define TelemetryCommon_h__
 
-#include "nsTHashtable.h"
 #include "jsapi.h"
-#include "nsIScriptError.h"
-#include "nsXULAppAPI.h"
 #include "mozilla/TypedEnumBits.h"
 #include "mozilla/TelemetryProcessEnums.h"
+#include "nsIScriptError.h"
+#include "nsTHashtable.h"
+#include "nsXULAppAPI.h"
 
 namespace mozilla {
 namespace Telemetry {
 namespace Common {
 
 enum class RecordedProcessType : uint32_t {
   Main         = (1 << GeckoProcessType_Default),  // Also known as "parent process"
   Content      = (1 << GeckoProcessType_Content),
--- a/toolkit/components/telemetry/core/TelemetryEvent.cpp
+++ b/toolkit/components/telemetry/core/TelemetryEvent.cpp
@@ -1,41 +1,40 @@
 /* -*- 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/. */
 
+#include "Telemetry.h"
+#include "TelemetryEvent.h"
 #include <prtime.h>
 #include <limits>
+#include "ipc/TelemetryIPCAccumulator.h"
+#include "jsapi.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/Pair.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/Services.h"
+#include "mozilla/StaticMutex.h"
+#include "mozilla/StaticPtr.h"
+#include "mozilla/Unused.h"
+#include "nsClassHashtable.h"
+#include "nsDataHashtable.h"
+#include "nsHashKeys.h"
 #include "nsIObserverService.h"
 #include "nsITelemetry.h"
-#include "nsHashKeys.h"
-#include "nsDataHashtable.h"
-#include "nsClassHashtable.h"
+#include "nsJSUtils.h"
+#include "nsPrintfCString.h"
 #include "nsTArray.h"
-#include "mozilla/Preferences.h"
-#include "mozilla/StaticMutex.h"
-#include "mozilla/Unused.h"
-#include "mozilla/Maybe.h"
-#include "mozilla/Services.h"
-#include "mozilla/StaticPtr.h"
-#include "mozilla/Pair.h"
-#include "jsapi.h"
-#include "nsJSUtils.h"
+#include "nsUTF8Utils.h"
 #include "nsXULAppAPI.h"
-#include "nsUTF8Utils.h"
-#include "nsPrintfCString.h"
-
-#include "Telemetry.h"
 #include "TelemetryCommon.h"
-#include "TelemetryEvent.h"
 #include "TelemetryEventData.h"
 #include "TelemetryScalar.h"
-#include "ipc/TelemetryIPCAccumulator.h"
 
 using mozilla::StaticMutex;
 using mozilla::StaticMutexAutoLock;
 using mozilla::ArrayLength;
 using mozilla::Maybe;
 using mozilla::Nothing;
 using mozilla::StaticAutoPtr;
 using mozilla::TimeStamp;
--- a/toolkit/components/telemetry/core/TelemetryEvent.h
+++ b/toolkit/components/telemetry/core/TelemetryEvent.h
@@ -1,16 +1,17 @@
 /* -*-  Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef TelemetryEvent_h__
 #define TelemetryEvent_h__
 
+#include <stdint.h>
 #include "mozilla/TelemetryEventEnums.h"
 #include "mozilla/TelemetryProcessEnums.h"
 
 namespace mozilla {
 namespace Telemetry {
   struct ChildEventData;
 }
 }
--- a/toolkit/components/telemetry/core/TelemetryHistogram.cpp
+++ b/toolkit/components/telemetry/core/TelemetryHistogram.cpp
@@ -1,42 +1,39 @@
 /* -*- 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/. */
 
+#include "TelemetryHistogram.h"
+
+#include <limits>
+#include "base/histogram.h"
+#include "ipc/TelemetryIPCAccumulator.h"
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "js/GCAPI.h"
-#include "nsString.h"
-#include "nsTHashtable.h"
-#include "nsHashKeys.h"
-#include "nsBaseHashtable.h"
-#include "nsClassHashtable.h"
-#include "nsITelemetry.h"
-#include "nsPrintfCString.h"
-
 #include "mozilla/dom/ToJSValue.h"
 #include "mozilla/gfx/GPUProcessManager.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/JSONWriter.h"
 #include "mozilla/StartupTimeline.h"
 #include "mozilla/StaticMutex.h"
 #include "mozilla/Unused.h"
-
+#include "nsBaseHashtable.h"
+#include "nsClassHashtable.h"
+#include "nsString.h"
+#include "nsTHashtable.h"
+#include "nsHashKeys.h"
+#include "nsITelemetry.h"
+#include "nsPrintfCString.h"
 #include "TelemetryCommon.h"
-#include "TelemetryHistogram.h"
 #include "TelemetryHistogramNameMap.h"
 #include "TelemetryScalar.h"
-#include "ipc/TelemetryIPCAccumulator.h"
-
-#include "base/histogram.h"
-
-#include <limits>
 
 using base::Histogram;
 using base::BooleanHistogram;
 using base::CountHistogram;
 using base::FlagHistogram;
 using base::LinearHistogram;
 using mozilla::MakeTuple;
 using mozilla::StaticMutexNotRecorded;
--- a/toolkit/components/telemetry/core/TelemetryHistogram.h
+++ b/toolkit/components/telemetry/core/TelemetryHistogram.h
@@ -1,20 +1,19 @@
 /* -*-  Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef TelemetryHistogram_h__
 #define TelemetryHistogram_h__
 
+#include "mozilla/TelemetryComms.h"
 #include "mozilla/TelemetryHistogramEnums.h"
 #include "mozilla/TelemetryProcessEnums.h"
-
-#include "mozilla/TelemetryComms.h"
 #include "nsXULAppAPI.h"
 
 namespace mozilla{
 // This is only used for the GeckoView persistence.
 class JSONWriter;
 }
 
 // This module is internal to Telemetry.  It encapsulates Telemetry's
--- a/toolkit/components/telemetry/core/TelemetryScalar.cpp
+++ b/toolkit/components/telemetry/core/TelemetryScalar.cpp
@@ -1,39 +1,39 @@
 /* -*- 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/. */
 
-#include "nsITelemetry.h"
-#include "nsIVariant.h"
-#include "nsVariant.h"
-#include "nsHashKeys.h"
-#include "nsBaseHashtable.h"
-#include "nsClassHashtable.h"
-#include "nsDataHashtable.h"
-#include "nsIXPConnect.h"
-#include "nsContentUtils.h"
-#include "nsThreadUtils.h"
-#include "nsJSUtils.h"
-#include "nsPrintfCString.h"
+#include "TelemetryScalar.h"
+
+#include "ipc/TelemetryComms.h"
+#include "ipc/TelemetryIPCAccumulator.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/PContent.h"
 #include "mozilla/JSONWriter.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/StaticMutex.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/Unused.h"
-
+#include "nsBaseHashtable.h"
+#include "nsClassHashtable.h"
+#include "nsContentUtils.h"
+#include "nsDataHashtable.h"
+#include "nsHashKeys.h"
+#include "nsITelemetry.h"
+#include "nsIVariant.h"
+#include "nsIXPConnect.h"
+#include "nsJSUtils.h"
+#include "nsPrintfCString.h"
+#include "nsThreadUtils.h"
+#include "nsVariant.h"
 #include "TelemetryCommon.h"
-#include "TelemetryScalar.h"
 #include "TelemetryScalarData.h"
-#include "ipc/TelemetryComms.h"
-#include "ipc/TelemetryIPCAccumulator.h"
 
 using mozilla::Preferences;
 using mozilla::StaticAutoPtr;
 using mozilla::StaticMutex;
 using mozilla::StaticMutexNotRecorded;
 using mozilla::StaticMutexAutoLock;
 using mozilla::Some;
 using mozilla::Nothing;
--- a/toolkit/components/telemetry/core/TelemetryScalar.h
+++ b/toolkit/components/telemetry/core/TelemetryScalar.h
@@ -1,19 +1,20 @@
 /* -*-  Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef TelemetryScalar_h__
 #define TelemetryScalar_h__
 
-#include "nsTArray.h"
+#include <stdint.h>
+#include "mozilla/TelemetryProcessEnums.h"
 #include "mozilla/TelemetryScalarEnums.h"
-#include "mozilla/TelemetryProcessEnums.h"
+#include "nsTArray.h"
 
 // This module is internal to Telemetry. It encapsulates Telemetry's
 // scalar accumulation and storage logic. It should only be used by
 // Telemetry.cpp. These functions should not be used anywhere else.
 // For the public interface to Telemetry functionality, see Telemetry.h.
 
 namespace mozilla {
 // This is only used for the GeckoView persistence.
--- a/toolkit/components/telemetry/core/ipc/TelemetryComms.h
+++ b/toolkit/components/telemetry/core/ipc/TelemetryComms.h
@@ -2,20 +2,20 @@
 /* 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
  */
 
 #ifndef Telemetry_Comms_h__
 #define Telemetry_Comms_h__
 
 #include "ipc/IPCMessageUtils.h"
+#include "mozilla/TelemetryProcessEnums.h"
+#include "mozilla/TimeStamp.h"
 #include "nsITelemetry.h"
 #include "nsVariant.h"
-#include "mozilla/TimeStamp.h"
-#include "mozilla/TelemetryProcessEnums.h"
 
 namespace mozilla {
 namespace Telemetry {
 
 // Histogram accumulation types.
 enum HistogramID : uint32_t;
 
 struct HistogramAccumulation
--- a/toolkit/components/telemetry/core/ipc/TelemetryIPC.h
+++ b/toolkit/components/telemetry/core/ipc/TelemetryIPC.h
@@ -1,19 +1,20 @@
 /* -*-  Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef TelemetryIPC_h__
 #define TelemetryIPC_h__
 
+#include <stdint.h>
+#include "mozilla/TelemetryProcessEnums.h"
 #include "nsTArray.h"
 #include "nsXULAppAPI.h"
-#include "mozilla/TelemetryProcessEnums.h"
 
 // This module provides the interface to accumulate Telemetry from child processes.
 // Top-level actors for different child processes types (ContentParent, GPUChild)
 // will call this for messages from their respective processes.
 
 namespace mozilla {
 
 namespace Telemetry {
--- a/toolkit/components/telemetry/core/ipc/TelemetryIPCAccumulator.cpp
+++ b/toolkit/components/telemetry/core/ipc/TelemetryIPCAccumulator.cpp
@@ -1,28 +1,28 @@
 /* -*- 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/. */
 
 #include "TelemetryIPCAccumulator.h"
 
+#include "core/TelemetryHistogram.h"
+#include "core/TelemetryScalar.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/gfx/GPUParent.h"
 #include "mozilla/gfx/GPUProcessManager.h"
 #include "mozilla/StaticMutex.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/SystemGroup.h"
 #include "mozilla/Unused.h"
 #include "nsComponentManagerUtils.h"
 #include "nsITimer.h"
 #include "nsThreadUtils.h"
-#include "core/TelemetryHistogram.h"
-#include "core/TelemetryScalar.h"
 
 using mozilla::StaticMutex;
 using mozilla::StaticMutexAutoLock;
 using mozilla::StaticAutoPtr;
 using mozilla::SystemGroup;
 using mozilla::TaskCategory;
 using mozilla::Telemetry::HistogramAccumulation;
 using mozilla::Telemetry::DiscardedData;
--- a/toolkit/components/telemetry/geckoview/TelemetryGeckoViewPersistence.cpp
+++ b/toolkit/components/telemetry/geckoview/TelemetryGeckoViewPersistence.cpp
@@ -1,41 +1,41 @@
 /* -*- 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/. */
 
 #include "TelemetryGeckoViewPersistence.h"
 
+#include "core/TelemetryHistogram.h"
+#include "core/TelemetryScalar.h"
 #include "jsapi.h"
 #include "js/JSON.h"
+#include "mozilla/dom/ScriptSettings.h" // for AutoJSAPI
+#include "mozilla/dom/SimpleGlobalObject.h"
 #include "mozilla/ErrorNames.h"
 #include "mozilla/JSONWriter.h"
 #include "mozilla/Path.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ScopeExit.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/SystemGroup.h"
-#include "mozilla/dom/ScriptSettings.h" // for AutoJSAPI
-#include "mozilla/dom/SimpleGlobalObject.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsIFile.h"
 #include "nsIInputStream.h"
 #include "nsIObserverService.h"
 #include "nsIOutputStream.h"
 #include "nsISafeOutputStream.h"
 #include "nsITimer.h"
 #include "nsLocalFile.h"
 #include "nsNetUtil.h"
 #include "nsXULAppAPI.h"
 #include "prenv.h"
 #include "prio.h"
-#include "core/TelemetryScalar.h"
-#include "core/TelemetryHistogram.h"
 #include "xpcpublic.h"
 
 using mozilla::GetErrorName;
 using mozilla::MakeScopeExit;
 using mozilla::Preferences;
 using mozilla::StaticRefPtr;
 using mozilla::SystemGroup;
 using mozilla::TaskCategory;
--- a/toolkit/components/telemetry/geckoview/gtest/TestGeckoView.cpp
+++ b/toolkit/components/telemetry/geckoview/gtest/TestGeckoView.cpp
@@ -7,18 +7,18 @@
 #include "mozilla/JSONWriter.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
 #include "nsIOutputStream.h"
 #include "nsITelemetry.h"
 #include "nsJSUtils.h"
 #include "nsNetUtil.h"
+#include "nsPrintfCString.h"
 #include "nsThreadUtils.h"
-#include "nsPrintfCString.h"
 #include "prenv.h"
 #include "mozilla/Telemetry.h"
 #include "TelemetryFixture.h"
 #include "TelemetryGeckoViewPersistence.h"
 #include "core/TelemetryScalar.h"
 #include "TelemetryTestHelpers.h"
 
 using namespace mozilla;
--- a/toolkit/components/telemetry/other/CombinedStacks.cpp
+++ b/toolkit/components/telemetry/other/CombinedStacks.cpp
@@ -1,17 +1,18 @@
 /* -*- 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/. */
 
 #include "CombinedStacks.h"
+
+#include "jsapi.h"
 #include "mozilla/HangAnnotations.h"
-#include "jsapi.h"
 
 namespace mozilla {
 namespace Telemetry {
 
 // The maximum number of chrome hangs stacks that we're keeping.
 const size_t kMaxChromeStacksKept = 50;
 
 CombinedStacks::CombinedStacks()
--- a/toolkit/components/telemetry/other/KeyedStackCapturer.cpp
+++ b/toolkit/components/telemetry/other/KeyedStackCapturer.cpp
@@ -1,19 +1,20 @@
 /* -*- 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/. */
 
 #include "KeyedStackCapturer.h"
-#include "nsPrintfCString.h"
+
+#include "jsapi.h"
 #include "mozilla/StackWalk.h"
+#include "nsPrintfCString.h"
 #include "ProcessedStack.h"
-#include "jsapi.h"
 
 namespace {
 
 /** Defines the size of the keyed stack dictionary. */
 const uint8_t kMaxKeyLength = 50;
 
 /** The maximum number of captured stacks that we're keeping. */
 const size_t kMaxCapturedStacksKept = 50;
--- a/toolkit/components/telemetry/other/KeyedStackCapturer.h
+++ b/toolkit/components/telemetry/other/KeyedStackCapturer.h
@@ -1,21 +1,21 @@
 /* -*-  Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef KeyedStackCapturer_h__
 #define KeyedStackCapturer_h__
 
+#include "CombinedStacks.h"
+#include "mozilla/Mutex.h"
 #include "mozilla/Telemetry.h"
-#include "nsString.h"
 #include "nsClassHashtable.h"
-#include "mozilla/Mutex.h"
-#include "CombinedStacks.h"
+#include "nsString.h"
 
 struct JSContext;
 
 namespace mozilla {
 namespace Telemetry {
 
 /**
 * Allows taking a snapshot of a call stack on demand. Captured stacks are
--- a/toolkit/components/telemetry/other/TelemetryIOInterposeObserver.h
+++ b/toolkit/components/telemetry/other/TelemetryIOInterposeObserver.h
@@ -8,25 +8,24 @@
 /**
  * IOInterposeObserver recording statistics of main-thread I/O during execution,
  * aimed at consumption by TelemetryImpl
  */
 
 #ifndef TelemetryIOInterposeObserver_h__
 #define TelemetryIOInterposeObserver_h__
 
+#include "core/TelemetryCommon.h"
 #include "jsapi.h"
+#include "mozilla/IOInterposer.h"
+#include "nsBaseHashtable.h"
+#include "nsClassHashtable.h"
+#include "nsHashKeys.h"
 #include "nsTArray.h"
 #include "nsTHashtable.h"
-#include "nsHashKeys.h"
-#include "nsBaseHashtable.h"
-#include "nsClassHashtable.h"
-
-#include "core/TelemetryCommon.h"
-#include "mozilla/IOInterposer.h"
 
 namespace mozilla {
 namespace Telemetry {
 
 class TelemetryIOInterposeObserver : public IOInterposeObserver
 {
   /** File-level statistics structure */
   struct FileStats {
--- a/toolkit/components/telemetry/other/WebrtcTelemetry.cpp
+++ b/toolkit/components/telemetry/other/WebrtcTelemetry.cpp
@@ -1,21 +1,20 @@
 /* -*- 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/. */
 
+#include "WebrtcTelemetry.h"
 
+#include "jsapi.h"
 #include "mozilla/Telemetry.h"
-#include "WebrtcTelemetry.h"
-#include "jsapi.h"
 #include "nsPrintfCString.h"
 #include "nsTHashtable.h"
-
 void
 WebrtcTelemetry::RecordIceCandidateMask(const uint32_t iceCandidateBitmask,
                                         const bool success)
 {
   WebrtcIceCandidateType *entry = mWebrtcIceCandidates.GetEntry(iceCandidateBitmask);
   if (!entry) {
     entry = mWebrtcIceCandidates.PutEntry(iceCandidateBitmask);
     if (MOZ_UNLIKELY(!entry))
--- a/toolkit/components/telemetry/pingsender/pingsender_unix_common.cpp
+++ b/toolkit/components/telemetry/pingsender/pingsender_unix_common.cpp
@@ -1,24 +1,21 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <cerrno>
 #include <cstring>
+#include <dlfcn.h>
 #include <string>
-
-#include <dlfcn.h>
 #include <unistd.h>
-
+#include "mozilla/Unused.h"
 #include "third_party/curl/curl.h"
 
-#include "mozilla/Unused.h"
-
 namespace PingSender {
 
 using std::string;
 
 using mozilla::Unused;
 
 /**
  * A simple wrapper around libcurl "easy" functions. Provides RAII opening
--- a/toolkit/components/telemetry/tests/gtest/TelemetryFixture.h
+++ b/toolkit/components/telemetry/tests/gtest/TelemetryFixture.h
@@ -1,19 +1,19 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 #ifndef TelemetryFixture_h_
 #define TelemetryFixture_h_
 
 #include "gtest/gtest.h"
-#include "nsITelemetry.h"
 #include "mozilla/CycleCollectedJSContext.h"
 #include "mozilla/dom/ScriptSettings.h"
+#include "nsITelemetry.h"
 
 class TelemetryTestFixture: public ::testing::Test {
 protected:
   TelemetryTestFixture() : mCleanGlobal(nullptr) {}
   virtual void SetUp();
 
   JSObject* mCleanGlobal;
 
--- a/toolkit/components/telemetry/tests/gtest/TelemetryTestHelpers.cpp
+++ b/toolkit/components/telemetry/tests/gtest/TelemetryTestHelpers.cpp
@@ -1,17 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 #include "TelemetryTestHelpers.h"
 
+#include "core/TelemetryCommon.h"
 #include "gtest/gtest.h"
 #include "mozilla/CycleCollectedJSContext.h"
-#include "core/TelemetryCommon.h"
 #include "mozilla/Unused.h"
 
 using namespace mozilla;
 
 // Helper methods provided to simplify writing tests and meant to be used in C++ Gtests.
 namespace TelemetryTestHelpers {
 
 void
--- a/toolkit/components/telemetry/tests/gtest/TestCounters.cpp
+++ b/toolkit/components/telemetry/tests/gtest/TestCounters.cpp
@@ -1,17 +1,17 @@
 /* vim:set ts=2 sw=2 sts=0 et: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 #include "gtest/gtest.h"
 #include "js/Conversions.h"
+#include "mozilla/Telemetry.h"
 #include "nsITelemetry.h"
-#include "mozilla/Telemetry.h"
 #include "TelemetryFixture.h"
 #include "TelemetryTestHelpers.h"
 
 using namespace mozilla;
 using namespace TelemetryTestHelpers;
 
 TEST_F(TelemetryTestFixture, AutoCounter)
 {
--- a/toolkit/components/telemetry/tests/gtest/TestHistograms.cpp
+++ b/toolkit/components/telemetry/tests/gtest/TestHistograms.cpp
@@ -1,17 +1,17 @@
 /* vim:set ts=2 sw=2 sts=0 et: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 #include "gtest/gtest.h"
 #include "js/Conversions.h"
+#include "mozilla/Telemetry.h"
 #include "nsITelemetry.h"
-#include "mozilla/Telemetry.h"
 #include "TelemetryFixture.h"
 #include "TelemetryTestHelpers.h"
 
 using namespace mozilla;
 using namespace TelemetryTestHelpers;
 
 TEST_F(TelemetryTestFixture, AccumulateCountHistogram)
 {
--- a/toolkit/components/telemetry/tests/gtest/TestScalars.cpp
+++ b/toolkit/components/telemetry/tests/gtest/TestScalars.cpp
@@ -1,24 +1,23 @@
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
+#include "core/TelemetryScalar.h"
 #include "gtest/gtest.h"
-
 #include "js/Conversions.h"
+#include "mozilla/Telemetry.h"
+#include "mozilla/TelemetryProcessEnums.h"
 #include "mozilla/Unused.h"
 #include "nsJSUtils.h" // nsAutoJSString
 #include "nsITelemetry.h"
 #include "nsThreadUtils.h"
-#include "mozilla/Telemetry.h"
-#include "mozilla/TelemetryProcessEnums.h"
 #include "TelemetryFixture.h"
-#include "core/TelemetryScalar.h"
 #include "TelemetryTestHelpers.h"
 
 using namespace mozilla;
 using namespace TelemetryTestHelpers;
 using mozilla::Telemetry::ProcessID;
 
 #define EXPECTED_STRING "Nice, expected and creative string."