Merge autoland to mozilla-central. a=merge
authorAndreea Pavel <apavel@mozilla.com>
Tue, 11 Sep 2018 00:58:48 +0300
changeset 491283 fea371cafd2c
parent 491267 b0bf04a1cbbf (current diff)
parent 491282 a08e6206cd97 (diff)
child 491303 ded88ee162ac
child 491354 8fe21bce8d05
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone64.0a1
first release with
nightly linux32
fea371cafd2c / 64.0a1 / 20180910220142 / files
nightly linux64
fea371cafd2c / 64.0a1 / 20180910220142 / files
nightly mac
fea371cafd2c / 64.0a1 / 20180910220142 / files
nightly win32
fea371cafd2c / 64.0a1 / 20180910220142 / files
nightly win64
fea371cafd2c / 64.0a1 / 20180910220142 / 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 autoland to mozilla-central. a=merge
modules/libpref/init/all.js
toolkit/components/places/tests/unifiedcomplete/test_zero_frecency.js
toolkit/components/telemetry/build_scripts/parsers/__init__.py
toolkit/components/telemetry/build_scripts/parsers/parse_events.py
toolkit/components/telemetry/build_scripts/parsers/parse_histograms.py
toolkit/components/telemetry/build_scripts/parsers/parse_scalars.py
toolkit/components/telemetry/build_scripts/parsers/shared_telemetry_utils.py
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1754,16 +1754,26 @@ pref("app.shield.optoutstudies.enabled",
 #else
 pref("app.shield.optoutstudies.enabled", false);
 #endif
 
 // Multi-lingual preferences
 pref("intl.multilingual.enabled", false);
 
 // Prio preferences
+// Only enable by default on Nightly.
+// On platforms that do not build libprio, do not set these prefs at all, which gives us a way to detect support.
+
 // Curve25519 public keys for Prio servers
+#ifdef MOZ_LIBPRIO
 pref("prio.publicKeyA", "35AC1C7576C7C6EDD7FED6BCFC337B34D48CB4EE45C86BEEFB40BD8875707733");
 pref("prio.publicKeyB", "26E6674E65425B823F1F1D5F96E3BB3EF9E406EC7FBA7DEF8B08A35DD135AF50");
+#endif
+
+// Whether or not Prio-encoded Telemetry will be sent along with the main ping.
+#if defined(NIGHTLY_BUILD) && defined(MOZ_LIBPRIO)
+pref("prio.enabled", true);
+#endif
 
 #ifdef NIGHTLY_BUILD
 pref("browser.fastblock.enabled", true);
 #endif
 
--- a/browser/base/content/test/siteIdentity/browser.ini
+++ b/browser/base/content/test/siteIdentity/browser.ini
@@ -50,17 +50,16 @@ support-files = ../permissions/permissio
 [browser_identityPopup_focus.js]
 [browser_insecureLoginForms.js]
 support-files =
   insecure_opener.html
   !/toolkit/components/passwordmgr/test/browser/form_basic.html
   !/toolkit/components/passwordmgr/test/browser/insecure_test.html
   !/toolkit/components/passwordmgr/test/browser/insecure_test_subframe.html
 [browser_mcb_redirect.js]
-skip-if = (verify && !debug && os == 'mac') || (os == 'linux') || (os == 'mac') # Bug 1376771
 tags = mcb
 support-files =
   test_mcb_redirect.html
   test_mcb_redirect_image.html
   test_mcb_double_redirect_image.html
   test_mcb_redirect.js
   test_mcb_redirect.sjs
 [browser_mixed_content_cert_override.js]
--- a/browser/base/content/test/siteIdentity/browser_mcb_redirect.js
+++ b/browser/base/content/test/siteIdentity/browser_mcb_redirect.js
@@ -86,26 +86,26 @@ function cleanUpAfterTests() {
 }
 
 // ------------------------ Test 1 ------------------------------
 
 function test1() {
   Services.prefs.setBoolPref(PREF_INSECURE_ICON, false);
 
   var url = HTTPS_TEST_ROOT + "test_mcb_redirect.html";
+  BrowserTestUtils.browserLoaded(gTestBrowser, false, url).then(checkUIForTest1);
   BrowserTestUtils.loadURI(gTestBrowser, url);
-  BrowserTestUtils.browserLoaded(gTestBrowser).then(checkUIForTest1);
 }
 
 function testInsecure1() {
   Services.prefs.setBoolPref(PREF_INSECURE_ICON, true);
 
   var url = HTTPS_TEST_ROOT + "test_mcb_redirect.html";
+  BrowserTestUtils.browserLoaded(gTestBrowser, false, url).then(checkUIForTest1);
   BrowserTestUtils.loadURI(gTestBrowser, url);
-  BrowserTestUtils.browserLoaded(gTestBrowser).then(checkUIForTest1);
 }
 
 async function checkUIForTest1() {
   await assertMixedContentBlockingState(gTestBrowser, {activeLoaded: false, activeBlocked: true, passiveLoaded: false});
 
   ContentTask.spawn(gTestBrowser, null, async function() {
     var expected = "script blocked";
     await ContentTaskUtils.waitForCondition(
@@ -113,18 +113,18 @@ async function checkUIForTest1() {
       "OK: Expected result in innerHTML for Test1!");
   }).then(test2);
 }
 
 // ------------------------ Test 2 ------------------------------
 
 function test2() {
   var url = HTTP_TEST_ROOT + "test_mcb_redirect.html";
+  BrowserTestUtils.browserLoaded(gTestBrowser, false, url).then(checkUIForTest2);
   BrowserTestUtils.loadURI(gTestBrowser, url);
-  BrowserTestUtils.browserLoaded(gTestBrowser).then(checkUIForTest2);
 }
 
 async function checkUIForTest2() {
   await assertMixedContentBlockingState(gTestBrowser, {activeLoaded: false, activeBlocked: false, passiveLoaded: false});
 
   ContentTask.spawn(gTestBrowser, null, async function() {
     var expected = "script executed";
     await ContentTaskUtils.waitForCondition(
@@ -133,36 +133,36 @@ async function checkUIForTest2() {
   }).then(test3);
 }
 
 // ------------------------ Test 3 ------------------------------
 // HTTPS page loading insecure image
 function test3() {
   info("test3");
   var url = HTTPS_TEST_ROOT + "test_mcb_redirect_image.html";
+  BrowserTestUtils.browserLoaded(gTestBrowser, false, url).then(checkLoadEventForTest3);
   BrowserTestUtils.loadURI(gTestBrowser, url);
-  BrowserTestUtils.browserLoaded(gTestBrowser).then(checkLoadEventForTest3);
 }
 
 function checkLoadEventForTest3() {
   ContentTask.spawn(gTestBrowser, null, async function() {
     var expected = "image blocked";
     await ContentTaskUtils.waitForCondition(
       () => content.document.getElementById("mctestdiv").innerHTML == expected,
       "OK: Expected result in innerHTML for Test3!");
   }).then(test4);
 }
 
 // ------------------------ Test 4 ------------------------------
 // HTTP page loading insecure image
 function test4() {
   info("test4");
   var url = HTTP_TEST_ROOT + "test_mcb_redirect_image.html";
+  BrowserTestUtils.browserLoaded(gTestBrowser, false, url).then(checkLoadEventForTest4);
   BrowserTestUtils.loadURI(gTestBrowser, url);
-  BrowserTestUtils.browserLoaded(gTestBrowser).then(checkLoadEventForTest4);
 }
 
 function checkLoadEventForTest4() {
   ContentTask.spawn(gTestBrowser, null, async function() {
     var expected = "image loaded";
     await ContentTaskUtils.waitForCondition(
       () => content.document.getElementById("mctestdiv").innerHTML == expected,
       "OK: Expected result in innerHTML for Test4!");
@@ -174,18 +174,18 @@ function checkLoadEventForTest4() {
 // Assuming test 4 succeeded, the image has already been loaded once
 // and hence should be cached per the sjs cache-control header
 // Going into offline mode to ensure we are loading from the cache.
 function test5() {
   // Go into offline mode
   info("test5");
   Services.io.offline = true;
   var url = HTTP_TEST_ROOT + "test_mcb_redirect_image.html";
+  BrowserTestUtils.browserLoaded(gTestBrowser, false, url).then(checkLoadEventForTest5);
   BrowserTestUtils.loadURI(gTestBrowser, url);
-  BrowserTestUtils.browserLoaded(gTestBrowser).then(checkLoadEventForTest5);
 }
 
 function checkLoadEventForTest5() {
   ContentTask.spawn(gTestBrowser, null, async function() {
     var expected = "image loaded";
     await ContentTaskUtils.waitForCondition(
       () => content.document.getElementById("mctestdiv").innerHTML == expected,
       "OK: Expected result in innerHTML for Test5!");
@@ -201,18 +201,18 @@ function checkLoadEventForTest5() {
 // Assuming test 4 succeeded, the image has already been loaded once
 // and hence should be cached per the sjs cache-control header
 // Going into offline mode to ensure we are loading from the cache.
 function test6() {
   // Go into offline mode
   info("test6");
   Services.io.offline = true;
   var url = HTTPS_TEST_ROOT + "test_mcb_redirect_image.html";
+  BrowserTestUtils.browserLoaded(gTestBrowser, false, url).then(checkLoadEventForTest6);
   BrowserTestUtils.loadURI(gTestBrowser, url);
-  BrowserTestUtils.browserLoaded(gTestBrowser).then(checkLoadEventForTest6);
 }
 
 function checkLoadEventForTest6() {
   ContentTask.spawn(gTestBrowser, null, async function() {
     var expected = "image blocked";
     await ContentTaskUtils.waitForCondition(
       () => content.document.getElementById("mctestdiv").innerHTML == expected,
       "OK: Expected result in innerHTML for Test6!");
@@ -222,18 +222,18 @@ function checkLoadEventForTest6() {
     test7();
   });
 }
 
 // ------------------------ Test 7 ------------------------------
 // HTTP page loading insecure image that went through a double redirect
 function test7() {
   var url = HTTP_TEST_ROOT + "test_mcb_double_redirect_image.html";
+  BrowserTestUtils.browserLoaded(gTestBrowser, false, url).then(checkLoadEventForTest7);
   BrowserTestUtils.loadURI(gTestBrowser, url);
-  BrowserTestUtils.browserLoaded(gTestBrowser).then(checkLoadEventForTest7);
 }
 
 function checkLoadEventForTest7() {
   ContentTask.spawn(gTestBrowser, null, async function() {
     var expected = "image loaded";
     await ContentTaskUtils.waitForCondition(
       () => content.document.getElementById("mctestdiv").innerHTML == expected,
       "OK: Expected result in innerHTML for Test7!");
@@ -244,18 +244,18 @@ function checkLoadEventForTest7() {
 // HTTP page loading insecure cached image that went through a double redirect
 // Assuming test 7 succeeded, the image has already been loaded once
 // and hence should be cached per the sjs cache-control header
 // Going into offline mode to ensure we are loading from the cache.
 function test8() {
   // Go into offline mode
   Services.io.offline = true;
   var url = HTTP_TEST_ROOT + "test_mcb_double_redirect_image.html";
+  BrowserTestUtils.browserLoaded(gTestBrowser, false, url).then(checkLoadEventForTest8);
   BrowserTestUtils.loadURI(gTestBrowser, url);
-  BrowserTestUtils.browserLoaded(gTestBrowser).then(checkLoadEventForTest8);
 }
 
 function checkLoadEventForTest8() {
   ContentTask.spawn(gTestBrowser, null, async function() {
     var expected = "image loaded";
     await ContentTaskUtils.waitForCondition(
       () => content.document.getElementById("mctestdiv").innerHTML == expected,
       "OK: Expected result in innerHTML for Test8!");
@@ -270,18 +270,18 @@ function checkLoadEventForTest8() {
 // HTTPS page loading insecure cached image that went through a double redirect
 // Assuming test 7 succeeded, the image has already been loaded once
 // and hence should be cached per the sjs cache-control header
 // Going into offline mode to ensure we are loading from the cache.
 function test9() {
   // Go into offline mode
   Services.io.offline = true;
   var url = HTTPS_TEST_ROOT + "test_mcb_double_redirect_image.html";
+  BrowserTestUtils.browserLoaded(gTestBrowser, false, url).then(checkLoadEventForTest9);
   BrowserTestUtils.loadURI(gTestBrowser, url);
-  BrowserTestUtils.browserLoaded(gTestBrowser).then(checkLoadEventForTest9);
 }
 
 function checkLoadEventForTest9() {
   ContentTask.spawn(gTestBrowser, null, async function() {
     var expected = "image blocked";
     await ContentTaskUtils.waitForCondition(
       () => content.document.getElementById("mctestdiv").innerHTML == expected,
       "OK: Expected result in innerHTML for Test9!");
--- a/browser/components/payments/res/containers/completion-error-page.js
+++ b/browser/components/payments/res/containers/completion-error-page.js
@@ -21,16 +21,20 @@ export default class CompletionErrorPage
 
     this.classList.add("error-page");
     this.suggestionHeading = document.createElement("p");
     this.body.append(this.suggestionHeading);
     this.suggestionsList = document.createElement("ul");
     this.suggestions = [];
     this.body.append(this.suggestionsList);
 
+    this.brandingSpan = document.createElement("span");
+    this.brandingSpan.classList.add("branding");
+    this.footer.appendChild(this.brandingSpan);
+
     this.doneButton = document.createElement("button");
     this.doneButton.classList.add("done-button", "primary");
     this.doneButton.addEventListener("click", this);
 
     this.footer.appendChild(this.doneButton);
   }
 
   render(state) {
@@ -46,16 +50,17 @@ export default class CompletionErrorPage
     for (let key of ["pageTitle", "suggestion-heading", "suggestion-1", "suggestion-2"]) {
       if (this.dataset[key]) {
         this.dataset[key] = this.dataset[key].replace("**host-name**", displayHost);
       }
     }
 
     this.pageTitleHeading.textContent = this.dataset.pageTitle;
     this.suggestionHeading.textContent = this.dataset.suggestionHeading;
+    this.brandingSpan.textContent = this.dataset.brandingLabel;
     this.doneButton.textContent = this.dataset.doneButtonLabel;
 
     this.suggestionsList.textContent = "";
     if (this.dataset["suggestion-1"]) {
       this.suggestions[0] = this.dataset["suggestion-1"];
     }
     if (this.dataset["suggestion-2"]) {
       this.suggestions[1] = this.dataset["suggestion-2"];
--- a/browser/components/payments/res/containers/error-page.css
+++ b/browser/components/payments/res/containers/error-page.css
@@ -1,24 +1,37 @@
 .error-page.illustrated > .page-body {
-  min-height: 300px;
+  display: flex;
+  justify-content: center;
+  min-height: 160px;
   background-position: left center;
   background-repeat: no-repeat;
-  background-size: 38%;
-  padding-inline-start: 38%;
+  background-size: 160px;
+  padding-inline-start: 160px;
 }
 
 .error-page.illustrated > .page-body:dir(rtl) {
   background-position: right center;
 }
 
 .error-page.illustrated > .page-body > h2 {
   background: none;
   padding-inline-start: 0;
   margin-inline-start: 0;
+  font-weight: lighter;
+  font-size: 2rem;
+}
+
+.error-page.illustrated > .page-body > p {
+  margin-top: 0;
+  margin-bottom: 0;
+}
+
+.error-page.illustrated > .page-body > ul {
+  margin-top: .5rem;
 }
 
 .error-page#completion-timeout-error > .page-body {
   background-image: url("./timeout.svg");
 }
 
 .error-page#completion-fail-error > .page-body {
   background-image: url("./warning.svg");
--- a/browser/components/payments/res/debugging.js
+++ b/browser/components/payments/res/debugging.js
@@ -32,17 +32,17 @@ const paymentOptionsUpdater = {
     for (let input of completeStatusInputs) {
       input.checked = input.value == completeStatus;
     }
   },
 };
 
 let REQUEST_1 = {
   tabId: 9,
-  topLevelPrincipal: {URI: {displayHost: "tschaeff.github.io"}},
+  topLevelPrincipal: {URI: {displayHost: "debugging.example.com"}},
   requestId: "3797081f-a96b-c34b-a58b-1083c6e66e25",
   completeStatus: "",
   paymentMethods: [],
   paymentDetails: {
     id: "",
     totalItem: {label: "Demo total", amount: {currency: "EUR", value: "1.00"}, pending: false},
     displayItems: [
       {
--- a/browser/components/payments/res/paymentRequest.css
+++ b/browser/components/payments/res/paymentRequest.css
@@ -154,37 +154,34 @@ payment-dialog[changes-prevented][comple
 payment-dialog[changes-prevented][complete-status="unknown"] #pay,
 payment-dialog[changes-prevented][complete-status="processing"] #pay,
 payment-dialog[changes-prevented][complete-status="success"] #pay {
   /* Show the pay button above #disabled-overlay */
   position: relative;
   z-index: 1;
 }
 
-#cancel {
-  margin-inline-start: auto;
-}
-
 #disabled-overlay {
   background: white;
   grid-area: disabled-overlay;
   opacity: 0.6;
   width: 100%;
   height: 100%;
   position: absolute;
   top: 0;
   right: 0;
   bottom: 0;
   left: 0;
 }
 
-#branding {
+.branding {
   background-image: url(chrome://branding/content/icon32.png);
   background-size: 16px;
   background-repeat: no-repeat;
   background-position: left center;
   padding-inline-start: 20px;
   line-height: 20px;
+  margin-inline-end: auto;
 }
 
-body[dir="rtl"] #branding {
+body[dir="rtl"] .branding {
   background-position: right center;
 }
--- a/browser/components/payments/res/paymentRequest.xhtml
+++ b/browser/components/payments/res/paymentRequest.xhtml
@@ -149,17 +149,17 @@
                           label="&payerLabel;"
                           data-add-link-label="&payer.addLink.label;"
                           data-edit-link-label="&payer.editLink.label;"
                           data-invalid-label="&invalidOption.label;"
                           selected-state-key="selectedPayerAddress"></address-picker>
         </div>
 
         <footer>
-          <span id="branding">&webPaymentsBranding.label;</span>
+          <span class="branding">&webPaymentsBranding.label;</span>
           <button id="cancel">&cancelPaymentButton.label;</button>
           <button id="pay"
                   class="primary"
                   data-label="&approvePaymentButton.label;"
                   data-processing-label="&processingPaymentButton.label;"
                   data-unknown-label="&unknownPaymentButton.label;"
                   data-success-label="&successPaymentButton.label;"></button>
         </footer>
@@ -193,23 +193,25 @@
                     data-update-button-label="&addressPage.updateButton.label;"
                     data-persist-checkbox-label="&addressPage.persistCheckbox.label;"
                     data-field-required-symbol="&fieldRequiredSymbol;"
                     hidden="hidden"></address-form>
 
       <completion-error-page id="completion-timeout-error" class="illustrated"
                   data-page-title="&timeoutErrorPage.title;"
                   data-suggestion-heading="&timeoutErrorPage.suggestionHeading;"
+                  data-branding-label="&webPaymentsBranding.label;"
                   data-done-button-label="&timeoutErrorPage.doneButton.label;"
                   hidden="hidden"></completion-error-page>
       <completion-error-page id="completion-fail-error" class="illustrated"
                   data-page-title="&failErrorPage.title;"
                   data-suggestion-heading="&failErrorPage.suggestionHeading;"
                   data-suggestion-1="&failErrorPage.suggestion1;"
                   data-suggestion-2="&failErrorPage.suggestion2;"
+                  data-branding-label="&webPaymentsBranding.label;"
                   data-done-button-label="&failErrorPage.doneButton.label;"
                   hidden="hidden"></completion-error-page>
     </div>
 
     <div id="disabled-overlay" hidden="hidden">
       <!-- overlay to prevent changes while waiting for a response from the merchant -->
     </div>
   </template>
--- a/browser/components/payments/test/mochitest/test_completion_error_page.html
+++ b/browser/components/payments/test/mochitest/test_completion_error_page.html
@@ -16,16 +16,17 @@ Test the completion-error-page component
 </head>
 <body>
   <p id="display">
     <completion-error-page id="completion-timeout-error" class="illustrated"
             data-page-title="Sample Title"
             data-suggestion-heading="Sample suggestion heading"
             data-suggestion-1="Sample suggestion"
             data-suggestion-2="Sample suggestion"
+            data-branding-label="Sample Brand"
             data-done-button-label="OK"></completion-error-page>
   </p>
 <div id="content" style="display: none">
 
 </div>
 <pre id="test">
 </pre>
 <script type="module">
@@ -39,16 +40,17 @@ add_task(async function test_no_values()
   ok(page, "page exists");
   is(page.dataset.pageTitle, "Sample Title", "Title set on page");
   is(page.dataset.suggestionHeading, "Sample suggestion heading",
      "Suggestion heading set on page");
   is(page.dataset["suggestion-1"], "Sample suggestion",
      "Suggestion 1 set on page");
   is(page.dataset["suggestion-2"], "Sample suggestion",
      "Suggestion 2 set on page");
+  is(page.dataset.brandingLabel, "Sample Brand", "Branding string set");
 
   page.dataset.pageTitle = "Oh noes! **host-name** is having an issue";
   page.dataset["suggestion-2"] = "You should probably blame **host-name**, not us";
   const displayHost = "allizom.com";
   let request = { topLevelPrincipal: { URI: { displayHost } } };
   await page.requestStore.setState({
     changesPrevented: false,
     request: Object.assign({}, request, {completeStatus: ""}),
@@ -67,13 +69,19 @@ add_task(async function test_no_values()
   is(page.querySelector("p").textContent,
      "Sample suggestion heading",
      "Suggestion heading set on page");
   is(page.querySelector("li:nth-child(1)").textContent, "Sample suggestion",
      "Suggestion 1 set on page");
   is(page.querySelector("li:nth-child(2)").textContent,
      `You should probably blame ${displayHost}, not us`,
      "Suggestion 2 includes host-name");
+  is(page.querySelector(".branding").textContent,
+     "Sample Brand",
+     "Branding set on page");
+  is(page.querySelector(".primary").textContent,
+     "OK",
+     "Primary button label set correctly");
 });
 </script>
 
 </body>
 </html>
--- a/browser/moz.build
+++ b/browser/moz.build
@@ -40,16 +40,19 @@ export('DIST_SUBDIR')
 DEFINES['APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
 
 for cdm in CONFIG['MOZ_EME_MODULES']:
     DEFINES['MOZ_%s_EME' % cdm.upper()] = True
 
 if CONFIG['MOZ_GPSD']:
     DEFINES['MOZ_GPSD'] = True
 
+if CONFIG['MOZ_LIBPRIO']:
+    DEFINES['MOZ_LIBPRIO'] = True
+
 # These files are specified in this moz.build to pick up DIST_SUBDIR as set in
 # this directory, which is un-set in browser/app.
 JS_PREFERENCE_PP_FILES += [
     'app/profile/firefox.js',
 ]
 FINAL_TARGET_FILES += ['app/blocklist.xml']
 FINAL_TARGET_FILES.defaults += ['app/permissions']
 
--- a/devtools/client/inspector/test/browser.ini
+++ b/devtools/client/inspector/test/browser.ini
@@ -26,16 +26,17 @@ support-files =
   doc_inspector_highlighter_xbl.xul
   doc_inspector_infobar_01.html
   doc_inspector_infobar_02.html
   doc_inspector_infobar_03.html
   doc_inspector_infobar_textnode.html
   doc_inspector_long-divs.html
   doc_inspector_menu.html
   doc_inspector_outerhtml.html
+  doc_inspector_reload_xul.xul
   doc_inspector_remove-iframe-during-load.html
   doc_inspector_search.html
   doc_inspector_search-reserved.html
   doc_inspector_search-suggestions.html
   doc_inspector_search-svg.html
   doc_inspector_select-last-selected-01.html
   doc_inspector_select-last-selected-02.html
   doc_inspector_svg.svg
@@ -164,16 +165,17 @@ skip-if = (os == 'linux' && bits == 32 &
 [browser_inspector_pane-toggle-04.js]
 [browser_inspector_picker-stop-on-destroy.js]
 [browser_inspector_picker-stop-on-tool-change.js]
 [browser_inspector_portrait_mode.js]
 [browser_inspector_pseudoclass-lock.js]
 [browser_inspector_pseudoclass-menu.js]
 [browser_inspector_reload-01.js]
 [browser_inspector_reload-02.js]
+[browser_inspector_reload_xul.js]
 [browser_inspector_remove-iframe-during-load.js]
 [browser_inspector_search-01.js]
 [browser_inspector_search-02.js]
 [browser_inspector_search-03.js]
 [browser_inspector_search-04.js]
 [browser_inspector_search-05.js]
 [browser_inspector_search-06.js]
 [browser_inspector_search-07.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/test/browser_inspector_reload_xul.js
@@ -0,0 +1,60 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ts=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/. */
+/* globals getTestActorWithoutToolbox */
+"use strict";
+
+// Tests for inspecting a node on a XUL document, spanning a tab reload.
+
+const TEST_URI = URL_ROOT + "doc_inspector_reload_xul.xul";
+
+add_task(async function() {
+  await pushPref("dom.allow_XUL_XBL_for_file", false);
+
+  const { tab, inspector, toolbox } = await openInspectorForURL(TEST_URI);
+  await testToolboxInitialization(tab, inspector, toolbox);
+});
+
+async function testToolboxInitialization(tab, inspector, toolbox) {
+  const target = TargetFactory.forTab(tab);
+
+  ok(true, "Inspector started, and notification received.");
+  ok(inspector, "Inspector instance is accessible.");
+  ok(inspector.isReady, "Inspector instance is ready.");
+  is(inspector.target.tab, tab, "Valid target.");
+
+  await selectNode("#p", inspector);
+  await testMarkupView("#p", inspector);
+
+  info("Reloading the page.");
+  const markuploaded = inspector.once("markuploaded");
+  const onNewRoot = inspector.once("new-root");
+  const onUpdated = inspector.once("inspector-updated");
+  await toolbox.target.activeTab.reload();
+  info("Waiting for inspector to be ready.");
+  await markuploaded;
+  await onNewRoot;
+  await onUpdated;
+
+  await selectNode("#q", inspector);
+  await testMarkupView("#q", inspector);
+
+  info("Destroying toolbox.");
+  await toolbox.destroy();
+
+  ok("true", "'destroyed' notification received.");
+  ok(!gDevTools.getToolbox(target), "Toolbox destroyed.");
+}
+
+async function testMarkupView(selector, inspector) {
+  const nodeFront = await getNodeFront(selector, inspector);
+  try {
+    is(inspector.selection.nodeFront, nodeFront,
+       "Right node is selected in the markup view");
+  } catch (ex) {
+    ok(false, "Got exception while resolving selected node of markup view.");
+    console.error(ex);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/test/doc_inspector_reload_xul.xul
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin/xul.css" type="text/css"?>
+<!DOCTYPE window>
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <body xmlns="http://www.w3.org/1999/xhtml">
+  <div id="p">a node inspected before reload</div>
+  <div id="q">a node inspected after reload</div>
+  </body>
+</window>
--- a/devtools/server/actors/inspector/inspector.js
+++ b/devtools/server/actors/inspector/inspector.js
@@ -101,31 +101,35 @@ exports.InspectorActor = protocol.ActorC
   getWalker: function(options = {}) {
     if (this._walkerPromise) {
       return this._walkerPromise;
     }
 
     const deferred = defer();
     this._walkerPromise = deferred.promise;
 
+    const isXULDocument =
+      this.targetActor.window.document.documentElement.namespaceURI === XUL_NS;
+    const loadEvent = isXULDocument ? "load" : "DOMContentLoaded";
+
     const window = this.window;
     const domReady = () => {
       const targetActor = this.targetActor;
-      window.removeEventListener("DOMContentLoaded", domReady, true);
+      window.removeEventListener(loadEvent, domReady, true);
       this.walker = WalkerActor(this.conn, targetActor, options);
       this.manage(this.walker);
       this.walker.once("destroyed", () => {
         this._walkerPromise = null;
         this._pageStylePromise = null;
       });
       deferred.resolve(this.walker);
     };
 
     if (window.document.readyState === "loading") {
-      window.addEventListener("DOMContentLoaded", domReady, true);
+      window.addEventListener(loadEvent, domReady, true);
     } else {
       domReady();
     }
 
     return this._walkerPromise;
   },
 
   getPageStyle: function() {
--- a/devtools/server/actors/inspector/walker.js
+++ b/devtools/server/actors/inspector/walker.js
@@ -37,16 +37,18 @@ loader.lazyRequireGetter(this, "NodeList
 loader.lazyRequireGetter(this, "LayoutActor", "devtools/server/actors/layout", true);
 loader.lazyRequireGetter(this, "getLayoutChangesObserver", "devtools/server/actors/reflow", true);
 loader.lazyRequireGetter(this, "releaseLayoutChangesObserver", "devtools/server/actors/reflow", true);
 loader.lazyRequireGetter(this, "WalkerSearch", "devtools/server/actors/utils/walker-search", true);
 
 loader.lazyServiceGetter(this, "eventListenerService",
   "@mozilla.org/eventlistenerservice;1", "nsIEventListenerService");
 
+loader.lazyRequireGetter(this, "ChromeUtils");
+
 // Minimum delay between two "new-mutations" events.
 const MUTATIONS_THROTTLING_DELAY = 100;
 // List of mutation types that should -not- be throttled.
 const IMMEDIATE_MUTATIONS = [
   "documentUnload",
   "frameLoad",
   "newRoot",
   "pseudoClassLock",
@@ -1839,17 +1841,25 @@ var WalkerActor = protocol.ActorClassWit
       target: actor.actorID,
     };
     this.queueMutation(mutation);
   },
 
   onFrameLoad: function({ window, isTopLevel }) {
     const { readyState } = window.document;
     if (readyState != "interactive" && readyState != "complete") {
-      window.addEventListener("DOMContentLoaded",
+      // The document is not loaded, so we want to register to fire again when the
+      // DOM has been loaded. To do this, we need to know if this is a XUL document.
+      // We listen for "DOMContentLoaded" on HTML documents, but XUL documents don't
+      // fire this event, so we fallback to the "load" event for XUL. Unfortunately,
+      // since the document isn't loaded yet, we can't check its namespace declaration
+      // to determine if it is XUL. Instead, we use ChromeUtils to see if the document
+      // object class is XULDocument.
+      const isXULDocument = (ChromeUtils.getClassName(window.document) == "XULDocument");
+      window.addEventListener(isXULDocument ? "load" : "DOMContentLoaded",
         this.onFrameLoad.bind(this, { window, isTopLevel }),
         { once: true });
       return;
     }
     if (isTopLevel) {
       // If we initialize the inspector while the document is loading,
       // we may already have a root document set in the constructor.
       if (this.rootDoc && !Cu.isDeadWrapper(this.rootDoc) &&
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -8677,19 +8677,19 @@ nsIDocument::OnPageHide(bool aPersisted,
     // document, so we must manually call CleanupFullscreenState() below too.
     // Note that CleanupFullscreenState() clears nsDocument::mFullscreenRoot,
     // so we *must* call it after ExitFullscreen(), not before.
     // OnPageHide() is called in every hidden (i.e. descendant) document,
     // so calling CleanupFullscreenState() here will ensure all hidden
     // documents have their fullscreen state reset.
     CleanupFullscreenState();
 
-    // If anyone was listening to this document's state, advertizing the state
-    // change would be the least of the politeness.
-    DispatchFullScreenChange(this);
+    // The fullscreenchange event is to be queued in the refresh driver,
+    // however a hidden page wouldn't trigger that again, so it makes no
+    // sense to dispatch such event here.
   }
 }
 
 void
 nsIDocument::WillDispatchMutationEvent(nsINode* aTarget)
 {
   NS_ASSERTION(mSubtreeModifiedDepth != 0 ||
                mSubtreeModifiedTargets.Count() == 0,
@@ -10664,123 +10664,16 @@ nsIDocument::IsFullscreenLeaf()
   // A fullscreen leaf document is fullscreen, and has no fullscreen
   // subdocuments.
   if (!FullScreenStackTop()) {
     return false;
   }
   return CountFullscreenSubDocuments(this) == 0;
 }
 
-static bool
-ResetFullScreen(nsIDocument* aDocument, void* aData)
-{
-  if (aDocument->FullScreenStackTop()) {
-    NS_ASSERTION(CountFullscreenSubDocuments(aDocument) <= 1,
-        "Should have at most 1 fullscreen subdocument.");
-    aDocument->CleanupFullscreenState();
-    NS_ASSERTION(!aDocument->FullScreenStackTop(),
-                 "Should reset full-screen");
-    auto changed = reinterpret_cast<nsCOMArray<nsIDocument>*>(aData);
-    changed->AppendElement(aDocument);
-    aDocument->EnumerateSubDocuments(ResetFullScreen, aData);
-  }
-  return true;
-}
-
-// Since nsIDocument::ExitFullscreenInDocTree() could be called from
-// Element::UnbindFromTree() where it is not safe to synchronously run
-// script. This runnable is the script part of that function.
-class ExitFullscreenScriptRunnable : public Runnable
-{
-public:
-  explicit ExitFullscreenScriptRunnable(nsCOMArray<nsIDocument>&& aDocuments)
-    : mozilla::Runnable("ExitFullscreenScriptRunnable")
-    , mDocuments(std::move(aDocuments))
-  {
-  }
-
-  NS_IMETHOD Run() override
-  {
-    // Dispatch MozDOMFullscreen:Exited to the last document in
-    // the list since we want this event to follow the same path
-    // MozDOMFullscreen:Entered dispatched.
-    nsIDocument* lastDocument = mDocuments[mDocuments.Length() - 1];
-    nsContentUtils::DispatchEventOnlyToChrome(
-      lastDocument, ToSupports(lastDocument),
-      NS_LITERAL_STRING("MozDOMFullscreen:Exited"),
-      CanBubble::eYes, Cancelable::eNo, /* DefaultAction */ nullptr);
-    // Ensure the window exits fullscreen.
-    if (nsPIDOMWindowOuter* win = mDocuments[0]->GetWindow()) {
-      win->SetFullscreenInternal(FullscreenReason::ForForceExitFullscreen, false);
-    }
-    return NS_OK;
-  }
-
-private:
-  nsCOMArray<nsIDocument> mDocuments;
-};
-
-/* static */ void
-nsIDocument::ExitFullscreenInDocTree(nsIDocument* aMaybeNotARootDoc)
-{
-  MOZ_ASSERT(aMaybeNotARootDoc);
-
-  // Unlock the pointer
-  UnlockPointer();
-
-  nsCOMPtr<nsIDocument> root = aMaybeNotARootDoc->GetFullscreenRoot();
-  if (!root || !root->FullScreenStackTop()) {
-    // If a document was detached before exiting from fullscreen, it is
-    // possible that the root had left fullscreen state. In this case,
-    // we would not get anything from the ResetFullScreen() call. Root's
-    // not being a fullscreen doc also means the widget should have
-    // exited fullscreen state. It means even if we do not return here,
-    // we would actually do nothing below except crashing ourselves via
-    // dispatching the "MozDOMFullscreen:Exited" event to an nonexistent
-    // document.
-    return;
-  }
-
-  // Stores a list of documents to which we must dispatch "fullscreenchange".
-  // We're required by the spec to dispatch the events in leaf-to-root
-  // order when exiting fullscreen, but we traverse the doctree in a
-  // root-to-leaf order, so we save references to the documents we must
-  // dispatch to so that we dispatch in the specified order.
-  nsCOMArray<nsIDocument> changed;
-
-  // Walk the tree of fullscreen documents, and reset their fullscreen state.
-  ResetFullScreen(root, static_cast<void*>(&changed));
-
-  // Dispatch "fullscreenchange" events. Note this loop is in reverse
-  // order so that the events for the leaf document arrives before the root
-  // document, as required by the spec.
-  for (uint32_t i = 0; i < changed.Length(); ++i) {
-    DispatchFullScreenChange(changed[changed.Length() - i - 1]);
-  }
-
-  NS_ASSERTION(!root->FullScreenStackTop(),
-    "Fullscreen root should no longer be a fullscreen doc...");
-
-  // Move the top-level window out of fullscreen mode.
-  FullscreenRoots::Remove(root);
-
-  nsContentUtils::AddScriptRunner(
-    new ExitFullscreenScriptRunnable(std::move(changed)));
-}
-
-static void
-DispatchFullscreenNewOriginEvent(nsIDocument* aDoc)
-{
-  RefPtr<AsyncEventDispatcher> asyncDispatcher =
-    new AsyncEventDispatcher(
-        aDoc, NS_LITERAL_STRING("MozDOMFullscreen:NewOrigin"),
-        CanBubble::eYes, ChromeOnlyDispatch::eYes);
-  asyncDispatcher->PostDOMEvent();
-}
-
 bool
 GetFullscreenLeaf(nsIDocument* aDoc, void* aData)
 {
   if (aDoc->IsFullscreenLeaf()) {
     nsIDocument** result = static_cast<nsIDocument**>(aData);
     *result = aDoc;
     return false;
   } else if (aDoc->FullScreenStackTop()) {
@@ -10804,16 +10697,115 @@ GetFullscreenLeaf(nsIDocument* aDoc)
   // around its descendants.
   if (!root->FullScreenStackTop()) {
     return nullptr;
   }
   GetFullscreenLeaf(root, &leaf);
   return leaf;
 }
 
+static bool
+ResetFullScreen(nsIDocument* aDocument, void* aData)
+{
+  if (aDocument->FullScreenStackTop()) {
+    NS_ASSERTION(CountFullscreenSubDocuments(aDocument) <= 1,
+        "Should have at most 1 fullscreen subdocument.");
+    aDocument->CleanupFullscreenState();
+    NS_ASSERTION(!aDocument->FullScreenStackTop(),
+                 "Should reset full-screen");
+    DispatchFullScreenChange(aDocument);
+    aDocument->EnumerateSubDocuments(ResetFullScreen, nullptr);
+  }
+  return true;
+}
+
+// Since nsIDocument::ExitFullscreenInDocTree() could be called from
+// Element::UnbindFromTree() where it is not safe to synchronously run
+// script. This runnable is the script part of that function.
+class ExitFullscreenScriptRunnable : public Runnable
+{
+public:
+  explicit ExitFullscreenScriptRunnable(nsIDocument* aRoot, nsIDocument* aLeaf)
+    : mozilla::Runnable("ExitFullscreenScriptRunnable")
+    , mRoot(aRoot)
+    , mLeaf(aLeaf)
+  {
+  }
+
+  NS_IMETHOD Run() override
+  {
+    // Dispatch MozDOMFullscreen:Exited to the original fullscreen leaf
+    // document since we want this event to follow the same path that
+    // MozDOMFullscreen:Entered was dispatched.
+    nsContentUtils::DispatchEventOnlyToChrome(
+      mLeaf, ToSupports(mLeaf),
+      NS_LITERAL_STRING("MozDOMFullscreen:Exited"),
+      CanBubble::eYes, Cancelable::eNo, /* DefaultAction */ nullptr);
+    // Ensure the window exits fullscreen.
+    if (nsPIDOMWindowOuter* win = mRoot->GetWindow()) {
+      win->SetFullscreenInternal(FullscreenReason::ForForceExitFullscreen, false);
+    }
+    return NS_OK;
+  }
+
+private:
+  nsCOMPtr<nsIDocument> mRoot;
+  nsCOMPtr<nsIDocument> mLeaf;
+};
+
+/* static */ void
+nsIDocument::ExitFullscreenInDocTree(nsIDocument* aMaybeNotARootDoc)
+{
+  MOZ_ASSERT(aMaybeNotARootDoc);
+
+  // Unlock the pointer
+  UnlockPointer();
+
+  nsCOMPtr<nsIDocument> root = aMaybeNotARootDoc->GetFullscreenRoot();
+  if (!root || !root->FullScreenStackTop()) {
+    // If a document was detached before exiting from fullscreen, it is
+    // possible that the root had left fullscreen state. In this case,
+    // we would not get anything from the ResetFullScreen() call. Root's
+    // not being a fullscreen doc also means the widget should have
+    // exited fullscreen state. It means even if we do not return here,
+    // we would actually do nothing below except crashing ourselves via
+    // dispatching the "MozDOMFullscreen:Exited" event to an nonexistent
+    // document.
+    return;
+  }
+
+  // Record the fullscreen leaf document for MozDOMFullscreen:Exited.
+  // See ExitFullscreenScriptRunnable::Run for details. We have to
+  // record it here because we don't have such information after we
+  // reset the fullscreen state below.
+  nsIDocument* fullscreenLeaf = GetFullscreenLeaf(root);
+
+  // Walk the tree of fullscreen documents, and reset their fullscreen state.
+  ResetFullScreen(root, nullptr);
+
+  NS_ASSERTION(!root->FullScreenStackTop(),
+    "Fullscreen root should no longer be a fullscreen doc...");
+
+  // Move the top-level window out of fullscreen mode.
+  FullscreenRoots::Remove(root);
+
+  nsContentUtils::AddScriptRunner(
+    new ExitFullscreenScriptRunnable(root, fullscreenLeaf));
+}
+
+static void
+DispatchFullscreenNewOriginEvent(nsIDocument* aDoc)
+{
+  RefPtr<AsyncEventDispatcher> asyncDispatcher =
+    new AsyncEventDispatcher(
+        aDoc, NS_LITERAL_STRING("MozDOMFullscreen:NewOrigin"),
+        CanBubble::eYes, ChromeOnlyDispatch::eYes);
+  asyncDispatcher->PostDOMEvent();
+}
+
 void
 nsIDocument::RestorePreviousFullScreenState()
 {
   NS_ASSERTION(!FullScreenStackTop() || !FullscreenRoots::IsEmpty(),
     "Should have at least 1 fullscreen root when fullscreen!");
 
   if (!FullScreenStackTop() || !GetWindow() || FullscreenRoots::IsEmpty()) {
     return;
@@ -10869,18 +10861,20 @@ nsIDocument::RestorePreviousFullScreenSt
   nsIDocument* newFullscreenDoc;
   if (lastDoc->mFullScreenStack.Length() > 1) {
     lastDoc->FullScreenStackPop();
     newFullscreenDoc = lastDoc;
   } else {
     lastDoc->CleanupFullscreenState();
     newFullscreenDoc = lastDoc->GetParentDocument();
   }
-  // Dispatch the fullscreenchange event to all document listed.
-  for (nsIDocument* d : exitDocs) {
+  // Dispatch the fullscreenchange event to all document listed. Note
+  // that the loop order is reversed so that events are dispatched in
+  // the tree order as indicated in the spec.
+  for (nsIDocument* d : Reversed(exitDocs)) {
     DispatchFullScreenChange(d);
   }
 
   MOZ_ASSERT(newFullscreenDoc, "If we were going to exit from fullscreen on "
              "all documents in this doctree, we should've asked the window to "
              "exit first instead of reaching here.");
   if (fullScreenDoc != newFullscreenDoc &&
       !nsContentUtils::HaveEqualPrincipals(fullScreenDoc, newFullscreenDoc)) {
@@ -11522,21 +11516,21 @@ nsIDocument::ApplyFullscreen(const Fulls
   // process browser, the code in content process is responsible for
   // sending message with the origin to its parent, and the parent
   // shouldn't rely on this event itself.
   if (aRequest.mShouldNotifyNewOrigin &&
       !nsContentUtils::HaveEqualPrincipals(previousFullscreenDoc, this)) {
     DispatchFullscreenNewOriginEvent(this);
   }
 
-  // Dispatch "fullscreenchange" events. Note this loop is in reverse
-  // order so that the events for the root document arrives before the leaf
-  // document, as required by the spec.
-  for (uint32_t i = 0; i < changed.Length(); ++i) {
-    DispatchFullScreenChange(changed[changed.Length() - i - 1]);
+  // Dispatch "fullscreenchange" events. Note that the loop order is
+  // reversed so that events are dispatched in the tree order as
+  // indicated in the spec.
+  for (nsIDocument* d : Reversed(changed)) {
+    DispatchFullScreenChange(d);
   }
   return true;
 }
 
 bool
 nsIDocument::FullscreenEnabled(CallerType aCallerType)
 {
   return !GetFullscreenError(this, aCallerType == CallerType::System);
--- a/dom/chrome-webidl/PrioEncoder.webidl
+++ b/dom/chrome-webidl/PrioEncoder.webidl
@@ -2,21 +2,21 @@
 /* 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/.
  */
 
 [ChromeOnly, Exposed=(Window,System)]
 namespace PrioEncoder {
   [Throws, NewObject]
-  Promise<PrioEncodedData> encode(ByteString batchID, PrioParams params);
+  PrioEncodedData encode(ByteString batchID, PrioParams params);
 };
 
 dictionary PrioParams {
-  required boolean startupCrashDetected;
-  required boolean safeModeUsage;
   required boolean browserIsUserDefault;
+  required boolean newTabPageEnabled;
+  required boolean pdfViewerUsed;
 };
 
 dictionary PrioEncodedData {
   Uint8Array a;
   Uint8Array b;
 };
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/html/test/file_fullscreen-event-order.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="file_fullscreen-utils.js"></script>
+<iframe src="about:blank" allowfullscreen></iframe>
+<script>
+function ok(condition, msg) {
+  opener.ok(condition, "[event-order] " + msg);
+}
+function is(a, b, msg) {
+  opener.is(a, b, "[event-order] " + msg);
+}
+
+let fullscreenEvents = [];
+let iframeDoc;
+
+function begin() {
+  iframeDoc = document.querySelector("iframe").contentDocument;
+  document.addEventListener("fullscreenchange", evt => {
+    fullscreenEvents.push(evt);
+  });
+  iframeDoc.addEventListener("fullscreenchange", evt => {
+    fullscreenEvents.push(evt);
+  });
+  addFullscreenChangeContinuation("enter", enterFullscreen);
+  iframeDoc.body.requestFullscreen();
+}
+
+function assertFullscreenEvents(action) {
+  is(fullscreenEvents.length, 2,
+    "Two documents should have event dispatched for " + action);
+  is(fullscreenEvents[0].target, document,
+     "Root document should have the event dispatched first after " + action);
+  is(fullscreenEvents[1].target, iframeDoc,
+     "Inner document should have the event dispatched second after " + action);
+}
+
+function enterFullscreen() {
+  assertFullscreenEvents("requestFullscreen");
+  fullscreenEvents = [];
+  addFullscreenChangeContinuation("exit", exitFullscreen);
+  document.exitFullscreen();
+}
+
+function exitFullscreen() {
+  assertFullscreenEvents("exitFullscreen");
+  opener.nextTest();
+}
+</script>
--- a/dom/html/test/mochitest.ini
+++ b/dom/html/test/mochitest.ini
@@ -440,16 +440,17 @@ tags = fullscreen
 skip-if = toolkit == 'android'
 support-files =
   file_fullscreen-api.html
   file_fullscreen-backdrop.html
   file_fullscreen-denied-inner.html
   file_fullscreen-denied.html
   file_fullscreen-esc-exit-inner.html
   file_fullscreen-esc-exit.html
+  file_fullscreen-event-order.html
   file_fullscreen-hidden.html
   file_fullscreen-lenient-setters.html
   file_fullscreen-multiple-inner.html
   file_fullscreen-multiple.html
   file_fullscreen-navigation.html
   file_fullscreen-nested.html
   file_fullscreen-prefixed.html
   file_fullscreen-plugins.html
--- a/dom/html/test/test_fullscreen-api.html
+++ b/dom/html/test/test_fullscreen-api.html
@@ -42,16 +42,17 @@ var gTestWindows = [
   "file_fullscreen-shadowdom.html",
   "file_fullscreen-top-layer.html",
   "file_fullscreen-backdrop.html",
   "file_fullscreen-nested.html",
   "file_fullscreen-prefixed.html",
   "file_fullscreen-unprefix-disabled.html",
   "file_fullscreen-lenient-setters.html",
   "file_fullscreen-table.html",
+  "file_fullscreen-event-order.html",
 ];
 
 var testWindow = null;
 var gTestIndex = 0;
 
 function finish() {
   SimpleTest.finish();
 }
--- a/dom/prio/PrioEncoder.cpp
+++ b/dom/prio/PrioEncoder.cpp
@@ -1,19 +1,22 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ClearOnShutdown.h"
-#include "mozilla/dom/Promise.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/ScopeExit.h"
 #include "mozilla/Services.h"
 #include "mozilla/TextUtils.h"
 
+#include "mozilla/dom/ToJSValue.h"
+
 #include "PrioEncoder.h"
 
 namespace mozilla {
 namespace dom {
 
 /* static */ StaticRefPtr<PrioEncoder> PrioEncoder::sSingleton;
 
 /* static */ PublicKey PrioEncoder::sPublicKeyA = nullptr;
@@ -30,139 +33,153 @@ PrioEncoder::~PrioEncoder()
   if (sPublicKeyB) {
     PublicKey_clear(sPublicKeyB);
     sPublicKeyB = nullptr;
   }
 
   Prio_clear();
 }
 
-/* static */
-already_AddRefed<Promise>
-PrioEncoder::Encode(GlobalObject& aGlobal, const nsCString& aBatchID, const PrioParams& aPrioParams, ErrorResult& aRv)
+/* static */ void
+PrioEncoder::Encode(GlobalObject& aGlobal,
+                    const nsCString& aBatchID,
+                    const PrioParams& aPrioParams,
+                    RootedDictionary<PrioEncodedData>& aData,
+                    ErrorResult& aRv)
 {
   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
-
   if (!global) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
-    return nullptr;
+    return;
   }
 
   SECStatus prio_rv = SECSuccess;
 
   if (!sSingleton) {
     sSingleton = new PrioEncoder();
 
     ClearOnShutdown(&sSingleton);
 
     Prio_init();
 
+    nsresult rv;
+
     nsAutoCStringN<CURVE25519_KEY_LEN_HEX + 1> prioKeyA;
-    nsresult rv = Preferences::GetCString("prio.publicKeyA", prioKeyA);
+    rv = Preferences::GetCString("prio.publicKeyA", prioKeyA);
     if (NS_FAILED(rv)) {
       aRv.Throw(NS_ERROR_UNEXPECTED);
-      return nullptr;
+      return;
     }
 
     nsAutoCStringN<CURVE25519_KEY_LEN_HEX + 1> prioKeyB;
     rv = Preferences::GetCString("prio.publicKeyB", prioKeyB);
     if (NS_FAILED(rv)) {
       aRv.Throw(NS_ERROR_UNEXPECTED);
-      return nullptr;
+      return;
     }
 
     // Check that both public keys are of the right length
     // and contain only hex digits 0-9a-fA-f
     if (!PrioEncoder::IsValidHexPublicKey(prioKeyA)
         || !PrioEncoder::IsValidHexPublicKey(prioKeyB))  {
       aRv.Throw(NS_ERROR_UNEXPECTED);
-      return nullptr;
+      return;
     }
 
-    prio_rv = PublicKey_import_hex(&sPublicKeyA, reinterpret_cast<const unsigned char*>(prioKeyA.BeginReading()), CURVE25519_KEY_LEN_HEX);
+    prio_rv = PublicKey_import_hex(&sPublicKeyA,
+                                   reinterpret_cast<const unsigned char*>(prioKeyA.BeginReading()),
+                                   CURVE25519_KEY_LEN_HEX);
     if (prio_rv != SECSuccess) {
       aRv.Throw(NS_ERROR_UNEXPECTED);
-      return nullptr;
+      return;
     }
 
-    prio_rv = PublicKey_import_hex(&sPublicKeyB, reinterpret_cast<const unsigned char*>(prioKeyB.BeginReading()), CURVE25519_KEY_LEN_HEX);
+    prio_rv = PublicKey_import_hex(&sPublicKeyB,
+              reinterpret_cast<const unsigned char*>(prioKeyB.BeginReading()),
+              CURVE25519_KEY_LEN_HEX);
     if (prio_rv != SECSuccess) {
       aRv.Throw(NS_ERROR_UNEXPECTED);
-      return nullptr;
+      return;
     }
   }
 
-  RefPtr<Promise> promise = Promise::Create(global, aRv);
-
   bool dataItems[] = {
-    aPrioParams.mStartupCrashDetected,
-    aPrioParams.mSafeModeUsage,
-    aPrioParams.mBrowserIsUserDefault
+    aPrioParams.mBrowserIsUserDefault,
+    aPrioParams.mNewTabPageEnabled,
+    aPrioParams.mPdfViewerUsed,
   };
 
-  PrioConfig prioConfig = PrioConfig_new(mozilla::ArrayLength(dataItems), sPublicKeyA, sPublicKeyB, reinterpret_cast<const unsigned char*>(aBatchID.BeginReading()), aBatchID.Length());
+  PrioConfig prioConfig = PrioConfig_new(mozilla::ArrayLength(dataItems),
+                                         sPublicKeyA,
+                                         sPublicKeyB,
+                                         reinterpret_cast<const unsigned char*>(aBatchID.BeginReading()),
+                                         aBatchID.Length());
 
   if (!prioConfig) {
-    promise->MaybeReject(NS_ERROR_FAILURE);
-    return promise.forget();
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
   }
 
   auto configGuard = MakeScopeExit([&] {
     PrioConfig_clear(prioConfig);
   });
 
   unsigned char* forServerA = nullptr;
   unsigned int lenA = 0;
   unsigned char* forServerB = nullptr;
   unsigned int lenB = 0;
 
-  prio_rv = PrioClient_encode(prioConfig, dataItems, &forServerA, &lenA, &forServerB, &lenB);
-
-  // Package the data into the dictionary
-  PrioEncodedData data;
+  prio_rv = PrioClient_encode(prioConfig,
+                              dataItems,
+                              &forServerA,
+                              &lenA,
+                              &forServerB,
+                              &lenB);
 
   nsTArray<uint8_t> arrayForServerA;
   nsTArray<uint8_t> arrayForServerB;
 
-  if (!arrayForServerA.AppendElements(reinterpret_cast<uint8_t*>(forServerA), lenA, fallible)) {
-    promise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
-    return promise.forget();
+  if (!arrayForServerA.AppendElements(reinterpret_cast<uint8_t*>(forServerA),
+                                      lenA,
+                                      fallible)) {
+    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+    return;
   }
 
   free(forServerA);
 
-  if (!arrayForServerB.AppendElements(reinterpret_cast<uint8_t*>(forServerB), lenB, fallible)) {
-    promise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
-    return promise.forget();
+  if (!arrayForServerB.AppendElements(reinterpret_cast<uint8_t*>(forServerB),
+                                      lenB,
+                                      fallible)) {
+    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+    return ;
   }
 
   free(forServerB);
 
+  if (prio_rv != SECSuccess) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
+
   JS::Rooted<JS::Value> valueA(aGlobal.Context());
   if (!ToJSValue(aGlobal.Context(), TypedArrayCreator<Uint8Array>(arrayForServerA), &valueA)) {
-    promise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
-    return promise.forget();
+    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+    return;
   }
-  data.mA.Construct().Init(&valueA.toObject());
+
+  aData.mA.Construct().Init(&valueA.toObject());
 
   JS::Rooted<JS::Value> valueB(aGlobal.Context());
   if (!ToJSValue(aGlobal.Context(), TypedArrayCreator<Uint8Array>(arrayForServerB), &valueB)) {
-    promise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
-    return promise.forget();
-  }
-  data.mB.Construct().Init(&valueB.toObject());
-
-  if (prio_rv != SECSuccess) {
-    promise->MaybeReject(NS_ERROR_FAILURE);
-    return promise.forget();
+    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+    return;
   }
 
-  promise->MaybeResolve(data);
-
-  return promise.forget();
+  aData.mB.Construct().Init(&valueB.toObject());
 }
 
 bool
 PrioEncoder::IsValidHexPublicKey(mozilla::Span<const char> aStr)
 {
   if (aStr.Length() != CURVE25519_KEY_LEN_HEX) {
     return false;
   }
--- a/dom/prio/PrioEncoder.h
+++ b/dom/prio/PrioEncoder.h
@@ -16,18 +16,22 @@ class nsIGlobalObject;
 namespace mozilla {
 namespace dom {
 
 class PrioEncoder
 {
 public:
   NS_INLINE_DECL_REFCOUNTING(PrioEncoder)
 
-  static already_AddRefed<Promise>
-  Encode(GlobalObject& aGlobal, const nsCString& aBatchID, const PrioParams& aPrioParams, ErrorResult& aRv);
+  static
+  void Encode(GlobalObject& aGlobal,
+              const nsCString& aBatchID,
+              const PrioParams& aPrioParams,
+              RootedDictionary<PrioEncodedData>& aData,
+              ErrorResult& aRv);
 
 private:
   PrioEncoder();
   ~PrioEncoder();
 
   static PublicKey
   sPublicKeyA;
 
--- a/js/src/jit/BaselineInspector.cpp
+++ b/js/src/jit/BaselineInspector.cpp
@@ -376,20 +376,25 @@ ParseCacheIRStub(ICStub* stub)
       case CacheOp::Int32MulResult:
       case CacheOp::Int32DivResult:
       case CacheOp::Int32ModResult:
       case CacheOp::Int32BitOrResult:
       case CacheOp::Int32BitXorResult:
       case CacheOp::Int32BitAndResult:
       case CacheOp::Int32LeftShiftResult:
       case CacheOp::Int32RightShiftResult:
-      case CacheOp::Int32URightShiftResult:
       case CacheOp::Int32NotResult:
       case CacheOp::Int32NegationResult:
         return MIRType::Int32;
+      // Int32URightShiftResult may return a double under some
+      // circumstances.
+      case CacheOp::Int32URightShiftResult:
+        reader.skip(); // Skip over lhs
+        reader.skip(); // Skip over rhs
+        return reader.readByte() == 0  ?  MIRType::Int32 : MIRType::Double;
       case CacheOp::LoadValueResult:
         return MIRType::Value;
       default:
         MOZ_CRASH("Unknown op");
         return MIRType::None;
     }
 }
 
--- a/layout/generic/nsFlexContainerFrame.cpp
+++ b/layout/generic/nsFlexContainerFrame.cpp
@@ -4247,20 +4247,18 @@ nsFlexContainerFrame::SizeItemInCrossAxi
     MeasureAscentAndBSizeForFlexItem(aItem, aPresContext, aChildReflowInput);
 
   // Save the sizing info that we learned from this reflow
   // -----------------------------------------------------
 
   // Tentatively store the child's desired content-box cross-size.
   // Note that childDesiredSize is the border-box size, so we have to
   // subtract border & padding to get the content-box size.
-  // (Note that at this point in the code, we know our cross axis is vertical,
-  // so we don't bother with making aAxisTracker pick the cross-axis component
-  // for us.)
-  nscoord crossAxisBorderPadding = aItem.GetBorderPadding().TopBottom();
+  nscoord crossAxisBorderPadding =
+    aItem.GetBorderPaddingSizeInAxis(aAxisTracker.GetCrossAxis());
   if (reflowResult.BSize() < crossAxisBorderPadding) {
     // Child's requested size isn't large enough for its border/padding!
     // This is OK for the trivial nsFrame::Reflow() impl, but other frame
     // classes should know better. So, if we get here, the child had better be
     // an instance of nsFrame (i.e. it should return null from GetType()).
     // XXXdholbert Once we've fixed bug 765861, we should upgrade this to an
     // assertion that trivially passes if bug 765861's flag has been flipped.
     NS_WARNING_ASSERTION(
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/flexbox/flexbox-writing-mode-016-ref.html
@@ -0,0 +1,136 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>CSS Reftest Reference</title>
+  <meta charset="utf-8">
+  <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+  <style>
+  .container {
+    display: block;
+    border: 2px solid purple;
+    margin: 3px;
+    /* This red should't be visible, because each container should shrinkwrap
+       its sole child (and the child should cover up this background). */
+    background: red;
+    /* Float the containers, to test in "rows", with 1 row per writing-mode. */
+    float: left;
+  }
+  br { clear: both; }
+
+  .container > * {
+    width: 10px;
+    height: 10px;
+    background: teal;
+    border: 1px solid yellow;
+  }
+  .container > * > * {
+    background: pink;
+    height: 4px;
+    width: 4px;
+    border: 1px solid black;
+  }
+
+  .pad_top    { padding-top:    3px; }
+  .pad_right  { padding-right:  4px; }
+  .pad_bottom { padding-bottom: 5px; }
+  .pad_left   { padding-left:   6px; }
+
+  .hl  { writing-mode: horizontal-tb;  direction: ltr; }
+  .hr  { writing-mode: horizontal-tb;  direction: rtl; }
+  .vl  { writing-mode: vertical-lr;    direction: ltr; }
+  .vr  { writing-mode: vertical-rl;    direction: ltr; }
+  .vl_rtl { writing-mode: vertical-lr; direction: rtl; }
+  .vr_rtl { writing-mode: vertical-rl; direction: rtl; }
+  </style>
+</head>
+<body>
+  <!-- Here, we test padding on each side of a flex item, across 6 different
+       writing-mode combinations (writing-mode X direction). -->
+  <div class="container hl">
+    <div class="pad_top"><div></div></div>
+  </div>
+  <div class="container hl">
+    <div class="pad_right"><div></div></div>
+  </div>
+  <div class="container hl">
+    <div class="pad_bottom"><div></div></div>
+  </div>
+  <div class="container hl">
+    <div class="pad_left"><div></div></div>
+  </div>
+  <br>
+
+  <div class="container hr">
+    <div class="pad_top"><div></div></div>
+  </div>
+  <div class="container hr">
+    <div class="pad_right"><div></div></div>
+  </div>
+  <div class="container hr">
+    <div class="pad_bottom"><div></div></div>
+  </div>
+  <div class="container hr">
+    <div class="pad_left"><div></div></div>
+  </div>
+  <br>
+
+  <div class="container vl">
+    <div class="pad_top"><div></div></div>
+  </div>
+  <div class="container vl">
+    <div class="pad_right"><div></div></div>
+  </div>
+  <div class="container vl">
+    <div class="pad_bottom"><div></div></div>
+  </div>
+  <div class="container vl">
+    <div class="pad_left"><div></div></div>
+  </div>
+  <br>
+
+  <div class="container vr">
+    <div class="pad_top"><div></div></div>
+  </div>
+  <div class="container vr">
+    <div class="pad_right"><div></div></div>
+  </div>
+  <div class="container vr">
+    <div class="pad_bottom"><div></div></div>
+  </div>
+  <div class="container vr">
+    <div class="pad_left"><div></div></div>
+  </div>
+  <br>
+
+  <div class="container vl_rtl">
+    <div class="pad_top"><div></div></div>
+  </div>
+  <div class="container vl_rtl">
+    <div class="pad_right"><div></div></div>
+  </div>
+  <div class="container vl_rtl">
+    <div class="pad_bottom"><div></div></div>
+  </div>
+  <div class="container vl_rtl">
+    <div class="pad_left"><div></div></div>
+  </div>
+  <br>
+
+  <div class="container vr_rtl">
+    <div class="pad_top"><div></div></div>
+  </div>
+  <div class="container vr_rtl">
+    <div class="pad_right"><div></div></div>
+  </div>
+  <div class="container vr_rtl">
+    <div class="pad_bottom"><div></div></div>
+  </div>
+  <div class="container vr_rtl">
+    <div class="pad_left"><div></div></div>
+  </div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/flexbox/flexbox-writing-mode-016.html
@@ -0,0 +1,144 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>
+    CSS Test: Testing auto-sized flex containers
+    with various 'writing-mode' values
+    and various padding amounts on flex items.
+  </title>
+  <meta charset="utf-8">
+  <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+  <link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#flex-direction-property">
+  <link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#propdef-writing-mode">
+  <link rel="match" href="flexbox-writing-mode-016-ref.html">
+  <style>
+  .container {
+    display: flex;
+    flex-direction: row;
+    border: 2px solid purple;
+    margin: 3px;
+    /* This red should't be visible, because each container should shrinkwrap
+       its sole child (and the child should cover up this background). */
+    background: red;
+    /* Float the containers, to test in "rows", with 1 row per writing-mode. */
+    float: left;
+  }
+  br { clear: both; }
+
+  .container > * {
+    width: 10px;
+    height: 10px;
+    background: teal;
+    border: 1px solid yellow;
+  }
+  .container > * > * {
+    background: pink;
+    height: 4px;
+    width: 4px;
+    border: 1px solid black;
+  }
+
+  .pad_top    { padding-top:    3px; }
+  .pad_right  { padding-right:  4px; }
+  .pad_bottom { padding-bottom: 5px; }
+  .pad_left   { padding-left:   6px; }
+
+  .hl  { writing-mode: horizontal-tb;  direction: ltr; }
+  .hr  { writing-mode: horizontal-tb;  direction: rtl; }
+  .vl  { writing-mode: vertical-lr;    direction: ltr; }
+  .vr  { writing-mode: vertical-rl;    direction: ltr; }
+  .vl_rtl { writing-mode: vertical-lr; direction: rtl; }
+  .vr_rtl { writing-mode: vertical-rl; direction: rtl; }
+  </style>
+</head>
+<body>
+  <!-- Here, we test padding on each side of a flex item, across 6 different
+       writing-mode combinations (writing-mode X direction). -->
+  <div class="container hl">
+    <div class="pad_top"><div></div></div>
+  </div>
+  <div class="container hl">
+    <div class="pad_right"><div></div></div>
+  </div>
+  <div class="container hl">
+    <div class="pad_bottom"><div></div></div>
+  </div>
+  <div class="container hl">
+    <div class="pad_left"><div></div></div>
+  </div>
+  <br>
+
+  <div class="container hr">
+    <div class="pad_top"><div></div></div>
+  </div>
+  <div class="container hr">
+    <div class="pad_right"><div></div></div>
+  </div>
+  <div class="container hr">
+    <div class="pad_bottom"><div></div></div>
+  </div>
+  <div class="container hr">
+    <div class="pad_left"><div></div></div>
+  </div>
+  <br>
+
+  <div class="container vl">
+    <div class="pad_top"><div></div></div>
+  </div>
+  <div class="container vl">
+    <div class="pad_right"><div></div></div>
+  </div>
+  <div class="container vl">
+    <div class="pad_bottom"><div></div></div>
+  </div>
+  <div class="container vl">
+    <div class="pad_left"><div></div></div>
+  </div>
+  <br>
+
+  <div class="container vr">
+    <div class="pad_top"><div></div></div>
+  </div>
+  <div class="container vr">
+    <div class="pad_right"><div></div></div>
+  </div>
+  <div class="container vr">
+    <div class="pad_bottom"><div></div></div>
+  </div>
+  <div class="container vr">
+    <div class="pad_left"><div></div></div>
+  </div>
+  <br>
+
+  <div class="container vl_rtl">
+    <div class="pad_top"><div></div></div>
+  </div>
+  <div class="container vl_rtl">
+    <div class="pad_right"><div></div></div>
+  </div>
+  <div class="container vl_rtl">
+    <div class="pad_bottom"><div></div></div>
+  </div>
+  <div class="container vl_rtl">
+    <div class="pad_left"><div></div></div>
+  </div>
+  <br>
+
+  <div class="container vr_rtl">
+    <div class="pad_top"><div></div></div>
+  </div>
+  <div class="container vr_rtl">
+    <div class="pad_right"><div></div></div>
+  </div>
+  <div class="container vr_rtl">
+    <div class="pad_bottom"><div></div></div>
+  </div>
+  <div class="container vr_rtl">
+    <div class="pad_left"><div></div></div>
+  </div>
+</body>
+</html>
--- a/layout/reftests/w3c-css/submitted/flexbox/reftest.list
+++ b/layout/reftests/w3c-css/submitted/flexbox/reftest.list
@@ -256,16 +256,17 @@ fails == flexbox-min-height-auto-002b.ht
 == flexbox-writing-mode-008.html flexbox-writing-mode-008-ref.html
 == flexbox-writing-mode-009.html flexbox-writing-mode-009-ref.html
 == flexbox-writing-mode-010.html flexbox-writing-mode-010-ref.html
 == flexbox-writing-mode-011.html flexbox-writing-mode-011-ref.html
 == flexbox-writing-mode-012.html flexbox-writing-mode-012-ref.html
 == flexbox-writing-mode-013.html flexbox-writing-mode-013-ref.html
 == flexbox-writing-mode-014.html flexbox-writing-mode-014-ref.html
 == flexbox-writing-mode-015.html flexbox-writing-mode-015-ref.html
+== flexbox-writing-mode-016.html flexbox-writing-mode-016-ref.html
 
 # Single-line size clamping
 == flexbox-single-line-clamp-1.html flexbox-single-line-clamp-1-ref.html
 == flexbox-single-line-clamp-2.html flexbox-single-line-clamp-2-ref.html
 == flexbox-single-line-clamp-3.html flexbox-single-line-clamp-3-ref.html
 
 # Flexbox as an absolute containing block.
 == position-absolute-containing-block-001.html position-absolute-containing-block-001-ref.html
--- a/layout/xul/nsXULTooltipListener.cpp
+++ b/layout/xul/nsXULTooltipListener.cpp
@@ -584,18 +584,18 @@ nsXULTooltipListener::FindTooltip(nsICon
   if (!window) {
     return NS_OK;
   }
 
   if (window->Closed()) {
     return NS_OK;
   }
 
-  // non-XUL documents should just use the default tooltip
-  if (!document->IsXULDocument()) {
+  // non-XUL elements should just use the default tooltip
+  if (!aTarget->IsXULElement()) {
     nsIPopupContainer* popupContainer =
       nsIPopupContainer::GetPopupContainer(document->GetShell());
     NS_ENSURE_STATE(popupContainer);
     if (RefPtr<Element> tooltip = popupContainer->GetDefaultTooltip()) {
       tooltip.forget(aTooltip);
       return NS_OK;
     }
     return NS_ERROR_FAILURE;
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -5890,8 +5890,13 @@ pref("mozilla.widget.use-argb-visuals", 
 #endif
 
 #ifdef NIGHTLY_BUILD
 // Disable moz* APIs in DataTransfer
 pref("dom.datatransfer.mozAtAPIs", false);
 #else
 pref("dom.datatransfer.mozAtAPIs", true);
 #endif
+
+// Whether or not Prio is supported on this platform.
+#ifdef MOZ_LIBPRIO
+pref("prio.enabled", false);
+#endif
--- a/python/mozbuild/mozbuild/backend/tup.py
+++ b/python/mozbuild/mozbuild/backend/tup.py
@@ -696,21 +696,36 @@ class TupBackend(CommonBackend):
                 os.path.relpath(self.environment.topsrcdir, self.environment.topobjdir)
             ))
             fh.write('PYTHON = PYTHONDONTWRITEBYTECODE=1 %s\n' % self.environment.substs['PYTHON'])
             fh.write('PYTHON_PATH = $(PYTHON) $(topsrcdir)/config/pythonpath.py\n')
             fh.write('PLY_INCLUDE = -I$(topsrcdir)/other-licenses/ply\n')
             fh.write('IDL_PARSER_DIR = $(topsrcdir)/xpcom/idl-parser\n')
             fh.write('IDL_PARSER_CACHE_DIR = $(MOZ_OBJ_ROOT)/xpcom/idl-parser/xpidl\n')
 
-        # Run 'tup init' if necessary.
-        if not os.path.exists(mozpath.join(self.environment.topsrcdir, ".tup")):
+        # Run 'tup init' if necessary, attempting to cover both the objdir
+        # and srcdir.
+        tup_base_dir = os.path.commonprefix([self.environment.topsrcdir,
+                                             self.environment.topobjdir])
+        if tup_base_dir != self.environment.topsrcdir:
+            if os.path.isdir(mozpath.join(self.environment.topsrcdir, '.tup')):
+                print("Found old tup root at '%s', removing..." %
+                      mozpath.join(self.environment.topsrcdir, '.tup'))
+                shutil.rmtree(mozpath.join(self.environment.topsrcdir, '.tup'))
+        if not os.path.isdir(mozpath.join(tup_base_dir, '.tup')):
+            if tup_base_dir != self.environment.topsrcdir:
+                # Ask the user to figure out where to run 'tup init' before
+                # continuing.
+                raise Exception("Please run `tup init --no-sync` in a common "
+                    "ancestor directory of your objdir and srcdir, possibly "
+                    "%s. To reduce file scanning overhead, this directory "
+                    "should contain the fewest files possible that are not "
+                    "necessary for this build." % tup_base_dir)
             tup = self.environment.substs.get('TUP', 'tup')
-            self._cmd.run_process(cwd=self.environment.topsrcdir, log_name='tup', args=[tup, 'init', '--no-sync'])
-
+            self._cmd.run_process(cwd=tup_base_dir, log_name='tup', args=[tup, 'init', '--no-sync'])
 
     def _get_cargo_flags(self, obj):
         cargo_flags = ['--build-plan', '-Z', 'unstable-options']
         if not self.environment.substs.get('MOZ_DEBUG_RUST'):
             cargo_flags += ['--release']
         cargo_flags += [
             '--frozen',
             '--manifest-path', mozpath.join(obj.srcdir, 'Cargo.toml'),
--- a/toolkit/components/places/UnifiedComplete.js
+++ b/toolkit/components/places/UnifiedComplete.js
@@ -258,34 +258,33 @@ const SQL_ADAPTIVE_QUERY =
 // Result row indexes for originQuery()
 const QUERYINDEX_ORIGIN_AUTOFILLED_VALUE = 1;
 const QUERYINDEX_ORIGIN_URL = 2;
 const QUERYINDEX_ORIGIN_FRECENCY = 3;
 
 // `WITH` clause for the autofill queries.  autofill_frecency_threshold.value is
 // the mean of all moz_origins.frecency values + stddevMultiplier * one standard
 // deviation.  This is inlined directly in the SQL (as opposed to being a custom
-// Sqlite function for example) in order to be as efficient as possible.  The
-// MAX() is to make sure that places with <= 0 frecency are never autofilled.
+// Sqlite function for example) in order to be as efficient as possible.
 const SQL_AUTOFILL_WITH = `
   WITH
   frecency_stats(count, sum, squares) AS (
     SELECT
       CAST((SELECT IFNULL(value, 0.0) FROM moz_meta WHERE key = "origin_frecency_count") AS REAL),
       CAST((SELECT IFNULL(value, 0.0) FROM moz_meta WHERE key = "origin_frecency_sum") AS REAL),
       CAST((SELECT IFNULL(value, 0.0) FROM moz_meta WHERE key = "origin_frecency_sum_of_squares") AS REAL)
   ),
   autofill_frecency_threshold(value) AS (
-    SELECT MAX(1,
+    SELECT
       CASE count
       WHEN 0 THEN 0.0
       WHEN 1 THEN sum
       ELSE (sum / count) + (:stddevMultiplier * sqrt((squares - ((sum * sum) / count)) / count))
       END
-    ) FROM frecency_stats
+    FROM frecency_stats
   )
 `;
 
 const SQL_AUTOFILL_FRECENCY_THRESHOLD = `(
   SELECT value FROM autofill_frecency_threshold
 )`;
 
 function originQuery(conditions = "", bookmarkedFragment = "NULL") {
@@ -352,28 +351,30 @@ function urlQuery(conditions1, condition
           SELECT :query_type,
                  url,
                  :strippedURL,
                  frecency,
                  foreign_count > 0 AS bookmarked,
                  id
           FROM moz_places
           WHERE rev_host = :revHost
-                AND frecency >= ${SQL_AUTOFILL_FRECENCY_THRESHOLD}
+                AND MAX(frecency, 0) >= ${SQL_AUTOFILL_FRECENCY_THRESHOLD}
+                AND hidden = 0
                 ${conditions1}
           UNION ALL
           SELECT :query_type,
                  url,
                  :strippedURL,
                  frecency,
                  foreign_count > 0 AS bookmarked,
                  id
           FROM moz_places
           WHERE rev_host = :revHost || 'www.'
-                AND frecency >= ${SQL_AUTOFILL_FRECENCY_THRESHOLD}
+                AND MAX(frecency, 0) >= ${SQL_AUTOFILL_FRECENCY_THRESHOLD}
+                AND hidden = 0
                 ${conditions2}
           ORDER BY frecency DESC, id DESC
           LIMIT 1 `;
 }
 
 const SQL_URL_QUERY = urlQuery(
   `AND strip_prefix_and_userinfo(url) BETWEEN :strippedURL AND :strippedURL || X'FFFF'`,
   `AND strip_prefix_and_userinfo(url) BETWEEN 'www.' || :strippedURL AND 'www.' || :strippedURL || X'FFFF'`
--- a/toolkit/components/places/tests/unifiedcomplete/autofill_tasks.js
+++ b/toolkit/components/places/tests/unifiedcomplete/autofill_tasks.js
@@ -666,9 +666,67 @@ function addAutofillTasks(origins) {
           comment,
           style: ["autofill", "heuristic"],
         },
       ],
     });
 
     await cleanup();
   });
+
+  // Bookmark a page and then clear history.  The bookmarked origin/URL should
+  // be autofilled even though its frecency is <= 0 since the autofill threshold
+  // is 0.
+  add_task(async function zeroThreshold() {
+    await addBookmark({
+      uri: "http://" + url,
+    });
+
+    await PlacesUtils.history.clear();
+
+    // Make sure the place's frecency is <= 0.  (It will be reset to -1 on the
+    // history.clear() above, and then on idle it will be reset to 0.  xpcshell
+    // tests disable the idle service, so in practice it should always be -1,
+    // but in order to avoid possible intermittent failures in the future, don't
+    // assume that.)
+    let placeFrecency =
+      await PlacesTestUtils.fieldInDB("http://" + url, "frecency");
+    Assert.ok(placeFrecency <= 0);
+
+    // Make sure the origin's frecency is 0.
+    let db = await PlacesUtils.promiseDBConnection();
+    let rows = await db.execute(`
+      SELECT frecency FROM moz_origins WHERE host = '${host}';
+    `);
+    Assert.equal(rows.length, 1);
+    let originFrecency = rows[0].getResultByIndex(0);
+    Assert.equal(originFrecency, 0);
+
+    // Make sure the autofill threshold is 0.
+    rows = await db.execute(`
+      SELECT
+        IFNULL((SELECT value FROM moz_meta WHERE key = "origin_frecency_count"), 0),
+        IFNULL((SELECT value FROM moz_meta WHERE key = "origin_frecency_sum"), 0),
+        IFNULL((SELECT value FROM moz_meta WHERE key = "origin_frecency_sum_of_squares"), 0)
+    `);
+    let count = rows[0].getResultByIndex(0);
+    let sum = rows[0].getResultByIndex(1);
+    let squares = rows[0].getResultByIndex(2);
+    Assert.equal(count, 0);
+    Assert.equal(sum, 0);
+    Assert.equal(squares, 0);
+
+    await check_autocomplete({
+      search,
+      autofilled: url,
+      completed: "http://" + url,
+      matches: [
+        {
+          value: url,
+          comment,
+          style: ["autofill", "heuristic"],
+        },
+      ],
+    });
+
+    await cleanup();
+  });
 }
deleted file mode 100644
--- a/toolkit/components/places/tests/unifiedcomplete/test_zero_frecency.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-// Ensure inline autocomplete doesn't return zero frecency pages.
-
-add_task(async function test_zero_frec_domain() {
-  info("Searching for zero frecency domain should not autoFill it");
-  await PlacesTestUtils.addVisits({
-    uri: NetUtil.newURI("http://mozilla.org/framed_link/"),
-    transition: TRANSITION_FRAMED_LINK,
-  });
-  await check_autocomplete({
-    search: "moz",
-    autofilled: "moz",
-    completed:  "moz",
-  });
-  await cleanup();
-});
-
-add_task(async function test_zero_frec_url() {
-  info("Searching for zero frecency url should not autoFill it");
-  await PlacesTestUtils.addVisits({
-    uri: NetUtil.newURI("http://mozilla.org/framed_link/"),
-    transition: TRANSITION_FRAMED_LINK,
-  });
-  await check_autocomplete({
-    search: "mozilla.org/f",
-    autofilled: "mozilla.org/f",
-    completed:  "mozilla.org/f",
-  });
-  await cleanup();
-});
--- a/toolkit/components/places/tests/unifiedcomplete/xpcshell.ini
+++ b/toolkit/components/places/tests/unifiedcomplete/xpcshell.ini
@@ -51,9 +51,8 @@ skip-if = !sync
 [test_search_engine_restyle.js]
 [test_search_suggestions.js]
 [test_special_search.js]
 [test_swap_protocol.js]
 [test_tab_matches.js]
 [test_trimming.js]
 [test_visit_url.js]
 [test_word_boundary_search.js]
-[test_zero_frecency.js]
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -12829,19 +12829,19 @@
     "expires_in_version": "66",
     "kind": "flag",
     "bug_numbers": [1337115],
     "description": "Both the main session file and its backup could not be read and and the first run pref is false.",
     "operating_systems": ["android"]
   },
   "NUMBER_OF_PROFILES": {
     "record_in_processes": ["main", "content"],
-    "alert_emails": ["amarchesini@mozilla.com"],
-    "expires_in_version": "59",
-    "bug_numbers": [1296606],
+    "alert_emails": ["dtownsend@mozilla.com"],
+    "expires_in_version": "70",
+    "bug_numbers": [1296606, 1488881],
     "kind": "count",
     "description": "Number of named browser profiles for the current user, as reported by the profile service at startup."
   },
   "TIME_TO_FIRST_CLICK_MS": {
     "record_in_processes": ["main", "content"],
     "alert_emails": ["hkirschner@mozilla.com"],
     "bug_numbers": [1307675, 1332511],
     "expires_in_version": "58",
new file mode 100644
--- /dev/null
+++ b/toolkit/components/telemetry/build_scripts/README.md
@@ -0,0 +1,5 @@
+# Telemetry Registries Parsers
+This package exports the parsers for Mozilla's probes registries. These registry file contains the definitions for the different probes (i.e. [scalars](https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/telemetry/collection/scalars.html), [histograms](https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/telemetry/collection/histograms.html) and [events](https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/telemetry/collection/events.html)) that can be used to collect data.
+
+# License
+Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
--- a/toolkit/components/telemetry/build_scripts/gen_event_data.py
+++ b/toolkit/components/telemetry/build_scripts/gen_event_data.py
@@ -2,18 +2,22 @@
 # 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/.
 
 # Write out event information for C++. The events are defined
 # in a file provided as a command-line argument.
 
 from __future__ import print_function
 from collections import OrderedDict
-from parsers.shared_telemetry_utils import StringTable, static_assert, ParserError
-from parsers import parse_events
+from python_mozparsers.shared_telemetry_utils import (
+    StringTable,
+    static_assert,
+    ParserError
+)
+from python_mozparsers import parse_events
 
 import json
 import sys
 import itertools
 
 # The banner/text at the top of the generated file.
 banner = """/* This file is auto-generated, only for internal use in TelemetryEvent.h,
    see gen_event_data.py. */
--- a/toolkit/components/telemetry/build_scripts/gen_event_enum.py
+++ b/toolkit/components/telemetry/build_scripts/gen_event_enum.py
@@ -2,18 +2,18 @@
 # 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/.
 
 # Write out C++ enum definitions that represent the different event types.
 #
 # The events are defined in files provided as command-line arguments.
 
 from __future__ import print_function
-from parsers.shared_telemetry_utils import ParserError
-from parsers import parse_events
+from python_mozparsers.shared_telemetry_utils import ParserError
+from python_mozparsers import parse_events
 
 import sys
 
 banner = """/* This file is auto-generated, see gen_event_enum.py.  */
 """
 
 file_header = """\
 #ifndef mozilla_TelemetryEventEnums_h
--- a/toolkit/components/telemetry/build_scripts/gen_histogram_data.py
+++ b/toolkit/components/telemetry/build_scripts/gen_histogram_data.py
@@ -1,18 +1,22 @@
 # 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/.
 
 # Write out histogram information for C++.  The histograms are defined
 # in a file provided as a command-line argument.
 
 from __future__ import print_function
-from parsers.shared_telemetry_utils import StringTable, static_assert, ParserError
-from parsers import parse_histograms
+from python_mozparsers.shared_telemetry_utils import (
+    StringTable,
+    static_assert,
+    ParserError
+)
+from python_mozparsers import parse_histograms
 
 import sys
 import buildconfig
 
 banner = """/* This file is auto-generated, see gen_histogram_data.py.  */
 """
 
 
--- a/toolkit/components/telemetry/build_scripts/gen_histogram_enum.py
+++ b/toolkit/components/telemetry/build_scripts/gen_histogram_enum.py
@@ -8,18 +8,18 @@
 #   - HistogramCount
 #   - HistogramFirstUseCounter
 #   - HistogramLastUseCounter
 #   - HistogramUseCounterCount
 #
 # The histograms are defined in files provided as command-line arguments.
 
 from __future__ import print_function
-from parsers.shared_telemetry_utils import ParserError
-from parsers import parse_histograms
+from python_mozparsers.shared_telemetry_utils import ParserError
+from python_mozparsers import parse_histograms
 
 import itertools
 import sys
 import buildconfig
 
 
 banner = """/* This file is auto-generated, see gen_histogram_enum.py.  */
 """
--- a/toolkit/components/telemetry/build_scripts/gen_histogram_phf.py
+++ b/toolkit/components/telemetry/build_scripts/gen_histogram_phf.py
@@ -1,19 +1,19 @@
 # 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/.
 
 from __future__ import print_function
-from parsers.shared_telemetry_utils import ParserError
+from python_mozparsers.shared_telemetry_utils import ParserError
 from perfecthash import PerfectHash
 
 PHFSIZE = 512
 
-from parsers import parse_histograms
+from python_mozparsers import parse_histograms
 import sys
 import buildconfig
 
 
 banner = """/* This file is auto-generated, see gen_histogram_phf.py.  */
 """
 
 header = """
--- a/toolkit/components/telemetry/build_scripts/gen_process_data.py
+++ b/toolkit/components/telemetry/build_scripts/gen_process_data.py
@@ -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/.
 
 # Write out processes data for C++. The processes are defined
 # in a file provided as a command-line argument.
 
 from __future__ import print_function
-from parsers.shared_telemetry_utils import ParserError, load_yaml_file
+from python_mozparsers.shared_telemetry_utils import ParserError, load_yaml_file
 
 import sys
 import collections
 
 # The banner/text at the top of the generated file.
 banner = """/* This file is auto-generated from Telemetry build scripts,
    see gen_process_data.py. */
 """
--- a/toolkit/components/telemetry/build_scripts/gen_process_enum.py
+++ b/toolkit/components/telemetry/build_scripts/gen_process_enum.py
@@ -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/.
 
 # Write out processes data for C++. The processes are defined
 # in a file provided as a command-line argument.
 
 from __future__ import print_function
-from parsers.shared_telemetry_utils import ParserError, load_yaml_file
+from python_mozparsers.shared_telemetry_utils import ParserError, load_yaml_file
 
 import sys
 import collections
 
 # The banner/text at the top of the generated file.
 banner = """/* This file is auto-generated from Telemetry build scripts,
    see gen_process_enum.py. */
 """
--- a/toolkit/components/telemetry/build_scripts/gen_scalar_data.py
+++ b/toolkit/components/telemetry/build_scripts/gen_scalar_data.py
@@ -2,18 +2,22 @@
 # 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/.
 
 # Write out scalar information for C++.  The scalars are defined
 # in a file provided as a command-line argument.
 
 from __future__ import print_function
 from collections import OrderedDict
-from parsers.shared_telemetry_utils import StringTable, static_assert, ParserError
-from parsers import parse_scalars
+from python_mozparsers.shared_telemetry_utils import (
+    StringTable,
+    static_assert,
+    ParserError
+)
+from python_mozparsers import parse_scalars
 
 import json
 import sys
 
 # The banner/text at the top of the generated file.
 banner = """/* This file is auto-generated, only for internal use in TelemetryScalar.h,
    see gen_scalar_data.py. */
 """
--- a/toolkit/components/telemetry/build_scripts/gen_scalar_enum.py
+++ b/toolkit/components/telemetry/build_scripts/gen_scalar_enum.py
@@ -3,18 +3,18 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 # Write out a C++ enum definition whose members are the names of
 # scalar types.
 #
 # The scalars are defined in files provided as command-line arguments.
 
 from __future__ import print_function
-from parsers.shared_telemetry_utils import ParserError
-from parsers import parse_scalars
+from python_mozparsers.shared_telemetry_utils import ParserError
+from python_mozparsers import parse_scalars
 
 import sys
 
 banner = """/* This file is auto-generated, see gen_scalar_enum.py.  */
 """
 
 file_header = """\
 #ifndef mozilla_TelemetryScalarEnums_h
rename from toolkit/components/telemetry/build_scripts/parsers/__init__.py
rename to toolkit/components/telemetry/build_scripts/python_mozparsers/__init__.py
rename from toolkit/components/telemetry/build_scripts/parsers/parse_events.py
rename to toolkit/components/telemetry/build_scripts/python_mozparsers/parse_events.py
rename from toolkit/components/telemetry/build_scripts/parsers/parse_histograms.py
rename to toolkit/components/telemetry/build_scripts/python_mozparsers/parse_histograms.py
rename from toolkit/components/telemetry/build_scripts/parsers/parse_scalars.py
rename to toolkit/components/telemetry/build_scripts/python_mozparsers/parse_scalars.py
rename from toolkit/components/telemetry/build_scripts/parsers/shared_telemetry_utils.py
rename to toolkit/components/telemetry/build_scripts/python_mozparsers/shared_telemetry_utils.py
new file mode 100644
--- /dev/null
+++ b/toolkit/components/telemetry/build_scripts/setup.py
@@ -0,0 +1,30 @@
+# 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/.
+
+from setuptools import setup, find_packages
+
+VERSION = '1.0.0'
+
+with open("README.md", "r") as fh:
+    long_description = fh.read()
+
+setup(
+    author='Mozilla Telemetry Team',
+    author_email='telemetry-client-dev@mozilla.com',
+    url=('https://firefox-source-docs.mozilla.org/'
+         'toolkit/components/telemetry/telemetry/collection/index.html'),
+    name='python_mozparsers',
+    description='Shared parsers for the Telemetry probe regitries.',
+    long_description=long_description,
+    long_description_content_type="text/markdown",
+    license='MPL 2.0',
+    packages=find_packages(),
+    version=VERSION,
+    classifiers=[
+        'Topic :: Software Development :: Build Tools',
+        'License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)',
+        'Programming Language :: Python :: 2.7',
+    ],
+    keywords=['mozilla', 'telemetry', 'parsers'],
+)
--- a/toolkit/components/telemetry/docs/data/main-ping.rst
+++ b/toolkit/components/telemetry/docs/data/main-ping.rst
@@ -672,16 +672,34 @@ Structure:
         "name": "awesomescreen.1",
         "reason": "commit",
         "start": 123,
         "end": 456
       }
       ...
     ],
 
+Prio
+----
+This section contains experimental data encoded with a basic version of the Prio system for private aggregation.
+See `the Prio paper <https://crypto.stanford.edu/prio/>`_ and `the libprio Github repo <https://github.com/mozilla/libprio>`_
+for more information.
+
+Prio splits data packets into two "shares", signed for different servers that will do the decryption+decoding and
+aggregation. We call these "Server A" and "Server B", represented as `a` and `b` keys in `payload.prio`.
+
+Structure:
+
+.. code-block:: js
+    "prio": {
+      a: ... // Uint8Array containing data signed for Server A
+      b: ... // Uint8Array containing data signed for Server B
+    }
+
+
 Version History
 ---------------
 
 - Firefox 61:
 
   - Stopped reporting ``childPayloads`` (`bug 1443599 <https://bugzilla.mozilla.org/show_bug.cgi?id=1443599>`_).
   - Stopped reporting ``saved-session`` pings on Firefox Desktop (`bug 1443603 <https://bugzilla.mozilla.org/show_bug.cgi?id=1443603>`_).
   - Stopped reporting ``simpleMeasurements.js`` (`bug 1278920 <https://bugzilla.mozilla.org/show_bug.cgi?id=1278920>`_).
--- a/toolkit/components/telemetry/pings/TelemetrySession.jsm
+++ b/toolkit/components/telemetry/pings/TelemetrySession.jsm
@@ -82,16 +82,19 @@ const IDLE_TIMEOUT_SECONDS = Services.pr
 // in case of aborted sessions (currently 5 minutes).
 const ABORTED_SESSION_UPDATE_INTERVAL_MS = 5 * 60 * 1000;
 
 const TOPIC_CYCLE_COLLECTOR_BEGIN = "cycle-collector-begin";
 
 // How long to wait in millis for all the child memory reports to come in
 const TOTAL_MEMORY_COLLECTOR_TIMEOUT = 200;
 
+// Control whether Telemetry data should be encrypted with Prio.
+const PRIO_ENABLED_PREF = "prio.enabled";
+
 var gLastMemoryPoll = null;
 
 var gWasDebuggerAttached = false;
 
 XPCOMUtils.defineLazyServiceGetters(this, {
   Telemetry: ["@mozilla.org/base/telemetry;1", "nsITelemetry"],
   idleService: ["@mozilla.org/widget/idleservice;1", "nsIIdleService"],
 });
@@ -1163,16 +1166,21 @@ var Impl = {
       }
 
       // Add process measurements to payload.
       payloadObj.processes[processType] = processPayload;
     }
 
     payloadObj.info = info;
 
+    // Collect Prio-encoded measurements.
+    if (Services.prefs.getBoolPref(PRIO_ENABLED_PREF, false)) {
+      payloadObj.prio = protect(() => this._prioEncode());
+    }
+
     // Add extended set measurements for chrome process.
     if (Telemetry.canRecordExtended) {
       payloadObj.slowSQL = protect(() => Telemetry.slowSQL);
       payloadObj.fileIOReports = protect(() => Telemetry.fileIOReports);
       payloadObj.lateWrites = protect(() => Telemetry.lateWrites);
 
       payloadObj.addonDetails = protect(() => AddonManagerPrivate.getTelemetryDetails());
 
@@ -1942,9 +1950,49 @@ var Impl = {
     return TelemetryController.saveAbortedSessionPing(payload);
   },
 
   async markNewProfilePingSent() {
     this._log.trace("markNewProfilePingSent");
     this._newProfilePingSent = true;
     return TelemetryStorage.saveSessionData(this._getSessionDataObject());
   },
+
+  /**
+   * Encodes data for experimental Prio pilot project.
+   *
+   * @return {Object} An object containing Prio-encoded data.
+   */
+  _prioEncode() {
+    // First, map the Telemetry histogram names to the params PrioEncoder.encode() expects.
+    const prioEncodedHistograms = {
+      "BROWSER_IS_USER_DEFAULT": "browserIsUserDefault",
+      "NEWTAB_PAGE_ENABLED": "newTabPageEnabled",
+      "PDF_VIEWER_USED": "pdfViewerUsed",
+    };
+
+    // Build list of Prio parameters, using the first value recorded in each histogram.
+    let prioParams = {};
+    for (const [histogramName, prioName] of Object.entries(prioEncodedHistograms)) {
+      try {
+        const histogram = Telemetry.getHistogramById(histogramName);
+        const firstCount = Boolean(histogram.snapshot().sum);
+        prioParams[prioName] = firstCount;
+
+      } catch (ex) {
+        this._log.error(ex);
+      }
+    }
+
+    // Prio encode the data and add to payload.
+    const batchID = Policy.now();
+
+    let prioEncodedData;
+
+    try {
+      prioEncodedData = PrioEncoder.encode(batchID, prioParams);
+    } catch (ex) {
+      this._log.error(ex);
+    }
+
+    return prioEncodedData;
+  },
 };
--- a/toolkit/components/telemetry/tests/python/test_histogramtools_non_strict.py
+++ b/toolkit/components/telemetry/tests/python/test_histogramtools_non_strict.py
@@ -8,17 +8,17 @@ import sys
 import unittest
 from os import path
 
 TELEMETRY_ROOT_PATH = path.abspath(path.join(path.dirname(__file__), path.pardir, path.pardir))
 sys.path.append(TELEMETRY_ROOT_PATH)
 # The parsers live in a subdirectory of "build_scripts", account for that.
 # NOTE: if the parsers are moved, this logic will need to be updated.
 sys.path.append(path.join(TELEMETRY_ROOT_PATH, "build_scripts"))
-from parsers import parse_histograms   # noqa: E402
+from python_mozparsers import parse_histograms   # noqa: E402
 
 
 def load_histogram(histograms):
     """Parse the passed Histogram and return a dictionary mapping histogram
     names to histogram parameters.
 
     :param histogram: Histogram as a python dictionary
     :returns: Parsed Histogram dictionary mapping histogram names to histogram parameters
--- a/toolkit/components/telemetry/tests/python/test_histogramtools_strict.py
+++ b/toolkit/components/telemetry/tests/python/test_histogramtools_strict.py
@@ -8,18 +8,18 @@ import unittest
 from os import path
 from test_histogramtools_non_strict import load_histogram
 
 TELEMETRY_ROOT_PATH = path.abspath(path.join(path.dirname(__file__), path.pardir, path.pardir))
 sys.path.append(TELEMETRY_ROOT_PATH)
 # The parsers live in a subdirectory of "build_scripts", account for that.
 # NOTE: if the parsers are moved, this logic will need to be updated.
 sys.path.append(path.join(TELEMETRY_ROOT_PATH, "build_scripts"))
-from parsers.shared_telemetry_utils import ParserError
-from parsers import parse_histograms
+from python_mozparsers.shared_telemetry_utils import ParserError
+from python_mozparsers import parse_histograms
 
 
 class TestParser(unittest.TestCase):
     def test_valid_histogram(self):
         SAMPLE_HISTOGRAM = {
             "TEST_VALID_HISTOGRAM": {
                 "record_in_processes": ["main", "content"],
                 "alert_emails": ["team@mozilla.xyz"],
--- a/toolkit/components/telemetry/tests/python/test_parse_scalars.py
+++ b/toolkit/components/telemetry/tests/python/test_parse_scalars.py
@@ -8,18 +8,18 @@ import sys
 import unittest
 from os import path
 
 TELEMETRY_ROOT_PATH = path.abspath(path.join(path.dirname(__file__), path.pardir, path.pardir))
 sys.path.append(TELEMETRY_ROOT_PATH)
 # The parsers live in a subdirectory of "build_scripts", account for that.
 # NOTE: if the parsers are moved, this logic will need to be updated.
 sys.path.append(path.join(TELEMETRY_ROOT_PATH, "build_scripts"))
-from parsers.shared_telemetry_utils import ParserError
-from parsers import parse_scalars
+from python_mozparsers.shared_telemetry_utils import ParserError
+from python_mozparsers import parse_scalars
 
 
 def load_scalar(scalar):
     """Parse the passed Scalar and return a dictionary
 
     :param scalar: Scalar as YAML string
     :returns: Parsed Scalar dictionary
     """
--- a/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
@@ -398,16 +398,21 @@ function checkPayload(payload, reason, s
       values: {0: 1, 1: 0},
       sum: 1,
     },
   };
   Assert.deepEqual(expected_keyed_count, keyedHistograms[TELEMETRY_TEST_KEYED_COUNT]);
 
   Assert.ok("processes" in payload, "The payload must have a processes section.");
   Assert.ok("parent" in payload.processes, "There must be at least a parent process.");
+
+  if (Services.prefs.getBoolPref("prio.enabled", false)) {
+    Assert.ok("prio" in payload, "The payload must have a prio section.");
+  }
+
   checkScalars(payload.processes);
 }
 
 function writeStringToFile(file, contents) {
   let ostream = Cc["@mozilla.org/network/safe-file-output-stream;1"]
                 .createInstance(Ci.nsIFileOutputStream);
   ostream.init(file, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
                RW_OWNER, ostream.DEFER_OPEN);
--- a/toolkit/moz.configure
+++ b/toolkit/moz.configure
@@ -1065,17 +1065,19 @@ def launcher(value, target):
     if enabled:
         return True
 
 set_config('MOZ_LAUNCHER_PROCESS', launcher)
 set_define('MOZ_LAUNCHER_PROCESS', launcher)
 
 # Prio
 # ==============================================================
-@depends(c_compiler)
-def libprio(info):
+@depends(c_compiler, target)
+def libprio(info, target):
     if info:
-      if info.type in ('msvc',):
+      # TODO - re-enable Windows when bug 1489691 is fixed.
+      # Note that we will probably never support MSVC however.
+      if info.type in ('msvc',) or target.os in ('WINNT',):
         return None
     return True
 
 set_config('MOZ_LIBPRIO', libprio)
 
--- a/toolkit/xre/nsXREDirProvider.cpp
+++ b/toolkit/xre/nsXREDirProvider.cpp
@@ -1171,31 +1171,37 @@ GetCachedHash(HKEY rootKey, const nsAStr
   if (result == ERROR_SUCCESS) {
     cachedHash.Assign(cachedHashRaw);
   }
   return ERROR_SUCCESS == result;
 }
 
 #endif
 
+// Compatibility Mode (aUseCompatibilityMode) outputs hashes that are what this
+// function has historically returned. The new default is to output hashes that
+// are consistent with those generated by the installer.
 nsresult
-nsXREDirProvider::GetInstallHash(nsAString & aPathHash)
+nsXREDirProvider::GetInstallHash(nsAString & aPathHash,
+                                 bool aUseCompatibilityMode /* = false */)
 {
   nsCOMPtr<nsIFile> updRoot;
   nsCOMPtr<nsIFile> appFile;
   bool per = false;
   nsresult rv = GetFile(XRE_EXECUTABLE_FILE, &per, getter_AddRefs(appFile));
   NS_ENSURE_SUCCESS(rv, rv);
   rv = appFile->GetParent(getter_AddRefs(updRoot));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoString appDirPath;
   rv = updRoot->GetPath(appDirPath);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  aPathHash.Truncate();
+
 #ifdef XP_WIN
   // Figure out where we should check for a cached hash value. If the
   // application doesn't have the nsXREAppData vendor value defined check
   // under SOFTWARE\Mozilla.
   bool hasVendor = gAppData->vendor && strlen(gAppData->vendor) != 0;
   wchar_t regPath[1024] = { L'\0' };
   swprintf_s(regPath, mozilla::ArrayLength(regPath), L"SOFTWARE\\%S\\%S\\TaskBarIDs",
               (hasVendor ? gAppData->vendor : "Mozilla"), MOZ_APP_BASENAME);
@@ -1211,23 +1217,27 @@ nsXREDirProvider::GetInstallHash(nsAStri
     return NS_OK;
   }
 #endif
 
   // This should only happen when the installer isn't used (e.g. zip builds).
   void* buffer = appDirPath.BeginWriting();
   uint32_t length = appDirPath.Length() * sizeof(nsAutoString::char_type);
   uint64_t hash = CityHash64(static_cast<const char*>(buffer), length);
-  aPathHash.AppendInt((int)(hash >> 32), 16);
-  aPathHash.AppendInt((int)hash, 16);
-  // The installer implementation writes the registry values that were checked
-  // in the previous block for this value in uppercase and since it is an
-  // option to have a case sensitive file system on Windows this value must
-  // also be in uppercase.
-  ToUpperCase(aPathHash);
+  if (aUseCompatibilityMode) {
+    aPathHash.AppendInt((int)(hash >> 32), 16);
+    aPathHash.AppendInt((int)hash, 16);
+    // The installer implementation writes the registry values that were checked
+    // in the previous block for this value in uppercase and since it is an
+    // option to have a case sensitive file system on Windows this value must
+    // also be in uppercase.
+    ToUpperCase(aPathHash);
+  } else {
+    aPathHash.AppendPrintf("%" PRIX64, hash);
+  }
 
   return NS_OK;
 }
 
 nsresult
 nsXREDirProvider::GetUpdateRootDir(nsIFile* *aResult)
 {
   nsCOMPtr<nsIFile> updRoot;
@@ -1270,17 +1280,17 @@ nsXREDirProvider::GetUpdateRootDir(nsIFi
     return NS_ERROR_FAILURE;
   }
 
   localDir.forget(aResult);
   return NS_OK;
 
 #elif XP_WIN
   nsAutoString pathHash;
-  rv = GetInstallHash(pathHash);
+  rv = GetInstallHash(pathHash, true);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // As a last ditch effort, get the local app data directory and if a vendor
   // name exists append it. If only a product name exists, append it. If neither
   // exist fallback to old handling. We don't use the product name on purpose
   // because we want a shared update directory for different apps run from the
   // same path.
   nsCOMPtr<nsIFile> localDir;
--- a/toolkit/xre/nsXREDirProvider.h
+++ b/toolkit/xre/nsXREDirProvider.h
@@ -67,17 +67,18 @@ public:
     if (mXULAppDir)
       return mXULAppDir;
     return mGREDir;
   }
 
   /**
    * Get a hash for the install directory.
    */
-  nsresult GetInstallHash(nsAString & aPathHash);
+  nsresult GetInstallHash(nsAString & aPathHash,
+                          bool aUseCompatibilityMode = false);
 
   /**
    * Get the directory under which update directory is created.
    * This method may be called before XPCOM is started. aResult
    * is a clone, it may be modified.
    */
   nsresult GetUpdateRootDir(nsIFile* *aResult);
 
--- a/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/recommended.js
+++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/recommended.js
@@ -50,16 +50,17 @@ module.exports = {
     "KeyEvent": false,
     "MatchGlob": false,
     "MatchPattern": false,
     "MatchPatternSet": false,
     "MenuBoxObject": false,
     // Specific to Firefox (Chrome code only).
     "PlacesObservers": false,
     "PlacesWeakCallbackWrapper": false,
+    "PrioEncoder": false,
     // Specific to Firefox (Chrome code only).
     "SharedArrayBuffer": false,
     "SimpleGestureEvent": false,
     // Note: StopIteration will likely be removed as part of removing legacy
     // generators, see bug 968038.
     "StopIteration": false,
     "StructuredCloneHolder": false,
     "WebAssembly": false,