Merge inbound to mozilla-central r=merge a=merge
authorGurzau Raul <rgurzau@mozilla.com>
Mon, 18 Dec 2017 23:57:42 +0200
changeset 396747 7c4579e705c4a3a3610183fe6f44affff3ad57ef
parent 396746 a3d5e7d3d98caa22b7bdc9bb7b89f525c7d61459 (current diff)
parent 396712 fb2acbf403de48072409030e72ad61edbed9f803 (diff)
child 396748 bc0c1d799434c723061fd698244c6a249325389d
child 396788 66ccb03771abc5b91cf69049f11b1ec80e80e60a
push id98361
push userrgurzau@mozilla.com
push dateMon, 18 Dec 2017 22:02:01 +0000
treeherdermozilla-inbound@bc0c1d799434 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge, merge
milestone59.0a1
first release with
nightly linux32
7c4579e705c4 / 59.0a1 / 20171218220523 / files
nightly linux64
7c4579e705c4 / 59.0a1 / 20171218220523 / files
nightly mac
7c4579e705c4 / 59.0a1 / 20171218220523 / files
nightly win32
7c4579e705c4 / 59.0a1 / 20171218220523 / files
nightly win64
7c4579e705c4 / 59.0a1 / 20171218220523 / 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 r=merge a=merge
testing/web-platform/meta/shadow-dom/event-composed-path-after-dom-mutation.html.ini
testing/web-platform/meta/shadow-dom/event-composed.html.ini
--- a/accessible/base/NotificationController.cpp
+++ b/accessible/base/NotificationController.cpp
@@ -414,33 +414,33 @@ NotificationController::ScheduleChildDoc
   ScheduleProcessing();
 }
 
 void
 NotificationController::ScheduleContentInsertion(Accessible* aContainer,
                                                  nsIContent* aStartChildNode,
                                                  nsIContent* aEndChildNode)
 {
-  nsTArray<nsCOMPtr<nsIContent>>* list =
-    mContentInsertions.LookupOrAdd(aContainer);
+  nsTArray<nsCOMPtr<nsIContent>> list;
 
   bool needsProcessing = false;
   nsIContent* node = aStartChildNode;
   while (node != aEndChildNode) {
     // Notification triggers for content insertion even if no content was
     // actually inserted, check if the given content has a frame to discard
     // this case early.
     if (node->GetPrimaryFrame()) {
-      if (list->AppendElement(node))
+      if (list.AppendElement(node))
         needsProcessing = true;
     }
     node = node->GetNextSibling();
   }
 
   if (needsProcessing) {
+    mContentInsertions.LookupOrAdd(aContainer)->AppendElements(list);
     ScheduleProcessing();
   }
 }
 
 void
 NotificationController::ScheduleProcessing()
 {
   // If notification flush isn't planed yet start notification flush
@@ -454,21 +454,41 @@ NotificationController::ScheduleProcessi
 ////////////////////////////////////////////////////////////////////////////////
 // NotificationCollector: protected
 
 bool
 NotificationController::IsUpdatePending()
 {
   return mPresShell->IsLayoutFlushObserver() ||
     mObservingState == eRefreshProcessingForUpdate ||
+    WaitingForParent() ||
     mContentInsertions.Count() != 0 || mNotifications.Length() != 0 ||
     mTextHash.Count() != 0 ||
     !mDocument->HasLoadState(DocAccessible::eTreeConstructed);
 }
 
+bool
+NotificationController::WaitingForParent()
+{
+  DocAccessible* parentdoc = mDocument->ParentDocument();
+  if (!parentdoc) {
+    return false;
+  }
+
+  NotificationController* parent = parentdoc->mNotificationController;
+  if (!parent || parent == this) {
+    // Do not wait for nothing or ourselves
+    return false;
+  }
+
+  // Wait for parent's notifications processing
+  return parent->mContentInsertions.Count() != 0 ||
+         parent->mNotifications.Length() != 0;
+}
+
 void
 NotificationController::ProcessMutationEvents()
 {
   // there is no reason to fire a hide event for a child of a show event
   // target.  That can happen if something is inserted into the tree and
   // removed before the next refresh driver tick, but it should not be
   // observable outside gecko so it should be safe to coalesce away any such
   // events.  This means that it should be fine to fire all of the hide events
@@ -587,16 +607,18 @@ NotificationController::ProcessMutationE
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // NotificationCollector: private
 
 void
 NotificationController::WillRefresh(mozilla::TimeStamp aTime)
 {
+  Telemetry::AutoTimer<Telemetry::A11Y_TREE_UPDATE_TIMING_MS> timer;
+
   AUTO_PROFILER_LABEL("NotificationController::WillRefresh", OTHER);
 
   // If the document accessible that notification collector was created for is
   // now shut down, don't process notifications anymore.
   NS_ASSERTION(mDocument,
                "The document was shut down while refresh observer is attached!");
   if (!mDocument)
     return;
@@ -604,16 +626,22 @@ NotificationController::WillRefresh(mozi
   // Wait until an update, we have started, or an interruptible reflow is
   // finished.
   if (mObservingState == eRefreshProcessing ||
       mObservingState == eRefreshProcessingForUpdate ||
       mPresShell->IsReflowInterrupted()) {
     return;
   }
 
+  // Wait for parent's notifications, to get proper ordering between e.g. tab
+  // event and content event.
+  if (WaitingForParent()) {
+    return;
+  }
+
   // Any generic notifications should be queued if we're processing content
   // insertions or generic notifications.
   mObservingState = eRefreshProcessingForUpdate;
 
   // Initial accessible tree construction.
   if (!mDocument->HasLoadState(DocAccessible::eTreeConstructed)) {
     // If document is not bound to parent at this point then the document is not
     // ready yet (process notifications later).
--- a/accessible/base/NotificationController.h
+++ b/accessible/base/NotificationController.h
@@ -269,16 +269,22 @@ protected:
   nsCycleCollectingAutoRefCnt mRefCnt;
   NS_DECL_OWNINGTHREAD
 
   /**
    * Return true if the accessible tree state update is pending.
    */
   bool IsUpdatePending();
 
+  /**
+   * Return true if we should wait for processing from the parent before we can
+   * process our own queue.
+   */
+  bool WaitingForParent();
+
 private:
   NotificationController(const NotificationController&);
   NotificationController& operator = (const NotificationController&);
 
   // nsARefreshObserver
   virtual void WillRefresh(mozilla::TimeStamp aTime) override;
 
   /**
--- a/browser/base/content/aboutTabCrashed.js
+++ b/browser/base/content/aboutTabCrashed.js
@@ -298,13 +298,14 @@ var AboutTabCrashed = {
     sendAsyncMessage(messageName, {
       sendReport,
       comments,
       email,
       emailMe,
       includeURL,
       URL,
       autoSubmit,
+      hasReport: this.hasReport,
     });
   },
 };
 
 AboutTabCrashed.init();
--- a/browser/base/content/test/general/browser_tabfocus.js
+++ b/browser/base/content/test/general/browser_tabfocus.js
@@ -133,19 +133,21 @@ add_task(async function() {
   browser1 = gBrowser.getBrowserForTab(tab1);
 
   tab2 = BrowserTestUtils.addTab(gBrowser);
   browser2 = gBrowser.getBrowserForTab(tab2);
 
   await promiseTabLoadEvent(tab1, "data:text/html," + escape(testPage1));
   await promiseTabLoadEvent(tab2, "data:text/html," + escape(testPage2));
 
-  var childFocusScript = "data:,(" + escape(focusInChild.toString()) + ")();";
-  browser1.messageManager.loadFrameScript(childFocusScript, true);
-  browser2.messageManager.loadFrameScript(childFocusScript, true);
+  if (gMultiProcessBrowser) {
+    var childFocusScript = "data:,(" + escape(focusInChild.toString()) + ")();";
+    browser1.messageManager.loadFrameScript(childFocusScript, true);
+    browser2.messageManager.loadFrameScript(childFocusScript, true);
+  }
 
   gURLBar.focus();
   await SimpleTest.promiseFocus();
 
   if (gMultiProcessBrowser) {
     window.messageManager.addMessageListener("Browser:FocusChanged", message => {
       actualEvents.push(message.data.details);
       compareFocusResults();
--- a/browser/base/content/test/siteIdentity/browser_check_identity_state.js
+++ b/browser/base/content/test/siteIdentity/browser_check_identity_state.js
@@ -1,15 +1,15 @@
 /*
  * Test the identity mode UI for a variety of page types
  */
 
 "use strict";
 
-const DUMMY = "browser/browser/base/content/test/general/dummy_page.html";
+const DUMMY = "browser/browser/base/content/test/siteIdentity/dummy_page.html";
 const INSECURE_ICON_PREF = "security.insecure_connection_icon.enabled";
 const INSECURE_PBMODE_ICON_PREF = "security.insecure_connection_icon.pbmode.enabled";
 
 function loadNewTab(url) {
   return BrowserTestUtils.openNewForegroundTab(gBrowser, url, true);
 }
 
 function getIdentityMode(aWindow = window) {
@@ -228,16 +228,44 @@ async function noCertErrorTest(secureChe
   await SpecialPowers.popPrefEnv();
 }
 
 add_task(async function test_about_net_error_uri() {
   await noCertErrorTest(true);
   await noCertErrorTest(false);
 });
 
+async function noCertErrorFromNavigationTest(secureCheck) {
+  await SpecialPowers.pushPrefEnv({set: [[INSECURE_ICON_PREF, secureCheck]]});
+  let newTab = await loadNewTab("http://example.com/" + DUMMY);
+
+  let promise = BrowserTestUtils.waitForErrorPage(gBrowser.selectedBrowser);
+  await ContentTask.spawn(gBrowser.selectedBrowser, {}, function() {
+    content.document.getElementById("no-cert").click();
+  });
+  await promise;
+  await ContentTask.spawn(gBrowser.selectedBrowser, {}, function() {
+    is(content.window.location.href, "https://nocert.example.com/", "Should be the cert error URL");
+  });
+
+
+  is(newTab.linkedBrowser.documentURI.spec.startsWith("about:certerror?"), true, "Should be an about:certerror");
+  is(getIdentityMode(), "unknownIdentity", "Identity should be unknown");
+  is(getConnectionState(), "not-secure", "Connection should be file");
+
+  gBrowser.removeTab(newTab);
+
+  await SpecialPowers.popPrefEnv();
+}
+
+add_task(async function test_about_net_error_uri_from_navigation_tab() {
+  await noCertErrorFromNavigationTest(true);
+  await noCertErrorFromNavigationTest(false);
+});
+
 async function aboutUriTest(secureCheck) {
   let oldTab = gBrowser.selectedTab;
   await SpecialPowers.pushPrefEnv({set: [[INSECURE_ICON_PREF, secureCheck]]});
   let aboutURI = "about:robots";
 
   let newTab = await loadNewTab(aboutURI);
   is(getConnectionState(), "file", "Connection should be file");
 
--- a/browser/base/content/test/siteIdentity/dummy_page.html
+++ b/browser/base/content/test/siteIdentity/dummy_page.html
@@ -1,9 +1,10 @@
 <html>
 <head>
 <title>Dummy test page</title>
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8"></meta>
 </head>
 <body>
+  <a href="https://nocert.example.com" id="no-cert">No Cert page</a>
 <p>Dummy test page</p>
 </body>
 </html>
--- a/browser/base/content/test/tabcrashed/browser_autoSubmitRequest.js
+++ b/browser/base/content/test/tabcrashed/browser_autoSubmitRequest.js
@@ -16,17 +16,17 @@ requestLongerTimeout(2);
  * backlogged crash reports, that we offer to do that, and
  * that the user can accept that offer.
  */
 add_task(async function test_show_form() {
   await SpecialPowers.pushPrefEnv({
     set: [[AUTOSUBMIT_PREF, false]],
   });
 
-  return BrowserTestUtils.withNewTab({
+  await BrowserTestUtils.withNewTab({
     gBrowser,
     url: PAGE,
   }, async function(browser) {
     // Make sure we've flushed the browser messages so that
     // we can restore it.
     await TabStateFlusher.flush(browser);
 
     // Now crash the browser.
@@ -64,17 +64,17 @@ add_task(async function test_show_form()
  * Tests that if the user is autosubmitting backlogged crash reports
  * that we don't make the offer again.
  */
 add_task(async function test_show_form() {
   await SpecialPowers.pushPrefEnv({
     set: [[AUTOSUBMIT_PREF, true]],
   });
 
-  return BrowserTestUtils.withNewTab({
+  await BrowserTestUtils.withNewTab({
     gBrowser,
     url: PAGE,
   }, async function(browser) {
     await TabStateFlusher.flush(browser);
     // Now crash the browser.
     await BrowserTestUtils.crashBrowser(browser);
 
     // eslint-disable-next-line mozilla/no-cpows-in-tests
@@ -92,8 +92,63 @@ add_task(async function test_show_form()
 
     await BrowserTestUtils.browserLoaded(browser, false, PAGE);
 
     // The autosubmission pref should still be set to true.
     Assert.ok(Services.prefs.getBoolPref(AUTOSUBMIT_PREF),
               "Autosubmission pref should have been set.");
   });
 });
+
+/**
+ * Tests that we properly set the autoSubmit preference if the user is
+ * presented with a tabcrashed page without a crash report.
+ */
+add_task(async function test_no_offer() {
+  // We should default to sending the report.
+  Assert.ok(TabCrashHandler.prefs.getBoolPref("sendReport"));
+
+  await SpecialPowers.pushPrefEnv({
+    set: [[AUTOSUBMIT_PREF, false]],
+  });
+
+  await BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: PAGE,
+  }, async function(browser) {
+    await TabStateFlusher.flush(browser);
+
+    // Make it so that it seems like no dump is available for the next crash.
+    prepareNoDump();
+
+    // Now crash the browser.
+    await BrowserTestUtils.crashBrowser(browser);
+
+    // eslint-disable-next-line mozilla/no-cpows-in-tests
+    let doc = browser.contentDocument;
+
+    // Ensure the request to autosubmit is invisible, since there's no report.
+    let requestRect = doc.getElementById("requestAutoSubmit")
+                         .getBoundingClientRect();
+    Assert.equal(0, requestRect.height,
+                 "Request for autosubmission has no height");
+    Assert.equal(0, requestRect.width,
+                 "Request for autosubmission has no width");
+
+    // Since the pref is set to false, the checkbox should be
+    // unchecked.
+    let autoSubmit = doc.getElementById("autoSubmit");
+    Assert.ok(!autoSubmit.checked,
+              "Checkbox for autosubmission is not checked.");
+
+    let restoreButton = doc.getElementById("restoreTab");
+    restoreButton.click();
+
+    await BrowserTestUtils.browserLoaded(browser, false, PAGE);
+
+    // The autosubmission pref should now be set.
+    Assert.ok(!Services.prefs.getBoolPref(AUTOSUBMIT_PREF),
+              "Autosubmission pref should not have changed.");
+  });
+
+  // We should not have changed the default value for sending the report.
+  Assert.ok(TabCrashHandler.prefs.getBoolPref("sendReport"));
+});
--- a/browser/base/content/test/tabcrashed/browser_withoutDump.js
+++ b/browser/base/content/test/tabcrashed/browser_withoutDump.js
@@ -1,22 +1,14 @@
 "use strict";
 
 const PAGE = "data:text/html,<html><body>A%20regular,%20everyday,%20normal%20page.";
 
-/**
- * Monkey patches TabCrashHandler.getDumpID to return null in order to test
- * about:tabcrashed when a dump is not available.
- */
 add_task(async function setup() {
-  let originalGetDumpID = TabCrashHandler.getDumpID;
-  TabCrashHandler.getDumpID = function(browser) { return null; };
-  registerCleanupFunction(() => {
-    TabCrashHandler.getDumpID = originalGetDumpID;
-  });
+  prepareNoDump();
 });
 
 /**
  * Tests tab crash page when a dump is not available.
  */
 add_task(async function test_without_dump() {
   return BrowserTestUtils.withNewTab({
     gBrowser,
--- a/browser/base/content/test/tabcrashed/head.js
+++ b/browser/base/content/test/tabcrashed/head.js
@@ -116,8 +116,20 @@ async function setupLocalCrashReportServ
   env.set("MOZ_CRASHREPORTER_NO_REPORT", "");
   env.set("MOZ_CRASHREPORTER_URL", SERVER_URL);
 
   registerCleanupFunction(function() {
     env.set("MOZ_CRASHREPORTER_NO_REPORT", noReport);
     env.set("MOZ_CRASHREPORTER_URL", serverUrl);
   });
 }
+
+/**
+ * Monkey patches TabCrashHandler.getDumpID to return null in order to test
+ * about:tabcrashed when a dump is not available.
+ */
+function prepareNoDump() {
+  let originalGetDumpID = TabCrashHandler.getDumpID;
+  TabCrashHandler.getDumpID = function(browser) { return null; };
+  registerCleanupFunction(() => {
+    TabCrashHandler.getDumpID = originalGetDumpID;
+  });
+}
--- a/browser/components/contextualidentity/test/browser/browser_usercontextid_tabdrop.js
+++ b/browser/components/contextualidentity/test/browser/browser_usercontextid_tabdrop.js
@@ -6,17 +6,17 @@ Services.scriptloader.loadSubScript("chr
 /**
  * Dragging an URL to a tab without userContextId set.
  */
 add_task(async function() {
   let tab = BrowserTestUtils.addTab(gBrowser, "http://example.com/");
   await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
 
   let awaitDrop = BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "drop");
-  let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, "http://test1.example.com/");
+  let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, "http://test1.example.com/", true);
 
   // A drop type of "link" onto an existing tab would normally trigger a
   // load in that same tab, but tabbrowser code in _getDragTargetTab treats
   // drops on the outer edges of a tab differently (loading a new tab
   // instead). Make events created by synthesizeDrop have all of their
   // coordinates set to 0 (screenX/screenY), so they're treated as drops
   // on the outer edge of the tab, thus they open new tabs.
   let event = {
@@ -27,18 +27,16 @@ add_task(async function() {
   };
   EventUtils.synthesizeDrop(tab, tab, [[{type: "text/plain", data: "http://test1.example.com/"}]], "link", window, undefined, event);
 
   await awaitDrop;
 
   let tab2 = await newTabPromise;
   Assert.ok(!tab2.hasAttribute("usercontextid"), "Tab shouldn't have usercontextid attribute");
 
-  await BrowserTestUtils.browserLoaded(tab2.linkedBrowser);
-
   await ContentTask.spawn(tab2.linkedBrowser, {}, async function() {
     Assert.equal(content.document.documentURI, "http://test1.example.com/");
     Assert.equal(content.document.nodePrincipal.originAttributes.userContextId, 0);
 
     // referrer is empty when urls are dragged to new or existing tabs.
     // If this changes in the future, it would be okay to send the referrer
     // in this case because we are creating a new tab with the default
     // usercontextid as the original tab.
@@ -53,17 +51,17 @@ add_task(async function() {
  * When dragging an URL to a new tab, the new tab should have the same
  * userContextId as the original tab.
  */
 add_task(async function() {
   let tab = BrowserTestUtils.addTab(gBrowser, "http://example.com/", {userContextId: 1});
   await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
 
   let awaitDrop = BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "drop");
-  let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, "http://test1.example.com/");
+  let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, "http://test1.example.com/", true);
 
   // A drop type of "link" onto an existing tab would normally trigger a
   // load in that same tab, but tabbrowser code in _getDragTargetTab treats
   // drops on the outer edges of a tab differently (loading a new tab
   // instead). Make events created by synthesizeDrop have all of their
   // coordinates set to 0 (screenX/screenY), so they're treated as drops
   // on the outer edge of the tab, thus they open new tabs.
   let event = {
@@ -74,18 +72,16 @@ add_task(async function() {
   };
   EventUtils.synthesizeDrop(tab, tab, [[{type: "text/plain", data: "http://test1.example.com/"}]], "link", window, undefined, event);
 
   await awaitDrop;
 
   let tab2 = await newTabPromise;
   Assert.equal(tab2.getAttribute("usercontextid"), 1);
 
-  await BrowserTestUtils.browserLoaded(tab2.linkedBrowser);
-
   await ContentTask.spawn(tab2.linkedBrowser, {}, async function() {
     Assert.equal(content.document.documentURI, "http://test1.example.com/");
     Assert.equal(content.document.nodePrincipal.originAttributes.userContextId, 1);
 
     // referrer is empty when urls are dragged to new or existing tabs.
     // If this changes in the future, it would be okay to send the referrer
     // in this case because we are creating a new tab with the same
     // usercontextid as the original tab.
--- a/browser/components/customizableui/test/head.js
+++ b/browser/components/customizableui/test/head.js
@@ -281,17 +281,17 @@ function promiseOverflowHidden(win) {
 function promisePanelElementHidden(win, aPanel) {
   return new Promise((resolve, reject) => {
     let timeoutId = win.setTimeout(() => {
       reject("Panel did not hide within 20 seconds.");
     }, 20000);
     function onPanelClose(e) {
       aPanel.removeEventListener("popuphidden", onPanelClose);
       win.clearTimeout(timeoutId);
-      resolve();
+      executeSoon(resolve);
     }
     aPanel.addEventListener("popuphidden", onPanelClose);
   });
 }
 
 function isPanelUIOpen() {
   return PanelUI.panel.state == "open" || PanelUI.panel.state == "showing";
 }
--- a/browser/modules/ContentCrashHandlers.jsm
+++ b/browser/modules/ContentCrashHandlers.jsm
@@ -363,31 +363,38 @@ this.TabCrashHandler = {
    *          The email address of the user.
    *        comments (String):
    *          Any additional comments from the user.
    *
    *        Note that it is expected that all properties are set,
    *        even if they are empty.
    */
   maybeSendCrashReport(message) {
-    if (!AppConstants.MOZ_CRASHREPORTER)
+    if (!AppConstants.MOZ_CRASHREPORTER) {
       return;
+    }
+
+    if (!message.data.hasReport) {
+      // There was no report, so nothing to do.
+      return;
+    }
 
     let browser = message.target.browser;
 
     if (message.data.autoSubmit) {
       // The user has opted in to autosubmitted backlogged
       // crash reports in the future.
       UnsubmittedCrashHandler.autoSubmit = true;
     }
 
     let childID = this.browserMap.get(browser);
     let dumpID = this.childMap.get(childID);
-    if (!dumpID)
+    if (!dumpID) {
       return;
+    }
 
     if (!message.data.sendReport) {
       Services.telemetry.getHistogramById("FX_CONTENT_CRASH_NOT_SUBMITTED").add(1);
       this.prefs.setBoolPref("sendReport", false);
       return;
     }
 
     let {
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -794,32 +794,42 @@ ifdef ASFILES
 $(ASOBJS):
 	$(REPORT_BUILD_VERBOSE)
 	$(AS) $(ASOUTOPTION)$@ $(ASFLAGS) $($(notdir $<)_FLAGS) $(AS_DASH_C_FLAG) $(_VPATH_SRCS)
 endif
 
 define syms_template
 syms:: $(2)
 $(2): $(1)
+ifdef MOZ_CRASHREPORTER
 	$$(call py_action,dumpsymbols,$$(abspath $$<) $$(abspath $$@))
+endif
 endef
 
 ifndef MOZ_PROFILE_GENERATE
 ifneq (,$(filter $(DIST)/bin%,$(FINAL_TARGET)))
 DUMP_SYMS_TARGETS := $(SHARED_LIBRARY) $(PROGRAM) $(SIMPLE_PROGRAMS)
 endif
 endif
 
 ifdef MOZ_AUTOMATION
 ifeq (,$(filter 1,$(MOZ_AUTOMATION_BUILD_SYMBOLS)))
 DUMP_SYMS_TARGETS :=
 endif
 endif
 
+ifdef MOZ_CRASHREPORTER
 $(foreach file,$(DUMP_SYMS_TARGETS),$(eval $(call syms_template,$(file),$(file)_syms.track)))
+else ifneq (,$(and $(LLVM_SYMBOLIZER),$(filter WINNT,$(OS_ARCH)),$(MOZ_AUTOMATION)))
+$(foreach file,$(DUMP_SYMS_TARGETS),$(eval $(call syms_template,$(file),$(addsuffix .pdb,$(basename $(file))))))
+PDB_FILES = $(addsuffix .pdb,$(basename $(DUMP_SYMS_TARGETS)))
+PDB_DEST ?= $(FINAL_TARGET)
+PDB_TARGET = target
+INSTALL_TARGETS += PDB
+endif
 
 cargo_host_flag := --target=$(RUST_HOST_TARGET)
 cargo_target_flag := --target=$(RUST_TARGET)
 
 # Permit users to pass flags to cargo from their mozconfigs (e.g. --color=always).
 cargo_build_flags = $(CARGOFLAGS)
 ifndef MOZ_DEBUG_RUST
 cargo_build_flags += --release
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -9389,37 +9389,38 @@ nsDocShell::CreateContentViewer(const ns
   // Set mFiredUnloadEvent = false so that the unload handler for the
   // *new* document will fire.
   mFiredUnloadEvent = false;
 
   // we've created a new document so go ahead and call
   // OnLoadingSite(), but don't fire OnLocationChange()
   // notifications before we've called Embed(). See bug 284993.
   mURIResultedInDocument = true;
+  bool errorOnLocationChangeNeeded = false;
+  nsCOMPtr<nsIChannel> failedChannel = mFailedChannel;
+  nsCOMPtr<nsIURI> failedURI;
 
   if (mLoadType == LOAD_ERROR_PAGE) {
     // We need to set the SH entry and our current URI here and not
     // at the moment we load the page. We want the same behavior
     // of Stop() as for a normal page load. See bug 514232 for details.
 
     // Revert mLoadType to load type to state the page load failed,
     // following function calls need it.
     mLoadType = mFailedLoadType;
 
-    nsCOMPtr<nsIChannel> failedChannel = mFailedChannel;
 
     nsIDocument* doc = viewer->GetDocument();
     if (doc) {
       doc->SetFailedChannel(failedChannel);
     }
 
-    // Make sure we have a URI to set currentURI.
-    nsCOMPtr<nsIURI> failedURI;
     nsCOMPtr<nsIPrincipal> triggeringPrincipal;
     if (failedChannel) {
+      // Make sure we have a URI to set currentURI.
       NS_GetFinalChannelURI(failedChannel, getter_AddRefs(failedURI));
     }
      else {
        // if there is no failed channel we have to explicitly provide
        // a triggeringPrincipal for the history entry.
        triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
     }
 
@@ -9435,24 +9436,19 @@ nsDocShell::CreateContentViewer(const ns
     // bug 291876.
     MOZ_ASSERT(failedURI, "We don't have a URI for history APIs.");
 
     mFailedChannel = nullptr;
     mFailedURI = nullptr;
 
     // Create an shistory entry for the old load.
     if (failedURI) {
-      bool errorOnLocationChangeNeeded = OnNewURI(
+      errorOnLocationChangeNeeded = OnNewURI(
         failedURI, failedChannel, triggeringPrincipal,
         nullptr, mLoadType, false, false, false);
-
-      if (errorOnLocationChangeNeeded) {
-        FireOnLocationChange(this, failedChannel, failedURI,
-                             LOCATION_CHANGE_ERROR_PAGE);
-      }
     }
 
     // Be sure to have a correct mLSHE, it may have been cleared by
     // EndPageLoad. See bug 302115.
     if (mSessionHistory && !mLSHE) {
       int32_t idx;
       mSessionHistory->GetRequestedIndex(&idx);
       if (idx == -1) {
@@ -9533,17 +9529,20 @@ nsDocShell::CreateContentViewer(const ns
   // performance over normal native event dispatch priorities.
   if (++gNumberOfDocumentsLoading == 1) {
     // Hint to favor performance for the plevent notification mechanism.
     // We want the pages to load as fast as possible even if its means
     // native messages might be starved.
     FavorPerformanceHint(true);
   }
 
-  if (onLocationChangeNeeded) {
+  if (errorOnLocationChangeNeeded){
+    FireOnLocationChange(this, failedChannel, failedURI,
+                         LOCATION_CHANGE_ERROR_PAGE);
+  } else if (onLocationChangeNeeded) {
     FireOnLocationChange(this, aRequest, mCurrentURI, 0);
   }
 
   return NS_OK;
 }
 
 nsresult
 nsDocShell::NewContentViewerObj(const nsACString& aContentType,
--- a/docshell/test/browser/browser_uriFixupAlternateRedirects.js
+++ b/docshell/test/browser/browser_uriFixupAlternateRedirects.js
@@ -11,14 +11,19 @@ add_task(async function() {
   await errorPageLoaded;
   let [contentURL, originalURL] = await ContentTask.spawn(tab.linkedBrowser, null, () => {
     return [
       content.document.documentURI,
       content.document.mozDocumentURIIfNotForErrorPages.spec,
     ];
   });
   info("Page that loaded: " + contentURL);
-  ok(contentURL.startsWith("about:neterror?"), "Should be on an error page");
+  const errorURI = "about:neterror?";
+  ok(contentURL.startsWith(errorURI), "Should be on an error page");
+
+  const contentPrincipal = tab.linkedBrowser.contentPrincipal;
+  ok(contentPrincipal.URI.spec.startsWith(errorURI), "Principal should be for the error page");
+
   originalURL = new URL(originalURL);
   is(originalURL.host, "example", "Should be an error for http://example, not http://www.example.com/");
 
   await BrowserTestUtils.removeTab(tab);
 });
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -975,16 +975,17 @@ nsIContent::GetEventTargetParent(EventCh
 {
   //FIXME! Document how this event retargeting works, Bug 329124.
   aVisitor.mCanHandle = true;
   aVisitor.mMayHaveListenerManager = HasListenerManager();
 
   // Don't propagate mouseover and mouseout events when mouse is moving
   // inside chrome access only content.
   bool isAnonForEvents = IsRootOfChromeAccessOnlySubtree();
+  aVisitor.mRootOfClosedTree = isAnonForEvents;
   if ((aVisitor.mEvent->mMessage == eMouseOver ||
        aVisitor.mEvent->mMessage == eMouseOut ||
        aVisitor.mEvent->mMessage == ePointerOver ||
        aVisitor.mEvent->mMessage == ePointerOut) &&
       // Check if we should stop event propagation when event has just been
       // dispatched or when we're about to propagate from
       // chrome access only subtree or if we are about to propagate out of
       // a shadow root to a shadow root host.
@@ -996,17 +997,17 @@ nsIContent::GetEventTargetParent(EventCh
         relatedTarget->OwnerDoc() == OwnerDoc()) {
 
       // In the web components case, we may need to stop propagation of events
       // at shadow root host.
       if (GetShadowRoot()) {
         nsIContent* adjustedTarget =
           Event::GetShadowRelatedTarget(this, relatedTarget);
         if (this == adjustedTarget) {
-          aVisitor.mParentTarget = nullptr;
+          aVisitor.SetParentTarget(nullptr, false);
           aVisitor.mCanHandle = false;
           return NS_OK;
         }
       }
 
       // If current target is anonymous for events or we know that related
       // target is descendant of an element which is anonymous for events,
       // we may want to stop event propagation.
@@ -1053,17 +1054,17 @@ nsIContent::GetEventTargetParent(EventCh
                      NS_ConvertUTF16toUTF8(rt).get(),
                      relatedTarget->ChromeOnlyAccess()
                        ? "(is in native anonymous subtree)" : "",
                      (originalTarget &&
                       relatedTarget->FindFirstNonChromeOnlyAccessContent() ==
                         originalTarget->FindFirstNonChromeOnlyAccessContent())
                        ? "" : "Wrong event propagation!?!\n");
 #endif
-              aVisitor.mParentTarget = nullptr;
+              aVisitor.SetParentTarget(nullptr, false);
               // Event should not propagate to non-anon content.
               aVisitor.mCanHandle = isAnonForEvents;
               return NS_OK;
             }
           }
         }
       }
     }
@@ -1105,21 +1106,27 @@ nsIContent::GetEventTargetParent(EventCh
     if (insertionParent) {
       parent = insertionParent;
     }
   }
 
   if (!aVisitor.mEvent->mFlags.mComposedInNativeAnonymousContent &&
       IsRootOfNativeAnonymousSubtree() && OwnerDoc() &&
       OwnerDoc()->GetWindow()) {
-    aVisitor.mParentTarget = OwnerDoc()->GetWindow()->GetParentTarget();
+    aVisitor.SetParentTarget(OwnerDoc()->GetWindow()->GetParentTarget(), true);
   } else if (parent) {
-    aVisitor.mParentTarget = parent;
+    aVisitor.SetParentTarget(parent, false);
+    if (slot) {
+      ShadowRoot* root = slot->GetContainingShadow();
+      if (root && root->IsClosed()) {
+        aVisitor.mParentIsSlotInClosedTree = true;
+      }
+    }
   } else {
-    aVisitor.mParentTarget = GetComposedDoc();
+    aVisitor.SetParentTarget(GetComposedDoc(), false);
   }
   return NS_OK;
 }
 
 bool
 nsIContent::GetAttr(int32_t aNameSpaceID, nsAtom* aName,
                     nsAString& aResult) const
 {
--- a/dom/base/ShadowRoot.cpp
+++ b/dom/base/ShadowRoot.cpp
@@ -302,37 +302,38 @@ ShadowRoot::GetElementsByClassName(const
 {
   return nsContentUtils::GetElementsByClassName(this, aClasses);
 }
 
 nsresult
 ShadowRoot::GetEventTargetParent(EventChainPreVisitor& aVisitor)
 {
   aVisitor.mCanHandle = true;
+  aVisitor.mRootOfClosedTree = IsClosed();
 
   // https://dom.spec.whatwg.org/#ref-for-get-the-parent%E2%91%A6
   if (!aVisitor.mEvent->mFlags.mComposed) {
     nsCOMPtr<nsIContent> originalTarget =
       do_QueryInterface(aVisitor.mEvent->mOriginalTarget);
     if (originalTarget->GetContainingShadow() == this) {
       // If we do stop propagation, we still want to propagate
       // the event to chrome (nsPIDOMWindow::GetParentTarget()).
       // The load event is special in that we don't ever propagate it
       // to chrome.
       nsCOMPtr<nsPIDOMWindowOuter> win = OwnerDoc()->GetWindow();
       EventTarget* parentTarget = win && aVisitor.mEvent->mMessage != eLoad
         ? win->GetParentTarget() : nullptr;
 
-      aVisitor.mParentTarget = parentTarget;
+      aVisitor.SetParentTarget(parentTarget, true);
       return NS_OK;
     }
   }
 
   nsIContent* shadowHost = GetHost();
-  aVisitor.mParentTarget = shadowHost;
+  aVisitor.SetParentTarget(shadowHost, false);
 
   if (aVisitor.mOriginalTargetIsInAnon) {
     nsCOMPtr<nsIContent> content(do_QueryInterface(aVisitor.mEvent->mTarget));
     if (content && content->GetBindingParent() == shadowHost) {
       aVisitor.mEventTargetAtParent = shadowHost;
     }
  }
 
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -8204,18 +8204,18 @@ nsDocument::GetEventTargetParent(EventCh
   aVisitor.mCanHandle = true;
    // FIXME! This is a hack to make middle mouse paste working also in Editor.
    // Bug 329119
   aVisitor.mForceContentDispatch = true;
 
   // Load events must not propagate to |window| object, see bug 335251.
   if (aVisitor.mEvent->mMessage != eLoad) {
     nsGlobalWindowOuter* window = nsGlobalWindowOuter::Cast(GetWindow());
-    aVisitor.mParentTarget =
-      window ? window->GetTargetForEventTargetChain() : nullptr;
+    aVisitor.SetParentTarget(
+      window ? window->GetTargetForEventTargetChain() : nullptr, false);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocument::CreateEvent(const nsAString& aEventType, nsIDOMEvent** aReturn)
 {
   NS_ENSURE_ARG_POINTER(aReturn);
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -1944,17 +1944,17 @@ nsGlobalWindowInner::GetEventTargetParen
         do_GetService("@mozilla.org/widget/dragservice;1");
       if (ds) {
         sDragServiceDisabled = false;
         ds->Unsuppress();
       }
     }
   }
 
-  aVisitor.mParentTarget = GetParentTarget();
+  aVisitor.SetParentTarget(GetParentTarget(), true);
 
   // Handle 'active' event.
   if (!mIdleObservers.IsEmpty() &&
       aVisitor.mEvent->IsTrusted() &&
       (aVisitor.mEvent->HasMouseEventMessage() ||
        aVisitor.mEvent->HasDragEventMessage())) {
     mAddActiveEventFuzzTime = false;
   }
--- a/dom/base/nsInProcessTabChildGlobal.cpp
+++ b/dom/base/nsInProcessTabChildGlobal.cpp
@@ -272,29 +272,31 @@ nsInProcessTabChildGlobal::GetEventTarge
                    "Wrong event target!");
       NS_ASSERTION(fl->mMessageManager == mChromeMessageManager,
                    "Wrong message manager!");
     }
   }
 #endif
 
   if (mPreventEventsEscaping) {
-    aVisitor.mParentTarget = nullptr;
+    aVisitor.SetParentTarget(nullptr, false);
     return NS_OK;
   }
 
   if (mIsBrowserFrame &&
       (!mOwner || !nsContentUtils::IsInChromeDocshell(mOwner->OwnerDoc()))) {
     if (mOwner) {
       if (nsPIDOMWindowInner* innerWindow = mOwner->OwnerDoc()->GetInnerWindow()) {
-        aVisitor.mParentTarget = innerWindow->GetParentTarget();
+        // 'this' is already a "chrome handler", so we consider window's
+        // parent target to be part of that same part of the event path.
+        aVisitor.SetParentTarget(innerWindow->GetParentTarget(), false);
       }
     }
   } else {
-    aVisitor.mParentTarget = mOwner;
+    aVisitor.SetParentTarget(mOwner, false);
   }
 
   return NS_OK;
 }
 
 nsresult
 nsInProcessTabChildGlobal::InitTabChildGlobal()
 {
--- a/dom/base/nsWindowRoot.cpp
+++ b/dom/base/nsWindowRoot.cpp
@@ -169,17 +169,17 @@ nsWindowRoot::GetContextForEventHandlers
 
 nsresult
 nsWindowRoot::GetEventTargetParent(EventChainPreVisitor& aVisitor)
 {
   aVisitor.mCanHandle = true;
   aVisitor.mForceContentDispatch = true; //FIXME! Bug 329119
   // To keep mWindow alive
   aVisitor.mItemData = static_cast<nsISupports *>(mWindow);
-  aVisitor.mParentTarget = mParent;
+  aVisitor.SetParentTarget(mParent, false);
   return NS_OK;
 }
 
 nsresult
 nsWindowRoot::PostHandleEvent(EventChainPostVisitor& aVisitor)
 {
   return NS_OK;
 }
--- a/dom/clients/manager/ClientOpenWindowUtils.cpp
+++ b/dom/clients/manager/ClientOpenWindowUtils.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ClientOpenWindowUtils.h"
 
 #include "ClientInfo.h"
 #include "ClientState.h"
+#include "mozilla/SystemGroup.h"
 #include "nsContentUtils.h"
 #include "nsIBrowserDOMWindow.h"
 #include "nsIDocShell.h"
 #include "nsIDOMChromeWindow.h"
 #include "nsIURI.h"
 #include "nsIWebProgress.h"
 #include "nsIWebProgressListener.h"
 #include "nsIWindowWatcher.h"
@@ -420,17 +421,17 @@ ClientOpenWindowInCurrentProcess(const C
   nsresult rv = OpenWindow(aArgs, getter_AddRefs(outerWindow));
 
 #ifdef MOZ_WIDGET_ANDROID
   // If we get the NOT_AVAILABLE error that means the browser is still
   // launching on android.  Use the observer we created above to wait
   // until the launch completes and then try to open the window again.
   if (rv == NS_ERROR_NOT_AVAILABLE && launchObserver) {
     RefPtr<GenericPromise> p = launchObserver->Promise();
-    p->Then(outerWindow->EventTargetFor(TaskCategory::Other), __func__,
+    p->Then(SystemGroup::EventTargetFor(TaskCategory::Other), __func__,
       [aArgs, promise] (bool aResult) {
         nsCOMPtr<nsPIDOMWindowOuter> outerWindow;
         nsresult rv = OpenWindow(aArgs, getter_AddRefs(outerWindow));
         if (NS_WARN_IF(NS_FAILED(rv))) {
           promise->Reject(rv, __func__);
         }
 
         WaitForLoad(aArgs, outerWindow, promise);
--- a/dom/events/DOMEventTargetHelper.cpp
+++ b/dom/events/DOMEventTargetHelper.cpp
@@ -302,17 +302,17 @@ DOMEventTargetHelper::DispatchTrustedEve
   bool dummy;
   return DispatchEvent(event, &dummy);
 }
 
 nsresult
 DOMEventTargetHelper::GetEventTargetParent(EventChainPreVisitor& aVisitor)
 {
   aVisitor.mCanHandle = true;
-  aVisitor.mParentTarget = nullptr;
+  aVisitor.SetParentTarget(nullptr, false);
   return NS_OK;
 }
 
 nsresult
 DOMEventTargetHelper::PostHandleEvent(EventChainPostVisitor& aVisitor)
 {
   return NS_OK;
 }
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -268,16 +268,22 @@ Event::GetTarget(nsIDOMEventTarget** aTa
 }
 
 EventTarget*
 Event::GetCurrentTarget() const
 {
   return mEvent->GetCurrentDOMEventTarget();
 }
 
+void
+Event::ComposedPath(nsTArray<RefPtr<EventTarget>>& aPath)
+{
+  EventDispatcher::GetComposedPathFor(mEvent, aPath);
+}
+
 NS_IMETHODIMP
 Event::GetCurrentTarget(nsIDOMEventTarget** aCurrentTarget)
 {
   NS_IF_ADDREF(*aCurrentTarget = GetCurrentTarget());
   return NS_OK;
 }
 
 //
--- a/dom/events/Event.h
+++ b/dom/events/Event.h
@@ -153,16 +153,18 @@ public:
                                              ErrorResult& aRv);
 
   // Implemented as xpidl method
   // void GetType(nsString& aRetval) {}
 
   EventTarget* GetTarget() const;
   EventTarget* GetCurrentTarget() const;
 
+  void ComposedPath(nsTArray<RefPtr<EventTarget>>& aPath);
+
   uint16_t EventPhase() const;
 
   // xpidl implementation
   // void StopPropagation();
 
   // xpidl implementation
   // void StopImmediatePropagation();
 
--- a/dom/events/EventDispatcher.cpp
+++ b/dom/events/EventDispatcher.cpp
@@ -241,16 +241,46 @@ public:
     mFlags.mPreHandleEventOnly = aWants;
   }
 
   bool PreHandleEventOnly()
   {
     return mFlags.mPreHandleEventOnly;
   }
 
+  void SetRootOfClosedTree(bool aSet)
+  {
+    mFlags.mRootOfClosedTree = aSet;
+  }
+
+  bool IsRootOfClosedTree()
+  {
+    return mFlags.mRootOfClosedTree;
+  }
+
+  void SetIsSlotInClosedTree(bool aSet)
+  {
+    mFlags.mIsSlotInClosedTree = aSet;
+  }
+
+  bool IsSlotInClosedTree()
+  {
+    return mFlags.mIsSlotInClosedTree;
+  }
+
+  void SetIsChromeHandler(bool aSet)
+  {
+    mFlags.mIsChromeHandler = aSet;
+  }
+
+  bool IsChromeHandler()
+  {
+    return mFlags.mIsChromeHandler;
+  }
+
   void SetMayHaveListenerManager(bool aMayHave)
   {
     mFlags.mMayHaveManager = aMayHave;
   }
 
   bool MayHaveListenerManager()
   {
     return mFlags.mMayHaveManager;
@@ -339,16 +369,19 @@ private:
     // manage or speedup event dispatching.
     bool mForceContentDispatch : 1;
     bool mWantsWillHandleEvent : 1;
     bool mMayHaveManager : 1;
     bool mChechedIfChrome : 1;
     bool mIsChromeContent : 1;
     bool mWantsPreHandleEvent : 1;
     bool mPreHandleEventOnly : 1;
+    bool mRootOfClosedTree : 1;
+    bool mIsSlotInClosedTree : 1;
+    bool mIsChromeHandler : 1;
   private:
     typedef uint32_t RawFlags;
     void SetRawFlags(RawFlags aRawFlags)
     {
       static_assert(sizeof(EventTargetChainFlags) <= sizeof(RawFlags),
         "EventTargetChainFlags must not be bigger than the RawFlags");
       memcpy(this, &aRawFlags, sizeof(EventTargetChainFlags));
     }
@@ -385,16 +418,17 @@ EventTargetChainItem::GetEventTargetPare
 {
   aVisitor.Reset();
   Unused << mTarget->GetEventTargetParent(aVisitor);
   SetForceContentDispatch(aVisitor.mForceContentDispatch);
   SetWantsWillHandleEvent(aVisitor.mWantsWillHandleEvent);
   SetMayHaveListenerManager(aVisitor.mMayHaveListenerManager);
   SetWantsPreHandleEvent(aVisitor.mWantsPreHandleEvent);
   SetPreHandleEventOnly(aVisitor.mWantsPreHandleEvent && !aVisitor.mCanHandle);
+  SetRootOfClosedTree(aVisitor.mRootOfClosedTree);
   mItemFlags = aVisitor.mItemFlags;
   mItemData = aVisitor.mItemData;
 }
 
 void
 EventTargetChainItem::PreHandleEvent(EventChainVisitor& aVisitor)
 {
   if (!WantsPreHandleEvent()) {
@@ -765,26 +799,29 @@ EventDispatcher::Dispatch(nsISupports* a
     }
   } else {
     // At least the original target can handle the event.
     // Setting the retarget to the |target| simplifies retargeting code.
     nsCOMPtr<EventTarget> t = do_QueryInterface(aEvent->mTarget);
     targetEtci->SetNewTarget(t);
     EventTargetChainItem* topEtci = targetEtci;
     targetEtci = nullptr;
-    while (preVisitor.mParentTarget) {
-      EventTarget* parentTarget = preVisitor.mParentTarget;
+    while (preVisitor.GetParentTarget()) {
+      EventTarget* parentTarget = preVisitor.GetParentTarget();
       EventTargetChainItem* parentEtci =
-        EventTargetChainItem::Create(chain, preVisitor.mParentTarget, topEtci);
+        EventTargetChainItem::Create(chain, parentTarget, topEtci);
       if (!parentEtci->IsValid()) {
         EventTargetChainItem::DestroyLast(chain, parentEtci);
         rv = NS_ERROR_FAILURE;
         break;
       }
 
+      parentEtci->SetIsSlotInClosedTree(preVisitor.mParentIsSlotInClosedTree);
+      parentEtci->SetIsChromeHandler(preVisitor.mParentIsChromeHandler);
+
       // Item needs event retargetting.
       if (preVisitor.mEventTargetAtParent) {
         // Need to set the target of the event
         // so that also the next retargeting works.
         preVisitor.mEvent->mTarget = preVisitor.mEventTargetAtParent;
         parentEtci->SetNewTarget(preVisitor.mEventTargetAtParent);
       }
 
@@ -818,18 +855,21 @@ EventDispatcher::Dispatch(nsISupports* a
         }
       } else {
         // Event target chain is created. PreHandle the chain.
         for (uint32_t i = 0; i < chain.Length(); ++i) {
           chain[i].PreHandleEvent(preVisitor);
         }
         // Handle the chain.
         EventChainPostVisitor postVisitor(preVisitor);
+        MOZ_RELEASE_ASSERT(!aEvent->mPath);
+        aEvent->mPath = &chain;
         EventTargetChainItem::HandleEventTargetChain(chain, postVisitor,
                                                      aCallback, cd);
+        aEvent->mPath = nullptr;
 
         preVisitor.mEventStatus = postVisitor.mEventStatus;
         // If the DOM event was created during event flow.
         if (!preVisitor.mDOMEvent && postVisitor.mDOMEvent) {
           preVisitor.mDOMEvent = postVisitor.mDOMEvent;
         }
       }
     }
@@ -1112,9 +1152,69 @@ EventDispatcher::CreateEvent(EventTarget
 #undef LOG_EVENT_CREATION
 
   // NEW EVENT TYPES SHOULD NOT BE ADDED HERE; THEY SHOULD USE ONLY EVENT
   // CONSTRUCTORS
 
   return nullptr;
 }
 
+// static
+void
+EventDispatcher::GetComposedPathFor(WidgetEvent* aEvent,
+                                    nsTArray<RefPtr<EventTarget>>& aPath)
+{
+  nsTArray<EventTargetChainItem>* path = aEvent->mPath;
+  if (!path || path->IsEmpty() || !aEvent->mCurrentTarget) {
+    return;
+  }
+
+  EventTarget* currentTarget =
+    aEvent->mCurrentTarget->GetTargetForEventTargetChain();
+  if (!currentTarget) {
+    return;
+  }
+
+  AutoTArray<EventTarget*, 128> reversedComposedPath;
+  bool hasSeenCurrentTarget = false;
+  uint32_t hiddenSubtreeLevel = 0;
+  for (uint32_t i = path->Length(); i; ) {
+    --i;
+
+    EventTargetChainItem& item = path->ElementAt(i);
+    if (item.PreHandleEventOnly()) {
+      continue;
+    }
+
+    if (!hasSeenCurrentTarget && currentTarget == item.CurrentTarget()) {
+      hasSeenCurrentTarget = true;
+    } else if (hasSeenCurrentTarget && item.IsRootOfClosedTree()) {
+      ++hiddenSubtreeLevel;
+    }
+
+    if (hiddenSubtreeLevel == 0) {
+      reversedComposedPath.AppendElement(item.CurrentTarget());
+    }
+
+    if (item.IsSlotInClosedTree() && hiddenSubtreeLevel > 0) {
+      --hiddenSubtreeLevel;
+    }
+
+    if (item.IsChromeHandler()) {
+      if (hasSeenCurrentTarget) {
+        // The current behavior is to include only EventTargets from
+        // either chrome side of event path or content side, not from both.
+        break;
+      }
+
+      // Need to start all over to collect the composed path on content side.
+      reversedComposedPath.Clear();
+    }
+  }
+
+  aPath.SetCapacity(reversedComposedPath.Length());
+  for (uint32_t i = reversedComposedPath.Length(); i; ) {
+    --i;
+    aPath.AppendElement(reversedComposedPath[i]->GetTargetForDOMEvent());
+  }
+}
+
 } // namespace mozilla
--- a/dom/events/EventDispatcher.h
+++ b/dom/events/EventDispatcher.h
@@ -120,35 +120,54 @@ public:
     , mCanHandle(true)
     , mAutomaticChromeDispatch(true)
     , mForceContentDispatch(false)
     , mRelatedTargetIsInAnon(false)
     , mOriginalTargetIsInAnon(aIsInAnon)
     , mWantsWillHandleEvent(false)
     , mMayHaveListenerManager(true)
     , mWantsPreHandleEvent(false)
+    , mRootOfClosedTree(false)
+    , mParentIsSlotInClosedTree(false)
+    , mParentIsChromeHandler(false)
     , mParentTarget(nullptr)
     , mEventTargetAtParent(nullptr)
   {
   }
 
   void Reset()
   {
     mItemFlags = 0;
     mItemData = nullptr;
     mCanHandle = true;
     mAutomaticChromeDispatch = true;
     mForceContentDispatch = false;
     mWantsWillHandleEvent = false;
     mMayHaveListenerManager = true;
     mWantsPreHandleEvent = false;
+    mRootOfClosedTree = false;
+    mParentIsSlotInClosedTree = false;
+    mParentIsChromeHandler = false;
     mParentTarget = nullptr;
     mEventTargetAtParent = nullptr;
   }
 
+  dom::EventTarget* GetParentTarget()
+  {
+    return mParentTarget;
+  }
+
+  void SetParentTarget(dom::EventTarget* aParentTarget, bool aIsChromeHandler)
+  {
+    mParentTarget = aParentTarget;
+    if (mParentTarget) {
+      mParentIsChromeHandler = aIsChromeHandler;
+    }
+  }
+
   /**
    * Member that must be set in GetEventTargetParent by event targets. If set to
    * false, indicates that this event target will not be handling the event and
    * construction of the event target chain is complete. The target that sets
    * mCanHandle to false is NOT included in the event target chain.
    */
   bool                  mCanHandle;
 
@@ -191,20 +210,39 @@ public:
 
   /**
    * Whether or not nsIDOMEventTarget::PreHandleEvent will be called. Default is
    * false;
    */
   bool mWantsPreHandleEvent;
 
   /**
+   * True if the current target is either closed ShadowRoot or root of
+   * chrome only access tree (for example native anonymous content).
+   */
+  bool mRootOfClosedTree;
+
+  /**
+   * True if mParentTarget is HTMLSlotElement in a closed shadow tree and the
+   * current target is assigned to that slot.
+   */
+  bool mParentIsSlotInClosedTree;
+
+  /**
+   * True if mParentTarget is a chrome handler in the event path.
+   */
+  bool mParentIsChromeHandler;
+
+private:
+  /**
    * Parent item in the event target chain.
    */
   dom::EventTarget* mParentTarget;
 
+public:
   /**
    * If the event needs to be retargeted, this is the event target,
    * which should be used when the event is handled at mParentTarget.
    */
   dom::EventTarget* mEventTargetAtParent;
 };
 
 class EventChainPostVisitor : public mozilla::EventChainVisitor
@@ -279,16 +317,19 @@ public:
    */
   static already_AddRefed<dom::Event> CreateEvent(dom::EventTarget* aOwner,
                                                   nsPresContext* aPresContext,
                                                   WidgetEvent* aEvent,
                                                   const nsAString& aEventType,
                                                   dom::CallerType aCallerType =
                                                     dom::CallerType::System);
 
+  static void GetComposedPathFor(WidgetEvent* aEvent,
+                                 nsTArray<RefPtr<dom::EventTarget>>& aPath);
+
   /**
    * Called at shutting down.
    */
   static void Shutdown();
 };
 
 } // namespace mozilla
 
--- a/dom/events/PointerEvent.cpp
+++ b/dom/events/PointerEvent.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * Portions Copyright 2013 Microsoft Open Technologies, Inc. */
 
 #include "mozilla/dom/PointerEvent.h"
+#include "mozilla/dom/PointerEventBinding.h"
 #include "mozilla/MouseEvents.h"
 #include "prtime.h"
 
 namespace mozilla {
 namespace dom {
 
 PointerEvent::PointerEvent(EventTarget* aOwner,
                            nsPresContext* aPresContext,
@@ -32,16 +33,23 @@ PointerEvent::PointerEvent(EventTarget* 
     mEvent->mRefPoint = LayoutDeviceIntPoint(0, 0);
     mouseEvent->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
   }
   // 5.2 Pointer Event types, for all pointer events, |detail| attribute SHOULD
   // be 0.
   mDetail = 0;
 }
 
+JSObject*
+PointerEvent::WrapObjectInternal(JSContext* aCx,
+                                 JS::Handle<JSObject*> aGivenProto)
+{
+  return PointerEventBinding::Wrap(aCx, this, aGivenProto);
+}
+
 static uint16_t
 ConvertStringToPointerType(const nsAString& aPointerTypeArg)
 {
   if (aPointerTypeArg.EqualsLiteral("mouse")) {
     return nsIDOMMouseEvent::MOZ_SOURCE_MOUSE;
   }
   if (aPointerTypeArg.EqualsLiteral("pen")) {
     return nsIDOMMouseEvent::MOZ_SOURCE_PEN;
@@ -96,32 +104,51 @@ PointerEvent::Constructor(EventTarget* a
   widgetEvent->tangentialPressure = aParam.mTangentialPressure;
   widgetEvent->tiltX = aParam.mTiltX;
   widgetEvent->tiltY = aParam.mTiltY;
   widgetEvent->twist = aParam.mTwist;
   widgetEvent->inputSource = ConvertStringToPointerType(aParam.mPointerType);
   widgetEvent->mIsPrimary = aParam.mIsPrimary;
   widgetEvent->buttons = aParam.mButtons;
 
+  if (!aParam.mCoalescedEvents.IsEmpty()) {
+    e->mCoalescedEvents.AppendElements(aParam.mCoalescedEvents);
+  }
   e->SetTrusted(trusted);
   e->SetComposed(aParam.mComposed);
   return e.forget();
 }
 
 // static
 already_AddRefed<PointerEvent>
 PointerEvent::Constructor(const GlobalObject& aGlobal,
                           const nsAString& aType,
                           const PointerEventInit& aParam,
                           ErrorResult& aRv)
 {
   nsCOMPtr<EventTarget> owner = do_QueryInterface(aGlobal.GetAsSupports());
   return Constructor(owner, aType, aParam);
 }
 
+NS_IMPL_CYCLE_COLLECTION_CLASS(PointerEvent)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PointerEvent, MouseEvent)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mCoalescedEvents)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PointerEvent, MouseEvent)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCoalescedEvents)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PointerEvent)
+NS_INTERFACE_MAP_END_INHERITING(MouseEvent)
+
+NS_IMPL_ADDREF_INHERITED(PointerEvent, MouseEvent)
+NS_IMPL_RELEASE_INHERITED(PointerEvent, MouseEvent)
+
 void
 PointerEvent::GetPointerType(nsAString& aPointerType)
 {
   ConvertPointerTypeToString(mEvent->AsPointerEvent()->inputSource, aPointerType);
 }
 
 int32_t
 PointerEvent::PointerId()
@@ -172,16 +199,60 @@ PointerEvent::Twist()
 }
 
 bool
 PointerEvent::IsPrimary()
 {
   return mEvent->AsPointerEvent()->mIsPrimary;
 }
 
+void
+PointerEvent::GetCoalescedEvents(nsTArray<RefPtr<PointerEvent>>& aPointerEvents)
+{
+  WidgetPointerEvent* widgetEvent = mEvent->AsPointerEvent();
+  if (mCoalescedEvents.IsEmpty() && widgetEvent &&
+      widgetEvent->mCoalescedWidgetEvents &&
+      !widgetEvent->mCoalescedWidgetEvents->mEvents.IsEmpty()) {
+    for (WidgetPointerEvent& event :
+         widgetEvent->mCoalescedWidgetEvents->mEvents) {
+      RefPtr<PointerEvent> domEvent =
+        NS_NewDOMPointerEvent(nullptr, nullptr, &event);
+
+      // The dom event is derived from an OS generated widget event. Setup
+      // mWidget and mPresContext since they are necessary to calculate
+      // offsetX / offsetY.
+      domEvent->mEvent->AsGUIEvent()->mWidget = widgetEvent->mWidget;
+      domEvent->mPresContext = mPresContext;
+
+      // The coalesced widget mouse events shouldn't have been dispatched.
+      MOZ_ASSERT(!domEvent->mEvent->mTarget);
+      // The event target should be the same as the dispatched event's target.
+      domEvent->mEvent->mTarget = mEvent->mTarget;
+
+      // JS could hold reference to dom events. We have to ask dom event to
+      // duplicate its private data to avoid the widget event is destroyed.
+      domEvent->DuplicatePrivateData();
+
+      // Setup mPresContext again after DuplicatePrivateData since it clears
+      // mPresContext.
+      domEvent->mPresContext = mPresContext;
+      mCoalescedEvents.AppendElement(domEvent);
+    }
+  }
+  if (mEvent->mTarget) {
+    for (RefPtr<PointerEvent>& pointerEvent : mCoalescedEvents) {
+      // Only set event target when it's null.
+      if (!pointerEvent->mEvent->mTarget) {
+        pointerEvent->mEvent->mTarget = mEvent->mTarget;
+      }
+    }
+  }
+  aPointerEvents.AppendElements(mCoalescedEvents);
+}
+
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 already_AddRefed<PointerEvent>
 NS_NewDOMPointerEvent(EventTarget* aOwner,
--- a/dom/events/PointerEvent.h
+++ b/dom/events/PointerEvent.h
@@ -12,27 +12,31 @@
 #include "mozilla/dom/MouseEvent.h"
 #include "mozilla/dom/PointerEventBinding.h"
 
 class nsPresContext;
 
 namespace mozilla {
 namespace dom {
 
+struct PointerEventInit;
+
 class PointerEvent : public MouseEvent
 {
 public:
   PointerEvent(EventTarget* aOwner,
                nsPresContext* aPresContext,
                WidgetPointerEvent* aEvent);
 
-  virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
-  {
-    return PointerEventBinding::Wrap(aCx, this, aGivenProto);
-  }
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PointerEvent, MouseEvent)
+
+  virtual JSObject* WrapObjectInternal(
+                      JSContext* aCx,
+                      JS::Handle<JSObject*> aGivenProto) override;
 
   static already_AddRefed<PointerEvent>
   Constructor(const GlobalObject& aGlobal,
               const nsAString& aType,
               const PointerEventInit& aParam,
               ErrorResult& aRv);
 
   static already_AddRefed<PointerEvent>
@@ -45,16 +49,23 @@ public:
   int32_t Height();
   float Pressure();
   float TangentialPressure();
   int32_t TiltX();
   int32_t TiltY();
   int32_t Twist();
   bool IsPrimary();
   void GetPointerType(nsAString& aPointerType);
+  void GetCoalescedEvents(nsTArray<RefPtr<PointerEvent>>& aPointerEvents);
+
+protected:
+  ~PointerEvent() {}
+
+private:
+  nsTArray<RefPtr<PointerEvent>> mCoalescedEvents;
 };
 
 void ConvertPointerTypeToString(uint16_t aPointerTypeSrc, nsAString& aPointerTypeDest);
 
 } // namespace dom
 } // namespace mozilla
 
 already_AddRefed<mozilla::dom::PointerEvent>
--- a/dom/events/test/chrome.ini
+++ b/dom/events/test/chrome.ini
@@ -3,25 +3,27 @@ skip-if = os == 'android'
 support-files =
   bug415498-doc1.html
   bug415498-doc2.html
   bug418986-3.js
   bug591249_iframe.xul
   bug602962.xul
   file_bug679494.html
   window_bug617528.xul
+  window_bug1412775.xul
   test_bug336682.js
 
 [test_bug336682_2.xul]
 [test_bug415498.xul]
 [test_bug418986-3.xul]
 [test_bug524674.xul]
 [test_bug586961.xul]
 [test_bug591249.xul]
 [test_bug602962.xul]
 [test_bug617528.xul]
 [test_bug679494.xul]
 [test_bug930374-chrome.html]
 [test_bug1128787-1.html]
 [test_bug1128787-2.html]
 [test_bug1128787-3.html]
+[test_bug1412775.xul]
 [test_eventctors.xul]
 [test_DataTransferItemList.html]
--- a/dom/events/test/pointerevents/mochitest.ini
+++ b/dom/events/test/pointerevents/mochitest.ini
@@ -130,8 +130,12 @@ support-files =
     pointerevent_touch-action-pan-down-css_touch-manual.html
     pointerevent_touch-action-pan-left-css_touch-manual.html
     pointerevent_touch-action-pan-right-css_touch-manual.html
     pointerevent_touch-action-pan-up-css_touch-manual.html
 [test_trigger_fullscreen_by_pointer_events.html]
   support-files =
     file_test_trigger_fullscreen.html
 [test_trigger_popup_by_pointer_events.html]
+[test_getCoalescedEvents.html]
+  skip-if = !e10s
+  support-files =
+    ../../../../gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js
new file mode 100644
--- /dev/null
+++ b/dom/events/test/pointerevents/test_getCoalescedEvents.html
@@ -0,0 +1,93 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1303957
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1303957</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="apz_test_native_event_utils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1303957">Mozilla Bug 1303957</a>
+<p id="display"></p>
+<div id="target0" style="width: 50px; height: 50px; background: green"></div>
+<script type="text/javascript">
+/** Test for Bug 1303957 **/
+SimpleTest.waitForExplicitFinish();
+
+function runTests() {
+  let target0 = window.document.getElementById("target0");
+  let utils = SpecialPowers.getDOMWindowUtils(window);
+  utils.advanceTimeAndRefresh(0);
+
+  SimpleTest.executeSoon(() => {
+    // Flush all pending mouse events before synthesizing events.
+
+    target0.addEventListener("pointermove", (ev) => {
+      let length = ev.getCoalescedEvents().length;
+      ok(length >= 1, "Coalesced events should >= 1, got " + length);
+
+      let rect = target0.getBoundingClientRect();
+      let prevOffsetX = 0;
+      let prevOffsetY = 0;
+
+      for (let i = 0; i < length; ++i) {
+        let coalescedEvent = ev.getCoalescedEvents()[i];
+        is(coalescedEvent.pointerId, ev.pointerId, "getCoalescedEvents()[" + i + "].pointerId");
+        is(coalescedEvent.pointerType, ev.pointerType, "getCoalescedEvents()[" + i + "].pointerType");
+        is(coalescedEvent.isPrimary, ev.isPrimary, "getCoalescedEvents()[" + i + "].isPrimary");
+        is(coalescedEvent.target, ev.target, "getCoalescedEvents()[" + i + "].target");
+        is(coalescedEvent.currentTarget, null, "getCoalescedEvents()[" + i + "].currentTarget");
+        is(coalescedEvent.eventPhase, Event.NONE, "getCoalescedEvents()[" + i + "].eventPhase");
+        is(coalescedEvent.cancelable, false, "getCoalescedEvents()[" + i + "].cancelable");
+        is(coalescedEvent.bubbles, false, "getCoalescedEvents()[" + i + "].bubbles");
+
+        let offsetX = 20 - (length - i - 1) * 5;
+        let offsetY = 20 - (length - i - 1) * 5;
+        ok(coalescedEvent.offsetX > prevOffsetX, "getCoalescedEvents()[" + i + "].offsetX = " + coalescedEvent.offsetX);
+        ok(coalescedEvent.offsetX == 5 || coalescedEvent.offsetX == 10 ||
+           coalescedEvent.offsetX == 15 || coalescedEvent.offsetX == 20, "expected offsetX");
+
+        ok(coalescedEvent.offsetY > prevOffsetY, "getCoalescedEvents()[" + i + "].offsetY = " + coalescedEvent.offsetY);
+        ok(coalescedEvent.offsetY == 5 || coalescedEvent.offsetY == 10 ||
+           coalescedEvent.offsetY == 15 || coalescedEvent.offsetY == 20, "expected offsetY");
+
+        prevOffsetX = coalescedEvent.offsetX;
+        prevOffsetY = coalescedEvent.offsetY;
+
+        let x = rect.left + prevOffsetX;
+        let y = rect.top + prevOffsetY;
+        // coordinates may change slightly due to rounding
+        ok((coalescedEvent.clientX <= x+2) && (coalescedEvent.clientX >= x-2), "getCoalescedEvents()[" + i + "].clientX");
+        ok((coalescedEvent.clientY <= y+2) && (coalescedEvent.clientY >= y-2), "getCoalescedEvents()[" + i + "].clientY");
+      }
+    }, { once: true });
+
+    target0.addEventListener("pointerup", (ev) => {
+      utils.restoreNormalRefresh();
+      SimpleTest.finish();
+    }, { once: true });
+
+    synthesizeNativeMouseEvent(target0, 5, 5, nativeMouseMoveEventMsg(), () => {
+      synthesizeNativeMouseEvent(target0, 10, 10, nativeMouseMoveEventMsg(), () => {
+        synthesizeNativeMouseEvent(target0, 15, 15, nativeMouseMoveEventMsg(), () => {
+          synthesizeNativeMouseEvent(target0, 20, 20, nativeMouseMoveEventMsg(), () => {
+            synthesizeNativeClick(target0, 20, 20);
+          });
+        });
+      });
+    });
+  });
+}
+
+SimpleTest.waitForFocus(() => {
+  SpecialPowers.pushPrefEnv({"set": [["dom.w3c_pointer_events.enabled", true],
+                                     ["dom.event.coalesce_mouse_move", true]]}, runTests);
+});
+
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/events/test/test_bug1412775.xul
@@ -0,0 +1,71 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1412775
+-->
+<window title="Mozilla Bug 1412775"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="init()">
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/chrome-harness.js"></script>
+
+  <!-- test code goes here -->
+  <script type="application/javascript">
+  <![CDATA[
+
+  /** Test for Bug 1412775 **/
+  const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+
+  var win;
+  function init() {
+    SimpleTest.waitForExplicitFinish();
+    win = window.open("window_bug1412775.xul", "_new", "chrome");
+    win.onload = function() {
+      var b = win.document.getElementById("browser");
+      var d = b.contentWindow.document;
+      var e = new d.defaultView.Event("foo");
+      var didCallChromeSide = false;
+      var didCallContentSide = false;
+      b.addEventListener("foo", function(e) {
+        didCallChromeSide = true;
+        var path = e.composedPath();
+        var mm = d.defaultView.QueryInterface(Ci.nsIInterfaceRequestor)
+                              .getInterface(Ci.nsIWebNavigation)
+                              .QueryInterface(Ci.nsIInterfaceRequestor)
+                              .getInterface(Ci.nsIContentFrameMessageManager);
+        is(path.length, 5, "Should have 5 items in composedPath in chrome.");
+        is(path[0], mm, "TabChildGlobal is the chrome handler.");
+        is(path[1], b, "browser element should be in the path.");
+        is(path[2], b.parentNode, "window element should be in the path.");
+        is(path[3], win.document, "Document object should be in the path.");
+        is(path[4], win, "Window object should be in the path.");
+      }, true, true);
+      d.addEventListener("foo", function(e) {
+        didCallContentSide = true;;
+        var path = e.composedPath();
+        is(path.length, 4, "Should have 4 items in composedPath in content.");
+        is(path[0], d.body, "body element should be in the path.");
+        is(path[1], d.documentElement, "html element should be in the path.");
+        is(path[2], d, "Document object should be in the path.");
+        is(path[3], d.defaultView, "Window object should be in the path.");
+      }, true, true);
+      d.body.dispatchEvent(e);
+      ok(didCallChromeSide, "didCallChromeSide");
+      ok(didCallContentSide, "didCallContentSide");
+      win.close();
+      SimpleTest.finish();
+    }
+  }
+
+  ]]>
+  </script>
+
+  <!-- test results are displayed in the html:body -->
+  <body xmlns="http://www.w3.org/1999/xhtml">
+  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1412775"
+     target="_blank">Mozilla Bug 1412775</a>
+  </body>
+</window>
new file mode 100644
--- /dev/null
+++ b/dom/events/test/window_bug1412775.xul
@@ -0,0 +1,8 @@
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        width="640" height="480">
+
+  <browser id="browser" type="content" primary="true" flex="1" src="about:blank"/>
+
+</window>
--- a/dom/indexedDB/IDBFileHandle.cpp
+++ b/dom/indexedDB/IDBFileHandle.cpp
@@ -781,17 +781,17 @@ IDBFileHandle::Run()
 }
 
 nsresult
 IDBFileHandle::GetEventTargetParent(EventChainPreVisitor& aVisitor)
 {
   AssertIsOnOwningThread();
 
   aVisitor.mCanHandle = true;
-  aVisitor.mParentTarget = mMutableFile;
+  aVisitor.SetParentTarget(mMutableFile, false);
   return NS_OK;
 }
 
 // virtual
 JSObject*
 IDBFileHandle::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   AssertIsOnOwningThread();
--- a/dom/indexedDB/IDBFileRequest.cpp
+++ b/dom/indexedDB/IDBFileRequest.cpp
@@ -108,17 +108,17 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(IDBFi
                                    mFileHandle)
 
 nsresult
 IDBFileRequest::GetEventTargetParent(EventChainPreVisitor& aVisitor)
 {
   AssertIsOnOwningThread();
 
   aVisitor.mCanHandle = true;
-  aVisitor.mParentTarget = mFileHandle;
+  aVisitor.SetParentTarget(mFileHandle, false);
   return NS_OK;
 }
 
 // virtual
 JSObject*
 IDBFileRequest::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   AssertIsOnOwningThread();
--- a/dom/indexedDB/IDBRequest.cpp
+++ b/dom/indexedDB/IDBRequest.cpp
@@ -406,17 +406,17 @@ NS_IMPL_ADDREF_INHERITED(IDBRequest, IDB
 NS_IMPL_RELEASE_INHERITED(IDBRequest, IDBWrapperCache)
 
 nsresult
 IDBRequest::GetEventTargetParent(EventChainPreVisitor& aVisitor)
 {
   AssertIsOnOwningThread();
 
   aVisitor.mCanHandle = true;
-  aVisitor.mParentTarget = mTransaction;
+  aVisitor.SetParentTarget(mTransaction, false);
   return NS_OK;
 }
 
 class IDBOpenDBRequest::WorkerHolder final
   : public mozilla::dom::workers::WorkerHolder
 {
   WorkerPrivate* mWorkerPrivate;
 #ifdef DEBUG
--- a/dom/indexedDB/IDBTransaction.cpp
+++ b/dom/indexedDB/IDBTransaction.cpp
@@ -1049,17 +1049,17 @@ IDBTransaction::WrapObject(JSContext* aC
 }
 
 nsresult
 IDBTransaction::GetEventTargetParent(EventChainPreVisitor& aVisitor)
 {
   AssertIsOnOwningThread();
 
   aVisitor.mCanHandle = true;
-  aVisitor.mParentTarget = mDatabase;
+  aVisitor.SetParentTarget(mDatabase, false);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBTransaction::Run()
 {
   AssertIsOnOwningThread();
 
--- a/dom/ipc/CoalescedMouseData.cpp
+++ b/dom/ipc/CoalescedMouseData.cpp
@@ -15,36 +15,54 @@ void
 CoalescedMouseData::Coalesce(const WidgetMouseEvent& aEvent,
                              const ScrollableLayerGuid& aGuid,
                              const uint64_t& aInputBlockId)
 {
   if (IsEmpty()) {
     mCoalescedInputEvent = MakeUnique<WidgetMouseEvent>(aEvent);
     mGuid = aGuid;
     mInputBlockId = aInputBlockId;
+    MOZ_ASSERT(!mCoalescedInputEvent->mCoalescedWidgetEvents);
   } else {
     MOZ_ASSERT(mGuid == aGuid);
     MOZ_ASSERT(mInputBlockId == aInputBlockId);
     MOZ_ASSERT(mCoalescedInputEvent->mModifiers == aEvent.mModifiers);
     MOZ_ASSERT(mCoalescedInputEvent->mReason == aEvent.mReason);
     MOZ_ASSERT(mCoalescedInputEvent->inputSource == aEvent.inputSource);
     MOZ_ASSERT(mCoalescedInputEvent->button == aEvent.button);
     MOZ_ASSERT(mCoalescedInputEvent->buttons == aEvent.buttons);
     mCoalescedInputEvent->mTimeStamp = aEvent.mTimeStamp;
     mCoalescedInputEvent->mRefPoint = aEvent.mRefPoint;
     mCoalescedInputEvent->pressure = aEvent.pressure;
     mCoalescedInputEvent->AssignPointerHelperData(aEvent);
   }
+
+  if (aEvent.mMessage == eMouseMove &&
+      PointerEventHandler::IsPointerEventEnabled()) {
+    // PointerEvent::getCoalescedEvents is only applied to pointermove events.
+    if (!mCoalescedInputEvent->mCoalescedWidgetEvents) {
+      mCoalescedInputEvent->mCoalescedWidgetEvents =
+        new WidgetPointerEventHolder();
+    }
+    // Append current event in mCoalescedWidgetEvents. We use them to generate
+    // DOM events when content calls PointerEvent::getCoalescedEvents.
+    WidgetPointerEvent* event = mCoalescedInputEvent->mCoalescedWidgetEvents
+                                  ->mEvents.AppendElement(aEvent);
+
+    event->mFlags.mBubbles = false;
+    event->mFlags.mCancelable = false;
+  }
 }
 
 bool
 CoalescedMouseData::CanCoalesce(const WidgetMouseEvent& aEvent,
                              const ScrollableLayerGuid& aGuid,
                              const uint64_t& aInputBlockId)
 {
+  MOZ_ASSERT(aEvent.mMessage == eMouseMove);
   return !mCoalescedInputEvent ||
          (mCoalescedInputEvent->mModifiers == aEvent.mModifiers &&
           mCoalescedInputEvent->inputSource == aEvent.inputSource &&
           mCoalescedInputEvent->pointerId == aEvent.pointerId &&
           mCoalescedInputEvent->button == aEvent.button &&
           mCoalescedInputEvent->buttons == aEvent.buttons &&
           mGuid == aGuid &&
           mInputBlockId == aInputBlockId);
--- a/dom/webidl/Event.webidl
+++ b/dom/webidl/Event.webidl
@@ -15,16 +15,18 @@
 interface Event {
   [Pure]
   readonly attribute DOMString type;
   [Pure]
   readonly attribute EventTarget? target;
   [Pure]
   readonly attribute EventTarget? currentTarget;
 
+  sequence<EventTarget> composedPath();
+
   const unsigned short NONE = 0;
   const unsigned short CAPTURING_PHASE = 1;
   const unsigned short AT_TARGET = 2;
   const unsigned short BUBBLING_PHASE = 3;
   [Pure]
   readonly attribute unsigned short eventPhase;
 
   void stopPropagation();
--- a/dom/webidl/PointerEvent.webidl
+++ b/dom/webidl/PointerEvent.webidl
@@ -18,24 +18,25 @@ interface PointerEvent : MouseEvent
   readonly attribute long height;
   readonly attribute float pressure;
   readonly attribute float tangentialPressure;
   readonly attribute long tiltX;
   readonly attribute long tiltY;
   readonly attribute long twist;
   readonly attribute DOMString pointerType;
   readonly attribute boolean isPrimary;
+  sequence<PointerEvent> getCoalescedEvents();
 };
 
 dictionary PointerEventInit : MouseEventInit
 {
   long pointerId = 0;
   long width = 1;
   long height = 1;
   float pressure = 0;
   float tangentialPressure = 0;
   long tiltX = 0;
   long tiltY = 0;
   long twist = 0;
   DOMString pointerType = "";
   boolean isPrimary = false;
+  sequence<PointerEvent> coalescedEvents = [];
 };
-
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -39,16 +39,17 @@
 #include "mozilla/dom/asmjscache/AsmJSCache.h"
 #include "mozilla/dom/AtomList.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/ErrorEventBinding.h"
 #include "mozilla/dom/EventTargetBinding.h"
 #include "mozilla/dom/FetchUtil.h"
 #include "mozilla/dom/MessageChannel.h"
 #include "mozilla/dom/MessageEventBinding.h"
+#include "mozilla/dom/PerformanceService.h"
 #include "mozilla/dom/WorkerBinding.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/IndexedDatabaseManager.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/Navigator.h"
 #include "mozilla/Monitor.h"
@@ -987,16 +988,18 @@ public:
     }
   }
 
   void Shutdown(JSContext* cx) override
   {
     // The CC is shut down, and the superclass destructor will GC, so make sure
     // we don't try to CC again.
     mWorkerPrivate = nullptr;
+
+    CycleCollectedJSRuntime::Shutdown(cx);
   }
 
   ~WorkerJSRuntime()
   {
     MOZ_COUNT_DTOR_INHERITED(WorkerJSRuntime, CycleCollectedJSRuntime);
   }
 
   virtual void
@@ -2017,16 +2020,19 @@ RuntimeService::Init()
   if (NS_WARN_IF(!osFileConstantsService)) {
     return NS_ERROR_FAILURE;
   }
 
   if (NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate())) {
     return NS_ERROR_UNEXPECTED;
   }
 
+  // PerformanceService must be initialized on the main-thread.
+  PerformanceService::GetOrCreate();
+
   return NS_OK;
 }
 
 void
 RuntimeService::Shutdown()
 {
   AssertIsOnMainThread();
 
--- a/dom/workers/SharedWorker.cpp
+++ b/dom/workers/SharedWorker.cpp
@@ -196,14 +196,14 @@ SharedWorker::GetEventTargetParent(Event
       event = EventDispatcher::CreateEvent(aVisitor.mEvent->mOriginalTarget,
                                            aVisitor.mPresContext,
                                            aVisitor.mEvent, EmptyString());
     }
 
     QueueEvent(event);
 
     aVisitor.mCanHandle = false;
-    aVisitor.mParentTarget = nullptr;
+    aVisitor.SetParentTarget(nullptr, false);
     return NS_OK;
   }
 
   return DOMEventTargetHelper::GetEventTargetParent(aVisitor);
 }
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -1924,17 +1924,17 @@ WorkerLoadInfo::GetPrincipalAndLoadGroup
                                                     nsILoadGroup** aLoadGroupOut)
 {
   AssertIsOnMainThread();
   MOZ_DIAGNOSTIC_ASSERT(aChannel);
   MOZ_DIAGNOSTIC_ASSERT(aPrincipalOut);
   MOZ_DIAGNOSTIC_ASSERT(aLoadGroupOut);
 
   // Initial triggering principal should be set
-  MOZ_DIAGNOSTIC_ASSERT(mLoadingPrincipal);
+  NS_ENSURE_TRUE(mLoadingPrincipal, NS_ERROR_DOM_INVALID_STATE_ERR);
 
   nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
   MOZ_DIAGNOSTIC_ASSERT(ssm);
 
   nsCOMPtr<nsIPrincipal> channelPrincipal;
   nsresult rv = ssm->GetChannelResultPrincipal(aChannel, getter_AddRefs(channelPrincipal));
   NS_ENSURE_SUCCESS(rv, rv);
 
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -1286,17 +1286,17 @@ nsXULElement::DispatchXULCommand(const E
 
 nsresult
 nsXULElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
 {
     aVisitor.mForceContentDispatch = true; //FIXME! Bug 329119
     if (IsEventStoppedFromAnonymousScrollbar(aVisitor.mEvent->mMessage)) {
         // Don't propagate these events from native anonymous scrollbar.
         aVisitor.mCanHandle = true;
-        aVisitor.mParentTarget = nullptr;
+        aVisitor.SetParentTarget(nullptr, false);
         return NS_OK;
     }
     if (aVisitor.mEvent->mMessage == eXULCommand &&
         aVisitor.mEvent->mClass == eInputEventClass &&
         aVisitor.mEvent->mOriginalTarget == static_cast<nsIContent*>(this) &&
         !IsXULElement(nsGkAtoms::command)) {
         // Check that we really have an xul command event. That will be handled
         // in a special way.
--- a/gfx/thebes/gfxGradientCache.cpp
+++ b/gfx/thebes/gfxGradientCache.cpp
@@ -4,17 +4,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/gfx/2D.h"
 #include "nsTArray.h"
 #include "PLDHashTable.h"
 #include "nsExpirationTracker.h"
 #include "nsClassHashtable.h"
 #include "mozilla/SystemGroup.h"
-#include "mozilla/Telemetry.h"
 #include "gfxGradientCache.h"
 #include <time.h>
 
 namespace mozilla {
 namespace gfx {
 
 using namespace mozilla;
 
@@ -122,18 +121,16 @@ class GradientCache final : public nsExp
 {
   public:
     GradientCache()
       : nsExpirationTracker<GradientCacheData,4>(MAX_GENERATION_MS,
                                                  "GradientCache",
                                                  SystemGroup::EventTargetFor(TaskCategory::Other))
     {
       srand(time(nullptr));
-      mTimerPeriod = rand() % MAX_GENERATION_MS + 1;
-      Telemetry::Accumulate(Telemetry::GRADIENT_RETENTION_TIME, mTimerPeriod);
     }
 
     virtual void NotifyExpired(GradientCacheData* aObject)
     {
       // This will free the gfxPattern.
       RemoveObject(aObject);
       mHashEntries.Remove(aObject->mKey);
     }
@@ -163,17 +160,16 @@ class GradientCache final : public nsExp
         // anyway, we probably don't want to retain things.
         return false;
       }
       mHashEntries.Put(aValue->mKey, aValue);
       return true;
     }
 
   protected:
-    uint32_t mTimerPeriod;
     static const uint32_t MAX_GENERATION_MS = 10000;
     /**
      * FIXME use nsTHashtable to avoid duplicating the GradientCacheKey.
      * https://bugzilla.mozilla.org/show_bug.cgi?id=761393#c47
      */
     nsClassHashtable<GradientCacheKey, GradientCacheData> mHashEntries;
 };
 
--- a/js/src/vm/ProxyObject.cpp
+++ b/js/src/vm/ProxyObject.cpp
@@ -51,16 +51,17 @@ ProxyObject::New(JSContext* cx, const Ba
     Rooted<TaggedProto> proto(cx, proto_);
 
     const Class* clasp = options.clasp();
 
     MOZ_ASSERT(isValidProxyClass(clasp));
     MOZ_ASSERT(clasp->shouldDelayMetadataBuilder());
     MOZ_ASSERT_IF(proto.isObject(), cx->compartment() == proto.toObject()->compartment());
     MOZ_ASSERT(clasp->hasFinalize());
+    MOZ_ASSERT_IF(priv.isGCThing(), !JS::GCThingIsMarkedGray(JS::GCCellPtr(priv)));
 
     /*
      * Eagerly mark properties unknown for proxies, so we don't try to track
      * their properties and so that we don't need to walk the compartment if
      * their prototype changes later.  But don't do this for DOM proxies,
      * because we want to be able to keep track of them in typesets in useful
      * ways.
      */
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -990,18 +990,16 @@ class Shape : public gc::TenuredCell
 
     void setOverwritten() {
         flags |= OVERWRITTEN;
     }
     bool hadOverwrite() const {
         return flags & OVERWRITTEN;
     }
 
-    void update(GetterOp getter, SetterOp setter, uint8_t attrs);
-
     bool matches(const Shape* other) const {
         return propid_.get() == other->propid_.get() &&
                matchesParamsAfterId(other->base(), other->maybeSlot(), other->attrs,
                                     other->getter(), other->setter());
     }
 
     inline bool matches(const StackShape& other) const;
 
--- a/layout/painting/nsCSSRenderingGradients.cpp
+++ b/layout/painting/nsCSSRenderingGradients.cpp
@@ -19,17 +19,16 @@
 #include "nsPresContext.h"
 #include "nsPoint.h"
 #include "nsRect.h"
 #include "nsStyleContext.h"
 #include "nsCSSColorUtils.h"
 #include "gfxContext.h"
 #include "nsStyleStructInlines.h"
 #include "nsCSSProps.h"
-#include "mozilla/Telemetry.h"
 #include "gfxUtils.h"
 #include "gfxGradientCache.h"
 
 #include "mozilla/layers/StackingContextHelper.h"
 #include "mozilla/layers/WebRenderLayerManager.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 #include "mozilla/webrender/WebRenderAPI.h"
 #include "Units.h"
@@ -656,17 +655,16 @@ nsCSSGradientRenderer::Paint(gfxContext&
                              const nsRect& aDest,
                              const nsRect& aFillArea,
                              const nsSize& aRepeatSize,
                              const CSSIntRect& aSrc,
                              const nsRect& aDirtyRect,
                              float aOpacity)
 {
   AUTO_PROFILER_LABEL("nsCSSGradientRenderer::Paint", GRAPHICS);
-  Telemetry::AutoTimer<Telemetry::GRADIENT_DURATION, Telemetry::Microsecond> gradientTimer;
 
   if (aDest.IsEmpty() || aFillArea.IsEmpty()) {
     return;
   }
 
   nscoord appUnitsPerDevPixel = mPresContext->AppUnitsPerDevPixel();
 
   gfxFloat lineLength = NS_hypot(mLineEnd.x - mLineStart.x,
--- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
+++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
@@ -552,24 +552,25 @@ public:
 
     uint32_t audio_10ms = rate / 100;
 
     if (!mPacketizer || mPacketizer->PacketSize() != audio_10ms ||
         mPacketizer->Channels() != outputChannels) {
       // It's ok to drop the audio still in the packetizer here.
       mPacketizer = MakeUnique<AudioPacketizer<int16_t, int16_t>>(
         audio_10ms, outputChannels);
+      mPacket = MakeUnique<int16_t[]>(audio_10ms * outputChannels);
     }
 
     mPacketizer->Input(samples, chunk.mDuration);
 
     while (mPacketizer->PacketsAvailable()) {
-      mPacketizer->Output(mPacket);
+      mPacketizer->Output(mPacket.get());
       mConduit->SendAudioFrame(
-        mPacket, mPacketizer->PacketSize(), rate, mPacketizer->Channels(), 0);
+        mPacket.get(), mPacketizer->PacketSize(), rate, mPacketizer->Channels(), 0);
     }
   }
 
   void QueueAudioChunk(TrackRate aRate, const AudioChunk& aChunk, bool aEnabled)
   {
     RefPtr<AudioProxyThread> self = this;
     nsresult rv = mTaskQueue->Dispatch(NS_NewRunnableFunction(
       "AudioProxyThread::QueueAudioChunk", [self, aRate, aChunk, aEnabled]() {
@@ -589,17 +590,17 @@ protected:
     MOZ_COUNT_DTOR(AudioProxyThread);
   }
 
   RefPtr<AudioSessionConduit> mConduit;
   const RefPtr<AutoTaskQueue> mTaskQueue;
   // Only accessed on mTaskQueue
   UniquePtr<AudioPacketizer<int16_t, int16_t>> mPacketizer;
   // A buffer to hold a single packet of audio.
-  int16_t mPacket[AUDIO_SAMPLE_BUFFER_MAX_BYTES / sizeof(int16_t)];
+  UniquePtr<int16_t[]> mPacket;
 };
 
 static char kDTLSExporterLabel[] = "EXTRACTOR-dtls_srtp";
 
 MediaPipeline::MediaPipeline(const std::string& aPc,
                              DirectionType aDirection,
                              nsCOMPtr<nsIEventTarget> aMainThread,
                              nsCOMPtr<nsIEventTarget> aStsThread,
--- a/media/webrtc/trunk/webrtc/modules/audio_device/include/fake_audio_device.h
+++ b/media/webrtc/trunk/webrtc/modules/audio_device/include/fake_audio_device.h
@@ -34,17 +34,17 @@ class FakeAudioDeviceModule : public Aud
   virtual int32_t SetStereoPlayout(bool enable) { return 0; }
   virtual int32_t StopPlayout() { return 0; }
   virtual int32_t InitMicrophone() { return 0; }
   virtual int32_t SetRecordingDevice(uint16_t index) { return 0; }
   virtual int32_t SetRecordingDevice(WindowsDeviceType device) { return 0; }
   virtual int32_t SetStereoRecording(bool enable) { return 0; }
   virtual int32_t SetAGC(bool enable) { return 0; }
   virtual int32_t StopRecording() { return 0; }
-  virtual int64_t TimeUntilNextProcess() { return 0; }
+  virtual int64_t TimeUntilNextProcess() { return 100; }
   virtual void Process() {}
   virtual int32_t Terminate() { return 0; }
 
   virtual int32_t ActiveAudioLayer(AudioLayer* audioLayer) const { return 0; }
   virtual ErrorCode LastError() const { return kAdmErrNone; }
   virtual bool Initialized() const { return true; }
   virtual int16_t PlayoutDevices() { return 0; }
   virtual int16_t RecordingDevices() { return 0; }
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -114,16 +114,18 @@
 #define UA_PREF(_pref) UA_PREF_PREFIX _pref
 #define HTTP_PREF(_pref) HTTP_PREF_PREFIX _pref
 #define BROWSER_PREF(_pref) BROWSER_PREF_PREFIX _pref
 
 #define NS_HTTP_PROTOCOL_FLAGS (URI_STD | ALLOWS_PROXY | ALLOWS_PROXY_HTTP | URI_LOADABLE_BY_ANYONE)
 
 //-----------------------------------------------------------------------------
 
+using mozilla::Telemetry::LABELS_NETWORK_HTTP_REDIRECT_TO_SCHEME;
+
 namespace mozilla {
 namespace net {
 
 LazyLogModule gHttpLog("nsHttp");
 
 static nsresult
 NewURI(const nsACString &aSpec,
        const char *aCharset,
@@ -823,24 +825,38 @@ nsHttpHandler::NotifyObservers(nsIHttpCh
 }
 
 nsresult
 nsHttpHandler::AsyncOnChannelRedirect(nsIChannel* oldChan,
                                       nsIChannel* newChan,
                                       uint32_t flags,
                                       nsIEventTarget* mainThreadEventTarget)
 {
-    // TODO E10S This helper has to be initialized on the other process
-    RefPtr<nsAsyncRedirectVerifyHelper> redirectCallbackHelper =
-        new nsAsyncRedirectVerifyHelper();
+  MOZ_ASSERT(NS_IsMainThread() && (oldChan && newChan));
+
+  nsCOMPtr<nsIURI> newURI;
+  newChan->GetURI(getter_AddRefs(newURI));
+  MOZ_ASSERT(newURI);
+
+  nsAutoCString scheme;
+  newURI->GetScheme(scheme);
+  MOZ_ASSERT(!scheme.IsEmpty());
 
-    return redirectCallbackHelper->Init(oldChan,
-                                        newChan,
-                                        flags,
-                                        mainThreadEventTarget);
+  Telemetry::AccumulateCategoricalKeyed(
+    scheme,
+    oldChan->IsDocument()
+      ? LABELS_NETWORK_HTTP_REDIRECT_TO_SCHEME::topLevel
+      : LABELS_NETWORK_HTTP_REDIRECT_TO_SCHEME::subresource);
+
+  // TODO E10S This helper has to be initialized on the other process
+  RefPtr<nsAsyncRedirectVerifyHelper> redirectCallbackHelper =
+    new nsAsyncRedirectVerifyHelper();
+
+  return redirectCallbackHelper->Init(
+    oldChan, newChan, flags, mainThreadEventTarget);
 }
 
 /* static */ nsresult
 nsHttpHandler::GenerateHostPort(const nsCString& host, int32_t port,
                                 nsACString& hostLine)
 {
     return NS_GenerateHostPort(host, port, hostLine);
 }
--- a/nsprpub/TAG-INFO
+++ b/nsprpub/TAG-INFO
@@ -1,1 +1,1 @@
-NSPR_4_18_BETA3
+NSPR_4_18_BETA4
--- a/nsprpub/config/prdepend.h
+++ b/nsprpub/config/prdepend.h
@@ -5,8 +5,9 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSPR in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
+
--- a/nsprpub/pr/src/md/windows/ntthread.c
+++ b/nsprpub/pr/src/md/windows/ntthread.c
@@ -22,16 +22,19 @@ DWORD _pr_intsOffIndex;
 
 _MDLock                       _nt_idleLock;
 PRCList                       _nt_idleList;
 PRUint32                        _nt_idleCount;
 
 extern __declspec(thread) PRThread *_pr_io_restarted_io;
 extern DWORD _pr_io_restartedIOIndex;
 
+typedef HRESULT (WINAPI *SETTHREADDESCRIPTION)(HANDLE, PCWSTR);
+static SETTHREADDESCRIPTION sSetThreadDescription = NULL;
+
 /* Must check the restarted_io *before* decrementing no_sched to 0 */
 #define POST_SWITCH_WORK() \
     PR_BEGIN_MACRO \
         PRThread *restarted_io = \
             (_pr_use_static_tls ? _pr_io_restarted_io \
             : (PRThread *) TlsGetValue(_pr_io_restartedIOIndex)); \
         if (restarted_io) { \
             _nt_handle_restarted_io(restarted_io); \
@@ -74,16 +77,18 @@ void
     } else {
         TlsSetValue(_pr_io_restartedIOIndex, NULL);
     }
 }
 
 void
 _PR_MD_EARLY_INIT()
 {
+    HMODULE hModule;
+
     _MD_NEW_LOCK( &_nt_idleLock );
     _nt_idleCount = 0;
     PR_INIT_CLIST(&_nt_idleList);
 
 #if 0
     /* Make the clock tick at least once per millisecond */
     if ( timeBeginPeriod(1) == TIMERR_NOCANDO) {
         /* deep yoghurt; clock doesn't tick fast enough! */
@@ -93,16 +98,25 @@ void
 
     if (!_pr_use_static_tls) {
         _pr_currentFiberIndex = TlsAlloc();
         _pr_lastFiberIndex = TlsAlloc();
         _pr_currentCPUIndex = TlsAlloc();
         _pr_intsOffIndex = TlsAlloc();
         _pr_io_restartedIOIndex = TlsAlloc();
     }
+
+    // SetThreadDescription is Windows 10 build 1607+
+    hModule = GetModuleHandleW(L"kernel32.dll");
+    if (hModule) {
+        sSetThreadDescription =
+            (SETTHREADDESCRIPTION) GetProcAddress(
+                                       hModule,
+                                       "SetThreadDescription");
+    }
 }
 
 void _PR_MD_CLEANUP_BEFORE_EXIT(void)
 {
     _PR_NT_FreeSids();
 
     WSACleanup();
 
@@ -288,17 +302,26 @@ typedef struct tagTHREADNAME_INFO
 } THREADNAME_INFO;
 #pragma pack(pop)
 
 void
 _PR_MD_SET_CURRENT_THREAD_NAME(const char *name)
 {
 #ifdef _MSC_VER
    THREADNAME_INFO info;
+#endif
 
+   if (sSetThreadDescription) {
+      WCHAR wideName[MAX_PATH];
+      if (MultiByteToWideChar(CP_ACP, 0, name, -1, wideName, MAX_PATH)) {
+         sSetThreadDescription(GetCurrentThread(), wideName);
+      }
+   }
+
+#ifdef _MSC_VER
    if (!IsDebuggerPresent())
       return;
 
    info.dwType = 0x1000;
    info.szName = (char*) name;
    info.dwThreadID = -1;
    info.dwFlags = 0;
 
--- a/nsprpub/pr/src/md/windows/w95thred.c
+++ b/nsprpub/pr/src/md/windows/w95thred.c
@@ -1,8 +1,9 @@
+
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "primpl.h"
 #include <process.h>  /* for _beginthreadex() */
 
@@ -22,28 +23,42 @@ typedef DWORD DWORD_PTR;
 #else
 DWORD _pr_currentThreadIndex;
 DWORD _pr_lastThreadIndex;
 DWORD _pr_currentCPUIndex;
 #endif
 int                           _pr_intsOff = 0; 
 _PRInterruptTable             _pr_interruptTable[] = { { 0 } };
 
+typedef HRESULT (WINAPI *SETTHREADDESCRIPTION)(HANDLE, PCWSTR);
+static SETTHREADDESCRIPTION sSetThreadDescription = NULL;
+
 void
 _PR_MD_EARLY_INIT()
 {
+    HMODULE hModule;
+
 #ifndef _PR_USE_STATIC_TLS
     _pr_currentThreadIndex = TlsAlloc();
     _pr_lastThreadIndex = TlsAlloc();
     _pr_currentCPUIndex = TlsAlloc();
 #endif
 
 #if defined(_WIN64) && defined(WIN95)
     _fd_waiting_for_overlapped_done_lock = PR_NewLock();
 #endif
+
+    // SetThreadDescription is Windows 10 build 1607+
+    hModule = GetModuleHandleW(L"kernel32.dll");
+    if (hModule) {
+        sSetThreadDescription =
+            (SETTHREADDESCRIPTION) GetProcAddress(
+                                       hModule,
+                                       "SetThreadDescription");
+    }
 }
 
 void _PR_MD_CLEANUP_BEFORE_EXIT(void)
 {
     _PR_NT_FreeSids();
 
     _PR_MD_CleanupSockets();
 
@@ -212,17 +227,26 @@ typedef struct tagTHREADNAME_INFO
 } THREADNAME_INFO;
 #pragma pack(pop)
 
 void
 _PR_MD_SET_CURRENT_THREAD_NAME(const char *name)
 {
 #ifdef _MSC_VER
    THREADNAME_INFO info;
+#endif
 
+   if (sSetThreadDescription) {
+      WCHAR wideName[MAX_PATH];
+      if (MultiByteToWideChar(CP_ACP, 0, name, -1, wideName, MAX_PATH)) {
+         sSetThreadDescription(GetCurrentThread(), wideName);
+      }
+   }
+
+#ifdef _MSC_VER
    if (!IsDebuggerPresent())
       return;
 
    info.dwType = 0x1000;
    info.szName = (char*) name;
    info.dwThreadID = -1;
    info.dwFlags = 0;
 
--- a/taskcluster/ci/release-notify-promote/kind.yml
+++ b/taskcluster/ci/release-notify-promote/kind.yml
@@ -4,17 +4,17 @@
 
 loader: taskgraph.loader.transform:loader
 
 transforms:
    - taskgraph.transforms.release_deps:transforms
    - taskgraph.transforms.task:transforms
 
 kind-dependencies:
-   - beetmover-checksums
+   - post-beetmover-dummy
    - release-bouncer-sub
 
 job-defaults:
    name: notify-release-drivers-promote
    description: Sends email to release-drivers telling release was promoted.
    run-on-projects: []
    shipping-phase: promote
    worker-type: aws-provisioner-v1/gecko-{level}-b-linux
--- a/taskcluster/ci/release-updates-builder/kind.yml
+++ b/taskcluster/ci/release-updates-builder/kind.yml
@@ -1,17 +1,17 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 loader: taskgraph.loader.transform:loader
 
 kind-dependencies:
    # For the $platform_info.txt files.
-   - beetmover-repackage
+   - post-beetmover-dummy
 
 transforms:
    - taskgraph.transforms.release_deps:transforms
    - taskgraph.transforms.release_updates:transforms
    - taskgraph.transforms.job:transforms
    - taskgraph.transforms.task:transforms
 
 job-defaults:
--- a/taskcluster/scripts/misc/build-clang-windows-helper32.sh
+++ b/taskcluster/scripts/misc/build-clang-windows-helper32.sh
@@ -16,16 +16,20 @@ 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
 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/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"
--- a/taskcluster/scripts/misc/build-clang-windows-helper64.sh
+++ b/taskcluster/scripts/misc/build-clang-windows-helper64.sh
@@ -16,16 +16,20 @@ 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
 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 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"
--- a/taskcluster/taskgraph/actions/release_promotion.py
+++ b/taskcluster/taskgraph/actions/release_promotion.py
@@ -224,43 +224,47 @@ def release_promotion_action(parameters,
     if release_promotion_flavor in VERSION_BUMP_FLAVORS:
         # We force str() the input, hence the 'None'
         if next_version in ['', 'None']:
             raise Exception(
                 "`next_version` property needs to be provided for %s "
                 "targets." % ', '.join(VERSION_BUMP_FLAVORS)
             )
 
-    if release_promotion_flavor in PARTIAL_UPDATES_FLAVORS:
-        partial_updates = json.dumps(input.get('partial_updates', {}))
-        if partial_updates == "{}":
-            raise Exception(
-                "`partial_updates` property needs to be provided for %s "
-                "targets." % ', '.join(PARTIAL_UPDATES_FLAVORS)
-            )
-        os.environ['PARTIAL_UPDATES'] = partial_updates
-        release_history = populate_release_history(
-            'Firefox', parameters['project'], partial_updates=input['partial_updates']
-        )
-
-    if release_promotion_flavor in UPTAKE_MONITORING_PLATFORMS_FLAVORS:
-        uptake_monitoring_platforms = json.dumps(input.get('uptake_monitoring_platforms', []))
-        if partial_updates == "[]":
-            raise Exception(
-                "`uptake_monitoring_platforms` property needs to be provided for %s "
-                "targets." % ', '.join(UPTAKE_MONITORING_PLATFORMS_FLAVORS)
-            )
-        os.environ['UPTAKE_MONITORING_PLATFORMS'] = uptake_monitoring_platforms
-
     if release_promotion_flavor in DESKTOP_RELEASE_TYPE_FLAVORS:
         desktop_release_type = input.get('desktop_release_type', None)
         if desktop_release_type not in VALID_DESKTOP_RELEASE_TYPES:
             raise Exception("`desktop_release_type` must be one of: %s" %
                             ", ".join(VALID_DESKTOP_RELEASE_TYPES))
 
+        if release_promotion_flavor in PARTIAL_UPDATES_FLAVORS:
+            partial_updates = json.dumps(input.get('partial_updates', {}))
+            if partial_updates == "{}":
+                raise Exception(
+                    "`partial_updates` property needs to be provided for %s "
+                    "targets." % ', '.join(PARTIAL_UPDATES_FLAVORS)
+                )
+            balrog_prefix = 'Firefox'
+            if desktop_release_type == 'devedition':
+                balrog_prefix = 'Devedition'
+            os.environ['PARTIAL_UPDATES'] = partial_updates
+            release_history = populate_release_history(
+                balrog_prefix, parameters['project'],
+                partial_updates=input['partial_updates']
+            )
+
+        if release_promotion_flavor in UPTAKE_MONITORING_PLATFORMS_FLAVORS:
+            uptake_monitoring_platforms = json.dumps(input.get('uptake_monitoring_platforms', []))
+            if partial_updates == "[]":
+                raise Exception(
+                    "`uptake_monitoring_platforms` property needs to be provided for %s "
+                    "targets." % ', '.join(UPTAKE_MONITORING_PLATFORMS_FLAVORS)
+                )
+            os.environ['UPTAKE_MONITORING_PLATFORMS'] = uptake_monitoring_platforms
+
     promotion_config = RELEASE_PROMOTION_CONFIG[release_promotion_flavor]
 
     target_tasks_method = input.get(
         'target_tasks_method',
         promotion_config['target_tasks_method'].format(project=parameters['project'])
     )
     rebuild_kinds = input.get(
         'rebuild_kinds', promotion_config.get('rebuild_kinds', [])
--- a/taskcluster/taskgraph/transforms/job/buildbot.py
+++ b/taskcluster/taskgraph/transforms/job/buildbot.py
@@ -27,26 +27,56 @@ buildbot_run_schema = Schema({
 
     # the product to use
     Required('product'): Any('firefox', 'mobile', 'fennec', 'devedition', 'thunderbird'),
 
     Optional('release-promotion'): bool,
 })
 
 
+def _get_balrog_api_root(branch):
+    if branch in ('mozilla-beta', 'mozilla-release') or branch.startswith('mozilla-esr'):
+        return 'https://aus4-admin.mozilla.org/api'
+    else:
+        return 'https://balrog-admin.stage.mozaws.net/api'
+
+
+def _get_balrog_channel(product, branch):
+    if product == 'devedition':
+        return 'aurora'
+    elif product == 'firefox':
+        if branch in ('mozilla-beta', 'maple'):
+            return 'beta'
+        elif branch == 'mozilla-release':
+            return 'release'
+        elif branch.startswith('mozilla-esr'):
+            return 'esr'
+    # Unsupported channels are filtered out after the task is generated. Then, we must
+    # provide a dummy value for them, otherwise the Decision task breaks.
+    return 'unknown'
+
+
 def bb_release_worker(config, worker, run):
     # props
     release_props = get_release_config(config)
     repo_path = urlparse(config.params['head_repository']).path.lstrip('/')
     revision = config.params['head_rev']
+    branch = config.params['project']
+    product = run['product']
+
     release_props.update({
         'release_promotion': True,
         'repo_path': repo_path,
         'revision': revision,
     })
+
+    if product in ('devedition', 'firefox'):
+        release_props['balrog_api_root'] = _get_balrog_api_root(branch)
+        release_props['channels'] = _get_balrog_channel(product, branch)
+
     worker['properties'].update(release_props)
     # Setting script_repo_revision to the gecko revision doesn't work for
     # jobs that clone build/tools or other repos instead of gecko.
     if 'script_repo_revision' not in worker['properties']:
         worker['properties']['script_repo_revision'] = revision
 
 
 def bb_ci_worker(config, worker):
--- a/testing/marionette/harness/marionette_harness/tests/harness_unit/test_marionette_arguments.py
+++ b/testing/marionette/harness/marionette_harness/tests/harness_unit/test_marionette_arguments.py
@@ -1,15 +1,15 @@
 # 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/.
 import mozunit
 import pytest
 
-from marionette_harness.runtests import MarionetteArguments
+from marionette_harness.runtests import MarionetteArguments, MarionetteTestRunner
 
 
 @pytest.mark.parametrize("socket_timeout", ['A', '10', '1B-', '1C2', '44.35'])
 def test_parse_arg_socket_timeout(socket_timeout):
     argv = ['marionette', '--socket-timeout', socket_timeout]
     parser = MarionetteArguments()
 
     def _is_float_convertible(value):
@@ -23,10 +23,44 @@ def test_parse_arg_socket_timeout(socket
         with pytest.raises(SystemExit) as ex:
             parser.parse_args(args=argv)
         assert ex.value.code == 2
     else:
         args = parser.parse_args(args=argv)
         assert hasattr(args, 'socket_timeout') and args.socket_timeout == float(socket_timeout)
 
 
+@pytest.mark.parametrize("arg_name, arg_dest, arg_value, expected_value",
+                         [('app-arg', 'app_args', 'samplevalue', ['samplevalue']),
+                          ('symbols-path', 'symbols_path', 'samplevalue', 'samplevalue'),
+                          ('gecko-log', 'gecko_log', 'samplevalue', 'samplevalue'),
+                          ('app', 'app', 'samplevalue', 'samplevalue')])
+def test_parsing_optional_arguments(mach_parsed_kwargs, arg_name, arg_dest, arg_value,
+                                    expected_value):
+    parser = MarionetteArguments()
+    parsed_args = parser.parse_args(['--' + arg_name, arg_value])
+    result = vars(parsed_args)
+    assert result.get(arg_dest) == expected_value
+    mach_parsed_kwargs[arg_dest] = result[arg_dest]
+    runner = MarionetteTestRunner(**mach_parsed_kwargs)
+    built_kwargs = runner._build_kwargs()
+    assert built_kwargs[arg_dest] == expected_value
+
+
+@pytest.mark.parametrize("arg_name, arg_dest, arg_value, expected_value",
+                         [('adb', 'adb_path', 'samplevalue', 'samplevalue'),
+                          ('avd', 'avd', 'samplevalue', 'samplevalue'),
+                          ('avd-home', 'avd_home', 'samplevalue', 'samplevalue'),
+                          ('package', 'package_name', 'samplevalue', 'samplevalue')])
+def test_parse_opt_args_emulator(mach_parsed_kwargs, arg_name, arg_dest, arg_value, expected_value):
+    parser = MarionetteArguments()
+    parsed_args = parser.parse_args(['--' + arg_name, arg_value])
+    result = vars(parsed_args)
+    assert result.get(arg_dest) == expected_value
+    mach_parsed_kwargs[arg_dest] = result[arg_dest]
+    mach_parsed_kwargs["emulator"] = True
+    runner = MarionetteTestRunner(**mach_parsed_kwargs)
+    built_kwargs = runner._build_kwargs()
+    assert built_kwargs[arg_dest] == expected_value
+
+
 if __name__ == '__main__':
     mozunit.main('--log-tbpl=-')
--- a/testing/mozharness/configs/single_locale/dev-mozilla-beta_devedition.py
+++ b/testing/mozharness/configs/single_locale/dev-mozilla-beta_devedition.py
@@ -29,9 +29,11 @@ config = {
         "pull",
         "clone-locales",
         "list-locales",
         "setup",
         "repack",
         "taskcluster-upload",
         "summary",
     ],
+
+    "update_channel": "aurora",
 }
--- a/testing/mozharness/configs/single_locale/linux64_devedition.py
+++ b/testing/mozharness/configs/single_locale/linux64_devedition.py
@@ -68,9 +68,11 @@ config = {
     'mock_files': [
         ('/home/cltbld/.ssh', '/home/mock_mozilla/.ssh'),
         ('/home/cltbld/.hgrc', '/builds/.hgrc'),
         ('/home/cltbld/.boto', '/builds/.boto'),
         ('/builds/gapi.data', '/builds/gapi.data'),
         ('/builds/relengapi.tok', '/builds/relengapi.tok'),
         ('/usr/local/lib/hgext', '/usr/local/lib/hgext'),
     ],
+
+    "update_channel": "aurora",
 }
--- a/testing/mozharness/configs/single_locale/linux_devedition.py
+++ b/testing/mozharness/configs/single_locale/linux_devedition.py
@@ -88,9 +88,11 @@ config = {
     'mock_files': [
         ('/home/cltbld/.ssh', '/home/mock_mozilla/.ssh'),
         ('/home/cltbld/.hgrc', '/builds/.hgrc'),
         ('/home/cltbld/.boto', '/builds/.boto'),
         ('/builds/gapi.data', '/builds/gapi.data'),
         ('/builds/relengapi.tok', '/builds/relengapi.tok'),
         ('/usr/local/lib/hgext', '/usr/local/lib/hgext'),
     ],
+
+    "update_channel": "aurora",
 }
--- a/testing/mozharness/configs/single_locale/macosx64_devedition.py
+++ b/testing/mozharness/configs/single_locale/macosx64_devedition.py
@@ -38,9 +38,11 @@ config = {
 
     # MAR
     "update_mar_dir": "dist/update",  # sure?
     "application_ini": "Contents/Resources/application.ini",
     "local_mar_tool_dir": "dist/host/bin",
     "mar": "mar",
     "mbsdiff": "mbsdiff",
     "localized_mar": "firefox-%(version)s.%(locale)s.mac.complete.mar",
+
+    "update_channel": "aurora",
 }
--- a/testing/mozharness/configs/single_locale/win32_devedition.py
+++ b/testing/mozharness/configs/single_locale/win32_devedition.py
@@ -50,10 +50,12 @@ config = {
 
     # use mozmake?
     "enable_mozmake": True,
     'exes': {
         'virtualenv': [
             sys.executable,
             'c:/mozilla-build/buildbotve/virtualenv.py'
         ],
-    }
+    },
+
+    "update_channel": "aurora",
 }
--- a/testing/mozharness/configs/single_locale/win64_devedition.py
+++ b/testing/mozharness/configs/single_locale/win64_devedition.py
@@ -50,10 +50,12 @@ config = {
 
     # use mozmake?
     "enable_mozmake": True,
     'exes': {
         'virtualenv': [
             sys.executable,
             'c:/mozilla-build/buildbotve/virtualenv.py'
         ],
-    }
+    },
+
+    "update_channel": "aurora",
 }
--- a/testing/web-platform/meta/pointerevents/extension/idlharness.html.ini
+++ b/testing/web-platform/meta/pointerevents/extension/idlharness.html.ini
@@ -1,6 +1,3 @@
 [idlharness.html]
   type: testharness
   prefs: [dom.w3c_pointer_events.enabled:true]
-  [PointerEvent interface: operation getCoalescedEvents()]
-    expected: FAIL
-
--- a/testing/web-platform/meta/pointerevents/extension/pointerevent_constructor.html.ini
+++ b/testing/web-platform/meta/pointerevents/extension/pointerevent_constructor.html.ini
@@ -1,5 +1,4 @@
 [pointerevent_constructor.html]
   type: testharness
-  [PointerEvent: Constructor test]
-    expected: FAIL
+  prefs: [dom.w3c_pointer_events.enabled:true]
 
--- a/testing/web-platform/meta/shadow-dom/Extensions-to-Event-Interface.html.ini
+++ b/testing/web-platform/meta/shadow-dom/Extensions-to-Event-Interface.html.ini
@@ -1,18 +1,10 @@
 [Extensions-to-Event-Interface.html]
   type: testharness
-  [composedPath() must exist on Event]
-    expected: FAIL
-
-  [composedPath() must return an empty array when the event has not been dispatched]
-    expected: FAIL
-
-  [composedPath() must return an empty array when the event is no longer dispatched]
-    expected: FAIL
 
   [The event must propagate out of open mode shadow boundaries when the composed flag is set]
     expected: FAIL
 
   [The event must propagate out of closed mode shadow boundaries when the composed flag is set]
     expected: FAIL
 
   [The event must not propagate out of open mode shadow boundaries when the composed flag is unset]
deleted file mode 100644
--- a/testing/web-platform/meta/shadow-dom/event-composed-path-after-dom-mutation.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[event-composed-path-after-dom-mutation.html]
-  [Event.composedPath() should return the same result even if DOM is mutated (1/2)]
-    expected: FAIL
-
-  [Event.composedPath() should return the same result even if DOM is mutated (2/2)]
-    expected: FAIL
-
--- a/testing/web-platform/meta/shadow-dom/event-composed-path-with-related-target.html.ini
+++ b/testing/web-platform/meta/shadow-dom/event-composed-path-with-related-target.html.ini
@@ -1,14 +1,10 @@
 [event-composed-path-with-related-target.html]
   type: testharness
-  expected: ERROR
-  [Event path for an event with a relatedTarget. relatedTarget != target.]
-    expected: FAIL
-
   [Event path for an event with a relatedTarget. Event shoul be dispatched if 1) target and relatedTarget are same, and 2) they are not in a shadow tree.]
     expected: FAIL
 
   [Event path for an event with a relatedTarget. Event should stop at the shadow root]
     expected: FAIL
 
   [Event path for an event with a relatedTarget. Event should not be dispatched if 1) target and relatedTarget are same, and 2) both are in a shadow tree.]
     expected: FAIL
@@ -35,14 +31,11 @@
     expected: FAIL
 
   [Event path for an event with a relatedTarget. Event should be dispatched at every slots.]
     expected: FAIL
 
   [Event path for an event with a relatedTarget. Event should be dispatched at every slots. relatedTarget should be correctly retargeted.]
     expected: FAIL
 
-  [Event path for an event with a relatedTarget. Event should be dispatched even when target and relatedTarget are same.]
-    expected: FAIL
-
   [Event path for an event with a relatedTarget which is identical to target. Event should be dispatched and should stop at the shadow root.]
     expected: FAIL
 
--- a/testing/web-platform/meta/shadow-dom/event-composed-path.html.ini
+++ b/testing/web-platform/meta/shadow-dom/event-composed-path.html.ini
@@ -1,36 +1,9 @@
 [event-composed-path.html]
   type: testharness
-  expected: ERROR
-  [Event Path without ShadowRoots.]
-    expected: FAIL
-
-  [Event Path with an open ShadowRoot.]
-    expected: FAIL
-
-  [Event Path with a closed ShadowRoot.]
-    expected: FAIL
-
-  [Event Path with nested ShadowRoots: open > open.]
-    expected: FAIL
-
-  [Event Path with nested ShadowRoots: open > closed.]
-    expected: FAIL
-
-  [Event Path with nested ShadowRoots: closed > open.]
-    expected: FAIL
-
-  [Event Path with nested ShadowRoots: closed > closed.]
-    expected: FAIL
-
-  [Event Path with a slot in an open Shadow Root.]
-    expected: FAIL
 
   [Event Path with a slot in a closed Shadow Root.]
     expected: FAIL
 
-  [Event Path with slots in nested ShadowRoots: open > open.]
-    expected: FAIL
-
   [Event Path with slots in nested ShadowRoots: closed > closed.]
     expected: FAIL
 
deleted file mode 100644
--- a/testing/web-platform/meta/shadow-dom/event-composed.html.ini
+++ /dev/null
@@ -1,24 +0,0 @@
-[event-composed.html]
-  type: testharness
-  expected: ERROR
-  [An event should be scoped by default]
-    expected: FAIL
-
-  [An event should not be scoped if composed is specified]
-    expected: FAIL
-
-  [A synthetic MouseEvent should be scoped by default]
-    expected: FAIL
-
-  [A synthetic MouseEvent with composed=true should not be scoped]
-    expected: FAIL
-
-  [A synthetic FocusEvent should be scoped by default]
-    expected: FAIL
-
-  [A synthetic FocusEvent with composed=true should not be scoped]
-    expected: FAIL
-
-  [A UA click event should not be scoped]
-    expected: FAIL
-
--- a/testing/web-platform/meta/shadow-dom/event-post-dispatch.html.ini
+++ b/testing/web-platform/meta/shadow-dom/event-post-dispatch.html.ini
@@ -1,42 +1,25 @@
 [event-post-dispatch.html]
-  [Event properties post dispatch without ShadowRoots (composed: true).]
-    expected: FAIL
-
-  [Event properties post dispatch without ShadowRoots (composed: false).]
-    expected: FAIL
-
-  [Event properties post dispatch with an open ShadowRoot (composed: true).]
-    expected: FAIL
 
   [Event properties post dispatch with an open ShadowRoot (composed: false).]
     expected: FAIL
 
-  [Event properties post dispatch with a closed ShadowRoot (composed: true).]
-    expected: FAIL
-
   [Event properties post dispatch with a closed ShadowRoot (composed: false).]
     expected: FAIL
 
-  [Event properties post dispatch with nested ShadowRoots (composed: true).]
-    expected: FAIL
-
   [Event properties post dispatch with nested ShadowRoots (composed: false).]
     expected: FAIL
 
   [Event properties post dispatch with relatedTarget in the same shadow tree. (composed: true)]
     expected: FAIL
 
   [Event properties post dispatch with relatedTarget in the same shadow tree. (composed: false)]
     expected: FAIL
 
-  [Event properties post dispatch with relatedTarget in the document tree and the shadow tree. (composed: true)]
-    expected: FAIL
-
   [Event properties post dispatch with relatedTarget in the document tree and the shadow tree. (composed: false)]
     expected: FAIL
 
   [Event properties post dispatch with relatedTarget in the different shadow trees. (composed: true)]
     expected: FAIL
 
   [Event properties post dispatch with relatedTarget in the different shadow trees. (composed: false)]
     expected: FAIL
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -38,16 +38,26 @@
     "kind": "exponential",
     "high": 60000,
     "n_buckets": 20,
     "keyed": false,
     "description": "The amount of time the parent process blocked while detecting a UIA client.",
     "bug_numbers": [1423989],
     "alert_emails": ["dbolter@mozilla.com"]
   },
+  "A11Y_TREE_UPDATE_TIMING_MS" : {
+    "record_in_processes": ["main", "content"],
+    "alert_emails": ["asurkov@mozilla.com"],
+    "bug_numbers": [1424768],
+    "expires_in_version": "never",
+    "description": "The amount of time taken to update the accessibility tree (ms)",
+    "kind" : "exponential",
+    "high": 60000,
+    "n_buckets": 50
+  },
   "ADDON_CONTENT_POLICY_SHIM_BLOCKING_LOADING_MS": {
     "record_in_processes": ["main", "content"],
     "expires_in_version": "58",
     "kind": "exponential",
     "high": 60000,
     "n_buckets": 20,
     "keyed": true,
     "description": "The amount of time the content process blocked processing shouldLoad shims for an add-on (keyed by add-on ID) prior to the load event, for each document load.",
@@ -1620,32 +1630,16 @@
   },
   "SYSTEM_FONT_FALLBACK_SCRIPT": {
     "record_in_processes": ["main", "content"],
     "expires_in_version": "never",
     "kind": "enumerated",
     "n_values": 110,
     "description": "System font fallback script"
   },
-  "GRADIENT_DURATION": {
-    "record_in_processes": ["main", "content"],
-    "expires_in_version": "default",
-    "kind": "exponential",
-    "high": 50000000,
-    "n_buckets": 20,
-    "description": "Gradient generation time (us)"
-  },
-  "GRADIENT_RETENTION_TIME": {
-    "record_in_processes": ["main", "content"],
-    "expires_in_version": "never",
-    "kind": "linear",
-    "high": 10000,
-    "n_buckets": 20,
-    "description": "Maximum retention time for the gradient cache. (ms)"
-  },
   "FONT_CACHE_HIT": {
     "record_in_processes": ["main", "content"],
     "expires_in_version": "never",
     "kind": "boolean",
     "description": "font cache hit"
   },
   "BAD_FALLBACK_FONT": {
     "record_in_processes": ["main", "content"],
@@ -2394,16 +2388,26 @@
     "record_in_processes": ["main"],
     "expires_in_version": "62",
     "alert_emails": ["necko@mozilla.com"],
     "bug_numbers": [1377223],
     "kind": "categorical",
     "labels": ["NotSent", "CachedContentUsed", "CachedContentNotUsed"],
     "description": "Stats for validation requests when cache won the race."
   },
+  "NETWORK_HTTP_REDIRECT_TO_SCHEME" :{
+    "record_in_processes": ["main"],
+    "alert_emails": ["necko@mozilla.com", "seceng-telemetry@mozilla.com", "jkt@mozilla.com"],
+    "bug_numbers": [1413512],
+    "expires_in_version": "64",
+    "kind": "categorical",
+    "keyed": true,
+    "description": "Count of the HTTP redirection that triggered by top-level document or by subresource, keyed by the URL scheme redirected to.",
+    "labels": ["topLevel", "subresource"]
+  },
   "HTTP_AUTH_DIALOG_STATS_3": {
     "record_in_processes": ["main", "content"],
     "expires_in_version": "61",
     "alert_emails": ["necko@mozilla.com", "ddamjanovic@mozilla.com"],
     "bug_numbers": [1357835],
     "kind": "enumerated",
     "n_values": 64,
     "description": "Stats about what kind of resource requested http authentication. (29=top-level doc, 30=same origin subresources, 31=same origin xhr, 32=non-web-content, (nsIContentPolicy type)=cross-origin subresources per nsIContentPolicy type)"
@@ -7073,165 +7077,165 @@
     "alert_emails": ["perf-telemetry-alerts@mozilla.com"],
     "expires_in_version": "never",
     "kind": "exponential",
     "high": 3000,
     "n_buckets": 10,
     "description": "Number of histograms with total count low errors"
   },
   "TELEMETRY_ARCHIVE_DIRECTORIES_COUNT": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "linear",
     "high": 13,
     "n_buckets": 12,
     "bug_numbers": [1162538],
     "description": "Number of directories in the archive at scan"
   },
   "TELEMETRY_ARCHIVE_OLDEST_DIRECTORY_AGE": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "linear",
     "high": 13,
     "n_buckets": 12,
     "bug_numbers": [1162538],
     "description": "The age of the oldest Telemetry archive directory in months"
   },
   "TELEMETRY_ARCHIVE_SCAN_PING_COUNT": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "exponential",
     "high": 100000,
     "n_buckets": 100,
     "bug_numbers": [1162538],
     "description": "Number of Telemetry pings in the archive at scan"
   },
   "TELEMETRY_ARCHIVE_SESSION_PING_COUNT": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "count",
     "bug_numbers": [1162538],
     "description": "Number of Telemetry pings added to the archive during the session"
   },
   "TELEMETRY_ARCHIVE_SIZE_MB": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "linear",
     "high": 300,
     "n_buckets": 60,
     "bug_numbers": [1162538],
     "description": "The size of the Telemetry archive (MB)"
   },
   "TELEMETRY_ARCHIVE_EVICTED_OVER_QUOTA": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "exponential",
     "high": 100000,
     "n_buckets": 100,
     "bug_numbers": [1162538],
     "description": "Number of Telemetry pings evicted from the archive during cleanup, because they were over the quota"
   },
   "TELEMETRY_ARCHIVE_EVICTED_OLD_DIRS": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "linear",
     "high": 13,
     "n_buckets": 12,
     "bug_numbers": [1162538],
     "description": "Number of Telemetry directories evicted from the archive during cleanup, because they were too old"
   },
   "TELEMETRY_ARCHIVE_EVICTING_DIRS_MS": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "exponential",
     "high": 300000,
     "n_buckets": 20,
     "bug_numbers": [1162538],
     "description": "Time (ms) it takes for evicting old directories"
   },
   "TELEMETRY_ARCHIVE_CHECKING_OVER_QUOTA_MS": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "exponential",
     "high": 300000,
     "n_buckets": 20,
     "bug_numbers": [1162538],
     "description": "Time (ms) it takes for checking if the archive is over-quota"
   },
   "TELEMETRY_ARCHIVE_EVICTING_OVER_QUOTA_MS": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "exponential",
     "high": 300000,
     "n_buckets": 20,
     "bug_numbers": [1162538],
     "description": "Time (ms) it takes for evicting over-quota pings"
   },
   "TELEMETRY_PENDING_LOAD_FAILURE_READ": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "count",
     "description": "Number of pending Telemetry pings that failed to load from the disk"
   },
   "TELEMETRY_PENDING_LOAD_FAILURE_PARSE": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "count",
     "description": "Number of pending Telemetry pings that failed to parse once loaded from the disk"
   },
   "TELEMETRY_PENDING_PINGS_SIZE_MB": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "linear",
     "high": 17,
     "n_buckets": 16,
     "description": "The size of the Telemetry pending pings directory (MB). The special value 17 is used to indicate over quota pings."
   },
   "TELEMETRY_PENDING_PINGS_AGE": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "exponential",
     "high": 365,
     "n_buckets": 30,
     "description": "The age, in days, of the pending pings."
   },
   "TELEMETRY_PENDING_PINGS_EVICTED_OVER_QUOTA": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "exponential",
     "high": 100000,
     "n_buckets": 100,
     "description": "Number of Telemetry pings evicted from the pending pings directory during cleanup, because they were over the quota"
   },
   "TELEMETRY_PENDING_EVICTING_OVER_QUOTA_MS": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "exponential",
     "high": 300000,
     "n_buckets": 20,
     "description": "Time (ms) it takes for evicting over-quota pending pings"
   },
   "TELEMETRY_PENDING_CHECKING_OVER_QUOTA_MS": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "exponential",
     "high": 300000,
     "n_buckets": 20,
     "description": "Time (ms) it takes for checking if the pending pings are over-quota"
   },
   "TELEMETRY_PENDING_LOAD_MS": {
@@ -7272,56 +7276,56 @@
     "kind": "exponential",
     "low": 10,
     "high": 1024,
     "n_buckets": 20,
     "bug_numbers": [1367094],
     "description": "The size (KB) of the Telemetry unsuccessfully sent pings"
   },
   "TELEMETRY_PING_SIZE_EXCEEDED_SEND": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "count",
     "description": "Number of Telemetry pings discarded before sending because they exceeded the maximum size"
   },
   "TELEMETRY_PING_SIZE_EXCEEDED_PENDING": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "count",
     "description": "Number of Telemetry pending pings discarded because they exceeded the maximum size"
   },
   "TELEMETRY_PING_SIZE_EXCEEDED_ARCHIVED": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "count",
     "description": "Number of archived Telemetry pings discarded because they exceeded the maximum size"
   },
   "TELEMETRY_PING_SUBMISSION_WAITING_CLIENTID": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "count",
     "releaseChannelCollection": "opt-out",
     "bug_numbers": [1233986],
     "description": "The number of pings that were submitted and had to wait for a client id (i.e. before it was cached or loaded from disk)"
   },
   "TELEMETRY_DISCARDED_PENDING_PINGS_SIZE_MB": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "linear",
     "high": 30,
     "n_buckets": 29,
     "description": "The size (MB) of the Telemetry pending pings exceeding the maximum file size"
   },
   "TELEMETRY_DISCARDED_ARCHIVED_PINGS_SIZE_MB": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "linear",
     "high": 30,
     "n_buckets": 29,
     "description": "The size (MB) of the Telemetry archived, compressed, pings exceeding the maximum file size"
   },
   "TELEMETRY_DISCARDED_SEND_PINGS_SIZE_MB": {
@@ -7329,43 +7333,43 @@
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "linear",
     "high": 30,
     "n_buckets": 29,
     "description": "The size (MB) of the ping data submitted to Telemetry exceeding the maximum size"
   },
   "TELEMETRY_DISCARDED_CONTENT_PINGS_COUNT": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "count",
     "description": "Count of discarded content payloads."
   },
   "TELEMETRY_COMPRESS": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "exponential",
     "high": 3000,
     "n_buckets": 10,
     "description": "Time taken to compress telemetry object (ms)"
   },
   "TELEMETRY_SEND_SUCCESS" : {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "bug_numbers": [1318284],
     "expires_in_version": "never",
     "kind": "exponential",
     "high": 120000,
     "n_buckets": 20,
     "description": "Time needed (in ms) for a successful send of a Telemetry ping to the servers and getting a reply back."
   },
   "TELEMETRY_SEND_FAILURE" : {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "bug_numbers": [1318284],
     "expires_in_version": "never",
     "kind": "exponential",
     "high": 120000,
     "n_buckets": 20,
     "description": "Time needed (in ms) for a failed send of a Telemetry ping to the servers and getting a reply back."
   },
@@ -7383,26 +7387,26 @@
       "eRedirect",
       "abort",
       "timeout",
       "eTooLate"
     ],
     "description": "Counts of the different ways sending a Telemetry ping can fail."
   },
   "TELEMETRY_STRINGIFY" : {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "exponential",
     "high": 3000,
     "n_buckets": 10,
     "description": "Time to stringify telemetry object (ms)"
   },
   "TELEMETRY_SUCCESS": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "boolean",
     "description": "Successful telemetry submission"
   },
   "TELEMETRY_INVALID_PING_TYPE_SUBMITTED": {
     "record_in_processes": ["main", "content"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
@@ -7415,68 +7419,68 @@
     "record_in_processes": ["main", "content"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "bug_numbers": [1292226],
     "kind": "count",
     "description": "Count of individual invalid payloads that were submitted to Telemetry."
   },
   "TELEMETRY_PING_EVICTED_FOR_SERVER_ERRORS": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "count",
     "description": "Number of Telemetry ping files evicted due to server errors (4XX HTTP code received)"
   },
   "TELEMETRY_SESSIONDATA_FAILED_LOAD": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "flag",
     "description": "Set if Telemetry failed to load the session data from disk."
   },
   "TELEMETRY_SESSIONDATA_FAILED_PARSE": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "flag",
     "description": "Set if Telemetry failed to parse the session data loaded from disk."
   },
   "TELEMETRY_SESSIONDATA_FAILED_VALIDATION": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "flag",
     "description": "Set if Telemetry failed to validate the session data loaded from disk."
   },
   "TELEMETRY_SESSIONDATA_FAILED_SAVE": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "expires_in_version": "never",
     "kind": "flag",
     "description": "Set if Telemetry failed to save the session data to disk."
   },
   "TELEMETRY_ASSEMBLE_PAYLOAD_EXCEPTION": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "bug_numbers": [1250640],
     "expires_in_version": "53",
     "kind": "count",
     "description": "Count of exceptions in TelemetrySession.getSessionPayload()."
   },
   "TELEMETRY_SCHEDULER_TICK_EXCEPTION": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "bug_numbers": [1250640],
     "expires_in_version": "53",
     "kind": "count",
     "description": "Count of exceptions during executing the TelemetrySession scheduler tick logic."
   },
   "TELEMETRY_SCHEDULER_WAKEUP": {
-    "record_in_processes": ["main", "content"],
+    "record_in_processes": ["main"],
     "alert_emails": ["telemetry-client-dev@mozilla.com"],
     "bug_numbers": [1250640],
     "expires_in_version": "53",
     "kind": "count",
     "description": "Count of TelemetrySession scheduler ticks that were delayed long enough to suspect sleep."
   },
   "TELEMETRY_TEST_FLAG": {
     "record_in_processes": ["main", "content"],
--- a/toolkit/components/telemetry/histogram-whitelists.json
+++ b/toolkit/components/telemetry/histogram-whitelists.json
@@ -238,18 +238,16 @@
     "FX_TOTAL_TOP_VISITS",
     "FX_TOUCH_USED",
     "GDI_INITFONTLIST_TOTAL",
     "GEOLOCATION_ACCURACY_EXPONENTIAL",
     "GEOLOCATION_ERROR",
     "GEOLOCATION_OSX_SOURCE_IS_MLS",
     "GEOLOCATION_WIN8_SOURCE_IS_MLS",
     "GFX_CRASH",
-    "GRADIENT_DURATION",
-    "GRADIENT_RETENTION_TIME",
     "HISTORY_LASTVISITED_TREE_QUERY_TIME_MS",
     "HTTPCONNMGR_TOTAL_SPECULATIVE_CONN",
     "HTTPCONNMGR_UNUSED_SPECULATIVE_CONN",
     "HTTPCONNMGR_USED_SPECULATIVE_CONN",
     "HTTP_CACHE_DISPOSITION_2_V2",
     "HTTP_CACHE_ENTRY_ALIVE_TIME",
     "HTTP_CACHE_ENTRY_RELOAD_TIME",
     "HTTP_CACHE_ENTRY_REUSE_COUNT",
@@ -892,18 +890,16 @@
     "GDI_INITFONTLIST_TOTAL",
     "GEOLOCATION_ACCURACY_EXPONENTIAL",
     "GEOLOCATION_ERROR",
     "GEOLOCATION_OSX_SOURCE_IS_MLS",
     "GEOLOCATION_WIN8_SOURCE_IS_MLS",
     "GFX_CONTENT_FAILED_TO_ACQUIRE_DEVICE",
     "GFX_CRASH",
     "GHOST_WINDOWS",
-    "GRADIENT_DURATION",
-    "GRADIENT_RETENTION_TIME",
     "GRAPHICS_DRIVER_STARTUP_TEST",
     "GRAPHICS_SANITY_TEST",
     "GRAPHICS_SANITY_TEST_OS_SNAPSHOT",
     "GRAPHICS_SANITY_TEST_REASON",
     "HISTORY_LASTVISITED_TREE_QUERY_TIME_MS",
     "HTTPCONNMGR_TOTAL_SPECULATIVE_CONN",
     "HTTPCONNMGR_UNUSED_SPECULATIVE_CONN",
     "HTTPCONNMGR_USED_SPECULATIVE_CONN",
@@ -1588,17 +1584,16 @@
     "TRANSLATED_PAGES",
     "FX_SESSION_RESTORE_SEND_UPDATE_CAUSED_OOM",
     "SSL_PERMANENT_CERT_ERROR_OVERRIDES",
     "FX_THUMBNAILS_BG_QUEUE_SIZE_ON_CAPTURE",
     "AUTO_REJECTED_TRANSLATION_OFFERS",
     "TRANSLATED_CHARACTERS",
     "WEAVE_CONFIGURED",
     "NEWTAB_PAGE_ENABLED",
-    "GRADIENT_DURATION",
     "MOZ_SQLITE_OPEN_MS",
     "SHOULD_TRANSLATION_UI_APPEAR",
     "NEWTAB_PAGE_LIFE_SPAN",
     "FX_TOTAL_TOP_VISITS",
     "FX_SESSION_RESTORE_NUMBER_OF_EAGER_TABS_RESTORED",
     "CACHE_DISK_SEARCH_2",
     "FX_THUMBNAILS_BG_CAPTURE_QUEUE_TIME_MS",
     "NEWTAB_PAGE_PINNED_SITES_COUNT",
--- a/toolkit/components/url-classifier/nsUrlClassifierUtils.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierUtils.cpp
@@ -507,17 +507,17 @@ AddThreatSourceFromChannel(ThreatHit& aH
   }
 
   nsresult rv;
 
   auto matchingSource = aHit.add_resources();
   matchingSource->set_type(aType);
 
   nsCOMPtr<nsIURI> uri;
-  rv = aChannel->GetURI(getter_AddRefs(uri));
+  rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCString spec;
   rv = GetSpecWithoutSensitiveData(uri, spec);
   NS_ENSURE_SUCCESS(rv, rv);
   matchingSource->set_url(spec.get());
 
   nsCOMPtr<nsIHttpChannel> httpChannel =
@@ -629,22 +629,22 @@ AddTabThreatSources(ThreatHit& aHit, nsI
   if (NS_SUCCEEDED(rv) && !isTopUri) {
     nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
     if (loadInfo && loadInfo->RedirectChain().Length()) {
       AddThreatSourceFromRedirectEntry(aHit, loadInfo->RedirectChain()[0],
                                        ThreatHit_ThreatSourceType_TAB_RESOURCE);
     }
   }
 
-  // Set top level tab_url threatshource
+  // Set top level tab_url threat source
   rv = AddThreatSourceFromChannel(aHit, topChannel,
                                   ThreatHit_ThreatSourceType_TAB_URL);
   Unused << NS_WARN_IF(NS_FAILED(rv));
 
-  // Set tab_redirect threatshources if there's any
+  // Set tab_redirect threat sources if there's any
   nsCOMPtr<nsILoadInfo> topLoadInfo = topChannel->GetLoadInfo();
   if (!topLoadInfo) {
     return NS_OK;
   }
 
   nsIRedirectHistoryEntry* redirectEntry;
   size_t length = topLoadInfo->RedirectChain().Length();
   for (size_t i = 0; i < length; i++) {
--- a/toolkit/mozapps/installer/packager.py
+++ b/toolkit/mozapps/installer/packager.py
@@ -18,16 +18,17 @@ from mozpack.files import (
     FileFinder,
     File,
 )
 from mozpack.copier import (
     FileCopier,
     Jarrer,
 )
 from mozpack.errors import errors
+from mozpack.files import ExecutableFile
 from mozpack.mozjar import JAR_BROTLI
 import mozpack.path as mozpath
 import buildconfig
 from argparse import ArgumentParser
 from createprecomplete import generate_precomplete
 import os
 from StringIO import StringIO
 import subprocess
@@ -308,16 +309,24 @@ def main():
                 libbase = mozpath.join(respath, '%s%s') \
                     % (buildconfig.substs['DLL_PREFIX'], lib)
                 libname = '%s%s' % (libbase, buildconfig.substs['DLL_SUFFIX'])
                 if copier.contains(libname):
                     copier.add(libbase + '.chk',
                                LibSignFile(os.path.join(args.destination,
                                                         libname)))
 
+    # Include pdb files for llvm-symbolizer to resolve symbols.
+    if buildconfig.substs.get('LLVM_SYMBOLIZER') and mozinfo.isWin:
+        for p, f in copier:
+            if isinstance(f, ExecutableFile):
+                pdbname = os.path.splitext(f.inputs()[0])[0] + '.pdb'
+                if os.path.exists(pdbname):
+                    copier.add(os.path.basename(pdbname), File(pdbname))
+
     # Setup preloading
     if args.jarlog and os.path.exists(args.jarlog):
         from mozpack.mozjar import JarLog
         log = JarLog(args.jarlog)
         for p, f in copier:
             if not isinstance(f, Jarrer):
                 continue
             key = JarLog.canonicalize(os.path.join(args.destination, p))
--- a/widget/BasicEvents.h
+++ b/widget/BasicEvents.h
@@ -24,16 +24,18 @@
 
 namespace IPC {
 template<typename T>
 struct ParamTraits;
 } // namespace IPC
 
 namespace mozilla {
 
+class EventTargetChainItem;
+
 /******************************************************************************
  * mozilla::BaseEventFlags
  *
  * BaseEventFlags must be a POD struct for safe to use memcpy (including
  * in ParamTraits<BaseEventFlags>).  So don't make virtual methods, constructor,
  * destructor and operators.
  * This is necessary for VC which is NOT C++0x compiler.
  ******************************************************************************/
@@ -509,27 +511,29 @@ protected:
               EventClassID aEventClassID)
     : WidgetEventTime()
     , mClass(aEventClassID)
     , mMessage(aMessage)
     , mRefPoint(0, 0)
     , mLastRefPoint(0, 0)
     , mFocusSequenceNumber(0)
     , mSpecifiedEventType(nullptr)
+    , mPath(nullptr)
   {
     MOZ_COUNT_CTOR(WidgetEvent);
     mFlags.Clear();
     mFlags.mIsTrusted = aIsTrusted;
     SetDefaultCancelableAndBubbles();
     SetDefaultComposed();
     SetDefaultComposedInNativeAnonymousContent();
   }
 
   WidgetEvent()
     : WidgetEventTime()
+    , mPath(nullptr)
   {
     MOZ_COUNT_CTOR(WidgetEvent);
   }
 
 public:
   WidgetEvent(bool aIsTrusted, EventMessage aMessage)
     : WidgetEvent(aIsTrusted, aMessage, eBasicEventClass)
   {
@@ -583,16 +587,18 @@ public:
 
   // Event targets, needed by DOM Events
   // Note that when you need event target for DOM event, you should use
   // Get*DOMEventTarget() instead of accessing these members directly.
   nsCOMPtr<dom::EventTarget> mTarget;
   nsCOMPtr<dom::EventTarget> mCurrentTarget;
   nsCOMPtr<dom::EventTarget> mOriginalTarget;
 
+  nsTArray<EventTargetChainItem>* mPath;
+
   dom::EventTarget* GetDOMEventTarget() const;
   dom::EventTarget* GetCurrentDOMEventTarget() const;
   dom::EventTarget* GetOriginalDOMEventTarget() const;
 
   void AssignEventData(const WidgetEvent& aEvent, bool aCopyTargets)
   {
     // mClass should be initialized with the constructor.
     // mMessage should be initialized with the constructor.
--- a/widget/MouseEvents.h
+++ b/widget/MouseEvents.h
@@ -31,29 +31,41 @@ enum nsDragDropEventStatus
 
 namespace mozilla {
 
 namespace dom {
   class PBrowserParent;
   class PBrowserChild;
 } // namespace dom
 
+class WidgetPointerEvent;
+class WidgetPointerEventHolder final
+{
+public:
+  nsTArray<WidgetPointerEvent> mEvents;
+  NS_INLINE_DECL_REFCOUNTING(WidgetPointerEventHolder)
+
+private:
+  virtual ~WidgetPointerEventHolder() {}
+};
+
 /******************************************************************************
  * mozilla::WidgetPointerHelper
  ******************************************************************************/
 
 class WidgetPointerHelper
 {
 public:
   uint32_t pointerId;
   uint32_t tiltX;
   uint32_t tiltY;
   uint32_t twist;
   float tangentialPressure;
   bool convertToPointer;
+  RefPtr<WidgetPointerEventHolder> mCoalescedWidgetEvents;
 
   WidgetPointerHelper()
     : pointerId(0)
     , tiltX(0)
     , tiltY(0)
     , twist(0)
     , tangentialPressure(0)
     , convertToPointer(true)
@@ -66,24 +78,39 @@ public:
     , tiltX(aTiltX)
     , tiltY(aTiltY)
     , twist(aTwist)
     , tangentialPressure(aTangentialPressure)
     , convertToPointer(true)
   {
   }
 
-  void AssignPointerHelperData(const WidgetPointerHelper& aEvent)
+  explicit WidgetPointerHelper(const WidgetPointerHelper& aHelper)
+    : pointerId(aHelper.pointerId)
+    , tiltX(aHelper.tiltX)
+    , tiltY(aHelper.tiltY)
+    , twist(aHelper.twist)
+    , tangentialPressure(aHelper.tangentialPressure)
+    , convertToPointer(aHelper.convertToPointer)
+    , mCoalescedWidgetEvents(aHelper.mCoalescedWidgetEvents)
+  {
+  }
+
+  void AssignPointerHelperData(const WidgetPointerHelper& aEvent,
+                               bool aCopyCoalescedEvents = false)
   {
     pointerId = aEvent.pointerId;
     tiltX = aEvent.tiltX;
     tiltY = aEvent.tiltY;
     twist = aEvent.twist;
     tangentialPressure = aEvent.tangentialPressure;
     convertToPointer = aEvent.convertToPointer;
+    if (aCopyCoalescedEvents) {
+      mCoalescedWidgetEvents = aEvent.mCoalescedWidgetEvents;
+    }
   }
 };
 
 /******************************************************************************
  * mozilla::WidgetMouseEventBase
  ******************************************************************************/
 
 class WidgetMouseEventBase : public WidgetInputEvent
@@ -313,17 +340,17 @@ public:
   // mClickCount may be non-zero value when mMessage is eMouseDown, eMouseUp,
   // eMouseClick or eMouseDoubleClick. The number is count of mouse clicks.
   // Otherwise, this must be 0.
   uint32_t mClickCount;
 
   void AssignMouseEventData(const WidgetMouseEvent& aEvent, bool aCopyTargets)
   {
     AssignMouseEventBaseData(aEvent, aCopyTargets);
-    AssignPointerHelperData(aEvent);
+    AssignPointerHelperData(aEvent, /* aCopyCoalescedEvents */ true);
 
     mIgnoreRootScrollFrame = aEvent.mIgnoreRootScrollFrame;
     mClickCount = aEvent.mClickCount;
   }
 
   /**
    * Returns true if the event is a context menu event caused by key.
    */
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -508,16 +508,19 @@ CycleCollectedJSRuntime::CycleCollectedJ
   , mJSZoneCycleCollectorGlobal(sJSZoneCycleCollectorGlobal)
   , mJSRuntime(JS_GetRuntime(aCx))
   , mHasPendingIdleGCTask(false)
   , mPrevGCSliceCallback(nullptr)
   , mPrevGCNurseryCollectionCallback(nullptr)
   , mJSHolderMap(256)
   , mOutOfMemoryState(OOMState::OK)
   , mLargeAllocationFailureState(OOMState::OK)
+#ifdef DEBUG
+  , mShutdownCalled(false)
+#endif
 {
   MOZ_COUNT_CTOR(CycleCollectedJSRuntime);
   MOZ_ASSERT(aCx);
   MOZ_ASSERT(mJSRuntime);
 
   if (!JS_AddExtraGCRootsTracer(aCx, TraceBlackJS, this)) {
     MOZ_CRASH("JS_AddExtraGCRootsTracer failed");
   }
@@ -555,22 +558,26 @@ CycleCollectedJSRuntime::CycleCollectedJ
   JS::dbg::SetDebuggerMallocSizeOf(aCx, moz_malloc_size_of);
 }
 
 void
 CycleCollectedJSRuntime::Shutdown(JSContext* cx)
 {
   JS_RemoveExtraGCRootsTracer(cx, TraceBlackJS, this);
   JS_RemoveExtraGCRootsTracer(cx, TraceGrayJS, this);
+#ifdef DEBUG
+  mShutdownCalled = true;
+#endif
 }
 
 CycleCollectedJSRuntime::~CycleCollectedJSRuntime()
 {
   MOZ_COUNT_DTOR(CycleCollectedJSRuntime);
   MOZ_ASSERT(!mDeferredFinalizerTable.Count());
+  MOZ_ASSERT(mShutdownCalled);
 }
 
 void
 CycleCollectedJSRuntime::AddContext(CycleCollectedJSContext* aContext)
 {
   mContexts.insertBack(aContext);
 }
 
--- a/xpcom/base/CycleCollectedJSRuntime.h
+++ b/xpcom/base/CycleCollectedJSRuntime.h
@@ -363,16 +363,20 @@ private:
     mPreservedNurseryObjects;
 
   nsTHashtable<nsPtrHashKey<JS::Zone>> mZonesWaitingForGC;
 
   struct EnvironmentPreparer : public js::ScriptEnvironmentPreparer {
     void invoke(JS::HandleObject scope, Closure& closure) override;
   };
   EnvironmentPreparer mEnvironmentPreparer;
+
+#ifdef DEBUG
+  bool mShutdownCalled;
+#endif
 };
 
 void TraceScriptHolder(nsISupports* aHolder, JSTracer* aTracer);
 
 // Returns true if the JS::TraceKind is one the cycle collector cares about.
 inline bool AddToCCKind(JS::TraceKind aKind)
 {
   return aKind == JS::TraceKind::Object ||