Merge inbound to mozilla-central a=merge
authorCoroiu Cristina <ccoroiu@mozilla.com>
Sat, 16 Feb 2019 11:36:46 +0200
changeset 459671 7ab4a0c9980f2e89cd9af2bda3cdf656d5c1b0a1
parent 459670 1cfd69d05aa1cd508266c37c1b27ce061bec7bb3 (current diff)
parent 459579 f8058a73d119bb9cb1cd4634b779516dece2c6ff (diff)
child 459672 b759c45d1f01948e19b160b87b44174162de3213
child 459684 939d6ac72fedd803d22d3f62a995cb46b7c2b825
push id111982
push userccoroiu@mozilla.com
push dateSat, 16 Feb 2019 09:42:42 +0000
treeherdermozilla-inbound@7ab4a0c9980f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone67.0a1
first release with
nightly linux32
7ab4a0c9980f / 67.0a1 / 20190216093716 / files
nightly linux64
7ab4a0c9980f / 67.0a1 / 20190216093716 / files
nightly mac
7ab4a0c9980f / 67.0a1 / 20190216093716 / files
nightly win32
7ab4a0c9980f / 67.0a1 / 20190216093716 / files
nightly win64
7ab4a0c9980f / 67.0a1 / 20190216093716 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central a=merge
taskcluster/docker/debian-base/cloud-mirror-workaround.sh
taskcluster/docker/debian-base/setup_packages.sh
taskcluster/scripts/misc/gn.patch
testing/web-platform/meta/css/css-scroll-anchoring/ancestor-change-heuristic.html.ini
testing/web-platform/meta/css/css-scroll-anchoring/anchoring-with-bounds-clamping.html.ini
testing/web-platform/meta/css/css-scroll-anchoring/basic.html.ini
testing/web-platform/meta/css/css-scroll-anchoring/descend-into-container-with-float.html.ini
testing/web-platform/meta/css/css-scroll-anchoring/descend-into-container-with-overflow.html.ini
testing/web-platform/meta/css/css-scroll-anchoring/exclude-fixed-position.html.ini
testing/web-platform/meta/css/css-scroll-anchoring/inline-block.html.ini
testing/web-platform/meta/css/css-scroll-anchoring/position-change-heuristic.html.ini
testing/web-platform/meta/css/css-scroll-anchoring/start-edge-in-block-layout-direction.html.ini
testing/web-platform/meta/css/css-scroll-anchoring/subtree-exclusion.html.ini
testing/web-platform/meta/css/css-scroll-anchoring/wrapped-text.html.ini
testing/web-platform/meta/css/mediaqueries/prefers-color-scheme.html.ini
--- a/accessible/tests/crashtests/471493.xul
+++ b/accessible/tests/crashtests/471493.xul
@@ -25,18 +25,18 @@
     }
 
     function doTest()
     {
       var accService = SpecialPowers.Cc["@mozilla.org/accessibilityService;1"].
         getService(SpecialPowers.Ci.nsIAccessibilityService);
 
       var treecol = document.getElementById("col");
-      var x = treecol.boxObject.screenX;
-      var y = treecol.boxObject.screenY;
+      var x = treecol.screenX;
+      var y = treecol.screenY;
 
       var tree = document.getElementById("tree");
       addA11yLoadEvent(accService, () => {
         var treeAcc = accService.getAccessibleFor(tree);
         treeAcc.getChildAtPoint(x + 1, y + 1);
         document.documentElement.removeAttribute("class");
       });
     }
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -4640,17 +4640,17 @@ var XULBrowserWindow = {
     }
 
     // The x,y coordinates are relative to the <browser> element using
     // the chrome zoom level.
     let elt = document.getElementById("remoteBrowserTooltip");
     elt.label = tooltip;
     elt.style.direction = direction;
 
