Merge autoland to central, a=merge
authorWes Kocher <wkocher@mozilla.com>
Tue, 01 Aug 2017 12:58:59 -0700
changeset 420899 65d1f1440a9fd3006e2c94a811986d3df84b257d
parent 420876 ef9a0f01e4f68214f0ff8f4631783b8a0e075a82 (current diff)
parent 420898 2ca9999610542d892390ed7da7d28e0c30ec2867 (diff)
child 420924 a3e675a3b10a0ea289c301bedc31866f3daf7875
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone56.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge autoland to central, a=merge MozReview-Commit-ID: 5yEsTtR0WIL
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -1504,20 +1504,24 @@ var BookmarkingUI = {
     this._recentlyBookmarkedObserver.onItemRemoved = () => {
       // Update the menu when a bookmark has been removed.
       // The native menubar on Mac doesn't support live update, so this won't
       // work there.
       this._populateRecentBookmarks(aHeaderItem, aExtraCSSClass);
     };
 
     let updatePlacesContextMenu = (shouldHidePrefUI = false) => {
-      let prefEnabled = !shouldHidePrefUI && Services.prefs.getBoolPref(this.RECENTLY_BOOKMARKED_PREF);
       let showItem = document.getElementById("placesContext_showRecentlyBookmarked");
+      // On Mac the menuitem doesn't exist when we're in the Library window context.
+      if (!showItem) {
+        return;
+      }
       let hideItem = document.getElementById("placesContext_hideRecentlyBookmarked");
       let separator = document.getElementById("placesContext_recentlyBookmarkedSeparator");
+      let prefEnabled = !shouldHidePrefUI && Services.prefs.getBoolPref(this.RECENTLY_BOOKMARKED_PREF);
       showItem.hidden = shouldHidePrefUI || prefEnabled;
       hideItem.hidden = shouldHidePrefUI || !prefEnabled;
       separator.hidden = shouldHidePrefUI;
       if (!shouldHidePrefUI) {
         // Move to the bottom of the menu.
         separator.parentNode.appendChild(separator);
         showItem.parentNode.appendChild(showItem);
         hideItem.parentNode.appendChild(hideItem);
--- a/browser/extensions/formautofill/FormAutofillPreferences.jsm
+++ b/browser/extensions/formautofill/FormAutofillPreferences.jsm
@@ -65,17 +65,16 @@ FormAutofillPreferences.prototype = {
    * Create Form Autofill preference group
    *
    * @param  {XULDocument} document
    */
   createPreferenceGroup(document) {
     let formAutofillGroup;
     let addressAutofill = document.createElementNS(XUL_NS, "hbox");
     let addressAutofillCheckbox = document.createElementNS(XUL_NS, "checkbox");
-    let spacer = document.createElementNS(XUL_NS, "spacer");
     let savedAddressesBtn = document.createElementNS(XUL_NS, "button");
 
     if (this.useOldOrganization) {
       let caption = document.createElementNS(XUL_NS, "caption");
       let captionLabel = document.createElementNS(XUL_NS, "label");
 
       formAutofillGroup = document.createElementNS(XUL_NS, "groupbox");
       formAutofillGroup.hidden = document.location.href != "about:preferences#privacy";
@@ -100,21 +99,20 @@ FormAutofillPreferences.prototype = {
     savedAddressesBtn.setAttribute("label", this.bundle.GetStringFromName("savedAddresses"));
     addressAutofillCheckbox.setAttribute("label", this.bundle.GetStringFromName("enableAddressAutofill"));
 
     // Manually set the checked state
     if (this.isAutofillEnabled) {
       addressAutofillCheckbox.setAttribute("checked", true);
     }
 
-    spacer.flex = 1;
+    addressAutofillCheckbox.flex = 1;
 
     formAutofillGroup.appendChild(addressAutofill);
     addressAutofill.appendChild(addressAutofillCheckbox);
-    addressAutofill.appendChild(spacer);
     addressAutofill.appendChild(savedAddressesBtn);
   },
 
   /**
    * Handle events
    *
    * @param  {DOMEvent} event
    */
--- a/browser/extensions/onboarding/content/onboarding-tour-agent.js
+++ b/browser/extensions/onboarding/content/onboarding-tour-agent.js
@@ -1,33 +1,46 @@
 /* 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 Mozilla */
 
 "use strict";
 
+document.addEventListener("Agent:CanSetDefaultBrowserInBackground", () => {
+  Mozilla.UITour.getConfiguration("appinfo", config => {
+    let canSetInBackGround = config.canSetDefaultBrowserInBackground;
+    let btn = document.getElementById("onboarding-tour-default-browser-button");
+    btn.setAttribute("data-cansetbg", canSetInBackGround);
+    btn.textContent = canSetInBackGround ? btn.getAttribute("data-bg") : btn.getAttribute("data-panel");
+  });
+});
+
 document.getElementById("onboarding-overlay")
-                        .addEventListener("click", evt => {
+  .addEventListener("click", evt => {
   switch (evt.target.id) {
     case "onboarding-tour-addons-button":
       Mozilla.UITour.showHighlight("addons");
       break;
     case "onboarding-tour-customize-button":
       Mozilla.UITour.showHighlight("customize");
       break;
     case "onboarding-tour-default-browser-button":
       Mozilla.UITour.getConfiguration("appinfo", (config) => {
         let isDefaultBrowser = config.defaultBrowser;
         let btn = document.getElementById("onboarding-tour-default-browser-button");
         let msg = document.getElementById("onboarding-tour-is-default-browser-msg");
-        if (isDefaultBrowser) {
+        let canSetInBackGround = btn.getAttribute("data-cansetbg") === "true";
+        if (isDefaultBrowser || canSetInBackGround) {
           btn.classList.add("onboarding-hidden");
           msg.classList.remove("onboarding-hidden");
+          if (canSetInBackGround) {
+            Mozilla.UITour.setConfiguration("defaultBrowser");
+          }
         } else {
           btn.disabled = true;
           Mozilla.UITour.setConfiguration("defaultBrowser");
         }
       });
       break;
     case "onboarding-tour-library-button":
       Mozilla.UITour.showHighlight("library");
--- a/browser/extensions/onboarding/content/onboarding.js
+++ b/browser/extensions/onboarding/content/onboarding.js
@@ -157,34 +157,39 @@ var onboardingTourset = {
       return {
         title: bundle.formatStringFromName("onboarding.notification.onboarding-tour-default-browser.title", [BRAND_SHORT_NAME], 1),
         message: bundle.formatStringFromName("onboarding.notification.onboarding-tour-default-browser.message", [BRAND_SHORT_NAME], 1),
         button: bundle.GetStringFromName("onboarding.button.learnMore"),
       };
     },
     getPage(win, bundle) {
       let div = win.document.createElement("div");
-      let defaultBrowserButtonId = win.matchMedia("(-moz-os-version: windows-win7)").matches ?
-        "onboarding.tour-default-browser.win7.button" : "onboarding.tour-default-browser.button";
+      let setFromBackGround = bundle.formatStringFromName("onboarding.tour-default-browser.win7.button", [BRAND_SHORT_NAME], 1);
+      let setFromPanel = bundle.GetStringFromName("onboarding.tour-default-browser.button");
       let isDefaultMessage = bundle.GetStringFromName("onboarding.tour-default-browser.is-default.message");
       let isDefault2ndMessage = bundle.formatStringFromName("onboarding.tour-default-browser.is-default.2nd-message", [BRAND_SHORT_NAME], 1);
       // eslint-disable-next-line no-unsanitized/property
       div.innerHTML = `
         <section class="onboarding-tour-description">
           <h1 data-l10n-id="onboarding.tour-default-browser.title2"></h1>
           <p data-l10n-id="onboarding.tour-default-browser.description2"></p>
         </section>
         <section class="onboarding-tour-content">
           <img src="resource://onboarding/img/figure_default.svg" role="presentation"/>
         </section>
         <aside class="onboarding-tour-button-container">
-          <button id="onboarding-tour-default-browser-button" class="onboarding-tour-action-button" data-l10n-id="${defaultBrowserButtonId}"></button>
+          <button id="onboarding-tour-default-browser-button" class="onboarding-tour-action-button"
+            data-bg="${setFromBackGround}" data-panel="${setFromPanel}"></button>
           <div id="onboarding-tour-is-default-browser-msg" class="onboarding-hidden">${isDefaultMessage}<br/>${isDefault2ndMessage}</div>
         </aside>
       `;
+
+      div.addEventListener("beforeshow", () => {
+        win.document.dispatchEvent(new Event("Agent:CanSetDefaultBrowserInBackground"));
+      });
       return div;
     },
   },
   "sync": {
     id: "onboarding-tour-sync",
     tourNameId: "onboarding.tour-sync2",
     getNotificationStrings(bundle) {
       return {
--- a/browser/locales/searchplugins/yahoo-jp-auctions.xml
+++ b/browser/locales/searchplugins/yahoo-jp-auctions.xml
@@ -2,16 +2,16 @@
    - 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/. -->
 
 <SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
 <ShortName>ヤフオク!</ShortName>
 <Description>ヤフオク! 検索</Description>
 <InputEncoding>EUC-JP</InputEncoding>
 <Image width="16" height="16">data:image/x-icon;base64,AAABAAIAEBAAAAEAIAAEAwAAJgAAACAgAAABACAARgcAACoDAACJUE5HDQoaCgAAAA1JSERSAAAAEAAAABAIBgAAAB/z/2EAAALLSURBVDiNfZNbSFRRFIb/dc4Zz2gz3iK1oFToJSPCpECoqBAiCPPFy0PFoBUlEWRmiFDjg4VmkYHdCDQIIiswM30IL5g6mQ1qeQuzcVQ0YWq00XScc87qQSfHAVsv+2Hv/1v/umxgjWBmWj4N9vdvzSNNr079u6uqEtfSrQD6qgKWAVGtN3Pmuouz2d5ef2YlwX8gbDYLAAgA2ooyTC9SjTMvD4EtRWd5tK0+28elIPnbbm4uFOmgWQXAlpJMk8s2UGHQheF3WLB7vOWBrDGXjzTXIOZA8j0i0iRfMREBgAIAlpJM06xtoMLj+AJN0HuCZKM8p210OxsfyiERm8pdo/29xi1xLZKPmL2wjzdMpmnbQIXH8RmaYPCwuE7Hs985InKXrO1Iap+ZcVTOOZ2DAEDMLBCRxsyBYx0Nub9GhvZMvLufRK5veg+FKhACJF4YcRui9snGuMTa3eeL04ho3ptYgtUqAtAAbPg11HvN3VImTk/YPOtCYzUBisTqgiouQp4XAhGTePTLslhcdq0ISEhQABARjUbGJ2Zp29NVvQLdgkdVFbcDsjQvRqRcH3YFx2rdzx7l27ss1wCoRKQ0NTVJq5YGAJy2AVNn+VWu2gt+c3InfyjLa2Tm4LE+6/nagtNcffkEj/Z0FKyauxkQ6uruygB0APBzeDDTUnqJe4rPsWPQetz7bry/+2J1fha/zjvJtm7LlaUmAkQAwy+mej9lT9u/xgfNTV3YnJYz7wvpfFJ2O8RoQPTh1IsEAE+PhAe71EW9qs6q4bHJkv1xzWI+4PRbMpGIVAAY6mjOsXW23orYui2XAKB0f+AdEoQMMCYAZT2k8K5LDZMpwNLHobQ01R/CzNEAxqgmPSpbJJTrRUDRAFEAmBl/1IBbx56P5QKAb5nevfE6k0DkAqhyEfjBIB0zKxojHOyZ9O8LluatMTPBapUKa2vVv/Q3b+fAt5TJAAAAAElFTkSuQmCCiVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAHDUlEQVRYha2Xa3AT1xXH/2f3rixZfie2eQ9JKK+EJinm0RRcPCkm00cSIKb1wDTNtIlJO3TSyfRLv7BpM518aHAmHejkVTJtEicycXAInYSXFGqoS+WkmJcfWEBpjI0B+SFZ2t27e/pBspGNBAZ6ZjQare4957f/87i7wG0aM6vJb0/0Qtci49LZeSn/0Y32K7cZnIjIZmZPtK97+3DHF0fO/6vppNHfvRYAAoEX1Nvxf0MLBoMaALA5+BPuaOY6wPy0uoBDn9WxTEL4/bqYiBK3ZKzrCgAwc9bh2uc/2LO+hBsfR/xvVUhC9K4FAPb51EwQ4nYAAggoAJyT23/9QP/5Y0v7oyay3bNcVuy0bHujWgB1O2R/9xNUMOVDXwLCISL+vwD4dV1U6Lpsr/vt8kunOw5khc8LZrYHYwNqXvYsYcVOy7Y3qwXw/g451LtW5JY2pIO4pdwEX3tGK6t53Tr5rl5+JdS5L3LKrxnGgCRRICKmhHRs5GXng2JdUgiIeU+/jxkPVawVuaUNzD6VaJ094uumuyA1eDjUuS96yq8ZRkSSVigAB15NgVBUDA4Pgt33CCkh2974Ef5z2P8hD/WuIVpn+3y+0e64KQVY1wXpukwG3xtpC7ji8SFJWp4A21fXMRC1HEjHRr63EBzrtFRAm1dTh5nLVm0QOUXvMrNCRM6EFfCPDb4v0uZ3xYxBS3HlC7Acs5YI8GqAJrIRDnfaInu2JnsB5UIXzMjAWgBAfT0B1ynCZNuoaGmhlpYWlNXUWFeDB7S4MWSpWoHGjnWNkMwOVOGFOxaSntIyIYru6HffeRc7xZO/8JR6fwwAqKpycM3Oq8EVInJSr3X6fv/ti+0n9kRO+V1xIyIVLV8wXxsc7ICEFzISsnKL5mqllU9HJs2dW1H8je8FmU+4iO41kxOU0wIwszoyXu34wAbV7RnuOXJAnN617dX4uZN5w8MXJWkjso/fziDFDTtyVuYW3ydKVz4VmfbgkoqCucuCmW5uTApSZrs72tf9tnPu+LpI3EJf51Fc+nIXlJwpTiK4nV48ErDNbsdb8oAoXv7EhekLFj6WP3dZMPjaM9onF6bYmzdv5vHKjvEy0qPG5XPzw63NJwKrf2grd4PjOSD1julKjiaJ0icNIAHVVYT4f1vljNW/Efeu3/RxdtHkx6oA1Ze4MyfdzjFdUF+f+HYVzYhw4bTI1J8+rGpTwYUz71eJoxQxHTjMYz2wA1LccKzLTuxMqxUWUA821qL90OeP2kb0d/WATUQOM6ftuHQ1oCQ3lPcc++fejjefc11ua7a0kvnaUKQXDAGvi6AQgdmBIryQQyHpLV4gJn2rGoHG7Rg+0Sm9ORCrtuzEPeWrdFXzvJDqO6MCAEBEjq7rChEdnLRgycrZP3vFLJqzVLMunrRyvSUgOIiaDIcdqCIbMhKS+SVfF6XLq7rnrHnqrys2/YELp0JYWbB2b3wcZ5r26rYR2zzie7wSGSdhMBjUysrKLGYu72lt3tfx1q+0K+3NUtw5RwxFrwCqG27rvJ1XNFudVFkTmb5w0cP5c8qPsG1uCv0j8Oqnz1fCJFi4BO37rzfi7uWV11UirfHIAwdzec/RZjOwaQl/tArWrg3z+J0fwN6x/j4++peXeqNdTWUA4NOrXMn1G0OH9/LWxeDapTBr54A79u9k24jpqam+IUByoRiBuNDabAQ2LeGPvgur4VHIv29+kge7zxwfUZOZFT2ZVmbeGDq0h7cuBW9ZDPOV+eDO/Y23COH3j0L0HG02P3+unN8Dhltf/iWHu47tGV2XgCAkU8vMz3Y17eFtD4FfXpiA6Ni/k20rURM3ZakQ3f8+FOve8Ufu3P3n/XzG705eH60nZqYUJZ7tOpSA2LI4kY7OA41sGddCkA4oDFC6j67rSkpNPGKGe9/hvr7cTFJeA9H0GW/9JnjLIhhb7gJ3BT5mM/zVgzevRPI9IOV3xjyOhwgllaj92lWA1LOA9Bs8oOgAJ88KBYGAghUr7Ou1ExExMwNEChH9iZnxnZd2b4O0MGPJSl3zeL4k/wqIigDk1sqcn8OhFwFcZEAQgZlHgWwCF4Bw8Bd7I1WceObgTIHTKDHa9xwfmGWYpurOK24HAFERgA0Ag8O2Z3KOWthvOIXKuBPHYSDHRbgSd2YCAAHsq4K6rh42JmDJCUhExOTOP50KJhpWTy3yZDvlPQPWIsu2keWCyeNGNAGOTXAVZJP3k+rCJ01Htqz5oPe4rkPRddx4omE0HYT6egVVAFDlEJEj1CyekaepDa5CBYZkBuDK5ISBedNylbfPDiovAjg+uRsqMDGAEQhgrGoCJO0BQ4DBYEb64z5pkoEBw4HiYBgAZndMvA4ymcjLyu4YNOT9ACBsi6XI/CLJNnHYIGFbzlcAsCIwsRq4nv0Phi4X5d/okEsAAAAASUVORK5CYII=</Image>
-<Url type="text/html" method="GET" template="http://auctions.search.yahoo.co.jp/search" resultdomain="yahoo.co.jp">
+<Url type="text/html" method="GET" template="https://auctions.yahoo.co.jp/search/search" resultdomain="yahoo.co.jp">
   <Param name="p" value="{searchTerms}"/>
   <Param name="ei" value="EUC-JP"/>
   <Param name="fr" value="mozff" />
   <Param name="rls" value="{moz:distributionID}:ja-JP:{moz:official}"/>
 </Url>
-<SearchForm>http://auctions.yahoo.co.jp/</SearchForm>
+<SearchForm>https://auctions.yahoo.co.jp/</SearchForm>
 </SearchPlugin>
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -1566,18 +1566,17 @@ toolbarbutton.chevron > .toolbarbutton-m
 
 #TabsToolbar:not(:-moz-lwtheme) {
   color: #333;
   text-shadow: @loweredShadow@;
 }
 
 %ifdef MOZ_PHOTON_THEME
 :root:-moz-any([inFullscreen], [tabsintitlebar]) #TabsToolbar:not(:-moz-lwtheme) {
-  -moz-appearance: none;
-  background-color: #232323;
+  -moz-appearance: -moz-mac-vibrancy-dark;
   color: hsl(240, 9%, 98%);
   text-shadow: none;
 }
 %endif
 
 %ifndef MOZ_PHOTON_THEME
 #navigator-toolbox[inFullscreen] > #TabsToolbar {
   padding-top: var(--space-above-tabbar);
--- a/build/unix/elfhack/Makefile.in
+++ b/build/unix/elfhack/Makefile.in
@@ -6,18 +6,19 @@
 OS_CXXFLAGS := $(filter-out -fno-exceptions,$(OS_CXXFLAGS)) -fexceptions
 
 include $(topsrcdir)/config/rules.mk
 
 test-array$(DLL_SUFFIX) test-ctors$(DLL_SUFFIX): %$(DLL_SUFFIX): %.$(OBJ_SUFFIX) elfhack
 	$(MKSHLIB) $(LDFLAGS) $< -nostartfiles
 	@echo ===
 	@echo === If you get failures below, please file a bug describing the error
-	@echo === and your environment \(compiler and linker versions\), and use
-	@echo === --disable-elf-hack until this is fixed.
+	@echo === and your environment \(compiler and linker versions\), and
+	@echo === provide the pre-elfhacked library as an attachment.
+	@echo === Use --disable-elf-hack until this is fixed.
 	@echo ===
 	# Fail if the library doesn't have $(DT_TYPE) .dynamic info
 	$(TOOLCHAIN_PREFIX)readelf -d $@ | grep '($(DT_TYPE))'
 	@rm -f $@.bak
 	$(CURDIR)/elfhack -b -f $@
 	# Fail if the backup file doesn't exist
 	[ -f '$@.bak' ]
 	# Fail if the new library doesn't contain less relocations
--- a/devtools/client/performance/modules/logic/waterfall-utils.js
+++ b/devtools/client/performance/modules/logic/waterfall-utils.js
@@ -2,29 +2,28 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 /**
  * Utility functions for collapsing markers into a waterfall.
  */
 
-const { extend } = require("sdk/util/object");
 const { MarkerBlueprintUtils } = require("devtools/client/performance/modules/marker-blueprint-utils");
 
 /**
  * Creates a parent marker, which functions like a regular marker,
  * but is able to hold additional child markers.
  *
  * The marker is seeded with values from `marker`.
  * @param object marker
  * @return object
  */
 function createParentNode(marker) {
-  return extend(marker, { submarkers: [] });
+  return Object.assign({}, marker, { submarkers: [] });
 }
 
 /**
  * Collapses markers into a tree-like structure.
  * @param object rootNode
  * @param array markersList
  * @param array filter
  */
@@ -51,17 +50,17 @@ function collapseMarkersIntoNode({ rootN
 
     let finalized = false;
 
     // Extend the marker with extra properties needed in the marker tree
     let extendedProps = { index: i };
     if (collapsible) {
       extendedProps.submarkers = [];
     }
-    curr = extend(curr, extendedProps);
+    Object.assign(curr, extendedProps);
 
     // If not nestible, just push it inside the root node. Additionally,
     // markers originating outside the main thread are considered to be
     // "never collapsible", to avoid confusion.
     // A beter solution would be to collapse every marker with its siblings
     // from the same thread, but that would require a thread id attached
     // to all markers, which is potentially expensive and rather useless at
     // the moment, since we don't really have that many OTMT markers.
--- a/devtools/server/actors/performance-recording.js
+++ b/devtools/server/actors/performance-recording.js
@@ -2,29 +2,29 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { Actor, ActorClassWithSpec } = require("devtools/shared/protocol");
 const { performanceRecordingSpec } = require("devtools/shared/specs/performance-recording");
 
-loader.lazyRequireGetter(this, "merge", "sdk/util/object", true);
 loader.lazyRequireGetter(this, "RecordingUtils",
   "devtools/shared/performance/recording-utils");
 loader.lazyRequireGetter(this, "PerformanceRecordingCommon",
   "devtools/shared/performance/recording-common", true);
 
 /**
  * This actor wraps the Performance module at devtools/shared/shared/performance.js
  * and provides RDP definitions.
  *
  * @see devtools/shared/shared/performance.js for documentation.
  */
-const PerformanceRecordingActor = ActorClassWithSpec(performanceRecordingSpec, merge({
+const PerformanceRecordingActor = ActorClassWithSpec(performanceRecordingSpec,
+Object.assign({
   form: function (detail) {
     if (detail === "actorid") {
       return this.actorID;
     }
 
     let form = {
       // actorID is set when this is added to a pool
       actor: this.actorID,
@@ -137,12 +137,11 @@ const PerformanceRecordingActor = ActorC
         // in a waterfall view.
         this._markers = this._markers.sort((a, b) => (a.start > b.start));
 
         this._completed = true;
         break;
       }
     }
   },
-
 }, PerformanceRecordingCommon));
 
 exports.PerformanceRecordingActor = PerformanceRecordingActor;
--- a/devtools/server/actors/performance.js
+++ b/devtools/server/actors/performance.js
@@ -5,17 +5,16 @@
 "use strict";
 
 const { Task } = require("devtools/shared/task");
 const { Actor, ActorClassWithSpec } = require("devtools/shared/protocol");
 const { actorBridgeWithSpec } = require("devtools/server/actors/common");
 const { performanceSpec } = require("devtools/shared/specs/performance");
 
 loader.lazyRequireGetter(this, "events", "sdk/event/core");
-loader.lazyRequireGetter(this, "extend", "sdk/util/object", true);
 
 loader.lazyRequireGetter(this, "PerformanceRecorder",
   "devtools/server/performance/recorder", true);
 loader.lazyRequireGetter(this, "normalizePerformanceFeatures",
   "devtools/shared/performance/recording-utils", true);
 
 const PIPE_TO_FRONT_EVENTS = new Set([
   "recording-started", "recording-stopping", "recording-stopped",
--- a/devtools/server/actors/script.js
+++ b/devtools/server/actors/script.js
@@ -12,17 +12,16 @@ const { ActorPool, OriginalLocation, Gen
 const { ObjectActor, createValueGrip, longStringGrip } = require("devtools/server/actors/object");
 const { ActorClassWithSpec } = require("devtools/shared/protocol");
 const DevToolsUtils = require("devtools/shared/DevToolsUtils");
 const flags = require("devtools/shared/flags");
 const { assert, dumpn } = DevToolsUtils;
 const promise = require("promise");
 const xpcInspector = require("xpcInspector");
 const { DevToolsWorker } = require("devtools/shared/worker/worker");
-const object = require("sdk/util/object");
 const { threadSpec } = require("devtools/shared/specs/script");
 
 const { resolve, reject, all } = promise;
 
 loader.lazyGetter(this, "Debugger", () => {
   let Debugger = require("Debugger");
   hackDebugger(Debugger);
   return Debugger;
@@ -2035,17 +2034,17 @@ const ThreadActor = ActorClassWithSpec(t
       }
       result[actorID] = handler.call(actor, {});
     }
     return { from: this.actorID,
              actors: result };
   }
 });
 
-ThreadActor.prototype.requestTypes = object.merge(ThreadActor.prototype.requestTypes, {
+Object.assign(ThreadActor.prototype.requestTypes, {
   "attach": ThreadActor.prototype.onAttach,
   "detach": ThreadActor.prototype.onDetach,
   "reconfigure": ThreadActor.prototype.onReconfigure,
   "resume": ThreadActor.prototype.onResume,
   "clientEvaluate": ThreadActor.prototype.onClientEvaluate,
   "frames": ThreadActor.prototype.onFrames,
   "interrupt": ThreadActor.prototype.onInterrupt,
   "eventListeners": ThreadActor.prototype.onEventListeners,
--- a/devtools/server/performance/recorder.js
+++ b/devtools/server/performance/recorder.js
@@ -3,18 +3,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const { Cu } = require("chrome");
 const { Task } = require("devtools/shared/task");
 
 loader.lazyRequireGetter(this, "Services");
 loader.lazyRequireGetter(this, "promise");
-loader.lazyRequireGetter(this, "extend",
-  "sdk/util/object", true);
 loader.lazyRequireGetter(this, "Class",
   "sdk/core/heritage", true);
 loader.lazyRequireGetter(this, "EventTarget",
   "sdk/event/target", true);
 loader.lazyRequireGetter(this, "events",
   "sdk/event/core");
 
 loader.lazyRequireGetter(this, "Memory",
@@ -178,17 +176,17 @@ exports.PerformanceRecorder = Class({
     if (recordings.find(e => e.getLabel() === profileLabel)) {
       return;
     }
 
     // Immediately emit this so the client can start setting things up,
     // expecting a recording very soon.
     events.emit(this, "console-profile-start");
 
-    yield this.startRecording(extend({}, getPerformanceRecordingPrefs(), {
+    yield this.startRecording(Object.assign({}, getPerformanceRecordingPrefs(), {
       console: true,
       label: profileLabel
     }));
   }),
 
   /**
    * Invoked whenever `console.profileEnd` is called.
    *
@@ -344,17 +342,17 @@ exports.PerformanceRecorder = Class({
     if (options.withMarkers || options.withTicks || options.withMemory) {
       timelineStart = this._timeline.start(mapRecordingOptions("timeline", options));
     }
 
     if (options.withAllocations) {
       if (this._memory.getState() === "detached") {
         this._memory.attach();
       }
-      let recordingOptions = extend(mapRecordingOptions("memory", options), {
+      let recordingOptions = Object.assign(mapRecordingOptions("memory", options), {
         drainAllocationsTimeout: DRAIN_ALLOCATIONS_TIMEOUT
       });
       memoryStart = this._memory.startRecordingAllocations(recordingOptions);
     }
 
     let [profilerStartData, timelineStartData, memoryStartData] = yield promise.all([
       profilerStart, timelineStart, memoryStart
     ]);
@@ -475,17 +473,17 @@ exports.PerformanceRecorder = Class({
    */
   getConfiguration: function () {
     let allocationSettings = Object.create(null);
 
     if (this._memory.getState() === "attached") {
       allocationSettings = this._memory.getAllocationsSettings();
     }
 
-    return extend({}, allocationSettings, this._profiler.getStartOptions());
+    return Object.assign({}, allocationSettings, this._profiler.getStartOptions());
   },
 
   toString: () => "[object PerformanceRecorder]"
 });
 
 /**
  * Creates an object of configurations based off of
  * preferences for a PerformanceRecording.
--- a/devtools/shared/fronts/inspector.js
+++ b/devtools/shared/fronts/inspector.js
@@ -19,17 +19,16 @@ const {
   nodeSpec,
   nodeListSpec,
   walkerSpec
 } = require("devtools/shared/specs/inspector");
 const promise = require("promise");
 const defer = require("devtools/shared/defer");
 const { Task } = require("devtools/shared/task");
 const events = require("sdk/event/core");
-const object = require("sdk/util/object");
 const nodeConstants = require("devtools/shared/dom-node-constants.js");
 loader.lazyRequireGetter(this, "CommandUtils",
   "devtools/client/shared/developer-toolbar", true);
 
 const HIDDEN_CLASS = "__fx-devtools-hide-shortcut__";
 
 /**
  * Convenience API for building a list of attribute modifications
@@ -119,17 +118,17 @@ const NodeFront = FrontClassWithSpec(nod
     if (form.shortValue) {
       // If the value is not complete, set nodeValue to null, it will be fetched
       // when calling getNodeValue()
       form.nodeValue = form.incompleteValue ? null : form.shortValue;
     }
 
     // Shallow copy of the form.  We could just store a reference, but
     // eventually we'll want to update some of the data.
-    this._form = object.merge(form);
+    this._form = Object.assign({}, form);
     this._form.attrs = this._form.attrs ? this._form.attrs.slice() : [];
 
     if (form.parent) {
       // Get the owner actor for this actor (the walker), and find the
       // parent node of this actor from it, creating a standin node if
       // necessary.
       let parentNodeFront = ctx.marshallPool().ensureParentFront(form.parent);
       this.reparent(parentNodeFront);
@@ -767,17 +766,17 @@ const WalkerFront = FrontClassWithSpec(w
 
         if (!targetFront) {
           console.warn("Got a mutation for an unexpected actor: " + targetID +
             ", please file a bug on bugzilla.mozilla.org!");
           console.trace();
           continue;
         }
 
-        let emittedMutation = object.merge(change, { target: targetFront });
+        let emittedMutation = Object.assign(change, { target: targetFront });
 
         if (change.type === "childList" ||
             change.type === "nativeAnonymousChildList") {
           // Update the ownership tree according to the mutation record.
           let addedFronts = [];
           let removedFronts = [];
           for (let removed of change.removed) {
             let removedFront = this.get(removed);
--- a/devtools/shared/fronts/performance-recording.js
+++ b/devtools/shared/fronts/performance-recording.js
@@ -7,23 +7,23 @@ const { Front, FrontClassWithSpec } = re
 const { performanceRecordingSpec } = require("devtools/shared/specs/performance-recording");
 
 loader.lazyRequireGetter(this, "PerformanceIO",
   "devtools/client/performance/modules/io");
 loader.lazyRequireGetter(this, "PerformanceRecordingCommon",
   "devtools/shared/performance/recording-common", true);
 loader.lazyRequireGetter(this, "RecordingUtils",
   "devtools/shared/performance/recording-utils");
-loader.lazyRequireGetter(this, "merge", "sdk/util/object", true);
 
 /**
  * This can be used on older Profiler implementations, but the methods cannot
  * be changed -- you must introduce a new method, and detect the server.
  */
-const PerformanceRecordingFront = FrontClassWithSpec(performanceRecordingSpec, merge({
+const PerformanceRecordingFront = FrontClassWithSpec(performanceRecordingSpec,
+Object.assign({
   form: function (form, detail) {
     if (detail === "actorid") {
       this.actorID = form;
       return;
     }
     this.actorID = form.actor;
     this._form = form;
     this._configuration = form.configuration;
--- a/devtools/shared/fronts/profiler.js
+++ b/devtools/shared/fronts/profiler.js
@@ -7,17 +7,16 @@ const { Cu } = require("chrome");
 const {
   Front,
   FrontClassWithSpec,
   custom
 } = require("devtools/shared/protocol");
 const { profilerSpec } = require("devtools/shared/specs/profiler");
 
 loader.lazyRequireGetter(this, "events", "sdk/event/core");
-loader.lazyRequireGetter(this, "extend", "sdk/util/object", true);
 
 /**
  * This can be used on older Profiler implementations, but the methods cannot
  * be changed -- you must introduce a new method, and detect the server.
  */
 exports.ProfilerFront = FrontClassWithSpec(profilerSpec, {
   initialize: function (client, form) {
     Front.prototype.initialize.call(this, client, form);
@@ -35,17 +34,17 @@ exports.ProfilerFront = FrontClassWithSp
 
   /**
    * If using the protocol.js Fronts, then make stringify default,
    * since the read/write mechanisms will expose it as an object anyway, but
    * this lets other consumers who connect directly (xpcshell tests, Gecko Profiler) to
    * have unchanged behaviour.
    */
   getProfile: custom(function (options) {
-    return this._getProfile(extend({ stringify: true }, options));
+    return this._getProfile(Object.assign({ stringify: true }, options));
   }, {
     impl: "_getProfile"
   }),
 
   /**
    * Also emit an old `eventNotification` for older consumers of the profiler.
    */
   _onProfilerEvent: function (eventName, data) {
--- a/devtools/shared/performance/recording-utils.js
+++ b/devtools/shared/performance/recording-utils.js
@@ -1,16 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
-loader.lazyRequireGetter(this, "extend",
-  "sdk/util/object", true);
-
 /**
  * Utility functions for managing recording models and their internal data,
  * such as filtering profile samples or offsetting timestamps.
  */
 
 function mapRecordingOptions(type, options) {
   if (type === "profiler") {
     return {
--- a/devtools/shared/protocol.js
+++ b/devtools/shared/protocol.js
@@ -4,17 +4,16 @@
 
 "use strict";
 
 var promise = require("promise");
 var defer = require("devtools/shared/defer");
 var {Class} = require("sdk/core/heritage");
 var {EventTarget} = require("sdk/event/target");
 var events = require("sdk/event/core");
-var object = require("sdk/util/object");
 var {getStack, callFunctionWithAsyncStack} = require("devtools/shared/platform/stack");
 var {settleAll} = require("devtools/shared/DevToolsUtils");
 
 exports.emit = events.emit;
 
 /**
  * Types: named marshallers/demarshallers.
  *
@@ -142,17 +141,17 @@ function identityWrite(v) {
  *
  * @returns a type object that can be used in protocol definitions.
  */
 types.addType = function (name, typeObject = {}, options = {}) {
   if (registeredTypes.has(name)) {
     throw Error("Type '" + name + "' already exists.");
   }
 
-  let type = object.merge({
+  let type = Object.assign({
     toString() {
       return "[protocol type:" + name + "]";
     },
     name: name,
     primitive: !(typeObject.read || typeObject.write),
     read: identityWrite,
     write: identityWrite
   }, typeObject);
@@ -1004,50 +1003,50 @@ var generateActorSpec = function (actorD
         actorSpec[name] = types.addDictType(actorDesc.typeName + "__" + name, desc.value);
       }
     }
 
     if (desc.value._methodSpec) {
       let methodSpec = desc.value._methodSpec;
       let spec = {};
       spec.name = methodSpec.name || name;
-      spec.request = Request(object.merge({type: spec.name},
+      spec.request = Request(Object.assign({type: spec.name},
                                           methodSpec.request || undefined));
       spec.response = Response(methodSpec.response || undefined);
       spec.release = methodSpec.release;
       spec.oneway = methodSpec.oneway;
 
       actorSpec.methods.push(spec);
     }
   }
 
   // Find additional method specifications
   if (actorDesc.methods) {
     for (let name in actorDesc.methods) {
       let methodSpec = actorDesc.methods[name];
       let spec = {};
 
       spec.name = methodSpec.name || name;
-      spec.request = Request(object.merge({type: spec.name},
+      spec.request = Request(Object.assign({type: spec.name},
                                           methodSpec.request || undefined));
       spec.response = Response(methodSpec.response || undefined);
       spec.release = methodSpec.release;
       spec.oneway = methodSpec.oneway;
 
       actorSpec.methods.push(spec);
     }
   }
 
   // Find event specifications
   if (actorDesc.events) {
     actorSpec.events = new Map();
     for (let name in actorDesc.events) {
       let eventRequest = actorDesc.events[name];
       Object.freeze(eventRequest);
-      actorSpec.events.set(name, Request(object.merge({type: name}, eventRequest)));
+      actorSpec.events.set(name, Request(Object.assign({type: name}, eventRequest)));
     }
   }
 
   if (!registeredTypes.has(actorSpec.typeName)) {
     types.addActorType(actorSpec.typeName);
   }
   registeredTypes.get(actorSpec.typeName).actorSpec = actorSpec;
 
--- a/dom/media/gmp/ChromiumCDMAdapter.cpp
+++ b/dom/media/gmp/ChromiumCDMAdapter.cpp
@@ -10,17 +10,17 @@
 #include "gmp-api/gmp-entrypoints.h"
 #include "gmp-api/gmp-decryption.h"
 #include "gmp-api/gmp-video-codec.h"
 #include "gmp-api/gmp-platform.h"
 #include "WidevineUtils.h"
 #include "GMPLog.h"
 #include "mozilla/Move.h"
 
-#if defined(XP_MACOSX) || defined(XP_LINUX)
+#ifndef XP_WIN
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <fcntl.h>
 #endif
 
 // Declared in WidevineAdapter.cpp.
 extern const GMPPlatformAPI* sPlatform;
@@ -193,17 +193,17 @@ HostFile::HostFile(const nsCString& aPat
                               NULL,
                               OPEN_EXISTING,
                               0,
                               NULL);
   mFile = (handle == INVALID_HANDLE_VALUE) ? cdm::kInvalidPlatformFile : handle;
 }
 #endif
 
-#if defined(XP_MACOSX) || defined(XP_LINUX)
+#ifndef XP_WIN
 HostFile::HostFile(const nsCString& aPath)
   : mPath(aPath)
 {
   // Note: open() returns -1 on failure; i.e. kInvalidPlatformFile.
   mFile = open(aPath.get(), O_RDONLY);
 }
 #endif
 
--- a/dom/media/gmp/ChromiumCDMAdapter.h
+++ b/dom/media/gmp/ChromiumCDMAdapter.h
@@ -12,17 +12,17 @@
 #include "nsTArray.h"
 #include "content_decryption_module_ext.h"
 #include "nsString.h"
 
 struct GMPPlatformAPI;
 
 namespace mozilla {
 
-#if defined(OS_WIN)
+#if defined(XP_WIN)
 typedef nsString HostFileString;
 #else
 typedef nsCString HostFileString;
 #endif
 
 class HostFile
 {
 public:
--- a/dom/media/gmp/GMPChild.cpp
+++ b/dom/media/gmp/GMPChild.cpp
@@ -340,25 +340,25 @@ GMPChild::GetUTF8LibPath(nsACString& aOu
   nsAutoString path;
   libFile->GetPath(path);
   aOutLibPath = NS_ConvertUTF16toUTF8(path);
 
   return true;
 #endif
 }
 
-#if defined(XP_MACOSX)
+#if defined(XP_WIN)
+#define FIREFOX_FILE NS_LITERAL_STRING("firefox.exe")
+#define XUL_LIB_FILE NS_LITERAL_STRING("xul.dll")
+#elif defined(XP_MACOSX)
 #define FIREFOX_FILE NS_LITERAL_STRING("firefox")
 #define XUL_LIB_FILE NS_LITERAL_STRING("XUL")
-#elif defined(XP_LINUX)
+#else
 #define FIREFOX_FILE NS_LITERAL_STRING("firefox")
 #define XUL_LIB_FILE NS_LITERAL_STRING("libxul.so")
-#elif defined(OS_WIN)
-#define FIREFOX_FILE NS_LITERAL_STRING("firefox.exe")
-#define XUL_LIB_FILE NS_LITERAL_STRING("xul.dll")
 #endif
 
 #if defined(XP_MACOSX)
 static bool
 GetFirefoxAppPath(nsCOMPtr<nsIFile> aPluginContainerPath,
                   nsCOMPtr<nsIFile>& aOutFirefoxAppPath)
 {
   // aPluginContainerPath will end with something like:
@@ -407,29 +407,29 @@ GMPChild::MakeCDMHostVerificationPaths()
   } else {
     // Without successfully determining plugin-container's path, we can't
     // determine libxul's or Firefox's. So give up.
     return paths;
   }
 
   // Firefox application binary path.
   nsCOMPtr<nsIFile> appDir;
-#if defined(XP_WIN) || defined(XP_LINUX)
-  // Note: re-using 'path' var here, as on Windows/Linux we assume Firefox
-  // executable is in the same directory as plugin-container.
-  if (NS_SUCCEEDED(path->GetParent(getter_AddRefs(appDir))) &&
+#if defined(XP_MACOSX)
+  // On MacOS the firefox binary is a few parent directories up from
+  // plugin-container.
+  if (GetFirefoxAppPath(path, appDir) &&
       NS_SUCCEEDED(appDir->Clone(getter_AddRefs(path))) &&
       NS_SUCCEEDED(path->Append(FIREFOX_FILE)) && FileExists(path) &&
       ResolveLinks(path) && NS_SUCCEEDED(path->GetPath(str))) {
     paths.AppendElement(NS_ConvertUTF16toUTF8(str));
   }
-#elif defined(XP_MACOSX)
-  // On MacOS the firefox binary is a few parent directories up from
-  // plugin-container.
-  if (GetFirefoxAppPath(path, appDir) &&
+#else
+  // Note: re-using 'path' var here, as on Windows/Linux we assume Firefox
+  // executable is in the same directory as plugin-container.
+  if (NS_SUCCEEDED(path->GetParent(getter_AddRefs(appDir))) &&
       NS_SUCCEEDED(appDir->Clone(getter_AddRefs(path))) &&
       NS_SUCCEEDED(path->Append(FIREFOX_FILE)) && FileExists(path) &&
       ResolveLinks(path) && NS_SUCCEEDED(path->GetPath(str))) {
     paths.AppendElement(NS_ConvertUTF16toUTF8(str));
   }
 #endif
   // Libxul path. Note: re-using 'path' var here, as we assume libxul is in
   // the same directory as Firefox executable.
--- a/gfx/layers/UpdateImageHelper.h
+++ b/gfx/layers/UpdateImageHelper.h
@@ -14,23 +14,26 @@
 #include "mozilla/gfx/Types.h"
 
 namespace mozilla {
 namespace layers {
 
 class UpdateImageHelper
 {
 public:
-  UpdateImageHelper(ImageContainer* aImageContainer, ImageClient* aImageClient, gfx::IntSize aImageSize) :
+  UpdateImageHelper(ImageContainer* aImageContainer,
+                    ImageClient* aImageClient,
+                    gfx::IntSize aImageSize,
+                    gfx::SurfaceFormat aFormat) :
     mImageContainer(aImageContainer),
     mImageClient(aImageClient),
     mImageSize(aImageSize),
     mIsLocked(false)
   {
-    mTexture = mImageClient->GetTextureClientRecycler()->CreateOrRecycle(gfx::SurfaceFormat::B8G8R8A8,
+    mTexture = mImageClient->GetTextureClientRecycler()->CreateOrRecycle(aFormat,
                                                                          mImageSize,
                                                                          BackendSelector::Content,
                                                                          TextureFlags::DEFAULT);
     if (!mTexture) {
       return;
     }
 
     mIsLocked = mTexture->Lock(OpenMode::OPEN_WRITE_ONLY);
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -366,36 +366,43 @@ PaintItemByDrawTarget(nsDisplayItem* aIt
                       DrawTarget* aDT,
                       const LayerRect& aImageRect,
                       const LayerPoint& aOffset,
                       nsDisplayListBuilder* aDisplayListBuilder)
 {
   aDT->ClearRect(aImageRect.ToUnknownRect());
   RefPtr<gfxContext> context = gfxContext::CreateOrNull(aDT, aOffset.ToUnknownPoint());
   MOZ_ASSERT(context);
-  aItem->Paint(aDisplayListBuilder, context);
+
+  if (aItem->GetType() == nsDisplayItem::TYPE_MASK) {
+    context->SetMatrix(gfxMatrix::Translation(-aOffset.x, -aOffset.y));
+    static_cast<nsDisplayMask*>(aItem)->PaintMask(aDisplayListBuilder, context);
+  } else {
+    aItem->Paint(aDisplayListBuilder, context);
+  }
 
   if (gfxPrefs::WebRenderHighlightPaintedLayers()) {
     aDT->SetTransform(Matrix());
     aDT->FillRect(Rect(0, 0, aImageRect.width, aImageRect.height), ColorPattern(Color(1.0, 0.0, 0.0, 0.5)));
   }
   if (aItem->Frame()->PresContext()->GetPaintFlashing()) {
     aDT->SetTransform(Matrix());
     float r = float(rand()) / RAND_MAX;
     float g = float(rand()) / RAND_MAX;
     float b = float(rand()) / RAND_MAX;
     aDT->FillRect(Rect(0, 0, aImageRect.width, aImageRect.height), ColorPattern(Color(r, g, b, 0.5)));
   }
 }
 
-bool
-WebRenderLayerManager::PushItemAsImage(nsDisplayItem* aItem,
-                                       wr::DisplayListBuilder& aBuilder,
-                                       const StackingContextHelper& aSc,
-                                       nsDisplayListBuilder* aDisplayListBuilder)
+already_AddRefed<WebRenderFallbackData>
+WebRenderLayerManager::GenerateFallbackData(nsDisplayItem* aItem,
+                                            wr::DisplayListBuilder& aBuilder,
+                                            nsDisplayListBuilder* aDisplayListBuilder,
+                                            LayerRect& aImageRect,
+                                            LayerPoint& aOffset)
 {
   RefPtr<WebRenderFallbackData> fallbackData = CreateOrRecycleWebRenderUserData<WebRenderFallbackData>(aItem);
 
   bool snap;
   nsRect itemBounds = aItem->GetBounds(aDisplayListBuilder, &snap);
   nsRect clippedBounds = itemBounds;
 
   const DisplayItemClip& clip = aItem->GetClip();
@@ -404,24 +411,23 @@ WebRenderLayerManager::PushItemAsImage(n
   }
 
   const int32_t appUnitsPerDevPixel = aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
   LayerRect bounds = ViewAs<LayerPixel>(
       LayoutDeviceRect::FromAppUnits(clippedBounds, appUnitsPerDevPixel),
       PixelCastJustification::WebRenderHasUnitResolution);
 
   LayerIntSize imageSize = RoundedToInt(bounds.Size());
-  LayerRect imageRect;
-  imageRect.SizeTo(LayerSize(imageSize));
+  aImageRect = LayerRect(LayerPoint(0, 0), LayerSize(imageSize));
   if (imageSize.width == 0 || imageSize.height == 0) {
-    return true;
+    return nullptr;
   }
 
   nsPoint shift = clippedBounds.TopLeft() - itemBounds.TopLeft();
-  LayerPoint offset = ViewAs<LayerPixel>(
+  aOffset = ViewAs<LayerPixel>(
       LayoutDevicePoint::FromAppUnits(aItem->ToReferenceFrame() + shift, appUnitsPerDevPixel),
       PixelCastJustification::WebRenderHasUnitResolution);
 
   nsRegion invalidRegion;
   nsAutoPtr<nsDisplayItemGeometry> geometry = fallbackData->GetGeometry();
 
   if (geometry) {
     nsRect invalid;
@@ -437,63 +443,105 @@ WebRenderLayerManager::PushItemAsImage(n
 
       if (!lastBounds.IsEqualInterior(clippedBounds)) {
         invalidRegion.OrWith(lastBounds);
         invalidRegion.OrWith(clippedBounds);
       }
     }
   }
 
+  gfx::SurfaceFormat format = aItem->GetType() == nsDisplayItem::TYPE_MASK ?
+                                                    gfx::SurfaceFormat::A8 : gfx::SurfaceFormat::B8G8R8A8;
   if (!geometry || !invalidRegion.IsEmpty() || fallbackData->IsInvalid()) {
     if (gfxPrefs::WebRenderBlobImages()) {
       RefPtr<gfx::DrawEventRecorderMemory> recorder = MakeAndAddRef<gfx::DrawEventRecorderMemory>();
+      // TODO: should use 'format' to replace gfx::SurfaceFormat::B8G8R8X8. Currently blob image doesn't support A8 format.
       RefPtr<gfx::DrawTarget> dummyDt =
         gfx::Factory::CreateDrawTarget(gfx::BackendType::SKIA, gfx::IntSize(1, 1), gfx::SurfaceFormat::B8G8R8X8);
       RefPtr<gfx::DrawTarget> dt = gfx::Factory::CreateRecordingDrawTarget(recorder, dummyDt, imageSize.ToUnknownSize());
-      PaintItemByDrawTarget(aItem, dt, imageRect, offset, aDisplayListBuilder);
+      PaintItemByDrawTarget(aItem, dt, aImageRect, aOffset, aDisplayListBuilder);
       recorder->Finish();
 
       wr::ByteBuffer bytes(recorder->mOutputStream.mLength, (uint8_t*)recorder->mOutputStream.mData);
       wr::ImageKey key = WrBridge()->GetNextImageKey();
       WrBridge()->SendAddBlobImage(key, imageSize.ToUnknownSize(), imageSize.width * 4, dt->GetFormat(), bytes);
       fallbackData->SetKey(key);
     } else {
       fallbackData->CreateImageClientIfNeeded();
       RefPtr<ImageClient> imageClient = fallbackData->GetImageClient();
       RefPtr<ImageContainer> imageContainer = LayerManager::CreateImageContainer();
 
       {
-        UpdateImageHelper helper(imageContainer, imageClient, imageSize.ToUnknownSize());
+        UpdateImageHelper helper(imageContainer, imageClient, imageSize.ToUnknownSize(), format);
         {
           RefPtr<gfx::DrawTarget> dt = helper.GetDrawTarget();
-          PaintItemByDrawTarget(aItem, dt, imageRect, offset, aDisplayListBuilder);
+          PaintItemByDrawTarget(aItem, dt, aImageRect, aOffset, aDisplayListBuilder);
         }
         if (!helper.UpdateImage()) {
-          return false;
+          return nullptr;
         }
       }
 
       // Force update the key in fallback data since we repaint the image in this path.
       // If not force update, fallbackData may reuse the original key because it
       // doesn't know UpdateImageHelper already updated the image container.
       if (!fallbackData->UpdateImageKey(imageContainer, true)) {
-        return false;
+        return nullptr;
       }
     }
 
     geometry = aItem->AllocateGeometry(aDisplayListBuilder);
     fallbackData->SetInvalid(false);
   }
 
   // Update current bounds to fallback data
   fallbackData->SetGeometry(Move(geometry));
   fallbackData->SetBounds(clippedBounds);
 
   MOZ_ASSERT(fallbackData->GetKey());
 
+  return fallbackData.forget();
+}
+
+Maybe<wr::WrImageMask>
+WebRenderLayerManager::BuildWrMaskImage(nsDisplayItem* aItem,
+                                        wr::DisplayListBuilder& aBuilder,
+                                        const StackingContextHelper& aSc,
+                                        nsDisplayListBuilder* aDisplayListBuilder,
+                                        const LayerRect& aBounds)
+{
+  LayerRect imageRect;
+  LayerPoint offset;
+  RefPtr<WebRenderFallbackData> fallbackData = GenerateFallbackData(aItem, aBuilder, aDisplayListBuilder,
+                                                                    imageRect, offset);
+  if (!fallbackData) {
+    return Nothing();
+  }
+
+  wr::WrImageMask imageMask;
+  imageMask.image = fallbackData->GetKey().value();
+  imageMask.rect = aSc.ToRelativeLayoutRect(aBounds);
+  imageMask.repeat = false;
+  return Some(imageMask);
+}
+
+bool
+WebRenderLayerManager::PushItemAsImage(nsDisplayItem* aItem,
+                                       wr::DisplayListBuilder& aBuilder,
+                                       const StackingContextHelper& aSc,
+                                       nsDisplayListBuilder* aDisplayListBuilder)
+{
+  LayerRect imageRect;
+  LayerPoint offset;
+  RefPtr<WebRenderFallbackData> fallbackData = GenerateFallbackData(aItem, aBuilder, aDisplayListBuilder,
+                                                                    imageRect, offset);
+  if (!fallbackData) {
+    return false;
+  }
+
   wr::LayoutRect dest = aSc.ToRelativeLayoutRect(imageRect + offset);
   aBuilder.PushImage(dest,
                      dest,
                      wr::ImageRendering::Auto,
                      fallbackData->GetKey().value());
   return true;
 }
 
--- a/gfx/layers/wr/WebRenderLayerManager.h
+++ b/gfx/layers/wr/WebRenderLayerManager.h
@@ -65,16 +65,26 @@ public:
                                      mozilla::wr::DisplayListBuilder& aBuilder,
                                      const StackingContextHelper& aSc,
                                      gfx::IntSize& aSize);
   bool PushImage(nsDisplayItem* aItem,
                  ImageContainer* aContainer,
                  mozilla::wr::DisplayListBuilder& aBuilder,
                  const StackingContextHelper& aSc,
                  const LayerRect& aRect);
+  already_AddRefed<WebRenderFallbackData> GenerateFallbackData(nsDisplayItem* aItem,
+                                                               wr::DisplayListBuilder& aBuilder,
+                                                               nsDisplayListBuilder* aDisplayListBuilder,
+                                                               LayerRect& aImageRect,
+                                                               LayerPoint& aOffset);
+  Maybe<wr::WrImageMask> BuildWrMaskImage(nsDisplayItem* aItem,
+                                          wr::DisplayListBuilder& aBuilder,
+                                          const StackingContextHelper& aSc,
+                                          nsDisplayListBuilder* aDisplayListBuilder,
+                                          const LayerRect& aBounds);
   bool PushItemAsImage(nsDisplayItem* aItem,
                        wr::DisplayListBuilder& aBuilder,
                        const StackingContextHelper& aSc,
                        nsDisplayListBuilder* aDisplayListBuilder);
   void CreateWebRenderCommandsFromDisplayList(nsDisplayList* aDisplayList,
                                               nsDisplayListBuilder* aDisplayListBuilder,
                                               const StackingContextHelper& aSc,
                                               wr::DisplayListBuilder& aBuilder);
--- a/gfx/layers/wr/WebRenderPaintedLayer.cpp
+++ b/gfx/layers/wr/WebRenderPaintedLayer.cpp
@@ -52,17 +52,17 @@ WebRenderPaintedLayer::SetupExternalImag
 bool
 WebRenderPaintedLayer::UpdateImageClient()
 {
   MOZ_ASSERT(WrManager()->GetPaintedLayerCallback());
   nsIntRegion visibleRegion = GetVisibleRegion().ToUnknownRegion();
   IntRect bounds = visibleRegion.GetBounds();
   IntSize imageSize = bounds.Size();
 
-  UpdateImageHelper helper(mImageContainer, mImageClient, imageSize);
+  UpdateImageHelper helper(mImageContainer, mImageClient, imageSize, gfx::SurfaceFormat::B8G8R8A8);
 
   {
     RefPtr<DrawTarget> target = helper.GetDrawTarget();
     if (!target) {
       return false;
     }
 
     target->ClearRect(Rect(0, 0, imageSize.width, imageSize.height));
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -175,16 +175,20 @@ static void AddTransformFunctions(const 
                                   nsPresContext* aPresContext,
                                   TransformReferenceBox& aRefBox,
                                   InfallibleTArray<TransformFunction>& aFunctions)
 {
   if (aList->mValue.GetUnit() == eCSSUnit_None) {
     return;
   }
 
+  GeckoStyleContext* contextIfGecko = aContext
+                                      ? aContext->GetAsGecko()
+                                      : nullptr;
+
   for (const nsCSSValueList* curr = aList; curr; curr = curr->mNext) {
     const nsCSSValue& currElem = curr->mValue;
     NS_ASSERTION(currElem.GetUnit() == eCSSUnit_Function,
                  "Stream should consist solely of functions!");
     nsCSSValue::Array* array = currElem.GetArrayValue();
     RuleNodeCacheConditions conditions;
     switch (nsStyleTransformMatrix::TransformFunctionOf(array)) {
       case eCSSKeyword_rotatex:
@@ -252,62 +256,62 @@ static void AddTransformFunctions(const 
         double y = array->Item(2).GetFloatValue();
         double z = array->Item(3).GetFloatValue();
         aFunctions.AppendElement(Scale(x, y, z));
         break;
       }
       case eCSSKeyword_translatex:
       {
         double x = nsStyleTransformMatrix::ProcessTranslatePart(
-          array->Item(1), aContext, aPresContext, conditions,
+          array->Item(1), contextIfGecko, aPresContext, conditions,
           &aRefBox, &TransformReferenceBox::Width);
         aFunctions.AppendElement(Translation(x, 0, 0));
         break;
       }
       case eCSSKeyword_translatey:
       {
         double y = nsStyleTransformMatrix::ProcessTranslatePart(
-          array->Item(1), aContext, aPresContext, conditions,
+          array->Item(1), contextIfGecko, aPresContext, conditions,
           &aRefBox, &TransformReferenceBox::Height);
         aFunctions.AppendElement(Translation(0, y, 0));
         break;
       }
       case eCSSKeyword_translatez:
       {
         double z = nsStyleTransformMatrix::ProcessTranslatePart(
-          array->Item(1), aContext, aPresContext, conditions,
+          array->Item(1), contextIfGecko, aPresContext, conditions,
           nullptr);
         aFunctions.AppendElement(Translation(0, 0, z));
         break;
       }
       case eCSSKeyword_translate:
       {
         double x = nsStyleTransformMatrix::ProcessTranslatePart(
-          array->Item(1), aContext, aPresContext, conditions,
+          array->Item(1), contextIfGecko, aPresContext, conditions,
           &aRefBox, &TransformReferenceBox::Width);
         // translate(x) is shorthand for translate(x, 0)
         double y = 0;
         if (array->Count() == 3) {
            y = nsStyleTransformMatrix::ProcessTranslatePart(
-            array->Item(2), aContext, aPresContext, conditions,
+            array->Item(2), contextIfGecko, aPresContext, conditions,
             &aRefBox, &TransformReferenceBox::Height);
         }
         aFunctions.AppendElement(Translation(x, y, 0));
         break;
       }
       case eCSSKeyword_translate3d:
       {
         double x = nsStyleTransformMatrix::ProcessTranslatePart(
-          array->Item(1), aContext, aPresContext, conditions,
+          array->Item(1), contextIfGecko, aPresContext, conditions,
           &aRefBox, &TransformReferenceBox::Width);
         double y = nsStyleTransformMatrix::ProcessTranslatePart(
-          array->Item(2), aContext, aPresContext, conditions,
+          array->Item(2), contextIfGecko, aPresContext, conditions,
           &aRefBox, &TransformReferenceBox::Height);
         double z = nsStyleTransformMatrix::ProcessTranslatePart(
-          array->Item(3), aContext, aPresContext, conditions,
+          array->Item(3), contextIfGecko, aPresContext, conditions,
           nullptr);
 
         aFunctions.AppendElement(Translation(x, y, z));
         break;
       }
       case eCSSKeyword_skewx:
       {
         CSSAngle x = MakeCSSAngle(array->Item(1));
@@ -375,30 +379,30 @@ static void AddTransformFunctions(const 
         aFunctions.AppendElement(TransformMatrix(matrix));
         break;
       }
       case eCSSKeyword_interpolatematrix:
       {
         bool dummy;
         Matrix4x4 matrix;
         nsStyleTransformMatrix::ProcessInterpolateMatrix(matrix, array,
-                                                         aContext,
+                                                         contextIfGecko,
                                                          aPresContext,
                                                          conditions,
                                                          aRefBox,
                                                          &dummy);
         aFunctions.AppendElement(TransformMatrix(matrix));
         break;
       }
       case eCSSKeyword_accumulatematrix:
       {
         bool dummy;
         Matrix4x4 matrix;
         nsStyleTransformMatrix::ProcessAccumulateMatrix(matrix, array,
-                                                        aContext,
+                                                        contextIfGecko,
                                                         aPresContext,
                                                         conditions,
                                                         aRefBox,
                                                         &dummy);
         aFunctions.AppendElement(TransformMatrix(matrix));
         break;
       }
       case eCSSKeyword_perspective:
@@ -8862,16 +8866,43 @@ nsDisplayMask::PaintAsLayer(nsDisplayLis
 
   nsSVGIntegrationUtils::PaintMaskAndClipPath(params);
 
   context->PopClip();
 
   nsDisplayMaskGeometry::UpdateDrawResult(this, imgParams.result);
 }
 
+bool
+nsDisplayMask::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+                                       const StackingContextHelper& aSc,
+                                       nsTArray<WebRenderParentCommand>& aParentCommands,
+                                       mozilla::layers::WebRenderLayerManager* aManager,
+                                       nsDisplayListBuilder* aDisplayListBuilder)
+{
+  bool snap;
+  float appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
+  nsRect displayBound = GetBounds(aDisplayListBuilder, &snap);
+  LayerRect bounds = ViewAs<LayerPixel>(LayoutDeviceRect::FromAppUnits(displayBound, appUnitsPerDevPixel),
+                                        PixelCastJustification::WebRenderHasUnitResolution);
+
+  Maybe<wr::WrImageMask> mask = aManager->BuildWrMaskImage(this, aBuilder, aSc, aDisplayListBuilder, bounds);
+  if (mask) {
+    aBuilder.PushClip(aSc.ToRelativeLayoutRect(bounds), mask.ptr());
+  }
+
+  nsDisplaySVGEffects::CreateWebRenderCommands(aBuilder, aSc, aParentCommands, aManager, aDisplayListBuilder);
+
+  if (mask) {
+    aBuilder.PopClip();
+  }
+
+  return true;
+}
+
 #ifdef MOZ_DUMP_PAINTING
 void
 nsDisplayMask::PrintEffects(nsACString& aTo)
 {
   nsIFrame* firstFrame =
     nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
   nsSVGEffects::EffectProperties effectProperties =
     nsSVGEffects::GetEffectProperties(firstFrame);
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -4515,16 +4515,22 @@ public:
    * return whether the mask layer was painted successfully.
    */
   bool PaintMask(nsDisplayListBuilder* aBuilder, gfxContext* aMaskContext);
 
   const nsTArray<nsRect>& GetDestRects()
   {
     return mDestRects;
   }
+
+  virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+                                       const StackingContextHelper& aSc,
+                                       nsTArray<WebRenderParentCommand>& aParentCommands,
+                                       mozilla::layers::WebRenderLayerManager* aManager,
+                                       nsDisplayListBuilder* aDisplayListBuilder) override;
 private:
   // According to mask property and the capability of aManager, determine
   // whether paint mask onto a dedicate mask layer.
   bool ShouldPaintOnMaskLayer(LayerManager* aManager);
 
   nsTArray<nsRect> mDestRects;
 };
 
--- a/layout/style/nsStyleTransformMatrix.cpp
+++ b/layout/style/nsStyleTransformMatrix.cpp
@@ -131,17 +131,17 @@ TransformReferenceBox::Init(const nsSize
   mY = 0;
   mWidth = aDimensions.width;
   mHeight = aDimensions.height;
   mIsCached = true;
 }
 
 float
 ProcessTranslatePart(const nsCSSValue& aValue,
-                     nsStyleContext* aContext,
+                     GeckoStyleContext* aContext,
                      nsPresContext* aPresContext,
                      RuleNodeCacheConditions& aConditions,
                      TransformReferenceBox* aRefBox,
                      TransformReferenceBox::DimensionGetter aDimensionGetter)
 {
   nscoord offset = 0;
   float percent = 0.0f;
 
@@ -155,49 +155,65 @@ ProcessTranslatePart(const nsCSSValue& a
     // StyleAnimationValue does) that all lengths within the transform
     // function have already been computed to pixels and percents.
     //
     // Raw numbers are treated as being pixels.
     //
     // Don't convert to aValue to AppUnits here to avoid precision issues.
     return aValue.GetFloatValue();
   } else if (aValue.IsCalcUnit()) {
-    nsRuleNode::ComputedCalc result =
-      nsRuleNode::SpecifiedCalcToComputedCalc(aValue, aContext, aPresContext,
-                                              aConditions);
-    percent = result.mPercent;
-    offset = result.mLength;
+    if (aContext) {
+      // Gecko backend
+      nsRuleNode::ComputedCalc result =
+        nsRuleNode::SpecifiedCalcToComputedCalc(aValue, aContext, aPresContext,
+                                                aConditions);
+      percent = result.mPercent;
+      offset = result.mLength;
+    } else {
+      // Servo backend. We can retrieve the Calc value directly because it has
+      // been computed from Servo side and set by nsCSSValue::SetCalcValue().
+      // We don't use nsRuleNode::SpecifiedCalcToComputedCalc() because it
+      // asserts for null context and we always pass null context for Servo
+      // backend.
+      nsStyleCoord::CalcValue calc = aValue.GetCalcValue();
+      percent = calc.mPercent;
+      offset = calc.mLength;
+    }
   } else {
+    // Note: The unit of nsCSSValue passed from Servo side would be number,
+    //       pixel, percent, or eCSSUnit_Calc, so it is impossible to go into
+    //       this branch.
+    MOZ_ASSERT(aContext, "We need a valid context to compute the length");
     offset = nsRuleNode::CalcLength(aValue, aContext, aPresContext,
                                     aConditions);
   }
 
-  float translation = NSAppUnitsToFloatPixels(offset,
-                                              nsPresContext::AppUnitsPerCSSPixel());
+  float translation =
+    NSAppUnitsToFloatPixels(offset, nsPresContext::AppUnitsPerCSSPixel());
   // We want to avoid calling aDimensionGetter if there's no percentage to be
   // resolved (for performance reasons - see TransformReferenceBox).
   if (percent != 0.0f && aRefBox && !aRefBox->IsEmpty()) {
-    translation += percent *
-                     NSAppUnitsToFloatPixels((aRefBox->*aDimensionGetter)(),
-                                             nsPresContext::AppUnitsPerCSSPixel());
+    translation +=
+      percent * NSAppUnitsToFloatPixels((aRefBox->*aDimensionGetter)(),
+                                        nsPresContext::AppUnitsPerCSSPixel());
   }
   return translation;
 }
 
 /**
  * Helper functions to process all the transformation function types.
  *
  * These take a matrix parameter to accumulate the current matrix.
  */
 
 /* Helper function to process a matrix entry. */
 static void
 ProcessMatrix(Matrix4x4& aMatrix,
               const nsCSSValue::Array* aData,
-              nsStyleContext* aContext,
+              GeckoStyleContext* aContext,
               nsPresContext* aPresContext,
               RuleNodeCacheConditions& aConditions,
               TransformReferenceBox& aRefBox)
 {
   NS_PRECONDITION(aData->Count() == 7, "Invalid array!");
 
   gfxMatrix result;
 
@@ -220,17 +236,17 @@ ProcessMatrix(Matrix4x4& aMatrix,
                                    &aRefBox, &TransformReferenceBox::Height);
 
   aMatrix = result * aMatrix;
 }
 
 static void
 ProcessMatrix3D(Matrix4x4& aMatrix,
                 const nsCSSValue::Array* aData,
-                nsStyleContext* aContext,
+                GeckoStyleContext* aContext,
                 nsPresContext* aPresContext,
                 RuleNodeCacheConditions& aConditions,
                 TransformReferenceBox& aRefBox)
 {
   NS_PRECONDITION(aData->Count() == 17, "Invalid array!");
 
   Matrix4x4 temp;
 
@@ -463,17 +479,17 @@ OperateTransformMatrixByServo(const Matr
 {
   return Operator::operateByServo(aMatrix1, aMatrix2, aProgress);
 }
 
 template <typename Operator>
 static void
 ProcessMatrixOperator(Matrix4x4& aMatrix,
                       const nsCSSValue::Array* aData,
-                      nsStyleContext* aContext,
+                      GeckoStyleContext* aContext,
                       nsPresContext* aPresContext,
                       RuleNodeCacheConditions& aConditions,
                       TransformReferenceBox& aRefBox,
                       bool* aContains3dTransform)
 {
   NS_PRECONDITION(aData->Count() == 4, "Invalid array!");
 
   auto readTransform = [&](const nsCSSValue& aValue) -> Matrix4x4 {
@@ -509,61 +525,64 @@ ProcessMatrixOperator(Matrix4x4& aMatrix
                                                     aContains3dTransform);
     return matrix;
   };
 
   Matrix4x4 matrix1 = readTransform(aData->Item(1));
   Matrix4x4 matrix2 = readTransform(aData->Item(2));
   double progress = aData->Item(3).GetPercentValue();
 
-  if (aContext && aContext->IsServo()) {
+  // We cannot use GeckoStyleContext to check if we use Servo backend because
+  // it could be null in Gecko. Instead, use the unit of the nsCSSValue because
+  // we use eCSSUnit_SharedList for Servo backend.
+  if (aData->Item(1).GetUnit() == eCSSUnit_SharedList) {
     aMatrix =
       OperateTransformMatrixByServo<Operator>(matrix1, matrix2, progress)
         * aMatrix;
     return;
   }
 
   aMatrix =
     OperateTransformMatrix<Operator>(matrix1, matrix2, progress) * aMatrix;
 }
 
 /* Helper function to process two matrices that we need to interpolate between */
 void
 ProcessInterpolateMatrix(Matrix4x4& aMatrix,
                          const nsCSSValue::Array* aData,
-                         nsStyleContext* aContext,
+                         GeckoStyleContext* aContext,
                          nsPresContext* aPresContext,
                          RuleNodeCacheConditions& aConditions,
                          TransformReferenceBox& aRefBox,
                          bool* aContains3dTransform)
 {
   ProcessMatrixOperator<Interpolate>(aMatrix, aData, aContext, aPresContext,
                                      aConditions, aRefBox,
                                      aContains3dTransform);
 }
 
 void
 ProcessAccumulateMatrix(Matrix4x4& aMatrix,
                         const nsCSSValue::Array* aData,
-                        nsStyleContext* aContext,
+                        GeckoStyleContext* aContext,
                         nsPresContext* aPresContext,
                         RuleNodeCacheConditions& aConditions,
                         TransformReferenceBox& aRefBox,
                         bool* aContains3dTransform)
 {
   ProcessMatrixOperator<Accumulate>(aMatrix, aData, aContext, aPresContext,
                                     aConditions, aRefBox,
                                     aContains3dTransform);
 }
 
 /* Helper function to process a translatex function. */
 static void
 ProcessTranslateX(Matrix4x4& aMatrix,
                   const nsCSSValue::Array* aData,
-                  nsStyleContext* aContext,
+                  GeckoStyleContext* aContext,
                   nsPresContext* aPresContext,
                   RuleNodeCacheConditions& aConditions,
                   TransformReferenceBox& aRefBox)
 {
   NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
 
   Point3D temp;
 
@@ -572,17 +591,17 @@ ProcessTranslateX(Matrix4x4& aMatrix,
                                 &aRefBox, &TransformReferenceBox::Width);
   aMatrix.PreTranslate(temp);
 }
 
 /* Helper function to process a translatey function. */
 static void
 ProcessTranslateY(Matrix4x4& aMatrix,
                   const nsCSSValue::Array* aData,
-                  nsStyleContext* aContext,
+                  GeckoStyleContext* aContext,
                   nsPresContext* aPresContext,
                   RuleNodeCacheConditions& aConditions,
                   TransformReferenceBox& aRefBox)
 {
   NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
 
   Point3D temp;
 
@@ -590,17 +609,17 @@ ProcessTranslateY(Matrix4x4& aMatrix,
                                 aContext, aPresContext, aConditions,
                                 &aRefBox, &TransformReferenceBox::Height);
   aMatrix.PreTranslate(temp);
 }
 
 static void
 ProcessTranslateZ(Matrix4x4& aMatrix,
                   const nsCSSValue::Array* aData,
-                  nsStyleContext* aContext,
+                  GeckoStyleContext* aContext,
                   nsPresContext* aPresContext,
                   RuleNodeCacheConditions& aConditions)
 {
   NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
 
   Point3D temp;
 
   temp.z = ProcessTranslatePart(aData->Item(1), aContext,
@@ -608,17 +627,17 @@ ProcessTranslateZ(Matrix4x4& aMatrix,
                                 nullptr);
   aMatrix.PreTranslate(temp);
 }
 
 /* Helper function to process a translate function. */
 static void
 ProcessTranslate(Matrix4x4& aMatrix,
                  const nsCSSValue::Array* aData,
-                 nsStyleContext* aContext,
+                 GeckoStyleContext* aContext,
                  nsPresContext* aPresContext,
                  RuleNodeCacheConditions& aConditions,
                  TransformReferenceBox& aRefBox)
 {
   NS_PRECONDITION(aData->Count() == 2 || aData->Count() == 3, "Invalid array!");
 
   Point3D temp;
 
@@ -633,17 +652,17 @@ ProcessTranslate(Matrix4x4& aMatrix,
                                   &aRefBox, &TransformReferenceBox::Height);
   }
   aMatrix.PreTranslate(temp);
 }
 
 static void
 ProcessTranslate3D(Matrix4x4& aMatrix,
                    const nsCSSValue::Array* aData,
-                   nsStyleContext* aContext,
+                   GeckoStyleContext* aContext,
                    nsPresContext* aPresContext,
                    RuleNodeCacheConditions& aConditions,
                    TransformReferenceBox& aRefBox)
 {
   NS_PRECONDITION(aData->Count() == 4, "Invalid array!");
 
   Point3D temp;
 
@@ -800,17 +819,17 @@ ProcessRotate3D(Matrix4x4& aMatrix, cons
   temp.SetRotateAxisAngle(x, y, z, theta);
 
   aMatrix = temp * aMatrix;
 }
 
 static void
 ProcessPerspective(Matrix4x4& aMatrix,
                    const nsCSSValue::Array* aData,
-                   nsStyleContext *aContext,
+                   GeckoStyleContext *aContext,
                    nsPresContext *aPresContext,
                    RuleNodeCacheConditions& aConditions)
 {
   NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
 
   float depth = ProcessTranslatePart(aData->Item(1), aContext,
                                      aPresContext, aConditions, nullptr);
   ApplyPerspectiveToMatrix(aMatrix, depth);
@@ -819,29 +838,28 @@ ProcessPerspective(Matrix4x4& aMatrix,
 
 /**
  * SetToTransformFunction is essentially a giant switch statement that fans
  * out to many smaller helper functions.
  */
 static void
 MatrixForTransformFunction(Matrix4x4& aMatrix,
                            const nsCSSValue::Array * aData,
-                           nsStyleContext* aContext,
+                           GeckoStyleContext* aContext,
                            nsPresContext* aPresContext,
                            RuleNodeCacheConditions& aConditions,
                            TransformReferenceBox& aRefBox,
                            bool* aContains3dTransform)
 {
   MOZ_ASSERT(aContains3dTransform);
   NS_PRECONDITION(aData, "Why did you want to get data from a null array?");
   // It's OK if aContext and aPresContext are null if the caller already
   // knows that all length units have been converted to pixels (as
   // StyleAnimationValue does).
 
-
   /* Get the keyword for the transform. */
   switch (TransformFunctionOf(aData)) {
   case eCSSKeyword_translatex:
     ProcessTranslateX(aMatrix, aData, aContext, aPresContext,
                       aConditions, aRefBox);
     break;
   case eCSSKeyword_translatey:
     ProcessTranslateY(aMatrix, aData, aContext, aPresContext,
@@ -976,31 +994,34 @@ ReadTransforms(const nsCSSValueList* aLi
                nsStyleContext* aContext,
                nsPresContext* aPresContext,
                RuleNodeCacheConditions& aConditions,
                TransformReferenceBox& aRefBox,
                float aAppUnitsPerMatrixUnit,
                bool* aContains3dTransform)
 {
   Matrix4x4 result;
+  GeckoStyleContext* contextIfGecko = aContext
+                                      ? aContext->GetAsGecko()
+                                      : nullptr;
 
   for (const nsCSSValueList* curr = aList; curr != nullptr; curr = curr->mNext) {
     const nsCSSValue &currElem = curr->mValue;
     if (currElem.GetUnit() != eCSSUnit_Function) {
       NS_ASSERTION(currElem.GetUnit() == eCSSUnit_None &&
                    !aList->mNext,
                    "stream should either be a list of functions or a "
                    "lone None");
       continue;
     }
     NS_ASSERTION(currElem.GetArrayValue()->Count() >= 1,
                  "Incoming function is too short!");
 
     /* Read in a single transform matrix. */
-    MatrixForTransformFunction(result, currElem.GetArrayValue(), aContext,
+    MatrixForTransformFunction(result, currElem.GetArrayValue(), contextIfGecko,
                                aPresContext, aConditions, aRefBox,
                                aContains3dTransform);
   }
 
   float scale = float(nsPresContext::AppUnitsPerCSSPixel()) / aAppUnitsPerMatrixUnit;
   result.PreScale(1/scale, 1/scale, 1/scale);
   result.PostScale(scale, scale, scale);
 
--- a/layout/style/nsStyleTransformMatrix.h
+++ b/layout/style/nsStyleTransformMatrix.h
@@ -19,16 +19,17 @@
 #include <limits>
 
 class nsIFrame;
 class nsStyleContext;
 class nsPresContext;
 struct gfxQuaternion;
 struct nsRect;
 namespace mozilla {
+class GeckoStyleContext;
 class RuleNodeCacheConditions;
 } // namespace mozilla
 
 /**
  * A helper to generate gfxMatrixes from css transform functions.
  */
 namespace nsStyleTransformMatrix {
   // The operator passed to Servo backend.
@@ -152,35 +153,35 @@ namespace nsStyleTransformMatrix {
    * Return the transform function, as an nsCSSKeyword, for the given
    * nsCSSValue::Array from a transform list.
    */
   nsCSSKeyword TransformFunctionOf(const nsCSSValue::Array* aData);
 
   void SetIdentityMatrix(nsCSSValue::Array* aMatrix);
 
   float ProcessTranslatePart(const nsCSSValue& aValue,
-                             nsStyleContext* aContext,
+                             mozilla::GeckoStyleContext* aContext,
                              nsPresContext* aPresContext,
                              mozilla::RuleNodeCacheConditions& aConditions,
                              TransformReferenceBox* aRefBox,
                              TransformReferenceBox::DimensionGetter aDimensionGetter = nullptr);
 
   void
   ProcessInterpolateMatrix(mozilla::gfx::Matrix4x4& aMatrix,
                            const nsCSSValue::Array* aData,
-                           nsStyleContext* aContext,
+                           mozilla::GeckoStyleContext* aContext,
                            nsPresContext* aPresContext,
                            mozilla::RuleNodeCacheConditions& aConditions,
                            TransformReferenceBox& aBounds,
                            bool* aContains3dTransform);
 
   void
   ProcessAccumulateMatrix(mozilla::gfx::Matrix4x4& aMatrix,
                           const nsCSSValue::Array* aData,
-                          nsStyleContext* aContext,
+                          mozilla::GeckoStyleContext* aContext,
                           nsPresContext* aPresContext,
                           mozilla::RuleNodeCacheConditions& aConditions,
                           TransformReferenceBox& aBounds,
                           bool* aContains3dTransform);
 
   /**
    * Given an nsCSSValueList containing -moz-transform functions,
    * returns a matrix containing the value of those functions.
--- a/media/gmp-clearkey/0.1/gmp-clearkey.cpp
+++ b/media/gmp-clearkey/0.1/gmp-clearkey.cpp
@@ -22,17 +22,17 @@
 #include "ClearKeyCDM.h"
 #include "ClearKeySessionManager.h"
 // This include is required in order for content_decryption_module to work
 // on Unix systems.
 #include "stddef.h"
 #include "content_decryption_module.h"
 #include "content_decryption_module_ext.h"
 
-#if defined(XP_MACOSX) || defined(XP_LINUX)
+#ifndef XP_WIN
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #endif
 
 #ifdef ENABLE_WMF
 #include "WMFUtils.h"
 #endif // ENABLE_WMF
@@ -83,29 +83,27 @@ bool
 CanReadSome(cdm::PlatformFile aFile)
 {
   vector<uint8_t> data;
   data.resize(TEST_READ_SIZE);
 #ifdef XP_WIN
   DWORD bytesRead = 0;
   return ReadFile(aFile, &data.front(), TEST_READ_SIZE, &bytesRead, nullptr) &&
          bytesRead > 0;
-#elif defined(XP_MACOSX) || defined(XP_LINUX)
+#else
   return read(aFile, &data.front(), TEST_READ_SIZE) > 0;
-#else
-  return false;
 #endif
 }
 
 void
 ClosePlatformFile(cdm::PlatformFile aFile)
 {
 #ifdef XP_WIN
   CloseHandle(aFile);
-#elif defined(XP_MACOSX) || defined(XP_LINUX)
+#else
   close(aFile);
 #endif
 }
 
 CDM_API
 bool
 VerifyCdmHost_0(const cdm::HostFile* aHostFiles, uint32_t aNumFiles)
 {
--- a/mobile/android/chrome/content/aboutAddons.js
+++ b/mobile/android/chrome/content/aboutAddons.js
@@ -354,17 +354,21 @@ var Addons = {
     let optionsURL = aListItem.getAttribute("optionsURL");
 
     // Always clean the options content before rendering the options of the
     // newly selected extension.
     optionsBox.innerHTML = "";
 
     switch (parseInt(addon.optionsType)) {
       case AddonManager.OPTIONS_TYPE_INLINE_BROWSER:
-        this.createWebExtensionOptions(optionsBox, optionsURL, addon.optionsBrowserStyle);
+        // WebExtensions are loaded asynchronously and the optionsURL
+        // may not be available via listitem when the add-on has just been
+        // installed, but it is available on the addon if one is set.
+        detailItem.setAttribute("optionsURL", addon.optionsURL);
+        this.createWebExtensionOptions(optionsBox, addon.optionsURL, addon.optionsBrowserStyle);
         break;
       case AddonManager.OPTIONS_TYPE_INLINE:
         this.createInlineOptions(optionsBox, optionsURL, aListItem);
         break;
     }
 
     showAddonOptions();
   },
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -3830,21 +3830,16 @@ pref("intl.tsf.hack.free_chang_jie.do_no
 // For Microsoft Pinyin and Microsoft Wubi
 pref("intl.tsf.hack.ms_simplified_chinese.do_not_return_no_layout_error", true);
 // For Microsoft ChangJie and Microsoft Quick
 pref("intl.tsf.hack.ms_traditional_chinese.do_not_return_no_layout_error", true);
 // Whether use previous character rect for the result of
 // ITfContextView::GetTextExt() if the specified range is the first character
 // of selected clause of composition string.
 pref("intl.tsf.hack.ms_japanese_ime.do_not_return_no_layout_error_at_first_char", true);
-// Whether default IMC should be associated with focused window when MS-IME
-// for Japanese on Win10 is active.  MS-IME for Japanese on Win10 has a crash
-// bug.  While restoring default IMC when MS-IME for Japanese is active,
-// it sometimes crashes after Creators Update.  This pref avoid the crash.
-pref("intl.tsf.hack.ms_japanese_ime.do_not_associate_imc_on_win10", true);
 // Whether use previous character rect for the result of
 // ITfContextView::GetTextExt() if the specified range is the caret of
 // composition string.
 pref("intl.tsf.hack.ms_japanese_ime.do_not_return_no_layout_error_at_caret", true);
 // Whether hack ITextStoreACP::QueryInsert() or not.  The method should return
 // new selection after specified length text is inserted at specified range.
 // However, Microsoft's some Chinese TIPs expect that the result is same as
 // specified range.  If following prefs are true, ITextStoreACP::QueryInsert()
--- a/services/sync/modules/policies.js
+++ b/services/sync/modules/policies.js
@@ -594,16 +594,17 @@ ErrorHandler.prototype = {
   didReportProlongedError: false,
 
   init: function init() {
     Svc.Obs.add("weave:engine:sync:applied", this);
     Svc.Obs.add("weave:engine:sync:error", this);
     Svc.Obs.add("weave:service:login:error", this);
     Svc.Obs.add("weave:service:sync:error", this);
     Svc.Obs.add("weave:service:sync:finish", this);
+    Svc.Obs.add("weave:service:start-over:finish", this);
 
     this.initLogs();
   },
 
   initLogs: function initLogs() {
     this._log = Log.repository.getLogger("Sync.ErrorHandler");
     this._log.level = Log.Level[Svc.Prefs.get("log.logger.service.main")];
 
@@ -711,16 +712,20 @@ ErrorHandler.prototype = {
             break;
           }
         } else {
           this.resetFileLog();
         }
         this.dontIgnoreErrors = false;
         this.notifyOnNextTick("weave:ui:sync:finish");
         break;
+      case "weave:service:start-over:finish":
+        // ensure we capture any logs between the last sync and the reset completing.
+        this.resetFileLog();
+        break;
     }
   },
 
   notifyOnNextTick: function notifyOnNextTick(topic) {
     Utils.nextTick(function() {
       this._log.trace("Notifying " + topic +
                       ". Status.login is " + Status.login +
                       ". Status.sync is " + Status.sync);
--- a/services/sync/tests/unit/test_errorhandler_1.js
+++ b/services/sync/tests/unit/test_errorhandler_1.js
@@ -50,17 +50,19 @@ add_task(async function setup() {
   Log.repository.getLogger("Sync.ErrorHandler").level = Log.Level.Trace;
 
   Service.engineManager.clear();
   await Service.engineManager.register(EHTestsCommon.CatapultEngine);
   engine = Service.engineManager.get("catapult");
 });
 
 async function clean() {
+  let promiseLogReset = promiseOneObserver("weave:service:reset-file-log");
   await Service.startOver();
+  await promiseLogReset;
   Status.resetSync();
   Status.resetBackoff();
   errorHandler.didReportProlongedError = false;
 }
 
 add_task(async function test_401_logout() {
   enableValidationPrefs();
 
--- a/services/sync/tests/unit/test_errorhandler_2.js
+++ b/services/sync/tests/unit/test_errorhandler_2.js
@@ -21,48 +21,86 @@ do_register_cleanup(function() {
     fakeServer.stop(resolve);
   });
 });
 
 var fakeServerUrl = "http://localhost:" + fakeServer.port;
 
 const logsdir = FileUtils.getDir("ProfD", ["weave", "logs"], true);
 
+function removeLogFiles() {
+  let entries = logsdir.directoryEntries;
+  while (entries.hasMoreElements()) {
+    let logfile = entries.getNext().QueryInterface(Ci.nsILocalFile);
+    logfile.remove(false);
+  }
+}
+
+function getLogFiles() {
+  let result = [];
+  let entries = logsdir.directoryEntries;
+  while (entries.hasMoreElements()) {
+    result.push(entries.getNext().QueryInterface(Ci.nsILocalFile));
+  }
+  return result;
+}
+
 const PROLONGED_ERROR_DURATION =
   (Svc.Prefs.get("errorhandler.networkFailureReportTimeout") * 2) * 1000;
 
 const NON_PROLONGED_ERROR_DURATION =
   (Svc.Prefs.get("errorhandler.networkFailureReportTimeout") / 2) * 1000;
 
 function setLastSync(lastSyncValue) {
   Svc.Prefs.set("lastSync", (new Date(Date.now() - lastSyncValue)).toString());
 }
 
 // This relies on Service/ErrorHandler being a singleton. Fixing this will take
 // a lot of work.
 var errorHandler = Service.errorHandler;
 let engine;
 
+async function syncAndWait(topic) {
+  let promise1 = promiseOneObserver(topic);
+  // also wait for the log file to be written
+  let promise2 = promiseOneObserver("weave:service:reset-file-log");
+  await Service.sync();
+  await promise1;
+  await promise2;
+}
+
+async function syncAndReportErrorsAndWait(topic) {
+  let promise1 = promiseOneObserver(topic);
+  // also wait for the log file to be written
+  let promise2 = promiseOneObserver("weave:service:reset-file-log");
+  errorHandler.syncAndReportErrors();
+  await promise1;
+  await promise2;
+}
 add_task(async function setup() {
   initTestLogging("Trace");
 
   Log.repository.getLogger("Sync.Service").level = Log.Level.Trace;
   Log.repository.getLogger("Sync.SyncScheduler").level = Log.Level.Trace;
   Log.repository.getLogger("Sync.ErrorHandler").level = Log.Level.Trace;
+  Log.repository.getLogger("Sync.LogManager").level = Log.Level.Trace;
 
   Service.engineManager.clear();
   await Service.engineManager.register(EHTestsCommon.CatapultEngine);
   engine = Service.engineManager.get("catapult");
 });
 
 async function clean() {
+  let promiseLogReset = promiseOneObserver("weave:service:reset-file-log");
   await Service.startOver();
+  await promiseLogReset;
   Status.resetSync();
   Status.resetBackoff();
   errorHandler.didReportProlongedError = false;
+  removeLogFiles();
 }
 
 add_task(async function test_crypto_keys_login_server_maintenance_error() {
   enableValidationPrefs();
 
   Status.resetSync();
   // Test crypto/keys server maintenance errors are not reported.
   let server = await EHTestsCommon.sync_httpd_setup();
@@ -82,21 +120,18 @@ add_task(async function test_crypto_keys
   function onUIUpdate() {
     do_throw("Shouldn't get here!");
   }
   Svc.Obs.add("weave:ui:login:error", onUIUpdate);
 
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
-  let promiseObserved = promiseOneObserver("weave:ui:clear-error");
-
   setLastSync(NON_PROLONGED_ERROR_DURATION);
-  await Service.sync();
-  await promiseObserved;
+  await syncAndWait("weave:ui:clear-error");
 
   do_check_true(Status.enforceBackoff);
   do_check_eq(backoffInterval, 42);
   do_check_eq(Status.service, LOGIN_FAILED);
   do_check_eq(Status.login, SERVER_MAINTENANCE);
   do_check_false(errorHandler.didReportProlongedError);
 
   Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
@@ -145,24 +180,21 @@ add_task(async function test_info_collec
   await configureIdentity({username: "broken.info"}, server);
 
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
 
-  let promiseObserved = promiseOneObserver("weave:ui:login:error");
-
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
   setLastSync(PROLONGED_ERROR_DURATION);
-  await Service.sync();
-  await promiseObserved;
+  await syncAndWait("weave:ui:login:error");
 
   do_check_true(Status.enforceBackoff);
   do_check_eq(backoffInterval, 42);
   do_check_eq(Status.service, SYNC_FAILED);
   do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
   do_check_true(errorHandler.didReportProlongedError);
 
   await clean();
@@ -179,24 +211,21 @@ add_task(async function test_meta_global
   await configureIdentity({username: "broken.meta"}, server);
 
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
 
-  let promiseObserved = promiseOneObserver("weave:ui:login:error");
-
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
   setLastSync(PROLONGED_ERROR_DURATION);
-  await Service.sync();
-  await promiseObserved;
+  await syncAndWait("weave:ui:login:error");
 
   do_check_true(Status.enforceBackoff);
   do_check_eq(backoffInterval, 42);
   do_check_eq(Status.service, SYNC_FAILED);
   do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
   do_check_true(errorHandler.didReportProlongedError);
 
   await clean();
@@ -215,24 +244,21 @@ add_task(async function test_download_cr
   Service.collectionKeys.clear();
 
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
 
-  let promiseObserved = promiseOneObserver("weave:ui:login:error");
-
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
   setLastSync(PROLONGED_ERROR_DURATION);
-  await Service.sync();
-  await promiseObserved;
+  await syncAndWait("weave:ui:login:error");
   do_check_true(Status.enforceBackoff);
   do_check_eq(backoffInterval, 42);
   do_check_eq(Status.service, SYNC_FAILED);
   do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
   do_check_true(errorHandler.didReportProlongedError);
 
   await clean();
   await promiseStopServer(server);
@@ -248,24 +274,21 @@ add_task(async function test_upload_cryp
   await configureIdentity({username: "broken.keys"}, server);
 
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
 
-  let promiseObserved = promiseOneObserver("weave:ui:login:error");
-
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
   setLastSync(PROLONGED_ERROR_DURATION);
-  await Service.sync();
-  await promiseObserved;
+  await syncAndWait("weave:ui:login:error");
 
   do_check_true(Status.enforceBackoff);
   do_check_eq(backoffInterval, 42);
   do_check_eq(Status.service, SYNC_FAILED);
   do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
   do_check_true(errorHandler.didReportProlongedError);
 
   await clean();
@@ -283,24 +306,21 @@ add_task(async function test_wipeServer_
   await configureIdentity({username: "broken.wipe"}, server);
 
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
 
-  let promiseObserved = promiseOneObserver("weave:ui:login:error");
-
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
   setLastSync(PROLONGED_ERROR_DURATION);
-  await Service.sync();
-  await promiseObserved;
+  await syncAndWait("weave:ui:login:error");
 
   do_check_true(Status.enforceBackoff);
   do_check_eq(backoffInterval, 42);
   do_check_eq(Status.service, SYNC_FAILED);
   do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
   do_check_true(errorHandler.didReportProlongedError);
 
   await clean();
@@ -356,23 +376,20 @@ add_task(async function test_sync_syncAn
   let server = await EHTestsCommon.sync_httpd_setup();
   await EHTestsCommon.setUp(server);
 
   const BACKOFF = 42;
   engine.enabled = true;
   engine.exception = {status: 503,
                       headers: {"retry-after": BACKOFF}};
 
-  let promiseObserved = promiseOneObserver("weave:ui:sync:error");
-
   do_check_eq(Status.service, STATUS_OK);
 
   setLastSync(NON_PROLONGED_ERROR_DURATION);
-  errorHandler.syncAndReportErrors();
-  await promiseObserved;
+  await syncAndReportErrorsAndWait("weave:ui:sync:error")
 
   do_check_eq(Status.service, SYNC_FAILED_PARTIAL);
   do_check_eq(Status.sync, SERVER_MAINTENANCE);
   do_check_false(errorHandler.didReportProlongedError);
 
   await clean();
   await promiseStopServer(server);
 });
@@ -388,24 +405,21 @@ add_task(async function test_info_collec
   await configureIdentity({username: "broken.info"}, server);
 
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
 
-  let promiseObserved = promiseOneObserver("weave:ui:login:error");
-
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
   setLastSync(NON_PROLONGED_ERROR_DURATION);
-  errorHandler.syncAndReportErrors();
-  await promiseObserved;
+  await syncAndReportErrorsAndWait("weave:ui:login:error")
 
   do_check_true(Status.enforceBackoff);
   do_check_eq(backoffInterval, 42);
   do_check_eq(Status.service, LOGIN_FAILED);
   do_check_eq(Status.login, SERVER_MAINTENANCE);
   do_check_false(errorHandler.didReportProlongedError);
 
   await clean();
@@ -423,24 +437,21 @@ add_task(async function test_meta_global
   await configureIdentity({username: "broken.meta"}, server);
 
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
 
-  let promiseObserved = promiseOneObserver("weave:ui:login:error");
-
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
   setLastSync(NON_PROLONGED_ERROR_DURATION);
-  errorHandler.syncAndReportErrors();
-  await promiseObserved;
+  await syncAndReportErrorsAndWait("weave:ui:login:error")
 
   do_check_true(Status.enforceBackoff);
   do_check_eq(backoffInterval, 42);
   do_check_eq(Status.service, LOGIN_FAILED);
   do_check_eq(Status.login, SERVER_MAINTENANCE);
   do_check_false(errorHandler.didReportProlongedError);
 
   await clean();
@@ -460,24 +471,21 @@ add_task(async function test_download_cr
   Service.collectionKeys.clear();
 
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
 
-  let promiseObserved = promiseOneObserver("weave:ui:login:error");
-
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
   setLastSync(NON_PROLONGED_ERROR_DURATION);
-  errorHandler.syncAndReportErrors();
-  await promiseObserved;
+  await syncAndReportErrorsAndWait("weave:ui:login:error")
 
   do_check_true(Status.enforceBackoff);
   do_check_eq(backoffInterval, 42);
   do_check_eq(Status.service, LOGIN_FAILED);
   do_check_eq(Status.login, SERVER_MAINTENANCE);
   do_check_false(errorHandler.didReportProlongedError);
 
   await clean();
@@ -495,24 +503,21 @@ add_task(async function test_upload_cryp
   await configureIdentity({username: "broken.keys"}, server);
 
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
 
-  let promiseObserved = promiseOneObserver("weave:ui:login:error");
-
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
   setLastSync(NON_PROLONGED_ERROR_DURATION);
-  errorHandler.syncAndReportErrors();
-  await promiseObserved;
+  await syncAndReportErrorsAndWait("weave:ui:login:error")
 
   do_check_true(Status.enforceBackoff);
   do_check_eq(backoffInterval, 42);
   do_check_eq(Status.service, LOGIN_FAILED);
   do_check_eq(Status.login, SERVER_MAINTENANCE);
   do_check_false(errorHandler.didReportProlongedError);
 
   await clean();
@@ -530,24 +535,21 @@ add_task(async function test_wipeServer_
   await configureIdentity({username: "broken.wipe"}, server);
 
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
 
-  let promiseObserved = promiseOneObserver("weave:ui:login:error");
-
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
   setLastSync(NON_PROLONGED_ERROR_DURATION);
-  errorHandler.syncAndReportErrors();
-  await promiseObserved;
+  await syncAndReportErrorsAndWait("weave:ui:login:error")
 
   do_check_true(Status.enforceBackoff);
   do_check_eq(backoffInterval, 42);
   do_check_eq(Status.service, LOGIN_FAILED);
   do_check_eq(Status.login, SERVER_MAINTENANCE);
   do_check_false(errorHandler.didReportProlongedError);
 
   await clean();
@@ -568,25 +570,22 @@ add_task(async function test_wipeRemote_
   engine.enabled = true;
 
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
 
-  let promiseObserved = promiseOneObserver("weave:ui:sync:error");
-
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
   Svc.Prefs.set("firstSync", "wipeRemote");
   setLastSync(NON_PROLONGED_ERROR_DURATION);
-  errorHandler.syncAndReportErrors();
-  await promiseObserved;
+  await syncAndReportErrorsAndWait("weave:ui:sync:error")
 
   do_check_true(Status.enforceBackoff);
   do_check_eq(backoffInterval, 42);
   do_check_eq(Status.service, SYNC_FAILED);
   do_check_eq(Status.sync, SERVER_MAINTENANCE);
   do_check_eq(Svc.Prefs.get("firstSync"), "wipeRemote");
   do_check_false(errorHandler.didReportProlongedError);
 
@@ -602,23 +601,20 @@ add_task(async function test_sync_syncAn
   let server = await EHTestsCommon.sync_httpd_setup();
   await EHTestsCommon.setUp(server);
 
   const BACKOFF = 42;
   engine.enabled = true;
   engine.exception = {status: 503,
                       headers: {"retry-after": BACKOFF}};
 
-  let promiseObserved = promiseOneObserver("weave:ui:sync:error");
-
   do_check_eq(Status.service, STATUS_OK);
 
   setLastSync(PROLONGED_ERROR_DURATION);
-  errorHandler.syncAndReportErrors();
-  await promiseObserved;
+  await syncAndReportErrorsAndWait("weave:ui:sync:error")
 
   do_check_eq(Status.service, SYNC_FAILED_PARTIAL);
   do_check_eq(Status.sync, SERVER_MAINTENANCE);
   // syncAndReportErrors means dontIgnoreErrors, which means
   // didReportProlongedError not touched.
   do_check_false(errorHandler.didReportProlongedError);
 
   await clean();
@@ -636,24 +632,21 @@ add_task(async function test_info_collec
   await configureIdentity({username: "broken.info"}, server);
 
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
 
-  let promiseObserved = promiseOneObserver("weave:ui:login:error");
-
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
   setLastSync(PROLONGED_ERROR_DURATION);
-  errorHandler.syncAndReportErrors();
-  await promiseObserved;
+  await syncAndReportErrorsAndWait("weave:ui:login:error")
 
   do_check_true(Status.enforceBackoff);
   do_check_eq(backoffInterval, 42);
   do_check_eq(Status.service, LOGIN_FAILED);
   do_check_eq(Status.login, SERVER_MAINTENANCE);
   // syncAndReportErrors means dontIgnoreErrors, which means
   // didReportProlongedError not touched.
   do_check_false(errorHandler.didReportProlongedError);
@@ -673,24 +666,21 @@ add_task(async function test_meta_global
   await configureIdentity({username: "broken.meta"}, server);
 
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
 
-  let promiseObserved = promiseOneObserver("weave:ui:login:error");
-
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
   setLastSync(PROLONGED_ERROR_DURATION);
-  errorHandler.syncAndReportErrors();
-  await promiseObserved;
+  await syncAndReportErrorsAndWait("weave:ui:login:error")
 
   do_check_true(Status.enforceBackoff);
   do_check_eq(backoffInterval, 42);
   do_check_eq(Status.service, LOGIN_FAILED);
   do_check_eq(Status.login, SERVER_MAINTENANCE);
   // syncAndReportErrors means dontIgnoreErrors, which means
   // didReportProlongedError not touched.
   do_check_false(errorHandler.didReportProlongedError);
@@ -712,24 +702,21 @@ add_task(async function test_download_cr
   Service.collectionKeys.clear();
 
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
 
-  let promiseObserved = promiseOneObserver("weave:ui:login:error");
-
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
   setLastSync(PROLONGED_ERROR_DURATION);
-  errorHandler.syncAndReportErrors();
-  await promiseObserved;
+  await syncAndReportErrorsAndWait("weave:ui:login:error")
 
   do_check_true(Status.enforceBackoff);
   do_check_eq(backoffInterval, 42);
   do_check_eq(Status.service, LOGIN_FAILED);
   do_check_eq(Status.login, SERVER_MAINTENANCE);
   // syncAndReportErrors means dontIgnoreErrors, which means
   // didReportProlongedError not touched.
   do_check_false(errorHandler.didReportProlongedError);
@@ -749,24 +736,21 @@ add_task(async function test_upload_cryp
   await configureIdentity({username: "broken.keys"}, server);
 
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
 
-  let promiseObserved = promiseOneObserver("weave:ui:login:error");
-
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
   setLastSync(PROLONGED_ERROR_DURATION);
-  errorHandler.syncAndReportErrors();
-  await promiseObserved;
+  await syncAndReportErrorsAndWait("weave:ui:login:error")
 
   do_check_true(Status.enforceBackoff);
   do_check_eq(backoffInterval, 42);
   do_check_eq(Status.service, LOGIN_FAILED);
   do_check_eq(Status.login, SERVER_MAINTENANCE);
   // syncAndReportErrors means dontIgnoreErrors, which means
   // didReportProlongedError not touched.
   do_check_false(errorHandler.didReportProlongedError);
@@ -786,40 +770,39 @@ add_task(async function test_wipeServer_
   await configureIdentity({username: "broken.wipe"}, server);
 
   let backoffInterval;
   Svc.Obs.add("weave:service:backoff:interval", function observe(subject, data) {
     Svc.Obs.remove("weave:service:backoff:interval", observe);
     backoffInterval = subject;
   });
 
-  let promiseObserved = promiseOneObserver("weave:ui:login:error");
-
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
   setLastSync(PROLONGED_ERROR_DURATION);
-  errorHandler.syncAndReportErrors();
-  await promiseObserved;
+  await syncAndReportErrorsAndWait("weave:ui:login:error")
 
   do_check_true(Status.enforceBackoff);
   do_check_eq(backoffInterval, 42);
   do_check_eq(Status.service, LOGIN_FAILED);
   do_check_eq(Status.login, SERVER_MAINTENANCE);
   // syncAndReportErrors means dontIgnoreErrors, which means
   // didReportProlongedError not touched.
   do_check_false(errorHandler.didReportProlongedError);
 
   await clean();
   await promiseStopServer(server);
 });
 
 add_task(async function test_sync_engine_generic_fail() {
   enableValidationPrefs();
 
+  equal(getLogFiles().length, 0);
+
   let server = await EHTestsCommon.sync_httpd_setup();
   engine.enabled = true;
   engine.sync = async function sync() {
     Svc.Obs.notify("weave:engine:sync:error", ENGINE_UNKNOWN_FAIL, "catapult");
   };
 
   let log = Log.repository.getLogger("Sync.ErrorHandler");
   Svc.Prefs.set("log.appender.file.logOnError", true);
@@ -845,20 +828,19 @@ add_task(async function test_sync_engine
 
   await promiseObserved;
 
   _("Status.engines: " + JSON.stringify(Status.engines));
   do_check_eq(Status.engines["catapult"], ENGINE_UNKNOWN_FAIL);
   do_check_eq(Status.service, SYNC_FAILED_PARTIAL);
 
   // Test Error log was written on SYNC_FAILED_PARTIAL.
-  let entries = logsdir.directoryEntries;
-  do_check_true(entries.hasMoreElements());
-  let logfile = entries.getNext().QueryInterface(Ci.nsILocalFile);
-  do_check_true(logfile.leafName.startsWith("error-sync-"), logfile.leafName);
+  let logFiles = getLogFiles();
+  equal(logFiles.length, 1);
+  do_check_true(logFiles[0].leafName.startsWith("error-sync-"), logFiles[0].leafName);
 
   await clean();
 
   let syncErrors = sumHistogram("WEAVE_ENGINE_SYNC_ERRORS", { key: "catapult" });
   do_check_true(syncErrors, 1);
 
   await clean();
   await promiseStopServer(server);
@@ -878,20 +860,19 @@ add_task(async function test_logs_on_syn
   Status.login = MASTER_PASSWORD_LOCKED;
   do_check_false(errorHandler.shouldReportError());
 
   let promiseObserved = promiseOneObserver("weave:service:reset-file-log");
   Svc.Obs.notify("weave:service:sync:error", {});
   await promiseObserved;
 
   // Test that error log was written.
-  let entries = logsdir.directoryEntries;
-  do_check_true(entries.hasMoreElements());
-  let logfile = entries.getNext().QueryInterface(Ci.nsILocalFile);
-  do_check_true(logfile.leafName.startsWith("error-sync-"), logfile.leafName);
+  let logFiles = getLogFiles();
+  equal(logFiles.length, 1);
+  do_check_true(logFiles[0].leafName.startsWith("error-sync-"), logFiles[0].leafName);
 
   await clean();
 });
 
 add_task(async function test_logs_on_login_error_despite_shouldReportError() {
   enableValidationPrefs();
 
   _("Ensure that an error is still logged when weave:service:login:error " +
@@ -905,20 +886,19 @@ add_task(async function test_logs_on_log
   Status.login = MASTER_PASSWORD_LOCKED;
   do_check_false(errorHandler.shouldReportError());
 
   let promiseObserved = promiseOneObserver("weave:service:reset-file-log");
   Svc.Obs.notify("weave:service:login:error", {});
   await promiseObserved;
 
   // Test that error log was written.
-  let entries = logsdir.directoryEntries;
-  do_check_true(entries.hasMoreElements());
-  let logfile = entries.getNext().QueryInterface(Ci.nsILocalFile);
-  do_check_true(logfile.leafName.startsWith("error-sync-"), logfile.leafName);
+  let logFiles = getLogFiles();
+  equal(logFiles.length, 1);
+  do_check_true(logFiles[0].leafName.startsWith("error-sync-"), logFiles[0].leafName);
 
   await clean();
 });
 
 // This test should be the last one since it monkeypatches the engine object
 // and we should only have one engine object throughout the file (bug 629664).
 add_task(async function test_engine_applyFailed() {
   enableValidationPrefs();
@@ -939,16 +919,15 @@ add_task(async function test_engine_appl
   do_check_true(await EHTestsCommon.setUp(server));
   await Service.sync();
   await promiseObserved;
 
   do_check_eq(Status.engines["catapult"], ENGINE_APPLY_FAIL);
   do_check_eq(Status.service, SYNC_FAILED_PARTIAL);
 
   // Test Error log was written on SYNC_FAILED_PARTIAL.
-  let entries = logsdir.directoryEntries;
-  do_check_true(entries.hasMoreElements());
-  let logfile = entries.getNext().QueryInterface(Ci.nsILocalFile);
-  do_check_true(logfile.leafName.startsWith("error-sync-"), logfile.leafName);
+  let logFiles = getLogFiles();
+  equal(logFiles.length, 1);
+  do_check_true(logFiles[0].leafName.startsWith("error-sync-"), logFiles[0].leafName);
 
   await clean();
   await promiseStopServer(server);
 });
--- a/testing/mozbase/mozlog/mozlog/pytest_mozlog/plugin.py
+++ b/testing/mozbase/mozlog/mozlog/pytest_mozlog/plugin.py
@@ -76,17 +76,17 @@ class MozLog(object):
 
     def pytest_runtest_logreport(self, report):
         '''Called 3 times per test (setup, call, teardown), indicated by report.when'''
         test = report.nodeid
         status = expected = 'PASS'
         message = stack = None
         if hasattr(report, 'wasxfail'):
             expected = 'FAIL'
-        if report.failed:
+        if report.failed or report.outcome == 'rerun':
             status = 'FAIL' if report.when == 'call' else 'ERROR'
         if report.skipped:
             status = 'SKIP' if not hasattr(report, 'wasxfail') else 'FAIL'
         if report.longrepr is not None:
             longrepr = report.longrepr
             if isinstance(longrepr, basestring):
                 # When using pytest-xdist, longrepr is serialised as a str
                 message = stack = longrepr
@@ -105,13 +105,13 @@ class MozLog(object):
             elif hasattr(longrepr, "__getitem__") and len(longrepr) == 3:
                 # For skips, longrepr is a tuple of (file, lineno, reason)
                 message = report.longrepr[-1]
             else:
                 raise ValueError("Unable to convert longrepr to message:\ntype %s\nfields:" %
                                  (longrepr.__class__, dir(longrepr)))
         if status != expected or expected != 'PASS':
             self.results[test] = (status, expected, message, stack)
-        if report.when == 'teardown':
+        if report.outcome == 'rerun' or report.when == 'teardown':
             defaults = ('PASS', 'PASS', None, None)
             status, expected, message, stack = self.results.get(test, defaults)
             self.logger.test_end(test=test, status=status, expected=expected,
                                  message=message, stack=stack)
--- a/toolkit/components/satchel/AutoCompletePopup.jsm
+++ b/toolkit/components/satchel/AutoCompletePopup.jsm
@@ -147,32 +147,39 @@ this.AutoCompletePopup = {
     let window = browser.ownerGlobal;
     // Also check window top in case this is a sidebar.
     if (Services.focus.activeWindow !== window.top) {
       // We were sent a message from a window or tab that went into the
       // background, so we'll ignore it for now.
       return;
     }
 
+    let firstResultStyle = results[0].style;
     this.weakBrowser = Cu.getWeakReference(browser);
     this.openedPopup = browser.autoCompletePopup;
     // the layout varies according to different result type
-    this.openedPopup.setAttribute("firstresultstyle", results[0].style);
+    this.openedPopup.setAttribute("firstresultstyle", firstResultStyle);
     this.openedPopup.hidden = false;
     // don't allow the popup to become overly narrow
     this.openedPopup.setAttribute("width", Math.max(100, rect.width));
     this.openedPopup.style.direction = dir;
 
     AutoCompleteResultView.setResults(results);
     this.openedPopup.view = AutoCompleteResultView;
     this.openedPopup.selectedIndex = -1;
 
     if (results.length) {
       // Reset fields that were set from the last time the search popup was open
       this.openedPopup.mInput = AutoCompleteResultView;
+      // Temporarily increase the maxRows as we don't want to show
+      // the scrollbar in form autofill popup.
+      if (firstResultStyle == "autofill-profile") {
+        this.openedPopup._normalMaxRows = this.openedPopup.maxRows;
+        this.openedPopup.mInput.maxRows = 100;
+      }
       this.openedPopup.showCommentColumn = false;
       this.openedPopup.showImageColumn = false;
       this.openedPopup.addEventListener("popuphidden", this);
       this.openedPopup.addEventListener("popupshowing", this);
       this.openedPopup.openPopupAtScreenRect("after_start", rect.left, rect.top,
                                              rect.width, rect.height, false,
                                              false);
       this.openedPopup.invalidate();
--- a/toolkit/content/widgets/preferences.xml
+++ b/toolkit/content/widgets/preferences.xml
@@ -28,29 +28,29 @@
 #   </prefwindow>
 #
 
   <binding id="preferences">
     <implementation implements="nsIObserver">
       <method name="_constructAfterChildren">
       <body>
       <![CDATA[
-      // This method will be called after each one of the child
+      // This method will be called after the last of the child
       // <preference> elements is constructed. Its purpose is to propagate
-      // the values to the associated form elements
+      // the values to the associated form elements. Sometimes the code for
+      // some <preference> initializers depend on other <preference> elements
+      // being initialized so we wait and call updateElements on all of them
+      // once the last one has been constructed. See bugs 997570 and 992185.
 
       var elements = this.getElementsByTagName("preference");
       for (let element of elements) {
-        if (!element._constructed) {
-          return;
-        }
-      }
-      for (let element of elements) {
         element.updateElements();
       }
+
+      this._constructAfterChildrenCalled = true;
       ]]>
       </body>
       </method>
       <method name="observe">
         <parameter name="aSubject"/>
         <parameter name="aTopic"/>
         <parameter name="aData"/>
         <body>
@@ -107,25 +107,42 @@
         <getter>
           <![CDATA[
             var doc = document.documentElement;
             return this.type == "child" ? doc.instantApply
                                         : doc.instantApply || this.rootBranch.getBoolPref("browser.preferences.instantApply");
           ]]>
         </getter>
       </property>
+
+      <!-- We want to call _constructAfterChildren after all child
+           <preference> elements have been constructed. To do this, we get
+           and store the node list of all child <preference> elements in the
+           constructor, and maintain a count which is incremented in the
+           constructor of <preference>. _constructAfterChildren is called
+           when the count matches the length of the list. -->
+      <field name="_constructedChildrenCount">0</field>
+      <field name="_preferenceChildren">null</field>
+      <!-- Some <preference> elements are added dynamically after
+           _constructAfterChildren has already been called - we want to
+           avoid looping over all of them again in this case so we remember
+           if we already called it. -->
+      <field name="_constructAfterChildrenCalled">false</field>
+      <constructor>
+      <![CDATA[
+        this._preferenceChildren = this.getElementsByTagName("preference");
+      ]]>
+      </constructor>
     </implementation>
   </binding>
 
   <binding id="preference">
     <implementation>
       <constructor>
       <![CDATA[
-        this._constructed = true;
-
         // if the element has been inserted without the name attribute set,
         // we have nothing to do here
         if (!this.name)
           return;
 
         this.preferences.rootBranchInternal
             .addObserver(this.name, this.preferences);
         // In non-instant apply mode, we must try and use the last saved state
@@ -148,19 +165,31 @@
             for (var l = 0; (l < parentPrefs.length && !preference); ++l) {
               if (parentPrefs[l].localName == "preference")
                 preference = parentPrefs[l];
             }
           }
 
           // Don't use the value setter here, we don't want updateElements to be prematurely fired.
           this._value = preference ? preference.value : this.valueFromPreferences;
-        } else
+        } else {
           this._value = this.valueFromPreferences;
-        this.preferences._constructAfterChildren();
+        }
+        if (this.preferences._constructAfterChildrenCalled) {
+          // This <preference> was added after _constructAfterChildren() was already called.
+          // We can directly call updateElements().
+          this.updateElements();
+          return;
+        }
+        this.preferences._constructedChildrenCount++;
+        if (this.preferences._constructedChildrenCount ==
+            this.preferences._preferenceChildren.length) {
+          // This is the last <preference>, time to updateElements() on all of them.
+          this.preferences._constructAfterChildren();
+        }
       ]]>
       </constructor>
       <destructor>
         this.preferences.rootBranchInternal
             .removeObserver(this.name, this.preferences);
       </destructor>
       <field name="_constructed">false</field>
       <property name="instantApply">
--- a/toolkit/modules/PopupNotifications.jsm
+++ b/toolkit/modules/PopupNotifications.jsm
@@ -254,25 +254,31 @@ this.PopupNotifications = function Popup
         focusedElement == this.tabbrowser.selectedBrowser ||
         // Ignore focused elements inside the notification.
         getNotificationFromElement(focusedElement) == notification ||
         notification.contains(focusedElement)) {
       this._onButtonEvent(aEvent, "secondarybuttoncommand", notification);
     }
   };
 
+  let documentElement = this.window.document.documentElement;
+  let locationBarHidden = documentElement.getAttribute("chromehidden").includes("location");
+  let isFullscreen = !!this.window.document.fullscreenElement;
+
+  this.panel.setAttribute("followanchor", !locationBarHidden && !isFullscreen);
+
   // There are no anchor icons in DOM fullscreen mode, but we would
   // still like to show the popup notification. To avoid an infinite
   // loop of showing and hiding, we have to disable followanchor
   // (which hides the element without an anchor) in fullscreen.
   this.window.addEventListener("MozDOMFullscreen:Entered", () => {
     this.panel.setAttribute("followanchor", "false");
   }, true);
   this.window.addEventListener("MozDOMFullscreen:Exited", () => {
-    this.panel.setAttribute("followanchor", "true");
+    this.panel.setAttribute("followanchor", !locationBarHidden);
   }, true);
 
   this.window.addEventListener("activate", this, true);
   if (this.tabbrowser.tabContainer)
     this.tabbrowser.tabContainer.addEventListener("TabSelect", this, true);
 }
 
 PopupNotifications.prototype = {
@@ -935,16 +941,23 @@ PopupNotifications.prototype = {
 
       // If the identity icon is not available in this window, or maybe the
       // entire location bar is hidden for any reason, use the tab as the
       // anchor. We only ever show notifications for the current browser, so we
       // can just use the current tab.
       if (!anchorElement || (anchorElement.boxObject.height == 0 &&
                              anchorElement.boxObject.width == 0)) {
         anchorElement = this.tabbrowser.selectedTab;
+
+        // If we're in an entirely chromeless environment, set the anchorElement
+        // to null and let openPopup show the notification at (0,0) later.
+        if (!anchorElement || (anchorElement.boxObject.height == 0 &&
+                               anchorElement.boxObject.width == 0)) {
+          anchorElement = null;
+        }
       }
     }
 
     if (this.isPanelOpen && this._currentAnchorElement == anchorElement) {
       notificationsToShow.forEach(function(n) {
         this._fireCallback(n, NOTIFICATION_EVENT_SHOWN);
       }, this);
 
@@ -1018,17 +1031,17 @@ PopupNotifications.prototype = {
         this.panel.dispatchEvent(new this.window.CustomEvent("Shown"));
         let event = new this.window.CustomEvent("PanelUpdated",
                                                 {"detail": notificationIds});
         this.panel.dispatchEvent(event);
       };
       this._popupshownListener = this._popupshownListener.bind(this);
       target.addEventListener("popupshown", this._popupshownListener, true);
 
-      this.panel.openPopup(anchorElement, "bottomcenter topleft");
+      this.panel.openPopup(anchorElement, "bottomcenter topleft", 0, 0);
     });
   },
 
   /**
    * Updates the notification state in response to window activation or tab
    * selection changes.
    *
    * @param notifications an array of Notification instances. if null,
--- a/widget/windows/WinIMEHandler.cpp
+++ b/widget/windows/WinIMEHandler.cpp
@@ -416,29 +416,17 @@ IMEHandler::OnDestroyWindow(nsWindow* aW
   AssociateIMEContext(aWindow, true);
 }
 
 #ifdef NS_ENABLE_TSF
 // static
 bool
 IMEHandler::NeedsToAssociateIMC()
 {
-  if (sAssociateIMCOnlyWhenIMM_IMEActive) {
-    return IsIMMActive();
-  }
-
-  // Even if IMC should be associated with focused widget with non-IMM-IME,
-  // we need to avoid crash bug of MS-IME for Japanese on Win10.  It crashes
-  // while we're associating default IME to a window when it's active.
-  static const bool sDoNotAssociateIMCWhenMSJapaneseIMEActiveOnWin10 =
-    IsWin10OrLater() &&
-    Preferences::GetBool(
-      "intl.tsf.hack.ms_japanese_ime.do_not_associate_imc_on_win10", true);
-  return !sDoNotAssociateIMCWhenMSJapaneseIMEActiveOnWin10 ||
-         !TSFTextStore::IsMSJapaneseIMEActive();
+  return !sAssociateIMCOnlyWhenIMM_IMEActive || !IsIMMActive();
 }
 #endif // #ifdef NS_ENABLE_TSF
 
 // static
 void
 IMEHandler::SetInputContext(nsWindow* aWindow,
                             InputContext& aInputContext,
                             const InputContextAction& aAction)
@@ -561,16 +549,23 @@ IMEHandler::OnKeyboardLayoutChanged()
   // observe active TIP change.  If you need to be notified of this, you
   // need to create TSFStaticSink::Observe() or something and call it
   // TSFStaticSink::EnsureInitActiveTIPKeyboard() forcibly.
 
   if (!sIsIMMEnabled || !IsTSFAvailable()) {
     return;
   }
 
+  // We don't need to do anything when sAssociateIMCOnlyWhenIMM_IMEActive is
+  // false because IMContext won't be associated/disassociated when changing
+  // active keyboard layout/IME.
+  if (!sAssociateIMCOnlyWhenIMM_IMEActive) {
+    return;
+  }
+
   // If there is no TSFTextStore which has focus, i.e., no editor has focus,
   // nothing to do here.
   nsWindowBase* windowBase = TSFTextStore::GetEnabledWindowBase();
   if (!windowBase) {
     return;
   }
 
   // If IME isn't available, nothing to do here.