Merge mozilla-central to inbound. a=merge CLOSED TREE
authorshindli <shindli@mozilla.com>
Tue, 26 Feb 2019 12:20:22 +0200
changeset 461140 7ad5d74c3240164caf11b5784958988294af05cc
parent 461139 0659ccd37ee77462c135b590e39fc8e25b9b71a0 (current diff)
parent 461029 110ea2a7c3d4f34b5079c195f7ea57966748e6da (diff)
child 461141 17ad931f439ce74288a8777400c40a19aa6971c6
push id35618
push usershindli@mozilla.com
push dateTue, 26 Feb 2019 16:54:44 +0000
treeherdermozilla-central@d326a9d5f77b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to inbound. a=merge CLOSED TREE
gfx/wr/webrender/src/display_list_flattener.rs
testing/web-platform/meta/fetch/api/response/response-init-001.html.ini
--- a/browser/themes/shared/tabs.inc.css
+++ b/browser/themes/shared/tabs.inc.css
@@ -497,20 +497,20 @@
 .tab-background[multiselected=true],
 .tab-background[selected=true] {
   border-top-color: var(--tabs-border-color);
   background-color: var(--toolbar-bgcolor);
   background-image: var(--toolbar-bgimage);
   background-repeat: repeat-x;
 }
 