-    elt.openPopupAtScreen(browser.boxObject.screenX + x, browser.boxObject.screenY + y, false, null);
+    elt.openPopupAtScreen(browser.screenX + x, browser.screenY + y, false, null);
   },
 
   hideTooltip() {
     let elt = document.getElementById("remoteBrowserTooltip");
     elt.hidePopup();
   },
 
   getTabCount() {
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -625,24 +625,24 @@
           let tabWidth = draggedTab.getBoundingClientRect().width;
           let shiftWidth = tabWidth * movingTabs.length;
           draggedTab._dragData.tabWidth = tabWidth;
 
           // Move the dragged tab based on the mouse position.
 
           let leftTab = tabs[0];
           let rightTab = tabs[tabs.length - 1];
-          let rightMovingTabScreenX = movingTabs[movingTabs.length - 1].boxObject.screenX;
-          let leftMovingTabScreenX = movingTabs[0].boxObject.screenX;
+          let rightMovingTabScreenX = movingTabs[movingTabs.length - 1].screenX;
+          let leftMovingTabScreenX = movingTabs[0].screenX;
           let translateX = screenX - draggedTab._dragData.screenX;
           if (!pinned) {
             translateX += this.arrowScrollbox.scrollbox.scrollLeft - draggedTab._dragData.scrollX;
           }
-          let leftBound = leftTab.boxObject.screenX - leftMovingTabScreenX;
-          let rightBound = (rightTab.boxObject.screenX + rightTab.boxObject.width) -
+          let leftBound = leftTab.screenX - leftMovingTabScreenX;
+          let rightBound = (rightTab.screenX + rightTab.boxObject.width) -
                            (rightMovingTabScreenX + tabWidth);
           translateX = Math.min(Math.max(translateX, leftBound), rightBound);
 
           for (let tab of movingTabs) {
             tab.style.transform = "translateX(" + translateX + "px)";
           }
 
           draggedTab._dragData.translateX = translateX;
@@ -667,21 +667,20 @@
           let oldIndex = "animDropIndex" in draggedTab._dragData ?
                          draggedTab._dragData.animDropIndex : movingTabs[0]._tPos;
           let low = 0;
           let high = tabs.length - 1;
           while (low <= high) {
             let mid = Math.floor((low + high) / 2);
             if (tabs[mid] == draggedTab && ++mid > high)
               break;
-            let boxObject = tabs[mid].boxObject;
-            screenX = boxObject.screenX + getTabShift(tabs[mid], oldIndex);
+            screenX = tabs[mid].screenX + getTabShift(tabs[mid], oldIndex);
             if (screenX > tabCenter) {
               high = mid - 1;
-            } else if (screenX + boxObject.width < tabCenter) {
+            } else if (screenX + tabs[mid].getBoundingClientRect().width < tabCenter) {
               low = mid + 1;
             } else {
               newIndex = tabs[mid]._tPos;
               break;
             }
           }
           if (newIndex >= oldIndex)
             newIndex++;
@@ -993,37 +992,37 @@
 
       <method name="_getDragTargetTab">
         <parameter name="event"/>
         <parameter name="isLink"/>
         <body><![CDATA[
           let tab = event.target.localName == "tab" ? event.target : null;
           if (tab && isLink) {
             let boxObject = tab.boxObject;
-            if (event.screenX < boxObject.screenX + boxObject.width * .25 ||
-                event.screenX > boxObject.screenX + boxObject.width * .75)
+            if (event.screenX < tab.screenX + boxObject.width * .25 ||
+                event.screenX > tab.screenX + boxObject.width * .75)
               return null;
           }
           return tab;
         ]]></body>
       </method>
 
       <method name="_getDropIndex">
         <parameter name="event"/>
         <parameter name="isLink"/>
         <body><![CDATA[
           var tabs = this.children;
           var tab = this._getDragTargetTab(event, isLink);
           if (!RTL_UI) {
             for (let i = tab ? tab._tPos : 0; i < tabs.length; i++)
-              if (event.screenX < tabs[i].boxObject.screenX + tabs[i].boxObject.width / 2)
+              if (event.screenX < tabs[i].screenX + tabs[i].boxObject.width / 2)
                 return i;
           } else {
             for (let i = tab ? tab._tPos : 0; i < tabs.length; i++)
-              if (event.screenX > tabs[i].boxObject.screenX + tabs[i].boxObject.width / 2)
+              if (event.screenX > tabs[i].screenX + tabs[i].boxObject.width / 2)
                 return i;
           }
           return tabs.length;
         ]]></body>
       </method>
 
       <method name="_getDropEffectForTabDrag">
         <parameter name="event"/>
--- a/browser/components/customizableui/PanelMultiView.jsm
+++ b/browser/components/customizableui/PanelMultiView.jsm
@@ -1052,32 +1052,34 @@ var PanelMultiView = class extends Assoc
     }
   }
 
   _calculateMaxHeight() {
     // While opening the panel, we have to limit the maximum height of any
     // view based on the space that will be available. We cannot just use
     // window.screen.availTop and availHeight because these may return an
     // incorrect value when the window spans multiple screens.
-    let anchorBox = this._panel.anchorNode.boxObject;
-    let screen = this._screenManager.screenForRect(anchorBox.screenX,
-                                                   anchorBox.screenY,
+    let anchor = this._panel.anchorNode;
+    let anchorBox = anchor.boxObject;
+
+    let screen = this._screenManager.screenForRect(anchor.screenX,
+                                                   anchor.screenY,
                                                    anchorBox.width,
                                                    anchorBox.height);
     let availTop = {}, availHeight = {};
     screen.GetAvailRect({}, availTop, {}, availHeight);
     let cssAvailTop = availTop.value / screen.defaultCSSScaleFactor;
 
     // The distance from the anchor to the available margin of the screen is
     // based on whether the panel will open towards the top or the bottom.
     let maxHeight;
     if (this._panel.alignmentPosition.startsWith("before_")) {
-      maxHeight = anchorBox.screenY - cssAvailTop;
+      maxHeight = anchor.screenY - cssAvailTop;
     } else {
-      let anchorScreenBottom = anchorBox.screenY + anchorBox.height;
+      let anchorScreenBottom = anchor.screenY + anchorBox.height;
       let cssAvailHeight = availHeight.value / screen.defaultCSSScaleFactor;
       maxHeight = cssAvailTop + cssAvailHeight - anchorScreenBottom;
     }
 
     // To go from the maximum height of the panel to the maximum height of
     // the view stack, we need to subtract the height of the arrow and the
     // height of the opposite margin, but we cannot get their actual values
     // because the panel is not visible yet. However, we know that this is
--- a/browser/components/extensions/test/browser/browser_ext_popup_select.js
+++ b/browser/components/extensions/test/browser/browser_ext_popup_select.js
@@ -63,23 +63,22 @@ add_task(async function testPopupSelectP
 
     let elemRect = await ContentTask.spawn(browser, null, async function() {
       let elem = content.document.getElementById("select");
       let r = elem.getBoundingClientRect();
 
       return {left: r.left, bottom: r.bottom};
     });
 
-    let {boxObject} = browser;
     let popupRect = selectPopup.getOuterScreenRect();
 
-    is(Math.floor(boxObject.screenX + elemRect.left), popupRect.left,
+    is(Math.floor(browser.screenX + elemRect.left), popupRect.left,
        "Select popup has the correct x origin");
 
-    is(Math.floor(boxObject.screenY + elemRect.bottom), popupRect.top,
+    is(Math.floor(browser.screenY + elemRect.bottom), popupRect.top,
        "Select popup has the correct y origin");
 
     // Close the select popup before proceeding to the next test.
     const onPopupHidden = BrowserTestUtils.waitForEvent(selectPopup, "popuphidden");
     selectPopup.hidePopup();
     await onPopupHidden;
   }
 
--- a/browser/components/places/content/menu.xml
+++ b/browser/components/places/content/menu.xml
@@ -433,20 +433,20 @@
           return;
         }
 
         // We should display the drop indicator relative to the arrowscrollbox.
         let scrollbox = this._scrollBox.scrollBoxObject;
         let newMarginTop = 0;
         if (scrollDir == 0) {
           let elt = this.firstElementChild;
-          while (elt && event.screenY > elt.boxObject.screenY +
+          while (elt && event.screenY > elt.screenY +
                                         elt.boxObject.height / 2)
             elt = elt.nextElementSibling;
-          newMarginTop = elt ? elt.boxObject.screenY - scrollbox.screenY :
+          newMarginTop = elt ? elt.screenY - this._scrollBox.screenY :
                                scrollbox.height;
         } else if (scrollDir == 1)
           newMarginTop = scrollbox.height;
 
         // Set the new marginTop based on arrowscrollbox.
         newMarginTop += scrollbox.y - this._scrollBox.boxObject.y;
         this._indicatorBar.firstElementChild.style.marginTop = newMarginTop + "px";
         this._indicatorBar.hidden = false;
--- a/browser/config/tooltool-manifests/win32/build-clang-cl.manifest
+++ b/browser/config/tooltool-manifests/win32/build-clang-cl.manifest
@@ -1,15 +1,15 @@
 [
   {
-    "version": "Visual Studio 2017 15.4.2 / SDK 10.0.15063.0",
-    "digest": "18700889e6b5e81613b9cf57ce4e0d46a6ee45bb4c5c33bae2604a5275326128775b8a032a1eb178c5db973746d565340c4e36d98375789e1d5bd836ab16ba58",
-    "size": 303146863,
+    "version": "Visual Studio 2017 15.8.4 / SDK 10.0.17134.0",
+    "digest": "ecf1e03f6f98f86775059a43f9e7dc7e326f6643d7c08962d9f614e4f5a65b1ca63fa1cfeb0f1a3c2474bf0d4318dda960b378beb2a44ecf8a91111207f4ece5",
+    "size": 349626009,
     "algorithm": "sha512",
-    "filename": "vs2017_15.4.2.zip",
+    "filename": "vs2017_15.8.4.zip",
     "unpack": true
   },
   {
     "version": "SVN 1.9.4, repacked from SlikSvn (https://sliksvn.com/download/)",
     "size": 3934520,
     "digest": "d3b8f74936857ecbf542e403ed6835938a31d65302985729cbfa7191bf2cf94138565cefcc2f31517098013fbfc51868348863a55b588250902f9dec214dbc42",
     "algorithm": "sha512",
     "filename": "svn194.zip",
--- a/browser/config/tooltool-manifests/win32/gn-build.manifest
+++ b/browser/config/tooltool-manifests/win32/gn-build.manifest
@@ -1,15 +1,15 @@
 [
   {
-    "version": "Visual Studio 2017 15.4.2 / SDK 10.0.15063.0",
-    "size": 303146863,
-    "digest": "18700889e6b5e81613b9cf57ce4e0d46a6ee45bb4c5c33bae2604a5275326128775b8a032a1eb178c5db973746d565340c4e36d98375789e1d5bd836ab16ba58",
+    "version": "Visual Studio 2017 15.8.4 / SDK 10.0.17134.0",
+    "digest": "ecf1e03f6f98f86775059a43f9e7dc7e326f6643d7c08962d9f614e4f5a65b1ca63fa1cfeb0f1a3c2474bf0d4318dda960b378beb2a44ecf8a91111207f4ece5",
+    "size": 349626009,
     "algorithm": "sha512",
-    "filename": "vs2017_15.4.2.zip",
+    "filename": "vs2017_15.8.4.zip",
     "unpack": true
   },
   {
     "version": "Ninja 1.7.1",
     "size": 184821,
     "digest": "e4f9a1ae624a2630e75264ba37d396d9c7407d6e6aea3763056210ba6e1387908bd31cf4037a6a3661a418e86c4d2761e0c333e6a3bd0d66549d2b0d72d3f43b",
     "algorithm": "sha512",
     "filename": "ninja171.zip",
@@ -18,9 +18,9 @@
   {
     "version": "MinGit-2.13.3-64-bit",
     "size": 21482885,
     "digest": "929bb3c07be8487ee519422a312bdbfeec8f4db4b62c49d02f9aad9fd2a66c0ee5fad63d2b06c8744c336dc9d50446fa4457897333ad17ffd783ecabd1e2ddbb",
     "algorithm": "sha512",
     "filename": "git.zip",
     "unpack": true
   }
-]
\ No newline at end of file
+]
--- a/browser/config/tooltool-manifests/win64/sccache-build.manifest
+++ b/browser/config/tooltool-manifests/win64/sccache-build.manifest
@@ -1,15 +1,15 @@
 [
   {
-    "version": "Visual Studio 2017 15.4.2 / SDK 10.0.15063.0",
-    "size": 303146863,
-    "digest": "18700889e6b5e81613b9cf57ce4e0d46a6ee45bb4c5c33bae2604a5275326128775b8a032a1eb178c5db973746d565340c4e36d98375789e1d5bd836ab16ba58",
+    "version": "Visual Studio 2017 15.8.4 / SDK 10.0.17134.0",
+    "digest": "ecf1e03f6f98f86775059a43f9e7dc7e326f6643d7c08962d9f614e4f5a65b1ca63fa1cfeb0f1a3c2474bf0d4318dda960b378beb2a44ecf8a91111207f4ece5",
+    "size": 349626009,
     "algorithm": "sha512",
-    "filename": "vs2017_15.4.2.zip",
+    "filename": "vs2017_15.8.4.zip",
     "unpack": true
   },
   {
     "version": "MinGit-2.13.3-64-bit",
     "size": 21482885,
     "digest": "929bb3c07be8487ee519422a312bdbfeec8f4db4b62c49d02f9aad9fd2a66c0ee5fad63d2b06c8744c336dc9d50446fa4457897333ad17ffd783ecabd1e2ddbb",
     "algorithm": "sha512",
     "filename": "git.zip",
--- a/browser/tools/mozscreenshots/browser_boundingbox.js
+++ b/browser/tools/mozscreenshots/browser_boundingbox.js
@@ -4,24 +4,24 @@
 
 "use strict";
 
 add_task(async function() {
   const scale = window.docShell
                       .QueryInterface(Ci.nsIBaseWindow)
                       .devicePixelsPerDesktopPixel;
   let {bounds, rects} = TestRunner._findBoundingBox(["#tabbrowser-tabs"]);
-  let element = document.querySelector("#tabbrowser-tabs");
-  let tabBar = element.ownerDocument.getBoxObjectFor(element);
+  let tabBar = document.querySelector("#tabbrowser-tabs");
+  let tabBarRect = tabBar.getBoundingClientRect();
 
   // Calculate expected values
   let expectedLeft = scale * (tabBar.screenX - TestRunner.croppingPadding);
   let expectedTop = scale * (tabBar.screenY - TestRunner.croppingPadding);
-  let expectedRight = scale * (tabBar.width + TestRunner.croppingPadding * 2) + expectedLeft;
-  let expectedBottom = scale * (tabBar.height + TestRunner.croppingPadding * 2) + expectedTop;
+  let expectedRight = scale * (tabBarRect.width + TestRunner.croppingPadding * 2) + expectedLeft;
+  let expectedBottom = scale * (tabBarRect.height + TestRunner.croppingPadding * 2) + expectedTop;
 
   // Calculate browser region
   let windowLeft = window.screenX * scale;
   let windowTop = window.screenY * scale;
   let windowRight = window.outerWidth * scale + windowLeft;
   let windowBottom = window.outerHeight * scale + windowTop;
 
   // Adjust values based on browser window
@@ -43,31 +43,31 @@ add_task(async function() {
     "Checking _findBoundingBox union.top and rect.top is the same for a single selector");
   is(bounds.bottom, rects[0].bottom,
     "Checking _findBoundingBox union.bottom and rect.bottom is the same for a single selector");
 
   let result = TestRunner._findBoundingBox(["#forward-button", "#TabsToolbar"]);
   bounds = result.bounds;
   rects = result.rects;
 
-  element = document.querySelector("#TabsToolbar");
-  let tabToolbar = element.ownerDocument.getBoxObjectFor(element);
-  element = document.querySelector("#forward-button");
-  let fButton = element.ownerDocument.getBoxObjectFor(element);
+  let tabToolbar = document.querySelector("#TabsToolbar");
+  let tabToolbarRect = tabToolbar.getBoundingClientRect();
+  let fButton = document.querySelector("#forward-button");
+  let fButtonRect = fButton.getBoundingClientRect();
 
   // Calculate expected values
   expectedLeft = scale * (Math.min(tabToolbar.screenX, fButton.screenX)
                               - TestRunner.croppingPadding);
   expectedTop = scale * (Math.min(tabToolbar.screenY, fButton.screenY)
                               - TestRunner.croppingPadding);
-  expectedRight = scale * (Math.max(tabToolbar.width + tabToolbar.screenX,
-                                    fButton.width + fButton.screenX)
+  expectedRight = scale * (Math.max(tabToolbarRect.width + tabToolbar.screenX,
+                                    fButtonRect.width + fButton.screenX)
                               + TestRunner.croppingPadding);
-  expectedBottom = scale * (Math.max(tabToolbar.height + tabToolbar.screenY,
-                                     fButton.height + fButton.screenY)
+  expectedBottom = scale * (Math.max(tabToolbarRect.height + tabToolbar.screenY,
+                                     fButtonRect.height + fButton.screenY)
                               + TestRunner.croppingPadding );
 
   // Adjust values based on browser window
   expectedLeft = Math.max(expectedLeft, windowLeft);
   expectedTop = Math.max(expectedTop, windowTop);
   expectedRight = Math.min(expectedRight, windowRight);
   expectedBottom = Math.min(expectedBottom, windowBottom);
 
@@ -76,23 +76,23 @@ add_task(async function() {
      "Checking _findBoundingBox union width calculation");
   // Check height calculation on union
   is(bounds.height, expectedBottom - expectedTop,
      "Checking _findBoundingBox union height calculation");
   // Check single selector's left position
   is(rects[0].left, Math.max(scale * (fButton.screenX - TestRunner.croppingPadding), windowLeft),
     "Checking single selector's left position when _findBoundingBox has multiple selectors");
   // Check single selector's right position
-  is(rects[0].right, Math.min(scale * (fButton.width + fButton.screenX + TestRunner.croppingPadding), windowRight),
+  is(rects[0].right, Math.min(scale * (fButtonRect.width + fButton.screenX + TestRunner.croppingPadding), windowRight),
     "Checking single selector's right position when _findBoundingBox has multiple selectors");
   // Check single selector's top position
   is(rects[0].top, Math.max(scale * (fButton.screenY - TestRunner.croppingPadding), windowTop),
     "Checking single selector's top position when _findBoundingBox has multiple selectors");
   // Check single selector's bottom position
-  is(rects[0].bottom, Math.min(scale * (fButton.height + fButton.screenY + TestRunner.croppingPadding), windowBottom),
+  is(rects[0].bottom, Math.min(scale * (fButtonRect.height + fButton.screenY + TestRunner.croppingPadding), windowBottom),
     "Checking single selector's bottom position when _findBoundingBox has multiple selectors");
 
     // Check that nonexistent selectors throws an exception
   Assert.throws(() => {
     TestRunner._findBoundingBox(["#does_not_exist"]);
   }, /No element for '#does_not_exist' found/, "Checking that nonexistent selectors throws an exception");
 
   // Check that no selectors throws an exception
--- a/browser/tools/mozscreenshots/mozscreenshots/extension/TestRunner.jsm
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/TestRunner.jsm
@@ -252,19 +252,19 @@ var TestRunner = {
         element = browserWindow.document.querySelector(selector);
       }
 
       if (!element) {
         throw `No element for '${selector}' found.`;
       }
 
       // Calculate box region, convert to Rect
-      let box = element.ownerDocument.getBoxObjectFor(element);
-      let rect = new Rect(box.screenX * scale, box.screenY * scale,
-                             box.width * scale, box.height * scale);
+      let elementRect = element.getBoundingClientRect();
+      let rect = new Rect(element.screenX * scale, element.screenY * scale,
+                             elementRect.width * scale, elementRect.height * scale);
       rect.inflateFixed(this.croppingPadding * scale);
       rect.left = Math.max(rect.left, windowLeft);
       rect.top = Math.max(rect.top, windowTop);
       rect.right = Math.min(rect.right, windowLeft + windowWidth);
       rect.bottom = Math.min(rect.bottom, windowTop + windowHeight);
       rects.push(rect);
 
       if (!bounds) {
--- a/devtools/client/webconsole/reducers/messages.js
+++ b/devtools/client/webconsole/reducers/messages.js
@@ -120,16 +120,18 @@ function addMessage(state, filtersState,
     }
   }
 
   // Add the new message with a reference to the parent group.
   const parentGroups = getParentGroups(currentGroup, groupsById);
   newMessage.groupId = currentGroup;
   newMessage.indent = parentGroups.length;
 
+  ensureExecutionPoint(state, newMessage);
+
   const addedMessage = Object.freeze(newMessage);
   state.messagesById.set(newMessage.id, addedMessage);
 
   if (newMessage.type === "trace") {
     // We want the stacktrace to be open by default.
     state.messagesUiById.push(newMessage.id);
   } else if (isGroupType(newMessage.type)) {
     state.currentGroup = newMessage.id;
@@ -143,16 +145,17 @@ function addMessage(state, filtersState,
 
   const {
     visible,
     cause,
   } = getMessageVisibility(addedMessage, state, filtersState);
 
   if (visible) {
     state.visibleMessages.push(newMessage.id);
+    maybeSortVisibleMessages(state);
   } else if (DEFAULT_FILTERS.includes(cause)) {
     state.filteredMessagesCount.global++;
     state.filteredMessagesCount[cause]++;
   }
 
   // Append received network-data also into networkMessagesUpdateById
   // that is responsible for collecting (lazy loaded) HTTP payload data.
   if (newMessage.source == "network") {
@@ -360,21 +363,24 @@ function messages(state = MessageState()
         if (visible) {
           messagesToShow.push(msgId);
         } else if (DEFAULT_FILTERS.includes(cause)) {
           filtered.global = filtered.global + 1;
           filtered[cause] = filtered[cause] + 1;
         }
       });
 
-      return {
+      const filteredState = {
         ...state,
         visibleMessages: messagesToShow,
         filteredMessagesCount: filtered,
       };
+      maybeSortVisibleMessages(filteredState);
+
+      return filteredState;
   }
 
   return state;
 }
 
 /**
  * Returns the new current group id given the previous current group and the groupsById
  * state property.
@@ -934,9 +940,82 @@ function getDefaultFiltersCounter() {
   const count = DEFAULT_FILTERS.reduce((res, filter) => {
     res[filter] = 0;
     return res;
   }, {});
   count.global = 0;
   return count;
 }
 
+// Make sure that message has an execution point which can be used for sorting
+// if other messages with real execution points appear later.
+function ensureExecutionPoint(state, newMessage) {
+  if (newMessage.executionPoint) {
+    return;
+  }
+
+  // Add a lastExecutionPoint property which will place this message immediately
+  // after the last visible one when sorting.
+  let point = { progress: 0 }, messageCount = 1;
+  if (state.visibleMessages.length) {
+    const lastId = state.visibleMessages[state.visibleMessages.length - 1];
+    const lastMessage = state.messagesById.get(lastId);
+    if (lastMessage.executionPoint) {
+      point = lastMessage.executionPoint;
+    } else {
+      point = lastMessage.lastExecutionPoint.point;
+      messageCount = lastMessage.lastExecutionPoint.messageCount + 1;
+    }
+  }
+  newMessage.lastExecutionPoint = { point, messageCount };
+}
+
+function messageExecutionPoint(state, id) {
+  const message = state.messagesById.get(id);
+  return message.executionPoint || message.lastExecutionPoint.point;
+}
+
+function messageCountSinceLastExecutionPoint(state, id) {
+  const message = state.messagesById.get(id);
+  return message.lastExecutionPoint ? message.lastExecutionPoint.messageCount : 0;
+}
+
+function maybeSortVisibleMessages(state) {
+  // When using log points while replaying, messages can be added out of order
+  // with respect to how they originally executed. Use the execution point
+  // information in the messages to sort visible messages according to how
+  // they originally executed. This isn't necessary if we haven't seen any
+  // messages with progress counters, as either we aren't replaying or haven't
+  // seen any messages yet.
+  if (state.replayProgressMessages.size) {
+    state.visibleMessages.sort((a, b) => {
+      const pointA = messageExecutionPoint(state, a);
+      const pointB = messageExecutionPoint(state, b);
+      if (pointA.progress != pointB.progress) {
+        return pointA.progress > pointB.progress;
+      }
+      // Execution points without a progress counter predate execution points
+      // with one, i.e. a console.log() call (which bumps the progress value)
+      // predates the code that runs afterward.
+      if ("frameIndex" in pointA != "frameIndex" in pointB) {
+        return "frameIndex" in pointA;
+      }
+      // Deeper frames predate shallower frames, if the progress counter is the
+      // same. We bump the progress counter when pushing frames, but not when
+      // popping them.
+      if (pointA.frameIndex != pointB.frameIndex) {
+        return pointA.frameIndex < pointB.frameIndex;
+      }
+      // Earlier script locations predate later script locations.
+      if (pointA.offset != pointB.offset) {
+        return pointA.offset > pointB.offset;
+      }
+      // When messages don't have their own execution point, they can still be
+      // distinguished by the number of messages since the last one which did
+      // have an execution point.
+      const countA = messageCountSinceLastExecutionPoint(state, a);
+      const countB = messageCountSinceLastExecutionPoint(state, b);
+      return countA > countB;
+    });
+  }
+}
+
 exports.messages = messages;
--- a/devtools/client/webconsole/utils/messages.js
+++ b/devtools/client/webconsole/utils/messages.js
@@ -330,16 +330,17 @@ function getRepeatId(message) {
     level: message.level,
     messageText: message.messageText,
     parameters: message.parameters,
     source: message.source,
     type: message.type,
     userProvidedStyles: message.userProvidedStyles,
     private: message.private,
     stacktrace: message.stacktrace,
+    executionPoint: message.executionPoint,
   });
 }
 
 function convertCachedPacket(packet) {
   // The devtools server provides cached message packets in a different shape, so we
   // transform them here.
   let convertPacket = {};
   if (packet._type === "ConsoleAPI") {
--- a/devtools/client/webconsole/webconsole-connection-proxy.js
+++ b/devtools/client/webconsole/webconsole-connection-proxy.js
@@ -25,17 +25,16 @@ const PREF_CONNECTION_TIMEOUT = "devtool
 function WebConsoleConnectionProxy(webConsoleUI, target) {
   this.webConsoleUI = webConsoleUI;
   this.target = target;
   this.webConsoleClient = target.activeConsole;
 
   this._onPageError = this._onPageError.bind(this);
   this._onLogMessage = this._onLogMessage.bind(this);
   this._onConsoleAPICall = this._onConsoleAPICall.bind(this);
-  this._onVirtualConsoleLog = this._onVirtualConsoleLog.bind(this);
   this._onNetworkEvent = this._onNetworkEvent.bind(this);
   this._onNetworkEventUpdate = this._onNetworkEventUpdate.bind(this);
   this._onTabNavigated = this._onTabNavigated.bind(this);
   this._onTabWillNavigate = this._onTabWillNavigate.bind(this);
   this._onAttachConsole = this._onAttachConsole.bind(this);
   this._onCachedMessages = this._onCachedMessages.bind(this);
   this._connectionTimeout = this._connectionTimeout.bind(this);
   this._onLastPrivateContextExited =
@@ -123,18 +122,16 @@ WebConsoleConnectionProxy.prototype = {
 
     const client = this.client = this.target.client;
 
     client.addListener("logMessage", this._onLogMessage);
     client.addListener("pageError", this._onPageError);
     client.addListener("consoleAPICall", this._onConsoleAPICall);
     client.addListener("lastPrivateContextExited",
                        this._onLastPrivateContextExited);
-    client.addListener("virtualConsoleLog",
-                       this._onVirtualConsoleLog);
 
     this.target.on("will-navigate", this._onTabWillNavigate);
     this.target.on("navigate", this._onTabNavigated);
 
     if (this.target.isBrowsingContext) {
       this.webConsoleUI.onLocationChange(this.target.url, this.target.title);
     }
     this.isAttached = this._attachConsole();
@@ -307,29 +304,16 @@ WebConsoleConnectionProxy.prototype = {
    */
   _onConsoleAPICall: function(type, packet) {
     if (!this.webConsoleUI || packet.from != this.webConsoleClient.actor) {
       return;
     }
     this.dispatchMessageAdd(packet);
   },
 
-  _onVirtualConsoleLog: function(type, packet) {
-    if (!this.webConsoleUI) {
-      return;
-    }
-    this.dispatchMessageAdd({
-      type: "consoleAPICall",
-      message: {
-        executionPoint: packet.executionPoint,
-        "arguments": [packet.url + ":" + packet.line, packet.message],
-      },
-    });
-  },
-
   /**
    * The "networkEvent" message type handler. We redirect any message to
    * the UI for displaying.
    *
    * @private
    * @param object networkInfo
    *        The network request information.
    */
@@ -433,18 +417,16 @@ WebConsoleConnectionProxy.prototype = {
       return this._disconnecter.promise;
     }
 
     this.client.removeListener("logMessage", this._onLogMessage);
     this.client.removeListener("pageError", this._onPageError);
     this.client.removeListener("consoleAPICall", this._onConsoleAPICall);
     this.client.removeListener("lastPrivateContextExited",
                                this._onLastPrivateContextExited);
-    this.client.removeListener("virtualConsoleLog",
-                               this._onVirtualConsoleLog);
     this.webConsoleClient.off("networkEvent", this._onNetworkEvent);
     this.webConsoleClient.off("networkEventUpdate", this._onNetworkEventUpdate);
     this.target.off("will-navigate", this._onTabWillNavigate);
     this.target.off("navigate", this._onTabNavigated);
 
     this.client = null;
     this.webConsoleClient = null;
     this.target = null;
--- a/devtools/server/actors/breakpoint.js
+++ b/devtools/server/actors/breakpoint.js
@@ -94,26 +94,24 @@ BreakpointActor.prototype = {
       // When replaying, logging breakpoints are handled using an API to get logged
       // messages from throughout the recording.
       const oldLogValue = oldOptions && oldOptions.logValue;
       const newLogValue = newOptions && newOptions.logValue;
       if (oldLogValue != newLogValue) {
         for (const offset of offsets) {
           const { lineNumber, columnNumber } = script.getOffsetLocation(offset);
           script.replayVirtualConsoleLog(offset, newLogValue, (point, rv) => {
-            const packet = {
-              from: this.actorID,
-              type: "virtualConsoleLog",
-              url: script.url,
-              line: lineNumber,
-              column: columnNumber,
+            const message = {
+              filename: script.url,
+              lineNumber,
+              columnNumber,
               executionPoint: point,
-              message: "return" in rv ? "" + rv.return : "" + rv.throw,
+              "arguments": ["return" in rv ? rv.return : rv.throw],
             };
-            this.conn.send(packet);
+            this.threadActor._parent._consoleActor.onConsoleAPICall(message);
           });
         }
       }
     }
   },
 
   /**
    * Check if this breakpoint has a condition that doesn't error and
--- a/devtools/server/actors/replay/debugger.js
+++ b/devtools/server/actors/replay/debugger.js
@@ -377,18 +377,19 @@ ReplayDebugger.prototype = {
               type: "getFrame",
               index: NewestFrameIndex,
             });
             if ("index" in frameData) {
               const rv = this._searchControl.sendRequest({
                 type: "frameEvaluate",
                 index: frameData.index,
                 text,
+                convertOptions: { snapshot: true },
               });
-              evaluateResult = this._convertCompletionValue(rv, { forSearch: true });
+              evaluateResult = this._convertCompletionValue(rv);
             }
           }
           results.push(point);
           callback(point, evaluateResult);
         }
       }
     }
   },
@@ -525,69 +526,59 @@ ReplayDebugger.prototype = {
     const data = this._sendRequest({ type: "findSources" });
     return data.map(source => this._addSource(source));
   },
 
   /////////////////////////////////////////////////////////
   // Object methods
   /////////////////////////////////////////////////////////
 
-  _getObject(id, options) {
-    if (options && options.forSearch) {
-      // Returning objects through searches is NYI.
-      return "<UnknownSearchObject>";
-    }
-    const forConsole = options && options.forConsole;
-
+  _getObject(id) {
     if (id && !this._objects[id]) {
       const data = this._sendRequest({ type: "getObject", id });
       switch (data.kind) {
       case "Object":
-        // Objects which |forConsole| is set are objects that were logged in
-        // console messages, and had their properties recorded so that they can
-        // be inspected without switching to a replaying child.
-        this._objects[id] = new ReplayDebuggerObject(this, data, forConsole);
+        this._objects[id] = new ReplayDebuggerObject(this, data);
         break;
       case "Environment":
         this._objects[id] = new ReplayDebuggerEnvironment(this, data);
         break;
       default:
         ThrowError("Unknown object kind");
       }
     }
-    const rv = this._objects[id];
-    if (forConsole) {
-      rv._forConsole = true;
-    }
-    return rv;
+    return this._objects[id];
   },
 
   // Convert a value we received from the child.
-  _convertValue(value, options) {
+  _convertValue(value) {
     if (isNonNullObject(value)) {
       if (value.object) {
-        return this._getObject(value.object, options);
+        return this._getObject(value.object);
+      }
+      if (value.snapshot) {
+        return new ReplayDebuggerObjectSnapshot(this, value.snapshot);
       }
       switch (value.special) {
       case "undefined": return undefined;
       case "Infinity": return Infinity;
       case "-Infinity": return -Infinity;
       case "NaN": return NaN;
       case "0": return -0;
       }
     }
     return value;
   },
 
-  _convertCompletionValue(value, options) {
+  _convertCompletionValue(value) {
     if ("return" in value) {
-      return { return: this._convertValue(value.return, options) };
+      return { return: this._convertValue(value.return) };
     }
     if ("throw" in value) {
-      return { throw: this._convertValue(value.throw, options) };
+      return { throw: this._convertValue(value.throw) };
     }
     ThrowError("Unexpected completion value");
     return null; // For eslint
   },
 
   // Convert a value for sending to the child.
   _convertValueForChild(value) {
     if (isNonNullObject(value)) {
@@ -642,18 +633,17 @@ ReplayDebugger.prototype = {
   // Console Message methods
   /////////////////////////////////////////////////////////
 
   _convertConsoleMessage(message) {
     // Console API message arguments need conversion to debuggee values, but
     // other contents of the message can be left alone.
     if (message.messageType == "ConsoleAPI" && message.arguments) {
       for (let i = 0; i < message.arguments.length; i++) {
-        message.arguments[i] = this._convertValue(message.arguments[i],
-                                                  { forConsole: true });
+        message.arguments[i] = this._convertValue(message.arguments[i]);
       }
     }
     return message;
   },
 
   /////////////////////////////////////////////////////////
   // Handlers
   /////////////////////////////////////////////////////////
@@ -897,20 +887,19 @@ ReplayDebuggerFrame.prototype = {
   get implementation() { NYI(); },
   evalWithBindings: NYI,
 };
 
 ///////////////////////////////////////////////////////////////////////////////
 // ReplayDebuggerObject
 ///////////////////////////////////////////////////////////////////////////////
 
-function ReplayDebuggerObject(dbg, data, forConsole) {
+function ReplayDebuggerObject(dbg, data) {
   this._dbg = dbg;
   this._data = data;
-  this._forConsole = forConsole;
   this._properties = null;
   this._proxyData = null;
 }
 
 ReplayDebuggerObject.prototype = {
   _invalidate() {
     this._data = null;
     this._properties = null;
@@ -928,28 +917,22 @@ ReplayDebuggerObject.prototype = {
   get parameterNames() { return this._data.parameterNames; },
   get script() { return this._dbg._getScript(this._data.script); },
   get environment() { return this._dbg._getObject(this._data.environment); },
   get boundTargetFunction() { return this.isBoundFunction ? NYI() : undefined; },
   get boundThis() { return this.isBoundFunction ? NYI() : undefined; },
   get boundArguments() { return this.isBoundFunction ? NYI() : undefined; },
   get global() { return this._dbg._getObject(this._data.global); },
   get isProxy() { return this._data.isProxy; },
+  get proto() { return this._dbg._getObject(this._data.proto); },
 
   isExtensible() { return this._data.isExtensible; },
   isSealed() { return this._data.isSealed; },
   isFrozen() { return this._data.isFrozen; },
 
-  get proto() {
-    // Don't allow inspection of the prototypes of objects logged to the
-    // console. This is a hack that prevents the object inspector from crawling
-    // the object's prototype chain.
-    return this._forConsole ? null : this._dbg._getObject(this._data.proto);
-  },
-
   unsafeDereference() {
     // Direct access to the referent is not currently available.
     return null;
   },
 
   getOwnPropertyNames() {
     this._ensureProperties();
     return Object.keys(this._properties);
@@ -964,19 +947,18 @@ ReplayDebuggerObject.prototype = {
     this._ensureProperties();
     const desc = this._properties[name];
     return desc ? this._convertPropertyDescriptor(desc) : undefined;
   },
 
   _ensureProperties() {
     if (!this._properties) {
       const id = this._data.id;
-      const properties = this._forConsole
-        ? this._dbg._sendRequest({ type: "getObjectPropertiesForConsole", id })
-        : this._dbg._sendRequestAllowDiverge({ type: "getObjectProperties", id });
+      const properties =
+        this._dbg._sendRequestAllowDiverge({ type: "getObjectProperties", id });
       this._properties = Object.create(null);
       properties.forEach(({name, desc}) => { this._properties[name] = desc; });
     }
   },
 
   _convertPropertyDescriptor(desc) {
     const rv = Object.assign({}, desc);
     if ("value" in desc) {
@@ -1055,16 +1037,33 @@ ReplayDebuggerObject.prototype = {
   freeze: NotAllowed,
   defineProperty: NotAllowed,
   defineProperties: NotAllowed,
   deleteProperty: NotAllowed,
   forceLexicalInitializationByName: NotAllowed,
 };
 
 ///////////////////////////////////////////////////////////////////////////////
+// ReplayDebuggerObjectSnapshot
+///////////////////////////////////////////////////////////////////////////////
+
+// Create an object based on snapshot data which can be consulted without
+// communicating with the child process. This uses data provided by the child
+// process in the same format as for normal ReplayDebuggerObjects, except that
+// it does not contain references to any other objects.
+function ReplayDebuggerObjectSnapshot(dbg, data) {
+  this._dbg = dbg;
+  this._data = data;
+  this._properties = Object.create(null);
+  data.properties.forEach(({name, desc}) => { this._properties[name] = desc; });
+}
+
+ReplayDebuggerObjectSnapshot.prototype = ReplayDebuggerObject.prototype;
+
+///////////////////////////////////////////////////////////////////////////////
 // ReplayDebuggerEnvironment
 ///////////////////////////////////////////////////////////////////////////////
 
 function ReplayDebuggerEnvironment(dbg, data) {
   this._dbg = dbg;
   this._data = data;
   this._names = null;
 }
--- a/devtools/server/actors/replay/replay.js
+++ b/devtools/server/actors/replay/replay.js
@@ -186,34 +186,58 @@ dbg.onNewScript = function(script) {
 
   hitGlobalHandler("NewScript");
 
   // Check in case any handlers we need to install are on the scripts just
   // created.
   installPendingHandlers();
 };
 
-const gConsoleObjectProperties = new Map();
+///////////////////////////////////////////////////////////////////////////////
+// Object Snapshots
+///////////////////////////////////////////////////////////////////////////////
 
-function shouldSaveConsoleProperty({ desc }) {
-  // When logging an object to the console, only properties captured here will
-  // be shown. We limit this to non-object data properties, as more complex
-  // properties have two problems: A) to inspect them we will need to switch to
-  // a replaying child process, which is very slow when there are many console
-  // messages, and B) trying to access objects transitively referred to by
-  // logged console objects will fail when unpaused, and depends on the current
-  // state of the process otherwise.
-  return "value" in desc && !isNonNullObject(desc.value);
+// Snapshots are generated for objects that might be inspected at times when we
+// are not paused at the point where the snapshot was originally taken. The
+// snapshot data is provided to the server, which can use it to provide limited
+// answers to the client about the object's contents, without having to consult
+// a child process.
+
+function snapshotObjectProperty({ name, desc }) {
+  // Only capture primitive properties in object snapshots.
+  if ("value" in desc && !convertedValueIsObject(desc.value)) {
+    return { name, desc };
+  }
+  return { name, desc: { value: "<unavailable>" } };
 }
 
-function saveConsoleObjectProperties(obj) {
-  if (obj instanceof Debugger.Object) {
-    const properties = getObjectProperties(obj).filter(shouldSaveConsoleProperty);
-    gConsoleObjectProperties.set(obj, properties);
-  }
+function makeObjectSnapshot(object) {
+  assert(object instanceof Debugger.Object);
+
+  // Include properties that would be included in a normal object's data packet,
+  // except do not allow inspection of any other referenced objects.
+  // In particular, don't set the prototype so that the object inspector will
+  // not attempt to crawl the object's prototype chain.
+  return {
+    kind: "Object",
+    callable: object.callable,
+    isBoundFunction: object.isBoundFunction,
+    isArrowFunction: object.isArrowFunction,
+    isGeneratorFunction: object.isGeneratorFunction,
+    isAsyncFunction: object.isAsyncFunction,
+    class: object.class,
+    name: object.name,
+    displayName: object.displayName,
+    parameterNames: object.parameterNames,
+    isProxy: object.isProxy,
+    isExtensible: object.isExtensible(),
+    isSealed: object.isSealed(),
+    isFrozen: object.isFrozen(),
+    properties: getObjectProperties(object).map(snapshotObjectProperty),
+  };
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 // Console Message State
 ///////////////////////////////////////////////////////////////////////////////
 
 const gConsoleMessages = [];
 
@@ -276,37 +300,25 @@ Services.obs.addObserver({
     for (const id in apiMessage) {
       if (id != "wrappedJSObject" && id != "arguments") {
         contents[id] = JSON.parse(JSON.stringify(apiMessage[id]));
       }
     }
 
     // Message arguments are preserved as debuggee values.
     if (apiMessage.arguments) {
-      contents.arguments = apiMessage.arguments.map(makeDebuggeeValue);
-      contents.arguments.forEach(saveConsoleObjectProperties);
+      contents.arguments = apiMessage.arguments.map(v => {
+        return convertValue(makeDebuggeeValue(v), { snapshot: true });
+      });
     }
 
     newConsoleMessage("ConsoleAPI", null, contents);
   },
 }, "console-api-log-event");
 
-function convertConsoleMessage(contents) {
-  const result = {};
-  for (const id in contents) {
-    if (id == "arguments" && contents.messageType == "ConsoleAPI") {
-      // Copy arguments over as debuggee values.
-      result.arguments = contents.arguments.map(convertValue);
-    } else {
-      result[id] = contents[id];
-    }
-  }
-  return result;
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 // Position Handler State
 ///////////////////////////////////////////////////////////////////////////////
 
 // Position kinds we are expected to hit.
 let gPositionHandlerKinds = Object.create(null);
 
 // Handlers we tried to install but couldn't due to a script not existing.
@@ -464,35 +476,43 @@ function getObjectId(obj) {
     assert((obj instanceof Debugger.Object) ||
            (obj instanceof Debugger.Environment));
     return gPausedObjects.add(obj);
   }
   return id;
 }
 
 // Convert a value for sending to the parent.
-function convertValue(value) {
+function convertValue(value, options) {
   if (value instanceof Debugger.Object) {
+    if (options && options.snapshot) {
+      return { snapshot: makeObjectSnapshot(value) };
+    }
     return { object: getObjectId(value) };
-  } else if (value === undefined ||
-             value == Infinity ||
-             value == -Infinity ||
-             Object.is(value, NaN) ||
-             Object.is(value, -0)) {
-      return { special: "" + value };
-    }
+  }
+  if (value === undefined ||
+      value == Infinity ||
+      value == -Infinity ||
+      Object.is(value, NaN) ||
+      Object.is(value, -0)) {
+    return { special: "" + value };
+  }
   return value;
 }
 
-function convertCompletionValue(value) {
+function convertedValueIsObject(value) {
+  return isNonNullObject(value) && "object" in value;
+}
+
+function convertCompletionValue(value, options) {
   if ("return" in value) {
-    return { return: convertValue(value.return) };
+    return { return: convertValue(value.return, options) };
   }
   if ("throw" in value) {
-    return { throw: convertValue(value.throw) };
+    return { throw: convertValue(value.throw, options) };
   }
   throw new Error("Unexpected completion value");
 }
 
 // Convert a value we received from the parent.
 function convertValueFromParent(value) {
   if (isNonNullObject(value)) {
     if (value.object) {
@@ -688,25 +708,16 @@ const gRequestHandlers = {
         },
       }];
     }
 
     const object = gPausedObjects.getObject(request.id);
     return getObjectProperties(object);
   },
 
-  getObjectPropertiesForConsole(request) {
-    const object = gPausedObjects.getObject(request.id);
-    const properties = gConsoleObjectProperties.get(object);
-    if (!properties) {
-      throw new Error("Console object properties not saved");
-    }
-    return properties;
-  },
-
   objectProxyData(request) {
     if (!RecordReplayControl.maybeDivergeFromRecording()) {
       return { exception: "Recording divergence in unwrapObject" };
     }
     const obj = gPausedObjects.getObject(request.id);
     return {
       unwrapped: convertValue(obj.unwrap()),
       target: convertValue(obj.proxyTarget),
@@ -789,29 +800,29 @@ const gRequestHandlers = {
 
   frameEvaluate(request) {
     if (!RecordReplayControl.maybeDivergeFromRecording()) {
       return { throw: "Recording divergence in frameEvaluate" };
     }
 
     const frame = scriptFrameForIndex(request.index);
     const rv = frame.eval(request.text, request.options);
-    return convertCompletionValue(rv);
+    return convertCompletionValue(rv, request.convertOptions);
   },
 
   popFrameResult(request) {
     return gPopFrameResult ? convertCompletionValue(gPopFrameResult) : {};
   },
 
   findConsoleMessages(request) {
-    return gConsoleMessages.map(convertConsoleMessage);
+    return gConsoleMessages;
   },
 
   getNewConsoleMessage(request) {
-    return convertConsoleMessage(gConsoleMessages[gConsoleMessages.length - 1]);
+    return gConsoleMessages[gConsoleMessages.length - 1];
   },
 
   currentExecutionPoint(request) {
     return RecordReplayControl.currentExecutionPoint();
   },
 
   recordingEndpoint(request) {
     return RecordReplayControl.recordingEndpoint();
--- a/devtools/shared/client/constants.js
+++ b/devtools/shared/client/constants.js
@@ -32,17 +32,16 @@ const UnsolicitedNotifications = {
   "reflowActivity": "reflowActivity",
   "addonListChanged": "addonListChanged",
   "workerListChanged": "workerListChanged",
   "serviceWorkerRegistrationListChanged": "serviceWorkerRegistrationList",
   "pageError": "pageError",
   "evaluationResult": "evaluationResult",
   "updatedSource": "updatedSource",
   "inspectObject": "inspectObject",
-  "virtualConsoleLog": "virtualConsoleLog",
 
   // newSource is still emitted on the ThreadActor, in addition to the
   // BrowsingContextActor we have to keep it here until ThreadClient is converted to
   // ThreadFront and/or we stop emitting this duplicated events.
   // See ThreadActor.onNewSourceEvent.
   "newSource": "newSource",
 };
 
--- a/dom/base/Timeout.h
+++ b/dom/base/Timeout.h
@@ -84,17 +84,17 @@ class Timeout final : public LinkedListE
 
   // Returned as value of setTimeout()
   uint32_t mTimeoutId;
 
   // Identifies which firing level this Timeout is being processed in
   // when sync loops trigger nested firing.
   uint32_t mFiringId;
 
-#ifdef DEBUG
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
   int64_t mFiringIndex;
 #endif
 
   // The popup state at timeout creation time if not created from
   // another timeout
   PopupBlocker::PopupControlState mPopupState;
 
   // Used to allow several reasons for setting a timeout, where each
--- a/dom/base/TimeoutManager.cpp
+++ b/dom/base/TimeoutManager.cpp
@@ -449,17 +449,17 @@ int32_t gDisableOpenClickDelay;
 TimeoutManager::TimeoutManager(nsGlobalWindowInner& aWindow,
                                uint32_t aMaxIdleDeferMS)
     : mWindow(aWindow),
       mExecutor(new TimeoutExecutor(this, false, 0)),
       mIdleExecutor(new TimeoutExecutor(this, true, aMaxIdleDeferMS)),
       mTimeouts(*this),
       mTimeoutIdCounter(1),
       mNextFiringId(InvalidFiringId + 1),
-#ifdef DEBUG
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
       mFiringIndex(0),
       mLastFiringIndex(-1),
 #endif
       mRunningTimeout(nullptr),
       mIdleTimeouts(*this),
       mIdleCallbackTimeoutCounter(1),
       mLastBudgetUpdate(TimeStamp::Now()),
       mExecutionBudget(GetMaxBudget(mWindow.IsBackgroundInternal())),
@@ -558,16 +558,19 @@ nsresult TimeoutManager::SetTimeout(nsIT
   // code can handle. (Note: we already forced |interval| to be non-negative,
   // so the uint32_t cast (to avoid compiler warnings) is ok.)
   uint32_t maxTimeoutMs = PR_IntervalToMilliseconds(DOM_MAX_TIMEOUT_VALUE);
   if (static_cast<uint32_t>(interval) > maxTimeoutMs) {
     interval = maxTimeoutMs;
   }
 
   RefPtr<Timeout> timeout = new Timeout();
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
+  timeout->mFiringIndex = -1;
+#endif
   timeout->mWindow = &mWindow;
   timeout->mIsInterval = aIsInterval;
   timeout->mInterval = TimeDuration::FromMilliseconds(interval);
   timeout->mScriptHandler = aHandler;
   timeout->mReason = aReason;
 
   // No popups from timeouts by default
   timeout->mPopupState = PopupBlocker::openAbused;
@@ -793,17 +796,18 @@ void TimeoutManager::RunTimeout(const Ti
         }
       }
     }
   }
   if (aProcessIdle) {
     MOZ_LOG(gTimeoutLog, LogLevel::Debug,
             ("Running %u deferred timeouts on idle (TimeoutManager=%p), "
              "nextDeadline = %gms from now",
-             numTimersToRun, this, (nextDeadline - now).ToMilliseconds()));
+             numTimersToRun, this,
+             nextDeadline.IsNull() ? 0.0 : (nextDeadline - now).ToMilliseconds()));
   }
 
   now = TimeStamp::Now();
 
   // Wherever we stopped in the timer list, schedule the executor to
   // run for the next unexpired deadline.  Note, this *must* be done
   // before we start executing any content script handlers.  If one
   // of them spins the event loop the executor must already be scheduled
@@ -889,17 +893,17 @@ void TimeoutManager::RunTimeout(const Ti
       // retain compliance with the spec language
       // (https://html.spec.whatwg.org/#dom-settimeout) specifically items
       // 15 ("If method context is a Window object, wait until the Document
       // associated with method context has been fully active for a further
       // timeout milliseconds (not necessarily consecutively)") and item 16
       // ("Wait until any invocations of this algorithm that had the same
       // method context, that started before this one, and whose timeout is
       // equal to or less than this one's, have completed.").
-#ifdef DEBUG
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
       if (timeout->mFiringIndex == -1) {
         timeout->mFiringIndex = mFiringIndex++;
       }
 #endif
 
       if (mIsLoading && !aProcessIdle) {
         // Any timeouts that would fire during a load will be deferred
         // until the load event occurs, but if there's an idle time,
@@ -929,18 +933,18 @@ void TimeoutManager::RunTimeout(const Ti
         if (!scx) {
           // No context means this window was closed or never properly
           // initialized for this language.  This timer will never fire
           // so just remove it.
           timeout->remove();
           continue;
         }
 
-#ifdef DEBUG
-        MOZ_ASSERT(timeout->mFiringIndex > mLastFiringIndex);
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
+        MOZ_DIAGNOSTIC_ASSERT(timeout->mFiringIndex > mLastFiringIndex);
         mLastFiringIndex = timeout->mFiringIndex;
 #endif
         // This timeout is good to run
         bool timeout_was_cleared = mWindow.RunTimeoutHandler(timeout, scx);
 #if MOZ_GECKO_PROFILER
         if (profiler_is_active()) {
           TimeDuration elapsed = now - timeout->SubmitTime();
           TimeDuration target = timeout->When() - timeout->SubmitTime();
@@ -1058,17 +1062,17 @@ bool TimeoutManager::RescheduleTimeout(T
 
   // Compute time to next timeout for interval timer.
   // Make sure nextInterval is at least CalculateDelay().
   TimeDuration nextInterval = CalculateDelay(aTimeout);
 
   TimeStamp firingTime = aLastCallbackTime + nextInterval;
   TimeDuration delay = firingTime - aCurrentNow;
 
-#ifdef DEBUG
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
   aTimeout->mFiringIndex = -1;
 #endif
   // And make sure delay is nonnegative; that might happen if the timer
   // thread is firing our timers somewhat early or if they're taking a long
   // time to run the callback.
   if (delay < TimeDuration(0)) {
     delay = TimeDuration(0);
   }
--- a/dom/base/TimeoutManager.h
+++ b/dom/base/TimeoutManager.h
@@ -198,17 +198,17 @@ class TimeoutManager final {
   // it must be a separate ref-counted object.
   RefPtr<TimeoutExecutor> mExecutor;
   // For timeouts run off the idle queue
   RefPtr<TimeoutExecutor> mIdleExecutor;
   // The list of timeouts coming from non-tracking scripts.
   Timeouts mTimeouts;
   uint32_t mTimeoutIdCounter;
   uint32_t mNextFiringId;
-#ifdef DEBUG
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
   int64_t mFiringIndex;
   int64_t mLastFiringIndex;
 #endif
   AutoTArray<uint32_t, 2> mFiringIdStack;
   mozilla::dom::Timeout* mRunningTimeout;
 
   // Timeouts that would have fired but are being deferred until MainThread
   // is idle (because we're loading)
--- a/dom/tests/mochitest/chrome/test_bug1224790-1.xul
+++ b/dom/tests/mochitest/chrome/test_bug1224790-1.xul
@@ -32,18 +32,18 @@ https://bugzilla.mozilla.org/show_bug.cg
 
   var timer = null;
   function gotFocus() {
     var button = document.getElementById('button');
     synthesizeMouseAtCenter(button, { type: 'mousemove' }, window);
     function click() {
       // The bug is not reproducible with synthesizeMouseAtCenter.
       // Need to emulate native mouse event.
-      synthesizeNativeOSXClick(button.boxObject.screenX + button.boxObject.width / 2,
-                               button.boxObject.screenY + button.boxObject.height / 2);
+      synthesizeNativeOSXClick(button.screenX + button.boxObject.width / 2,
+                               button.screenY + button.boxObject.height / 2);
     }
     click();
     // On debug build, it's possible that the click event handler is not
     // triggered by the first click in case the click is dispatched too early
     // before Firefox gets ready for input.
     // Click the button again after 1 sec when we don't get click event.
     timer = setTimeout(click, 1000);
   }
--- a/dom/tests/mochitest/chrome/test_bug1224790-2.xul
+++ b/dom/tests/mochitest/chrome/test_bug1224790-2.xul
@@ -33,18 +33,18 @@ https://bugzilla.mozilla.org/show_bug.cg
 
   var timer = null;
   function gotFocus() {
     var button = document.getElementById('button');
     synthesizeMouseAtCenter(button, { type: 'mousemove' }, window);
     function click() {
       // The bug is not reproducible with synthesizeMouseAtCenter.
       // Need to emulate native mouse event.
-      synthesizeNativeOSXClick(button.boxObject.screenX + button.boxObject.width / 2,
-                               button.boxObject.screenY + button.boxObject.height / 2);
+      synthesizeNativeOSXClick(button.screenX + button.boxObject.width / 2,
+                               button.screenY + button.boxObject.height / 2);
     }
     click();
     // On debug build, it's possible that the click event handler is not
     // triggered by the first click in case the click is dispatched too early
     // before Firefox gets ready for input.
     // Click the button again after 1 sec when we don't get click event.
     timer = setTimeout(click, 1000);
   }
--- a/dom/tests/mochitest/general/test_innerScreen.xul
+++ b/dom/tests/mochitest/general/test_innerScreen.xul
@@ -35,20 +35,20 @@ function doTests()
   catch(ex) { }
   ok(!readable, "window pixels per css pixel shouldn't be readable to content");
 
   var domWindowUtils = window.windowUtils;
   var devPxPerCSSPx = domWindowUtils.screenPixelsPerCSSPixel;
 
   is(window.devicePixelRatio, devPxPerCSSPx, "window.devicePixelRatio");
 
-  var windowBO = document.documentElement.boxObject;
-  isRounded(window.mozInnerScreenX*devPxPerCSSPx, windowBO.screenX,
+  var rootElement = document.documentElement;
+  isRounded(window.mozInnerScreenX*devPxPerCSSPx, rootElement.screenX,
             "window screen X");
-  isRounded(window.mozInnerScreenY*devPxPerCSSPx, windowBO.screenY,
+  isRounded(window.mozInnerScreenY*devPxPerCSSPx, rootElement.screenY,
             "window screen Y");
 
   var f = document.getElementById("f");
   var fBounds = f.getBoundingClientRect();
 
   var fshell = f.contentWindow.docShell;
   var fmudv = fshell.contentViewer;
 
--- a/dom/webidl/XULElement.webidl
+++ b/dom/webidl/XULElement.webidl
@@ -55,16 +55,20 @@ interface XULElement : Element {
   // Position properties for
   // * popups - these are screen coordinates
   // * other elements - these are client coordinates relative to parent stack.
   [SetterThrows]
   attribute DOMString left;
   [SetterThrows]
   attribute DOMString top;
 
+  // Return the screen coordinates of the element.
+  readonly attribute long screenX;
+  readonly attribute long screenY;
+
   // Tooltip
   [SetterThrows]
   attribute DOMString tooltipText;
 
   // Properties for images
   [SetterThrows]
   attribute DOMString src;
 
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -2698,17 +2698,18 @@ void WorkerPrivate::DoRunLoop(JSContext*
     }
 
     // If the worker thread is spamming the main thread faster than it can
     // process the work, then pause the worker thread until the main thread
     // catches up.
     size_t queuedEvents = mMainThreadEventTarget->Length() +
                           mMainThreadDebuggeeEventTarget->Length();
     if (queuedEvents > 5000) {
-      mMainThreadEventTarget->AwaitIdle();
+      // Note, postMessage uses mMainThreadDebuggeeEventTarget!
+      mMainThreadDebuggeeEventTarget->AwaitIdle();
     }
   }
 
   MOZ_CRASH("Shouldn't get here!");
 }
 
 void WorkerPrivate::OnProcessNextEvent() {
   AssertIsOnWorkerThread();
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -467,16 +467,26 @@ bool nsXULElement::IsFocusableInternal(i
         *aTabIndex = -1;
       }
     }
   }
 
   return shouldFocus;
 }
 
+int32_t nsXULElement::ScreenX() {
+  nsIFrame* frame = GetPrimaryFrame(FlushType::Layout);
+  return frame ? frame->GetScreenRect().x: 0;
+}
+
+int32_t nsXULElement::ScreenY() {
+  nsIFrame* frame = GetPrimaryFrame(FlushType::Layout);
+  return frame ? frame->GetScreenRect().y : 0;
+}
+
 bool nsXULElement::HasMenu() {
   nsMenuFrame* menu = do_QueryFrame(GetPrimaryFrame());
   return menu != nullptr;
 }
 
 void nsXULElement::OpenMenu(bool aOpenFlag) {
   nsMenuFrame* menu = do_QueryFrame(GetPrimaryFrame(FlushType::Frames));
 
--- a/dom/xul/nsXULElement.h
+++ b/dom/xul/nsXULElement.h
@@ -332,16 +332,19 @@ class nsXULElement : public nsStyledElem
   virtual void DoneAddingChildren(bool aHaveNotified) override;
 
 #ifdef DEBUG
   virtual void List(FILE* out, int32_t aIndent) const override;
   virtual void DumpContent(FILE* out, int32_t aIndent,
                            bool aDumpAll) const override {}
 #endif
 
+  MOZ_CAN_RUN_SCRIPT int32_t ScreenX();
+  MOZ_CAN_RUN_SCRIPT int32_t ScreenY();
+
   bool HasMenu();
   MOZ_CAN_RUN_SCRIPT void OpenMenu(bool aOpenFlag);
 
   virtual bool PerformAccesskey(bool aKeyCausesActivation,
                                 bool aIsTrustedEvent) override;
   void ClickWithInputSource(uint16_t aInputSource, bool aIsTrustedEvent);
 
   nsIContent* GetBindingParent() const final { return mBindingParent; }
--- a/dom/xul/test/test_bug199692.xul
+++ b/dom/xul/test/test_bug199692.xul
@@ -42,30 +42,30 @@ xmlns="http://www.mozilla.org/keymaster/
   SimpleTest.waitForExplicitFinish();
 
   // Before onload, XUL docs have no root frame.
   is(document.elementFromPoint(10,10), null,
      "Calls to elementFromPoint before onload should return null");
 
   var d = 10;
   function middle(e) {
-    return { "x": e.boxObject.x + e.boxObject.width/2,
-             "y": e.boxObject.y + e.boxObject.height/2 };
+    return { "x": e.getBoundingClientRect().x + e.getBoundingClientRect().width/2,
+             "y": e.getBoundingClientRect().y + e.getBoundingClientRect().height/2 };
   }
   function lower_right(e) {
-    return { "x": e.boxObject.x + e.boxObject.width - d,
-             "y": e.boxObject.y + e.boxObject.height - d };
+    return { "x": e.getBoundingClientRect().x + e.getBoundingClientRect().width - d,
+             "y": e.getBoundingClientRect().y + e.getBoundingClientRect().height - d };
   }
   function upper_left(e) {
-    return { "x": e.boxObject.x + d,
-             "y": e.boxObject.y + d };
+    return { "x": e.getBoundingClientRect().x + d,
+             "y": e.getBoundingClientRect().y + d };
   }
   function scrollbar_button(e) { // a bit down from upper right
-    return { "x": e.boxObject.x + e.boxObject.width - d,
-             "y": e.boxObject.y + d + 15 };
+    return { "x": e.getBoundingClientRect().x + e.getBoundingClientRect().width - d,
+             "y": e.getBoundingClientRect().y + d + 15 };
   }
   
   function test(ptFunc, id, message) {
     var pt = ptFunc($(id));
     var e = document.elementFromPoint(pt.x, pt.y);
     ok(e != null, message + " (returned null)");
     is(e.id, id, message);
   }
--- a/gfx/thebes/gfxContext.cpp
+++ b/gfx/thebes/gfxContext.cpp
@@ -871,19 +871,14 @@ Rect gfxContext::GetAzureDeviceSpaceClip
 Point gfxContext::GetDeviceOffset() const {
   return CurrentState().deviceOffset;
 }
 
 void gfxContext::SetDeviceOffset(const Point& aOffset) {
   CurrentState().deviceOffset = aOffset;
 }
 
-Matrix gfxContext::GetDeviceTransform() const {
-  return Matrix::Translation(-CurrentState().deviceOffset.x,
-                             -CurrentState().deviceOffset.y);
-}
-
 Matrix gfxContext::GetDTTransform() const {
   Matrix mat = mTransform;
   mat._31 -= CurrentState().deviceOffset.x;
   mat._32 -= CurrentState().deviceOffset.y;
   return mat;
 }
--- a/gfx/thebes/gfxContext.h
+++ b/gfx/thebes/gfxContext.h
@@ -520,17 +520,16 @@ class gfxContext final {
   // This ensures mPath contains a valid path (in user space!)
   void EnsurePath();
   // This ensures mPathBuilder contains a valid PathBuilder (in user space!)
   void EnsurePathBuilder();
   CompositionOp GetOp();
   void ChangeTransform(const mozilla::gfx::Matrix& aNewMatrix,
                        bool aUpdatePatternTransform = true);
   Rect GetAzureDeviceSpaceClipBounds() const;
-  Matrix GetDeviceTransform() const;
   Matrix GetDTTransform() const;
 
   bool mPathIsRect;
   bool mTransformChanged;
   Matrix mPathTransform;
   Rect mRect;
   RefPtr<PathBuilder> mPathBuilder;
   RefPtr<Path> mPath;
--- a/image/decoders/nsBMPDecoder.cpp
+++ b/image/decoders/nsBMPDecoder.cpp
@@ -61,16 +61,26 @@
 //   another optional gap).
 //
 // WinBMPv3-ICO. This is a variant of WinBMPv3.
 // - It's the BMP format used for BMP images within ICO files.
 // - The only difference with WinBMPv3 is that if an image is 32bpp and has no
 //   compression, then instead of treating the pixel data as 0RGB it is treated
 //   as ARGB, but only if one or more of the A values are non-zero.
 //
+// Clipboard variants.
+// - It's the BMP format used for BMP images captured from the clipboard.
+// - It is missing the file header, containing the BM signature and the data
+//   offset. Instead the data begins after the header.
+// - If it uses BITFIELDS compression, then there is always an additional 12
+//   bytes of data after the header that must be read. In WinBMPv4+, the masks
+//   are supposed to be included in the header size, which are the values we use
+//   for decoding purposes, but there is additional three masks following the
+//   header which must be skipped to get to the pixel data.
+//
 // OS/2 VERSIONS OF THE BMP FORMAT
 // -------------------------------
 // OS2-BMPv1.
 // - Almost identical to WinBMPv2; the differences are basically ignorable.
 //
 // OS2-BMPv2.
 // - Similar to WinBMPv3.
 // - The info header is 64 bytes but can be reduced to as little as 16; any
@@ -152,40 +162,44 @@ static void Set4BitPixel(uint32_t*& aDec
   }
 }
 
 static mozilla::LazyLogModule sBMPLog("BMPDecoder");
 
 // The length of the mBIHSize field in the info header.
 static const uint32_t BIHSIZE_FIELD_LENGTH = 4;
 
-nsBMPDecoder::nsBMPDecoder(RasterImage* aImage, State aState, size_t aLength)
+nsBMPDecoder::nsBMPDecoder(RasterImage* aImage, State aState, size_t aLength,
+                           bool aForClipboard)
     : Decoder(aImage),
       mLexer(Transition::To(aState, aLength), Transition::TerminateSuccess()),
       mIsWithinICO(false),
+      mIsForClipboard(aForClipboard),
       mMayHaveTransparency(false),
       mDoesHaveTransparency(false),
       mNumColors(0),
       mColors(nullptr),
       mBytesPerColor(0),
       mPreGapLength(0),
       mPixelRowSize(0),
       mCurrentRow(0),
       mCurrentPos(0),
       mAbsoluteModeNumPixels(0) {}
 
 // Constructor for normal BMP files or from the clipboard.
 nsBMPDecoder::nsBMPDecoder(RasterImage* aImage, bool aForClipboard)
     : nsBMPDecoder(aImage,
-                   aForClipboard ? State::CLIPBOARD_HEADER : State::FILE_HEADER,
-                   aForClipboard ? BIHSIZE_FIELD_LENGTH : FILE_HEADER_LENGTH) {}
+                   aForClipboard ? State::INFO_HEADER_SIZE : State::FILE_HEADER,
+                   aForClipboard ? BIHSIZE_FIELD_LENGTH : FILE_HEADER_LENGTH,
+                   aForClipboard) {}
 
 // Constructor used for WinBMPv3-ICO files, which lack a file header.
 nsBMPDecoder::nsBMPDecoder(RasterImage* aImage, uint32_t aDataOffset)
-    : nsBMPDecoder(aImage, State::INFO_HEADER_SIZE, BIHSIZE_FIELD_LENGTH) {
+    : nsBMPDecoder(aImage, State::INFO_HEADER_SIZE, BIHSIZE_FIELD_LENGTH,
+                   /* aForClipboard */ false) {
   SetIsWithinICO();
 
   // Even though the file header isn't present in this case, the dataOffset
   // field is set as if it is, and so we must increment mPreGapLength
   // accordingly.
   mPreGapLength += FILE_HEADER_LENGTH;
 
   // This is the one piece of data we normally get from a BMP file header, so
@@ -399,18 +413,16 @@ LexerResult nsBMPDecoder::DoDecode(Sourc
                                    IResumable* aOnResume) {
   MOZ_ASSERT(!HasError(), "Shouldn't call DoDecode after error!");
 
   return mLexer.Lex(aIterator, aOnResume,
                     [=](State aState, const char* aData, size_t aLength) {
                       switch (aState) {
                         case State::FILE_HEADER:
                           return ReadFileHeader(aData, aLength);
-                        case State::CLIPBOARD_HEADER:
-                          return ReadClipboardHeader(aData, aLength);
                         case State::INFO_HEADER_SIZE:
                           return ReadInfoHeaderSize(aData, aLength);
                         case State::INFO_HEADER_REST:
                           return ReadInfoHeaderRest(aData, aLength);
                         case State::BITFIELDS:
                           return ReadBitfields(aData, aLength);
                         case State::COLOR_TABLE:
                           return ReadColorTable(aData, aLength);
@@ -443,23 +455,16 @@ LexerTransition<nsBMPDecoder::State> nsB
 
   // We ignore the filesize (aData + 2) and reserved (aData + 6) fields.
 
   mH.mDataOffset = LittleEndian::readUint32(aData + 10);
 
   return Transition::To(State::INFO_HEADER_SIZE, BIHSIZE_FIELD_LENGTH);
 }
 
-LexerTransition<nsBMPDecoder::State> nsBMPDecoder::ReadClipboardHeader(
-    const char* aData, size_t aLength) {
-  // With the clipboard, the data offset is the header length.
-  mH.mDataOffset = LittleEndian::readUint32(aData);
-  return ReadInfoHeaderSize(aData, aLength);
-}
-
 // We read the info header in two steps: (a) read the mBIHSize field to
 // determine how long the header is; (b) read the rest of the header.
 LexerTransition<nsBMPDecoder::State> nsBMPDecoder::ReadInfoHeaderSize(
     const char* aData, size_t aLength) {
   mPreGapLength += aLength;
 
   mH.mBIHSize = LittleEndian::readUint32(aData);
 
@@ -566,16 +571,23 @@ LexerTransition<nsBMPDecoder::State> nsB
 
   size_t bitFieldsLengthStillToRead = 0;
   if (mH.mCompression == Compression::BITFIELDS) {
     // Need to read bitfields.
     if (mH.mBIHSize >= InfoHeaderLength::WIN_V4) {
       // Bitfields are present in the info header, so we can read them
       // immediately.
       mBitFields.ReadFromHeader(aData + 36, /* aReadAlpha = */ true);
+
+      // If this came from the clipboard, then we know that even if the header
+      // explicitly includes the bitfield masks, we need to add an additional
+      // offset for the start of the RGB data.
+      if (mIsForClipboard) {
+        mH.mDataOffset += BitFields::LENGTH;
+      }
     } else {
       // Bitfields are present after the info header, so we will read them in
       // ReadBitfields().
       bitFieldsLengthStillToRead = BitFields::LENGTH;
     }
   } else if (mH.mBpp == 16) {
     // No bitfields specified; use the default 5-5-5 values.
     mBitFields.SetR5G5B5();
@@ -677,16 +689,22 @@ LexerTransition<nsBMPDecoder::State> nsB
   for (uint32_t i = 0; i < mNumColors; i++) {
     // The format is BGR or BGR0.
     mColors[i].mBlue = uint8_t(aData[0]);
     mColors[i].mGreen = uint8_t(aData[1]);
     mColors[i].mRed = uint8_t(aData[2]);
     aData += mBytesPerColor;
   }
 
+  // If we are decoding a BMP from the clipboard, we did not know the data
+  // offset in advance. It is just defined as after the header and color table.
+  if (mIsForClipboard) {
+    mH.mDataOffset += mPreGapLength;
+  }
+
   // We know how many bytes we've read so far (mPreGapLength) and we know the
   // offset of the pixel data (mH.mDataOffset), so we can determine the length
   // of the gap (possibly zero) between the color table and the pixel data.
   //
   // If the gap is negative the file must be malformed (e.g. mH.mDataOffset
   // points into the middle of the color palette instead of past the end) and
   // we give up.
   if (mPreGapLength > mH.mDataOffset) {
--- a/image/decoders/nsBMPDecoder.h
+++ b/image/decoders/nsBMPDecoder.h
@@ -149,17 +149,16 @@ class nsBMPDecoder : public Decoder {
   nsresult BeforeFinishInternal() override;
   nsresult FinishInternal() override;
 
  private:
   friend class DecoderFactory;
 
   enum class State {
     FILE_HEADER,
-    CLIPBOARD_HEADER,
     INFO_HEADER_SIZE,
     INFO_HEADER_REST,
     BITFIELDS,
     COLOR_TABLE,
     GAP,
     AFTER_GAP,
     PIXEL_ROW,
     RLE_SEGMENT,
@@ -169,26 +168,26 @@ class nsBMPDecoder : public Decoder {
 
   // This is the constructor used for normal and clipboard BMP images.
   explicit nsBMPDecoder(RasterImage* aImage, bool aForClipboard = false);
 
   // This is the constructor used for BMP resources in ICO images.
   nsBMPDecoder(RasterImage* aImage, uint32_t aDataOffset);
 
   // Helper constructor called by the other two.
-  nsBMPDecoder(RasterImage* aImage, State aState, size_t aLength);
+  nsBMPDecoder(RasterImage* aImage, State aState, size_t aLength,
+               bool aForClipboard);
 
   int32_t AbsoluteHeight() const { return abs(mH.mHeight); }
 
   uint32_t* RowBuffer();
 
   void FinishRow();
 
   LexerTransition<State> ReadFileHeader(const char* aData, size_t aLength);
-  LexerTransition<State> ReadClipboardHeader(const char* aData, size_t aLength);
   LexerTransition<State> ReadInfoHeaderSize(const char* aData, size_t aLength);
   LexerTransition<State> ReadInfoHeaderRest(const char* aData, size_t aLength);
   LexerTransition<State> ReadBitfields(const char* aData, size_t aLength);
   LexerTransition<State> ReadColorTable(const char* aData, size_t aLength);
   LexerTransition<State> SkipGap();
   LexerTransition<State> AfterGap();
   LexerTransition<State> ReadPixelRow(const char* aData);
   LexerTransition<State> ReadRLESegment(const char* aData);
@@ -197,16 +196,19 @@ class nsBMPDecoder : public Decoder {
 
   StreamingLexer<State> mLexer;
 
   bmp::Header mH;
 
   // If the BMP is within an ICO file our treatment of it differs slightly.
   bool mIsWithinICO;
 
+  // If the BMP decoded from the clipboard, we don't start with a data offset.
+  bool mIsForClipboard;
+
   bmp::BitFields mBitFields;
 
   // Might the image have transparency? Determined from the headers during
   // metadata decode. (Does not guarantee the image actually has transparency.)
   bool mMayHaveTransparency;
 
   // Does the image have transparency? Determined during full decoding, so only
   // use this after that has been completed.
--- a/image/decoders/nsWebPDecoder.cpp
+++ b/image/decoders/nsWebPDecoder.cpp
@@ -474,28 +474,39 @@ LexerResult nsWebPDecoder::ReadSingle(co
 
     for (int row = mLastRow; row < lastRow; row++) {
       uint8_t* src = rowStart + row * stride;
       if (mTransform) {
         qcms_transform_data(mTransform, src, src, width);
       }
 
       WriteState result;
-      if (noPremultiply) {
+      if (mFormat == SurfaceFormat::B8G8R8A8) {
+        if (noPremultiply) {
+          result =
+              mPipe.WritePixelsToRow<uint32_t>([&]() -> NextPixel<uint32_t> {
+                const uint32_t pixel =
+                    gfxPackedPixelNoPreMultiply(src[3], src[0], src[1], src[2]);
+                src += 4;
+                return AsVariant(pixel);
+              });
+        } else {
+          result =
+              mPipe.WritePixelsToRow<uint32_t>([&]() -> NextPixel<uint32_t> {
+                const uint32_t pixel =
+                    gfxPackedPixel(src[3], src[0], src[1], src[2]);
+                src += 4;
+                return AsVariant(pixel);
+              });
+        }
+      } else {
+        // We are producing a surface without transparency. Ignore the alpha
+        // channel provided to us by the library.
         result = mPipe.WritePixelsToRow<uint32_t>([&]() -> NextPixel<uint32_t> {
-          MOZ_ASSERT(mFormat == SurfaceFormat::B8G8R8A8 || src[3] == 0xFF);
-          const uint32_t pixel =
-              gfxPackedPixelNoPreMultiply(src[3], src[0], src[1], src[2]);
-          src += 4;
-          return AsVariant(pixel);
-        });
-      } else {
-        result = mPipe.WritePixelsToRow<uint32_t>([&]() -> NextPixel<uint32_t> {
-          MOZ_ASSERT(mFormat == SurfaceFormat::B8G8R8A8 || src[3] == 0xFF);
-          const uint32_t pixel = gfxPackedPixel(src[3], src[0], src[1], src[2]);
+          const uint32_t pixel = gfxPackedPixel(0xFF, src[0], src[1], src[2]);
           src += 4;
           return AsVariant(pixel);
         });
       }
 
       Maybe<SurfaceInvalidRect> invalidRect = mPipe.TakeInvalidRect();
       if (invalidRect) {
         PostInvalidation(invalidRect->mInputSpaceRect,
--- a/image/test/gtest/Common.cpp
+++ b/image/test/gtest/Common.cpp
@@ -608,16 +608,30 @@ ImageTestCase TransparentPNGTestCase() {
                        TEST_CASE_IS_TRANSPARENT);
 }
 
 ImageTestCase TransparentGIFTestCase() {
   return ImageTestCase("transparent.gif", "image/gif", IntSize(16, 16),
                        TEST_CASE_IS_TRANSPARENT);
 }
 
+ImageTestCase TransparentWebPTestCase() {
+  ImageTestCase test("transparent.webp", "image/webp", IntSize(100, 100),
+                     TEST_CASE_IS_TRANSPARENT);
+  test.mColor = BGRAColor::Transparent();
+  return test;
+}
+
+ImageTestCase TransparentNoAlphaHeaderWebPTestCase() {
+  ImageTestCase test("transparent-no-alpha-header.webp", "image/webp",
+                     IntSize(100, 100), TEST_CASE_IS_FUZZY);
+  test.mColor = BGRAColor(0x00, 0x00, 0x00, 0xFF);  // black
+  return test;
+}
+
 ImageTestCase FirstFramePaddingGIFTestCase() {
   return ImageTestCase("transparent.gif", "image/gif", IntSize(16, 16),
                        TEST_CASE_IS_TRANSPARENT);
 }
 
 ImageTestCase TransparentIfWithinICOBMPTestCase(TestCaseFlags aFlags) {
   // This is a BMP that is only transparent when decoded as if it is within an
   // ICO file. (Note: aFlags needs to be set to TEST_CASE_DEFAULT_FLAGS or
--- a/image/test/gtest/Common.h
+++ b/image/test/gtest/Common.h
@@ -25,50 +25,16 @@ class nsIInputStream;
 
 namespace mozilla {
 namespace image {
 
 ///////////////////////////////////////////////////////////////////////////////
 // Types
 ///////////////////////////////////////////////////////////////////////////////
 
-enum TestCaseFlags {
-  TEST_CASE_DEFAULT_FLAGS = 0,
-  TEST_CASE_IS_FUZZY = 1 << 0,
-  TEST_CASE_HAS_ERROR = 1 << 1,
-  TEST_CASE_IS_TRANSPARENT = 1 << 2,
-  TEST_CASE_IS_ANIMATED = 1 << 3,
-  TEST_CASE_IGNORE_OUTPUT = 1 << 4,
-};
-
-struct ImageTestCase {
-  ImageTestCase(const char* aPath, const char* aMimeType, gfx::IntSize aSize,
-                uint32_t aFlags = TEST_CASE_DEFAULT_FLAGS)
-      : mPath(aPath),
-        mMimeType(aMimeType),
-        mSize(aSize),
-        mOutputSize(aSize),
-        mFlags(aFlags) {}
-
-  ImageTestCase(const char* aPath, const char* aMimeType, gfx::IntSize aSize,
-                gfx::IntSize aOutputSize,
-                uint32_t aFlags = TEST_CASE_DEFAULT_FLAGS)
-      : mPath(aPath),
-        mMimeType(aMimeType),
-        mSize(aSize),
-        mOutputSize(aOutputSize),
-        mFlags(aFlags) {}
-
-  const char* mPath;
-  const char* mMimeType;
-  gfx::IntSize mSize;
-  gfx::IntSize mOutputSize;
-  uint32_t mFlags;
-};
-
 struct BGRAColor {
   BGRAColor() : BGRAColor(0, 0, 0, 0) {}
 
   BGRAColor(uint8_t aBlue, uint8_t aGreen, uint8_t aRed, uint8_t aAlpha,
             bool aPremultiplied = false)
       : mBlue(aBlue),
         mGreen(aGreen),
         mRed(aRed),
@@ -98,16 +64,53 @@ struct BGRAColor {
 
   uint8_t mBlue;
   uint8_t mGreen;
   uint8_t mRed;
   uint8_t mAlpha;
   bool mPremultiplied;
 };
 
+enum TestCaseFlags {
+  TEST_CASE_DEFAULT_FLAGS = 0,
+  TEST_CASE_IS_FUZZY = 1 << 0,
+  TEST_CASE_HAS_ERROR = 1 << 1,
+  TEST_CASE_IS_TRANSPARENT = 1 << 2,
+  TEST_CASE_IS_ANIMATED = 1 << 3,
+  TEST_CASE_IGNORE_OUTPUT = 1 << 4,
+};
+
+struct ImageTestCase {
+  ImageTestCase(const char* aPath, const char* aMimeType, gfx::IntSize aSize,
+                uint32_t aFlags = TEST_CASE_DEFAULT_FLAGS)
+      : mPath(aPath),
+        mMimeType(aMimeType),
+        mSize(aSize),
+        mOutputSize(aSize),
+        mFlags(aFlags),
+        mColor(BGRAColor::Green()) {}
+
+  ImageTestCase(const char* aPath, const char* aMimeType, gfx::IntSize aSize,
+                gfx::IntSize aOutputSize,
+                uint32_t aFlags = TEST_CASE_DEFAULT_FLAGS)
+      : mPath(aPath),
+        mMimeType(aMimeType),
+        mSize(aSize),
+        mOutputSize(aOutputSize),
+        mFlags(aFlags),
+        mColor(BGRAColor::Green()) {}
+
+  const char* mPath;
+  const char* mMimeType;
+  gfx::IntSize mSize;
+  gfx::IntSize mOutputSize;
+  uint32_t mFlags;
+  BGRAColor mColor;
+};
+
 ///////////////////////////////////////////////////////////////////////////////
 // General Helpers
 ///////////////////////////////////////////////////////////////////////////////
 
 /**
  * A RAII class that ensure that ImageLib services are available. Any tests that
  * require ImageLib to be initialized (for example, any test that uses the
  * SurfaceCache; see image::EnsureModuleInitialized() for the full list) can
@@ -431,16 +434,18 @@ ImageTestCase BlendAnimatedWebPTestCase(
 ImageTestCase CorruptTestCase();
 ImageTestCase CorruptBMPWithTruncatedHeader();
 ImageTestCase CorruptICOWithBadBMPWidthTestCase();
 ImageTestCase CorruptICOWithBadBMPHeightTestCase();
 ImageTestCase CorruptICOWithBadBppTestCase();
 
 ImageTestCase TransparentPNGTestCase();
 ImageTestCase TransparentGIFTestCase();
+ImageTestCase TransparentWebPTestCase();
+ImageTestCase TransparentNoAlphaHeaderWebPTestCase();
 ImageTestCase FirstFramePaddingGIFTestCase();
 ImageTestCase TransparentIfWithinICOBMPTestCase(TestCaseFlags aFlags);
 ImageTestCase NoFrameDelayGIFTestCase();
 ImageTestCase ExtraImageSubBlocksAnimatedGIFTestCase();
 
 ImageTestCase TransparentBMPWhenBMPAlphaEnabledTestCase();
 ImageTestCase RLE4BMPTestCase();
 ImageTestCase RLE8BMPTestCase();
--- a/image/test/gtest/TestDecoders.cpp
+++ b/image/test/gtest/TestDecoders.cpp
@@ -84,17 +84,17 @@ static void CheckDecoderResults(const Im
     return;
   }
 
   if (aTestCase.mFlags & TEST_CASE_IGNORE_OUTPUT) {
     return;
   }
 
   // Check the output.
-  EXPECT_TRUE(IsSolidColor(surface, BGRAColor::Green(),
+  EXPECT_TRUE(IsSolidColor(surface, aTestCase.mColor,
                            aTestCase.mFlags & TEST_CASE_IS_FUZZY ? 1 : 0));
 }
 
 template <typename Func>
 void WithSingleChunkDecode(const ImageTestCase& aTestCase,
                            const Maybe<IntSize>& aOutputSize,
                            Func aResultChecker) {
   nsCOMPtr<nsIInputStream> inputStream = LoadFile(aTestCase.mPath);
@@ -720,16 +720,24 @@ TEST_F(ImageDecoders, WebPLargeMultiChun
 TEST_F(ImageDecoders, WebPDownscaleDuringDecode) {
   CheckDownscaleDuringDecode(DownscaledWebPTestCase());
 }
 
 TEST_F(ImageDecoders, WebPIccSrgbMultiChunk) {
   CheckDecoderMultiChunk(GreenWebPIccSrgbTestCase());
 }
 
+TEST_F(ImageDecoders, WebPTransparentSingleChunk) {
+  CheckDecoderSingleChunk(TransparentWebPTestCase());
+}
+
+TEST_F(ImageDecoders, WebPTransparentNoAlphaHeaderSingleChunk) {
+  CheckDecoderSingleChunk(TransparentNoAlphaHeaderWebPTestCase());
+}
+
 TEST_F(ImageDecoders, AnimatedGIFSingleChunk) {
   CheckDecoderSingleChunk(GreenFirstFrameAnimatedGIFTestCase());
 }
 
 TEST_F(ImageDecoders, AnimatedGIFMultiChunk) {
   CheckDecoderMultiChunk(GreenFirstFrameAnimatedGIFTestCase());
 }
 
--- a/image/test/gtest/moz.build
+++ b/image/test/gtest/moz.build
@@ -71,18 +71,20 @@ TEST_HARNESS_FILES.gtest += [
     'green.webp',
     'invalid-truncated-metadata.bmp',
     'large.webp',
     'no-frame-delay.gif',
     'rle4.bmp',
     'rle8.bmp',
     'transparent-ico-with-and-mask.ico',
     'transparent-if-within-ico.bmp',
+    'transparent-no-alpha-header.webp',
     'transparent.gif',
     'transparent.png',
+    'transparent.webp',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 LOCAL_INCLUDES += [
     '/dom/base',
     '/gfx/2d',
     '/image',
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8ddd73ac7a2a23ae9e1d1aa3d807715d5202bd82
GIT binary patch
literal 120
zc$^FJbaN|UU|<M$bqWXzu!!JdfPiE$a`XxC-~{p**#!gzJ39WcGXT{nH~>X9urkbL
z)JkDUVX&L%vCwDf5@jWY6$~4MI5YDe7C&G}&R)6qNL&QluGx27pEf`_^B5TZ{Wr}F
H2bm85hhQRX
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..87b9520521a3dc90dcd8020a40791904820118d9
GIT binary patch
literal 120
zc$^FJbaN|UU|<M$bqWXzu!!ISvIT%R8H^l#0z5c@JVtf_LBWoWf9woEH3|+ukqxX2
za~ZW#7*ZJQCVDLNS-M17Nnr)U1|iPOyobdP7?QJB?mZG0!M1Dm9oMG~P|iFChJXJ}
JGsA(}832u-B76V<
--- a/js/src/builtin/Sorting.js
+++ b/js/src/builtin/Sorting.js
@@ -133,18 +133,18 @@ function RadixSort(array, len, buffer, n
             buffer = callFunction(std_TypedArray_buffer, array);
 
             assert(buffer !== null, "Attached data buffer should be reified");
         }
 
         // |array| is a possibly cross-compartment wrapped typed array.
         let offset = IsTypedArray(array)
                      ? TypedArrayByteOffset(array)
-                     : callFunction(CallTypedArrayMethodIfWrapped, array, array,
-                                    "TypedArrayByteOffset");
+                     : callFunction(CallTypedArrayMethodIfWrapped, array,
+                                    "TypedArrayByteOffsetMethod");
 
         view = new Int32Array(buffer, offset, len);
 
         // Flip sign bit for positive numbers; flip all bits for negative
         // numbers, except negative NaNs.
         for (let i = 0; i < len; i++) {
             if (view[i] & signMask) {
                 if ((view[i] & 0x7F800000) !== 0x7F800000 || (view[i] & 0x007FFFFF) === 0) {
--- a/js/src/builtin/TypedArray.js
+++ b/js/src/builtin/TypedArray.js
@@ -32,16 +32,20 @@ function IsDetachedBuffer(buffer) {
     var flags = UnsafeGetInt32FromReservedSlot(buffer, JS_ARRAYBUFFER_FLAGS_SLOT);
     return (flags & JS_ARRAYBUFFER_DETACHED_FLAG) !== 0;
 }
 
 function TypedArrayLengthMethod() {
     return TypedArrayLength(this);
 }
 
+function TypedArrayByteOffsetMethod() {
+    return TypedArrayByteOffset(this);
+}
+
 function GetAttachedArrayBuffer(tarray) {
     var buffer = ViewedArrayBufferIfReified(tarray);
     if (IsDetachedBuffer(buffer))
         ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
     return buffer;
 }
 
 function GetAttachedArrayBufferMethod() {
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testWrapWithProtoTypedArraySortFloat32.js
@@ -0,0 +1,3 @@
+let a = wrapWithProto(new Float32Array(1024), new Float32Array());
+
+a.sort();
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -6527,23 +6527,25 @@ class BaseCompiler final : public BaseCo
     uint32_t bytecodeOffset = iter_.lastOpcodeOffset();
 
     // The `valueAddr` is a raw pointer to the cell within some GC object or
     // TLS area, and we guarantee that the GC will not run while the
     // postbarrier call is active, so push a uintptr_t value.
 #ifdef JS_64BIT
     pushI64(RegI64(Register64(valueAddr)));
     if (!emitInstanceCall(bytecodeOffset, SigPL_, ExprType::Void,
-                          SymbolicAddress::PostBarrier)) {
+                          SymbolicAddress::PostBarrier,
+                          /*pushReturnedValue=*/false)) {
       return false;
     }
 #else
     pushI32(RegI32(valueAddr));
     if (!emitInstanceCall(bytecodeOffset, SigPI_, ExprType::Void,
-                          SymbolicAddress::PostBarrier)) {
+                          SymbolicAddress::PostBarrier,
+                          /*pushReturnedValue=*/false)) {
       return false;
     }
 #endif
     return true;
   }
 
   MOZ_MUST_USE bool emitBarrieredStore(const Maybe<RegPtr>& object,
                                        RegPtr valueAddr, RegPtr value,
@@ -6753,17 +6755,17 @@ class BaseCompiler final : public BaseCo
   MOZ_MUST_USE bool emitSetOrTeeLocal(uint32_t slot);
 
   void endBlock(ExprType type);
   void endLoop(ExprType type);
   void endIfThen();
   void endIfThenElse(ExprType type);
 
   void doReturn(ExprType returnType, bool popStack);
-  void pushReturnedIfNonVoid(const FunctionCall& call, ExprType type);
+  void pushReturnValueOfCall(const FunctionCall& call, ExprType type);
 
   void emitCompareI32(Assembler::Condition compareOp, ValType compareType);
   void emitCompareI64(Assembler::Condition compareOp, ValType compareType);
   void emitCompareF32(Assembler::DoubleCondition compareOp,
                       ValType compareType);
   void emitCompareF64(Assembler::DoubleCondition compareOp,
                       ValType compareType);
   void emitCompareRef(Assembler::Condition compareOp, ValType compareType);
@@ -6871,17 +6873,18 @@ class BaseCompiler final : public BaseCo
   void emitConvertI64ToF64();
   void emitConvertU64ToF64();
 #endif
   void emitReinterpretI32AsF32();
   void emitReinterpretI64AsF64();
   void emitRound(RoundingMode roundingMode, ValType operandType);
   MOZ_MUST_USE bool emitInstanceCall(uint32_t lineOrBytecode,
                                      const MIRTypeVector& sig, ExprType retType,
-                                     SymbolicAddress builtin);
+                                     SymbolicAddress builtin,
+                                     bool pushReturnedValue=true);
   MOZ_MUST_USE bool emitGrowMemory();
   MOZ_MUST_USE bool emitCurrentMemory();
 
   MOZ_MUST_USE bool emitRefNull();
   void emitRefIsNull();
 
   MOZ_MUST_USE bool emitAtomicCmpXchg(ValType type, Scalar::Type viewType);
   MOZ_MUST_USE bool emitAtomicLoad(ValType type, Scalar::Type viewType);
@@ -8622,22 +8625,19 @@ bool BaseCompiler::emitCallArgs(const Va
   for (size_t i = 0; i < numArgs; ++i) {
     passArg(argTypes[i], peek(numArgs - 1 - i), baselineCall);
   }
 
   masm.loadWasmTlsRegFromFrame();
   return true;
 }
 
-void BaseCompiler::pushReturnedIfNonVoid(const FunctionCall& call,
+void BaseCompiler::pushReturnValueOfCall(const FunctionCall& call,
                                          ExprType type) {
   switch (type.code()) {
-    case ExprType::Void:
-      // There's no return value.  Do nothing.
-      break;
     case ExprType::I32: {
       RegI32 rv = captureReturnedI32();
       pushI32(rv);
       break;
     }
     case ExprType::I64: {
       RegI64 rv = captureReturnedI64();
       pushI64(rv);
@@ -8657,16 +8657,18 @@ void BaseCompiler::pushReturnedIfNonVoid
     case ExprType::AnyRef: {
       RegPtr rv = captureReturnedRef();
       pushRef(rv);
       break;
     }
     case ExprType::NullRef:
       MOZ_CRASH("NullRef not expressible");
     default:
+      // In particular, passing |type| == ExprType::Void to this function is
+      // an error.
       MOZ_CRASH("Function return type");
   }
 }
 
 // For now, always sync() at the beginning of the call to easily save live
 // values.
 //
 // TODO / OPTIMIZE (Bug 1316806): We may be able to avoid a full sync(), since
@@ -8719,17 +8721,19 @@ bool BaseCompiler::emitCall() {
   if (!createStackMap("emitCall", raOffset)) {
     return false;
   }
 
   endCall(baselineCall, stackSpace);
 
   popValueStackBy(numArgs);
 
-  pushReturnedIfNonVoid(baselineCall, funcType.ret());
+  if (funcType.ret() != ExprType::Void) {
+    pushReturnValueOfCall(baselineCall, funcType.ret());
+  }
 
   return true;
 }
 
 bool BaseCompiler::emitCallIndirect() {
   uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
 
   uint32_t funcTypeIndex;
@@ -8771,17 +8775,19 @@ bool BaseCompiler::emitCallIndirect() {
   if (!createStackMap("emitCallIndirect", raOffset)) {
     return false;
   }
 
   endCall(baselineCall, stackSpace);
 
   popValueStackBy(numArgs);
 
-  pushReturnedIfNonVoid(baselineCall, funcType.ret());
+  if (funcType.ret() != ExprType::Void) {
+    pushReturnValueOfCall(baselineCall, funcType.ret());
+  }
 
   return true;
 }
 
 void BaseCompiler::emitRound(RoundingMode roundingMode, ValType operandType) {
   if (operandType == ValType::F32) {
     RegF32 f0 = popF32();
     roundF32(roundingMode, f0);
@@ -8834,17 +8840,18 @@ bool BaseCompiler::emitUnaryMathBuiltinC
   if (!createStackMap("emitUnaryMathBuiltin[..]", raOffset)) {
     return false;
   }
 
   endCall(baselineCall, stackSpace);
 
   popValueStackBy(numArgs);
 
-  pushReturnedIfNonVoid(baselineCall, retType);
+  // We know retType isn't ExprType::Void here, so there's no need to check it.
+  pushReturnValueOfCall(baselineCall, retType);
 
   return true;
 }
 
 #ifdef RABALDR_INT_DIV_I64_CALLOUT
 bool BaseCompiler::emitDivOrModI64BuiltinCall(SymbolicAddress callee,
                                               ValType operandType) {
   MOZ_ASSERT(operandType == ValType::I64);
@@ -9763,17 +9770,18 @@ void BaseCompiler::emitCompareRef(Assemb
   masm.cmpPtrSet(compareOp, rs1, rs2, rd);
   freeRef(rs1);
   freeRef(rs2);
   pushI32(rd);
 }
 
 bool BaseCompiler::emitInstanceCall(uint32_t lineOrBytecode,
                                     const MIRTypeVector& sig, ExprType retType,
-                                    SymbolicAddress builtin) {
+                                    SymbolicAddress builtin,
+                                    bool pushReturnedValue/*=true*/) {
   MOZ_ASSERT(sig[0] == MIRType::Pointer);
 
   sync();
 
   uint32_t numArgs = sig.length() - 1 /* instance */;
   size_t stackSpace = stackConsumed(numArgs);
 
   FunctionCall baselineCall(lineOrBytecode);
@@ -9814,17 +9822,20 @@ bool BaseCompiler::emitInstanceCall(uint
   //
   // Furthermore, clients assume that even if retType == ExprType::Void, the
   // callee may have returned a status result and left it in ReturnReg for us
   // to find, and that that register will not be destroyed here (or above).
   // In this case the callee will have a C++ declaration stating that there is
   // a return value.  Examples include memory and table operations that are
   // implemented as callouts.
 
-  pushReturnedIfNonVoid(baselineCall, retType);
+  if (pushReturnedValue) {
+    MOZ_ASSERT(retType != ExprType::Void);
+    pushReturnValueOfCall(baselineCall, retType);
+  }
   return true;
 }
 
 bool BaseCompiler::emitGrowMemory() {
   uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
 
   Nothing arg;
   if (!iter_.readGrowMemory(&arg)) {
@@ -10230,25 +10241,27 @@ bool BaseCompiler::emitMemOrTableCopy(bo
   if (deadCode_) {
     return true;
   }
 
   // Returns -1 on trap, otherwise 0.
   if (isMem) {
     MOZ_ASSERT(srcMemOrTableIndex == 0);
     MOZ_ASSERT(dstMemOrTableIndex == 0);
-    if (!emitInstanceCall(lineOrBytecode, SigPIII_, ExprType::Void,
-                          SymbolicAddress::MemCopy)) {
+    if (!emitInstanceCall(lineOrBytecode, SigPIII_, ExprType::I32,
+                          SymbolicAddress::MemCopy,
+                          /*pushReturnedValue=*/false)) {
       return false;
     }
   } else {
     pushI32(dstMemOrTableIndex);
     pushI32(srcMemOrTableIndex);
-    if (!emitInstanceCall(lineOrBytecode, SigPIIIII_, ExprType::Void,
-                          SymbolicAddress::TableCopy)) {
+    if (!emitInstanceCall(lineOrBytecode, SigPIIIII_, ExprType::I32,
+                          SymbolicAddress::TableCopy,
+                          /*pushReturnedValue=*/false)) {
       return false;
     }
   }
 
   Label ok;
   masm.branchTest32(Assembler::NotSigned, ReturnReg, ReturnReg, &ok);
   trap(Trap::ThrowReported);
   masm.bind(&ok);
@@ -10269,17 +10282,18 @@ bool BaseCompiler::emitDataOrElemDrop(bo
   }
 
   // Despite the cast to int32_t, the callee regards the value as unsigned.
   //
   // Returns -1 on trap, otherwise 0.
   pushI32(int32_t(segIndex));
   SymbolicAddress callee =
       isData ? SymbolicAddress::DataDrop : SymbolicAddress::ElemDrop;
-  if (!emitInstanceCall(lineOrBytecode, SigPI_, ExprType::Void, callee)) {
+  if (!emitInstanceCall(lineOrBytecode, SigPI_, ExprType::Void, callee,
+                        /*pushReturnedValue=*/false)) {
     return false;
   }
 
   Label ok;
   masm.branchTest32(Assembler::NotSigned, ReturnReg, ReturnReg, &ok);
   trap(Trap::ThrowReported);
   masm.bind(&ok);
 
@@ -10295,17 +10309,18 @@ bool BaseCompiler::emitMemFill() {
   }
 
   if (deadCode_) {
     return true;
   }
 
   // Returns -1 on trap, otherwise 0.
   if (!emitInstanceCall(lineOrBytecode, SigPIII_, ExprType::Void,
-                        SymbolicAddress::MemFill)) {
+                        SymbolicAddress::MemFill,
+                        /*pushReturnedValue=*/false)) {
     return false;
   }
 
   Label ok;
   masm.branchTest32(Assembler::NotSigned, ReturnReg, ReturnReg, &ok);
   trap(Trap::ThrowReported);
   masm.bind(&ok);
 
@@ -10326,23 +10341,25 @@ bool BaseCompiler::emitMemOrTableInit(bo
   if (deadCode_) {
     return true;
   }
 
   // Returns -1 on trap, otherwise 0.
   pushI32(int32_t(segIndex));
   if (isMem) {
     if (!emitInstanceCall(lineOrBytecode, SigPIIII_, ExprType::Void,
-                          SymbolicAddress::MemInit)) {
+                          SymbolicAddress::MemInit,
+                          /*pushReturnedValue=*/false)) {
       return false;
     }
   } else {
     pushI32(dstTableIndex);
     if (!emitInstanceCall(lineOrBytecode, SigPIIIII_, ExprType::Void,
-                          SymbolicAddress::TableInit)) {
+                          SymbolicAddress::TableInit,
+                          /*pushReturnedValue=*/false)) {
       return false;
     }
   }
 
   Label ok;
   masm.branchTest32(Assembler::NotSigned, ReturnReg, ReturnReg, &ok);
   trap(Trap::ThrowReported);
   masm.bind(&ok);
@@ -10410,18 +10427,19 @@ bool BaseCompiler::emitTableSet() {
   }
   if (deadCode_) {
     return true;
   }
   // set(index:u32, value:ref, table:u32) -> i32
   //
   // Returns -1 on range error, otherwise 0 (which is then ignored).
   pushI32(tableIndex);
-  if (!emitInstanceCall(lineOrBytecode, SigPIRI_, ExprType::Void,
-                        SymbolicAddress::TableSet)) {
+  if (!emitInstanceCall(lineOrBytecode, SigPIRI_, ExprType::I32,
+                        SymbolicAddress::TableSet,
+                        /*pushReturnedValue=*/false)) {
     return false;
   }
   Label noTrap;
   masm.branchTest32(Assembler::NotSigned, ReturnReg, ReturnReg, &noTrap);
   trap(Trap::ThrowReported);
   masm.bind(&noTrap);
   return true;
 }
--- a/layout/generic/test/plugin_clipping_helper.xhtml
+++ b/layout/generic/test/plugin_clipping_helper.xhtml
@@ -4,17 +4,17 @@
 <head>
   <style>
   embed { width:200px; height:200px; display:block; }
   iframe { border:none; }
   </style>
 </head>
 <body>
 
-<!-- Use a XUL element here so we can get its boxObject.screenX/Y -->
+<!-- Use a XUL element here so we can get its screenX/Y -->
 <hbox style="height:10px; position:absolute; left:0; top:0; z-index:-100;" id="h1"
       xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <hbox style="width:100px;"></hbox><hbox id="h2"/>
 </hbox>
 
 <!-- Non-clipped plugin -->
 <embed id="p1" type="application/x-test" wmode="window"
        style="position:absolute; left:300px; top:0"></embed>
--- a/layout/generic/test/plugin_clipping_helper2.xhtml
+++ b/layout/generic/test/plugin_clipping_helper2.xhtml
@@ -3,17 +3,17 @@
 <html xmlns="http://www.w3.org/1999/xhtml" title="Test Plugin Clipping: Dynamic Tests">
 <head>
   <style>
   embed { width:300px; height:200px; display:block; }
   </style>
 </head>
 <body>
 
-<!-- Use a XUL element here so we can get its boxObject.screenX/Y -->
+<!-- Use a XUL element here so we can get its screenX/Y -->
 <hbox style="height:10px; position:absolute; left:0; top:0; z-index:-100;" id="h1"
       xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <hbox style="width:100px;"></hbox><hbox id="h2"/>
 </hbox>
 
 <div id="d1" style="width:200px; overflow:hidden; position:absolute; top:0; left:0;">
   <embed id="p1" type="application/x-test" wmode="window" style="position:relative"></embed>
 </div>
--- a/layout/generic/test/plugin_clipping_helper_table.xhtml
+++ b/layout/generic/test/plugin_clipping_helper_table.xhtml
@@ -3,17 +3,17 @@
 <html xmlns="http://www.w3.org/1999/xhtml" title="Test Plugin Clipping: Plugins and Tables">
 <head>
   <style>
   embed { width:300px; height:200px; display:block; }
   </style>
 </head>
 <body>
 
-<!-- Use a XUL element here so we can get its boxObject.screenX/Y -->
+<!-- Use a XUL element here so we can get its screenX/Y -->
 <hbox style="height:10px; position:absolute; left:0; top:0; z-index:-100;" id="h1"
       xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <hbox style="width:100px;"></hbox><hbox id="h2"/>
 </hbox>
 
 <embed id="p1" type="application/x-test" wmode="window"
        style="position:absolute; top:0; left:0;"></embed>
 <table style="width:300px; height:100px; position:absolute; top:100px; left:0; background:white;">
--- a/layout/generic/test/plugin_clipping_helper_transformed.xhtml
+++ b/layout/generic/test/plugin_clipping_helper_transformed.xhtml
@@ -3,17 +3,17 @@
 <html xmlns="http://www.w3.org/1999/xhtml" title="Test Plugin Clipping: Plugins in Transforms">
 <head>
   <style>
   embed { width:300px; height:200px; display:block; }
   </style>
 </head>
 <body>
 
-<!-- Use a XUL element here so we can get its boxObject.screenX/Y -->
+<!-- Use a XUL element here so we can get its screenX/Y -->
 <hbox style="height:10px; position:absolute; left:0; top:0; z-index:-100;" id="h1"
       xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <hbox style="width:100px;"></hbox><hbox id="h2"/>
 </hbox>
 
 <div style="width:200px; position:absolute; top:0; left:0; -moz-transform:rotate(90deg)">
   <embed id="p1" type="application/x-test" wmode="window"></embed>
 </div>
--- a/layout/generic/test/plugin_clipping_lib.js
+++ b/layout/generic/test/plugin_clipping_lib.js
@@ -126,35 +126,35 @@ checkClipRegionForFrame = function check
 
 checkClipRegionNoBounds = function checkClipRegionNoBounds(id, rects) {
   checkClipRegionWithDoc(document, 0, 0, id, rects, false);
 }
 
 function loaded() {
   var h1 = document.getElementById("h1");
   var h2 = document.getElementById("h2");
-  var hwidth = h2.boxObject.screenX - h1.boxObject.screenX;
+  var hwidth = h2.screenX - h1.screenX;
   if (hwidth != 100) {
     // Maybe it's a DPI issue
     todo(false, "Unexpected DPI?");
     finish();
     window.close();
     return;
   }
 
   if (!document.getElementById("p1").identifierToStringTest) {
     todo(false, "Test plugin not available");
     finish();
     window.close();
     return;
   }
 
   var bounds = h1.getBoundingClientRect();
-  windowFrameX = h1.boxObject.screenX - bounds.left - window.screenX;
-  windowFrameY = h1.boxObject.screenY - bounds.top - window.screenY;
+  windowFrameX = h1.screenX - bounds.left - window.screenX;
+  windowFrameY = h1.screenY - bounds.top - window.screenY;
 
   // Run actual test code
   runTests();
 }
 
 // Need to run 'loaded' after painting is unsuppressed, or we'll set clip
 // regions to empty.  The timeout must be non-zero on X11 so that
 // gtk_container_idle_sizer runs after the GtkSocket gets the plug_window.
--- a/layout/generic/test/test_plugin_position.xhtml
+++ b/layout/generic/test/test_plugin_position.xhtml
@@ -1,17 +1,17 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
 <html xmlns="http://www.w3.org/1999/xhtml" title="Test Plugin Positioning">
 <head>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 </head>
 <body>
 
-<!-- Use a XUL element here so we can get its boxObject.screenX/Y -->
+<!-- Use a XUL element here so we can get its screenX/Y -->
 <hbox style="height:10px; position:absolute; left:0; top:0; z-index:-100;" id="h1"
       xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <hbox style="width:100px;"></hbox><hbox id="h2"/>
 </hbox>
 
 <embed id="p" type="application/x-test" width="200" height="200" wmode="window"></embed>
 <embed id="p2" type="application/x-test" wmode="window"
        style="outline:5px solid blue; width:200px; height:200px;
@@ -36,33 +36,33 @@ function checkGeometry(id, x, y, w, h) {
   is(pY, windowFrameY + bounds.top + y, id + " plugin Y");
   is(pWidth, w, id + " plugin width");
   is(pHeight, h, id + " plugin height");
 }
 
 function runTests() {
   var h1 = document.getElementById("h1");
   var h2 = document.getElementById("h2");
-  var hwidth = h2.boxObject.screenX - h1.boxObject.screenX;
+  var hwidth = h2.screenX - h1.screenX;
   if (hwidth != 100) {
     // Maybe it's a DPI issue
     todo(false, "Unexpected DPI?");
     SimpleTest.finish();
     return;
   }
 
   if (!document.getElementById("p").identifierToStringTest) {
     todo(false, "Test plugin not available");
     SimpleTest.finish();
     return;
   }
 
   var bounds = h1.getBoundingClientRect();
-  windowFrameX = h1.boxObject.screenX - bounds.left - window.screenX;
-  windowFrameY = h1.boxObject.screenY - bounds.top - window.screenY;
+  windowFrameX = h1.screenX - bounds.left - window.screenX;
+  windowFrameY = h1.screenY - bounds.top - window.screenY;
 
   checkGeometry("p", 0, 0, 200, 200);
   // This one tests widget positioning in the presence of borders and padding
   checkGeometry("p2", 9, 7, 182, 186);
 
   SimpleTest.finish();
 }
 
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-mediaqueries/greenbox-print.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<meta charset="utf-8">
+<html class="reftest-paged">
+<title>A reference of green box</title>
+<style>
+div {
+  width: 100px;
+  height: 100px;
+  background-color: green;
+}
+</style>
+<div></div>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-mediaqueries/mq_prefers_color_scheme.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<meta charset="utf-8">
+<html>
+<title>prefers-color-scheme is supported</title>
+<style>
+div {
+  width: 100px;
+  height: 100px;
+}
+
+@media (prefers-color-scheme) {
+  div { background-color: green; }
+}
+</style>
+<div></div>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-mediaqueries/mq_prefers_color_scheme_dark.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<html>
+<title>prefers-color-scheme: dark</title>
+<style>
+div {
+  width: 100px;
+  height: 100px;
+}
+
+@media (prefers-color-scheme: dark) {
+  div { background-color: green; }
+}
+@media (prefers-color-scheme: light) {
+  div { background-color: red; }
+}
+@media (prefers-color-scheme: no-preference) {
+  div { background-color: red; }
+}
+</style>
+<div></div>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-mediaqueries/mq_prefers_color_scheme_light.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<html>
+<title>prefers-color-scheme: light</title>
+<style>
+div {
+  width: 100px;
+  height: 100px;
+}
+
+@media (prefers-color-scheme: light) {
+  div { background-color: green; }
+}
+@media (prefers-color-scheme: dark) {
+  div { background-color: red; }
+}
+@media (prefers-color-scheme: no-preference) {
+  div { background-color: red; }
+}
+</style>
+<div></div>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-mediaqueries/mq_prefers_color_scheme_no_preference.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<html>
+<title>prefers-color-scheme: no-preference</title>
+<style>
+div {
+  width: 100px;
+  height: 100px;
+}
+
+@media (prefers-color-scheme: no-preference) {
+  div { background-color: green; }
+}
+@media (prefers-color-scheme: light) {
+  div { background-color: red; }
+}
+@media (prefers-color-scheme: dark) {
+  div { background-color: red; }
+}
+</style>
+<div></div>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-mediaqueries/mq_prefers_color_scheme_print.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<html class="reftest-paged">
+<title>prefers-color-scheme: light in print mode</title>
+<style>
+div {
+  width: 100px;
+  height: 100px;
+}
+
+@media (prefers-color-scheme: light) {
+  div { background-color: green; }
+}
+@media (prefers-color-scheme: dark) {
+  div { background-color: red; }
+}
+@media (prefers-color-scheme: no-preference) {
+  div { background-color: red; }
+}
+</style>
+<div></div>
+</html>
--- a/layout/reftests/css-mediaqueries/reftest.list
+++ b/layout/reftests/css-mediaqueries/reftest.list
@@ -22,8 +22,14 @@ fuzzy-if(Android,0-8,0-454) == mq_print_
 test-pref(ui.prefersReducedMotion,0) == mq_prefers_reduced_motion.html about:blank
 test-pref(ui.prefersReducedMotion,1) == mq_prefers_reduced_motion.html greenbox.html
 test-pref(ui.prefersReducedMotion,0) == mq_prefers_reduced_motion_no_preference.html greenbox.html
 test-pref(ui.prefersReducedMotion,1) == mq_prefers_reduced_motion_no_preference.html about:blank
 test-pref(ui.prefersReducedMotion,0) == mq_prefers_reduced_motion_reduce.html about:blank
 test-pref(ui.prefersReducedMotion,1) == mq_prefers_reduced_motion_reduce.html greenbox.html
 test-pref(privacy.resistFingerprinting,true) test-pref(ui.prefersReducedMotion,1) == mq_prefers_reduced_motion_reduce.html about:blank
 test-pref(privacy.resistFingerprinting,true) == mq_prefers_reduced_motion_both.html greenbox.html
+test-pref(ui.systemUsesDarkTheme,1) == mq_prefers_color_scheme.html greenbox.html
+test-pref(privacy.resistFingerprinting,true) == mq_prefers_color_scheme_light.html greenbox.html
+== mq_prefers_color_scheme_print.html greenbox-print.html
+test-pref(ui.systemUsesDarkTheme,0) == mq_prefers_color_scheme_light.html greenbox.html
+test-pref(ui.systemUsesDarkTheme,1) == mq_prefers_color_scheme_dark.html greenbox.html
+test-pref(ui.systemUsesDarkTheme,2) == mq_prefers_color_scheme_no_preference.html greenbox.html
--- a/layout/style/GeckoBindings.h
+++ b/layout/style/GeckoBindings.h
@@ -794,16 +794,18 @@ mozilla::StyleDisplayMode Gecko_MediaFea
 
 uint32_t Gecko_MediaFeatures_GetColorDepth(mozilla::dom::Document*);
 
 void Gecko_MediaFeatures_GetDeviceSize(mozilla::dom::Document*, nscoord* width,
                                        nscoord* height);
 
 float Gecko_MediaFeatures_GetResolution(mozilla::dom::Document*);
 bool Gecko_MediaFeatures_PrefersReducedMotion(mozilla::dom::Document*);
+mozilla::StylePrefersColorScheme Gecko_MediaFeatures_PrefersColorScheme(
+    mozilla::dom::Document*);
 
 mozilla::PointerCapabilities Gecko_MediaFeatures_PrimaryPointerCapabilities(
     mozilla::dom::Document*);
 
 mozilla::PointerCapabilities Gecko_MediaFeatures_AllPointerCapabilities(
     mozilla::dom::Document*);
 
 float Gecko_MediaFeatures_GetDevicePixelRatio(mozilla::dom::Document*);
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -385,16 +385,17 @@ cbindgen-types = [
     { gecko = "StyleAppearance", servo = "values::specified::Appearance" },
     { gecko = "StyleComputedFontStretchRange", servo = "font_face::ComputedFontStretchRange" },
     { gecko = "StyleComputedFontStyleDescriptor", servo = "font_face::ComputedFontStyleDescriptor" },
     { gecko = "StyleComputedFontWeightRange", servo = "font_face::ComputedFontWeightRange" },
     { gecko = "StyleComputedTimingFunction", servo = "values::computed::easing::TimingFunction" },
     { gecko = "StyleCursorKind", servo = "values::computed::ui::CursorKind" },
     { gecko = "StyleDisplay", servo = "values::specified::Display" },
     { gecko = "StyleDisplayMode", servo = "gecko::media_features::DisplayMode" },
+    { gecko = "StylePrefersColorScheme", servo = "gecko::media_features::PrefersColorScheme" },
     { gecko = "StyleExtremumLength", servo = "values::computed::length::ExtremumLength" },
     { gecko = "StyleFillRule", servo = "values::generics::basic_shape::FillRule" },
     { gecko = "StyleFontDisplay", servo = "font_face::FontDisplay" },
     { gecko = "StyleFontFaceSourceListComponent", servo = "font_face::FontFaceSourceListComponent" },
     { gecko = "StyleFontLanguageOverride", servo = "values::computed::font::FontLanguageOverride" },
     { gecko = "StylePathCommand", servo = "values::specified::svg_path::PathCommand" },
     { gecko = "StyleUnicodeRange", servo = "cssparser::UnicodeRange" },
     { gecko = "StyleOverflowWrap", servo = "values::computed::OverflowWrap" },
@@ -480,16 +481,17 @@ structs-types = [
     "mozilla::FontStretch",
     "mozilla::FontSlantStyle",
     "mozilla::FontWeight",
     "mozilla::MallocSizeOf",
     "mozilla::OriginFlags",
     "mozilla::StyleMotion",
     "mozilla::UniquePtr",
     "mozilla::StyleDisplayMode",
+    "mozilla::StylePrefersColorScheme",
     "mozilla::StyleIntersectionObserverRootMargin",
     "mozilla::StyleComputedFontStretchRange",
     "mozilla::StyleComputedFontStyleDescriptor",
     "mozilla::StyleComputedFontWeightRange",
     "mozilla::StyleFontDisplay",
     "mozilla::StyleUnicodeRange",
     "mozilla::StyleFontLanguageOverride",
     "mozilla::StyleFontFaceSourceListComponent",
--- a/layout/style/nsMediaFeatures.cpp
+++ b/layout/style/nsMediaFeatures.cpp
@@ -233,16 +233,36 @@ nsAtom* Gecko_MediaFeatures_GetOperating
 
 bool Gecko_MediaFeatures_PrefersReducedMotion(Document* aDocument) {
   if (nsContentUtils::ShouldResistFingerprinting(aDocument)) {
     return false;
   }
   return LookAndFeel::GetInt(LookAndFeel::eIntID_PrefersReducedMotion, 0) == 1;
 }
 
+StylePrefersColorScheme Gecko_MediaFeatures_PrefersColorScheme(Document* aDocument) {
+  if (nsContentUtils::ShouldResistFingerprinting(aDocument)) {
+    return StylePrefersColorScheme::Light;
+  }
+  if (nsPresContext* pc = aDocument->GetPresContext()) {
+    if (pc->IsPrintingOrPrintPreview()) {
+      return StylePrefersColorScheme::Light;
+    }
+  }
+  // If LookAndFeel::eIntID_SystemUsesDarkTheme fails then return 2 (no-preference)
+  switch (LookAndFeel::GetInt(LookAndFeel::eIntID_SystemUsesDarkTheme, 2)) {
+    case 0: return StylePrefersColorScheme::Light;
+    case 1: return StylePrefersColorScheme::Dark;
+    case 2: return StylePrefersColorScheme::NoPreference;
+    default:
+      // This only occurs if the user has set the ui.systemUsesDarkTheme pref to an invalid value.
+      return StylePrefersColorScheme::Light;
+  }
+}
+
 static PointerCapabilities GetPointerCapabilities(Document* aDocument,
                                                   LookAndFeel::IntID aID) {
   MOZ_ASSERT(aID == LookAndFeel::eIntID_PrimaryPointerCapabilities ||
              aID == LookAndFeel::eIntID_AllPointerCapabilities);
   MOZ_ASSERT(aDocument);
 
   if (nsIDocShell* docShell = aDocument->GetDocShell()) {
     // The touch-events-override happens only for the Responsive Design Mode so
--- a/layout/xul/nsXULTooltipListener.cpp
+++ b/layout/xul/nsXULTooltipListener.cpp
@@ -17,25 +17,23 @@
 #  include "nsITreeView.h"
 #endif
 #include "nsIScriptContext.h"
 #include "nsPIDOMWindow.h"
 #ifdef MOZ_XUL
 #  include "nsXULPopupManager.h"
 #endif
 #include "nsIPopupContainer.h"
-#include "nsIBoxObject.h"
 #include "nsTreeColumns.h"
 #include "nsContentUtils.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Event.h"  // for Event
-#include "mozilla/dom/BoxObject.h"
 #include "mozilla/dom/MouseEvent.h"
 #include "mozilla/dom/TreeColumnBinding.h"
 #include "mozilla/dom/XULTreeElementBinding.h"
 #include "mozilla/TextEvents.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
@@ -320,35 +318,29 @@ void nsXULTooltipListener::RemoveTooltip
   aNode->RemoveSystemEventListener(NS_LITERAL_STRING("dragstart"), this, true);
 }
 
 #ifdef MOZ_XUL
 void nsXULTooltipListener::CheckTreeBodyMove(MouseEvent* aMouseEvent) {
   nsCOMPtr<nsIContent> sourceNode = do_QueryReferent(mSourceNode);
   if (!sourceNode) return;
 
-  // get the boxObject of the documentElement of the document the tree is in
-  nsCOMPtr<nsIBoxObject> bx;
+  // get the documentElement of the document the tree is in
   Document* doc = sourceNode->GetComposedDoc();
-  if (doc) {
-    ErrorResult ignored;
-    bx = doc->GetBoxObjectFor(doc->GetRootElement(), ignored);
-  }
 
   RefPtr<XULTreeElement> tree = GetSourceTree();
-  if (bx && tree) {
+  Element* root = doc ? doc->GetRootElement() : nullptr;
+  if (root && root->GetPrimaryFrame() && tree) {
     int32_t x = aMouseEvent->ScreenX(CallerType::System);
     int32_t y = aMouseEvent->ScreenY(CallerType::System);
 
-    // subtract off the documentElement's boxObject
-    int32_t boxX, boxY;
-    bx->GetScreenX(&boxX);
-    bx->GetScreenY(&boxY);
-    x -= boxX;
-    y -= boxY;
+    // subtract off the documentElement's position
+    CSSIntRect rect = root->GetPrimaryFrame()->GetScreenRect();
+    x -= rect.x;
+    y -= rect.y;
 
     ErrorResult rv;
     TreeCellInfo cellInfo;
     tree->GetCellAt(x, y, cellInfo, rv);
 
     int32_t row = cellInfo.mRow;
     RefPtr<nsTreeColumn> col = cellInfo.mCol;
 
--- a/media/webrtc/trunk/webrtc/common_audio/fir_filter_neon.cc
+++ b/media/webrtc/trunk/webrtc/common_audio/fir_filter_neon.cc
@@ -5,21 +5,17 @@
  *  that can be found in the LICENSE file in the root of the source
  *  tree. An additional intellectual property rights grant can be found
  *  in the file PATENTS.  All contributing project authors may
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
 #include "common_audio/fir_filter_neon.h"
 
-#if defined(_MSC_VER) && !defined(__clang__)
-#include <arm64_neon.h>
-#else
 #include <arm_neon.h>
-#endif
 #include <string.h>
 
 #include "rtc_base/checks.h"
 #include "system_wrappers/include/aligned_malloc.h"
 
 namespace webrtc {
 
 FIRFilterNEON::~FIRFilterNEON() {
--- a/media/webrtc/trunk/webrtc/common_audio/resampler/sinc_resampler_neon.cc
+++ b/media/webrtc/trunk/webrtc/common_audio/resampler/sinc_resampler_neon.cc
@@ -8,21 +8,17 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
 // Modified from the Chromium original:
 // src/media/base/sinc_resampler.cc
 
 #include "common_audio/resampler/sinc_resampler.h"
 
-#if defined(_MSC_VER) && !defined(__clang__)
-#include <arm64_neon.h>
-#else
 #include <arm_neon.h>
-#endif
 
 namespace webrtc {
 
 float SincResampler::Convolve_NEON(const float* input_ptr, const float* k1,
                                    const float* k2,
                                    double kernel_interpolation_factor) {
   float32x4_t m_input;
   float32x4_t m_sums1 = vmovq_n_f32(0);
--- a/media/webrtc/trunk/webrtc/common_audio/signal_processing/cross_correlation_neon.c
+++ b/media/webrtc/trunk/webrtc/common_audio/signal_processing/cross_correlation_neon.c
@@ -5,21 +5,17 @@
  *  that can be found in the LICENSE file in the root of the source
  *  tree. An additional intellectual property rights grant can be found
  *  in the file PATENTS.  All contributing project authors may
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
 #include "common_audio/signal_processing/include/signal_processing_library.h"
 
-#if defined(_MSC_VER) && !defined(__clang__)
-#include <arm64_neon.h>
-#else
 #include <arm_neon.h>
-#endif
 
 static inline void DotProductWithScaleNeon(int32_t* cross_correlation,
                                            const int16_t* vector1,
                                            const int16_t* vector2,
                                            size_t length,
                                            int scaling) {
   size_t i = 0;
   size_t len1 = length >> 3;
@@ -50,17 +46,17 @@ static inline void DotProductWithScaleNe
   int64_t sum_res = 0;
   for (i = len2; i > 0; i -= 1) {
     sum_res += WEBRTC_SPL_MUL_16_16(*vector1, *vector2);
     vector1++;
     vector2++;
   }
 
   sum0 = vaddq_s64(sum0, sum1);
-#if defined(WEBRTC_ARCH_ARM64) && (!defined(_MSC_VER) || defined(__clang__))
+#if defined(WEBRTC_ARCH_ARM64)
   int64_t sum2 = vaddvq_s64(sum0);
   *cross_correlation = (int32_t)((sum2 + sum_res) >> scaling);
 #else
   int64x1_t shift = vdup_n_s64(-scaling);
   int64x1_t sum2 = vadd_s64(vget_low_s64(sum0), vget_high_s64(sum0));
   sum2 = vadd_s64(sum2, vdup_n_s64(sum_res));
   sum2 = vshl_s64(sum2, shift);
   vst1_lane_s32(cross_correlation, vreinterpret_s32_s64(sum2), 0);
--- a/media/webrtc/trunk/webrtc/common_audio/signal_processing/downsample_fast_neon.c
+++ b/media/webrtc/trunk/webrtc/common_audio/signal_processing/downsample_fast_neon.c
@@ -5,21 +5,17 @@
  *  that can be found in the LICENSE file in the root of the source
  *  tree. An additional intellectual property rights grant can be found
  *  in the file PATENTS.  All contributing project authors may
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
 #include "common_audio/signal_processing/include/signal_processing_library.h"
 
-#if defined(_MSC_VER) && !defined(__clang__)
-#include <arm64_neon.h>
-#else
 #include <arm_neon.h>
-#endif
 
 // NEON intrinsics version of WebRtcSpl_DownsampleFast()
 // for ARM 32-bit/64-bit platforms.
 int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in,
                                  size_t data_in_length,
                                  int16_t* data_out,
                                  size_t data_out_length,
                                  const int16_t* __restrict coefficients,
--- a/media/webrtc/trunk/webrtc/common_audio/signal_processing/min_max_operations_neon.c
+++ b/media/webrtc/trunk/webrtc/common_audio/signal_processing/min_max_operations_neon.c
@@ -3,21 +3,17 @@
  *
  *  Use of this source code is governed by a BSD-style license
  *  that can be found in the LICENSE file in the root of the source
  *  tree. An additional intellectual property rights grant can be found
  *  in the file PATENTS.  All contributing project authors may
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#if defined(_MSC_VER) && !defined(__clang__)
-#include <arm64_neon.h>
-#else
 #include <arm_neon.h>
-#endif
 #include <stdlib.h>
 
 #include "rtc_base/checks.h"
 #include "common_audio/signal_processing/include/signal_processing_library.h"
 
 // Maximum absolute value of word16 vector. C version for generic platforms.
 int16_t WebRtcSpl_MaxAbsValueW16Neon(const int16_t* vector, size_t length) {
   int absolute = 0, maximum = 0;
@@ -36,17 +32,17 @@ int16_t WebRtcSpl_MaxAbsValueW16Neon(con
     v = vld1q_s16(p_start);
     // Note vabs doesn't change the value of -32768.
     v = vabsq_s16(v);
     // Use u16 so we don't lose the value -32768.
     max_qv = vmaxq_u16(max_qv, vreinterpretq_u16_s16(v));
     p_start += 8;
   }
 
-#if defined(WEBRTC_ARCH_ARM64) && (!defined(_MSC_VER) || defined(__clang__))
+#ifdef WEBRTC_ARCH_ARM64
   maximum = (int)vmaxvq_u16(max_qv);
 #else
   uint16x4_t max_dv;
   max_dv = vmax_u16(vget_low_u16(max_qv), vget_high_u16(max_qv));
   max_dv = vpmax_u16(max_dv, max_dv);
   max_dv = vpmax_u16(max_dv, max_dv);
 
   maximum = (int)vget_lane_u16(max_dv, 0);
@@ -96,17 +92,17 @@ int32_t WebRtcSpl_MaxAbsValueW32Neon(con
     in32x4_1 = vabsq_s32(in32x4_1);
     // vabs doesn't change the value of 0x80000000.
     // Use u32 so we don't lose the value 0x80000000.
     max32x4_0 = vmaxq_u32(max32x4_0, vreinterpretq_u32_s32(in32x4_0));
     max32x4_1 = vmaxq_u32(max32x4_1, vreinterpretq_u32_s32(in32x4_1));
   }
 
   uint32x4_t max32x4 = vmaxq_u32(max32x4_0, max32x4_1);
-#if defined(WEBRTC_ARCH_ARM64) && (!defined(_MSC_VER) || defined(__clang__))
+#if defined(WEBRTC_ARCH_ARM64)
   maximum = vmaxvq_u32(max32x4);
 #else
   uint32x2_t max32x2 = vmax_u32(vget_low_u32(max32x4), vget_high_u32(max32x4));
   max32x2 = vpmax_u32(max32x2, max32x2);
 
   maximum = vget_lane_u32(max32x2, 0);
 #endif
 
@@ -139,17 +135,17 @@ int16_t WebRtcSpl_MaxValueW16Neon(const 
 
   // First part, unroll the loop 8 times.
   for (i = 0; i < length - residual; i += 8) {
     int16x8_t in16x8 = vld1q_s16(p_start);
     max16x8 = vmaxq_s16(max16x8, in16x8);
     p_start += 8;
   }
 
-#if defined(WEBRTC_ARCH_ARM64) && (!defined(_MSC_VER) || defined(__clang__))
+#if defined(WEBRTC_ARCH_ARM64)
   maximum = vmaxvq_s16(max16x8);
 #else
   int16x4_t max16x4 = vmax_s16(vget_low_s16(max16x8), vget_high_s16(max16x8));
   max16x4 = vpmax_s16(max16x4, max16x4);
   max16x4 = vpmax_s16(max16x4, max16x4);
 
   maximum = vget_lane_s16(max16x4, 0);
 #endif
@@ -182,17 +178,17 @@ int32_t WebRtcSpl_MaxValueW32Neon(const 
     p_start += 4;
     int32x4_t in32x4_1 = vld1q_s32(p_start);
     p_start += 4;
     max32x4_0 = vmaxq_s32(max32x4_0, in32x4_0);
     max32x4_1 = vmaxq_s32(max32x4_1, in32x4_1);
   }
 
   int32x4_t max32x4 = vmaxq_s32(max32x4_0, max32x4_1);
-#if defined(WEBRTC_ARCH_ARM64) && (!defined(_MSC_VER) || defined(__clang__))
+#if defined(WEBRTC_ARCH_ARM64)
   maximum = vmaxvq_s32(max32x4);
 #else
   int32x2_t max32x2 = vmax_s32(vget_low_s32(max32x4), vget_high_s32(max32x4));
   max32x2 = vpmax_s32(max32x2, max32x2);
 
   maximum = vget_lane_s32(max32x2, 0);
 #endif
 
@@ -219,17 +215,17 @@ int16_t WebRtcSpl_MinValueW16Neon(const 
 
   // First part, unroll the loop 8 times.
   for (i = 0; i < length - residual; i += 8) {
     int16x8_t in16x8 = vld1q_s16(p_start);
     min16x8 = vminq_s16(min16x8, in16x8);
     p_start += 8;
   }
 
-#if defined(WEBRTC_ARCH_ARM64) && (!defined(_MSC_VER) || defined(__clang__))
+#if defined(WEBRTC_ARCH_ARM64)
   minimum = vminvq_s16(min16x8);
 #else
   int16x4_t min16x4 = vmin_s16(vget_low_s16(min16x8), vget_high_s16(min16x8));
   min16x4 = vpmin_s16(min16x4, min16x4);
   min16x4 = vpmin_s16(min16x4, min16x4);
 
   minimum = vget_lane_s16(min16x4, 0);
 #endif
@@ -262,17 +258,17 @@ int32_t WebRtcSpl_MinValueW32Neon(const 
     p_start += 4;
     int32x4_t in32x4_1 = vld1q_s32(p_start);
     p_start += 4;
     min32x4_0 = vminq_s32(min32x4_0, in32x4_0);
     min32x4_1 = vminq_s32(min32x4_1, in32x4_1);
   }
 
   int32x4_t min32x4 = vminq_s32(min32x4_0, min32x4_1);
-#if defined(WEBRTC_ARCH_ARM64) && (!defined(_MSC_VER) || defined(__clang__))
+#if defined(WEBRTC_ARCH_ARM64)
   minimum = vminvq_s32(min32x4);
 #else
   int32x2_t min32x2 = vmin_s32(vget_low_s32(min32x4), vget_high_s32(min32x4));
   min32x2 = vpmin_s32(min32x2, min32x2);
 
   minimum = vget_lane_s32(min32x2, 0);
 #endif
 
--- a/media/webrtc/trunk/webrtc/modules/audio_coding/codecs/isac/fix/source/entropy_coding_neon.c
+++ b/media/webrtc/trunk/webrtc/modules/audio_coding/codecs/isac/fix/source/entropy_coding_neon.c
@@ -11,21 +11,17 @@
 /* This file contains WebRtcIsacfix_MatrixProduct1Neon() and
  * WebRtcIsacfix_MatrixProduct2Neon() for ARM Neon platform. API's are in
  * entropy_coding.c. Results are bit exact with the c code for
  * generic platforms.
  */
 
 #include "entropy_coding.h"
 
-#if defined(_MSC_VER) && !defined(__clang__)
-#include <arm64_neon.h>
-#else
 #include <arm_neon.h>
-#endif
 #include <stddef.h>
 
 #include "signal_processing_library.h"
 #include "rtc_base/checks.h"
 
 void WebRtcIsacfix_MatrixProduct1Neon(const int16_t matrix0[],
                                       const int32_t matrix1[],
                                       int32_t matrix_product[],
--- a/media/webrtc/trunk/webrtc/modules/audio_coding/codecs/isac/fix/source/filterbanks_neon.c
+++ b/media/webrtc/trunk/webrtc/modules/audio_coding/codecs/isac/fix/source/filterbanks_neon.c
@@ -8,21 +8,17 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
 // Contains a function for WebRtcIsacfix_AllpassFilter2FixDec16Neon()
 // in iSAC codec, optimized for ARM Neon platform. Bit exact with function
 // WebRtcIsacfix_AllpassFilter2FixDec16C() in filterbanks.c. Prototype
 // C code is at end of this file.
 
-#if defined(_MSC_VER) && !defined(__clang__)
-#include <arm64_neon.h>
-#else
 #include <arm_neon.h>
-#endif
 
 #include "rtc_base/checks.h"
 
 void WebRtcIsacfix_AllpassFilter2FixDec16Neon(
     int16_t* data_ch1,  // Input and output in channel 1, in Q0
     int16_t* data_ch2,  // Input and output in channel 2, in Q0
     const int16_t* factor_ch1,  // Scaling factor for channel 1, in Q15
     const int16_t* factor_ch2,  // Scaling factor for channel 2, in Q15
--- a/media/webrtc/trunk/webrtc/modules/audio_coding/codecs/isac/fix/source/filters_neon.c
+++ b/media/webrtc/trunk/webrtc/modules/audio_coding/codecs/isac/fix/source/filters_neon.c
@@ -3,21 +3,17 @@
  *
  *  Use of this source code is governed by a BSD-style license
  *  that can be found in the LICENSE file in the root of the source
  *  tree. An additional intellectual property rights grant can be found
  *  in the file PATENTS.  All contributing project authors may
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#if defined(_MSC_VER) && !defined(__clang__)
-#include <arm64_neon.h>
-#else
 #include <arm_neon.h>
-#endif
 
 #include "rtc_base/checks.h"
 #include "modules/audio_coding/codecs/isac/fix/source/codec.h"
 
 // Autocorrelation function in fixed point.
 // NOTE! Different from SPLIB-version in how it scales the signal.
 int WebRtcIsacfix_AutocorrNeon(int32_t* __restrict r,
                                const int16_t* x,
@@ -43,17 +39,17 @@ int WebRtcIsacfix_AutocorrNeon(int32_t* 
   const int16_t* x_end0 = x_start + n;
   while (x_start < x_end0) {
     x0_v = vld1_s16(x_start);
     tmpa0_v = vmull_s16(x0_v, x0_v);
     tmpb_v = vpadalq_s32(tmpb_v, tmpa0_v);
     x_start += 4;
   }
 
-#if defined(WEBRTC_ARCH_ARM64) && (!defined(_MSC_VER) || defined(__clang__))
+#ifdef WEBRTC_ARCH_ARM64
   prod = vaddvq_s64(tmpb_v);
 #else
   prod = vget_lane_s64(vadd_s64(vget_low_s64(tmpb_v), vget_high_s64(tmpb_v)),
                        0);
 #endif
   // Calculate scaling (the value of shifting).
   temp = (uint32_t)(prod >> 31);
 
@@ -89,17 +85,17 @@ int WebRtcIsacfix_AutocorrNeon(int32_t* 
     if (rest >= 4) {
         int16x4_t x2_v = vld1_s16(x_start);
         int16x4_t y2_v = vld1_s16(y_start);
         tmpa0_v = vmull_s16(x2_v, y2_v);
         tmpb_v = vpadalq_s32(tmpb_v, tmpa0_v);
         x_start += 4;
         y_start += 4;
     }
-#if defined(WEBRTC_ARCH_ARM64) && (!defined(_MSC_VER) || defined(__clang__))
+#ifdef WEBRTC_ARCH_ARM64
     prod = vaddvq_s64(tmpb_v);
 #else
     prod = vget_lane_s64(vadd_s64(vget_low_s64(tmpb_v), vget_high_s64(tmpb_v)),
                          0);
 #endif
 
     prod_tail = 0;
     while (x_start < x_end1) {
--- a/media/webrtc/trunk/webrtc/modules/audio_coding/codecs/isac/fix/source/lattice_neon.c
+++ b/media/webrtc/trunk/webrtc/modules/audio_coding/codecs/isac/fix/source/lattice_neon.c
@@ -3,21 +3,17 @@
  *
  *  Use of this source code is governed by a BSD-style license
  *  that can be found in the LICENSE file in the root of the source
  *  tree. An additional intellectual property rights grant can be found
  *  in the file PATENTS.  All contributing project authors may
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#if defined(_MSC_VER) && !defined(__clang__)
-#include <arm64_neon.h>
-#else
 #include <arm_neon.h>
-#endif
 
 #include "modules/audio_coding/codecs/isac/fix/source/codec.h"
 #include "modules/audio_coding/codecs/isac/fix/source/settings.h"
 
 // Contains a function for the core loop in the normalized lattice MA
 // filter routine for iSAC codec, optimized for ARM Neon platform.
 // It does:
 //  for 0 <= n < HALF_SUBFRAMELEN - 1:
--- a/media/webrtc/trunk/webrtc/modules/audio_coding/codecs/isac/fix/source/pitch_estimator_c.c
+++ b/media/webrtc/trunk/webrtc/modules/audio_coding/codecs/isac/fix/source/pitch_estimator_c.c
@@ -6,22 +6,18 @@
  *  tree. An additional intellectual property rights grant can be found
  *  in the file PATENTS.  All contributing project authors may
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
 #include "modules/audio_coding/codecs/isac/fix/source/pitch_estimator.h"
 
 #ifdef WEBRTC_HAS_NEON
-#if defined(_MSC_VER) && !defined(__clang__)
-#include <arm64_neon.h>
-#else
 #include <arm_neon.h>
 #endif
-#endif
 
 #include "common_audio/signal_processing/include/signal_processing_library.h"
 #include "rtc_base/compile_assert_c.h"
 
 extern int32_t WebRtcIsacfix_Log2Q8(uint32_t x);
 
 void WebRtcIsacfix_PCorr2Q32(const int16_t* in, int32_t* logcorQ8) {
   int16_t scaling,n,k;
--- a/media/webrtc/trunk/webrtc/modules/audio_coding/codecs/isac/fix/source/transform_neon.c
+++ b/media/webrtc/trunk/webrtc/modules/audio_coding/codecs/isac/fix/source/transform_neon.c
@@ -3,21 +3,17 @@
  *
  *  Use of this source code is governed by a BSD-style license
  *  that can be found in the LICENSE file in the root of the source
  *  tree. An additional intellectual property rights grant can be found
  *  in the file PATENTS.  All contributing project authors may
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#if defined(_MSC_VER) && !defined(__clang__)
-#include <arm64_neon.h>
-#else
 #include <arm_neon.h>
-#endif
 
 #include "modules/audio_coding/codecs/isac/fix/source/codec.h"
 #include "modules/audio_coding/codecs/isac/fix/source/fft.h"
 #include "modules/audio_coding/codecs/isac/fix/source/settings.h"
 
 // Tables are defined in transform_tables.c file.
 // Cosine table 1 in Q14.
 extern const int16_t WebRtcIsacfix_kCosTab1[FRAMESAMPLES/2];
@@ -50,17 +46,17 @@ static inline int32_t ComplexMulAndFindM
     inre1Q9 += 8;
     inre2Q9 += 8;
 
     // Use ">> 26", instead of ">> 7", ">> 16" and then ">> 3" as in the C code.
     int32x4_t tmp0 = vmull_s16(vget_low_s16(tmpr), vget_low_s16(inre1));
     int32x4_t tmp1 = vmull_s16(vget_low_s16(tmpr), vget_low_s16(inre2));
     tmp0 = vmlal_s16(tmp0, vget_low_s16(tmpi), vget_low_s16(inre2));
     tmp1 = vmlsl_s16(tmp1, vget_low_s16(tmpi), vget_low_s16(inre1));
-#if defined(WEBRTC_ARCH_ARM64) && (!defined(_MSC_VER) || defined(__clang__))
+#if defined(WEBRTC_ARCH_ARM64)
     int32x4_t tmp2 = vmull_high_s16(tmpr, inre1);
     int32x4_t tmp3 = vmull_high_s16(tmpr, inre2);
     tmp2 = vmlal_high_s16(tmp2, tmpi, inre2);
     tmp3 = vmlsl_high_s16(tmp3, tmpi, inre1);
 #else
     int32x4_t tmp2 = vmull_s16(vget_high_s16(tmpr), vget_high_s16(inre1));
     int32x4_t tmp3 = vmull_s16(vget_high_s16(tmpr), vget_high_s16(inre2));
     tmp2 = vmlal_s16(tmp2, vget_high_s16(tmpi), vget_high_s16(inre2));
@@ -89,17 +85,17 @@ static inline int32_t ComplexMulAndFindM
     // Use u32 so we don't lose the value 0x80000000.
     max_r = vmaxq_u32(max_r, vreinterpretq_u32_s32(tmp0));
     max_i = vmaxq_u32(max_i, vreinterpretq_u32_s32(tmp2));
     max_r = vmaxq_u32(max_r, vreinterpretq_u32_s32(tmp1));
     max_i = vmaxq_u32(max_i, vreinterpretq_u32_s32(tmp3));
   }
 
   max_r = vmaxq_u32(max_r, max_i);
-#if defined(WEBRTC_ARCH_ARM64) && (!defined(_MSC_VER) || defined(__clang__))
+#if defined(WEBRTC_ARCH_ARM64)
   uint32_t maximum = vmaxvq_u32(max_r);
 #else
   uint32x2_t max32x2_r = vmax_u32(vget_low_u32(max_r), vget_high_u32(max_r));
   max32x2_r = vpmax_u32(max32x2_r, max32x2_r);
   uint32_t maximum = vget_lane_u32(max32x2_r, 0);
 #endif
 
   return (int32_t)maximum;
@@ -330,17 +326,17 @@ static inline int32_t TransformAndFindMa
     outim1 += 4;
     vst1q_s32(outre2, outr_1);
     outre2 -= 4;
     vst1q_s32(outim2, outi_1);
     outim2 -= 4;
   }
 
   max_r = vmaxq_u32(max_r, max_i);
-#if defined(WEBRTC_ARCH_ARM64) && (!defined(_MSC_VER) || defined(__clang__))
+#if defined(WEBRTC_ARCH_ARM64)
   uint32_t maximum = vmaxvq_u32(max_r);
 #else
   uint32x2_t max32x2_r = vmax_u32(vget_low_u32(max_r), vget_high_u32(max_r));
   max32x2_r = vpmax_u32(max32x2_r, max32x2_r);
   uint32_t maximum = vget_lane_u32(max32x2_r, 0);
 #endif
 
   return (int32_t)maximum;
--- a/media/webrtc/trunk/webrtc/modules/audio_processing/aec/aec_core_neon.cc
+++ b/media/webrtc/trunk/webrtc/modules/audio_processing/aec/aec_core_neon.cc
@@ -9,21 +9,17 @@
  */
 
 /*
  * The core AEC algorithm, neon version of speed-critical functions.
  *
  * Based on aec_core_sse2.c.
  */
 
-#if defined(_MSC_VER) && !defined(__clang__)
-#include <arm64_neon.h>
-#else
 #include <arm_neon.h>
-#endif
 #include <math.h>
 #include <string.h>  // memset
 
 extern "C" {
 #include "common_audio/signal_processing/include/signal_processing_library.h"
 }
 #include "modules/audio_processing/aec/aec_common.h"
 #include "modules/audio_processing/aec/aec_core_optimized_methods.h"
@@ -98,18 +94,17 @@ static float32x4_t vdivq_f32(float32x4_t
   //
   // Note: The precision did not improve after 2 iterations.
   for (i = 0; i < 2; i++) {
     x = vmulq_f32(vrecpsq_f32(b, x), x);
   }
   // a/b = a*(1/b)
   return vmulq_f32(a, x);
 }
-#endif
-#if !defined(WEBRTC_ARCH_ARM64) || (defined(_MSC_VER) && !defined(__clang__))
+
 static float32x4_t vsqrtq_f32(float32x4_t s) {
   int i;
   float32x4_t x = vrsqrteq_f32(s);
 
   // Code to handle sqrt(0).
   // If the input to sqrtf() is zero, a zero will be returned.
   // If the input to vrsqrteq_f32() is zero, positive infinity is returned.
   const uint32x4_t vec_p_inf = vdupq_n_u32(0x7F800000);
--- a/media/webrtc/trunk/webrtc/modules/audio_processing/aec3/adaptive_fir_filter.cc
+++ b/media/webrtc/trunk/webrtc/modules/audio_processing/aec3/adaptive_fir_filter.cc
@@ -6,22 +6,18 @@
  *  tree. An additional intellectual property rights grant can be found
  *  in the file PATENTS.  All contributing project authors may
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
 #include "modules/audio_processing/aec3/adaptive_fir_filter.h"
 
 #if defined(WEBRTC_HAS_NEON)
-#if defined(_MSC_VER) && !defined(__clang__)
-#include <arm64_neon.h>
-#else
 #include <arm_neon.h>
 #endif
-#endif
 #include "typedefs.h"  // NOLINT(build/include)
 #if defined(WEBRTC_ARCH_X86_FAMILY)
 #include <emmintrin.h>
 #endif
 #include <algorithm>
 #include <functional>
 
 #include "modules/audio_processing/aec3/fft_data.h"
--- a/media/webrtc/trunk/webrtc/modules/audio_processing/aec3/matched_filter.cc
+++ b/media/webrtc/trunk/webrtc/modules/audio_processing/aec3/matched_filter.cc
@@ -5,22 +5,18 @@
  *  that can be found in the LICENSE file in the root of the source
  *  tree. An additional intellectual property rights grant can be found
  *  in the file PATENTS.  All contributing project authors may
  *  be found in the AUTHORS file in the root of the source tree.
  */
 #include "modules/audio_processing/aec3/matched_filter.h"
 
 #if defined(WEBRTC_HAS_NEON)
-#if defined(_MSC_VER) && !defined(__clang__)
-#include <arm64_neon.h>
-#else
 #include <arm_neon.h>
 #endif
-#endif
 #include "typedefs.h"  // NOLINT(build/include)
 #if defined(WEBRTC_ARCH_X86_FAMILY)
 #include <emmintrin.h>
 #endif
 #include <algorithm>
 #include <numeric>
 
 #include "modules/audio_processing/include/audio_processing.h"
--- a/media/webrtc/trunk/webrtc/modules/audio_processing/aec3/vector_math.h
+++ b/media/webrtc/trunk/webrtc/modules/audio_processing/aec3/vector_math.h
@@ -8,22 +8,18 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
 #ifndef MODULES_AUDIO_PROCESSING_AEC3_VECTOR_MATH_H_
 #define MODULES_AUDIO_PROCESSING_AEC3_VECTOR_MATH_H_
 
 #include "typedefs.h"  // NOLINT(build/include)
 #if defined(WEBRTC_HAS_NEON)
-#if defined(_MSC_VER) && !defined(__clang__)
-#include <arm64_neon.h>
-#else
 #include <arm_neon.h>
 #endif
-#endif
 #if defined(WEBRTC_ARCH_X86_FAMILY)
 #include <emmintrin.h>
 #endif
 #include <math.h>
 #include <algorithm>
 #include <array>
 #include <functional>
 
@@ -63,17 +59,17 @@ class VectorMath {
 #if defined(WEBRTC_HAS_NEON)
       case Aec3Optimization::kNeon: {
         const int x_size = static_cast<int>(x.size());
         const int vector_limit = x_size >> 2;
 
         int j = 0;
         for (; j < vector_limit * 4; j += 4) {
           float32x4_t g = vld1q_f32(&x[j]);
-#if !defined(WEBRTC_ARCH_ARM64) || (defined(_MSC_VER) && !defined(__clang__))
+#if !defined(WEBRTC_ARCH_ARM64)
           float32x4_t y = vrsqrteq_f32(g);
 
           // Code to handle sqrt(0).
           // If the input to sqrtf() is zero, a zero will be returned.
           // If the input to vrsqrteq_f32() is zero, positive infinity is
           // returned.
           const uint32x4_t vec_p_inf = vdupq_n_u32(0x7F800000);
           // check for divide by zero
--- a/media/webrtc/trunk/webrtc/modules/audio_processing/aecm/aecm_core_neon.cc
+++ b/media/webrtc/trunk/webrtc/modules/audio_processing/aecm/aecm_core_neon.cc
@@ -5,30 +5,26 @@
  *  that can be found in the LICENSE file in the root of the source
  *  tree. An additional intellectual property rights grant can be found
  *  in the file PATENTS.  All contributing project authors may
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
 #include "modules/audio_processing/aecm/aecm_core.h"
 
-#if defined(_MSC_VER) && !defined(__clang__)
-#include <arm64_neon.h>
-#else
 #include <arm_neon.h>
-#endif
 
 #include "common_audio/signal_processing/include/real_fft.h"
 #include "rtc_base/checks.h"
 
 // TODO(kma): Re-write the corresponding assembly file, the offset
 // generating script and makefile, to replace these C functions.
 
 static inline void AddLanes(uint32_t* ptr, uint32x4_t v) {
-#if defined(WEBRTC_ARCH_ARM64) && (!defined(_MSC_VER) || defined(__clang__))
+#if defined(WEBRTC_ARCH_ARM64)
   *(ptr) = vaddvq_u32(v);
 #else
   uint32x2_t tmp_v;
   tmp_v = vadd_u32(vget_low_u32(v), vget_high_u32(v));
   tmp_v = vpadd_u32(tmp_v, tmp_v);
   *(ptr) = vget_lane_u32(tmp_v, 0);
 #endif
 }
--- a/media/webrtc/trunk/webrtc/modules/audio_processing/ns/nsx_core_neon.c
+++ b/media/webrtc/trunk/webrtc/modules/audio_processing/ns/nsx_core_neon.c
@@ -5,21 +5,17 @@
  *  that can be found in the LICENSE file in the root of the source
  *  tree. An additional intellectual property rights grant can be found
  *  in the file PATENTS.  All contributing project authors may
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
 #include "modules/audio_processing/ns/nsx_core.h"
 
-#if defined(_MSC_VER) && !defined(__clang__)
-#include <arm64_neon.h>
-#else
 #include <arm_neon.h>
-#endif
 
 #include "rtc_base/checks.h"
 
 // Constants to compensate for shifting signal log(2^shifts).
 const int16_t WebRtcNsx_kLogTable[9] = {
   0, 177, 355, 532, 710, 887, 1065, 1242, 1420
 };
 
--- a/media/webrtc/trunk/webrtc/modules/audio_processing/utility/ooura_fft_neon.cc
+++ b/media/webrtc/trunk/webrtc/modules/audio_processing/utility/ooura_fft_neon.cc
@@ -11,21 +11,17 @@
 /*
  * The rdft AEC algorithm, neon version of speed-critical functions.
  *
  * Based on the sse2 version.
  */
 
 #include "modules/audio_processing/utility/ooura_fft.h"
 
-#if defined(_MSC_VER) && !defined(__clang__)
-#include <arm64_neon.h>
-#else
 #include <arm_neon.h>
-#endif
 
 #include "modules/audio_processing/utility/ooura_fft_tables_common.h"
 #include "modules/audio_processing/utility/ooura_fft_tables_neon_sse2.h"
 
 namespace webrtc {
 
 #if defined(WEBRTC_HAS_NEON)
 void cft1st_128_neon(float* a) {
--- a/media/webrtc/trunk/webrtc/modules/video_processing/util/denoiser_filter_neon.cc
+++ b/media/webrtc/trunk/webrtc/modules/video_processing/util/denoiser_filter_neon.cc
@@ -3,21 +3,17 @@
  *
  *  Use of this source code is governed by a BSD-style license
  *  that can be found in the LICENSE file in the root of the source
  *  tree. An additional intellectual property rights grant can be found
  *  in the file PATENTS.  All contributing project authors may
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#if defined(_MSC_VER) && !defined(__clang__)
-#include <arm64_neon.h>
-#else
 #include <arm_neon.h>
-#endif
 
 #include "modules/video_processing/util/denoiser_filter_neon.h"
 
 namespace webrtc {
 
 const int kSumDiffThresholdHighNeon = 600;
 
 static int HorizontalAddS16x8(const int16x8_t v_16x8) {
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/SessionLifecycleTest.kt
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/SessionLifecycleTest.kt
@@ -22,16 +22,17 @@ import android.os.Parcelable
 import android.os.SystemClock
 import android.support.test.InstrumentationRegistry
 import android.support.test.filters.MediumTest
 import android.support.test.runner.AndroidJUnit4
 import android.util.Log
 import android.util.SparseArray
 
 import org.hamcrest.Matchers.*
+import org.junit.Assume.assumeThat
 import org.junit.Test
 import org.junit.runner.RunWith
 import java.io.File
 import java.io.IOException
 import java.lang.ref.ReferenceQueue
 import java.lang.ref.WeakReference
 
 @RunWith(AndroidJUnit4::class)
@@ -144,16 +145,18 @@ class SessionLifecycleTest : BaseSession
                        newSession.isOpen, equalTo(false))
         }
 
         sessionRule.session.reload()
         sessionRule.session.waitForPageStop()
     }
 
     @Test fun readFromParcel_closedSessionAfterReadParcel() {
+        // disable test on opt for frequently failing Bug 1519591
+        assumeThat(sessionRule.env.isDebugBuild, equalTo(true))
         val session = sessionRule.createOpenSession()
 
         session.toParcel { parcel ->
             assertThat("Session is still open", session.isOpen, equalTo(true))
             val newSession = sessionRule.createClosedSession()
             newSession.readFromParcel(parcel)
             assertThat("New session should be open",
                     newSession.isOpen, equalTo(true))
--- a/netwerk/protocol/websocket/WebSocketChannel.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannel.cpp
@@ -2834,26 +2834,38 @@ nsresult WebSocketChannel::ApplyForAdmis
                "nsIProtocolProxyService::AsyncResolve succeeded but didn't "
                "return a cancelable object!");
   return rv;
 }
 
 // Called after both OnStartRequest and OnTransportAvailable have
 // executed. This essentially ends the handshake and starts the websockets
 // protocol state machine.
-nsresult WebSocketChannel::StartWebsocketData() {
-  nsresult rv;
+nsresult WebSocketChannel::CallStartWebsocketData() {
+  LOG(("WebSocketChannel::CallStartWebsocketData() %p", this));
+  MOZ_ASSERT(NS_IsMainThread(), "not main thread");
+
+  if (mOpenTimer) {
+    mOpenTimer->Cancel();
+    mOpenTimer = nullptr;
+  }
 
   if (!IsOnTargetThread()) {
     return mTargetThread->Dispatch(
         NewRunnableMethod("net::WebSocketChannel::StartWebsocketData", this,
                           &WebSocketChannel::StartWebsocketData),
         NS_DISPATCH_NORMAL);
   }
 
+  return StartWebsocketData();
+}
+
+nsresult WebSocketChannel::StartWebsocketData() {
+  nsresult rv;
+
   {
     MutexAutoLock lock(mMutex);
     LOG(("WebSocketChannel::StartWebsocketData() %p", this));
     MOZ_ASSERT(!mDataStarted, "StartWebsocketData twice");
 
     if (mStopped) {
       LOG(
           ("WebSocketChannel::StartWebsocketData channel already closed, not "
@@ -2920,17 +2932,17 @@ nsresult WebSocketChannel::StartPinging(
          mPingInterval));
   } else {
     NS_WARNING("unable to create ping timer. Carrying on.");
   }
 
   return NS_OK;
 }
 
-void WebSocketChannel::ReportConnectionTelemetry() {
+void WebSocketChannel::ReportConnectionTelemetry(nsresult aStatusCode) {
   // 3 bits are used. high bit is for wss, middle bit for failed,
   // and low bit for proxy..
   // 0 - 7 : ws-ok-plain, ws-ok-proxy, ws-failed-plain, ws-failed-proxy,
   //         wss-ok-plain, wss-ok-proxy, wss-failed-plain, wss-failed-proxy
 
   bool didProxy = false;
 
   nsCOMPtr<nsIProxyInfo> pi;
@@ -2938,18 +2950,20 @@ void WebSocketChannel::ReportConnectionT
   if (pc) pc->GetProxyInfo(getter_AddRefs(pi));
   if (pi) {
     nsAutoCString proxyType;
     pi->GetType(proxyType);
     if (!proxyType.IsEmpty() && !proxyType.EqualsLiteral("direct"))
       didProxy = true;
   }
 
-  uint8_t value = (mEncrypted ? (1 << 2) : 0) |
-                  (!mGotUpgradeOK ? (1 << 1) : 0) | (didProxy ? (1 << 0) : 0);
+  uint8_t value =
+      (mEncrypted ? (1 << 2) : 0) |
+      (!(mGotUpgradeOK && NS_SUCCEEDED(aStatusCode)) ? (1 << 1) : 0) |
+      (didProxy ? (1 << 0) : 0);
 
   LOG(("WebSocketChannel::ReportConnectionTelemetry() %p %d", this, value));
   Telemetry::Accumulate(Telemetry::WEBSOCKETS_HANDSHAKE_TYPE, value);
 }
 
 // nsIDNSListener
 
 NS_IMETHODIMP
@@ -3160,17 +3174,16 @@ WebSocketChannel::Notify(nsITimer *timer
 
     mCloseTimer = nullptr;
     if (mStopped || mServerClosed) /* no longer relevant */
       return NS_OK;
 
     LOG(("WebSocketChannel:: Expecting Server Close - Timed Out\n"));
     AbortSession(NS_ERROR_NET_TIMEOUT);
   } else if (timer == mOpenTimer) {
-    MOZ_ASSERT(!mGotUpgradeOK, "Open Timer after open complete");
     MOZ_ASSERT(NS_IsMainThread(), "not main thread");
 
     mOpenTimer = nullptr;
     LOG(("WebSocketChannel:: Connection Timed Out\n"));
     if (mStopped || mServerClosed) /* no longer relevant */
       return NS_OK;
 
     AbortSession(NS_ERROR_NET_TIMEOUT);
@@ -3592,17 +3605,17 @@ WebSocketChannel::OnTransportAvailable(n
 
   mRecvdHttpUpgradeTransport = 1;
   if (mGotUpgradeOK) {
     // We're now done CONNECTING, which means we can now open another,
     // perhaps parallel, connection to the same host if one
     // is pending
     nsWSAdmissionManager::OnConnected(this);
 
-    return StartWebsocketData();
+    return CallStartWebsocketData();
   }
 
   if (mIsServerSide) {
     if (!mNegotiatedExtensions.IsEmpty()) {
       bool clientNoContextTakeover;
       bool serverNoContextTakeover;
       int32_t clientMaxWindowBits;
       int32_t serverMaxWindowBits;
@@ -3635,36 +3648,31 @@ WebSocketChannel::OnTransportAvailable(n
             ("WebSocketChannel::OnTransportAvailable: Cannot init PMCE "
              "compression object\n"));
         mPMCECompressor = nullptr;
         AbortSession(NS_ERROR_UNEXPECTED);
         return NS_ERROR_UNEXPECTED;
       }
     }
 
-    return StartWebsocketData();
+    return CallStartWebsocketData();
   }
 
   return NS_OK;
 }
 
 // nsIRequestObserver (from nsIStreamListener)
 
 NS_IMETHODIMP
 WebSocketChannel::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) {
   LOG(("WebSocketChannel::OnStartRequest(): %p [%p %p] recvdhttpupgrade=%d\n",
        this, aRequest, mHttpChannel.get(), mRecvdHttpUpgradeTransport));
   MOZ_ASSERT(NS_IsMainThread(), "not main thread");
   MOZ_ASSERT(!mGotUpgradeOK, "OTA duplicated");
 
-  if (mOpenTimer) {
-    mOpenTimer->Cancel();
-    mOpenTimer = nullptr;
-  }
-
   if (mStopped) {
     LOG(("WebSocketChannel::OnStartRequest: Channel Already Done\n"));
     AbortSession(NS_ERROR_CONNECTION_REFUSED);
     return NS_ERROR_CONNECTION_REFUSED;
   }
 
   nsresult rv;
   uint32_t status;
@@ -3827,30 +3835,36 @@ WebSocketChannel::OnStartRequest(nsIRequ
 
   mGotUpgradeOK = 1;
   if (mRecvdHttpUpgradeTransport) {
     // We're now done CONNECTING, which means we can now open another,
     // perhaps parallel, connection to the same host if one
     // is pending
     nsWSAdmissionManager::OnConnected(this);
 
-    return StartWebsocketData();
+    return CallStartWebsocketData();
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 WebSocketChannel::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext,
                                 nsresult aStatusCode) {
   LOG(("WebSocketChannel::OnStopRequest() %p [%p %p %" PRIx32 "]\n", this,
        aRequest, mHttpChannel.get(), static_cast<uint32_t>(aStatusCode)));
   MOZ_ASSERT(NS_IsMainThread(), "not main thread");
 
-  ReportConnectionTelemetry();
+  // OnTransportAvailable won't be called if the request is stopped with
+  // an error. Abort the session now instead of waiting for timeout.
+  if (NS_FAILED(aStatusCode) && !mRecvdHttpUpgradeTransport) {
+    AbortSession(aStatusCode);
+  }
+
+  ReportConnectionTelemetry(aStatusCode);
 
   // This is the end of the HTTP upgrade transaction, the
   // upgraded streams live on
 
   mChannel = nullptr;
   mHttpChannel = nullptr;
   mLoadGroup = nullptr;
   mCallbacks = nullptr;
--- a/netwerk/protocol/websocket/WebSocketChannel.h
+++ b/netwerk/protocol/websocket/WebSocketChannel.h
@@ -152,19 +152,20 @@ class WebSocketChannel : public BaseWebS
   MOZ_MUST_USE nsresult StartPinging();
 
   void BeginOpen(bool aCalledFromAdmissionManager);
   void BeginOpenInternal();
   MOZ_MUST_USE nsresult HandleExtensions();
   MOZ_MUST_USE nsresult SetupRequest();
   MOZ_MUST_USE nsresult ApplyForAdmission();
   MOZ_MUST_USE nsresult DoAdmissionDNS();
+  MOZ_MUST_USE nsresult CallStartWebsocketData();
   MOZ_MUST_USE nsresult StartWebsocketData();
   uint16_t ResultToCloseCode(nsresult resultCode);
-  void ReportConnectionTelemetry();
+  void ReportConnectionTelemetry(nsresult aStatusCode);
 
   void StopSession(nsresult reason);
   void DoStopSession(nsresult reason);
   void AbortSession(nsresult reason);
   void ReleaseSession();
   void CleanupConnection();
   void IncrementSessionCount();
   void DecrementSessionCount();
--- a/servo/components/style/cbindgen.toml
+++ b/servo/components/style/cbindgen.toml
@@ -52,16 +52,17 @@ include = [
   "OutlineStyle",
   "ComputedFontStretchRange",
   "ComputedFontStyleDescriptor",
   "ComputedFontWeightRange",
   "ComputedTimingFunction",
   "CursorKind",
   "Display",
   "DisplayMode",
+  "PrefersColorScheme",
   "ExtremumLength",
   "FillRule",
   "FontDisplay",
   "FontFaceSourceListComponent",
   "FontLanguageOverride",
   "OverflowWrap",
   "TimingFunction",
   "PathCommand",
--- a/servo/components/style/gecko/media_features.rs
+++ b/servo/components/style/gecko/media_features.rs
@@ -275,16 +275,26 @@ fn eval_resolution(
 
 #[derive(Clone, Copy, Debug, FromPrimitive, Parse, ToCss)]
 #[repr(u8)]
 enum PrefersReducedMotion {
     NoPreference,
     Reduce,
 }
 
+/// Values for the prefers-color-scheme media feature.
+#[derive(Clone, Copy, Debug, FromPrimitive, Parse, PartialEq, ToCss)]
+#[repr(u8)]
+#[allow(missing_docs)]
+pub enum PrefersColorScheme {
+    Light,
+    Dark,
+    NoPreference,
+}
+
 /// https://drafts.csswg.org/mediaqueries-5/#prefers-reduced-motion
 fn eval_prefers_reduced_motion(device: &Device, query_value: Option<PrefersReducedMotion>) -> bool {
     let prefers_reduced =
         unsafe { bindings::Gecko_MediaFeatures_PrefersReducedMotion(device.document()) };
     let query_value = match query_value {
         Some(v) => v,
         None => return prefers_reduced,
     };
@@ -343,16 +353,26 @@ fn eval_overflow_inline(device: &Device,
     };
 
     match query_value {
         OverflowInline::None => !scrolling,
         OverflowInline::Scroll => scrolling,
     }
 }
 
+/// https://drafts.csswg.org/mediaqueries-5/#prefers-color-scheme
+fn eval_prefers_color_scheme(device: &Device, query_value: Option<PrefersColorScheme>) -> bool {
+    let prefers_color_scheme =
+        unsafe { bindings::Gecko_MediaFeatures_PrefersColorScheme(device.document()) };
+    match query_value {
+        Some(v) => prefers_color_scheme == v,
+        None => prefers_color_scheme != PrefersColorScheme::NoPreference,
+    }
+}
+
 /// https://drafts.csswg.org/mediaqueries-4/#mf-interaction
 bitflags! {
     struct PointerCapabilities: u8 {
         const COARSE = structs::PointerCapabilities_Coarse;
         const FINE = structs::PointerCapabilities_Fine;
         const HOVER = structs::PointerCapabilities_Hover;
     }
 }
@@ -521,17 +541,17 @@ macro_rules! system_metric_feature {
 }
 
 lazy_static! {
     /// Adding new media features requires (1) adding the new feature to this
     /// array, with appropriate entries (and potentially any new code needed
     /// to support new types in these entries and (2) ensuring that either
     /// nsPresContext::MediaFeatureValuesChanged is called when the value that
     /// would be returned by the evaluator function could change.
-    pub static ref MEDIA_FEATURES: [MediaFeatureDescription; 52] = [
+    pub static ref MEDIA_FEATURES: [MediaFeatureDescription; 53] = [
         feature!(
             atom!("width"),
             AllowsRanges::Yes,
             Evaluator::Length(eval_width),
             ParsingRequirements::empty(),
         ),
         feature!(
             atom!("height"),
@@ -653,16 +673,22 @@ lazy_static! {
         ),
         feature!(
             atom!("overflow-inline"),
             AllowsRanges::No,
             keyword_evaluator!(eval_overflow_inline, OverflowInline),
             ParsingRequirements::empty(),
         ),
         feature!(
+            atom!("prefers-color-scheme"),
+            AllowsRanges::No,
+            keyword_evaluator!(eval_prefers_color_scheme, PrefersColorScheme),
+            ParsingRequirements::empty(),
+        ),
+        feature!(
             atom!("pointer"),
             AllowsRanges::No,
             keyword_evaluator!(eval_pointer, Pointer),
             ParsingRequirements::empty(),
         ),
         feature!(
             atom!("any-pointer"),
             AllowsRanges::No,
--- a/taskcluster/ci/docker-image/kind.yml
+++ b/taskcluster/ci/docker-image/kind.yml
@@ -17,23 +17,44 @@ transforms:
 # (to use subdirectory clones of the proper directory), at which point we can
 # generate tasks for every docker image in the directory, secure in the
 # knowledge that unnecessary images will be omitted from the target task graph
 jobs:
   image_builder:
     symbol: I(ib)
   desktop1604-test:
     symbol: I(dt16t)
+  # Neither the debian7-*raw nor the debian7-*packages images can have
+  # packages dependencies.
+  debian7-raw:
+    symbol: I(deb7-raw)
+    definition: debian-raw
+    args:
+      BASE_IMAGE: debian:wheezy-20171210
+      DIST: wheezy
+      SNAPSHOT: '20171210T214726Z'
+  debian7-packages:
+    symbol: I(deb7-pkg)
+    definition: debian-packages
+    parent: debian7-raw
+  debian7-i386-raw:
+    symbol: I(deb7-32-raw)
+    definition: debian-raw
+    args:
+      BASE_IMAGE: i386/debian:wheezy-20171210
+      DIST: wheezy
+      SNAPSHOT: '20171210T214726Z'
+  debian7-i386-packages:
+    symbol: I(deb7-32-pkg)
+    definition: debian-packages
+    parent: debian7-i386-raw
   debian7-base:
     symbol: I(deb7-base)
     definition: debian-base
-    args:
-      DIST: wheezy
-      BASE_TAG: '20171210'
-      SNAPSHOT: '20171210T214726Z'
+    parent: debian7-raw
     packages:
       - deb7-gdb
       - deb7-git
       - deb7-make
       - deb7-mercurial
       - deb7-python
       - deb7-python3.5
       - deb7-python3-defaults
@@ -106,23 +127,33 @@ jobs:
     parent: debian7-amd64-build
     packages:
       - deb7-cmake
   valgrind-build:
     symbol: I(vb)
     parent: debian7-amd64-build
   lint:
     symbol: I(lnt)
+  # Neither the debian9-raw nor the debian9-packages images can have
+  # packages dependencies.
+  debian9-raw:
+    symbol: I(deb9-raw)
+    definition: debian-raw
+    args:
+      BASE_IMAGE: debian:stretch-20170620
+      DIST: stretch
+      SNAPSHOT: '20170830T000511Z'
+  debian9-packages:
+    symbol: I(deb9-pkg)
+    definition: debian-packages
+    parent: debian9-raw
   debian9-base:
     symbol: I(deb9-base)
     definition: debian-base
-    args:
-      DIST: stretch
-      BASE_TAG: '20170620'
-      SNAPSHOT: '20170830T000511Z'
+    parent: debian9-raw
     packages:
       - deb9-mercurial
       - deb9-python-zstandard
   debian9-amd64-build:
     symbol: I(deb9)
     parent: debian9-base
     definition: debian-build
     args:
--- a/taskcluster/ci/toolchain/gn.yml
+++ b/taskcluster/ci/toolchain/gn.yml
@@ -18,17 +18,17 @@ job-defaults:
         toolchain-artifact: public/build/gn.tar.xz
 
 linux64-gn:
     treeherder:
         symbol: TL(gn)
     run:
         script: build-gn-linux.sh
     toolchains:
-        - linux64-gcc-4.9
+        - linux64-gcc-6
 
 macosx64-gn:
     treeherder:
         symbol: TM(gn)
     worker:
         env:
             TOOLTOOL_MANIFEST: "browser/config/tooltool-manifests/macosx64/cross-clang.manifest"
     run:
--- a/taskcluster/docker/debian-base/Dockerfile
+++ b/taskcluster/docker/debian-base/Dockerfile
@@ -1,11 +1,10 @@
-# %ARG DIST
-# %ARG BASE_TAG
-FROM debian:$DIST-$BASE_TAG
+# %ARG DOCKER_IMAGE_PARENT
+FROM $DOCKER_IMAGE_PARENT
 MAINTAINER Mike Hommey <mhommey@mozilla.com>
 
 ### Add worker user and setup its workspace.
 RUN mkdir /builds && \
     groupadd -g 1000 worker && \
     useradd -u 1000 -g 1000 -d /builds/worker -s /bin/bash -m worker && \
     mkdir -p /builds/worker/workspace && \
     chown -R worker:worker /builds
@@ -18,46 +17,24 @@ VOLUME /builds/worker/workspace
 VOLUME /builds/worker/tooltool-cache
 
 # Set variable normally configured at login, by the shells parent process, these
 # are taken from GNU su manual
 ENV HOME=/builds/worker \
     SHELL=/bin/bash \
     USER=worker \
     LOGNAME=worker \
-    HOSTNAME=taskcluster-worker \
-    DEBIAN_FRONTEND=noninteractive
+    HOSTNAME=taskcluster-worker
 
 # Set a default command useful for debugging
 CMD ["/bin/bash", "--login"]
 
-# %ARG SNAPSHOT
-# Set apt sources list to a snapshot.
-RUN for s in debian_$DIST debian_$DIST-updates debian_$DIST-backports debian-security_$DIST/updates; do \
-      echo "deb http://snapshot.debian.org/archive/${s%_*}/$SNAPSHOT/ ${s#*_} main"; \
-    done > /etc/apt/sources.list && \
-    ( echo 'quiet "true";'; \
-      echo 'APT::Get::Assume-Yes "true";'; \
-      echo 'APT::Install-Recommends "false";'; \
-      echo 'Acquire::Check-Valid-Until "false";'; \
-      echo 'Acquire::Retries "5";'; \
-    ) > /etc/apt/apt.conf.d/99taskcluster
-
-RUN apt-get update && \
-    apt-get install \
-      apt-transport-https \
-      ca-certificates
-
-COPY setup_packages.sh /usr/local/sbin/
-COPY cloud-mirror-workaround.sh /usr/local/sbin/
-
 # %ARG TASKCLUSTER_ROOT_URL
 # %ARG DOCKER_IMAGE_PACKAGES
 RUN /usr/local/sbin/setup_packages.sh $TASKCLUSTER_ROOT_URL $DOCKER_IMAGE_PACKAGES && \
-    echo 'dir::bin::methods::https "/usr/local/sbin/cloud-mirror-workaround.sh";' > /etc/apt/apt.conf.d/99cloud-mirror-workaround && \
     apt-get update && \
     apt-get install \
       git \
       less \
       make \
       mercurial \
       patch \
       python \
new file mode 100644
--- /dev/null
+++ b/taskcluster/docker/debian-packages/Dockerfile
@@ -0,0 +1,10 @@
+# %ARG DOCKER_IMAGE_PARENT
+FROM $DOCKER_IMAGE_PARENT
+MAINTAINER Mike Hommey <mhommey@mozilla.com>
+
+RUN apt-get install --install-recommends \
+      apt-utils \
+      aptitude \
+      build-essential \
+      devscripts \
+      fakeroot
new file mode 100644
--- /dev/null
+++ b/taskcluster/docker/debian-raw/Dockerfile
@@ -0,0 +1,30 @@
+# %ARG BASE_IMAGE
+FROM $BASE_IMAGE
+MAINTAINER Mike Hommey <mhommey@mozilla.com>
+
+ENV DEBIAN_FRONTEND=noninteractive
+
+# Set a default command useful for debugging
+CMD ["/bin/bash", "--login"]
+
+COPY setup_packages.sh /usr/local/sbin/
+COPY cloud-mirror-workaround.sh /usr/local/sbin/
+
+# %ARG DIST
+# %ARG SNAPSHOT
+# Set apt sources list to a snapshot.
+RUN for s in debian_$DIST debian_$DIST-updates debian_$DIST-backports debian-security_$DIST/updates; do \
+      echo "deb http://snapshot.debian.org/archive/${s%_*}/$SNAPSHOT/ ${s#*_} main"; \
+    done > /etc/apt/sources.list && \
+    ( echo 'quiet "true";'; \
+      echo 'APT::Get::Assume-Yes "true";'; \
+      echo 'APT::Install-Recommends "false";'; \
+      echo 'Acquire::Check-Valid-Until "false";'; \
+      echo 'Acquire::Retries "5";'; \
+      echo 'dir::bin::methods::https "/usr/local/sbin/cloud-mirror-workaround.sh";'; \
+    ) > /etc/apt/apt.conf.d/99taskcluster
+
+RUN apt-get update && \
+    apt-get install \
+      apt-transport-https \
+      ca-certificates
rename from taskcluster/docker/debian-base/cloud-mirror-workaround.sh
rename to taskcluster/docker/debian-raw/cloud-mirror-workaround.sh
rename from taskcluster/docker/debian-base/setup_packages.sh
rename to taskcluster/docker/debian-raw/setup_packages.sh
--- a/taskcluster/scripts/misc/build-cbindgen.sh
+++ b/taskcluster/scripts/misc/build-cbindgen.sh
@@ -13,21 +13,23 @@ Linux)
     COMPRESS_EXT=xz
     ;;
 MINGW*)
     WORKSPACE=$PWD
     UPLOAD_DIR=$WORKSPACE/public/build
     WIN_WORKSPACE="$(pwd -W)"
     COMPRESS_EXT=bz2
 
-    export INCLUDE="$WIN_WORKSPACE/build/src/vs2017_15.4.2/VC/include;$WIN_WORKSPACE/build/src/vs2017_15.4.2/VC/atlmfc/include;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/Include/10.0.15063.0/ucrt;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/Include/10.0.15063.0/shared;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/Include/10.0.15063.0/um;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/Include/10.0.15063.0/winrt;$WIN_WORKSPACE/build/src/vs2017_15.4.2/DIA SDK/include"
+    export INCLUDE="$WIN_WORKSPACE/build/src/vs2017_15.8.4/VC/include;$WIN_WORKSPACE/build/src/vs2017_15.8.4/VC/atlmfc/include;$WIN_WORKSPACE/build/src/vs2017_15.8.4/SDK/Include/10.0.17134.0/ucrt;$WIN_WORKSPACE/build/src/vs2017_15.8.4/SDK/Include/10.0.17134.0/shared;$WIN_WORKSPACE/build/src/vs2017_15.8.4/SDK/Include/10.0.17134.0/um;$WIN_WORKSPACE/build/src/vs2017_15.8.4/SDK/Include/10.0.17134.0/winrt;$WIN_WORKSPACE/build/src/vs2017_15.8.4/DIA SDK/include"
+
+    export LIB="$WIN_WORKSPACE/build/src/vs2017_15.8.4/VC/lib/x64;$WIN_WORKSPACE/build/src/vs2017_15.8.4/VC/atlmfc/lib/x64;$WIN_WORKSPACE/build/src/vs2017_15.8.4/SDK/lib/10.0.17134.0/um/x64;$WIN_WORKSPACE/build/src/vs2017_15.8.4/SDK/lib/10.0.17134.0/ucrt/x64;$WIN_WORKSPACE/build/src/vs2017_15.8.4/DIA SDK/lib/amd64"
 
-    export LIB="$WIN_WORKSPACE/build/src/vs2017_15.4.2/VC/lib/x64;$WIN_WORKSPACE/build/src/vs2017_15.4.2/VC/atlmfc/lib/x64;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/lib/10.0.15063.0/um/x64;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/lib/10.0.15063.0/ucrt/x64;$WIN_WORKSPACE/build/src/vs2017_15.4.2/DIA SDK/lib/amd64"
+    PATH="$WORKSPACE/build/src/vs2017_15.8.4/VC/bin/Hostx64/x64:$WORKSPACE/build/src/vs2017_15.8.4/VC/bin/Hostx86/x86:$WORKSPACE/build/src/vs2017_15.8.4/SDK/bin/10.0.17134.0/x64:$WORKSPACE/build/src/vs2017_15.8.4/redist/x64/Microsoft.VC141.CRT:$WORKSPACE/build/src/vs2017_15.8.4/SDK/Redist/ucrt/DLLs/x64:$WORKSPACE/build/src/vs2017_15.8.4/DIA SDK/bin/amd64:$WORKSPACE/build/src/mingw64/bin:$PATH"
 
-    PATH="$WORKSPACE/build/src/vs2017_15.4.2/VC/bin/Hostx64/x64:$WORKSPACE/build/src/vs2017_15.4.2/VC/bin/Hostx86/x86:$WORKSPACE/build/src/vs2017_15.4.2/SDK/bin/10.0.15063.0/x64:$WORKSPACE/build/src/vs2017_15.4.2/redist/x64/Microsoft.VC141.CRT:$WORKSPACE/build/src/vs2017_15.4.2/SDK/Redist/ucrt/DLLs/x64:$WORKSPACE/build/src/vs2017_15.4.2/DIA SDK/bin/amd64:$WORKSPACE/build/src/mingw64/bin:$PATH"
+    export CC=clang-cl
     ;;
 esac
 
 cd $WORKSPACE/build/src
 
 . taskcluster/scripts/misc/tooltool-download.sh
 
 # OSX cross builds are a bit harder
--- a/taskcluster/scripts/misc/build-clang-windows-helper32.sh
+++ b/taskcluster/scripts/misc/build-clang-windows-helper32.sh
@@ -11,34 +11,34 @@ TOOLTOOL_AUTH_FILE=/c/builds/relengapi.t
 if [ ! -e ${TOOLTOOL_AUTH_FILE} ]; then
     echo cannot find ${TOOLTOOL_AUTH_FILE}
     exit 1
 fi
 
 ./build/src/mach artifact toolchain -v --authentication-file="${TOOLTOOL_AUTH_FILE}" --tooltool-manifest "build/src/${TOOLTOOL_MANIFEST}"${TOOLTOOL_CACHE:+ --cache-dir ${TOOLTOOL_CACHE}}${MOZ_TOOLCHAINS:+ ${MOZ_TOOLCHAINS}}
 
 # Set up all the Visual Studio paths.
-MSVC_DIR=vs2017_15.4.2
+MSVC_DIR=vs2017_15.8.4
 VSWINPATH="$(cd ${MSVC_DIR} && pwd)"
 
 echo vswinpath ${VSWINPATH}
 
 # LLVM_ENABLE_DIA_SDK is set if the directory "$ENV{VSINSTALLDIR}DIA SDK"
 # exists.
 export VSINSTALLDIR="${VSWINPATH}/"
 
 export WINDOWSSDKDIR="${VSWINPATH}/SDK"
 export WIN32_REDIST_DIR="${VSWINPATH}/VC/redist/x86/Microsoft.VC141.CRT"
 export WIN_UCRT_REDIST_DIR="${VSWINPATH}/SDK/Redist/ucrt/DLLs/x86"
 
-export PATH="${VSWINPATH}/VC/bin/Hostx64/x86:${VSWINPATH}/VC/bin/Hostx64/x64:${VSWINPATH}/SDK/bin/10.0.15063.0/x64:${VSWINPATH}/DIA SDK/bin:${PATH}"
+export PATH="${VSWINPATH}/VC/bin/Hostx64/x86:${VSWINPATH}/VC/bin/Hostx64/x64:${VSWINPATH}/SDK/bin/10.0.17134.0/x64:${VSWINPATH}/DIA SDK/bin:${PATH}"
 export PATH="${VSWINPATH}/VC/redist/x86/Microsoft.VC141.CRT:${VSWINPATH}/SDK/Redist/ucrt/DLLs/x86:${PATH}"
 
-export INCLUDE="${VSWINPATH}/VC/include:${VSWINPATH}/VC/atlmfc/include:${VSWINPATH}/SDK/Include/10.0.15063.0/ucrt:${VSWINPATH}/SDK/Include/10.0.15063.0/shared:${VSWINPATH}/SDK/Include/10.0.15063.0/um:${VSWINPATH}/SDK/Include/10.0.15063.0/winrt:${VSWINPATH}/DIA SDK/include"
-export LIB="${VSWINPATH}/VC/lib/x86:${VSWINPATH}/VC/atlmfc/lib/x86:${VSWINPATH}/SDK/Lib/10.0.15063.0/ucrt/x86:${VSWINPATH}/SDK/Lib/10.0.15063.0/um/x86:${VSWINPATH}/DIA SDK/lib"
+export INCLUDE="${VSWINPATH}/VC/include:${VSWINPATH}/VC/atlmfc/include:${VSWINPATH}/SDK/Include/10.0.17134.0/ucrt:${VSWINPATH}/SDK/Include/10.0.17134.0/shared:${VSWINPATH}/SDK/Include/10.0.17134.0/um:${VSWINPATH}/SDK/Include/10.0.17134.0/winrt:${VSWINPATH}/DIA SDK/include"
+export LIB="${VSWINPATH}/VC/lib/x86:${VSWINPATH}/VC/atlmfc/lib/x86:${VSWINPATH}/SDK/Lib/10.0.17134.0/ucrt/x86:${VSWINPATH}/SDK/Lib/10.0.17134.0/um/x86:${VSWINPATH}/DIA SDK/lib"
 
 export PATH="$(cd svn && pwd)/bin:${PATH}"
 export PATH="$(cd cmake && pwd)/bin:${PATH}"
 export PATH="$(cd ninja && pwd)/bin:${PATH}"
 
 # We use |mach python| to set up a virtualenv automatically for us.  We create
 # a dummy mozconfig, because the default machinery for config.guess-choosing
 # of the objdir doesn't work very well.
--- a/taskcluster/scripts/misc/build-clang-windows-helper64.sh
+++ b/taskcluster/scripts/misc/build-clang-windows-helper64.sh
@@ -11,33 +11,33 @@ TOOLTOOL_AUTH_FILE=/c/builds/relengapi.t
 if [ ! -e ${TOOLTOOL_AUTH_FILE} ]; then
     echo cannot find ${TOOLTOOL_AUTH_FILE}
     exit 1
 fi
 
 ./build/src/mach artifact toolchain -v --authentication-file="${TOOLTOOL_AUTH_FILE}" --tooltool-manifest "build/src/${TOOLTOOL_MANIFEST}"${TOOLTOOL_CACHE:+ --cache-dir ${TOOLTOOL_CACHE}}${MOZ_TOOLCHAINS:+ ${MOZ_TOOLCHAINS}}
 
 # Set up all the Visual Studio paths.
-MSVC_DIR=vs2017_15.4.2
+MSVC_DIR=vs2017_15.8.4
 VSWINPATH="$(cd ${MSVC_DIR} && pwd)"
 
 echo vswinpath ${VSWINPATH}
 
 # LLVM_ENABLE_DIA_SDK is set if the directory "$ENV{VSINSTALLDIR}DIA SDK"
 # exists.
 export VSINSTALLDIR="${VSWINPATH}/"
 
 export WINDOWSSDKDIR="${VSWINPATH}/SDK"
 export WIN32_REDIST_DIR="${VSWINPATH}/VC/redist/x64/Microsoft.VC141.CRT"
 export WIN_UCRT_REDIST_DIR="${VSWINPATH}/SDK/Redist/ucrt/DLLs/x64"
 
-export PATH="${VSWINPATH}/VC/bin/Hostx64/x64:${VSWINPATH}/SDK/bin/10.0.15063.0/x64:${VSWINPATH}/VC/redist/x64/Microsoft.VC141.CRT:${VSWINPATH}/SDK/Redist/ucrt/DLLs/x64:${VSWINPATH}/DIA SDK/bin/amd64:${PATH}"
+export PATH="${VSWINPATH}/VC/bin/Hostx64/x64:${VSWINPATH}/SDK/bin/10.0.17134.0/x64:${VSWINPATH}/VC/redist/x64/Microsoft.VC141.CRT:${VSWINPATH}/SDK/Redist/ucrt/DLLs/x64:${VSWINPATH}/DIA SDK/bin/amd64:${PATH}"
 
-export INCLUDE="${VSWINPATH}/VC/include:${VSWINPATH}/VC/atlmfc/include:${VSWINPATH}/SDK/Include/10.0.15063.0/ucrt:${VSWINPATH}/SDK/Include/10.0.15063.0/shared:${VSWINPATH}/SDK/Include/10.0.15063.0/um:${VSWINPATH}/SDK/Include/10.0.15063.0/winrt:${VSWINPATH}/DIA SDK/include"
-export LIB="${VSWINPATH}/VC/lib/x64:${VSWINPATH}/VC/atlmfc/lib/x64:${VSWINPATH}/SDK/Lib/10.0.15063.0/ucrt/x64:${VSWINPATH}/SDK/Lib/10.0.15063.0/um/x64:${VSWINPATH}/DIA SDK/lib/amd64"
+export INCLUDE="${VSWINPATH}/VC/include:${VSWINPATH}/VC/atlmfc/include:${VSWINPATH}/SDK/Include/10.0.17134.0/ucrt:${VSWINPATH}/SDK/Include/10.0.17134.0/shared:${VSWINPATH}/SDK/Include/10.0.17134.0/um:${VSWINPATH}/SDK/Include/10.0.17134.0/winrt:${VSWINPATH}/DIA SDK/include"
+export LIB="${VSWINPATH}/VC/lib/x64:${VSWINPATH}/VC/atlmfc/lib/x64:${VSWINPATH}/SDK/Lib/10.0.17134.0/ucrt/x64:${VSWINPATH}/SDK/Lib/10.0.17134.0/um/x64:${VSWINPATH}/DIA SDK/lib/amd64"
 
 export PATH="$(cd svn && pwd)/bin:${PATH}"
 export PATH="$(cd cmake && pwd)/bin:${PATH}"
 export PATH="$(cd ninja && pwd)/bin:${PATH}"
 
 # We use |mach python| to set up a virtualenv automatically for us.  We create
 # a dummy mozconfig, because the default machinery for config.guess-choosing
 # of the objdir doesn't work very well.
--- a/taskcluster/scripts/misc/build-gn-common.sh
+++ b/taskcluster/scripts/misc/build-gn-common.sh
@@ -1,48 +1,59 @@
 #!/bin/bash
 set -e -v
 
 # This is shared code for building GN.
-
-# Each is a recent commit from chromium's master branch.
-: CHROMIUM_REV           ${CHROMIUM_REV:=e6ba81e00ae835946e069e5bd80bd533b11d8442}
-: GTEST_REV              ${GTEST_REV:=6c5116014ce51ef3273d800cbf75fcef99e798c6}
-: CHROMIUM_SRC_REV       ${CHROMIUM_SRC_REV:=c338d43f49c0d72e69cd6e40eeaf4c0597dbdda1}
+: GN_REV                 ${GN_REV:=d69a9c3765dee2e650bcccebbadf72c5d42d92b1}
 
 
-git clone --no-checkout https://chromium.googlesource.com/chromium/src $WORKSPACE/gn-standalone
+git clone --no-checkout https://gn.googlesource.com/gn $WORKSPACE/gn-standalone
 cd $WORKSPACE/gn-standalone
-git checkout $CHROMIUM_SRC_REV
-
-git clone --no-checkout https://chromium.googlesource.com/chromium/chromium chromium_checkout
-cd chromium_checkout
-git checkout $CHROMIUM_REV
-mkdir -p ../third_party
-mv third_party/libevent ../third_party
-cd ..
+git checkout $GN_REV
 
-rm -rf testing
-mkdir testing
-cd testing
-git clone https://chromium.googlesource.com/chromium/testing/gtest
-cd gtest
-git checkout $GTEST_REV
-cd ../..
+# We remove /WC because of https://bugs.chromium.org/p/gn/issues/detail?id=51
+# And /MACHINE:x64 because we just let the PATH decide what cl and link are
+# used, and if cl is targetting x86, we don't want linkage to fail because of
+# /MACHINE:x64.
+patch -p1 <<'EOF'
+diff --git a/build/gen.py b/build/gen.py
+index a7142fab..78d0fd56 100755
+--- a/build/gen.py
++++ b/build/gen.py
+@@ -357,7 +357,6 @@ def WriteGNNinja(path, platform, host, options):
+         '/D_WIN32_WINNT=0x0A00',
+         '/FS',
+         '/W4',
+-        '/WX',
+         '/Zi',
+         '/wd4099',
+         '/wd4100',
+@@ -373,7 +372,7 @@ def WriteGNNinja(path, platform, host, options):
+         '/D_HAS_EXCEPTIONS=0',
+     ])
+ 
+-    ldflags.extend(['/DEBUG', '/MACHINE:x64'])
++    ldflags.extend(['/DEBUG'])
+ 
+   static_libraries = {
+       'base': {'sources': [
+EOF
 
-cd tools/gn
-patch -p1 < $WORKSPACE/build/src/taskcluster/scripts/misc/gn.patch
+if test -n "$MAC_CROSS"; then
+    python build/gen.py --platform darwin
+else
+    python build/gen.py
+fi
 
-./bootstrap/bootstrap.py -s
-cd ../..
+ninja -C out -v
 
 STAGE=gn
 mkdir -p $UPLOAD_DIR $STAGE
 
 # At this point, the resulting binary is at:
 # $WORKSPACE/out/Release/gn
 if test "$MAC_CROSS" = "" -a "$(uname)" = "Linux"; then
-    strip out/Release/gn
+    strip out/gn
 fi
-cp out/Release/gn $STAGE
+cp out/gn $STAGE
 
 tar -acf gn.tar.$COMPRESS_EXT $STAGE
 cp gn.tar.$COMPRESS_EXT $UPLOAD_DIR
--- a/taskcluster/scripts/misc/build-gn-linux.sh
+++ b/taskcluster/scripts/misc/build-gn-linux.sh
@@ -3,16 +3,17 @@ set -e -v
 
 # This script is for building GN on Linux.
 
 WORKSPACE=$HOME/workspace
 UPLOAD_DIR=$HOME/artifacts
 COMPRESS_EXT=xz
 export CC=$WORKSPACE/build/src/gcc/bin/gcc
 export CXX=$WORKSPACE/build/src/gcc/bin/g++
+export LDFLAGS=-lrt
 
 # Gn build scripts use #!/usr/bin/env python, which will be python 2.6 on
 # the worker and cause failures. Work around this by putting python2.7
 # ahead of it in PATH.
 mkdir -p $WORKSPACE/python_bin
 ln -s /usr/bin/python2.7 $WORKSPACE/python_bin/python
 export PATH=$WORKSPACE/python_bin:$PATH
 
--- a/taskcluster/scripts/misc/build-gn-macosx.sh
+++ b/taskcluster/scripts/misc/build-gn-macosx.sh
@@ -8,17 +8,17 @@ UPLOAD_DIR=$HOME/artifacts
 COMPRESS_EXT=xz
 
 CROSS_CCTOOLS_PATH=$WORKSPACE/build/src/cctools
 CROSS_SYSROOT=$WORKSPACE/build/src/MacOSX10.11.sdk
 
 export LD_LIBRARY_PATH=$WORKSPACE/build/src/clang/lib
 export CC=$WORKSPACE/build/src/clang/bin/clang
 export CXX=$WORKSPACE/build/src/clang/bin/clang++
-export AR=$WORKSPACE/build/src/clang/bin/clang
+export AR=$WORKSPACE/build/src/clang/bin/llvm-ar
 export CFLAGS="-target x86_64-darwin11 -mlinker-version=137 -B ${CROSS_CCTOOLS_PATH}/bin -isysroot ${CROSS_SYSROOT} -I${CROSS_SYSROOT}/usr/include -iframework ${CROSS_SYSROOT}/System/Library/Frameworks"
 export CXXFLAGS="-stdlib=libc++ ${CFLAGS}"
 export LDFLAGS="${CXXFLAGS} -Wl,-syslibroot,${CROSS_SYSROOT} -Wl,-dead_strip"
 
 # We patch tools/gn/bootstrap/bootstrap.py to detect this.
 export MAC_CROSS=1
 
 # Gn build scripts use #!/usr/bin/env python, which will be python 2.6 on
--- a/taskcluster/scripts/misc/build-gn-win32.sh
+++ b/taskcluster/scripts/misc/build-gn-win32.sh
@@ -2,22 +2,27 @@
 set -e -v
 
 # This script is for building GN on Windows.
 
 WORKSPACE=$PWD
 UPLOAD_DIR=$WORKSPACE/public/build
 COMPRESS_EXT=bz2
 
-VSPATH="$WORKSPACE/build/src/vs2017_15.4.2"
+VSPATH="$WORKSPACE/build/src/vs2017_15.8.4"
 
-export INCLUDE="${VSPATH}/VC/include:${VSPATH}/VC/atlmfc/include:${VSPATH}/SDK/Include/10.0.15063.0/ucrt:${VSPATH}/SDK/Include/10.0.15063.0/shared:${VSPATH}/SDK/Include/10.0.15063.0/um:${VSPATH}/SDK/Include/10.0.15063.0/winrt:${VSPATH}/DIA SDK/include"
-export LIB="${VSPATH}/VC/lib/x86:${VSPATH}/VC/atlmfc/lib/x86:${VSPATH}/SDK/lib/10.0.15063.0/ucrt/x86:${VSPATH}/SDK/lib/10.0.15063.0/um/x86:${VSPATH}/DIA SDK/lib"
+export INCLUDE="${VSPATH}/VC/include:${VSPATH}/VC/atlmfc/include:${VSPATH}/SDK/Include/10.0.17134.0/ucrt:${VSPATH}/SDK/Include/10.0.17134.0/shared:${VSPATH}/SDK/Include/10.0.17134.0/um:${VSPATH}/SDK/Include/10.0.17134.0/winrt:${VSPATH}/DIA SDK/include"
+export LIB="${VSPATH}/VC/lib/x86:${VSPATH}/VC/atlmfc/lib/x86:${VSPATH}/SDK/lib/10.0.17134.0/ucrt/x86:${VSPATH}/SDK/lib/10.0.17134.0/um/x86:${VSPATH}/DIA SDK/lib"
 
 export PATH="$WORKSPACE/build/src/ninja/bin:$PATH"
 export PATH="$WORKSPACE/build/src/mingw64/bin:$PATH"
-export PATH="${VSPATH}/VC/bin/Hostx64/x86:${VSPATH}/VC/bin/Hostx64/x64:${VSPATH}/VC/bin/Hostx86/x86:${VSPATH}/SDK/bin/10.0.15063.0/x64:${VSPATH}/DIA SDK/bin:${PATH}"
+export PATH="${VSPATH}/VC/bin/Hostx64/x86:${VSPATH}/VC/bin/Hostx64/x64:${VSPATH}/VC/bin/Hostx86/x86:${VSPATH}/SDK/bin/10.0.17134.0/x64:${VSPATH}/DIA SDK/bin:${PATH}"
 export PATH="${VSPATH}/VC/redist/x86/Microsoft.VC141.CRT:${VSPATH}/SDK/Redist/ucrt/DLLs/x86:${PATH}"
 
 cd $WORKSPACE/build/src
 
 . taskcluster/scripts/misc/tooltool-download.sh
 . taskcluster/scripts/misc/build-gn-common.sh
+
+# Building with MSVC spawns a mspdbsrv process that keeps a dll open in the MSVC directory.
+# This prevents the taskcluster worker from unmounting cleanly, and fails the build.
+# So we kill it.
+taskkill -f -im mspdbsrv.exe || true
--- a/taskcluster/scripts/misc/build-grcov.sh
+++ b/taskcluster/scripts/misc/build-grcov.sh
@@ -17,21 +17,21 @@ Linux)
     export CXX=clang++
     ;;
 MINGW*)
     WORKSPACE=$PWD
     UPLOAD_DIR=$WORKSPACE/public/build
     WIN_WORKSPACE="$(pwd -W)"
     COMPRESS_EXT=bz2
 
-    export INCLUDE="$WIN_WORKSPACE/build/src/vs2017_15.4.2/VC/include;$WIN_WORKSPACE/build/src/vs2017_15.4.2/VC/atlmfc/include;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/Include/10.0.15063.0/ucrt;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/Include/10.0.15063.0/shared;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/Include/10.0.15063.0/um;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/Include/10.0.15063.0/winrt;$WIN_WORKSPACE/build/src/vs2017_15.4.2/DIA SDK/include"
+    export INCLUDE="$WIN_WORKSPACE/build/src/vs2017_15.8.4/VC/include;$WIN_WORKSPACE/build/src/vs2017_15.8.4/VC/atlmfc/include;$WIN_WORKSPACE/build/src/vs2017_15.8.4/SDK/Include/10.0.17134.0/ucrt;$WIN_WORKSPACE/build/src/vs2017_15.8.4/SDK/Include/10.0.17134.0/shared;$WIN_WORKSPACE/build/src/vs2017_15.8.4/SDK/Include/10.0.17134.0/um;$WIN_WORKSPACE/build/src/vs2017_15.8.4/SDK/Include/10.0.17134.0/winrt;$WIN_WORKSPACE/build/src/vs2017_15.8.4/DIA SDK/include"
 
-    export LIB="$WIN_WORKSPACE/build/src/vs2017_15.4.2/VC/lib/x64;$WIN_WORKSPACE/build/src/vs2017_15.4.2/VC/atlmfc/lib/x64;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/lib/10.0.15063.0/um/x64;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/lib/10.0.15063.0/ucrt/x64;$WIN_WORKSPACE/build/src/vs2017_15.4.2/DIA SDK/lib/amd64"
+    export LIB="$WIN_WORKSPACE/build/src/vs2017_15.8.4/VC/lib/x64;$WIN_WORKSPACE/build/src/vs2017_15.8.4/VC/atlmfc/lib/x64;$WIN_WORKSPACE/build/src/vs2017_15.8.4/SDK/lib/10.0.17134.0/um/x64;$WIN_WORKSPACE/build/src/vs2017_15.8.4/SDK/lib/10.0.17134.0/ucrt/x64;$WIN_WORKSPACE/build/src/vs2017_15.8.4/DIA SDK/lib/amd64"
 
-    PATH="$WORKSPACE/build/src/vs2017_15.4.2/VC/bin/Hostx64/x64:$WORKSPACE/build/src/vs2017_15.4.2/VC/bin/Hostx86/x86:$WORKSPACE/build/src/vs2017_15.4.2/SDK/bin/10.0.15063.0/x64:$WORKSPACE/build/src/vs2017_15.4.2/redist/x64/Microsoft.VC141.CRT:$WORKSPACE/build/src/vs2017_15.4.2/SDK/Redist/ucrt/DLLs/x64:$WORKSPACE/build/src/vs2017_15.4.2/DIA SDK/bin/amd64:$WORKSPACE/build/src/mingw64/bin:$PATH"
+    PATH="$WORKSPACE/build/src/vs2017_15.8.4/VC/bin/Hostx64/x64:$WORKSPACE/build/src/vs2017_15.8.4/VC/bin/Hostx86/x86:$WORKSPACE/build/src/vs2017_15.8.4/SDK/bin/10.0.17134.0/x64:$WORKSPACE/build/src/vs2017_15.8.4/redist/x64/Microsoft.VC141.CRT:$WORKSPACE/build/src/vs2017_15.8.4/SDK/Redist/ucrt/DLLs/x64:$WORKSPACE/build/src/vs2017_15.8.4/DIA SDK/bin/amd64:$WORKSPACE/build/src/mingw64/bin:$PATH"
     ;;
 esac
 
 cd $WORKSPACE/build/src
 
 . taskcluster/scripts/misc/tooltool-download.sh
 
 # cargo gets mad if the parent directory has a Cargo.toml file in it
--- a/taskcluster/scripts/misc/build-rust-size.sh
+++ b/taskcluster/scripts/misc/build-rust-size.sh
@@ -13,21 +13,21 @@ Linux)
     COMPRESS_EXT=xz
     ;;
 MINGW*)
     WORKSPACE=$PWD
     UPLOAD_DIR=$WORKSPACE/public/build
     WIN_WORKSPACE="$(pwd -W)"
     COMPRESS_EXT=bz2
 
-    export INCLUDE="$WIN_WORKSPACE/build/src/vs2017_15.4.2/VC/include;$WIN_WORKSPACE/build/src/vs2017_15.4.2/VC/atlmfc/include;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/Include/10.0.15063.0/ucrt;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/Include/10.0.15063.0/shared;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/Include/10.0.15063.0/um;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/Include/10.0.15063.0/winrt;$WIN_WORKSPACE/build/src/vs2017_15.4.2/DIA SDK/include"
+    export INCLUDE="$WIN_WORKSPACE/build/src/vs2017_15.8.4/VC/include;$WIN_WORKSPACE/build/src/vs2017_15.8.4/VC/atlmfc/include;$WIN_WORKSPACE/build/src/vs2017_15.8.4/SDK/Include/10.0.17134.0/ucrt;$WIN_WORKSPACE/build/src/vs2017_15.8.4/SDK/Include/10.0.17134.0/shared;$WIN_WORKSPACE/build/src/vs2017_15.8.4/SDK/Include/10.0.17134.0/um;$WIN_WORKSPACE/build/src/vs2017_15.8.4/SDK/Include/10.0.17134.0/winrt;$WIN_WORKSPACE/build/src/vs2017_15.8.4/DIA SDK/include"
 
-    export LIB="$WIN_WORKSPACE/build/src/vs2017_15.4.2/VC/lib/x64;$WIN_WORKSPACE/build/src/vs2017_15.4.2/VC/atlmfc/lib/x64;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/lib/10.0.15063.0/um/x64;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/lib/10.0.15063.0/ucrt/x64;$WIN_WORKSPACE/build/src/vs2017_15.4.2/DIA SDK/lib/amd64"
+    export LIB="$WIN_WORKSPACE/build/src/vs2017_15.8.4/VC/lib/x64;$WIN_WORKSPACE/build/src/vs2017_15.8.4/VC/atlmfc/lib/x64;$WIN_WORKSPACE/build/src/vs2017_15.8.4/SDK/lib/10.0.17134.0/um/x64;$WIN_WORKSPACE/build/src/vs2017_15.8.4/SDK/lib/10.0.17134.0/ucrt/x64;$WIN_WORKSPACE/build/src/vs2017_15.8.4/DIA SDK/lib/amd64"
 
-    PATH="$WORKSPACE/build/src/vs2017_15.4.2/VC/bin/Hostx64/x64:$WORKSPACE/build/src/vs2017_15.4.2/VC/bin/Hostx86/x86:$WORKSPACE/build/src/vs2017_15.4.2/SDK/bin/10.0.15063.0/x64:$WORKSPACE/build/src/vs2017_15.4.2/redist/x64/Microsoft.VC141.CRT:$WORKSPACE/build/src/vs2017_15.4.2/SDK/Redist/ucrt/DLLs/x64:$WORKSPACE/build/src/vs2017_15.4.2/DIA SDK/bin/amd64:$WORKSPACE/build/src/mingw64/bin:$PATH"
+    PATH="$WORKSPACE/build/src/vs2017_15.8.4/VC/bin/Hostx64/x64:$WORKSPACE/build/src/vs2017_15.8.4/VC/bin/Hostx86/x86:$WORKSPACE/build/src/vs2017_15.8.4/SDK/bin/10.0.17134.0/x64:$WORKSPACE/build/src/vs2017_15.8.4/redist/x64/Microsoft.VC141.CRT:$WORKSPACE/build/src/vs2017_15.8.4/SDK/Redist/ucrt/DLLs/x64:$WORKSPACE/build/src/vs2017_15.8.4/DIA SDK/bin/amd64:$WORKSPACE/build/src/mingw64/bin:$PATH"
     ;;
 esac
 
 cd $WORKSPACE/build/src
 
 . taskcluster/scripts/misc/tooltool-download.sh
 
 # cargo gets mad if the parent directory has a Cargo.toml file in it
--- a/taskcluster/scripts/misc/build-sccache.sh
+++ b/taskcluster/scripts/misc/build-sccache.sh
@@ -14,21 +14,21 @@ Linux)
     PATH="$WORKSPACE/build/src/binutils/bin:$PATH"
     ;;
 MINGW*)
     WORKSPACE=$PWD
     UPLOAD_DIR=$WORKSPACE/public/build
     WIN_WORKSPACE="$(pwd -W)"
     COMPRESS_EXT=bz2
 
-    export INCLUDE="$WIN_WORKSPACE/build/src/vs2017_15.4.2/VC/include;$WIN_WORKSPACE/build/src/vs2017_15.4.2/VC/atlmfc/include;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/Include/10.0.15063.0/ucrt;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/Include/10.0.15063.0/shared;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/Include/10.0.15063.0/um;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/Include/10.0.15063.0/winrt;$WIN_WORKSPACE/build/src/vs2017_15.4.2/DIA SDK/include"
+    export INCLUDE="$WIN_WORKSPACE/build/src/vs2017_15.8.4/VC/include;$WIN_WORKSPACE/build/src/vs2017_15.8.4/VC/atlmfc/include;$WIN_WORKSPACE/build/src/vs2017_15.8.4/SDK/Include/10.0.17134.0/ucrt;$WIN_WORKSPACE/build/src/vs2017_15.8.4/SDK/Include/10.0.17134.0/shared;$WIN_WORKSPACE/build/src/vs2017_15.8.4/SDK/Include/10.0.17134.0/um;$WIN_WORKSPACE/build/src/vs2017_15.8.4/SDK/Include/10.0.17134.0/winrt;$WIN_WORKSPACE/build/src/vs2017_15.8.4/DIA SDK/include"
 
-    export LIB="$WIN_WORKSPACE/build/src/vs2017_15.4.2/VC/lib/x64;$WIN_WORKSPACE/build/src/vs2017_15.4.2/VC/atlmfc/lib/x64;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/lib/10.0.15063.0/um/x64;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/lib/10.0.15063.0/ucrt/x64;$WIN_WORKSPACE/build/src/vs2017_15.4.2/DIA SDK/lib/amd64"
+    export LIB="$WIN_WORKSPACE/build/src/vs2017_15.8.4/VC/lib/x64;$WIN_WORKSPACE/build/src/vs2017_15.8.4/VC/atlmfc/lib/x64;$WIN_WORKSPACE/build/src/vs2017_15.8.4/SDK/lib/10.0.17134.0/um/x64;$WIN_WORKSPACE/build/src/vs2017_15.8.4/SDK/lib/10.0.17134.0/ucrt/x64;$WIN_WORKSPACE/build/src/vs2017_15.8.4/DIA SDK/lib/amd64"
 
-    PATH="$WORKSPACE/build/src/vs2017_15.4.2/VC/bin/Hostx64/x64:$WORKSPACE/build/src/vs2017_15.4.2/VC/bin/Hostx86/x86:$WORKSPACE/build/src/vs2017_15.4.2/SDK/bin/10.0.15063.0/x64:$WORKSPACE/build/src/vs2017_15.4.2/redist/x64/Microsoft.VC141.CRT:$WORKSPACE/build/src/vs2017_15.4.2/SDK/Redist/ucrt/DLLs/x64:$WORKSPACE/build/src/vs2017_15.4.2/DIA SDK/bin/amd64:$WORKSPACE/build/src/mingw64/bin:$PATH"
+    PATH="$WORKSPACE/build/src/vs2017_15.8.4/VC/bin/Hostx64/x64:$WORKSPACE/build/src/vs2017_15.8.4/VC/bin/Hostx86/x86:$WORKSPACE/build/src/vs2017_15.8.4/SDK/bin/10.0.17134.0/x64:$WORKSPACE/build/src/vs2017_15.8.4/redist/x64/Microsoft.VC141.CRT:$WORKSPACE/build/src/vs2017_15.8.4/SDK/Redist/ucrt/DLLs/x64:$WORKSPACE/build/src/vs2017_15.8.4/DIA SDK/bin/amd64:$WORKSPACE/build/src/mingw64/bin:$PATH"
     ;;
 esac
 
 cd $WORKSPACE/build/src
 
 . taskcluster/scripts/misc/tooltool-download.sh
 
 PATH="$PWD/rustc/bin:$PATH"
deleted file mode 100644
--- a/taskcluster/scripts/misc/gn.patch
+++ /dev/null
@@ -1,78 +0,0 @@
-diff --git a/bootstrap/bootstrap.py b/bootstrap/bootstrap.py
-index ff2ae57..7e12436 100755
---- a/bootstrap/bootstrap.py
-+++ b/bootstrap/bootstrap.py
-@@ -29,9 +29,10 @@ BOOTSTRAP_DIR = os.path.dirname(os.path.abspath(__file__))
- GN_ROOT = os.path.dirname(BOOTSTRAP_DIR)
- SRC_ROOT = os.path.dirname(os.path.dirname(GN_ROOT))
- 
-+is_mac_cross = os.environ.get('MAC_CROSS', False)
- is_win = sys.platform.startswith('win')
--is_linux = sys.platform.startswith('linux')
--is_mac = sys.platform.startswith('darwin')
-+is_linux = sys.platform.startswith('linux') and not is_mac_cross
-+is_mac = sys.platform.startswith('darwin') or is_mac_cross
- is_aix = sys.platform.startswith('aix')
- is_posix = is_linux or is_mac or is_aix
- 
-@@ -595,7 +596,6 @@ def write_gn_ninja(path, root_gen_dir, options):
-         'base/synchronization/condition_variable_posix.cc',
-         'base/synchronization/lock_impl_posix.cc',
-         'base/synchronization/read_write_lock_posix.cc',
--        'base/synchronization/waitable_event_posix.cc',
-         'base/sys_info_posix.cc',
-         'base/task_scheduler/task_tracker_posix.cc',
-         'base/threading/platform_thread_internal_posix.cc',
-@@ -603,10 +603,19 @@ def write_gn_ninja(path, root_gen_dir, options):
-         'base/threading/thread_local_storage_posix.cc',
-         'base/threading/worker_pool_posix.cc',
-         'base/time/time_conversion_posix.cc',
-+    ])
-+
-+    if not is_mac:
-+      static_libraries['base']['sources'].extend([
-+        'base/synchronization/waitable_event_posix.cc',
-         'base/time/time_exploded_posix.cc',
-         'base/time/time_now_posix.cc',
--        'base/trace_event/heap_profiler_allocation_register_posix.cc',
-+      ])
-+
-+    static_libraries['base']['sources'].extend([
-+      'base/trace_event/heap_profiler_allocation_register_posix.cc',
-     ])
-+
-     static_libraries['libevent'] = {
-         'sources': [
-             'base/third_party/libevent/buffer.c',
-@@ -685,6 +694,7 @@ def write_gn_ninja(path, root_gen_dir, options):
-         'base/mac/call_with_eh_frame.cc',
-         'base/mac/call_with_eh_frame_asm.S',
-         'base/mac/foundation_util.mm',
-+        'base/mac/mac_util.mm',
-         'base/mac/mach_logging.cc',
-         'base/mac/scoped_mach_port.cc',
-         'base/mac/scoped_mach_vm.cc',
-@@ -697,6 +707,7 @@ def write_gn_ninja(path, root_gen_dir, options):
-         'base/process/process_iterator_mac.cc',
-         'base/process/process_metrics_mac.cc',
-         'base/strings/sys_string_conversions_mac.mm',
-+        'base/synchronization/waitable_event_mac.cc',
-         'base/sys_info_mac.mm',
-         'base/time/time_mac.cc',
-         'base/threading/platform_thread_mac.mm',
-@@ -735,6 +746,7 @@ def write_gn_ninja(path, root_gen_dir, options):
-         'base/memory/memory_pressure_monitor_win.cc',
-         'base/memory/shared_memory_handle_win.cc',
-         'base/memory/shared_memory_win.cc',
-+        'base/memory/shared_memory_tracker.cc',
-         'base/message_loop/message_pump_win.cc',
-         'base/native_library_win.cc',
-         'base/power_monitor/power_monitor_device_source_win.cc',
-@@ -799,6 +811,7 @@ def write_gn_ninja(path, root_gen_dir, options):
-         'version.lib',
-         'winmm.lib',
-         'ws2_32.lib',
-+        'shlwapi.lib',
-     ])
- 
-   # we just build static libraries that GN needs
--- a/taskcluster/taskgraph/transforms/job/debian_package.py
+++ b/taskcluster/taskgraph/transforms/job/debian_package.py
@@ -4,17 +4,16 @@
 """
 Support for running spidermonkey jobs via dedicated scripts
 """
 
 from __future__ import absolute_import, print_function, unicode_literals
 
 import os
 import re
-import taskcluster_urls
 
 from taskgraph.util.schema import Schema
 from voluptuous import Any, Optional, Required
 
 from taskgraph.transforms.job import run_job_using
 from taskgraph.transforms.job.common import add_artifacts
 
 from taskgraph.util.hash import hash_path
@@ -68,27 +67,31 @@ run_schema = Schema({
 
 
 @run_job_using("docker-worker", "debian-package", schema=run_schema)
 def docker_worker_debian_package(config, job, taskdesc):
     run = job['run']
 
     name = taskdesc['label'].replace('{}-'.format(config.kind), '', 1)
 
-    docker_repo = 'debian'
     arch = run.get('arch', 'amd64')
-    if arch != 'amd64':
-        docker_repo = '{}/{}'.format(arch, docker_repo)
 
     worker = taskdesc['worker']
     worker['artifacts'] = []
-    worker['docker-image'] = '{repo}:{dist}-{date}'.format(
-        repo=docker_repo,
-        dist=run['dist'],
-        date=run['snapshot'][:8])
+    version = {
+        'wheezy': 7,
+        'jessie': 8,
+        'stretch': 9,
+        'buster': 10,
+    }[run['dist']]
+    image = 'debian%d' % version
+    if arch != 'amd64':
+        image += '-' + arch
+    image += '-packages'
+    worker['docker-image'] = {'in-tree': image}
     # Retry on apt-get errors.
     worker['retry-exit-status'] = [100]
 
     add_artifacts(config, job, taskdesc, path='/tmp/artifacts')
 
     env = worker.setdefault('env', {})
     env['DEBFULLNAME'] = 'Mozilla build team'
     env['DEBEMAIL'] = 'dev-builds@lists.mozilla.org'
@@ -105,39 +108,30 @@ def docker_worker_debian_package(config,
     else:
         raise RuntimeError('Unreachable')
     src_url = src['url']
     src_file = os.path.basename(src_url)
     src_sha256 = src['sha256']
     package = package_re.match(src_file).group(0)
     unpack = unpack.format(src_file=src_file, package=package)
 
-    base_deps = [
-        'apt-utils',
-        'build-essential',
-        'devscripts',
-        'fakeroot',
-    ]
-
     resolver = run.get('resolver', 'apt-get')
     if resolver == 'apt-get':
         resolver = 'apt-get -yyq --no-install-recommends'
     elif resolver == 'aptitude':
         resolver = ('aptitude -y --without-recommends -o '
                     'Aptitude::ProblemResolver::Hints::KeepBuildDeps='
                     '"reject {}-build-deps :UNINST"').format(package)
-        base_deps.append('aptitude')
     else:
         raise RuntimeError('Unreachable')
 
     adjust = ''
     if 'patch' in run:
-        # We can't depend on docker images, so we don't have robustcheckout or
-        # or run-task to get a checkout. So for this one file we'd need
-        # from a checkout, download it.
+        # We don't use robustcheckout or run-task to get a checkout. So for
+        # this one file we'd need from a checkout, download it.
         env['PATCH_URL'] = '{head_repo}/raw-file/{head_rev}/build/debian-packages/{patch}'.format(
             head_repo=config.params['head_repository'],
             head_rev=config.params['head_rev'],
             patch=run['patch'],
         )
         adjust += 'curl -sL $PATCH_URL | patch -p1 && '
     if 'pre-build-command' in run:
         adjust += run['pre-build-command'] + ' && '
@@ -149,43 +143,25 @@ def docker_worker_debian_package(config,
         )
     if 'patch' not in run and 'pre-build-command' not in run:
         adjust += ('debchange -l ".{prefix}moz" --distribution "{dist}"'
                    ' "Mozilla backport for {dist}." < /dev/null && ').format(
             prefix=name.split('-', 1)[0],
             dist=run['dist'],
         )
 
-    queue_url = taskcluster_urls.api(get_root_url(), 'queue', 'v1', '')
-
-    # We can't depend on docker images (since docker images depend on packages),
-    # so we inline the whole script here.
     worker['command'] = [
         'sh',
         '-x',
         '-c',
-        # Fill /etc/apt/sources.list with the relevant snapshot repository.
-        'echo "deb http://snapshot.debian.org/archive/debian'
-        '/{snapshot}/ {dist} main" > /etc/apt/sources.list && '
-        'echo "deb http://snapshot.debian.org/archive/debian'
-        '/{snapshot}/ {dist}-updates main" >> /etc/apt/sources.list && '
-        'echo "deb http://snapshot.debian.org/archive/debian'
-        '/{snapshot}/ {dist}-backports main" >> /etc/apt/sources.list && '
-        'echo "deb http://snapshot.debian.org/archive/debian-security'
-        '/{snapshot}/ {dist}/updates main" >> /etc/apt/sources.list && '
-        'apt-get update -o Acquire::Check-Valid-Until=false -q && '
         # Add sources for packages coming from other package tasks.
-        'apt-get install -yyq apt-transport-https ca-certificates && '
-        'for task in $PACKAGES; do '
-        '  echo "deb [trusted=yes] {queue_url}task/$task/artifacts/public/build/ debian/" '
-        '>> /etc/apt/sources.list; '
-        'done && '
-        # Install the base utilities required to build debian packages.
-        'apt-get update -o Acquire::Check-Valid-Until=false -q && '
-        'apt-get install -yyq {base_deps} && '
+        '/usr/local/sbin/setup_packages.sh {queue_url} $PACKAGES && '
+        'apt-get update && '
+        # Upgrade packages that might have new versions in package tasks.
+        'apt-get dist-upgrade && '
         'cd /tmp && '
         # Get, validate and extract the package source.
         'dget -d -u {src_url} && '
         'echo "{src_sha256}  {src_file}" | sha256sum -c && '
         '{unpack} && '
         'cd {package} && '
         # Optionally apply patch and/or pre-build command.
         '{adjust}'
@@ -196,27 +172,26 @@ def docker_worker_debian_package(config,
         # Copy the artifacts
         'mkdir -p {artifacts}/debian && '
         'dcmd cp ../{package}_*.changes {artifacts}/debian/ && '
         'cd {artifacts} && '
         # Make the artifacts directory usable as an APT repository.
         'apt-ftparchive sources debian | gzip -c9 > debian/Sources.gz && '
         'apt-ftparchive packages debian | gzip -c9 > debian/Packages.gz'
         .format(
-            queue_url=queue_url,
+            queue_url=get_root_url(),
             package=package,
             snapshot=run['snapshot'],
             dist=run['dist'],
             src_url=src_url,
             src_file=src_file,
             src_sha256=src_sha256,
             unpack=unpack,
             adjust=adjust,
             artifacts='/tmp/artifacts',
-            base_deps=' '.join(base_deps),
             resolver=resolver,
         )
     ]
 
     if run.get('packages'):
         env = worker.setdefault('env', {})
         env['PACKAGES'] = {
             'task-reference': ' '.join('<{}>'.format(p)
@@ -228,17 +203,14 @@ def docker_worker_debian_package(config,
 
     # Use the command generated above as the base for the index hash.
     # We rely on it not varying depending on the head_repository or head_rev.
     digest_data = list(worker['command'])
     if 'patch' in run:
         digest_data.append(
             hash_path(os.path.join(GECKO, 'build', 'debian-packages', run['patch'])))
 
-    if docker_repo != 'debian':
-        digest_data.append(docker_repo)
-
     if not taskgraph.fast:
         taskdesc['cache'] = {
             'type': 'packages.v1',
             'name': name,
             'digest-data': digest_data
         }
--- a/testing/profiles/reftest/user.js
+++ b/testing/profiles/reftest/user.js
@@ -94,12 +94,13 @@ user_pref("startup.homepage_welcome_url.
 user_pref("testing.supports.moz-bool-pref", false);
 // Ensure that telemetry is disabled, so we don't connect to the telemetry
 // server in the middle of the tests.
 user_pref("toolkit.telemetry.enabled", false);
 user_pref("toolkit.telemetry.server", "https://%(server)s/telemetry-dummy/");
 user_pref("ui.caretBlinkTime", -1);
 user_pref("ui.caretWidth", 1);
 user_pref("ui.prefersReducedMotion", 0);
+user_pref("ui.systemUsesDarkTheme", 0);
 // Turn off the Push service.
 user_pref("dom.push.serverURL", "");
 // Disable intermittent telemetry collection
 user_pref("toolkit.telemetry.initDelay", 99999999);
deleted file mode 100644
--- a/testing/web-platform/meta/css/css-scroll-anchoring/ancestor-change-heuristic.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[ancestor-change-heuristic.html]
-  [Ancestor changes in document scroller.]
-    expected:
-      if not debug and (os == "android") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): PASS
-      FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/css/css-scroll-anchoring/anchoring-with-bounds-clamping.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[anchoring-with-bounds-clamping.html]
-  [Anchoring combined with scroll bounds clamping in the document.]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/css/css-scroll-anchoring/basic.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[basic.html]
-  [Minimal scroll anchoring example.]
-    expected:
-      if (os == "win"): "FAIL"
-      if (os == "mac"): "FAIL"
-      if (os == "linux"): "FAIL"
-
deleted file mode 100644
--- a/testing/web-platform/meta/css/css-scroll-anchoring/descend-into-container-with-float.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[descend-into-container-with-float.html]
-  [Zero-height container with float.]
-    expected:
-      if not debug and (os == "android") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): PASS
-      FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/css/css-scroll-anchoring/descend-into-container-with-overflow.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[descend-into-container-with-overflow.html]
-  [Zero-height container with visible overflow.]
-    expected:
-      if not debug and (os == "android") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): PASS
-      FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/css/css-scroll-anchoring/exclude-fixed-position.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[exclude-fixed-position.html]
-  [Fixed-position header.]
-    expected:
-      if not debug and (os == "android") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): PASS
-      FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/css/css-scroll-anchoring/inline-block.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[inline-block.html]
-  [Anchor selection descent into inline blocks.]
-    expected:
-      if (os == "linux"): "FAIL"
-      if (os == "mac"): "FAIL"
-      if (os == "win"): "FAIL"
-
deleted file mode 100644
--- a/testing/web-platform/meta/css/css-scroll-anchoring/position-change-heuristic.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[position-change-heuristic.html]
-  [Position changes in document scroller.]
-    expected:
-      if not debug and (os == "android") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): PASS
-      FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/css/css-scroll-anchoring/start-edge-in-block-layout-direction.html.ini
+++ /dev/null
@@ -1,19 +0,0 @@
-[start-edge-in-block-layout-direction.html]
-  [Vertical-RL LTR.]
-    expected: FAIL
-
-  [Horizontal RTL.]
-    expected: FAIL
-
-  [Vertical-LR LTR.]
-    expected: FAIL
-
-  [Horizontal LTR.]
-    expected: FAIL
-
-  [Vertical-RL RTL.]
-    expected: FAIL
-
-  [Vertical-LR RTL.]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/css/css-scroll-anchoring/subtree-exclusion.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[subtree-exclusion.html]
-  [Subtree exclusion with overflow-anchor.]
-    expected:
-      if (os == "win"): "FAIL"
-      if (os == "mac"): "FAIL"
-      if (os == "linux"): "FAIL"
-
deleted file mode 100644
--- a/testing/web-platform/meta/css/css-scroll-anchoring/wrapped-text.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[wrapped-text.html]
-  [Anchoring with text wrapping changes.]
-    expected:
-      if (os == "win"): "FAIL"
-      if (os == "mac"): "FAIL"
-      if (os == "linux"): "FAIL"
-
deleted file mode 100644
--- a/testing/web-platform/meta/css/mediaqueries/prefers-color-scheme.html.ini
+++ /dev/null
@@ -1,40 +0,0 @@
-[prefers-color-scheme.html]
-  [Should be parseable: '(prefers-color-scheme)']
-    expected: FAIL
-
-  [Check that no-preference evaluates to false in the boolean context]
-    expected: FAIL
-
-  [Should be parseable: '(prefers-color-scheme: dark)']
-    expected: FAIL
-
-  [Should be parseable: '(prefers-color-scheme: light)']
-    expected: FAIL
-
-  [Should be parseable: '(prefers-color-scheme: no-preference)']
-    expected: FAIL
-
-  [Should be parseable in JS: '(prefers-color-scheme: dark)']
-    expected: FAIL
-
-  [Should be parseable in a CSS stylesheet: '(prefers-color-scheme: light)']
-    expected: FAIL
-
-  [Should be parseable in a CSS stylesheet: '(prefers-color-scheme)']
-    expected: FAIL
-
-  [Should be parseable in JS: '(prefers-color-scheme: no-preference)']
-    expected: FAIL
-
-  [Should be parseable in a CSS stylesheet: '(prefers-color-scheme: dark)']
-    expected: FAIL
-
-  [Should be parseable in JS: '(prefers-color-scheme)']
-    expected: FAIL
-
-  [Should be parseable in a CSS stylesheet: '(prefers-color-scheme: no-preference)']
-    expected: FAIL
-
-  [Should be parseable in JS: '(prefers-color-scheme: light)']
-    expected: FAIL
-
--- a/testing/web-platform/tests/css/css-scroll-anchoring/ancestor-change-heuristic.html
+++ b/testing/web-platform/tests/css/css-scroll-anchoring/ancestor-change-heuristic.html
@@ -1,14 +1,14 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <style>
 
-#space { height: 1000px; }
+#space { height: 4000px; }
 #ancestor { position: relative; }
 #before, #anchor { height: 100px; }
 #anchor { background-color: green; }
 
 .layout1 { padding-top: 20px; }
 .layout2 { margin-right: 20px; }
 .layout3 { max-width: 100px; }
 .layout4 { min-height: 400px; }
--- a/testing/web-platform/tests/css/css-scroll-anchoring/anchoring-with-bounds-clamping.html
+++ b/testing/web-platform/tests/css/css-scroll-anchoring/anchoring-with-bounds-clamping.html
@@ -1,17 +1,17 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <style>
 
 #changer { height: 1500px; }
 #anchor {
   width: 150px;
-  height: 1000px;
+  height: 4000px;
   background-color: pink;
 }
 
 </style>
 <div id="changer"></div>
 <div id="anchor"></div>
 <script>
 
--- a/testing/web-platform/tests/css/css-scroll-anchoring/basic.html
+++ b/testing/web-platform/tests/css/css-scroll-anchoring/basic.html
@@ -1,14 +1,14 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <style>
 
-body { height: 1000px; }
+body { height: 4000px; }
 div { height: 100px; }
 
 </style>
 <div id="block1">abc</div>
 <div id="block2">def</div>
 <script>
 
 // Tests that growing an element above the viewport produces a scroll
--- a/testing/web-platform/tests/css/css-scroll-anchoring/descend-into-container-with-float.html
+++ b/testing/web-platform/tests/css/css-scroll-anchoring/descend-into-container-with-float.html
@@ -1,14 +1,14 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <style>
 
-body { height: 1000px; }
+body { height: 4000px; }
 #outer { width: 300px; }
 #outer:after { content: " "; clear:both; display: table; }
 #float {
   float: left; background-color: #ccc;
   height: 500px; width: 100%;
 }
 #inner { height: 100px; background-color: green; }
 
--- a/testing/web-platform/tests/css/css-scroll-anchoring/descend-into-container-with-overflow.html
+++ b/testing/web-platform/tests/css/css-scroll-anchoring/descend-into-container-with-overflow.html
@@ -1,14 +1,14 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <style>
 
-body { height: 1000px; }
+body { height: 4000px; }
 #outer { width: 300px; }
 #zeroheight { height: 0px; }
 #changer { height: 100px; background-color: red; }
 #bottom { margin-top: 600px; }
 
 </style>
 <div id="outer">
   <div id="zeroheight">
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-scroll-anchoring/device-pixel-adjustment.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-scroll-anchoring-1/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+
+body {
+    height: 200vh;
+}
+#anchor {
+    width: 100px;
+    height: 100px;
+    background-color: blue;
+}
+
+</style>
+<div id="expander"></div>
+<div id="anchor"></div>
+<script>
+
+// This tests that scroll anchor adjustments can happen by quantities smaller
+// than a device pixel.
+//
+// Unfortunately, we can't test this by simply reading 'scrollTop', because
+// 'scrollTop' may be rounded to the nearest CSS pixel. So, to test that
+// subpixel adjustments can in fact happen, we repeatedly trigger a scroll
+// adjustment in a way that would produce a different final .scrollTop value,
+// depending on whether or not we rounded each adjustment as we apply it.
+
+test(() => {
+    let scroller = document.scrollingElement;
+    let expander = document.querySelector("#expander");
+    let anchor = document.querySelector("#anchor");
+    const initialTop = 10;
+
+    // Scroll 10px to activate scroll anchoring
+    scroller.scrollTop = initialTop;
+
+    // Helper to insert a div with specified height before the anchor node
+    function addChild(height) {
+        let child = document.createElement("div");
+        child.style.height = `${height}px`;
+        anchor.before(child);
+    }
+
+    // Calculate what fraction of a CSS pixel corresponds to one device pixel
+    let devicePixel = 1.0 / window.devicePixelRatio;
+    assert_true(devicePixel <= 1.0, "there should be more device pixels than CSS pixels");
+
+    // The 0.5 is an arbitrary scale when creating the subpixel delta
+    let delta = 0.5 * devicePixel;
+
+    // To help us check for for premature rounding of adjustments, we'll
+    // trigger "count" subpixel adjustments of size "delta", where "count" is
+    // the first positive integer such that:
+    //   round(count * delta) != count * round(delta)
+    // As round(X) and count are integers, this happens when:
+    //   count * delta = count * round(delta) +/- 1
+    // Solving for count:
+    //   count = 1 / abs(delta - round(delta))
+    // Note that we don't need to worry about the denominator being zero, as:
+    //   0 < devicePixel <= 1
+    // And so halving devicePixel should never yield a whole number.
+    let count = 1 / Math.abs(delta - Math.round(delta));
+
+    for (let i = 0; i < count; i++) {
+        addChild(delta);
+        // Trigger an anchor adjustment by forcing a layout flush
+        scroller.scrollTop;
+    }
+
+    let destination = Math.round(initialTop + delta * count);
+    assert_equals(scroller.scrollTop, destination,
+        `adjusting by ${delta}px, ${count} times, should be the same as adjusting by ${delta * count}px, once.`);
+}, "Test that scroll anchor adjustments can happen by a sub device-pixel amount.");
+
+</script>
--- a/testing/web-platform/tests/css/css-scroll-anchoring/exclude-fixed-position.html
+++ b/testing/web-platform/tests/css/css-scroll-anchoring/exclude-fixed-position.html
@@ -1,14 +1,14 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <style>
 
-body { height: 1000px; margin: 0; }
+body { height: 4000px; margin: 0; }
 #fixed, #content { width: 200px; height: 100px; }
 #fixed { position: fixed; left: 100px; top: 50px; }
 #before { height: 50px; }
 #content { margin-top: 100px; }
 
 </style>
 <div id="fixed">fixed</div>
 <div id="before"></div>
--- a/testing/web-platform/tests/css/css-scroll-anchoring/inline-block.html
+++ b/testing/web-platform/tests/css/css-scroll-anchoring/inline-block.html
@@ -1,14 +1,14 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <style>
 
-body { height: 1000px }
+body { height: 4000px }
 #outer { line-height: 100px }
 #ib1, #ib2 { display: inline-block }
 
 </style>
 <span id=outer>
   <span id=ib1>abc</span>
   <br><br>
   <span id=ib2>def</span>
--- a/testing/web-platform/tests/css/css-scroll-anchoring/position-change-heuristic.html
+++ b/testing/web-platform/tests/css/css-scroll-anchoring/position-change-heuristic.html
@@ -1,15 +1,15 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <style>
 
 #space {
-  height: 1000px;
+  height: 4000px;
 }
 #header {
   background-color: #F5B335;
   height: 50px;
   width: 100%;
 }
 #content {
   background-color: #D3D3D3;
--- a/testing/web-platform/tests/css/css-scroll-anchoring/start-edge-in-block-layout-direction.html
+++ b/testing/web-platform/tests/css/css-scroll-anchoring/start-edge-in-block-layout-direction.html
@@ -27,35 +27,39 @@ html.vrl { writing-mode: vertical-rl; }
   width: 100px;
   height: 100px;
 }
 #block_pusher { background-color: #e88; }
 #inline_pusher { background-color: #88e; }
 .vpush { height: 80px !important; }
 .hpush { width: 70px !important; }
 
+#anchor-container {
+  display: inline-block;
+}
 #anchor {
   position: relative;
-  display: inline-block;
   background-color: #8e8;
   min-width: 100px;
   min-height: 100px;
 }
 
 #grower { width: 0; height: 0; }
 .grow {
   width: 180px !important;
   height: 160px !important;
 }
 
 </style>
 <div id="container">
   <div id="block_pusher"></div><br>
-  <div id="inline_pusher"></div><div id="anchor">
-    <div id="grower"></div>
+  <div id="inline_pusher"></div><div id="anchor-container">
+    <div id="anchor">
+      <div id="grower"></div>
+    </div>
   </div>
 </div>
 <script>
 
 // Tests that anchoring adjustments are only on the block layout axis and that
 // their magnitude is based on the movement of the block start edge of the
 // anchor node, for all 6 combinations of text direction and writing mode,
 // regardless of which corner of the viewport the anchor node overlaps.
--- a/testing/web-platform/tests/css/css-scroll-anchoring/subtree-exclusion.html
+++ b/testing/web-platform/tests/css/css-scroll-anchoring/subtree-exclusion.html
@@ -1,14 +1,14 @@
 <!DOCTYPE html>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <style>
 
-body { height: 1000px }
+body { height: 4000px }
 #A, #B { width: 100px; background-color: #afa; }
 #B { height: 100px; }
 #inner { width: 100px; height: 100px; background-color: pink; }
 #A { overflow-anchor: none; }
 
 </style>
 <div id="changer1"></div>
 <div id="A">
--- a/testing/web-platform/tests/css/css-scroll-anchoring/wrapped-text.html
+++ b/testing/web-platform/tests/css/css-scroll-anchoring/wrapped-text.html
@@ -2,17 +2,17 @@
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <style>
 
 body {
   position: absolute;
   font-size: 100px;
   width: 200px;
-  height: 1000px;
+  height: 4000px;
   line-height: 100px;
 }
 
 </style>
 abc <b id=b>def</b> ghi
 <script>
 
 // Tests anchoring to a text node that is moved by preceding text.
--- a/toolkit/content/tests/chrome/test_bug624329.xul
+++ b/toolkit/content/tests/chrome/test_bug624329.xul
@@ -72,39 +72,38 @@ function childResized() {
     openContextMenu();
 }
 
 function openContextMenu() {
     var mouseX = win.innerWidth - 10;
     var mouseY = 10;
 
     menu = win.document.getElementById("menu");
-    var screenX = menu.boxObject.screenX;
-    var screenY = menu.boxObject.screenY;
+    var screenX = menu.screenX;
+    var screenY = menu.screenY;
     var utils = win.windowUtils;
 
     utils.sendMouseEvent("contextmenu", mouseX, mouseY, 2, 0, 0);
 
     var interval = setInterval(checkMoved, 200);
     function checkMoved() {
-        if (menu.boxObject.screenX != screenX ||
-            menu.boxObject.screenY != screenY) {
+        if (menu.screenX != screenX ||
+            menu.screenY != screenY) {
             clearInterval(interval);
             // Wait further to check that the window does not move again.
             setTimeout(checkPosition, 1000);
         }
     }
 
     function checkPosition() {
-        var menubox = menu.boxObject;
-        var winbox = win.document.documentElement.boxObject;
+        var rootElement = win.document.documentElement;
         var platformIsMac = navigator.userAgent.indexOf("Mac") > -1;
 
-        var x = menubox.screenX - winbox.screenX;
-        var y = menubox.screenY - winbox.screenY;
+        var x = menu.screenX - rootElement.screenX;
+        var y = menu.screenY - rootElement.screenY;
 
         if (platformIsMac)
         {
           // This check is alterered slightly for OSX which adds padding to the top
           // and bottom of its context menus. The menu position calculation must
           // be changed to allow for the pointer to be outside this padding
           // when the menu opens.
           // (Bug 1075089)
@@ -117,17 +116,17 @@ function openContextMenu() {
              "menu top " + y + " should be below click point " + mouseY);
         }
         
         ok(y <= mouseY + 20,
            "menu top " + y + " should not be too far below click point " + mouseY);
 
         ok(x < mouseX,
            "menu left " + x + " should be left of click point " + mouseX);
-        var right = x + menubox.width;
+        var right = x + menu.boxObject.width;
 
         if (platformIsMac) {
           // Rather than be constrained by the right hand screen edge, OSX menus flip
           // horizontally and appear to the left of the mouse pointer
           ok(right < mouseX,
              "menu right " + right + " should be left of click point " + mouseX);
         }
         else {
--- a/toolkit/content/tests/chrome/test_popup_moveToAnchor.xul
+++ b/toolkit/content/tests/chrome/test_popup_moveToAnchor.xul
@@ -47,17 +47,17 @@ function popupshown()
   checkCoords(popup, button2rect.left, button2rect.top - popupheight, "move button2");
 
   popup.moveToAnchor($("button1"), "end_before");
   checkCoords(popup, button1rect.right, button1rect.top, "move anchor end_before");
 
   popup.moveToAnchor($("button2"), "after_start", 5, 4);
   checkCoords(popup, button2rect.left + 5, button2rect.bottom + 4, "move button2 left + 5, top + 4");
 
-  popup.moveTo($("button1").boxObject.screenX + 10, $("button1").boxObject.screenY + 12);
+  popup.moveTo($("button1").screenX + 10, $("button1").screenY + 12);
   checkCoords(popup, button1rect.left + 10, button1rect.top + 12, "move to button1 screen with offset");
 
   popup.moveToAnchor($("button1"), "after_start", 1, 2);
   checkCoords(popup, button1rect.left + 1, button1rect.bottom + 2, "move button2 after screen");
 
   popup.hidePopup();
 }
 
--- a/toolkit/content/tests/chrome/test_popup_scaled.xul
+++ b/toolkit/content/tests/chrome/test_popup_scaled.xul
@@ -41,48 +41,48 @@ function runTests()
 function setScale(win, scale)
 {
   var docViewer = win.docShell.contentViewer;
   docViewer.fullZoom = scale;
 }
 
 function shown()
 {
+  var popup = $("popup");
   if (screenTest) {
-    var box = $("popup").boxObject;
-    is(box.screenX, screenx, "screen left position");
-    is(box.screenY, screeny, "screen top position");
+    is(popup.screenX, screenx, "screen left position");
+    is(popup.screenY, screeny, "screen top position");
   }
   else {
     var anchor = $("frame").contentDocument.getElementById("two");
 
     is(Math.round(anchor.getBoundingClientRect().left * 2),
-       Math.round($("popup").getBoundingClientRect().left), "anchored left position");
+       Math.round(popup.getBoundingClientRect().left), "anchored left position");
     is(Math.round(anchor.getBoundingClientRect().bottom * 2),
-       Math.round($("popup").getBoundingClientRect().top), "anchored top position");
+       Math.round(popup.getBoundingClientRect().top), "anchored top position");
   }
 
-  $("popup").hidePopup();
+  popup.hidePopup();
 }
 
 function nextTest()
 {
   if (screenTest) {
     setScale(window, 1);
     SimpleTest.finish();
   }
   else {
     screenTest = true;
-    var box = document.documentElement.boxObject;
+    var rootElement = document.documentElement;
 
     // - the iframe is at 4×, but out here css pixels are only 2× device pixels
     // - the popup manager rounds off (or truncates) the coordinates to
     //   integers, so ensure we pass in even numbers to openPopupAtScreen
-    screenx = (x = even(box.screenX + 120))/2;
-    screeny = (y = even(box.screenY + 120))/2;
+    screenx = (x = even(rootElement.screenX + 120))/2;
+    screeny = (y = even(rootElement.screenY + 120))/2;
     setScale(window, 2);
     $("popup").openPopupAtScreen(x, y);
   }
 }
 
 function even(n)
 {
   return (n % 2) ? n+1 : n;
--- a/toolkit/content/tests/chrome/test_popupincontent.xul
+++ b/toolkit/content/tests/chrome/test_popupincontent.xul
@@ -55,18 +55,17 @@ function nextTest()
       popup.setAttribute("left", "800");
       popup.setAttribute("top", "2900");
       synthesizeMouse(menu, 2, 2, { });
       break;
     case "left and top":
       step = "open near bottom";
       // request that the menu be opened with a target point near the bottom of the window,
       // so that the menu's top margin will push it completely outside the window.
-      var bo = document.documentElement.boxObject;
-      popup.setAttribute("top", bo.screenY + window.innerHeight - 5);
+      popup.setAttribute("top", document.documentElement.screenY + window.innerHeight - 5);
       synthesizeMouse(menu, 2, 2, { });
       break;
     case "open near bottom":
       step = "large menu";
       popup.removeAttribute("left");
       popup.removeAttribute("top");
       for (var i = 0; i < 80; i++)
         menu.appendItem("Test", "");
--- a/toolkit/content/tests/chrome/window_panel.xul
+++ b/toolkit/content/tests/chrome/window_panel.xul
@@ -76,17 +76,17 @@ function popupShowing(event)
 }
 
 var waitSteps = 0;
 function popupShown(event)
 {
   var panel = event.target;
 
   if (waitSteps > 0 && navigator.platform.includes("Linux") &&
-      panel.boxObject.screenY == 210) {
+      panel.screenY == 210) {
     waitSteps--;
     setTimeout(popupShown, 10, event);
     return;
   }
 
   currentTest.result(currentTest.testname + " ", panel);
   panel.hidePopup();
 }
@@ -208,17 +208,17 @@ var tests = [
       ok(screenRect.width >= 120 && screenRect.width <= 140, testname + " screen width");
       ok(screenRect.height >= 40 && screenRect.height <= 80, testname + " screen height");
 
       var gotMouseEvent = false;
       function mouseMoved(event)
       {
         is(event.clientY, panelrect.top + 10,
            "popup clientY");
-        is(event.screenY, panel.boxObject.screenY + 10,
+        is(event.screenY, panel.screenY + 10,
            "popup screenY");
         is(event.originalTarget, panel.firstChild, "popup target");
         gotMouseEvent = true;
       }
 
       panel.addEventListener("mousemove", mouseMoved, true);
       synthesizeMouse(panel, 10, 10, { type: "mousemove" });
       ok(gotMouseEvent, "mouse event on panel");      
--- a/toolkit/content/widgets/richlistbox.js
+++ b/toolkit/content/widgets/richlistbox.js
@@ -613,36 +613,37 @@ MozElements.RichListBox = class RichList
     // at the extreme we're moving away from
     if (!this.currentItem) {
       return aDirection == -1 ? children.length : 0;
     }
 
     // If the current item is visible, scroll by one page so that
     // the new current item is at approximately the same position as
     // the existing current item.
+    let height = this.getBoundingClientRect().height;
     if (this._isItemVisible(this.currentItem)) {
-      this.scrollBy(0, this.clientHeight * aDirection);
+      this.scrollBy(0, height * aDirection);
     }
 
     // Figure out, how many items fully fit into the view port
     // (including the currently selected one), and determine
     // the index of the first one lying (partially) outside
-    var height = this.clientHeight;
-    var startBorder = this.currentItem.boxObject.y;
+    let currentItemRect = this.currentItem.getBoundingClientRect();
+    var startBorder = currentItemRect.y;
     if (aDirection == -1) {
-      startBorder += this.currentItem.clientHeight;
+      startBorder += currentItemRect.height;
     }
 
     var index = this.currentIndex;
     for (var ix = index; 0 <= ix && ix < children.length; ix += aDirection) {
-      var boxObject = children[ix].boxObject;
-      if (boxObject.height == 0) {
+      let childRect = children[ix].getBoundingClientRect();
+      if (childRect.height == 0) {
         continue; // hidden children have a y of 0
       }
-      var endBorder = boxObject.y + (aDirection == -1 ? boxObject.height : 0);
+      var endBorder = childRect.y + (aDirection == -1 ? childRect.height : 0);
       if ((endBorder - startBorder) * aDirection > height) {
         break; // we've reached the desired distance
       }
       index = ix;
     }
 
     return index != this.currentIndex ? index - this.currentIndex : aDirection;
   }
@@ -673,17 +674,17 @@ MozElements.RichListBox = class RichList
           this._currentIndex - 1, this.getRowCount()));
       }
       if (currentItem) {
         this.currentItem = currentItem;
         if (this.selType != "multiple" && this.selectedCount == 0) {
           this.selectedItem = currentItem;
         }
 
-        if (this.clientHeight) {
+        if (this.getBoundingClientRect().height) {
           this.ensureElementIsVisible(currentItem);
         } else {
           // XXX hack around a bug in ensureElementIsVisible as it will
           // scroll beyond the last element, bug 493645.
           this.ensureElementIsVisible(currentItem.previousElementSibling);
         }
       }
       this._suppressOnSelect = suppressSelect;
@@ -735,21 +736,22 @@ MozElements.RichListBox = class RichList
     }
   }
 
   _isItemVisible(aItem) {
     if (!aItem) {
       return false;
     }
 
-    var y = this.scrollTop + this.boxObject.y;
+    var y = this.getBoundingClientRect().y;
 
     // Partially visible items are also considered visible
-    return (aItem.boxObject.y + aItem.clientHeight > y) &&
-      (aItem.boxObject.y < y + this.clientHeight);
+    let itemRect = aItem.getBoundingClientRect();
+    return (itemRect.y + itemRect.height > y) &&
+           (itemRect.y < y + this.clientHeight);
   }
 
   moveByOffset(aOffset, aIsSelecting, aIsSelectingRange) {
     if ((aIsSelectingRange || !aIsSelecting) &&
       this.selType != "multiple") {
       return;
     }
 
--- a/xpcom/ds/StaticAtoms.py
+++ b/xpcom/ds/StaticAtoms.py
@@ -962,16 +962,17 @@ STATIC_ATOMS = [
     Atom("popupset", "popupset"),
     Atom("popupsinherittooltip", "popupsinherittooltip"),
     Atom("position", "position"),
     Atom("poster", "poster"),
     Atom("pre", "pre"),
     Atom("preceding", "preceding"),
     Atom("precedingSibling", "preceding-sibling"),
     Atom("prefersReducedMotion", "prefers-reduced-motion"),
+    Atom("prefersColorScheme", "prefers-color-scheme"),
     Atom("prefix", "prefix"),
     Atom("preload", "preload"),
     Atom("mozpresentation", "mozpresentation"),
     Atom("preserve", "preserve"),
     Atom("preserveSpace", "preserve-space"),
     Atom("preventdefault", "preventdefault"),
     Atom("previewDiv", "preview-div"),
     Atom("primary", "primary"),