-/* Add a translucent color (current text color at .2 alpha) on top of multiselected tabs */
+/* Add a translucent color on top of multiselected tabs */
 .tab-background[multiselected=true]:not([selected=true]) > .tab-background-inner {
   background: currentColor;
-  opacity: .2;
+  opacity: .1;
 }
 
 .tab-line[multiselected],
 .tab-line[selected=true] {
   background-color: var(--tab-line-color);
 }
 
 /*
new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging-new/documentation/TESTS_REAL_DEVICES.md
@@ -0,0 +1,67 @@
+# Running Tests with real USB connected devices for the new about:debugging
+
+This document explains how to test with real USB connected devices.
+
+## Tests overview
+
+The tests that use a real device are located in `devtools/client/aboutdebugging-new/test/browser/`and the name of tests starts with `browser_aboutdebugging_real`. These are normal mochitest, but we need to setup the environment before starting tests.
+
+## Setup environment
+### Real device side
+1. Enable USB debugging on your device
+2. Launch Firefox
+3. Enable USB debugging on your Firefox
+4. Connect to your PC via USB
+
+You can refer to https://developer.mozilla.org/docs/Tools/Remote_Debugging/Debugging_Firefox_for_Android_with_WebIDE#Setting_up_the_Android_device.
+
+### PC side
+Setup the real device information to evaluate the validity in tests.
+
+1. Copy a sample file which is located at `devtools/client/aboutdebugging-new/test/browser/real/usb-runtimes-sample.json` and rename it for example to `devtools/client/aboutdebugging-new/test/browser/real/local-usb-runtimes.json`.
+2. Edit the file.
+
+   This is a JSON file like below, write your real device information in here. This example indicates that there should be one USB device and should be displayed `Pixel 2` as device name and `Firefox Nightly` as short name on the sidebar of about:debugging. Regarding the other information, please see `Detail of config file` section of this document.
+
+```
+[
+  {
+    "sidebarInfo": {
+      "deviceName": "Pixel 2",
+      "shortName": "Firefox Nightly"
+    },
+    ...
+  },
+  ...
+]
+```
+
+## Test
+Normally, although we do test `./mach mochitest <path>`, to load the real device information created, specify the path as `USB_RUNTIME` environment variable, then do test.
+For example, if the name of the saved file is `devtools/client/aboutdebugging-new/test/browser/real/local-usb-runtimes.json`, run all real device test with a command like the one below:
+
+```
+USB_RUNTIMES=devtools/client/aboutdebugging-new/test/browser/real/local-usb-runtimes.json ./mach mochitest devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_real
+```
+
+If there is no `USB_RUNTIMES` environment variable, the tests will not run. This is also to avoid to run on try-server and so on.
+
+## Detail of config file
+
+```
+[
+  {
+    "sidebarInfo": {
+      "deviceName": "Pixel 2", // This should display as device name on the sidebar.
+      "shortName": "Firefox Nightly" // This should display as short name on the sidebar.
+    },
+    "runtimeDetails": {
+      "info": {
+        "name": "Mozilla Nightly", // This should display on the runtime info of runtime page.
+        "version": "64.0a1" // This should display on the runtime info of runtime page.
+      }
+    }
+  }
+  // Of course, you can append additional USB devices. Some tests can do with multiple devices.
+]
+```
\ No newline at end of file
--- a/devtools/client/aboutdebugging-new/test/browser/browser.ini
+++ b/devtools/client/aboutdebugging-new/test/browser/browser.ini
@@ -6,16 +6,17 @@ prefs =
   # ensure consistent test behavior by always setting this to false.
   devtools.aboutdebugging.showSystemAddons=false
 support-files =
   head.js
   helper-adb.js
   helper-addons.js
   helper-collapsibilities.js
   helper-mocks.js
+  helper-real-usb.js
   helper-serviceworker.js
   helper-telemetry.js
   mocks/*
   resources/bad-extension/*
   resources/packaged-extension/*
   resources/service-workers/*
   resources/test-adb-extension/*
   resources/test-temporary-extension/*
@@ -57,16 +58,18 @@ skip-if = (os == 'linux' && bits == 32) 
 [browser_aboutdebugging_devtoolstoolbox_menubar.js]
 [browser_aboutdebugging_devtoolstoolbox_reload.js]
 [browser_aboutdebugging_devtoolstoolbox_shortcuts.js]
 skip-if = (os == "win" && ccov) # Bug 1521349
 [browser_aboutdebugging_devtoolstoolbox_tooltip_markupview.js]
 [browser_aboutdebugging_navigate.js]
 [browser_aboutdebugging_persist_connection.js]
 [browser_aboutdebugging_profiler_dialog.js]
+[browser_aboutdebugging_real_usb_runtime_page_runtime_info.js]
+[browser_aboutdebugging_real_usb_sidebar.js]
 [browser_aboutdebugging_routes.js]
 [browser_aboutdebugging_runtime_compatibility_warning.js]
 [browser_aboutdebugging_runtime_remote_runtime_buttons.js]
 [browser_aboutdebugging_runtime_usbclient_closed.js]
 [browser_aboutdebugging_select_network_runtime.js]
 [browser_aboutdebugging_select_page_with_serviceworker.js]
 [browser_aboutdebugging_serviceworker_fetch_flag.js]
 [browser_aboutdebugging_serviceworker_multie10s.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_real_usb_runtime_page_runtime_info.js
@@ -0,0 +1,47 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* import-globals-from helper-real-usb.js */
+Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-real-usb.js", this);
+
+// Test that runtime info of USB runtime appears on main pane.
+// Documentation for real usb tests in /documentation/TESTS_REAL_DEVICES.md
+add_task(async function() {
+  if (!isAvailable()) {
+    ok(true, "Real usb runtime test is not available");
+    return;
+  }
+
+  const { document, tab } = await openAboutDebuggingWithADB();
+
+  const expectedRuntime = await getExpectedRuntime();
+  const { runtimeDetails, sidebarInfo } = expectedRuntime;
+
+  info("Connect a USB runtime");
+  await Promise.race([
+    connectToRuntime(sidebarInfo.deviceName, document),
+    /* eslint-disable mozilla/no-arbitrary-setTimeout */
+    new Promise(resolve => setTimeout(() => {
+      ok(false,
+         "Failed to connect, did you disable the connection prompt for this runtime?");
+      resolve();
+    }, 5000)),
+    /* eslint-enable mozilla/no-arbitrary-setTimeout */
+  ]);
+
+  info("Select a USB runtime");
+  await selectRuntime(sidebarInfo.deviceName, runtimeDetails.info.name, document);
+
+  info("Check that runtime info is properly displayed");
+  const runtimeInfo = document.querySelector(".js-runtime-info");
+  ok(runtimeInfo, "Runtime info is displayed");
+  const runtimeInfoText = runtimeInfo.textContent;
+  ok(runtimeInfoText.includes(runtimeDetails.info.name),
+     "Runtime info shows the correct runtime name: " + runtimeInfoText);
+  ok(runtimeInfoText.includes(runtimeDetails.info.version),
+     "Runtime info shows the correct version number: " + runtimeInfoText);
+
+  await removeTab(tab);
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_real_usb_sidebar.js
@@ -0,0 +1,29 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* import-globals-from helper-real-usb.js */
+Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-real-usb.js", this);
+
+// Test that USB runtimes appear from the sidebar.
+// Documentation for real usb tests in /documentation/TESTS_REAL_DEVICES.md
+add_task(async function() {
+  if (!isAvailable()) {
+    ok(true, "Real usb runtime test is not available");
+    return;
+  }
+
+  const { document, tab } = await openAboutDebuggingWithADB();
+
+  for (const { sidebarInfo } of await getExpectedRuntimeAll()) {
+    const { deviceName, shortName } = sidebarInfo;
+    await waitUntil(() => findSidebarItemByText(deviceName, document));
+    const usbRuntimeSidebarItem = findSidebarItemByText(deviceName, document);
+    ok(usbRuntimeSidebarItem.textContent.includes(shortName),
+       "The device name and short name of the usb runtime are visible in sidebar item " +
+       `[${usbRuntimeSidebarItem.textContent}]`);
+  }
+
+  await removeTab(tab);
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging-new/test/browser/helper-real-usb.js
@@ -0,0 +1,51 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* import-globals-from helper-adb.js */
+Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-adb.js", this);
+
+async function getExpectedRuntime() {
+  const runtimes = await getExpectedRuntimeAll();
+  return runtimes[0];
+}
+/* exported getExpectedRuntime */
+
+async function getExpectedRuntimeAll() {
+  const runtimesPath = _getExpectedRuntimesPath();
+  const currentPath = env.get("PWD");
+  const path = `${currentPath}/${runtimesPath}`;
+  info(`Load ${ path }`);
+  const buffer = await OS.File.read(path);
+  const data = new TextDecoder().decode(buffer);
+  return JSON.parse(data);
+}
+/* exported getExpectedRuntimeAll */
+
+function isAvailable() {
+  return !!_getExpectedRuntimesPath();
+}
+/* exported isAvailable */
+
+async function openAboutDebuggingWithADB() {
+  const { document, tab, window } = await openAboutDebugging();
+
+  await pushPref("devtools.remote.adb.extensionURL",
+                 CHROME_URL_ROOT + "resources/test-adb-extension/adb-extension-#OS#.xpi");
+  await checkAdbNotRunning();
+
+  const { adbAddon } = require("devtools/shared/adb/adb-addon");
+  adbAddon.install("internal");
+  const usbStatusElement = document.querySelector(".js-sidebar-usb-status");
+  await waitUntil(() => usbStatusElement.textContent.includes("USB devices enabled"));
+  await waitForAdbStart();
+
+  return { document, tab, window };
+}
+/* exported openAboutDebuggingWithADB */
+
+function _getExpectedRuntimesPath() {
+  const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
+  return env.get("USB_RUNTIMES");
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging-new/test/browser/resources/real/usb-runtimes-sample.json
@@ -0,0 +1,14 @@
+[
+  {
+    "sidebarInfo": {
+      "deviceName": "Pixel 2",
+      "shortName": "Firefox Nightly"
+    },
+    "runtimeDetails": {
+      "info": {
+        "name": "Mozilla Nightly",
+        "version": "64.0a1"
+      }
+    }
+  }
+]
--- a/devtools/client/netmonitor/test/service-workers/status-codes-service-worker.js
+++ b/devtools/client/netmonitor/test/service-workers/status-codes-service-worker.js
@@ -4,11 +4,11 @@
 "use strict";
 
 self.addEventListener("activate", event => {
   // start controlling the already loaded page
   event.waitUntil(self.clients.claim());
 });
 
 self.addEventListener("fetch", event => {
-  const response = new Response("Service worker response");
+  const response = new Response("Service worker response", { statusText: "OK" });
   event.respondWith(response);
 });
--- a/dom/canvas/WebGLProgram.cpp
+++ b/dom/canvas/WebGLProgram.cpp
@@ -468,16 +468,18 @@ static RefPtr<const webgl::LinkedProgram
       info->transformFeedbackVaryings.push_back(activeInfo);
     }
   }
 
   // Frag outputs
 
   {
     const auto& fragShader = prog->FragShader();
+    MOZ_RELEASE_ASSERT(fragShader);
+    MOZ_RELEASE_ASSERT(fragShader->Validator());
     const auto& handle = fragShader->Validator()->Handle();
     const auto version = sh::GetShaderVersion(handle);
 
     const auto fnAddInfo = [&](const webgl::FragOutputInfo& x) {
       info->fragOutputs.insert({x.loc, x});
     };
 
     if (version == 300) {
--- a/dom/canvas/WebGLShaderValidator.cpp
+++ b/dom/canvas/WebGLShaderValidator.cpp
@@ -208,16 +208,17 @@ webgl::ShaderValidator* WebGLContext::Cr
 
 namespace webgl {
 
 /*static*/ ShaderValidator* ShaderValidator::Create(
     GLenum shaderType, ShShaderSpec spec, ShShaderOutput outputLanguage,
     const ShBuiltInResources& resources, ShCompileOptions compileOptions) {
   ShHandle handle =
       sh::ConstructCompiler(shaderType, spec, outputLanguage, &resources);
+  MOZ_RELEASE_ASSERT(handle);
   if (!handle) return nullptr;
 
   return new ShaderValidator(handle, compileOptions,
                              resources.MaxVaryingVectors);
 }
 
 ShaderValidator::~ShaderValidator() { sh::Destruct(mHandle); }
 
--- a/dom/tests/mochitest/fetch/test_response.js
+++ b/dom/tests/mochitest/fetch/test_response.js
@@ -1,15 +1,15 @@
 function testDefaultCtor() {
   var res = new Response();
   is(res.type, "default", "Default Response type is default");
   ok(res.headers instanceof Headers, "Response should have non-null Headers object");
   is(res.url, "", "URL should be empty string");
   is(res.status, 200, "Default status is 200");
-  is(res.statusText, "OK", "Default statusText is OK");
+  is(res.statusText, "", "Default statusText is an empty string");
 }
 
 function testClone() {
   var orig = new Response("This is a body", {
               status: 404,
               statusText: "Not Found",
               headers: { "Content-Length": 5 },
             });
--- a/dom/webidl/Response.webidl
+++ b/dom/webidl/Response.webidl
@@ -39,13 +39,13 @@ Response implements Body;
 // See bug 1387483.
 partial interface Response {
   [GetterThrows, Func="mozilla::dom::DOMPrefs::javascript_options_streams"]
   readonly attribute ReadableStream? body;
 };
 
 dictionary ResponseInit {
   unsigned short status = 200;
-  ByteString statusText = "OK";
+  ByteString statusText = "";
   HeadersInit headers;
 };
 
 enum ResponseType { "basic", "cors", "default", "error", "opaque", "opaqueredirect" };
--- a/gfx/wr/webrender/src/border.rs
+++ b/gfx/wr/webrender/src/border.rs
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use api::{BorderRadius, BorderSide, BorderStyle, ColorF, ColorU, DeviceRect, DeviceSize};
 use api::{LayoutSideOffsets, LayoutSizeAu, LayoutPrimitiveInfo, LayoutToDeviceScale};
 use api::{DeviceVector2D, DevicePoint, LayoutRect, LayoutSize, DeviceIntSize};
-use api::{AuHelpers, LayoutPoint, LayoutPointAu, RepeatMode, TexelRect, LayoutVector2D};
+use api::{AuHelpers, LayoutPoint, LayoutPointAu, RepeatMode, TexelRect};
 use api::NormalBorder as ApiNormalBorder;
 use ellipse::Ellipse;
 use euclid::vec2;
 use display_list_flattener::DisplayListFlattener;
 use gpu_types::{BorderInstance, BorderSegment, BrushFlags};
 use prim_store::{BorderSegmentInfo, BrushSegment, NinePatchDescriptor};
 use prim_store::{EdgeAaSegmentMask, ScrollNodeAndClipChain};
 use prim_store::borders::NormalBorderPrim;
@@ -211,30 +211,28 @@ pub fn ensure_no_corner_overlap(
 
 impl<'a> DisplayListFlattener<'a> {
     pub fn add_normal_border(
         &mut self,
         info: &LayoutPrimitiveInfo,
         border: &ApiNormalBorder,
         widths: LayoutSideOffsets,
         clip_and_scroll: ScrollNodeAndClipChain,
-        reference_frame_relative_offset: LayoutVector2D,
     ) {
         let mut border = *border;
         ensure_no_corner_overlap(&mut border.radius, info.rect.size);
 
         self.add_primitive(
             clip_and_scroll,
             info,
             Vec::new(),
             NormalBorderPrim {
                 border: border.into(),
                 widths: widths.to_au(),
             },
-            reference_frame_relative_offset,
         );
     }
 }
 
 pub trait BorderSideHelpers {
     fn border_color(&self, is_inner_border: bool) -> ColorF;
 }
 
--- a/gfx/wr/webrender/src/box_shadow.rs
+++ b/gfx/wr/webrender/src/box_shadow.rs
@@ -72,17 +72,16 @@ impl<'a> DisplayListFlattener<'a> {
         clip_and_scroll: ScrollNodeAndClipChain,
         prim_info: &LayoutPrimitiveInfo,
         box_offset: &LayoutVector2D,
         color: ColorF,
         mut blur_radius: f32,
         spread_radius: f32,
         border_radius: BorderRadius,
         clip_mode: BoxShadowClipMode,
-        reference_frame_relative_offset: LayoutVector2D,
     ) {
         if color.a == 0.0 {
             return;
         }
 
         // Inset shadows get smaller as spread radius increases.
         let (spread_amount, prim_clip_mode) = match clip_mode {
             BoxShadowClipMode::Outset => (spread_radius, ClipMode::ClipOut),
@@ -162,17 +161,16 @@ impl<'a> DisplayListFlattener<'a> {
 
             self.add_primitive(
                 clip_and_scroll,
                 &LayoutPrimitiveInfo::with_clip_rect(final_prim_rect, prim_info.clip_rect),
                 clips,
                 PrimitiveKeyKind::Rectangle {
                     color: color.into(),
                 },
-                reference_frame_relative_offset,
             );
         } else {
             // Normal path for box-shadows with a valid blur radius.
             let blur_offset = (BLUR_SAMPLE_SCALE * blur_radius).ceil();
             let mut extra_clips = vec![];
 
             // Add a normal clip mask to clip out the contents
             // of the surrounding primitive.
@@ -252,17 +250,16 @@ impl<'a> DisplayListFlattener<'a> {
                 }
             };
 
             self.add_primitive(
                 clip_and_scroll,
                 &prim_info,
                 extra_clips,
                 prim,
-                reference_frame_relative_offset,
             );
         }
     }
 }
 
 fn adjust_border_radius_for_box_shadow(radius: BorderRadius, spread_amount: f32) -> BorderRadius {
     BorderRadius {
         top_left: adjust_corner_for_box_shadow(radius.top_left, spread_amount),
--- a/gfx/wr/webrender/src/display_list_flattener.rs
+++ b/gfx/wr/webrender/src/display_list_flattener.rs
@@ -55,16 +55,88 @@ impl ClipNode {
     fn new(id: ClipChainId, count: usize) -> Self {
         ClipNode {
             id,
             count,
         }
     }
 }
 
+/// The offset stack for a given reference frame.
+struct ReferenceFrameState {
+    /// A stack of current offsets from the current reference frame scope.
+    offsets: Vec<LayoutVector2D>,
+}
+
+/// Maps from stacking context layout coordinates into reference frame
+/// relative coordinates.
+struct ReferenceFrameMapper {
+    /// A stack of reference frame scopes.
+    frames: Vec<ReferenceFrameState>,
+}
+
+impl ReferenceFrameMapper {
+    fn new() -> Self {
+        ReferenceFrameMapper {
+            frames: vec![
+                ReferenceFrameState {
+                    offsets: vec![
+                        LayoutVector2D::zero(),
+                    ],
+                }
+            ],
+        }
+    }
+
+    /// Push a new scope. This resets the current offset to zero, and is
+    /// used when a new reference frame or iframe is pushed.
+    fn push_scope(&mut self) {
+        self.frames.push(ReferenceFrameState {
+            offsets: vec![
+                LayoutVector2D::zero(),
+            ],
+        });
+    }
+
+    /// Pop a reference frame scope off the stack.
+    fn pop_scope(&mut self) {
+        self.frames.pop().unwrap();
+    }
+
+    /// Push a new offset for the current scope. This is used when
+    /// a new stacking context is pushed.
+    fn push_offset(&mut self, offset: LayoutVector2D) {
+        let frame = self.frames.last_mut().unwrap();
+        let current_offset = *frame.offsets.last().unwrap();
+        frame.offsets.push(current_offset + offset);
+    }
+
+    /// Pop a local stacking context offset from the current scope.
+    fn pop_offset(&mut self) {
+        let frame = self.frames.last_mut().unwrap();
+        frame.offsets.pop().unwrap();
+    }
+
+    /// Retrieve the current offset to allow converting a stacking context
+    /// relative coordinate to be relative to the owing reference frame.
+    /// TODO(gw): We could perhaps have separate coordinate spaces for this,
+    ///           however that's going to either mean a lot of changes to
+    ///           public API code, or a lot of changes to internal code.
+    ///           Before doing that, we should revisit how Gecko would
+    ///           prefer to provide coordinates.
+    /// TODO(gw): For now, this includes only the reference frame relative
+    ///           offset. Soon, we will expand this to include the initial
+    ///           scroll offsets that are now available on scroll nodes. This
+    ///           will allow normalizing the coordinates even between display
+    ///           lists where APZ has scrolled the content.
+    fn current_offset(&self) -> LayoutVector2D {
+        *self.frames.last().unwrap().offsets.last().unwrap()
+    }
+}
+
 /// A data structure that keeps track of mapping between API Ids for clips/spatials and the indices
 /// used internally in the ClipScrollTree to avoid having to do HashMap lookups. NodeIdToIndexMapper
 /// is responsible for mapping both ClipId to ClipChainIndex and SpatialId to SpatialNodeIndex.
 #[derive(Default)]
 pub struct NodeIdToIndexMapper {
     clip_node_map: FastHashMap<ClipId, ClipNode>,
     spatial_node_map: FastHashMap<SpatialId, SpatialNodeIndex>,
 }
@@ -142,16 +214,19 @@ pub struct DisplayListFlattener<'a> {
     pub config: FrameBuilderConfig,
 
     /// Reference to the set of data that is interned across display lists.
     interners: &'a mut Interners,
 
     /// The root picture index for this flattener. This is the picture
     /// to start the culling phase from.
     pub root_pic_index: PictureIndex,
+
+    /// Helper struct to map stacking context coords <-> reference frame coords.
+    rf_mapper: ReferenceFrameMapper,
 }
 
 impl<'a> DisplayListFlattener<'a> {
     pub fn create_frame_builder(
         scene: &Scene,
         clip_scroll_tree: &mut ClipScrollTree,
         font_instances: FontInstanceMap,
         view: &DocumentView,
@@ -179,16 +254,17 @@ impl<'a> DisplayListFlattener<'a> {
             hit_testing_runs: Vec::new(),
             pending_shadow_items: VecDeque::new(),
             sc_stack: Vec::new(),
             pipeline_clip_chain_stack: vec![ClipChainId::NONE],
             prim_store: PrimitiveStore::new(&prim_store_stats),
             clip_store: ClipStore::new(),
             interners,
             root_pic_index: PictureIndex(0),
+            rf_mapper: ReferenceFrameMapper::new(),
         };
 
         flattener.push_root(
             root_pipeline_id,
             &root_pipeline.viewport_size,
             &root_pipeline.content_size,
         );
 
@@ -212,17 +288,16 @@ impl<'a> DisplayListFlattener<'a> {
             ROOT_SPATIAL_NODE_INDEX,
             ClipChainId::NONE,
             RasterSpace::Screen,
         );
 
         flattener.flatten_items(
             &mut root_pipeline.display_list.iter(),
             root_pipeline.pipeline_id,
-            LayoutVector2D::zero(),
             true,
         );
 
         flattener.pop_stacking_context();
 
         debug_assert!(flattener.sc_stack.is_empty());
 
         new_scene.root_pipeline_id = Some(root_pipeline_id);
@@ -464,17 +539,16 @@ impl<'a> DisplayListFlattener<'a> {
             .get_display_list_for_pipeline(pipeline_id)
             .get(items)
     }
 
     fn flatten_items(
         &mut self,
         traversal: &mut BuiltDisplayListIter<'a>,
         pipeline_id: PipelineId,
-        reference_frame_relative_offset: LayoutVector2D,
         apply_pipeline_clip: bool,
     ) {
         loop {
             let subtraversal = {
                 let item = match traversal.next() {
                     Some(item) => item,
                     None => break,
                 };
@@ -483,17 +557,16 @@ impl<'a> DisplayListFlattener<'a> {
                     SpecificDisplayItem::PopReferenceFrame |
                     SpecificDisplayItem::PopStackingContext => return,
                     _ => (),
                 }
 
                 self.flatten_item(
                     item,
                     pipeline_id,
-                    reference_frame_relative_offset,
                     apply_pipeline_clip,
                 )
             };
 
             // If flatten_item created a sub-traversal, we need `traversal` to have the
             // same state as the completed subtraversal, so we reinitialize it here.
             if let Some(subtraversal) = subtraversal {
                 *traversal = subtraversal;
@@ -501,19 +574,19 @@ impl<'a> DisplayListFlattener<'a> {
         }
     }
 
     fn flatten_sticky_frame(
         &mut self,
         item: &DisplayItemRef,
         info: &StickyFrameDisplayItem,
         parent_node_index: SpatialNodeIndex,
-        reference_frame_relative_offset: &LayoutVector2D,
     ) {
-        let frame_rect = item.rect().translate(reference_frame_relative_offset);
+        let current_offset = self.rf_mapper.current_offset();
+        let frame_rect = item.rect().translate(&current_offset);
         let sticky_frame_info = StickyFrameInfo::new(
             frame_rect,
             info.margins,
             info.vertical_offset_bounds,
             info.horizontal_offset_bounds,
             info.previously_applied_offset,
         );
 
@@ -526,24 +599,24 @@ impl<'a> DisplayListFlattener<'a> {
     }
 
     fn flatten_scroll_frame(
         &mut self,
         item: &DisplayItemRef,
         info: &ScrollFrameDisplayItem,
         parent_node_index: SpatialNodeIndex,
         pipeline_id: PipelineId,
-        reference_frame_relative_offset: &LayoutVector2D,
     ) {
         let complex_clips = self.get_complex_clips(pipeline_id, item.complex_clip().0);
+        let current_offset = self.rf_mapper.current_offset();
         let clip_region = ClipRegion::create_for_clip_node(
             *item.clip_rect(),
             complex_clips,
             info.image_mask,
-            reference_frame_relative_offset,
+            &current_offset,
         );
         // Just use clip rectangle as the frame rect for this scroll frame.
         // This is useful when calculating scroll extents for the
         // SpatialNode::scroll(..) API as well as for properly setting sticky
         // positioning offsets.
         let frame_rect = clip_region.main;
         let content_size = item.rect().size;
 
@@ -563,43 +636,48 @@ impl<'a> DisplayListFlattener<'a> {
 
     fn flatten_reference_frame(
         &mut self,
         traversal: &mut BuiltDisplayListIter<'a>,
         pipeline_id: PipelineId,
         parent_spatial_node: SpatialNodeIndex,
         origin: LayoutPoint,
         reference_frame: &ReferenceFrame,
-        reference_frame_relative_offset: LayoutVector2D,
         apply_pipeline_clip: bool,
     ) {
+        let current_offset = self.rf_mapper.current_offset();
         self.push_reference_frame(
             reference_frame.id,
             Some(parent_spatial_node),
             pipeline_id,
             reference_frame.transform_style,
             reference_frame.transform,
             reference_frame.kind,
-            reference_frame_relative_offset + origin.to_vector(),
+            current_offset + origin.to_vector(),
         );
 
-        self.flatten_items(traversal, pipeline_id, LayoutVector2D::zero(), apply_pipeline_clip);
+        self.rf_mapper.push_scope();
+        self.flatten_items(
+            traversal,
+            pipeline_id,
+            apply_pipeline_clip,
+        );
+        self.rf_mapper.pop_scope();
     }
 
 
     fn flatten_stacking_context(
         &mut self,
         traversal: &mut BuiltDisplayListIter<'a>,
         pipeline_id: PipelineId,
         stacking_context: &StackingContext,
         spatial_node_index: SpatialNodeIndex,
         origin: LayoutPoint,
         filters: ItemRange<FilterOp>,
         filter_datas: &[TempFilterData],
-        reference_frame_relative_offset: &LayoutVector2D,
         is_backface_visible: bool,
         apply_pipeline_clip: bool,
     ) {
         // Avoid doing unnecessary work for empty stacking contexts.
         if traversal.current_stacking_context_empty() {
             traversal.skip_current_stacking_context();
             return;
         }
@@ -644,54 +722,55 @@ impl<'a> DisplayListFlattener<'a> {
                     found_root = true;
                     break;
                 }
                 cur_clip = self.clip_store.get_clip_chain(cur_clip).parent_clip_chain_id;
             }
             debug_assert!(found_root);
         }
 
+        self.rf_mapper.push_offset(origin.to_vector());
         self.flatten_items(
             traversal,
             pipeline_id,
-            *reference_frame_relative_offset + origin.to_vector(),
             apply_pipeline_clip && clip_chain_id == ClipChainId::NONE,
         );
+        self.rf_mapper.pop_offset();
 
         self.pop_stacking_context();
     }
 
     fn flatten_iframe(
         &mut self,
         item: &DisplayItemRef,
         info: &IframeDisplayItem,
         spatial_node_index: SpatialNodeIndex,
-        reference_frame_relative_offset: &LayoutVector2D,
     ) {
         let iframe_pipeline_id = info.pipeline_id;
         let pipeline = match self.scene.pipelines.get(&iframe_pipeline_id) {
             Some(pipeline) => pipeline,
             None => {
                 debug_assert!(info.ignore_missing_pipeline);
                 return
             },
         };
 
+        let current_offset = self.rf_mapper.current_offset();
         let clip_chain_index = self.add_clip_node(
             ClipId::root(iframe_pipeline_id),
             item.space_and_clip_info(),
             ClipRegion::create_for_clip_node_with_local_clip(
                 item.clip_rect(),
-                reference_frame_relative_offset,
+                &current_offset,
             ),
         );
         self.pipeline_clip_chain_stack.push(clip_chain_index);
 
         let bounds = item.rect();
-        let origin = *reference_frame_relative_offset + bounds.origin.to_vector();
+        let origin = current_offset + bounds.origin.to_vector();
         let spatial_node_index = self.push_reference_frame(
             SpatialId::root_reference_frame(iframe_pipeline_id),
             Some(spatial_node_index),
             iframe_pipeline_id,
             TransformStyle::Flat,
             PropertyBinding::Value(LayoutTransform::identity()),
             ReferenceFrameKind::Transform,
             origin,
@@ -704,108 +783,104 @@ impl<'a> DisplayListFlattener<'a> {
             Some(ExternalScrollId(0, iframe_pipeline_id)),
             iframe_pipeline_id,
             &iframe_rect,
             &pipeline.content_size,
             ScrollSensitivity::ScriptAndInputEvents,
             ScrollFrameKind::PipelineRoot,
         );
 
+        self.rf_mapper.push_scope();
         self.flatten_items(
             &mut pipeline.display_list.iter(),
             pipeline.pipeline_id,
-            LayoutVector2D::zero(),
             true,
         );
+        self.rf_mapper.pop_scope();
 
         self.pipeline_clip_chain_stack.pop();
     }
 
     fn flatten_item<'b>(
         &'b mut self,
         item: DisplayItemRef<'a, 'b>,
         pipeline_id: PipelineId,
-        reference_frame_relative_offset: LayoutVector2D,
         apply_pipeline_clip: bool,
     ) -> Option<BuiltDisplayListIter<'a>> {
         let space_and_clip = item.space_and_clip_info();
         let clip_and_scroll = ScrollNodeAndClipChain::new(
             self.id_to_index_mapper.get_spatial_node_index(space_and_clip.spatial_id),
             if !apply_pipeline_clip && space_and_clip.clip_id.is_root() {
                 ClipChainId::NONE
             } else if space_and_clip.clip_id.is_valid() {
                 self.id_to_index_mapper.get_clip_chain_id(space_and_clip.clip_id)
             } else {
                 ClipChainId::INVALID
             },
         );
-        let prim_info = item.get_layout_primitive_info(&reference_frame_relative_offset);
+        let prim_info = item.get_layout_primitive_info(
+            &self.rf_mapper.current_offset(),
+        );
 
         match *item.item() {
             SpecificDisplayItem::Image(ref info) => {
                 self.add_image(
                     clip_and_scroll,
                     &prim_info,
                     info.stretch_size,
                     info.tile_spacing,
                     None,
                     info.image_key,
                     info.image_rendering,
                     info.alpha_type,
                     info.color,
-                    reference_frame_relative_offset,
                 );
             }
             SpecificDisplayItem::YuvImage(ref info) => {
                 self.add_yuv_image(
                     clip_and_scroll,
                     &prim_info,
                     info.yuv_data,
                     info.color_depth,
                     info.color_space,
                     info.image_rendering,
-                    reference_frame_relative_offset,
                 );
             }
             SpecificDisplayItem::Text(ref text_info) => {
                 self.add_text(
                     clip_and_scroll,
-                    reference_frame_relative_offset,
                     &prim_info,
                     &text_info.font_key,
                     &text_info.color,
                     item.glyphs(),
                     text_info.glyph_options,
                     pipeline_id,
                 );
             }
             SpecificDisplayItem::Rectangle(ref info) => {
                 self.add_solid_rectangle(
                     clip_and_scroll,
                     &prim_info,
                     info.color,
-                    reference_frame_relative_offset,
                 );
             }
             SpecificDisplayItem::ClearRectangle => {
                 self.add_clear_rectangle(
                     clip_and_scroll,
                     &prim_info,
-                    reference_frame_relative_offset,
                 );
             }
             SpecificDisplayItem::Line(ref info) => {
                 self.add_line(
                     clip_and_scroll,
                     &prim_info,
                     info.wavy_line_thickness,
                     info.orientation,
                     info.color,
                     info.style,
-                    reference_frame_relative_offset,
                 );
             }
             SpecificDisplayItem::Gradient(ref info) => {
                 if let Some(prim_key_kind) = self.create_linear_gradient_prim(
                     &prim_info,
                     info.gradient.start_point,
                     info.gradient.end_point,
                     item.gradient_stops(),
@@ -815,17 +890,16 @@ impl<'a> DisplayListFlattener<'a> {
                     pipeline_id,
                     None,
                 ) {
                     self.add_nonshadowable_primitive(
                         clip_and_scroll,
                         &prim_info,
                         Vec::new(),
                         prim_key_kind,
-                        reference_frame_relative_offset,
                     );
                 }
             }
             SpecificDisplayItem::RadialGradient(ref info) => {
                 let prim_key_kind = self.create_radial_gradient_prim(
                     &prim_info,
                     info.gradient.center,
                     info.gradient.start_offset * info.gradient.radius.width,
@@ -838,91 +912,87 @@ impl<'a> DisplayListFlattener<'a> {
                     pipeline_id,
                     None,
                 );
                 self.add_nonshadowable_primitive(
                     clip_and_scroll,
                     &prim_info,
                     Vec::new(),
                     prim_key_kind,
-                    reference_frame_relative_offset,
                 );
             }
             SpecificDisplayItem::BoxShadow(ref box_shadow_info) => {
+                let current_offset = self.rf_mapper.current_offset();
                 let bounds = box_shadow_info
                     .box_bounds
-                    .translate(&reference_frame_relative_offset);
+                    .translate(&current_offset);
                 let mut prim_info = prim_info.clone();
                 prim_info.rect = bounds;
                 self.add_box_shadow(
                     clip_and_scroll,
                     &prim_info,
                     &box_shadow_info.offset,
                     box_shadow_info.color,
                     box_shadow_info.blur_radius,
                     box_shadow_info.spread_radius,
                     box_shadow_info.border_radius,
                     box_shadow_info.clip_mode,
-                    reference_frame_relative_offset,
                 );
             }
             SpecificDisplayItem::Border(ref info) => {
                 self.add_border(
                     clip_and_scroll,
                     &prim_info,
                     info,
                     item.gradient_stops(),
                     pipeline_id,
-                    reference_frame_relative_offset,
                 );
             }
             SpecificDisplayItem::PushStackingContext(ref info) => {
                 let mut subtraversal = item.sub_iter();
                 self.flatten_stacking_context(
                     &mut subtraversal,
                     pipeline_id,
                     &info.stacking_context,
                     clip_and_scroll.spatial_node_index,
                     item.rect().origin,
                     item.filters(),
                     item.filter_datas(),
-                    &reference_frame_relative_offset,
                     prim_info.is_backface_visible,
                     apply_pipeline_clip,
                 );
                 return Some(subtraversal);
             }
             SpecificDisplayItem::PushReferenceFrame(ref info) => {
                 let mut subtraversal = item.sub_iter();
                 self.flatten_reference_frame(
                     &mut subtraversal,
                     pipeline_id,
                     clip_and_scroll.spatial_node_index,
                     item.rect().origin,
                     &info.reference_frame,
-                    reference_frame_relative_offset,
                     apply_pipeline_clip,
                 );
                 return Some(subtraversal);
             }
             SpecificDisplayItem::Iframe(ref info) => {
                 self.flatten_iframe(
                     &item,
                     info,
                     clip_and_scroll.spatial_node_index,
-                    &reference_frame_relative_offset,
                 );
             }
             SpecificDisplayItem::Clip(ref info) => {
+                let current_offset = self.rf_mapper.current_offset();
                 let complex_clips = self.get_complex_clips(pipeline_id, item.complex_clip().0);
                 let clip_region = ClipRegion::create_for_clip_node(
                     *item.clip_rect(),
                     complex_clips,
                     info.image_mask,
-                    &reference_frame_relative_offset,
+                    &current_offset,
                 );
                 self.add_clip_node(info.id, space_and_clip, clip_region);
             }
             SpecificDisplayItem::ClipChain(ref info) => {
                 // For a user defined clip-chain the parent (if specified) must
                 // refer to another user defined clip-chain. If none is specified,
                 // the parent is the root clip-chain for the given pipeline. This
                 // is used to provide a root clip chain for iframes.
@@ -991,48 +1061,47 @@ impl<'a> DisplayListFlattener<'a> {
                 self.id_to_index_mapper.add_clip_chain(ClipId::ClipChain(info.id), clip_chain_id, 0);
             },
             SpecificDisplayItem::ScrollFrame(ref info) => {
                 self.flatten_scroll_frame(
                     &item,
                     info,
                     clip_and_scroll.spatial_node_index,
                     pipeline_id,
-                    &reference_frame_relative_offset,
                 );
             }
             SpecificDisplayItem::StickyFrame(ref info) => {
                 self.flatten_sticky_frame(
                     &item,
                     info,
                     clip_and_scroll.spatial_node_index,
-                    &reference_frame_relative_offset,
                 );
             }
 
             // Do nothing; these are dummy items for the display list parser
             SpecificDisplayItem::SetGradientStops => {}
             SpecificDisplayItem::SetFilterOps => {}
             SpecificDisplayItem::SetFilterData => {}
 
             SpecificDisplayItem::PopReferenceFrame |
             SpecificDisplayItem::PopStackingContext => {
                 unreachable!("Should have returned in parent method.")
             }
             SpecificDisplayItem::PushShadow(shadow) => {
                 self.push_shadow(shadow, clip_and_scroll);
             }
             SpecificDisplayItem::PopAllShadows => {
-                self.pop_all_shadows(reference_frame_relative_offset);
+                self.pop_all_shadows();
             }
             SpecificDisplayItem::PushCacheMarker(_marker) => {
             }
             SpecificDisplayItem::PopCacheMarker => {
             }
         }
+
         None
     }
 
     // Given a list of clip sources, a positioning node and
     // a parent clip chain, return a new clip chain entry.
     // If the supplied list of clip sources is empty, then
     // just return the parent clip chain id directly.
     fn build_clip_chain(
@@ -1071,17 +1140,16 @@ impl<'a> DisplayListFlattener<'a> {
     ///
     /// TODO(djg): Can this inline into `add_interned_prim_to_draw_list`
     fn create_primitive<P>(
         &mut self,
         info: &LayoutPrimitiveInfo,
         clip_chain_id: ClipChainId,
         spatial_node_index: SpatialNodeIndex,
         prim: P,
-        reference_frame_relative_offset: LayoutVector2D,
     ) -> PrimitiveInstance
     where
         P: Internable<InternData=PrimitiveSceneData>,
         P::Source: AsInstanceKind<Handle<P::Marker>> + InternDebug,
         Interners: InternerMut<P>,
     {
         // Build a primitive key.
         let prim_key = prim.build_key(info);
@@ -1091,20 +1159,22 @@ impl<'a> DisplayListFlattener<'a> {
             interner
             .intern(&prim_key, || {
                 PrimitiveSceneData {
                     prim_size: info.rect.size,
                     is_backface_visible: info.is_backface_visible,
                 }
             });
 
+        let current_offset = self.rf_mapper.current_offset();
+
         let instance_kind = prim_key.as_instance_kind(
             prim_data_handle,
             &mut self.prim_store,
-            reference_frame_relative_offset,
+            current_offset,
         );
 
         PrimitiveInstance::new(
             info.rect.origin,
             info.clip_rect,
             instance_kind,
             clip_chain_id,
             spatial_node_index,
@@ -1150,17 +1220,16 @@ impl<'a> DisplayListFlattener<'a> {
     /// Convenience interface that creates a primitive entry and adds it
     /// to the draw list.
     fn add_nonshadowable_primitive<P>(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
         info: &LayoutPrimitiveInfo,
         clip_items: Vec<(LayoutPoint, ClipItemKey)>,
         prim: P,
-        reference_frame_relative_offset: LayoutVector2D,
     )
     where
         P: Internable<InternData = PrimitiveSceneData> + IsVisible,
         P::Source: AsInstanceKind<Handle<P::Marker>> + InternDebug,
         Interners: InternerMut<P>,
     {
         if prim.is_visible() {
             let clip_chain_id = self.build_clip_chain(
@@ -1168,44 +1237,41 @@ impl<'a> DisplayListFlattener<'a> {
                 clip_and_scroll.spatial_node_index,
                 clip_and_scroll.clip_chain_id,
             );
             self.add_prim_to_draw_list(
                 info,
                 clip_chain_id,
                 clip_and_scroll,
                 prim,
-                reference_frame_relative_offset,
             );
         }
     }
 
     pub fn add_primitive<P>(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
         info: &LayoutPrimitiveInfo,
         clip_items: Vec<(LayoutPoint, ClipItemKey)>,
         prim: P,
-        reference_frame_relative_offset: LayoutVector2D,
     )
     where
         P: Internable<InternData = PrimitiveSceneData> + IsVisible,
         P::Source: AsInstanceKind<Handle<P::Marker>> + InternDebug,
         Interners: InternerMut<P>,
         ShadowItem: From<PendingPrimitive<P>>
     {
         // If a shadow context is not active, then add the primitive
         // directly to the parent picture.
         if self.pending_shadow_items.is_empty() {
             self.add_nonshadowable_primitive(
                 clip_and_scroll,
                 info,
                 clip_items,
                 prim,
-                reference_frame_relative_offset,
             );
         } else {
             debug_assert!(clip_items.is_empty(), "No per-prim clips expected for shadowed primitives");
 
             // There is an active shadow context. Store as a pending primitive
             // for processing during pop_all_shadows.
             self.pending_shadow_items.push_back(PendingPrimitive {
                 clip_and_scroll,
@@ -1216,29 +1282,27 @@ impl<'a> DisplayListFlattener<'a> {
     }
 
     fn add_prim_to_draw_list<P>(
         &mut self,
         info: &LayoutPrimitiveInfo,
         clip_chain_id: ClipChainId,
         clip_and_scroll: ScrollNodeAndClipChain,
         prim: P,
-        reference_frame_relative_offset: LayoutVector2D,
     )
     where
         P: Internable<InternData = PrimitiveSceneData>,
         P::Source: AsInstanceKind<Handle<P::Marker>> + InternDebug,
         Interners: InternerMut<P>,
     {
         let prim_instance = self.create_primitive(
             info,
             clip_chain_id,
             clip_and_scroll.spatial_node_index,
             prim,
-            reference_frame_relative_offset,
         );
         self.register_chase_primitive_by_rect(
             &info.rect,
             &prim_instance,
         );
         self.add_primitive_to_hit_testing_list(info, clip_and_scroll);
         self.add_primitive_to_draw_list(prim_instance);
     }
@@ -1860,17 +1924,16 @@ impl<'a> DisplayListFlattener<'a> {
         self.pending_shadow_items.push_back(ShadowItem::Shadow(PendingShadow {
             shadow,
             clip_and_scroll,
         }));
     }
 
     pub fn pop_all_shadows(
         &mut self,
-        reference_frame_relative_offset: LayoutVector2D,
     ) {
         assert!(!self.pending_shadow_items.is_empty(), "popped shadows, but none were present");
 
         let pipeline_id = self.sc_stack.last().unwrap().pipeline_id;
         let max_clip = LayoutRect::max_rect();
         let mut items = mem::replace(&mut self.pending_shadow_items, VecDeque::new());
 
         //
@@ -1914,49 +1977,44 @@ impl<'a> DisplayListFlattener<'a> {
 
                     for item in &items {
                         match item {
                             ShadowItem::Image(ref pending_image) => {
                                 self.add_shadow_prim(
                                     &pending_shadow,
                                     pending_image,
                                     &mut prims,
-                                    reference_frame_relative_offset,
                                 )
                             }
                             ShadowItem::LineDecoration(ref pending_line_dec) => {
                                 self.add_shadow_prim(
                                     &pending_shadow,
                                     pending_line_dec,
                                     &mut prims,
-                                    reference_frame_relative_offset,
                                 )
                             }
                             ShadowItem::NormalBorder(ref pending_border) => {
                                 self.add_shadow_prim(
                                     &pending_shadow,
                                     pending_border,
                                     &mut prims,
-                                    reference_frame_relative_offset,
                                 )
                             }
                             ShadowItem::Primitive(ref pending_primitive) => {
                                 self.add_shadow_prim(
                                     &pending_shadow,
                                     pending_primitive,
                                     &mut prims,
-                                    reference_frame_relative_offset,
                                 )
                             }
                             ShadowItem::TextRun(ref pending_text_run) => {
                                 self.add_shadow_prim(
                                     &pending_shadow,
                                     pending_text_run,
                                     &mut prims,
-                                    reference_frame_relative_offset,
                                 )
                             }
                             _ => {}
                         }
                     }
 
                     // No point in adding a shadow here if there were no primitives
                     // added to the shadow.
@@ -2026,56 +2084,50 @@ impl<'a> DisplayListFlattener<'a> {
                         // Add the shadow primitive. This must be done before pushing this
                         // picture on to the shadow stack, to avoid infinite recursion!
                         self.add_primitive_to_draw_list(shadow_prim_instance);
                     }
                 }
                 ShadowItem::Image(pending_image) => {
                     self.add_shadow_prim_to_draw_list(
                         pending_image,
-                        reference_frame_relative_offset,
                     )
                 },
                 ShadowItem::LineDecoration(pending_line_dec) => {
                     self.add_shadow_prim_to_draw_list(
                         pending_line_dec,
-                        reference_frame_relative_offset,
                     )
                 },
                 ShadowItem::NormalBorder(pending_border) => {
                     self.add_shadow_prim_to_draw_list(
                         pending_border,
-                        reference_frame_relative_offset,
                     )
                 },
                 ShadowItem::Primitive(pending_primitive) => {
                     self.add_shadow_prim_to_draw_list(
                         pending_primitive,
-                        reference_frame_relative_offset,
                     )
                 },
                 ShadowItem::TextRun(pending_text_run) => {
                     self.add_shadow_prim_to_draw_list(
                         pending_text_run,
-                        reference_frame_relative_offset,
                     )
                 },
             }
         }
 
         debug_assert!(items.is_empty());
         self.pending_shadow_items = items;
     }
 
     fn add_shadow_prim<P>(
         &mut self,
         pending_shadow: &PendingShadow,
         pending_primitive: &PendingPrimitive<P>,
         prims: &mut Vec<PrimitiveInstance>,
-        reference_frame_relative_offset: LayoutVector2D,
     )
     where
         P: Internable<InternData=PrimitiveSceneData> + CreateShadow,
         P::Source: AsInstanceKind<Handle<P::Marker>> + InternDebug,
         Interners: InternerMut<P>,
     {
         // Offset the local rect and clip rect by the shadow offset.
         let mut info = pending_primitive.info.clone();
@@ -2085,41 +2137,38 @@ impl<'a> DisplayListFlattener<'a> {
         // Construct and add a primitive for the given shadow.
         let shadow_prim_instance = self.create_primitive(
             &info,
             pending_primitive.clip_and_scroll.clip_chain_id,
             pending_primitive.clip_and_scroll.spatial_node_index,
             pending_primitive.prim.create_shadow(
                 &pending_shadow.shadow,
             ),
-            reference_frame_relative_offset,
         );
 
         // Add the new primitive to the shadow picture.
         prims.push(shadow_prim_instance);
     }
 
     fn add_shadow_prim_to_draw_list<P>(
         &mut self,
         pending_primitive: PendingPrimitive<P>,
-        reference_frame_relative_offset: LayoutVector2D,
     ) where
         P: Internable<InternData = PrimitiveSceneData> + IsVisible,
         P::Source: AsInstanceKind<Handle<P::Marker>> + InternDebug,
         Interners: InternerMut<P>,
     {
         // For a normal primitive, if it has alpha > 0, then we add this
         // as a normal primitive to the parent picture.
         if pending_primitive.prim.is_visible() {
             self.add_prim_to_draw_list(
                 &pending_primitive.info,
                 pending_primitive.clip_and_scroll.clip_chain_id,
                 pending_primitive.clip_and_scroll,
                 pending_primitive.prim,
-                reference_frame_relative_offset,
             );
         }
     }
 
     #[cfg(debug_assertions)]
     fn register_chase_primitive_by_rect(
         &mut self,
         rect: &LayoutRect,
@@ -2139,60 +2188,55 @@ impl<'a> DisplayListFlattener<'a> {
     ) {
     }
 
     pub fn add_solid_rectangle(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
         info: &LayoutPrimitiveInfo,
         color: ColorF,
-        reference_frame_relative_offset: LayoutVector2D,
     ) {
         if color.a == 0.0 {
             // Don't add transparent rectangles to the draw list, but do consider them for hit
             // testing. This allows specifying invisible hit testing areas.
             self.add_primitive_to_hit_testing_list(info, clip_and_scroll);
             return;
         }
 
         self.add_primitive(
             clip_and_scroll,
             info,
             Vec::new(),
             PrimitiveKeyKind::Rectangle {
                 color: color.into(),
             },
-            reference_frame_relative_offset,
         );
     }
 
     pub fn add_clear_rectangle(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
         info: &LayoutPrimitiveInfo,
-        reference_frame_relative_offset: LayoutVector2D,
     ) {
         self.add_primitive(
             clip_and_scroll,
             info,
             Vec::new(),
             PrimitiveKeyKind::Clear,
-            reference_frame_relative_offset,
         );
     }
 
     pub fn add_line(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
         info: &LayoutPrimitiveInfo,
         wavy_line_thickness: f32,
         orientation: LineOrientation,
         color: ColorF,
         style: LineStyle,
-        reference_frame_relative_offset: LayoutVector2D,
     ) {
         // For line decorations, we can construct the render task cache key
         // here during scene building, since it doesn't depend on device
         // pixel ratio or transform.
         let mut info = info.clone();
 
         let size = get_line_decoration_sizes(
             &info.rect.size,
@@ -2244,28 +2288,26 @@ impl<'a> DisplayListFlattener<'a> {
         self.add_primitive(
             clip_and_scroll,
             &info,
             Vec::new(),
             LineDecoration {
                 cache_key,
                 color: color.into(),
             },
-            reference_frame_relative_offset,
         );
     }
 
     pub fn add_border(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
         info: &LayoutPrimitiveInfo,
         border_item: &BorderDisplayItem,
         gradient_stops: ItemRange<GradientStop>,
         pipeline_id: PipelineId,
-        reference_frame_relative_offset: LayoutVector2D,
     ) {
         match border_item.details {
             BorderDetails::NinePatch(ref border) => {
                 let nine_patch = NinePatchDescriptor {
                     width: border.width,
                     height: border.height,
                     slice: border.slice,
                     fill: border.fill,
@@ -2286,17 +2328,16 @@ impl<'a> DisplayListFlattener<'a> {
                             nine_patch,
                         };
 
                         self.add_nonshadowable_primitive(
                             clip_and_scroll,
                             info,
                             Vec::new(),
                             prim,
-                            reference_frame_relative_offset,
                         );
                     }
                     NinePatchBorderSource::Gradient(gradient) => {
                         let prim = match self.create_linear_gradient_prim(
                             &info,
                             gradient.start_point,
                             gradient.end_point,
                             gradient_stops,
@@ -2310,17 +2351,16 @@ impl<'a> DisplayListFlattener<'a> {
                             None => return,
                         };
 
                         self.add_nonshadowable_primitive(
                             clip_and_scroll,
                             info,
                             Vec::new(),
                             prim,
-                            reference_frame_relative_offset,
                         );
                     }
                     NinePatchBorderSource::RadialGradient(gradient) => {
                         let prim = self.create_radial_gradient_prim(
                             &info,
                             gradient.center,
                             gradient.start_offset * gradient.radius.width,
                             gradient.end_offset * gradient.radius.width,
@@ -2333,28 +2373,26 @@ impl<'a> DisplayListFlattener<'a> {
                             Some(Box::new(nine_patch)),
                         );
 
                         self.add_nonshadowable_primitive(
                             clip_and_scroll,
                             info,
                             Vec::new(),
                             prim,
-                            reference_frame_relative_offset,
                         );
                     }
                 };
             }
             BorderDetails::Normal(ref border) => {
                 self.add_normal_border(
                     info,
                     border,
                     border_item.widths,
                     clip_and_scroll,
-                    reference_frame_relative_offset,
                 );
             }
         }
     }
 
     pub fn create_linear_gradient_prim(
         &mut self,
         info: &LayoutPrimitiveInfo,
@@ -2464,24 +2502,25 @@ impl<'a> DisplayListFlattener<'a> {
             nine_patch,
             stops,
         }
     }
 
     pub fn add_text(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
-        offset: LayoutVector2D,
         prim_info: &LayoutPrimitiveInfo,
         font_instance_key: &FontInstanceKey,
         text_color: &ColorF,
         glyph_range: ItemRange<GlyphInstance>,
         glyph_options: Option<GlyphOptions>,
         pipeline_id: PipelineId,
     ) {
+        let offset = self.rf_mapper.current_offset();
+
         let text_run = {
             let instance_map = self.font_instances.read().unwrap();
             let font_instance = match instance_map.get(font_instance_key) {
                 Some(instance) => instance,
                 None => {
                     warn!("Unknown font instance key");
                     debug!("key={:?}", font_instance_key);
                     return;
@@ -2537,32 +2576,30 @@ impl<'a> DisplayListFlattener<'a> {
             }
         };
 
         self.add_primitive(
             clip_and_scroll,
             prim_info,
             Vec::new(),
             text_run,
-            offset,
         );
     }
 
     pub fn add_image(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
         info: &LayoutPrimitiveInfo,
         stretch_size: LayoutSize,
         mut tile_spacing: LayoutSize,
         sub_rect: Option<TexelRect>,
         image_key: ImageKey,
         image_rendering: ImageRendering,
         alpha_type: AlphaType,
         color: ColorF,
-        reference_frame_relative_offset: LayoutVector2D,
     ) {
         let mut prim_rect = info.rect;
         simplify_repeated_primitive(&stretch_size, &mut tile_spacing, &mut prim_rect);
         let info = LayoutPrimitiveInfo {
             rect: prim_rect,
             .. *info
         };
 
@@ -2587,29 +2624,27 @@ impl<'a> DisplayListFlattener<'a> {
                 key: image_key,
                 tile_spacing: tile_spacing.into(),
                 stretch_size: stretch_size.into(),
                 color: color.into(),
                 sub_rect,
                 image_rendering,
                 alpha_type,
             },
-            reference_frame_relative_offset,
         );
     }
 
     pub fn add_yuv_image(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
         info: &LayoutPrimitiveInfo,
         yuv_data: YuvData,
         color_depth: ColorDepth,
         color_space: YuvColorSpace,
         image_rendering: ImageRendering,
-        reference_frame_relative_offset: LayoutVector2D,
     ) {
         let format = yuv_data.get_format();
         let yuv_key = match yuv_data {
             YuvData::NV12(plane_0, plane_1) => [plane_0, plane_1, ImageKey::DUMMY],
             YuvData::PlanarYCbCr(plane_0, plane_1, plane_2) => [plane_0, plane_1, plane_2],
             YuvData::InterleavedYCbCr(plane_0) => [plane_0, ImageKey::DUMMY, ImageKey::DUMMY],
         };
 
@@ -2619,17 +2654,16 @@ impl<'a> DisplayListFlattener<'a> {
             Vec::new(),
             YuvImage {
                 color_depth,
                 yuv_key,
                 format,
                 color_space,
                 image_rendering,
             },
-            reference_frame_relative_offset,
         );
     }
 
     pub fn add_primitive_instance_to_3d_root(&mut self, instance: PrimitiveInstance) {
         // find the 3D root and append to the children list
         for sc in self.sc_stack.iter_mut().rev() {
             match sc.context_3d {
                 Picture3DContext::In { root_data: Some(ref mut prims), .. } => {
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -6856,16 +6856,22 @@ GeneralParser<ParseHandler, Unit>::class
     PropertyType propType;
     Node propName = propertyName(yieldHandling, PropertyNameInClass, declKind,
                                  classMembers, &propType, &propAtom);
     if (!propName) {
       return null();
     }
 
     if (propType == PropertyType::Field) {
+      // TODO(khyperia): Delete the two lines below once fields are fully
+      // supported in the backend. We can't fail in BytecodeCompiler because of
+      // lazy parsing.
+      errorAt(propNameOffset, JSMSG_FIELDS_NOT_SUPPORTED);
+      return null();
+
       if (isStatic) {
         errorAt(propNameOffset, JSMSG_BAD_METHOD_DEF);
         return null();
       }
       if (!tokenStream.getToken(&tt)) {
         return null();
       }
 
@@ -6888,21 +6894,17 @@ GeneralParser<ParseHandler, Unit>::class
         return null();
       }
 
       if (!handler_.addClassFieldDefinition(classMembers, propName,
                                             initializer)) {
         return null();
       }
 
-      // TODO(khyperia): Change the below to `continue;` once fields are
-      // fully supported in the backend. We can't fail in BytecodeCompiler
-      // because of lazy parsing.
-      errorAt(propNameOffset, JSMSG_FIELDS_NOT_SUPPORTED);
-      return null();
+      continue;
     }
 
     if (propType != PropertyType::Getter && propType != PropertyType::Setter &&
         propType != PropertyType::Method &&
         propType != PropertyType::GeneratorMethod &&
         propType != PropertyType::AsyncMethod &&
         propType != PropertyType::AsyncGeneratorMethod) {
       errorAt(propNameOffset, JSMSG_BAD_METHOD_DEF);
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -8455,26 +8455,27 @@ JS_FN_HELP("parseBin", BinParse, 1, 0,
 "  Decompile the currently executing script."),
 
     JS_FN_HELP("thisFilename", ThisFilename, 0, 0,
 "thisFilename()",
 "  Return the filename of the current script"),
 
     JS_FN_HELP("newGlobal", NewGlobal, 1, 0,
 "newGlobal([options])",
-"  Return a new global object in a new realm. If options\n"
-"  is given, it may have any of the following properties:\n"
-"\n"
-"      sameZoneAs: The compartment will be in the same zone as the given\n"
-"         object (defaults to a new zone).\n"
-"      sameCompartmentAs: The global will be in the same compartment and\n"
-"         zone as the given object (defaults to the current compartment,\n"
-"         unless the --more-compartments option is used).\n"
+"  Return a new global object/realm. The new global is created in the\n"
+"  'newGlobal' function object's compartment and zone, unless the\n"
+"  '--more-compartments' command-line flag was given, in which case new\n"
+"  globals get a fresh compartment and zone. If options is given, it may\n"
+"  have any of the following properties:\n"
+"      sameCompartmentAs: If an object, the global will be in the same\n"
+"         compartment and zone as the given object.\n"
+"      sameZoneAs: The global will be in a new compartment in the same zone\n"
+"         as the given object.\n"
 "      newCompartment: If true, the global will always be created in a new\n"
-"         compartment, even without --more-compartments.\n"
+"         compartment and zone.\n"
 "      cloneSingletons: If true, always clone the objects baked into\n"
 "         scripts, even if it's a top-level script that will only run once\n"
 "         (defaults to using them directly in scripts that will only run\n"
 "         once).\n"
 "      invisibleToDebugger: If true, the global will be invisible to the\n"
 "         debugger (default false)\n"
 "      disableLazyParsing: If true, don't create lazy scripts for functions\n"
 "         (default false).\n"
--- a/modules/libjar/nsZipArchive.cpp
+++ b/modules/libjar/nsZipArchive.cpp
@@ -605,17 +605,35 @@ nsresult nsZipArchive::BuildFileList(PRF
     uint32_t readaheadLength = xtolong(startp);
     if (readaheadLength) {
 #if defined(XP_SOLARIS)
       posix_madvise(const_cast<uint8_t *>(startp), readaheadLength,
                     POSIX_MADV_WILLNEED);
 #elif defined(XP_UNIX)
       madvise(const_cast<uint8_t *>(startp), readaheadLength, MADV_WILLNEED);
 #elif defined(XP_WIN)
-      if (aFd) {
+      static auto prefetchVirtualMemory =
+          reinterpret_cast<BOOL (*)(HANDLE, ULONG_PTR, PVOID, ULONG)>(
+              GetProcAddress(GetModuleHandle(L"kernel32.dll"),
+                               "PrefetchVirtualMemory"));
+      if (prefetchVirtualMemory) {
+        // Normally, we'd use WIN32_MEMORY_RANGE_ENTRY, but that requires
+        // a different _WIN32_WINNT value before including windows.h, but
+        // that causes complications with unified sources. It's a simple
+        // enough struct anyways.
+        struct {
+          PVOID VirtualAddress;
+          SIZE_T NumberOfBytes;
+        } entry;
+        entry.VirtualAddress = const_cast<uint8_t *>(startp);
+        entry.NumberOfBytes = readaheadLength;
+        prefetchVirtualMemory(GetCurrentProcess(), 1, &entry, 0);
+        readaheadLength = 0;
+      }
+      if (readaheadLength && aFd) {
         HANDLE hFile = (HANDLE)PR_FileDesc2NativeHandle(aFd);
         mozilla::ReadAhead(hFile, 0, readaheadLength);
       }
 #endif
     }
   } else {
     for (buf = endp - ZIPEND_SIZE; buf > startp; buf--) {
       if (xtolong(buf) == ENDSIG) {
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_cert_expiration_canary.js
@@ -0,0 +1,23 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+"use strict";
+
+// Attempts to verify a certificate for a time a few weeks into the future in
+// the hopes of avoiding mass test failures when the certificates all expire.
+// If this test fails, the certificates probably need to be regenerated.
+// See bug 1525191.
+add_task(async function() {
+  do_get_profile();
+  let certDB = Cc["@mozilla.org/security/x509certdb;1"]
+                 .getService(Ci.nsIX509CertDB);
+  addCertFromFile(certDB, "bad_certs/test-ca.pem", "CTu,,");
+  let threeWeeksFromNowInSeconds = (Date.now() / 1000) +
+                                   (3 * 7 * 24 * 60 * 60);
+  let ee = constructCertFromFile("bad_certs/default-ee.pem");
+  await checkCertErrorGenericAtTime(certDB, ee, PRErrorCodeSuccess,
+                                    certificateUsageSSLServer,
+                                    threeWeeksFromNowInSeconds, false,
+                                    "test.example.com");
+});
--- a/security/manager/ssl/tests/unit/xpcshell.ini
+++ b/security/manager/ssl/tests/unit/xpcshell.ini
@@ -48,16 +48,18 @@ support-files =
 skip-if = os != 'mac'
 [test_cert_blocklist.js]
 tags = addons psm blocklist
 [test_cert_chains.js]
 run-sequentially = hardcoded ports
 [test_cert_dbKey.js]
 [test_cert_eku.js]
 [test_cert_embedded_null.js]
+[test_cert_expiration_canary.js]
+run-if = nightly_build
 [test_cert_keyUsage.js]
 [test_cert_isBuiltInRoot.js]
 [test_cert_isBuiltInRoot_reload.js]
 [test_cert_overrides.js]
 run-sequentially = hardcoded ports
 [test_cert_overrides_read_only.js]
 run-sequentially = hardcoded ports
 [test_cert_override_bits_mismatches.js]
--- a/testing/web-platform/meta/fetch/api/response/response-clone.html.ini
+++ b/testing/web-platform/meta/fetch/api/response/response-clone.html.ini
@@ -30,11 +30,8 @@
     expected: FAIL
 
   [Check response clone use structureClone for teed ReadableStreams (DataViewchunk)]
     expected: FAIL
 
   [Cloned responses should provide the same data]
     expected: FAIL
 
-  [Check Response's clone with default values, without body]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/fetch/api/response/response-init-001.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[response-init-001.html]
-  [Check default value for statusText attribute]
-    expected: FAIL
-