Merge mozilla-central to mozillla-inbound
authorDaniel Varga <dvarga@mozilla.com>
Wed, 21 Aug 2019 19:56:09 +0300
changeset 489241 f278b6217571efbfb9c72a501524c6ef6ad16343
parent 489240 147abc22f7201361d465c55803dae136c54fb9ea (current diff)
parent 489179 4ab60925635ce3d59573a6021486ab9bd272cbec (diff)
child 489242 835d0d9cdae81b3ab583d4ccf7459d00b041fad6
push id36467
push useraciure@mozilla.com
push dateWed, 21 Aug 2019 21:55:24 +0000
treeherdermozilla-central@835d0d9cdae8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone70.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to mozillla-inbound
browser/base/content/browser-places.js
browser/components/customizableui/test/browser_973641_button_addon.js
browser/components/newtab/bin/vendor.js
browser/components/preferences/in-content/sync.inc.xul
browser/components/preferences/in-content/tests/siteData/offline/offline.html
browser/components/preferences/in-content/tests/siteData/service_worker_test.html
browser/components/preferences/in-content/tests/siteData/site_data_test.html
browser/components/sessionstore/test/browser_frame_history_a.html
browser/components/sessionstore/test/browser_frame_history_b.html
browser/components/sessionstore/test/browser_frame_history_c.html
browser/components/sessionstore/test/browser_frame_history_c1.html
browser/components/sessionstore/test/browser_frame_history_c2.html
devtools/client/debugger/test/mochitest/examples/sourcemapped/build.js
docshell/test/chrome/bug298622_window.xul
docshell/test/chrome/bug303267_window.xul
docshell/test/chrome/bug321671_window.xul
docshell/test/chrome/bug360511_window.xul
docshell/test/chrome/bug396649_window.xul
docshell/test/chrome/docshell_helpers.js
dom/events/test/test_eventTimeStamp.html
dom/xslt/crashtests/1330492.html
js/src/devtools/rootAnalysis/build.js
js/src/tests/non262/Array/regress-465980-02.js
js/src/tests/non262/regress/regress-451322.js
js/src/tests/user.js
layout/painting/crashtests/1469472.html
layout/style/crashtests/1340248.html
mobile/android/tests/browser/chrome/tp5/163.com/163.wrating.com/a1.js
mobile/android/tests/browser/chrome/tp5/163.com/analytics.163.com/ntes.js
mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=banner360x65&location=1.html
mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=banner360x65&location=2.html
mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column360x100&location=1.html
mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column360x100&location=2.html
mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column360x100&location=3.html
mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column360x100&location=5.html
mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column360x100&location=6.html
mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=1.html
mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=2.html
mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=3.html
mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=4.html
mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=5.html
mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column390x100&location=6.html
mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=column600x80&location=1.html
mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x100&location=1.html
mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x100&location=2.html
mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x180&location=1.html
mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x180&location=2.html
mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x180&location=3.html
mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x180&location=4.html
mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x300&location=1.html
mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=logo190x300&location=2.html
mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=textlinkhouse&location=1.html
mobile/android/tests/browser/chrome/tp5/163.com/g.163.com/r@site=netease&affiliate=homepage&cat=homepage&type=textlinkhouse&location=2.html
mobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/rpic/fld3/fld_homepage.js
mobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/rpic/fld3/flsclasses.js
mobile/android/tests/browser/chrome/tp5/163.com/img3.126.net/yodaoimages/pack.r091221/scripts/autocomplete.163.165290.js
mobile/android/tests/browser/chrome/tp5/163.com/img3.cache.netease.com/cnews/js/ntes_jslib_1.x.js
mobile/android/tests/browser/chrome/tp5/163.com/p.mail.163.com/mailinfo/ntes_mail_info_www_1222.js
mobile/android/tests/browser/chrome/tp5/163.com/p.mail.163.com/mailinfo/shownewmsg_www_1222.htm.html
mobile/android/tests/browser/chrome/tp5/163.com/show.mediav.com/s@type=1&db=mediav&pub=118_2620_36413&cus=0_0_0_0_0&wh=360x100&btype=1&js=1.html
mobile/android/tests/browser/chrome/tp5/163.com/www.163.com/index.html
mobile/android/tests/browser/chrome/tp5/163.com/zjs.ipinyou.com/2011032517331513260_2342_190180.js
mobile/android/tests/browser/chrome/tp5/baidu.com/c.baidu.com/c.gif@t=0&q=mozilla&p=0&pn=1.html
mobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/s@wd=mozilla.html
mobile/android/tests/browser/chrome/tp5/baidu.com/www.baidu.com/user/js/u.js
mobile/android/tests/browser/chrome/tp5/bbc.co.uk/b.scorecardresearch.com/b2@c1=2&c2=6035051&c3=&c4=www.bbc.co.uk%2Fnews%2F&c5=&c6=&c15=&cv=1.3&cj=1.html
mobile/android/tests/browser/chrome/tp5/bbc.co.uk/edge.quantserve.com/quant.js
mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/app/bbccom/19_52/s_code.js
mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/app/bbccom/19_61/bbccom.js
mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/common/3_2/bbc_fmtj_common.js
mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/config/apps/4_5/bbc_fmtj_config.js
mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/core/3_2/bbc_fmtj.js
mobile/android/tests/browser/chrome/tp5/bbc.co.uk/news.bbcimg.co.uk/js/locationservices/locator/v4_0/locator.js
mobile/android/tests/browser/chrome/tp5/bbc.co.uk/node1.bbcimg.co.uk/glow/gloader.0.1.4.js
mobile/android/tests/browser/chrome/tp5/bbc.co.uk/pixel.quantserve.com/pixel/r.html
mobile/android/tests/browser/chrome/tp5/bbc.co.uk/sa.bbc.co.uk/bbc/bbc/s.html
mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/barlesque/1.8.15/desktop/3/script/barlesque.js
mobile/android/tests/browser/chrome/tp5/bbc.co.uk/static.bbc.co.uk/frameworks/requirejs/0.6.4/sharedmodules/require.js
mobile/android/tests/browser/chrome/tp5/bbc.co.uk/www.bbc.co.uk/news/index.html
mobile/android/tests/browser/chrome/tp5/msn.com/col.stj.s-msn.com/br/sc/js/jquery/jquery-1.4.2.min.js
mobile/android/tests/browser/chrome/tp5/msn.com/www.msn.com/index.html
mobile/android/tests/browser/chrome/tp5/twitter.com/ajax.googleapis.com/ajax/libs/jquery/1.3.0/jquery.min.js
mobile/android/tests/browser/chrome/tp5/twitter.com/twitter.com/ICHCheezburger.html
modules/libpref/init/all.js
python/mozboot/support/ConEmu.xml
testing/talos/talos/startup_test/sessionrestore/profile/sessionstore.js
testing/talos/talos/startup_test/tspaint_test.html
testing/web-platform/tests/web-animations/resources/timing-override.js
toolkit/components/normandy/actions/schemas/export_json.js
toolkit/components/places/tests/sync/sync_utils_bookmarks.html
toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist_AllOS.xml
--- a/Makefile.in
+++ b/Makefile.in
@@ -162,16 +162,24 @@ recurse_android-fat-aar-artifact:
 	$(call py_action,fat_aar,\
     $(addprefix --armeabi-v7a $(MOZ_FETCHES_DIR)/,$(MOZ_ANDROID_FAT_AAR_ARMEABI_V7A)) \
     $(addprefix --arm64-v8a $(MOZ_FETCHES_DIR)/,$(MOZ_ANDROID_FAT_AAR_ARM64_V8A)) \
     $(addprefix --x86 $(MOZ_FETCHES_DIR)/,$(MOZ_ANDROID_FAT_AAR_X86)) \
     $(addprefix --x86-64 $(MOZ_FETCHES_DIR)/,$(MOZ_ANDROID_FAT_AAR_X86_64)) \
     --distdir $(abspath $(DIST)/fat-aar))
 endif
 
+ifeq ($(MOZ_BUILD_APP),mobile/android)
+
+recurse_android-stage-package: stage-package
+
+recurse_android-archive-geckoview:
+	GRADLE_INVOKED_WITHIN_MACH_BUILD=1 $(topsrcdir)/mach --log-no-times android archive-geckoview
+endif
+
 ifdef MOZ_WIDGET_TOOLKIT
 ifdef ENABLE_TESTS
 # Additional makefile targets to call automated test suites
 include $(topsrcdir)/testing/testsuite-targets.mk
 endif
 endif
 
 default all::
--- a/browser/app/winlauncher/moz.build
+++ b/browser/app/winlauncher/moz.build
@@ -27,16 +27,29 @@ SOURCES['DllBlocklistWin.cpp'].no_pgo = 
 # DllBlocklistWin.cpp should be compiled in a freestanding environment, as
 # our patched NtMapViewOfSection must not assume that it has access to any
 # runtime libraries.
 if CONFIG['CC_TYPE'] == 'clang-cl':
     SOURCES['DllBlocklistWin.cpp'].flags += ['-Xclang', '-ffreestanding']
 else:
     SOURCES['DllBlocklistWin.cpp'].flags += ['-ffreestanding']
 
+# Disable -ftrivial-auto-var-init=pattern for DllBlocklistWin.cpp because
+# the file's interceptions happen so early in the main process that the
+# loader hasn't yet resolved the import of memset (used by
+# -ftrivial-auto-var-init) from vcruntime140.dll.
+if CONFIG['CC_TYPE'] == 'clang-cl':
+    SOURCES['DllBlocklistWin.cpp'].flags += [
+        '-Xclang', '-ftrivial-auto-var-init=uninitialized',
+    ]
+else:
+    SOURCES['DllBlocklistWin.cpp'].flags += [
+        '-ftrivial-auto-var-init=uninitialized',
+    ]
+
 OS_LIBS += [
     'ntdll',
     'oleaut32',
     'ole32',
     'rpcrt4',
     'version',
 ]
 
old mode 100755
new mode 100644
--- a/browser/base/content/pageinfo/permissions.js
+++ b/browser/base/content/pageinfo/permissions.js
@@ -4,17 +4,16 @@
 
 /* import-globals-from pageInfo.js */
 
 const { SitePermissions } = ChromeUtils.import(
   "resource:///modules/SitePermissions.jsm"
 );
 
 var gPermPrincipal;
-var gUsageRequest;
 
 // Array of permissionIDs sorted alphabetically by label.
 var gPermissions = SitePermissions.listPermissions()
   .filter(p => SitePermissions.getPermissionLabel(p) != null)
   .sort((a, b) => {
     let firstLabel = SitePermissions.getPermissionLabel(a);
     let secondLabel = SitePermissions.getPermissionLabel(b);
     return firstLabel.localeCompare(secondLabel);
@@ -49,21 +48,16 @@ function onLoadPermission(uri, principal
     permTab.hidden = false;
   } else {
     permTab.hidden = true;
   }
 }
 
 function onUnloadPermission() {
   Services.obs.removeObserver(permissionObserver, "perm-changed");
-
-  if (gUsageRequest) {
-    gUsageRequest.cancel();
-    gUsageRequest = null;
-  }
 }
 
 function initRow(aPartId) {
   createRow(aPartId);
 
   var checkbox = document.getElementById(aPartId + "Def");
   var command = document.getElementById("cmd_" + aPartId + "Toggle");
   var { state, scope } = SitePermissions.getForPrincipal(
--- a/browser/base/content/test/trackingUI/browser_trackingUI_categories.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_categories.js
@@ -213,17 +213,20 @@ add_task(async function testCategorySect
         );
       } else {
         Services.prefs.setBoolPref(enabledPref, true);
       }
       gProtectionsHandler.onContentBlockingEvent(contentBlockingState);
       await waitForClass(itemToTest, "notFound", false);
       await waitForClass(itemToTest, "blocked", true);
       if (enabledPref == TPC_PREF) {
-        Services.prefs.setIntPref(TPC_PREF, Ci.nsICookieService.BEHAVIOR_ALLOW);
+        Services.prefs.setIntPref(
+          TPC_PREF,
+          Ci.nsICookieService.BEHAVIOR_ACCEPT
+        );
       } else {
         Services.prefs.setBoolPref(enabledPref, false);
       }
       await waitForClass(itemToTest, "notFound", false);
       await waitForClass(itemToTest, "blocked", false);
     }
   });
 });
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -205,20 +205,17 @@ menuitem.bookmark-item {
 }
 
 #urlbar-display-box {
   margin-top: -1px;
   margin-bottom: -1px;
 }
 
 .urlbar-display {
-  margin-top: 0;
-  margin-bottom: 0;
   margin-inline-start: 0;
-  color: GrayText;
 }
 
 #search-container {
   min-width: calc(54px + 11ch);
 }
 
 /* identity box */
 
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -288,22 +288,16 @@
 #search-container {
   min-width: calc(54px + 11ch);
 }
 
 #wrapper-urlbar-container[place="palette"] {
   max-width: 20em;
 }
 
-.urlbar-display {
-  margin-top: 0;
-  margin-bottom: 0;
-  color: GrayText;
-}
-
 #pageAction-urlbar-shareURL,
 #pageAction-panel-shareURL {
   list-style-image: url("chrome://browser/skin/share.svg");
 }
 
 /* ----- AUTOCOMPLETE ----- */
 
 %include ../shared/autocomplete.inc.css
--- a/browser/themes/shared/urlbar-searchbar.inc.css
+++ b/browser/themes/shared/urlbar-searchbar.inc.css
@@ -353,16 +353,29 @@
 
 .urlbar-icon:-moz-focusring,
 .urlbar-icon-wrapper:-moz-focusring {
   outline: var(--toolbarbutton-focus-outline);
   outline-offset: -2px;
   -moz-outline-radius: var(--toolbarbutton-border-radius);
 }
 
+.urlbar-display {
+  margin-top: 0;
+  margin-bottom: 0;
+}
+
+.urlbar-display:not(:-moz-lwtheme) {
+  color: GrayText;
+}
+
+.urlbar-display:-moz-lwtheme {
+  opacity: 0.5;
+}
+
 #urlbar-go-button,
 .search-go-button {
   list-style-image: url("chrome://browser/skin/forward.svg");
 }
 
 #urlbar-go-button:-moz-locale-dir(rtl),
 .search-go-button:-moz-locale-dir(rtl) {
   transform: scaleX(-1);
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -574,20 +574,17 @@ menuitem.bookmark-item {
 }
 
 #urlbar-zoom-button {
   -moz-appearance: none;
   color: inherit;
 }
 
 .urlbar-display {
-  margin-top: 0;
-  margin-bottom: 0;
   margin-inline-start: 0;
-  color: GrayText;
 }
 
 #pageAction-urlbar-shareURL,
 #pageAction-panel-shareURL {
   list-style-image: url("chrome://browser/skin/share.svg");
 }
 
 #search-container {
--- a/build/moz.configure/init.configure
+++ b/build/moz.configure/init.configure
@@ -789,42 +789,40 @@ def help_host_target(help, host, target)
             os='unknown',
             endianness='unknown',
             raw_cpu='unknown',
             raw_os='unknown',
             toolchain='unknown-unknown',
         )
 
 
-@imports('subprocess')
 def config_sub(shell, triplet):
     config_sub = os.path.join(os.path.dirname(__file__), '..',
                               'autoconf', 'config.sub')
-    return subprocess.check_output([shell, config_sub, triplet]).strip()
+    return check_cmd_output(shell, config_sub, triplet).strip()
 
 
 @depends('--host', shell)
 @checking('for host system type', lambda h: h.alias)
 @imports('os')
-@imports('subprocess')
 @imports('sys')
 @imports(_from='__builtin__', _import='ValueError')
 def real_host(value, shell):
     if not value and sys.platform == 'win32':
         arch = (os.environ.get('PROCESSOR_ARCHITEW6432') or
                 os.environ.get('PROCESSOR_ARCHITECTURE'))
         if arch == 'AMD64':
             return split_triplet('x86_64-pc-mingw32')
         elif arch == 'x86':
             return split_triplet('i686-pc-mingw32')
 
     if not value:
         config_guess = os.path.join(os.path.dirname(__file__), '..',
                                     'autoconf', 'config.guess')
-        host = subprocess.check_output([shell, config_guess], universal_newlines=True).strip()
+        host = check_cmd_output(shell, config_guess, universal_newlines=True).strip()
         try:
             return split_triplet(host)
         except ValueError:
             pass
     else:
         host = value[0]
 
     host = config_sub(shell, host)
--- a/build/moz.configure/node.configure
+++ b/build/moz.configure/node.configure
@@ -9,16 +9,17 @@ option('--disable-nodejs',
 option(env='NODEJS', nargs=1, help='Path to nodejs')
 
 
 @depends('--enable-nodejs', 'NODEJS')
 @checking('for nodejs',
           callback=lambda x: '%s (%s)' % (x.path, x.str_version) if x else 'no')
 @imports(_from='mozbuild.nodeutil', _import='find_node_executable')
 @imports(_from='mozbuild.nodeutil', _import='NODE_MIN_VERSION')
+@imports(_from='mozbuild.util', _import='system_encoding')
 def nodejs(require, env_node):
     node_exe = env_node[0] if env_node else None
 
     nodejs, version = find_node_executable(node_exe)
 
     MAYBE_FILE_A_BUG = '''
 
     Executing `mach bootstrap --no-system-changes` should
@@ -46,15 +47,15 @@ def nodejs(require, env_node):
 
         if require:
             raise FatalCheckError(msg)
         else:
             log.warning(msg)
             return
 
     return namespace(
-        path=nodejs,
+        path=nodejs.decode(system_encoding),
         version=version,
         str_version='.'.join(str(v) for v in version),
     )
 
 
 set_config('NODEJS', depends_if(nodejs)(lambda p: p.path))
--- a/build/moz.configure/old.configure
+++ b/build/moz.configure/old.configure
@@ -1,22 +1,15 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 
-@imports('codecs')
-@imports('sys')
-def encoded_open(path, mode):
-    encoding = 'mbcs' if sys.platform == 'win32' else 'utf-8'
-    return codecs.open(path, mode, encoding)
-
-
 option(env='AUTOCONF', nargs=1, help='Path to autoconf 2.13')
 
 
 @depends(mozconfig, 'AUTOCONF')
 @checking('for autoconf')
 @imports(_from='os.path', _import='exists')
 @imports('re')
 def autoconf(mozconfig, autoconf):
@@ -143,17 +136,17 @@ def prepare_configure(old_configure, moz
             try:
                 # Likely the file already existed (on Windows). Retry after removing it.
                 remove(old_configure)
                 rename(fh.name, old_configure)
             except OSError as e:
                 die('Failed re-creating old-configure: %s' % e.message)
 
     cmd = [shell, old_configure]
-    with encoded_open('old-configure.vars', 'w') as out:
+    with open('old-configure.vars', 'w') as out:
         log.debug('Injecting the following to old-configure:')
 
         def inject(command):
             print(command, file=out) # noqa Python 2vs3
             log.debug('| %s', command)
 
         if mozconfig:
             inject('# start of mozconfig values')
@@ -346,34 +339,34 @@ def old_configure(prepare_configure, pre
         if not line:
             break
         log.info(line.rstrip())
 
     ret = proc.wait()
     if ret:
         with log.queue_debug():
             if config_log:
-                with encoded_open(config_log.baseFilename, 'r') as fh:
+                with open(config_log.baseFilename, 'r') as fh:
                     fh.seek(log_size)
                     for line in fh:
                         log.debug(line.rstrip())
             log.error('old-configure failed')
         sys.exit(ret)
 
     if config_log:
         # Create a new handler in append mode
         handler = logging.FileHandler(config_log.baseFilename, mode='a', delay=True)
         handler.setFormatter(config_log.formatter)
         logger.addHandler(handler)
 
     raw_config = {
         'split': split,
         'unique_list': unique_list,
     }
-    with encoded_open('config.data', 'r') as fh:
+    with open('config.data', 'r') as fh:
         code = compile(fh.read(), 'config.data', 'exec')
         # Every variation of the exec() function I tried led to:
         # SyntaxError: unqualified exec is not allowed in function 'main' it
         # contains a nested function with free variables
         exec code in raw_config # noqa
 
     # Ensure all the flags known to old-configure appear in the
     # @old_configure_options above.
--- a/build/moz.configure/pkg.configure
+++ b/build/moz.configure/pkg.configure
@@ -11,17 +11,16 @@ def pkg_config(prefixes):
                  for p in (prefixes or ()) + ('',))
 
 
 pkg_config = check_prog('PKG_CONFIG', pkg_config, allow_missing=True)
 
 
 @depends_if(pkg_config)
 @checking('for pkg-config version')
-@imports('subprocess')
 def pkg_config_version(pkg_config):
     return Version(check_cmd_output(pkg_config, '--version').rstrip())
 
 # Locates the given module using pkg-config.
 # - `var` determines the name of variables to set when the package is found.
 #   <var>_CFLAGS and <var>_LIBS are set with corresponding values.
 # - `package_desc` package name and version requirement string, list of
 #   strings describing packages to locate, or depends function that will
@@ -54,36 +53,33 @@ def pkg_check_modules(var, package_desc,
             die("*** The pkg-config script could not be found. Make sure it is\n"
                 "*** in your path, or set the PKG_CONFIG environment variable\n"
                 "*** to the full path to pkg-config.")
         if version < min_version:
             die("*** Your version of pkg-config is too old. You need version %s or newer.",
                 min_version)
 
     @depends(pkg_config, package_desc, allow_missing, when=when_and_compile_environment)
-    @imports('subprocess')
     @imports('sys')
     @imports(_from='mozbuild.configure.util', _import='LineIO')
     def package(pkg_config, package_desc, allow_missing):
         # package_desc may start as a depends function, so we can't use
         # @checking here.
         log.info("checking for %s... " % package_desc)
-        with log.queue_debug():
-            try:
-                subprocess.check_output([pkg_config, '--errors-to-stdout',
-                                         '--print-errors', package_desc])
-                log.info("yes")
-                return True
-            except subprocess.CalledProcessError as e:
-                log.info("no")
-                log_writer = log.warning if allow_missing else log.error
-                with LineIO(lambda l: log_writer(l), 'replace') as o:
-                    o.write(e.output)
-                if not allow_missing:
-                    sys.exit(1)
+        retcode, stdout, stderr = get_cmd_output(
+            pkg_config, '--errors-to-stdout', '--print-errors', package_desc)
+        if retcode == 0:
+            log.info("yes")
+            return True
+        log.info("no")
+        log_writer = log.warning if allow_missing else log.error
+        with LineIO(lambda l: log_writer(l)) as o:
+            o.write(stdout)
+        if not allow_missing:
+            sys.exit(1)
 
     @depends(pkg_config, package_desc, when=package)
     @checking('%s_CFLAGS' % var, callback=lambda t: ' '.join(t))
     def pkg_cflags(pkg_config, package_desc):
         flags = check_cmd_output(pkg_config, '--cflags', package_desc)
         return tuple(flags.split())
 
     @depends(pkg_config, package_desc, when=package)
--- a/build/moz.configure/rust.configure
+++ b/build/moz.configure/rust.configure
@@ -36,17 +36,16 @@ def unwrap_rustup(prog, name):
     # with a different error message (e.g. "error: no such subcommand:
     # `+stable`"), and exits with status 101.
     #
     # Unfortunately, in the rustc case, when plain rustc is in use,
     # `rustc +stable` will exit with status 1, complaining about a missing
     # "+stable" file. We'll examine the error output to try and distinguish
     # between failing rustup and failing rustc.
     @depends(prog, dependable(name))
-    @imports('subprocess')
     @imports(_from='__builtin__', _import='open')
     @imports('os')
     def unwrap(prog, name):
         def from_rustup_which():
             out = check_cmd_output('rustup', 'which', name,
                                    executable=prog).rstrip()
             # If for some reason the above failed to return something, keep the
             # PROG we found originally.
@@ -227,17 +226,16 @@ def rust_triple_alias(host_or_target, ho
     assert host_or_target in {host, target}
 
     host_or_target_str = {host: 'host', target: 'target'}[host_or_target]
 
     @depends(rustc, host_or_target, host_or_target_c_compiler,
              rust_supported_targets, arm_target, when=rust_compiler)
     @checking('for rust %s triplet' % host_or_target_str)
     @imports('os')
-    @imports('subprocess')
     @imports(_from='mozbuild.configure.util', _import='LineIO')
     @imports(_from='mozbuild.shellutil', _import='quote')
     @imports(_from='tempfile', _import='mkstemp')
     @imports(_from='textwrap', _import='dedent')
     def rust_target(rustc, host_or_target, compiler_info,
                     rust_supported_targets, arm_target):
         # Rust's --target options are similar to, but not exactly the same
         # as, the autoconf-derived targets we use.  An example would be that
--- a/build/moz.configure/toolchain.configure
+++ b/build/moz.configure/toolchain.configure
@@ -598,32 +598,27 @@ def check_compiler(compiler, language, t
         target_os=info.os,
         flags=flags,
     )
 
 
 @imports(_from='__builtin__', _import='open')
 @imports('json')
 @imports('os')
-@imports('subprocess')
-@imports('sys')
 def get_vc_paths(topsrcdir):
     def vswhere(args):
-        encoding = 'mbcs' if sys.platform == 'win32' else 'utf-8'
         program_files = (os.environ.get('PROGRAMFILES(X86)') or
                          os.environ.get('PROGRAMFILES'))
         if not program_files:
             return []
         vswhere = os.path.join(program_files, 'Microsoft Visual Studio',
                                'Installer', 'vswhere.exe')
         if not os.path.exists(vswhere):
             return []
-        return json.loads(
-            subprocess.check_output([vswhere, '-format', 'json'] + args)
-            .decode(encoding, 'replace'))
+        return json.loads(check_cmd_output(vswhere, '-format', 'json', *args))
 
     for install in vswhere(['-products', '*', '-requires', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64']):
         path = install['installationPath']
         tools_version = open(os.path.join(
             path, r'VC\Auxiliary\Build\Microsoft.VCToolsVersion.default.txt'), 'rb').read().strip()
         tools_path = os.path.join(
             path, r'VC\Tools\MSVC', tools_version)
         yield (Version(install['installationVersion']), tools_path)
@@ -1429,16 +1424,31 @@ set_config('PREPROCESS_OPTION', preproce
 
 @depends(target, host)
 def is_windows(target, host):
     return host.kernel == 'WINNT' and target.kernel == 'WINNT'
 
 
 include('windows.configure', when=is_windows)
 
+
+# On Power ISA, determine compiler flags for VMX, VSX and VSX-3.
+
+set_config('PPC_VMX_FLAGS',
+           ['-maltivec'],
+           when=depends(target.cpu)(lambda cpu: cpu.startswith('ppc')))
+
+set_config('PPC_VSX_FLAGS',
+           ['-mvsx'],
+           when=depends(target.cpu)(lambda cpu: cpu.startswith('ppc')))
+
+set_config('PPC_VSX3_FLAGS',
+           ['-mvsx','-mcpu=power9'],
+           when=depends(target.cpu)(lambda cpu: cpu.startswith('ppc')))
+
 # ASAN
 # ==============================================================
 
 js_option('--enable-address-sanitizer', help='Enable Address Sanitizer')
 
 
 @depends(when='--enable-address-sanitizer')
 def asan():
@@ -1530,18 +1540,19 @@ option('--enable-hardening', env='MOZ_SE
 # is passed, and if no flag is passed.
 #
 # At time of this comment writing, all flags are actually added in the
 # default no-flag case; making --enable-hardening the same as omitting the
 # flag. --disable-hardening will omit the security flags. (However, not all
 # possible security flags will be omitted by --disable-hardening, as many are
 # compiler-default options we do not explicitly enable.)
 @depends('--enable-hardening', '--enable-address-sanitizer',
-         '--enable-optimize', c_compiler, target)
-def security_hardening_cflags(hardening_flag, asan, optimize, c_compiler, target):
+         '--enable-debug', '--enable-optimize', c_compiler, target)
+def security_hardening_cflags(hardening_flag, asan, debug, optimize, c_compiler,
+                              target):
     compiler_is_gccish = c_compiler.type in ('gcc', 'clang')
 
     flags = []
     ldflags = []
     js_flags = []
     js_ldflags = []
 
     # ----------------------------------------------------------
@@ -1556,28 +1567,41 @@ def security_hardening_cflags(hardening_
                 flags.append("-U_FORTIFY_SOURCE")
                 flags.append("-D_FORTIFY_SOURCE=2")
             js_flags.append("-U_FORTIFY_SOURCE")
             js_flags.append("-D_FORTIFY_SOURCE=2")
 
         # fstack-protector ------------------------------------
         # Enable only if hardening is not disabled and ASAN is
         # not on as ASAN will catch the crashes for us
+        # mingw-clang cross-compile toolchain has bugs with stack protector
+        mingw_clang = c_compiler.type == 'clang' and target.os == 'WINNT'
         if compiler_is_gccish and not asan:
-            # mingw-clang cross-compile toolchain has bugs with stack protector
-            if target.os != 'WINNT' or c_compiler == 'gcc':
+            if not mingw_clang:
                 flags.append("-fstack-protector-strong")
                 ldflags.append("-fstack-protector-strong")
                 js_flags.append("-fstack-protector-strong")
                 js_ldflags.append("-fstack-protector-strong")
 
+        # ftrivial-auto-var-init ------------------------------
+        # Initialize local variables with a 0xAA pattern in clang debug builds.
+        # Linux32 fails some xpcshell tests with -ftrivial-auto-var-init
+        linux32 = target.kernel == 'Linux' and target.cpu == 'x86'
+        if (c_compiler.type == 'clang' or c_compiler.type == 'clang-cl') and \
+            c_compiler.version >= '8' and debug and not linux32:
+            if c_compiler.type == 'clang-cl':
+                flags.append('-Xclang')
+                js_flags.append('-Xclang')
+            flags.append('-ftrivial-auto-var-init=pattern')
+            js_flags.append('-ftrivial-auto-var-init=pattern')
+
         # ASLR ------------------------------------------------
         # ASLR (dynamicbase) is enabled by default in clang-cl; but the
         # mingw-clang build requires it to be explicitly enabled
-        if target.os == 'WINNT' and c_compiler.type == 'clang':
+        if mingw_clang:
             ldflags.append("-Wl,--dynamicbase")
             js_ldflags.append("-Wl,--dynamicbase")
 
         # Control Flow Guard (CFG) ----------------------------
         # On aarch64, this is enabled only with explicit --enable-hardening
         # (roughly: automation) due to a dependency on a patched clang-cl.
         if c_compiler.type == 'clang-cl' and c_compiler.version >= '8' and \
            (target.cpu != 'aarch64' or hardening_flag):
--- a/build/moz.configure/util.configure
+++ b/build/moz.configure/util.configure
@@ -21,16 +21,17 @@ def configure_error(message):
 
 
 # A wrapper to obtain a process' output and return code.
 # Returns a tuple (retcode, stdout, stderr).
 @imports('os')
 @imports(_from='__builtin__', _import='unicode')
 @imports('subprocess')
 @imports(_from='mozbuild.shellutil', _import='quote')
+@imports(_from='mozbuild.util', _import='system_encoding')
 def get_cmd_output(*args, **kwargs):
     # subprocess on older Pythons can't handle unicode keys or values in
     # environment dicts. Normalize automagically so callers don't have to
     # deal with this.
     if 'env' in kwargs:
         normalized_env = {}
         for k, v in kwargs['env'].items():
             if isinstance(k, unicode):
@@ -48,16 +49,18 @@ def get_cmd_output(*args, **kwargs):
                             stderr=subprocess.PIPE,
                             # On Python 2 on Windows, close_fds prevents the
                             # process from inheriting stdout/stderr.
                             # Elsewhere, it simply prevents it from inheriting
                             # extra file descriptors, which is what we want.
                             close_fds=os.name != 'nt',
                             **kwargs)
     stdout, stderr = proc.communicate()
+    stdout = stdout.decode(system_encoding, 'replace')
+    stderr = stderr.decode(system_encoding, 'replace')
     return proc.wait(), stdout, stderr
 
 
 # A wrapper to obtain a process' output that returns the output generated
 # by running the given command if it exits normally, and streams that
 # output to log.debug and calls die or the given error callback if it
 # does not.
 @imports(_from='mozbuild.configure.util', _import='LineIO')
@@ -70,17 +73,17 @@ def check_cmd_output(*args, **kwargs):
         if retcode == 0:
             return stdout
 
         log.debug('The command returned non-zero exit status %d.',
                   retcode)
         for out, desc in ((stdout, 'output'), (stderr, 'error output')):
             if out:
                 log.debug('Its %s was:', desc)
-                with LineIO(lambda l: log.debug('| %s', l), 'replace') as o:
+                with LineIO(lambda l: log.debug('| %s', l)) as o:
                     o.write(out)
         if onerror:
             return onerror()
         die('Command `%s` failed with exit status %d.' %
             (quote(*args), retcode))
 
 
 @imports('os')
@@ -211,17 +214,16 @@ def find_program(file, paths=None):
         else:
             paths = environ['PATH'].split(pathsep)
         return normalize_path(which(file, path=paths, exts=exts))
     except WhichError:
         return None
 
 
 @imports('os')
-@imports('subprocess')
 @imports(_from='mozbuild.configure.util', _import='LineIO')
 @imports(_from='tempfile', _import='mkstemp')
 def try_invoke_compiler(compiler, language, source, flags=None, onerror=None):
     flags = flags or []
 
     if not isinstance(flags, (list, tuple)):
         die("Flags provided to try_compile must be a list of strings, "
             "not %r", flags)
--- a/build/moz.configure/windows.configure
+++ b/build/moz.configure/windows.configure
@@ -452,26 +452,22 @@ def sdk_bin_path(valid_windows_sdk_dir, 
 mt = check_prog('MT', ('mt.exe',), input='MT',
                 paths=sdk_bin_path)
 
 
 # Check that MT is not something unexpected like "magnetic tape manipulation
 # utility".
 @depends(mt)
 @checking('whether MT is really Microsoft Manifest Tool', lambda x: bool(x))
-@imports('subprocess')
 def valid_mt(path):
-    try:
-        out = subprocess.check_output([path]).splitlines()
-        out = '\n'.join(l for l in out
-                        if 'Microsoft (R) Manifest Tool' in l)
-        if out:
-            return path
-    except subprocess.CalledProcessError:
-        pass
+    out = check_cmd_output(path, onerror=lambda: '').splitlines()
+    out = '\n'.join(l for l in out
+                    if 'Microsoft (R) Manifest Tool' in l)
+    if out:
+        return path
     raise FatalCheckError('%s is not Microsoft Manifest Tool')
 
 
 set_config('MSMANIFEST_TOOL', depends(valid_mt)(lambda x: bool(x)))
 
 js_option(env='LINKER', nargs=1, help='Path to the linker')
 
 link = check_prog('LINKER', ('lld-link',), input='LINKER',
--- a/config/baseconfig.mk
+++ b/config/baseconfig.mk
@@ -38,29 +38,33 @@ ifeq (a,$(firstword a$(subst /, ,$(srcdi
 endif
 endif
 endif # WINNT
 
 ifndef INCLUDED_AUTOCONF_MK
 default::
 else
 # All possible tiers
-ALL_TIERS := artifact win32-artifact android-fat-aar-artifact pre-export export rust compile misc libs tools check
+ALL_TIERS := artifact win32-artifact android-fat-aar-artifact pre-export export rust compile misc libs android-stage-package android-archive-geckoview tools check
 
 # All tiers that may be used manually via `mach build $tier`
 RUNNABLE_TIERS := $(ALL_TIERS)
 ifndef MOZ_ARTIFACT_BUILDS
 RUNNABLE_TIERS := $(filter-out artifact,$(RUNNABLE_TIERS))
 endif
 ifndef MOZ_EME_WIN32_ARTIFACT
 RUNNABLE_TIERS := $(filter-out win32-artifact,$(RUNNABLE_TIERS))
 endif
 ifndef MOZ_ANDROID_FAT_AAR_ARCHITECTURES
 RUNNABLE_TIERS := $(filter-out android-fat-aar-artifact,$(RUNNABLE_TIERS))
 endif
+ifneq ($(MOZ_BUILD_APP),mobile/android)
+RUNNABLE_TIERS := $(filter-out android-stage-package,$(RUNNABLE_TIERS))
+RUNNABLE_TIERS := $(filter-out android-archive-geckoview,$(RUNNABLE_TIERS))
+endif
 
 # All tiers that run automatically on `mach build`
 TIERS := $(filter-out check,$(RUNNABLE_TIERS))
 ifndef COMPILE_ENVIRONMENT
 TIERS := $(filter-out rust compile,$(TIERS))
 endif
 ifndef MOZ_RUST_TIER
 TIERS := $(filter-out rust,$(TIERS))
--- a/config/mozunit/mozunit/mozunit.py
+++ b/config/mozunit/mozunit/mozunit.py
@@ -165,17 +165,18 @@ class MockedOpen(object):
     self.assertRaises(Exception,f.open('foo', 'r'))
     '''
 
     def __init__(self, files={}):
         self.files = {}
         for name, content in files.items():
             self.files[normcase(os.path.abspath(name))] = content
 
-    def __call__(self, name, mode='r'):
+    def __call__(self, name, mode='r', buffering=None):
+        # buffering is ignored.
         absname = normcase(os.path.abspath(name))
         if 'w' in mode:
             file = MockedFile(self, absname)
         elif absname in self.files:
             content = self.files[absname]
             if content is None:
                 raise IOError(2, 'No such file or directory')
             file = MockedFile(self, absname, content)
--- a/configure.py
+++ b/configure.py
@@ -5,32 +5,35 @@
 from __future__ import absolute_import, print_function, unicode_literals
 
 import codecs
 import itertools
 import logging
 import os
 import sys
 import textwrap
+from collections import Iterable
 
 
 base_dir = os.path.abspath(os.path.dirname(__file__))
 sys.path.insert(0, os.path.join(base_dir, 'python', 'mozbuild'))
 sys.path.insert(0, os.path.join(base_dir, 'third_party', 'python', 'six'))
 from mozbuild.configure import (
     ConfigureSandbox,
     TRACE,
 )
 from mozbuild.pythonutil import iter_modules_in_path
 from mozbuild.backend.configenvironment import PartialConfigEnvironment
 from mozbuild.util import (
     indented_repr,
     encode,
+    system_encoding,
 )
 import mozpack.path as mozpath
+import six
 
 
 def main(argv):
     config = {}
 
     sandbox = ConfigureSandbox(config, os.environ, argv)
 
     if os.environ.get('MOZ_CONFIGURE_TRACE'):
@@ -39,16 +42,37 @@ def main(argv):
     sandbox.run(os.path.join(os.path.dirname(__file__), 'moz.configure'))
 
     if sandbox._help:
         return 0
 
     return config_status(config)
 
 
+def check_unicode(obj):
+    '''Recursively check that all strings in the object are unicode strings.'''
+    if isinstance(obj, dict):
+        result = True
+        for k, v in six.iteritems(obj):
+            if not check_unicode(k):
+                print("%s key is not unicode." % k, file=sys.stderr)
+                result = False
+            elif not check_unicode(v):
+                print("%s value is not unicode." % k, file=sys.stderr)
+                result = False
+        return result
+    if isinstance(obj, bytes):
+        return False
+    if isinstance(obj, six.text_type):
+        return True
+    if isinstance(obj, Iterable):
+        return all(check_unicode(o) for o in obj)
+    return True
+
+
 def config_status(config):
     # Sanitize config data to feed config.status
     # Ideally, all the backend and frontend code would handle the booleans, but
     # there are so many things involved, that it's easier to keep config.status
     # untouched for now.
     def sanitized_bools(v):
         if v is True:
             return '1'
@@ -65,29 +89,33 @@ def config_status(config):
     sanitized_config['defines'] = {
         k: sanitized_bools(v) for k, v in config['DEFINES'].iteritems()
     }
     sanitized_config['non_global_defines'] = config['non_global_defines']
     sanitized_config['topsrcdir'] = config['TOPSRCDIR']
     sanitized_config['topobjdir'] = config['TOPOBJDIR']
     sanitized_config['mozconfig'] = config.get('MOZCONFIG')
 
+    if not check_unicode(sanitized_config):
+        print("Configuration should be all unicode.", file=sys.stderr)
+        print("Please file a bug for the above.", file=sys.stderr)
+        sys.exit(1)
+
     # Create config.status. Eventually, we'll want to just do the work it does
     # here, when we're able to skip configure tests/use cached results/not rely
     # on autoconf.
     logging.getLogger('moz.configure').info('Creating config.status')
-    encoding = 'mbcs' if sys.platform == 'win32' else 'utf-8'
-    with codecs.open('config.status', 'w', encoding) as fh:
+    with codecs.open('config.status', 'w', system_encoding) as fh:
         fh.write(textwrap.dedent('''\
             #!%(python)s
             # coding=%(encoding)s
             from __future__ import unicode_literals
             from mozbuild.util import encode
             encoding = '%(encoding)s'
-        ''') % {'python': config['PYTHON'], 'encoding': encoding})
+        ''') % {'python': config['PYTHON'], 'encoding': system_encoding})
         # A lot of the build backend code is currently expecting byte
         # strings and breaks in subtle ways with unicode strings. (bug 1296508)
         for k, v in sanitized_config.iteritems():
             fh.write('%s = encode(%s, encoding)\n' % (k, indented_repr(v)))
         fh.write("__all__ = ['topobjdir', 'topsrcdir', 'defines', "
                  "'non_global_defines', 'substs', 'mozconfig']")
 
         if config.get('MOZ_BUILD_APP') != 'js' or config.get('JS_STANDALONE'):
@@ -120,14 +148,14 @@ def config_status(config):
         # Some values in sanitized_config also have more complex types, such as
         # EnumString, which using when calling config_status would currently
         # break the build, as well as making it inconsistent with re-running
         # config.status. Fortunately, EnumString derives from unicode, so it's
         # covered by converting unicode strings.
 
         # A lot of the build backend code is currently expecting byte strings
         # and breaks in subtle ways with unicode strings.
-        return config_status(args=[], **encode(sanitized_config, encoding))
+        return config_status(args=[], **encode(sanitized_config, system_encoding))
     return 0
 
 
 if __name__ == '__main__':
     sys.exit(main(sys.argv))
old mode 100755
new mode 100644
--- a/devtools/client/netmonitor/src/assets/styles/websockets.css
+++ b/devtools/client/netmonitor/src/assets/styles/websockets.css
@@ -140,8 +140,12 @@
   background-repeat: no-repeat;
   -moz-context-properties: fill;
   fill: inherit;
 }
 
 #messages-panel .truncation-checkbox {
   margin-right: 5px;
 }
+
+#messages-panel .truncated-message {
+  font-variant-numeric: tabular-nums;
+}
--- a/devtools/client/netmonitor/src/components/websockets/FrameListContent.js
+++ b/devtools/client/netmonitor/src/components/websockets/FrameListContent.js
@@ -43,58 +43,88 @@ class FrameListContent extends Component
   static get propTypes() {
     return {
       connector: PropTypes.object.isRequired,
       startPanelContainer: PropTypes.object,
       frames: PropTypes.array,
       selectedFrame: PropTypes.object,
       selectFrame: PropTypes.func.isRequired,
       columns: PropTypes.object.isRequired,
+      channelId: PropTypes.number,
     };
   }
 
   constructor(props) {
     super(props);
 
     this.framesLimit = Services.prefs.getIntPref(
       "devtools.netmonitor.ws.displayed-frames.limit"
     );
     this.currentTruncatedNum = 0;
     this.state = {
       checked: false,
     };
     this.pinnedToBottom = false;
     this.initIntersectionObserver = false;
+    this.intersectionObserver = null;
   }
 
-  componentDidUpdate() {
+  componentDidMount() {
     const { startPanelContainer } = this.props;
     const scrollAnchor = this.refs.scrollAnchor;
 
+    if (scrollAnchor) {
+      // Always scroll to anchor when FrameListContent component first mounts.
+      scrollAnchor.scrollIntoView();
+    }
+    this.setupScrollToBottom(startPanelContainer, scrollAnchor);
+  }
+
+  componentDidUpdate(prevProps) {
+    const { startPanelContainer, channelId } = this.props;
+    const scrollAnchor = this.refs.scrollAnchor;
+
     // When frames are cleared, the previous scrollAnchor would be destroyed, so we need to reset this boolean.
     if (!scrollAnchor) {
       this.initIntersectionObserver = false;
     }
 
+    // If a new WebSocket connection is selected, scroll to anchor.
+    if (channelId !== prevProps.channelId && scrollAnchor) {
+      scrollAnchor.scrollIntoView();
+    }
+
+    this.setupScrollToBottom(startPanelContainer, scrollAnchor);
+  }
+
+  componentWillUnmount() {
+    // Reset observables and boolean values.
+    const scrollAnchor = this.refs.scrollAnchor;
+    this.intersectionObserver.unobserve(scrollAnchor);
+    this.initIntersectionObserver = false;
+    this.pinnedToBottom = false;
+  }
+
+  setupScrollToBottom(startPanelContainer, scrollAnchor) {
     if (startPanelContainer && scrollAnchor) {
       // Initialize intersection observer.
       if (!this.initIntersectionObserver) {
-        const observer = new IntersectionObserver(
+        this.intersectionObserver = new IntersectionObserver(
           () => {
             // When scrollAnchor first comes into view, this.pinnedToBottom is set to true.
             // When the anchor goes out of view, this callback function triggers again and toggles this.pinnedToBottom.
             // Subsequent scroll into/out of view will toggle this.pinnedToBottom.
             this.pinnedToBottom = !this.pinnedToBottom;
           },
           {
             root: startPanelContainer,
             threshold: 0.1,
           }
         );
-        observer.observe(scrollAnchor);
+        this.intersectionObserver.observe(scrollAnchor);
         this.initIntersectionObserver = true;
       }
 
       if (this.pinnedToBottom) {
         scrollAnchor.scrollIntoView();
       }
     }
   }
--- a/devtools/client/netmonitor/src/components/websockets/WebSocketsPanel.js
+++ b/devtools/client/netmonitor/src/components/websockets/WebSocketsPanel.js
@@ -102,17 +102,22 @@ class WebSocketsPanel extends Component 
   // Reset the filter text
   clearFilterText() {
     if (this.searchboxRef) {
       this.searchboxRef.current.onClearButtonClick();
     }
   }
 
   render() {
-    const { frameDetailsOpen, connector, selectedFrame } = this.props;
+    const {
+      frameDetailsOpen,
+      connector,
+      selectedFrame,
+      channelId,
+    } = this.props;
 
     const searchboxRef = this.searchboxRef;
     const startPanelContainer = this.state.startPanelContainer;
 
     const initialHeight = Services.prefs.getIntPref(
       "devtools.netmonitor.ws.payload-preview-height"
     );
 
@@ -126,16 +131,17 @@ class WebSocketsPanel extends Component 
         initialHeight: initialHeight,
         minSize: "50px",
         maxSize: "80%",
         splitterSize: frameDetailsOpen ? 1 : 0,
         onSelectContainerElement: this.handleContainerElement,
         startPanel: FrameListContent({
           connector,
           startPanelContainer,
+          channelId,
         }),
         endPanel:
           frameDetailsOpen &&
           FramePayload({
             ref: "endPanel",
             connector,
             selectedFrame,
           }),
--- a/devtools/client/netmonitor/src/workers/search/search.js
+++ b/devtools/client/netmonitor/src/workers/search/search.js
@@ -13,98 +13,106 @@ function searchInResource(resource, quer
   const results = [];
 
   if (resource.url) {
     results.push(
       findMatches(resource, query, {
         key: "url",
         label: "Url",
         type: "url",
+        panel: "headers",
       })
     );
   }
 
   if (resource.responseHeaders) {
     results.push(
       findMatches(resource, query, {
         key: "responseHeaders.headers",
         label: "Response Headers",
         type: "responseHeaders",
+        panel: "headers",
       })
     );
   }
 
   if (resource.requestHeaders) {
     results.push(
       findMatches(resource, query, {
         key: "requestHeaders.headers",
         label: "Request Headers",
         type: "requestHeaders",
+        panel: "headers",
       })
     );
   }
 
   if (resource.responseCookies) {
     let key = "responseCookies";
 
     if (resource.responseCookies.cookies) {
       key = "responseCookies.cookies";
     }
 
     results.push(
       findMatches(resource, query, {
         key,
         label: "Response Cookies",
         type: "responseCookies",
+        panel: "cookies",
       })
     );
   }
 
   if (resource.requestCookies) {
     let key = "requestCookies";
 
     if (resource.requestCookies.cookies) {
       key = "requestCookies.cookies";
     }
 
     results.push(
       findMatches(resource, query, {
         key,
         label: "Request Cookies",
         type: "requestCookies",
+        panel: "cookies",
       })
     );
   }
 
   if (resource.securityInfo) {
     results.push(
       findMatches(resource, query, {
         key: "securityInfo",
         label: "Security Information",
         type: "securityInfo",
+        panel: "security",
       })
     );
   }
 
   if (resource.responseContent) {
     results.push(
       findMatches(resource, query, {
         key: "responseContent.content.text",
         label: "Response Content",
         type: "responseContent",
+        panel: "response",
       })
     );
   }
 
   if (resource.requestPostData) {
     results.push(
       findMatches(resource, query, {
         key: "requestPostData.postData.text",
         label: "Request Post Data",
         type: "requestPostData",
+        panel: "headers",
       })
     );
   }
 
   return getResults(results);
 }
 
 /**
@@ -241,24 +249,24 @@ function searchInText(query, text, data)
  * Search for query in array.
  * Iterates through each array item and handles item based on type.
  * @param query
  * @param arr
  * @param data
  * @returns {*}
  */
 function searchInArray(query, arr, data) {
-  const { type, key, label } = data;
+  const { key, label } = data;
   const matches = arr
     .filter(match => JSON.stringify(match).includes(query))
     .map((match, i) =>
       findMatches(match, query, {
+        ...data,
         label: match.hasOwnProperty("name") ? match.name : label,
         key: key + ".[" + i + "]",
-        type,
       })
     );
 
   return getResults(matches);
 }
 
 /**
  * Return query match and up to 50 characters on left and right.
@@ -286,17 +294,16 @@ function getTruncatedValue(value, query,
  * Iterates through object, including nested objects, returns all
  * found matches.
  * @param query
  * @param obj
  * @param data
  * @returns {*}
  */
 function searchInObject(query, obj, data) {
-  const { type } = data;
   const matches = data.hasOwnProperty("collector") ? data.collector : [];
 
   for (const objectKey in obj) {
     const objectKeyType = getType(obj[objectKey]);
 
     // if the value is an object, send to search in object
     if (objectKeyType === "object" && Object.keys(obj[objectKey].length > 1)) {
       searchInObject(query, obj[objectKey], {
@@ -304,17 +311,16 @@ function searchInObject(query, obj, data
         collector: matches,
       });
     } else if (
       (objectKeyType === "string" && obj[objectKey].includes(query)) ||
       objectKey.includes(query)
     ) {
       const match = {
         ...data,
-        type,
       };
 
       const value = obj[objectKey];
       const startIndex = value.indexOf(query);
 
       match.label = objectKey;
       match.startIndex = startIndex;
       match.value = getTruncatedValue(value, query, startIndex);
--- a/devtools/client/webconsole/test/node/mocha-test-setup.js
+++ b/devtools/client/webconsole/test/node/mocha-test-setup.js
@@ -80,83 +80,69 @@ if (!global.ResizeObserver) {
 // Mock ChromeUtils.
 global.ChromeUtils = {
   import: () => {},
   defineModuleGetter: () => {},
 };
 
 // Point to vendored-in files and mocks when needed.
 const requireHacker = require("require-hacker");
-/* eslint-disable complexity */
 requireHacker.global_hook("default", (path, module) => {
-  switch (path) {
+  const paths = {
     // For Enzyme
-    case "react-dom":
-      return getModule("devtools/client/shared/vendor/react-dom");
-    case "react-dom/server":
-      return getModule("devtools/client/shared/vendor/react-dom-server");
-    case "react-dom/test-utils":
-      return getModule(
-        "devtools/client/shared/vendor/react-dom-test-utils-dev"
-      );
-    case "react-redux":
-      return getModule("devtools/client/shared/vendor/react-redux");
+    "react-dom": () => getModule("devtools/client/shared/vendor/react-dom"),
+    "react-dom/server": () =>
+      getModule("devtools/client/shared/vendor/react-dom-server"),
+    "react-dom/test-utils": () =>
+      getModule("devtools/client/shared/vendor/react-dom-test-utils-dev"),
+    "react-redux": () => getModule("devtools/client/shared/vendor/react-redux"),
     // Use react-dev. This would be handled by browserLoader in Firefox.
-    case "react":
-    case "devtools/client/shared/vendor/react":
-      return getModule("devtools/client/shared/vendor/react-dev");
-    case "chrome":
-      return `module.exports = { Cc: {}, Ci: {}, Cu: {} }`;
-  }
-
-  // Some modules depend on Chrome APIs which don't work in mocha. When such a module
-  // is required, replace it with a mock version.
-  switch (path) {
-    case "devtools/shared/l10n":
-      return getModule(
+    react: () => getModule("devtools/client/shared/vendor/react-dev"),
+    "devtools/client/shared/vendor/react": () =>
+      getModule("devtools/client/shared/vendor/react-dev"),
+    chrome: () => `module.exports = { Cc: {}, Ci: {}, Cu: {} }`,
+    // Some modules depend on Chrome APIs which don't work in mocha. When such a module
+    // is required, replace it with a mock version.
+    "devtools/shared/l10n": () =>
+      getModule(
         "devtools/client/webconsole/test/node/fixtures/LocalizationHelper"
-      );
-    case "devtools/shared/plural-form":
-      return getModule(
-        "devtools/client/webconsole/test/node/fixtures/PluralForm"
-      );
-    case "Services":
-    case "Services.default":
-      return `module.exports = require("devtools-modules/src/Services")`;
-    case "devtools/shared/client/object-client":
-    case "devtools/shared/client/long-string-client":
-      return `() => {}`;
-    case "devtools/client/shared/components/SmartTrace":
-    case "devtools/client/netmonitor/src/components/TabboxPanel":
-    case "devtools/client/webconsole/utils/context-menu":
-      return "{}";
-    case "devtools/client/shared/telemetry":
-      return `module.exports = function() {
-        this.recordEvent = () => {};
-        this.getKeyedHistogramById = () => ({add: () => {}});
-      }`;
-    case "devtools/shared/event-emitter":
-      return `module.exports = require("devtools-modules/src/utils/event-emitter")`;
-    case "devtools/client/shared/unicode-url":
-      return `module.exports = require("devtools-modules/src/unicode-url")`;
-    case "devtools/shared/DevToolsUtils":
-      return "{}";
-    case "devtools/server/actors/reflow":
-      return "{}";
-    case "devtools/shared/layout/utils":
-      return "{getCurrentZoom = () => {}}";
+      ),
+    "devtools/shared/plural-form": () =>
+      getModule("devtools/client/webconsole/test/node/fixtures/PluralForm"),
+    Services: () => `module.exports = require("devtools-modules/src/Services")`,
+    "Services.default": () =>
+      `module.exports = require("devtools-modules/src/Services")`,
+    "devtools/shared/client/object-client": () => `() => {}`,
+    "devtools/shared/client/long-string-client": () => `() => {}`,
+    "devtools/client/shared/components/SmartTrace": () => "{}",
+    "devtools/client/netmonitor/src/components/TabboxPanel": () => "{}",
+    "devtools/client/webconsole/utils/context-menu": () => "{}",
+    "devtools/client/shared/telemetry": () => `module.exports = function() {
+      this.recordEvent = () => {};
+      this.getKeyedHistogramById = () => ({add: () => {}});
+    }`,
+    "devtools/shared/event-emitter": () =>
+      `module.exports = require("devtools-modules/src/utils/event-emitter")`,
+    "devtools/client/shared/unicode-url": () =>
+      `module.exports = require("devtools-modules/src/unicode-url")`,
+    "devtools/shared/DevToolsUtils": () => "{}",
+    "devtools/server/actors/reflow": () => "{}",
+    "devtools/shared/layout/utils": () => "{getCurrentZoom = () => {}}",
+  };
+
+  if (paths.hasOwnProperty(path)) {
+    return paths[path]();
   }
 
   // We need to rewrite all the modules assuming the root is mozilla-central and give them
   // an absolute path.
   if (path.startsWith("devtools/")) {
     return getModule(path);
   }
 
   return undefined;
 });
-/* eslint-enable complexity */
 
 // Configure enzyme with React 16 adapter. This needs to be done after we set the
 // requireHack hook so `require()` calls in Enzyme are handled as well.
 const Enzyme = require("enzyme");
 const Adapter = require("enzyme-adapter-react-16");
 Enzyme.configure({ adapter: new Adapter() });
--- a/devtools/server/actors/inspector/node.js
+++ b/devtools/server/actors/inspector/node.js
@@ -140,21 +140,16 @@ loader.lazyRequireGetter(
   "devtools/server/actors/inspector/utils",
   true
 );
 
 const SUBGRID_ENABLED = Services.prefs.getBoolPref(
   "layout.css.grid-template-subgrid-value.enabled"
 );
 
-const BROWSER_TOOLBOX_FISSION_ENABLED = Services.prefs.getBoolPref(
-  "devtools.browsertoolbox.fission",
-  false
-);
-
 const FONT_FAMILY_PREVIEW_TEXT = "The quick brown fox jumps over the lazy dog";
 const FONT_FAMILY_PREVIEW_TEXT_SIZE = 20;
 
 /**
  * Server side of the node actor.
  */
 const NodeActor = protocol.ActorClassWithSpec(nodeSpec, {
   initialize: function(walker, node) {
@@ -312,18 +307,17 @@ const NodeActor = protocol.ActorClassWit
   /**
    * Check if the current node is representing a remote frame.
    * EXPERIMENTAL: Only works if fission is enabled in the toolbox.
    */
   get isRemoteFrame() {
     return (
       this.numChildren == 0 &&
       ChromeUtils.getClassName(this.rawNode) == "XULFrameElement" &&
-      this.rawNode.getAttribute("remote") == "true" &&
-      BROWSER_TOOLBOX_FISSION_ENABLED
+      this.rawNode.getAttribute("remote") == "true"
     );
   },
 
   // Estimate the number of children that the walker will return without making
   // a call to children() if possible.
   get numChildren() {
     // For pseudo elements, childNodes.length returns 1, but the walker
     // will return 0.
--- a/devtools/server/actors/targets/worker.js
+++ b/devtools/server/actors/targets/worker.js
@@ -37,16 +37,19 @@ const WorkerTargetActor = protocol.Actor
 
   form() {
     const form = {
       actor: this.actorID,
       consoleActor: this._consoleActor,
       threadActor: this._threadActor,
       id: this._dbg.id,
       url: this._dbg.url,
+      traits: {
+        isParentInterceptEnabled: swm.isParentInterceptEnabled(),
+      },
       type: this._dbg.type,
     };
     if (this._dbg.type === Ci.nsIWorkerDebugger.TYPE_SERVICE) {
       /**
        * With parent-intercept mode, the ServiceWorkerManager in content
        * processes don't maintain ServiceWorkerRegistrations; record the
        * ServiceWorker's ID, and this data will be merged with the
        * corresponding registration in the parent process.
@@ -65,23 +68,20 @@ const WorkerTargetActor = protocol.Actor
   },
 
   attach() {
     if (this._dbg.isClosed) {
       return { error: "closed" };
     }
 
     if (!this._attached) {
-      // Automatically disable their internal timeout that shut them down
-      // Should be refactored by having actors specific to service workers
-      if (this._dbg.type == Ci.nsIWorkerDebugger.TYPE_SERVICE) {
-        const worker = this._getServiceWorkerInfo();
-        if (worker) {
-          worker.attachDebugger();
-        }
+      const isServiceWorker =
+        this._dbg.type == Ci.nsIWorkerDebugger.TYPE_SERVICE;
+      if (isServiceWorker) {
+        this._preventServiceWorkerShutdown();
       }
       this._dbg.addListener(this);
       this._attached = true;
     }
 
     return {
       type: "attached",
       url: this._dbg.url,
@@ -184,21 +184,52 @@ const WorkerTargetActor = protocol.Actor
     // (_dbg.closed appears to be false when it throws)
     let type;
     try {
       type = this._dbg.type;
     } catch (e) {
       // nothing
     }
 
-    if (type == Ci.nsIWorkerDebugger.TYPE_SERVICE) {
-      const worker = this._getServiceWorkerInfo();
-      if (worker) {
-        worker.detachDebugger();
-      }
+    const isServiceWorker = type == Ci.nsIWorkerDebugger.TYPE_SERVICE;
+    if (isServiceWorker) {
+      this._allowServiceWorkerShutdown();
     }
 
     this._dbg.removeListener(this);
     this._attached = false;
   },
+
+  /**
+   * Automatically disable the internal sw timeout that shut them down by calling
+   * nsIWorkerInfo.attachDebugger().
+   * This can be removed when Bug 1496997 lands.
+   */
+  _preventServiceWorkerShutdown() {
+    if (swm.isParentInterceptEnabled()) {
+      // In parentIntercept mode, the worker target actor cannot call attachDebugger
+      // because this API can only be called from the parent process. This will be
+      // done by the worker target front.
+      return;
+    }
+
+    const worker = this._getServiceWorkerInfo();
+    if (worker) {
+      worker.attachDebugger();
+    }
+  },
+
+  /**
+   * Allow the service worker to time out. See _preventServiceWorkerShutdown.
+   */
+  _allowServiceWorkerShutdown() {
+    if (swm.isParentInterceptEnabled()) {
+      return;
+    }
+
+    const worker = this._getServiceWorkerInfo();
+    if (worker) {
+      worker.detachDebugger();
+    }
+  },
 });
 
 exports.WorkerTargetActor = WorkerTargetActor;
--- a/devtools/server/actors/worker/service-worker-registration.js
+++ b/devtools/server/actors/worker/service-worker-registration.js
@@ -199,16 +199,61 @@ const ServiceWorkerRegistrationActor = p
 
       const { principal, scope } = this._registration;
       const originAttributes = ChromeUtils.originAttributesToSuffix(
         principal.originAttributes
       );
       swm.sendPushEvent(originAttributes, scope);
     },
 
+    /**
+     * Prevent the current active worker to shutdown after the idle timeout.
+     */
+    preventShutdown() {
+      if (!swm.isParentInterceptEnabled()) {
+        // In non parent-intercept mode, this is handled by the WorkerTargetFront attach().
+        throw new Error(
+          "ServiceWorkerRegistrationActor.preventShutdown can only be used " +
+            "in parent-intercept mode"
+        );
+      }
+
+      if (!this._registration.activeWorker) {
+        throw new Error(
+          "ServiceWorkerRegistrationActor.preventShutdown could not find " +
+            "activeWorker in parent-intercept mode"
+        );
+      }
+
+      // attachDebugger has to be called from the parent process in parent-intercept mode.
+      this._registration.activeWorker.attachDebugger();
+    },
+
+    /**
+     * Allow the current active worker to shut down again.
+     */
+    allowShutdown() {
+      if (!swm.isParentInterceptEnabled()) {
+        // In non parent-intercept mode, this is handled by the WorkerTargetFront detach().
+        throw new Error(
+          "ServiceWorkerRegistrationActor.allowShutdown can only be used " +
+            "in parent-intercept mode"
+        );
+      }
+
+      if (!this._registration.activeWorker) {
+        throw new Error(
+          "ServiceWorkerRegistrationActor.allowShutdown could not find " +
+            "activeWorker in parent-intercept mode"
+        );
+      }
+
+      this._registration.activeWorker.detachDebugger();
+    },
+
     getPushSubscription() {
       const registration = this._registration;
       let pushSubscriptionActor = this._pushSubscriptionActor;
       if (pushSubscriptionActor) {
         return Promise.resolve(pushSubscriptionActor);
       }
       return new Promise((resolve, reject) => {
         PushService.getSubscription(
--- a/devtools/shared/fronts/node.js
+++ b/devtools/shared/fronts/node.js
@@ -7,30 +7,36 @@
 const promise = require("promise");
 const {
   FrontClassWithSpec,
   types,
   registerFront,
 } = require("devtools/shared/protocol.js");
 const { nodeSpec, nodeListSpec } = require("devtools/shared/specs/node");
 const { SimpleStringFront } = require("devtools/shared/fronts/string");
+const Services = require("Services");
 
 loader.lazyRequireGetter(
   this,
   "nodeConstants",
   "devtools/shared/dom-node-constants"
 );
 
 loader.lazyRequireGetter(
   this,
   "BrowsingContextTargetFront",
   "devtools/shared/fronts/targets/browsing-context",
   true
 );
 
+const BROWSER_TOOLBOX_FISSION_ENABLED = Services.prefs.getBoolPref(
+  "devtools.browsertoolbox.fission",
+  false
+);
+
 const HIDDEN_CLASS = "__fx-devtools-hide-shortcut__";
 
 /**
  * Client side of a node list as returned by querySelectorAll()
  */
 class NodeListFront extends FrontClassWithSpec(nodeListSpec) {
   marshallPool() {
     return this.parent();
@@ -275,17 +281,17 @@ class NodeFront extends FrontClassWithSp
 
   get hasChildren() {
     return this._form.numChildren > 0;
   }
   get numChildren() {
     return this._form.numChildren;
   }
   get remoteFrame() {
-    return this._form.remoteFrame;
+    return BROWSER_TOOLBOX_FISSION_ENABLED && this._form.remoteFrame;
   }
   get hasEventListeners() {
     return this._form.hasEventListeners;
   }
 
   get isMarkerPseudoElement() {
     return this._form.isMarkerPseudoElement;
   }
@@ -507,16 +513,20 @@ class NodeFront extends FrontClassWithSp
       // Can happen if we try to get the raw node for an already-expired
       // actor.
       return null;
     }
     return actor.rawNode;
   }
 
   async connectToRemoteFrame() {
+    if (!this.remoteFrame) {
+      console.warn("Tried to open remote connection to an invalid frame.");
+      return null;
+    }
     if (this._remoteFrameTarget) {
       return this._remoteFrameTarget;
     }
     // First get the target actor form of this remote frame element
     const form = await super.connectToRemoteFrame();
     // Build the related Target object
     this._remoteFrameTarget = new BrowsingContextTargetFront(this.conn);
     this._remoteFrameTarget.actorID = form.actor;
--- a/devtools/shared/fronts/targets/worker.js
+++ b/devtools/shared/fronts/targets/worker.js
@@ -1,13 +1,14 @@
 /* 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";
 
+const { Ci } = require("chrome");
 const { workerTargetSpec } = require("devtools/shared/specs/targets/worker");
 const {
   FrontClassWithSpec,
   registerFront,
 } = require("devtools/shared/protocol");
 const { TargetMixin } = require("./target-mixin");
 
 class WorkerTargetFront extends TargetMixin(
@@ -44,32 +45,71 @@ class WorkerTargetFront extends TargetMi
 
   async attach() {
     if (this._attach) {
       return this._attach;
     }
     this._attach = (async () => {
       const response = await super.attach();
 
+      const isServiceWorker = this.type === Ci.nsIWorkerDebugger.TYPE_SERVICE;
+      if (isServiceWorker && this.getTrait("isParentInterceptEnabled")) {
+        // In parentIntercept mode, the worker target actor cannot call the APIs needed
+        // to prevent the worker from shutting down. Instead call attachDebugger on the
+        // registration because the ServiceWorkerRegistration actor lives in the parent
+        // process.
+        // TODO: Cleanup after Bug 1496997 lands (no need to check
+        // isParentInterceptEnabled trait)
+        this.registration = await this._getRegistration();
+        await this.registration.preventShutdown();
+      }
+
       this._url = response.url;
 
       // Immediately call `connect` in other to fetch console and thread actors
       // that will be later used by Target.
       const connectResponse = await this.connect({});
       // Set the console actor ID on the form to expose it to Target.attachConsole
       // Set the ThreadActor on the target form so it is accessible by getFront
       this.targetForm.consoleActor = connectResponse.consoleActor;
       this.targetForm.threadActor = connectResponse.threadActor;
       this._threadActor = connectResponse.threadActor;
 
       return this.attachConsole();
     })();
     return this._attach;
   }
 
+  async detach() {
+    let response;
+    try {
+      response = await super.detach();
+    } catch (e) {
+      console.warn(
+        `Error while detaching the worker target front: ${e.message}`
+      );
+    }
+
+    if (this.registration) {
+      await this.registration.allowShutdown();
+      this.registration = null;
+    }
+
+    return response;
+  }
+
+  async _getRegistration() {
+    const {
+      registrations,
+    } = await this.client.mainRoot.listServiceWorkerRegistrations();
+    return registrations.find(registrationFront => {
+      return this.id === registrationFront.activeWorker.id;
+    });
+  }
+
   reconfigure() {
     // Toolbox and options panel are calling this method but Worker Target can't be
     // reconfigured. So we ignore this call here.
     return Promise.resolve();
   }
 }
 
 exports.WorkerTargetFront = WorkerTargetFront;
--- a/devtools/shared/specs/worker/service-worker-registration.js
+++ b/devtools/shared/specs/worker/service-worker-registration.js
@@ -13,16 +13,22 @@ const serviceWorkerRegistrationSpec = ge
       type: "push-subscription-modified",
     },
     "registration-changed": {
       type: "registration-changed",
     },
   },
 
   methods: {
+    allowShutdown: {
+      request: {},
+    },
+    preventShutdown: {
+      request: {},
+    },
     push: {
       request: {},
     },
     start: {
       request: {},
     },
     unregister: {
       request: {},
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
--- a/dom/base/nsPlainTextSerializer.cpp
+++ b/dom/base/nsPlainTextSerializer.cpp
@@ -77,45 +77,40 @@ NS_IMPL_CYCLE_COLLECTION(nsPlainTextSeri
 
 nsresult NS_NewPlainTextSerializer(nsIContentSerializer** aSerializer) {
   RefPtr<nsPlainTextSerializer> it = new nsPlainTextSerializer();
   it.forget(aSerializer);
   return NS_OK;
 }
 
 nsPlainTextSerializer::nsPlainTextSerializer()
-    : mFlags(0),
-      mFloatingLines(-1),
+    : mFloatingLines(-1),
       mLineBreakDue(false),
       kSpace(NS_LITERAL_STRING(" "))  // Init of "constant"
 {
   mOutputString = nullptr;
   mHeadLevel = 0;
   mAtFirstColumn = true;
   mIndent = 0;
   mCiteQuoteLevel = 0;
-  mStructs = true;                              // will be read from prefs later
-  mHeaderStrategy = 1 /*indent increasingly*/;  // ditto
   mHasWrittenCiteBlockquote = false;
   mSpanLevel = 0;
   for (int32_t i = 0; i <= 6; i++) {
     mHeaderCounter[i] = 0;
   }
 
   // Line breaker
   mWrapColumn = 72;  // XXX magic number, we expect someone to reset this
-  mCurrentLineWidth = 0;
 
   // Flow
   mEmptyLines = 1;  // The start of the document is an "empty line" in itself,
   mInWhitespace = false;
   mPreFormattedMail = false;
 
   mPreformattedBlockBoundary = false;
-  mWithRubyAnnotation = false;  // will be read from pref and flag later
 
   // initialize the tag stack to zero:
   // The stack only ever contains pointers to static atoms, so they don't
   // need refcounting.
   mTagStack = new nsAtom*[TagStackSize];
   mTagStackIndex = 0;
   mIgnoreAboveIndex = (uint32_t)kNotFound;
 
@@ -156,61 +151,62 @@ nsPlainTextSerializer::Init(uint32_t aFl
   if (aFlags & nsIDocumentEncoder::OutputFormatted) {
     NS_ASSERTION(
         !(aFlags & nsIDocumentEncoder::OutputPreformatted),
         "Can't do formatted and preformatted output at the same time!");
   }
 #endif
 
   *aNeedsPreformatScanning = true;
-  mFlags = aFlags;
+  mSettings.mFlags = aFlags;
   mWrapColumn = aWrapColumn;
 
   // Only create a linebreaker if we will handle wrapping.
   if (MayWrap() && MayBreakLines()) {
     mLineBreaker = nsContentUtils::LineBreaker();
   }
 
   // Set the line break character:
-  if ((mFlags & nsIDocumentEncoder::OutputCRLineBreak) &&
-      (mFlags & nsIDocumentEncoder::OutputLFLineBreak)) {
+  if ((mSettings.mFlags & nsIDocumentEncoder::OutputCRLineBreak) &&
+      (mSettings.mFlags & nsIDocumentEncoder::OutputLFLineBreak)) {
     // Windows
     mLineBreak.AssignLiteral("\r\n");
-  } else if (mFlags & nsIDocumentEncoder::OutputCRLineBreak) {
+  } else if (mSettings.mFlags & nsIDocumentEncoder::OutputCRLineBreak) {
     // Mac
     mLineBreak.Assign(char16_t('\r'));
-  } else if (mFlags & nsIDocumentEncoder::OutputLFLineBreak) {
+  } else if (mSettings.mFlags & nsIDocumentEncoder::OutputLFLineBreak) {
     // Unix/DOM
     mLineBreak.Assign(char16_t('\n'));
   } else {
     // Platform/default
     mLineBreak.AssignLiteral(NS_LINEBREAK);
   }
 
   mLineBreakDue = false;
   mFloatingLines = -1;
 
   mPreformattedBlockBoundary = false;
 
-  if (mFlags & nsIDocumentEncoder::OutputFormatted) {
+  if (mSettings.mFlags & nsIDocumentEncoder::OutputFormatted) {
     // Get some prefs that controls how we do formatted output
-    mStructs = Preferences::GetBool(PREF_STRUCTS, mStructs);
+    mSettings.mStructs = Preferences::GetBool(PREF_STRUCTS, mSettings.mStructs);
 
-    mHeaderStrategy =
-        Preferences::GetInt(PREF_HEADER_STRATEGY, mHeaderStrategy);
+    mSettings.mHeaderStrategy =
+        Preferences::GetInt(PREF_HEADER_STRATEGY, mSettings.mHeaderStrategy);
   }
 
   // The pref is default inited to false in libpref, but we use true
   // as fallback value because we don't want to affect behavior in
   // other places which use this serializer currently.
-  mWithRubyAnnotation =
-      gAlwaysIncludeRuby || (mFlags & nsIDocumentEncoder::OutputRubyAnnotation);
+  mSettings.mWithRubyAnnotation =
+      gAlwaysIncludeRuby ||
+      (mSettings.mFlags & nsIDocumentEncoder::OutputRubyAnnotation);
 
   // XXX We should let the caller decide whether to do this or not
-  mFlags &= ~nsIDocumentEncoder::OutputNoFramesContent;
+  mSettings.mFlags &= ~nsIDocumentEncoder::OutputNoFramesContent;
 
   return NS_OK;
 }
 
 bool nsPlainTextSerializer::GetLastBool(const nsTArray<bool>& aStack) {
   uint32_t size = aStack.Length();
   if (size == 0) {
     return false;
@@ -237,17 +233,17 @@ bool nsPlainTextSerializer::PopBool(nsTA
   if (size > 0) {
     returnValue = aStack.ElementAt(size - 1);
     aStack.RemoveElementAt(size - 1);
   }
   return returnValue;
 }
 
 bool nsPlainTextSerializer::IsIgnorableRubyAnnotation(nsAtom* aTag) {
-  if (mWithRubyAnnotation) {
+  if (mSettings.mWithRubyAnnotation) {
     return false;
   }
 
   return aTag == nsGkAtoms::rp || aTag == nsGkAtoms::rt ||
          aTag == nsGkAtoms::rtc;
 }
 
 // Return true if aElement has 'display:none' or if we just don't know.
@@ -443,26 +439,26 @@ nsresult nsPlainTextSerializer::DoOpenCo
     mIgnoredChildNodeLevel++;
     return NS_OK;
   }
   if (IsIgnorableScriptOrStyle(mElement)) {
     mIgnoredChildNodeLevel++;
     return NS_OK;
   }
 
-  if (mFlags & nsIDocumentEncoder::OutputForPlainTextClipboardCopy) {
+  if (mSettings.mFlags & nsIDocumentEncoder::OutputForPlainTextClipboardCopy) {
     if (mPreformattedBlockBoundary && DoOutput()) {
       // Should always end a line, but get no more whitespace
       if (mFloatingLines < 0) mFloatingLines = 0;
       mLineBreakDue = true;
     }
     mPreformattedBlockBoundary = false;
   }
 
-  if (mFlags & nsIDocumentEncoder::OutputRaw) {
+  if (mSettings.mFlags & nsIDocumentEncoder::OutputRaw) {
     // Raw means raw.  Don't even think about doing anything fancy
     // here like indenting, adding line breaks or any other
     // characters such as list item bullets, quote characters
     // around <q>, etc.  I mean it!  Don't make me smack you!
 
     return NS_OK;
   }
 
@@ -488,19 +484,19 @@ nsresult nsPlainTextSerializer::DoOpenCo
     nsresult rv = GetAttributeValue(nsGkAtoms::type, value);
     isInCiteBlockquote = NS_SUCCEEDED(rv) && value.EqualsIgnoreCase("cite");
   }
 
   if (mLineBreakDue && !isInCiteBlockquote) EnsureVerticalSpace(mFloatingLines);
 
   // Check if this tag's content that should not be output
   if ((aTag == nsGkAtoms::noscript &&
-       !(mFlags & nsIDocumentEncoder::OutputNoScriptContent)) ||
+       !(mSettings.mFlags & nsIDocumentEncoder::OutputNoScriptContent)) ||
       ((aTag == nsGkAtoms::iframe || aTag == nsGkAtoms::noframes) &&
-       !(mFlags & nsIDocumentEncoder::OutputNoFramesContent))) {
+       !(mSettings.mFlags & nsIDocumentEncoder::OutputNoFramesContent))) {
     // Ignore everything that follows the current tag in
     // question until a matching end tag is encountered.
     mIgnoreAboveIndex = mTagStackIndex - 1;
     return NS_OK;
   }
 
   if (aTag == nsGkAtoms::body) {
     // Try to figure out here whether we have a
@@ -595,34 +591,34 @@ nsresult nsPlainTextSerializer::DoOpenCo
   } else if (aTag == nsGkAtoms::ul) {
     // Indent here to support nested lists, which aren't included in li :-(
     EnsureVerticalSpace(mULCount + mOLStackIndex == 0 ? 1 : 0);
     // Must end the current line before we change indention
     mIndent += kIndentSizeList;
     mULCount++;
   } else if (aTag == nsGkAtoms::ol) {
     EnsureVerticalSpace(mULCount + mOLStackIndex == 0 ? 1 : 0);
-    if (mFlags & nsIDocumentEncoder::OutputFormatted) {
+    if (mSettings.mFlags & nsIDocumentEncoder::OutputFormatted) {
       // Must end the current line before we change indention
       if (mOLStackIndex < OLStackSize) {
         nsAutoString startAttr;
         int32_t startVal = 1;
         if (NS_SUCCEEDED(GetAttributeValue(nsGkAtoms::start, startAttr))) {
           nsresult rv = NS_OK;
           startVal = startAttr.ToInteger(&rv);
           if (NS_FAILED(rv)) startVal = 1;
         }
         mOLStack[mOLStackIndex++] = startVal;
       }
     } else {
       mOLStackIndex++;
     }
     mIndent += kIndentSizeList;  // see ul
   } else if (aTag == nsGkAtoms::li &&
-             (mFlags & nsIDocumentEncoder::OutputFormatted)) {
+             (mSettings.mFlags & nsIDocumentEncoder::OutputFormatted)) {
     if (mTagStackIndex > 1 && IsInOL()) {
       if (mOLStackIndex > 0) {
         nsAutoString valueAttr;
         if (NS_SUCCEEDED(GetAttributeValue(nsGkAtoms::value, valueAttr))) {
           nsresult rv = NS_OK;
           int32_t valueAttrVal = valueAttr.ToInteger(&rv);
           if (NS_SUCCEEDED(rv)) mOLStack[mOLStackIndex - 1] = valueAttrVal;
         }
@@ -667,31 +663,31 @@ nsresult nsPlainTextSerializer::DoOpenCo
 
   // Else make sure we'll separate block level tags,
   // even if we're about to leave, before doing any other formatting.
   else if (IsCssBlockLevelElement(mElement)) {
     EnsureVerticalSpace(0);
   }
 
   //////////////////////////////////////////////////////////////
-  if (!(mFlags & nsIDocumentEncoder::OutputFormatted)) {
+  if (!(mSettings.mFlags & nsIDocumentEncoder::OutputFormatted)) {
     return NS_OK;
   }
   //////////////////////////////////////////////////////////////
   // The rest of this routine is formatted output stuff,
   // which we should skip if we're not formatted:
   //////////////////////////////////////////////////////////////
 
   // Push on stack
   bool currentNodeIsConverted = IsCurrentNodeConverted();
 
   if (aTag == nsGkAtoms::h1 || aTag == nsGkAtoms::h2 || aTag == nsGkAtoms::h3 ||
       aTag == nsGkAtoms::h4 || aTag == nsGkAtoms::h5 || aTag == nsGkAtoms::h6) {
     EnsureVerticalSpace(2);
-    if (mHeaderStrategy == 2) {  // numbered
+    if (mSettings.mHeaderStrategy == 2) {  // numbered
       mIndent += kIndentSizeHeaders;
       // Caching
       int32_t level = HeaderLevel(aTag);
       // Increase counter for current level
       mHeaderCounter[level]++;
       // Reset all lower levels
       int32_t i;
 
@@ -702,42 +698,46 @@ nsresult nsPlainTextSerializer::DoOpenCo
       // Construct numbers
       nsAutoString leadup;
       for (i = 1; i <= level; i++) {
         leadup.AppendInt(mHeaderCounter[i]);
         leadup.Append(char16_t('.'));
       }
       leadup.Append(char16_t(' '));
       Write(leadup);
-    } else if (mHeaderStrategy == 1) {  // indent increasingly
+    } else if (mSettings.mHeaderStrategy == 1) {  // indent increasingly
       mIndent += kIndentSizeHeaders;
       for (int32_t i = HeaderLevel(aTag); i > 1; i--) {
         // for h(x), run x-1 times
         mIndent += kIndentIncrementHeaders;
       }
     }
   } else if (aTag == nsGkAtoms::a && !currentNodeIsConverted) {
     nsAutoString url;
     if (NS_SUCCEEDED(GetAttributeValue(nsGkAtoms::href, url)) &&
         !url.IsEmpty()) {
       mURL = url;
     }
-  } else if (aTag == nsGkAtoms::sup && mStructs && !currentNodeIsConverted) {
+  } else if (aTag == nsGkAtoms::sup && mSettings.mStructs &&
+             !currentNodeIsConverted) {
     Write(NS_LITERAL_STRING("^"));
-  } else if (aTag == nsGkAtoms::sub && mStructs && !currentNodeIsConverted) {
+  } else if (aTag == nsGkAtoms::sub && mSettings.mStructs &&
+             !currentNodeIsConverted) {
     Write(NS_LITERAL_STRING("_"));
-  } else if (aTag == nsGkAtoms::code && mStructs && !currentNodeIsConverted) {
+  } else if (aTag == nsGkAtoms::code && mSettings.mStructs &&
+             !currentNodeIsConverted) {
     Write(NS_LITERAL_STRING("|"));
-  } else if ((aTag == nsGkAtoms::strong || aTag == nsGkAtoms::b) && mStructs &&
-             !currentNodeIsConverted) {
+  } else if ((aTag == nsGkAtoms::strong || aTag == nsGkAtoms::b) &&
+             mSettings.mStructs && !currentNodeIsConverted) {
     Write(NS_LITERAL_STRING("*"));
-  } else if ((aTag == nsGkAtoms::em || aTag == nsGkAtoms::i) && mStructs &&
+  } else if ((aTag == nsGkAtoms::em || aTag == nsGkAtoms::i) &&
+             mSettings.mStructs && !currentNodeIsConverted) {
+    Write(NS_LITERAL_STRING("/"));
+  } else if (aTag == nsGkAtoms::u && mSettings.mStructs &&
              !currentNodeIsConverted) {
-    Write(NS_LITERAL_STRING("/"));
-  } else if (aTag == nsGkAtoms::u && mStructs && !currentNodeIsConverted) {
     Write(NS_LITERAL_STRING("_"));
   }
 
   /* Container elements are always block elements, so we shouldn't
      output any whitespace immediately after the container tag even if
      there's extra whitespace there because the HTML is pretty-printed
      or something. To ensure that happens, tell the serializer we're
      already in whitespace so it won't output more. */
@@ -751,26 +751,26 @@ nsresult nsPlainTextSerializer::DoCloseC
     mIgnoredChildNodeLevel--;
     return NS_OK;
   }
   if (IsIgnorableScriptOrStyle(mElement)) {
     mIgnoredChildNodeLevel--;
     return NS_OK;
   }
 
-  if (mFlags & nsIDocumentEncoder::OutputForPlainTextClipboardCopy) {
+  if (mSettings.mFlags & nsIDocumentEncoder::OutputForPlainTextClipboardCopy) {
     if (DoOutput() && IsElementPreformatted() &&
         IsCssBlockLevelElement(mElement)) {
       // If we're closing a preformatted block element, output a line break
       // when we find a new container.
       mPreformattedBlockBoundary = true;
     }
   }
 
-  if (mFlags & nsIDocumentEncoder::OutputRaw) {
+  if (mSettings.mFlags & nsIDocumentEncoder::OutputRaw) {
     // Raw means raw.  Don't even think about doing anything fancy
     // here like indenting, adding line breaks or any other
     // characters such as list item bullets, quote characters
     // around <q>, etc.  I mean it!  Don't make me smack you!
 
     return NS_OK;
   }
 
@@ -789,17 +789,17 @@ nsresult nsPlainTextSerializer::DoCloseC
   }
 
   // End current line if we're ending a block level tag
   if ((aTag == nsGkAtoms::body) || (aTag == nsGkAtoms::html)) {
     // We want the output to end with a new line,
     // but in preformatted areas like text fields,
     // we can't emit newlines that weren't there.
     // So add the newline only in the case of formatted output.
-    if (mFlags & nsIDocumentEncoder::OutputFormatted) {
+    if (mSettings.mFlags & nsIDocumentEncoder::OutputFormatted) {
       EnsureVerticalSpace(0);
     } else {
       FlushLine();
     }
     // We won't want to do anything with these in formatted mode either,
     // so just return now:
     return NS_OK;
   }
@@ -810,17 +810,17 @@ nsresult nsPlainTextSerializer::DoCloseC
   }
 
   if (aTag == nsGkAtoms::tr) {
     PopBool(mHasWrittenCellsForRow);
     // Should always end a line, but get no more whitespace
     if (mFloatingLines < 0) mFloatingLines = 0;
     mLineBreakDue = true;
   } else if (((aTag == nsGkAtoms::li) || (aTag == nsGkAtoms::dt)) &&
-             (mFlags & nsIDocumentEncoder::OutputFormatted)) {
+             (mSettings.mFlags & nsIDocumentEncoder::OutputFormatted)) {
     // Items that should always end a line, but get no more whitespace
     if (mFloatingLines < 0) mFloatingLines = 0;
     mLineBreakDue = true;
   } else if (aTag == nsGkAtoms::pre) {
     mFloatingLines = GetLastBool(mIsInCiteBlockquote) ? 0 : 1;
     mLineBreakDue = true;
   } else if (aTag == nsGkAtoms::ul) {
     FlushLine();
@@ -868,68 +868,70 @@ nsresult nsPlainTextSerializer::DoCloseC
     mLineBreakDue = true;
   } else if (aTag == nsGkAtoms::q) {
     Write(NS_LITERAL_STRING("\""));
   } else if (IsCssBlockLevelElement(mElement)) {
     // All other blocks get 1 vertical space after them
     // in formatted mode, otherwise 0.
     // This is hard. Sometimes 0 is a better number, but
     // how to know?
-    if (mFlags & nsIDocumentEncoder::OutputFormatted)
+    if (mSettings.mFlags & nsIDocumentEncoder::OutputFormatted)
       EnsureVerticalSpace(1);
     else {
       if (mFloatingLines < 0) mFloatingLines = 0;
       mLineBreakDue = true;
     }
   }
 
   //////////////////////////////////////////////////////////////
-  if (!(mFlags & nsIDocumentEncoder::OutputFormatted)) {
+  if (!(mSettings.mFlags & nsIDocumentEncoder::OutputFormatted)) {
     return NS_OK;
   }
   //////////////////////////////////////////////////////////////
   // The rest of this routine is formatted output stuff,
   // which we should skip if we're not formatted:
   //////////////////////////////////////////////////////////////
 
   // Pop the currentConverted stack
   bool currentNodeIsConverted = IsCurrentNodeConverted();
 
   if (aTag == nsGkAtoms::h1 || aTag == nsGkAtoms::h2 || aTag == nsGkAtoms::h3 ||
       aTag == nsGkAtoms::h4 || aTag == nsGkAtoms::h5 || aTag == nsGkAtoms::h6) {
-    if (mHeaderStrategy) { /*numbered or indent increasingly*/
+    if (mSettings.mHeaderStrategy) { /*numbered or indent increasingly*/
       mIndent -= kIndentSizeHeaders;
     }
-    if (mHeaderStrategy == 1 /*indent increasingly*/) {
+    if (mSettings.mHeaderStrategy == 1 /*indent increasingly*/) {
       for (int32_t i = HeaderLevel(aTag); i > 1; i--) {
         // for h(x), run x-1 times
         mIndent -= kIndentIncrementHeaders;
       }
     }
     EnsureVerticalSpace(1);
   } else if (aTag == nsGkAtoms::a && !currentNodeIsConverted &&
              !mURL.IsEmpty()) {
     nsAutoString temp;
     temp.AssignLiteral(" <");
     temp += mURL;
     temp.Append(char16_t('>'));
     Write(temp);
     mURL.Truncate();
-  } else if ((aTag == nsGkAtoms::sup || aTag == nsGkAtoms::sub) && mStructs &&
+  } else if ((aTag == nsGkAtoms::sup || aTag == nsGkAtoms::sub) &&
+             mSettings.mStructs && !currentNodeIsConverted) {
+    Write(kSpace);
+  } else if (aTag == nsGkAtoms::code && mSettings.mStructs &&
              !currentNodeIsConverted) {
-    Write(kSpace);
-  } else if (aTag == nsGkAtoms::code && mStructs && !currentNodeIsConverted) {
     Write(NS_LITERAL_STRING("|"));
-  } else if ((aTag == nsGkAtoms::strong || aTag == nsGkAtoms::b) && mStructs &&
-             !currentNodeIsConverted) {
+  } else if ((aTag == nsGkAtoms::strong || aTag == nsGkAtoms::b) &&
+             mSettings.mStructs && !currentNodeIsConverted) {
     Write(NS_LITERAL_STRING("*"));
-  } else if ((aTag == nsGkAtoms::em || aTag == nsGkAtoms::i) && mStructs &&
+  } else if ((aTag == nsGkAtoms::em || aTag == nsGkAtoms::i) &&
+             mSettings.mStructs && !currentNodeIsConverted) {
+    Write(NS_LITERAL_STRING("/"));
+  } else if (aTag == nsGkAtoms::u && mSettings.mStructs &&
              !currentNodeIsConverted) {
-    Write(NS_LITERAL_STRING("/"));
-  } else if (aTag == nsGkAtoms::u && mStructs && !currentNodeIsConverted) {
     Write(NS_LITERAL_STRING("_"));
   }
 
   return NS_OK;
 }
 
 bool nsPlainTextSerializer::MustSuppressLeaf() {
   if (mIgnoredChildNodeLevel > 0) {
@@ -969,17 +971,17 @@ void nsPlainTextSerializer::DoAddText(bo
 
   if (aIsLineBreak) {
     // The only times we want to pass along whitespace from the original
     // html source are if we're forced into preformatted mode via flags,
     // or if we're prettyprinting and we're inside a <pre>.
     // Otherwise, either we're collapsing to minimal text, or we're
     // prettyprinting to mimic the html format, and in neither case
     // does the formatting of the html source help us.
-    if ((mFlags & nsIDocumentEncoder::OutputPreformatted) ||
+    if ((mSettings.mFlags & nsIDocumentEncoder::OutputPreformatted) ||
         (mPreFormattedMail && !mWrapColumn) || IsElementPreformatted()) {
       EnsureVerticalSpace(mEmptyLines + 1);
     } else if (!mInWhitespace) {
       Write(kSpace);
       mInWhitespace = true;
     }
     return;
   }
@@ -1014,17 +1016,17 @@ nsresult nsPlainTextSerializer::DoAddLea
     //      of non-HTML element.
     // XXX Do we need to call `EnsureVerticalSpace()` when the <br> element
     //     is not an HTML element?
     HTMLBRElement* brElement = HTMLBRElement::FromNodeOrNull(mElement);
     if (!brElement || !brElement->IsPaddingForEmptyLastLine()) {
       EnsureVerticalSpace(mEmptyLines + 1);
     }
   } else if (aTag == nsGkAtoms::hr &&
-             (mFlags & nsIDocumentEncoder::OutputFormatted)) {
+             (mSettings.mFlags & nsIDocumentEncoder::OutputFormatted)) {
     EnsureVerticalSpace(0);
 
     // Make a line of dashes as wide as the wrap width
     // XXX honoring percentage would be nice
     nsAutoString line;
     uint32_t width = (mWrapColumn > 0 ? mWrapColumn : 25);
     while (line.Length() < width) {
       line.Append(char16_t('-'));
@@ -1080,32 +1082,32 @@ void nsPlainTextSerializer::EnsureVertic
  * This empties the current line cache without adding a NEWLINE.
  * Should not be used if line wrapping is of importance since
  * this function destroys the cache information.
  *
  * It will also write indentation and quotes if we believe us to be
  * at the start of the line.
  */
 void nsPlainTextSerializer::FlushLine() {
-  if (!mCurrentLine.IsEmpty()) {
+  if (!mCurrentLineContent.mValue.IsEmpty()) {
     if (mAtFirstColumn) {
       OutputQuotesAndIndent();  // XXX: Should we always do this? Bug?
     }
 
-    MaybeReplaceNbspsForOutput(mCurrentLine);
-    Output(mCurrentLine);
-    mAtFirstColumn = mAtFirstColumn && mCurrentLine.IsEmpty();
-    mCurrentLine.Truncate();
-    mCurrentLineWidth = 0;
+    MaybeReplaceNbspsForOutput(mCurrentLineContent.mValue);
+    Output(mCurrentLineContent.mValue);
+    mAtFirstColumn = mAtFirstColumn && mCurrentLineContent.mValue.IsEmpty();
+    mCurrentLineContent.mValue.Truncate();
+    mCurrentLineContent.mWidth = 0;
   }
 }
 
 void nsPlainTextSerializer::MaybeReplaceNbspsForOutput(
     nsString& aString) const {
-  if (!(mFlags & nsIDocumentEncoder::OutputPersistNBSP)) {
+  if (!(mSettings.mFlags & nsIDocumentEncoder::OutputPersistNBSP)) {
     // First, replace all nbsp characters with spaces,
     // which the unicode encoder won't do for us.
     aString.ReplaceChar(kNBSP, kSPACE);
   }
 }
 
 void nsPlainTextSerializer::Output(nsString& aString) {
   mOutputString->Append(aString);
@@ -1127,238 +1129,248 @@ static bool IsSpaceStuffable(const char1
  */
 void nsPlainTextSerializer::AddToLine(const char16_t* aLineFragment,
                                       int32_t aLineFragmentLength) {
   const uint32_t prefixwidth =
       (mCiteQuoteLevel > 0 ? mCiteQuoteLevel + 1 : 0) + mIndent;
 
   if (mLineBreakDue) EnsureVerticalSpace(mFloatingLines);
 
-  int32_t linelength = mCurrentLine.Length();
+  int32_t linelength = mCurrentLineContent.mValue.Length();
   if (0 == linelength) {
     if (0 == aLineFragmentLength) {
       // Nothing at all. Are you kidding me?
       return;
     }
 
-    if (mFlags & nsIDocumentEncoder::OutputFormatFlowed) {
+    if (mSettings.mFlags & nsIDocumentEncoder::OutputFormatFlowed) {
       if (IsSpaceStuffable(aLineFragment) &&
           mCiteQuoteLevel == 0  // We space-stuff quoted lines anyway
       ) {
         // Space stuffing a la RFC 2646 (format=flowed).
-        mCurrentLine.Append(char16_t(' '));
+        mCurrentLineContent.mValue.Append(char16_t(' '));
 
         if (MayWrap()) {
-          mCurrentLineWidth += GetUnicharWidth(' ');
+          mCurrentLineContent.mWidth += GetUnicharWidth(' ');
 #ifdef DEBUG_wrapping
-          NS_ASSERTION(GetUnicharStringWidth(mCurrentLine.get(),
-                                             mCurrentLine.Length()) ==
-                           (int32_t)mCurrentLineWidth,
-                       "mCurrentLineWidth and reality out of sync!");
+          NS_ASSERTION(
+              GetUnicharStringWidth(mCurrentLineContent.mValue.get(),
+                                    mCurrentLineContent.mValue.Length()) ==
+                  (int32_t)mCurrentLineContent.mWidth,
+              "mCurrentLineContent.mWidth and reality out of sync!");
 #endif
         }
       }
     }
     mEmptyLines = -1;
   }
 
-  mCurrentLine.Append(aLineFragment, aLineFragmentLength);
+  mCurrentLineContent.mValue.Append(aLineFragment, aLineFragmentLength);
 
   if (MayWrap()) {
-    mCurrentLineWidth +=
+    mCurrentLineContent.mWidth +=
         GetUnicharStringWidth(aLineFragment, aLineFragmentLength);
 #ifdef DEBUG_wrapping
-    NS_ASSERTION(
-        GetUnicharstringWidth(mCurrentLine.get(), mCurrentLine.Length()) ==
-            (int32_t)mCurrentLineWidth,
-        "mCurrentLineWidth and reality out of sync!");
+    NS_ASSERTION(GetUnicharstringWidth(mCurrentLineContent.mValue.get(),
+                                       mCurrentLineContent.mValue.Length()) ==
+                     (int32_t)mCurrentLineContent.mWidth,
+                 "mCurrentLineContent.mWidth and reality out of sync!");
 #endif
 
-    linelength = mCurrentLine.Length();
+    linelength = mCurrentLineContent.mValue.Length();
 
-#ifdef DEBUG_wrapping
-    NS_ASSERTION(
-        GetUnicharstringWidth(mCurrentLine.get(), mCurrentLine.Length()) ==
-            (int32_t)mCurrentLineWidth,
-        "mCurrentLineWidth and reality out of sync!");
-#endif
     // Yes, wrap!
     // The "+4" is to avoid wrap lines that only would be a couple
     // of letters too long. We give this bonus only if the
     // wrapcolumn is more than 20.
     uint32_t bonuswidth = (mWrapColumn > 20) ? 4 : 0;
 
     // XXX: Should calculate prefixwidth with GetUnicharStringWidth
-    while (mCurrentLineWidth + prefixwidth > mWrapColumn + bonuswidth) {
+    while (mCurrentLineContent.mWidth + prefixwidth >
+           mWrapColumn + bonuswidth) {
       // We go from the end removing one letter at a time until
       // we have a reasonable width
-      int32_t goodSpace = mCurrentLine.Length();
-      uint32_t width = mCurrentLineWidth;
+      int32_t goodSpace = mCurrentLineContent.mValue.Length();
+      uint32_t width = mCurrentLineContent.mWidth;
       while (goodSpace > 0 && (width + prefixwidth > mWrapColumn)) {
         goodSpace--;
-        width -= GetUnicharWidth(mCurrentLine[goodSpace]);
+        width -= GetUnicharWidth(mCurrentLineContent.mValue[goodSpace]);
       }
 
       goodSpace++;
 
       if (mLineBreaker) {
-        goodSpace = mLineBreaker->Prev(mCurrentLine.get(),
-                                       mCurrentLine.Length(), goodSpace);
-        if (goodSpace != NS_LINEBREAKER_NEED_MORE_TEXT &&
-            nsCRT::IsAsciiSpace(mCurrentLine.CharAt(goodSpace - 1))) {
+        goodSpace =
+            mLineBreaker->Prev(mCurrentLineContent.mValue.get(),
+                               mCurrentLineContent.mValue.Length(), goodSpace);
+        if (goodSpace !=
+                NS_LINEBREAKER_NEED_MORE_TEXT &&  // MB: surprisingly goodSpace
+                                                  // ==
+                                                  // NS_LINEBREAKER_NEED_MORE_TEXT.
+            nsCRT::IsAsciiSpace(
+                mCurrentLineContent.mValue.CharAt(goodSpace - 1))) {
           --goodSpace;  // adjust the position since line breaker returns a
                         // position next to space
         }
       }
       // fallback if the line breaker is unavailable or failed
       if (!mLineBreaker) {
-        if (mCurrentLine.IsEmpty() || mWrapColumn < prefixwidth) {
+        if (mCurrentLineContent.mValue.IsEmpty() || mWrapColumn < prefixwidth) {
           goodSpace = NS_LINEBREAKER_NEED_MORE_TEXT;
         } else {
-          goodSpace =
-              std::min(mWrapColumn - prefixwidth, mCurrentLine.Length() - 1);
+          goodSpace = std::min(mWrapColumn - prefixwidth,
+                               mCurrentLineContent.mValue.Length() - 1);
           while (goodSpace >= 0 &&
-                 !nsCRT::IsAsciiSpace(mCurrentLine.CharAt(goodSpace))) {
+                 !nsCRT::IsAsciiSpace(
+                     mCurrentLineContent.mValue.CharAt(goodSpace))) {
             goodSpace--;
           }
         }
       }
 
       nsAutoString restOfLine;
       if (goodSpace == NS_LINEBREAKER_NEED_MORE_TEXT) {
         // If we didn't find a good place to break, accept long line and
         // try to find another place to break
         goodSpace =
             (prefixwidth > mWrapColumn + 1) ? 1 : mWrapColumn - prefixwidth + 1;
         if (mLineBreaker) {
-          if ((uint32_t)goodSpace < mCurrentLine.Length())
-            goodSpace = mLineBreaker->Next(mCurrentLine.get(),
-                                           mCurrentLine.Length(), goodSpace);
+          if ((uint32_t)goodSpace < mCurrentLineContent.mValue.Length())
+            goodSpace = mLineBreaker->Next(mCurrentLineContent.mValue.get(),
+                                           mCurrentLineContent.mValue.Length(),
+                                           goodSpace);
           if (goodSpace == NS_LINEBREAKER_NEED_MORE_TEXT)
-            goodSpace = mCurrentLine.Length();
+            goodSpace = mCurrentLineContent.mValue.Length();
         }
         // fallback if the line breaker is unavailable or failed
         if (!mLineBreaker) {
           goodSpace =
               (prefixwidth > mWrapColumn) ? 1 : mWrapColumn - prefixwidth;
           while (goodSpace < linelength &&
-                 !nsCRT::IsAsciiSpace(mCurrentLine.CharAt(goodSpace))) {
+                 !nsCRT::IsAsciiSpace(
+                     mCurrentLineContent.mValue.CharAt(goodSpace))) {
             goodSpace++;
           }
         }
       }
 
       if ((goodSpace < linelength) && (goodSpace > 0)) {
         // Found a place to break
 
         // -1 (trim a char at the break position)
         // only if the line break was a space.
-        if (nsCRT::IsAsciiSpace(mCurrentLine.CharAt(goodSpace))) {
-          mCurrentLine.Right(restOfLine, linelength - goodSpace - 1);
+        if (nsCRT::IsAsciiSpace(mCurrentLineContent.mValue.CharAt(goodSpace))) {
+          mCurrentLineContent.mValue.Right(restOfLine,
+                                           linelength - goodSpace - 1);
         } else {
-          mCurrentLine.Right(restOfLine, linelength - goodSpace);
+          mCurrentLineContent.mValue.Right(restOfLine, linelength - goodSpace);
         }
         // if breaker was U+0020, it has to consider for delsp=yes support
-        const bool breakBySpace = mCurrentLine.CharAt(goodSpace) == ' ';
-        mCurrentLine.Truncate(goodSpace);
+        const bool breakBySpace =
+            mCurrentLineContent.mValue.CharAt(goodSpace) == ' ';
+        mCurrentLineContent.mValue.Truncate(goodSpace);
         EndLine(true, breakBySpace);
-        mCurrentLine.Truncate();
+        mCurrentLineContent.mValue.Truncate();
         // Space stuff new line?
-        if (mFlags & nsIDocumentEncoder::OutputFormatFlowed) {
+        if (mSettings.mFlags & nsIDocumentEncoder::OutputFormatFlowed) {
           if (!restOfLine.IsEmpty() && IsSpaceStuffable(restOfLine.get()) &&
               mCiteQuoteLevel == 0  // We space-stuff quoted lines anyway
           ) {
             // Space stuffing a la RFC 2646 (format=flowed).
-            mCurrentLine.Append(char16_t(' '));
+            mCurrentLineContent.mValue.Append(char16_t(' '));
             // XXX doesn't seem to work correctly for ' '
           }
         }
-        mCurrentLine.Append(restOfLine);
-        mCurrentLineWidth =
-            GetUnicharStringWidth(mCurrentLine.get(), mCurrentLine.Length());
-        linelength = mCurrentLine.Length();
+        mCurrentLineContent.mValue.Append(restOfLine);
+        mCurrentLineContent.mWidth =
+            GetUnicharStringWidth(mCurrentLineContent.mValue.get(),
+                                  mCurrentLineContent.mValue.Length());
+        linelength = mCurrentLineContent.mValue.Length();
         mEmptyLines = -1;
       } else {
         // Nothing to do. Hopefully we get more data later
         // to use for a place to break line
         break;
       }
     }
   }
 }
 
 /**
- * Outputs the contents of mCurrentLine, and resets line specific
+ * Outputs the contents of mCurrentLineContent.mValue, and resets line specific
  * variables. Also adds an indentation and prefix if there is
  * one specified. Strips ending spaces from the line if it isn't
  * preformatted.
  */
 void nsPlainTextSerializer::EndLine(bool aSoftlinebreak, bool aBreakBySpace) {
-  uint32_t currentlinelength = mCurrentLine.Length();
+  uint32_t currentlinelength = mCurrentLineContent.mValue.Length();
 
   if (aSoftlinebreak && 0 == currentlinelength) {
     // No meaning
     return;
   }
 
   /* In non-preformatted mode, remove spaces from the end of the line for
    * format=flowed compatibility. Don't do this for these special cases:
    * "-- ", the signature separator (RFC 2646) shouldn't be touched and
    * "- -- ", the OpenPGP dash-escaped signature separator in inline
    * signed messages according to the OpenPGP standard (RFC 2440).
    */
-  if (!(mFlags & nsIDocumentEncoder::OutputPreformatted) &&
-      (aSoftlinebreak || !(mCurrentLine.EqualsLiteral("-- ") ||
-                           mCurrentLine.EqualsLiteral("- -- ")))) {
+  if (!(mSettings.mFlags & nsIDocumentEncoder::OutputPreformatted) &&
+      (aSoftlinebreak ||
+       !(mCurrentLineContent.mValue.EqualsLiteral("-- ") ||
+         mCurrentLineContent.mValue.EqualsLiteral("- -- ")))) {
     // Remove spaces from the end of the line.
     while (currentlinelength > 0 &&
-           mCurrentLine[currentlinelength - 1] == ' ') {
+           mCurrentLineContent.mValue[currentlinelength - 1] == ' ') {
       --currentlinelength;
     }
-    mCurrentLine.SetLength(currentlinelength);
+    mCurrentLineContent.mValue.SetLength(currentlinelength);
   }
 
-  if (aSoftlinebreak && (mFlags & nsIDocumentEncoder::OutputFormatFlowed) &&
+  if (aSoftlinebreak &&
+      (mSettings.mFlags & nsIDocumentEncoder::OutputFormatFlowed) &&
       (mIndent == 0)) {
     // Add the soft part of the soft linebreak (RFC 2646 4.1)
     // We only do this when there is no indentation since format=flowed
     // lines and indentation doesn't work well together.
 
     // If breaker character is ASCII space with RFC 3676 support (delsp=yes),
     // add twice space.
-    if ((mFlags & nsIDocumentEncoder::OutputFormatDelSp) && aBreakBySpace)
-      mCurrentLine.AppendLiteral("  ");
+    if ((mSettings.mFlags & nsIDocumentEncoder::OutputFormatDelSp) &&
+        aBreakBySpace)
+      mCurrentLineContent.mValue.AppendLiteral("  ");
     else
-      mCurrentLine.Append(char16_t(' '));
+      mCurrentLineContent.mValue.Append(char16_t(' '));
   }
 
   if (aSoftlinebreak) {
     mEmptyLines = 0;
   } else {
     // Hard break
-    if (!mCurrentLine.IsEmpty() || !mInIndentString.IsEmpty()) {
+    if (!mCurrentLineContent.mValue.IsEmpty() || !mInIndentString.IsEmpty()) {
       mEmptyLines = -1;
     }
 
     mEmptyLines++;
   }
 
   if (mAtFirstColumn) {
     // If we don't have anything "real" to output we have to
     // make sure the indent doesn't end in a space since that
     // would trick a format=flowed-aware receiver.
-    bool stripTrailingSpaces = mCurrentLine.IsEmpty();
+    bool stripTrailingSpaces = mCurrentLineContent.mValue.IsEmpty();
     OutputQuotesAndIndent(stripTrailingSpaces);
   }
 
-  mCurrentLine.Append(mLineBreak);
-  MaybeReplaceNbspsForOutput(mCurrentLine);
-  Output(mCurrentLine);
-  mCurrentLine.Truncate();
-  mCurrentLineWidth = 0;
+  mCurrentLineContent.mValue.Append(mLineBreak);
+  MaybeReplaceNbspsForOutput(mCurrentLineContent.mValue);
+  Output(mCurrentLineContent.mValue);
+  mCurrentLineContent.mValue.Truncate();
+  mCurrentLineContent.mWidth = 0;
   mAtFirstColumn = true;
   mInWhitespace = true;
   mLineBreakDue = false;
   mFloatingLines = -1;
 }
 
 /**
  * Outputs the calculated and stored indent and text in the indentation. That is
@@ -1370,31 +1382,32 @@ void nsPlainTextSerializer::OutputQuotes
   nsAutoString stringToOutput;
 
   // Put the mail quote "> " chars in, if appropriate:
   if (mCiteQuoteLevel > 0) {
     nsAutoString quotes;
     for (int i = 0; i < mCiteQuoteLevel; i++) {
       quotes.Append(char16_t('>'));
     }
-    if (!mCurrentLine.IsEmpty()) {
+    if (!mCurrentLineContent.mValue.IsEmpty()) {
       /* Better don't output a space here, if the line is empty,
          in case a receiving f=f-aware UA thinks, this were a flowed line,
          which it isn't - it's just empty.
          (Flowed lines may be joined with the following one,
          so the empty line may be lost completely.) */
       quotes.Append(char16_t(' '));
     }
     stringToOutput = quotes;
     mAtFirstColumn = false;
   }
 
   // Indent if necessary
   int32_t indentwidth = mIndent - mInIndentString.Length();
-  if (indentwidth > 0 && (!mCurrentLine.IsEmpty() || !mInIndentString.IsEmpty())
+  if (indentwidth > 0 &&
+      (!mCurrentLineContent.mValue.IsEmpty() || !mInIndentString.IsEmpty())
       // Don't make empty lines look flowed
   ) {
     nsAutoString spaces;
     for (int i = 0; i < indentwidth; ++i) spaces.Append(char16_t(' '));
     stringToOutput += spaces;
     mAtFirstColumn = false;
   }
 
@@ -1437,17 +1450,17 @@ void nsPlainTextSerializer::Write(const 
 
   int32_t totLen = str.Length();
 
   // If the string is empty, do nothing:
   if (totLen <= 0) return;
 
   // For Flowed text change nbsp-ses to spaces at end of lines to allow them
   // to be cut off along with usual spaces if required. (bug #125928)
-  if (mFlags & nsIDocumentEncoder::OutputFormatFlowed) {
+  if (mSettings.mFlags & nsIDocumentEncoder::OutputFormatFlowed) {
     for (int32_t i = totLen - 1; i >= 0; i--) {
       char16_t c = str[i];
       if ('\n' == c || '\r' == c || ' ' == c || '\t' == c) continue;
       if (kNBSP == c)
         str.Replace(i, 1, ' ');
       else
         break;
     }
@@ -1457,21 +1470,21 @@ void nsPlainTextSerializer::Write(const 
   // that does normal formatted text. The one for preformatted text calls
   // Output directly while the other code path goes through AddToLine.
   if ((mPreFormattedMail && !mWrapColumn) ||
       (IsElementPreformatted() && !mPreFormattedMail && !MayWrap()) ||
       (mSpanLevel > 0 && mEmptyLines >= 0 && IsQuotedLine(str))) {
     // No intelligent wrapping.
 
     // This mustn't be mixed with intelligent wrapping without clearing
-    // the mCurrentLine buffer before!!!
-    NS_ASSERTION(mCurrentLine.IsEmpty() ||
+    // the mCurrentLineContent.mValue buffer before!!!
+    NS_ASSERTION(mCurrentLineContent.mValue.IsEmpty() ||
                      (IsElementPreformatted() && !mPreFormattedMail),
                  "Mixed wrapping data and nonwrapping data on the same line");
-    if (!mCurrentLine.IsEmpty()) {
+    if (!mCurrentLineContent.mValue.IsEmpty()) {
       FlushLine();
     }
 
     // Put the mail quote "> " chars in, if appropriate.
     // Have to put it in before every line.
     while (bol < totLen) {
       bool outputQuotes = mAtFirstColumn;
       bool atFirstColumn;
@@ -1525,42 +1538,42 @@ void nsPlainTextSerializer::Write(const 
         if ('\r' == *iter && bol < totLen && '\n' == *++iter) {
           // There was a CRLF in the input. This used to be illegal and
           // stripped by the parser. Apparently not anymore. Let's skip
           // over the LF.
           bol++;
         }
       }
 
-      mCurrentLine.Truncate();
-      if (mFlags & nsIDocumentEncoder::OutputFormatFlowed) {
+      mCurrentLineContent.mValue.Truncate();
+      if (mSettings.mFlags & nsIDocumentEncoder::OutputFormatFlowed) {
         if ((outputLineBreak || !spacesOnly) &&  // bugs 261467,125928
             !IsQuotedLine(stringpart) && !stringpart.EqualsLiteral("-- ") &&
             !stringpart.EqualsLiteral("- -- "))
           stringpart.Trim(" ", false, true, true);
         if (IsSpaceStuffable(stringpart.get()) && !IsQuotedLine(stringpart))
-          mCurrentLine.Append(char16_t(' '));
+          mCurrentLineContent.mValue.Append(char16_t(' '));
       }
-      mCurrentLine.Append(stringpart);
+      mCurrentLineContent.mValue.Append(stringpart);
 
       if (outputQuotes) {
         // Note: this call messes with mAtFirstColumn
         OutputQuotesAndIndent();
       }
 
-      MaybeReplaceNbspsForOutput(mCurrentLine);
-      Output(mCurrentLine);
+      MaybeReplaceNbspsForOutput(mCurrentLineContent.mValue);
+      Output(mCurrentLineContent.mValue);
       if (outputLineBreak) {
         Output(mLineBreak);
       }
       mAtFirstColumn = atFirstColumn;
     }
 
-    // Reset mCurrentLine.
-    mCurrentLine.Truncate();
+    // Reset mCurrentLineContent.mValue.
+    mCurrentLineContent.mValue.Truncate();
 
 #ifdef DEBUG_wrapping
     printf("No wrapping: newline is %d, totLen is %d\n", newline, totLen);
 #endif
     return;
   }
 
   // Intelligent handling of text
@@ -1597,17 +1610,17 @@ void nsPlainTextSerializer::Write(const 
           offsetIntoBuffer = str.get() + bol;
           AddToLine(offsetIntoBuffer, nextpos - bol);
           bol = nextpos + 1;
           continue;
         }
       }
       // If we're already in whitespace and not preformatted, just skip it:
       if (mInWhitespace && (nextpos == bol) && !mPreFormattedMail &&
-          !(mFlags & nsIDocumentEncoder::OutputPreformatted)) {
+          !(mSettings.mFlags & nsIDocumentEncoder::OutputPreformatted)) {
         // Skip whitespace
         bol++;
         continue;
       }
 
       if (nextpos == bol) {
         // Note that we are in whitespace.
         mInWhitespace = true;
@@ -1616,17 +1629,17 @@ void nsPlainTextSerializer::Write(const 
         bol++;
         continue;
       }
 
       mInWhitespace = true;
 
       offsetIntoBuffer = str.get() + bol;
       if (mPreFormattedMail ||
-          (mFlags & nsIDocumentEncoder::OutputPreformatted)) {
+          (mSettings.mFlags & nsIDocumentEncoder::OutputPreformatted)) {
         // Preserve the real whitespace character
         nextpos++;
         AddToLine(offsetIntoBuffer, nextpos - bol);
         bol = nextpos;
       } else {
         // Replace the whitespace with a space
         AddToLine(offsetIntoBuffer, nextpos - bol);
         AddToLine(kSpace.get(), 1);
--- a/dom/base/nsPlainTextSerializer.h
+++ b/dom/base/nsPlainTextSerializer.h
@@ -109,21 +109,22 @@ class nsPlainTextSerializer final : publ
   static nsAtom* GetIdForContent(nsIContent* aContent);
   nsresult DoOpenContainer(nsAtom* aTag);
   nsresult DoCloseContainer(nsAtom* aTag);
   nsresult DoAddLeaf(nsAtom* aTag);
   void DoAddText(bool aIsWhitespace, const nsAString& aText);
 
   // Inlined functions
   inline bool MayWrap() {
-    return mWrapColumn && ((mFlags & nsIDocumentEncoder::OutputFormatted) ||
-                           (mFlags & nsIDocumentEncoder::OutputWrap));
+    return mWrapColumn &&
+           ((mSettings.mFlags & nsIDocumentEncoder::OutputFormatted) ||
+            (mSettings.mFlags & nsIDocumentEncoder::OutputWrap));
   }
   inline bool MayBreakLines() {
-    return !(mFlags & nsIDocumentEncoder::OutputDisallowLineBreaking);
+    return !(mSettings.mFlags & nsIDocumentEncoder::OutputDisallowLineBreaking);
   }
 
   inline bool DoOutput() const { return mHeadLevel == 0; }
 
   inline bool IsQuotedLine(const nsAString& aLine) {
     return !aLine.IsEmpty() && aLine.First() == char16_t('>');
   }
 
@@ -139,43 +140,66 @@ class nsPlainTextSerializer final : publ
   //         be preserved according to its style or because it's a `<pre>`
   //         element.
   static bool IsElementPreformatted(mozilla::dom::Element* aElement);
 
   // https://drafts.csswg.org/css-display/#block-level
   static bool IsCssBlockLevelElement(mozilla::dom::Element* aElement);
 
  private:
-  nsString mCurrentLine;
   uint32_t mHeadLevel;
   bool mAtFirstColumn;
 
-  bool mStructs;  // Output structs (pref)
+  struct Settings {
+    // Pref: converter.html2txt.structs.
+    bool mStructs = true;
+
+    // Pref: converter.html2txt.header_strategy.
+    int32_t mHeaderStrategy = 1; /* Header strategy (pref)
+                                  0 = no indention
+                                  1 = indention, increased with
+                                      header level (default)
+                                  2 = numbering and slight indention */
+
+    // Flags defined in nsIDocumentEncoder.idl.
+    int32_t mFlags = 0;
+
+    // Whether the output should include ruby annotations.
+    bool mWithRubyAnnotation = false;
+  };
+
+  Settings mSettings;
+
+  struct CurrentLineContent {
+    // Excludes indentation and quotes.
+    nsString mValue;
+
+    // The width of the line as it will appear on the screen (approx.).
+    uint32_t mWidth = 0;
+  };
+
+  CurrentLineContent mCurrentLineContent;
 
   // If we've just written out a cite blockquote, we need to remember it
   // so we don't duplicate spaces before a <pre wrap> (which mail uses to quote
   // old messages).
   bool mHasWrittenCiteBlockquote;
 
   int32_t mIndent;
   // mInIndentString keeps a header that has to be written in the indent.
   // That could be, for instance, the bullet in a bulleted list.
   nsString mInIndentString;
   int32_t mCiteQuoteLevel;
-  int32_t mFlags;
   int32_t mFloatingLines;  // To store the number of lazy line breaks
 
   // The wrap column is how many standard sized chars (western languages)
   // should be allowed on a line. There could be less chars if the chars
   // are wider than latin chars of more if the chars are more narrow.
   uint32_t mWrapColumn;
 
-  // The width of the line as it will appear on the screen (approx.)
-  uint32_t mCurrentLineWidth;
-
   // Treat quoted text as though it's preformatted -- don't wrap it.
   // Having it on a pref is a temporary measure, See bug 69638.
   int32_t mSpanLevel;
 
   int32_t mEmptyLines;  // Will be the number of empty lines before
                         // the current. 0 if we are starting a new
                         // line and -1 if we are in a line.
 
@@ -186,25 +210,17 @@ class nsPlainTextSerializer final : publ
   // While handling a new tag, this variable should remind if any line break
   // is due because of a closing tag. Setting it to "TRUE" while closing the
   // tags. Hence opening tags are guaranteed to start with appropriate line
   // breaks.
   bool mLineBreakDue;
 
   bool mPreformattedBlockBoundary;
 
-  // Whether the output should include ruby annotations.
-  bool mWithRubyAnnotation;
-
   nsString mURL;
-  int32_t mHeaderStrategy;   /* Header strategy (pref)
-                                0 = no indention
-                                1 = indention, increased with
-                                    header level (default)
-                                2 = numbering and slight indention */
   int32_t mHeaderCounter[7]; /* For header-numbering:
                                 Number of previous headers of
                                 the same depth and in the same
                                 section.
                                 mHeaderCounter[1] for <h1> etc. */
 
   RefPtr<mozilla::dom::Element> mElement;
 
old mode 100755
new mode 100644
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -20029,17 +20029,17 @@ nsresult OpenDatabaseOp::DoDatabaseWork(
   }
 
   rv = markerFile->Append(NS_LITERAL_STRING(IDB_DELETION_MARKER_FILE_PREFIX) +
                           filename);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  markerFile->Exists(&exists);
+  rv = markerFile->Exists(&exists);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   if (exists) {
     // Delete the database and directroy since they should be deleted in
     // previous operation.
     // Note: only update usage to the QuotaManager when mEnforcingQuota == true
@@ -26000,58 +26000,36 @@ nsresult Cursor::OpenOp::DoObjectStoreKe
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   // Now we need to make the query to get the next match.
   keyRangeClause.Truncate();
   nsAutoCString continueToKeyRangeClause;
 
+  const bool isUpperBound = mCursor->mDirection == IDBCursor::NEXT ||
+                            mCursor->mDirection == IDBCursor::NEXT_UNIQUE;
+
+  Key bound;
+  bool open;
+  GetRangeKeyInfo(!isUpperBound, &bound, &open);
+
   NS_NAMED_LITERAL_CSTRING(currentKey, "current_key");
-  NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key");
-
-  switch (mCursor->mDirection) {
-    case IDBCursor::NEXT:
-    case IDBCursor::NEXT_UNIQUE: {
-      Key upper;
-      bool open;
-      GetRangeKeyInfo(false, &upper, &open);
-      AppendConditionClause(keyString, currentKey, false, false,
-                            keyRangeClause);
-      AppendConditionClause(keyString, currentKey, false, true,
-                            continueToKeyRangeClause);
-      if (usingKeyRange && !upper.IsUnset()) {
-        AppendConditionClause(keyString, rangeKey, true, !open, keyRangeClause);
-        AppendConditionClause(keyString, rangeKey, true, !open,
-                              continueToKeyRangeClause);
-        mCursor->mRangeKey = upper;
-      }
-      break;
-    }
-
-    case IDBCursor::PREV:
-    case IDBCursor::PREV_UNIQUE: {
-      Key lower;
-      bool open;
-      GetRangeKeyInfo(true, &lower, &open);
-      AppendConditionClause(keyString, currentKey, true, false, keyRangeClause);
-      AppendConditionClause(keyString, currentKey, true, true,
-                            continueToKeyRangeClause);
-      if (usingKeyRange && !lower.IsUnset()) {
-        AppendConditionClause(keyString, rangeKey, false, !open,
-                              keyRangeClause);
-        AppendConditionClause(keyString, rangeKey, false, !open,
-                              continueToKeyRangeClause);
-        mCursor->mRangeKey = lower;
-      }
-      break;
-    }
-
-    default:
-      MOZ_CRASH("Should never get here!");
+  AppendConditionClause(keyString, currentKey, !isUpperBound, false,
+                        keyRangeClause);
+  AppendConditionClause(keyString, currentKey, !isUpperBound, true,
+                        continueToKeyRangeClause);
+  if (usingKeyRange && !bound.IsUnset()) {
+    NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key");
+
+    AppendConditionClause(keyString, rangeKey, isUpperBound, !open,
+                          keyRangeClause);
+    AppendConditionClause(keyString, rangeKey, isUpperBound, !open,
+                          continueToKeyRangeClause);
+    mCursor->mRangeKey = bound;
   }
 
   mCursor->mContinueQuery =
       queryStart + keyRangeClause + directionClause + openLimit;
   mCursor->mContinueToQuery =
       queryStart + continueToKeyRangeClause + directionClause + openLimit;
 
   return NS_OK;
--- a/dom/indexedDB/IDBIndex.cpp
+++ b/dom/indexedDB/IDBIndex.cpp
@@ -490,17 +490,17 @@ already_AddRefed<IDBRequest> IDBIndex::O
         IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(keyRange),
         IDB_LOG_STRINGIFY(direction));
   } else {
     IDB_LOG_MARK(
         "IndexedDB %s: Child  Transaction[%lld] Request[%llu]: "
         "database(%s).transaction(%s).objectStore(%s).index(%s)."
         "openCursor(%s, %s)",
         "IndexedDB %s: C T[%lld] R[%llu]: "
-        "IDBObjectStore.openKeyCursor()",
+        "IDBObjectStore.openCursor()",
         IDB_LOG_ID_STRING(), transaction->LoggingSerialNumber(),
         request->LoggingSerialNumber(),
         IDB_LOG_STRINGIFY(transaction->Database()),
         IDB_LOG_STRINGIFY(transaction), IDB_LOG_STRINGIFY(mObjectStore),
         IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(keyRange),
         IDB_LOG_STRINGIFY(direction));
   }
 
--- a/dom/indexedDB/IDBKeyRange.cpp
+++ b/dom/indexedDB/IDBKeyRange.cpp
@@ -110,82 +110,16 @@ void IDBKeyRange::ToSerialized(Serialize
   aKeyRange.isOnly() = IsOnly();
 
   aKeyRange.lower() = Lower();
   if (!IsOnly()) {
     aKeyRange.upper() = Upper();
   }
 }
 
-void IDBKeyRange::GetBindingClause(const nsACString& aKeyColumnName,
-                                   nsACString& _retval) const {
-  NS_NAMED_LITERAL_CSTRING(andStr, " AND ");
-  NS_NAMED_LITERAL_CSTRING(spacecolon, " :");
-  NS_NAMED_LITERAL_CSTRING(lowerKey, "lower_key");
-
-  if (IsOnly()) {
-    // Both keys are set and they're equal.
-    _retval = andStr + aKeyColumnName + NS_LITERAL_CSTRING(" =") + spacecolon +
-              lowerKey;
-    return;
-  }
-
-  nsAutoCString clause;
-
-  if (!Lower().IsUnset()) {
-    // Lower key is set.
-    clause.Append(andStr + aKeyColumnName);
-    clause.AppendLiteral(" >");
-    if (!LowerOpen()) {
-      clause.Append('=');
-    }
-    clause.Append(spacecolon + lowerKey);
-  }
-
-  if (!Upper().IsUnset()) {
-    // Upper key is set.
-    clause.Append(andStr + aKeyColumnName);
-    clause.AppendLiteral(" <");
-    if (!UpperOpen()) {
-      clause.Append('=');
-    }
-    clause.Append(spacecolon + NS_LITERAL_CSTRING("upper_key"));
-  }
-
-  _retval = clause;
-}
-
-nsresult IDBKeyRange::BindToStatement(mozIStorageStatement* aStatement) const {
-  MOZ_ASSERT(aStatement);
-
-  NS_NAMED_LITERAL_CSTRING(lowerKey, "lower_key");
-
-  if (IsOnly()) {
-    return Lower().BindToStatement(aStatement, lowerKey);
-  }
-
-  nsresult rv;
-
-  if (!Lower().IsUnset()) {
-    rv = Lower().BindToStatement(aStatement, lowerKey);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-  }
-
-  if (!Upper().IsUnset()) {
-    rv = Upper().BindToStatement(aStatement, NS_LITERAL_CSTRING("upper_key"));
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-  }
-
-  return NS_OK;
-}
-
 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBKeyRange)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBKeyRange)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBKeyRange)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedLowerVal)
--- a/dom/indexedDB/IDBKeyRange.h
+++ b/dom/indexedDB/IDBKeyRange.h
@@ -87,21 +87,16 @@ class IDBKeyRange : public nsISupports {
 
   indexedDB::Key& Upper() { return mIsOnly ? mLower : mUpper; }
 
   bool Includes(JSContext* aCx, JS::Handle<JS::Value> aKey,
                 ErrorResult& aRv) const;
 
   bool IsOnly() const { return mIsOnly; }
 
-  void GetBindingClause(const nsACString& aKeyColumnName,
-                        nsACString& _retval) const;
-
-  nsresult BindToStatement(mozIStorageStatement* aStatement) const;
-
   void DropJSObjects();
 
   // WebIDL
   bool WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto,
                   JS::MutableHandle<JSObject*> aReflector);
 
   nsISupports* GetParentObject() const { return mGlobal; }
 
--- a/dom/media/webvtt/vtt.jsm
+++ b/dom/media/webvtt/vtt.jsm
@@ -867,26 +867,16 @@ XPCOMUtils.defineLazyPreferenceGetter(th
       for (let i = 0; i < boxes.length; i++) {
         if (this.overlaps(boxes[i])) {
           return true;
         }
       }
       return false;
     }
 
-    // Check if this box overlaps any other boxes in boxes.
-    overlapsAny(boxes) {
-      for (let i = 0; i < boxes.length; i++) {
-        if (this.overlaps(boxes[i])) {
-          return true;
-        }
-      }
-      return false;
-    }
-
     // Check if this box is within another box.
     within(container) {
       return (this.top >= container.top - this.fuzz) &&
              (this.bottom <= container.bottom + this.fuzz) &&
              (this.left >= container.left - this.fuzz) &&
              (this.right <= container.right + this.fuzz);
     }
 
@@ -931,16 +921,17 @@ XPCOMUtils.defineLazyPreferenceGetter(th
 
     // Spec 7.2.10, adjust the positions of boxes according to the appropriate
     // steps from the following list. Also, we use offsetHeight/offsetWidth here
     // in order to prevent the incorrect positioning caused by CSS transform
     // scale.
     const fullDimension = isWritingDirectionHorizontal ?
       containerBox.height : containerBox.width;
     if (cue.snapToLines) {
+      LOG(`Adjust position when 'snap-to-lines' is true.`);
       // The step is the height or width of the line box. We should use font
       // size directly, instead of using text box's width or height, because the
       // width or height of the box would be changed when the text is wrapped to
       // different line. Ex. if text is wrapped to two line, the height or width
       // of the box would become 2 times of font size.
       let step = styleBox.getFirstLineBoxSize();
       if (step == 0) {
         return;
@@ -1019,34 +1010,61 @@ XPCOMUtils.defineLazyPreferenceGetter(th
           top: getPercentagePosition(box.top, fullDimension),
         });
       } else {
         styleBox.applyStyles({
           left: getPercentagePosition(box.left, fullDimension),
         });
       }
     } else {
+      LOG(`Adjust position when 'snap-to-lines' is false.`);
       // (snap-to-lines if false) spec 7.2.10.1 ~ 7.2.10.2
       if (cue.lineAlign != "start") {
         const isCenterAlign = cue.lineAlign == "center";
         const movingDirection = isWritingDirectionHorizontal ? "-y" : "-x";
         if (isWritingDirectionHorizontal) {
           box.move(movingDirection, isCenterAlign ? box.height : box.height / 2);
         } else {
           box.move(movingDirection, isCenterAlign ? box.width : box.width / 2);
         }
       }
 
       // spec 7.2.10.3
       let bestPosition = {},
           specifiedPosition = box.clone(),
           outsideAreaPercentage = 1; // Highest possible so the first thing we get is better.
       let hasFoundBestPosition = false;
-      const axis = ["-y", "-x", "+x", "+y"];
-      const toMove = styleBox.getFirstLineBoxSize();
+
+      // For the different writing directions, we should have different priority
+      // for the moving direction. For example, if the writing direction is
+      // horizontal, which means the cues will grow from the top to the bottom,
+      // then moving cues along the `y` axis should be more important than moving
+      // cues along the `x` axis, and vice versa for those cues growing from the
+      // left to right, or from the right to the left. We don't follow the exact
+      // way which the spec requires, see the reason in bug1575460.
+      function getAxis(writingDirection) {
+        if (writingDirection == "") {
+          return ["+y", "-y", "+x", "-x"];
+        }
+        // Growing from left to right.
+        if (writingDirection == "lr") {
+          return ["+x", "-x", "+y", "-y"];
+        }
+        // Growing from right to left.
+        return ["-x", "+x", "+y", "-y"];
+      }
+      const axis = getAxis(cue.vertical);
+
+      // This factor effects the granularity of the moving unit, when using the
+      // factor=1 often moves too much and results in too many redudant spaces
+      // between boxes. So we can increase the factor to slightly reduce the
+      // move we do every time, but still can preverse the reasonable spaces
+      // between boxes.
+      const factor = 4;
+      const toMove = styleBox.getFirstLineBoxSize() / factor;
       for (let i = 0; i < axis.length && !hasFoundBestPosition; i++) {
         while (!box.isOutsideTheAxisBoundary(containerBox, axis[i]) &&
                (!box.within(containerBox) || box.overlapsAny(outputBoxes))) {
           box.move(axis[i], toMove);
         }
         // We found a spot where we aren't overlapping anything. This is our
         // best position.
         if (box.within(containerBox)) {
@@ -1060,19 +1078,24 @@ XPCOMUtils.defineLazyPreferenceGetter(th
         if (outsideAreaPercentage > p) {
           bestPosition = box.clone();
           outsideAreaPercentage = p;
         }
         // Reset the box position to the specified position.
         box = specifiedPosition.clone();
       }
 
+      // Can not find a place to place this box inside the rendering area.
+      if (!box.within(containerBox)) {
+        return null;
+      }
+
       styleBox.applyStyles({
-        top: getPercentagePosition(box.top, fullDimension),
-        left: getPercentagePosition(box.left, fullDimension),
+        top: getPercentagePosition(box.top, containerBox.height),
+        left: getPercentagePosition(box.left, containerBox.width),
       });
     }
 
     // In order to not be affected by CSS scale, so we use '%' to make sure the
     // cue can stick in the right position.
     function getPercentagePosition(position, fullDimension) {
       return (position / fullDimension) * 100 + "%";
     }
--- a/dom/payments/MerchantValidationEvent.cpp
+++ b/dom/payments/MerchantValidationEvent.cpp
@@ -4,23 +4,25 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/MerchantValidationEvent.h"
 #include "nsNetCID.h"
 #include "mozilla/dom/PaymentRequest.h"
 #include "mozilla/dom/Location.h"
 #include "mozilla/dom/URL.h"
+#include "mozilla/ResultExtensions.h"
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_INHERITED(MerchantValidationEvent, Event, mRequest)
+NS_IMPL_CYCLE_COLLECTION_INHERITED(MerchantValidationEvent, Event,
+                                   mValidationURL, mRequest)
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(MerchantValidationEvent, Event)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MerchantValidationEvent)
 NS_INTERFACE_MAP_END_INHERITING(Event)
 
 NS_IMPL_ADDREF_INHERITED(MerchantValidationEvent, Event)
@@ -38,64 +40,58 @@ already_AddRefed<MerchantValidationEvent
 
 // Internal JS object constructor
 already_AddRefed<MerchantValidationEvent> MerchantValidationEvent::Constructor(
     EventTarget* aOwner, const nsAString& aType,
     const MerchantValidationEventInit& aEventInitDict, ErrorResult& aRv) {
   RefPtr<MerchantValidationEvent> e = new MerchantValidationEvent(aOwner);
   bool trusted = e->Init(aOwner);
   e->InitEvent(aType, aEventInitDict.mBubbles, aEventInitDict.mCancelable);
-  if (!e->init(aEventInitDict, aRv)) {
+  nsString errMsg;
+  Result<Ok, nsresult> rv = e->init(aEventInitDict, errMsg);
+  if (rv.isErr()) {
+    auto err = rv.unwrapErr();
+    switch (err) {
+      case NS_ERROR_TYPE_ERR:
+        aRv.ThrowRangeError<MSG_ILLEGAL_RANGE_PR_CONSTRUCTOR>(errMsg);
+        break;
+      case NS_ERROR_MALFORMED_URI:
+        aRv.ThrowTypeError<MSG_INVALID_URL>(aEventInitDict.mValidationURL);
+        break;
+      default:
+        aRv.Throw(err);
+        break;
+    }
     return nullptr;
   }
   e->SetTrusted(trusted);
   e->SetComposed(aEventInitDict.mComposed);
   return e.forget();
 }
 
-bool MerchantValidationEvent::init(
-    const MerchantValidationEventInit& aEventInitDict, ErrorResult& aRv) {
+Result<Ok, nsresult> MerchantValidationEvent::init(
+    const MerchantValidationEventInit& aEventInitDict, nsString& errMsg) {
   // Check methodName is valid
   if (!aEventInitDict.mMethodName.IsEmpty()) {
-    nsString errMsg;
-    auto rv = PaymentRequest::IsValidPaymentMethodIdentifier(
+    nsresult rv = PaymentRequest::IsValidPaymentMethodIdentifier(
         aEventInitDict.mMethodName, errMsg);
     if (NS_FAILED(rv)) {
-      aRv.ThrowRangeError<MSG_ILLEGAL_RANGE_PR_CONSTRUCTOR>(errMsg);
-      return false;
+      return Err(rv);
     }
   }
   SetMethodName(aEventInitDict.mMethodName);
   nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetParentObject());
   auto doc = window->GetExtantDoc();
   if (!doc) {
-    aRv.Throw(NS_ERROR_UNEXPECTED);
-    return false;
+    return Err(NS_ERROR_UNEXPECTED);
   }
-  auto principal = doc->NodePrincipal();
-
-  nsCOMPtr<nsIURI> baseURI;
-  principal->GetURI(getter_AddRefs(baseURI));
 
-  nsresult rv;
-  nsCOMPtr<nsIURI> validationUri;
-  rv = NS_NewURI(getter_AddRefs(validationUri), aEventInitDict.mValidationURL,
-                 nullptr, baseURI);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    aRv.ThrowTypeError<MSG_INVALID_URL>(aEventInitDict.mValidationURL);
-    return false;
-  }
-  nsAutoCString utf8href;
-  rv = validationUri->GetSpec(utf8href);
-  if (NS_FAILED(rv)) {
-    aRv.Throw(NS_ERROR_DOM_BAD_URI);
-    return false;
-  }
-  CopyUTF8toUTF16(utf8href, mValidationURL);
-  return true;
+  MOZ_TRY_VAR(mValidationURL,
+              doc->ResolveWithBaseURI(aEventInitDict.mValidationURL));
+  return Ok();
 }
 
 MerchantValidationEvent::MerchantValidationEvent(EventTarget* aOwner)
     : Event(aOwner, nullptr, nullptr), mWaitForUpdate(false) {
   MOZ_ASSERT(aOwner);
 }
 
 void MerchantValidationEvent::ResolvedCallback(JSContext* aCx,
@@ -156,32 +152,32 @@ void MerchantValidationEvent::SetRequest
   MOZ_ASSERT(IsTrusted());
   MOZ_ASSERT(!mRequest);
   MOZ_ASSERT(aRequest);
 
   mRequest = aRequest;
 }
 
 void MerchantValidationEvent::GetValidationURL(nsAString& aValidationURL) {
-  aValidationURL.Assign(mValidationURL);
-}
-
-void MerchantValidationEvent::SetValidationURL(nsAString& aValidationURL) {
-  mValidationURL.Assign(aValidationURL);
+  nsAutoCString utf8href;
+  nsresult rv = mValidationURL->GetSpec(utf8href);
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
+  Unused << rv;
+  aValidationURL.Assign(NS_ConvertUTF8toUTF16(utf8href));
 }
 
 void MerchantValidationEvent::GetMethodName(nsAString& aMethodName) {
   aMethodName.Assign(mMethodName);
 }
 
 void MerchantValidationEvent::SetMethodName(const nsAString& aMethodName) {
   mMethodName.Assign(aMethodName);
 }
 
-MerchantValidationEvent::~MerchantValidationEvent() {}
+MerchantValidationEvent::~MerchantValidationEvent() = default;
 
 JSObject* MerchantValidationEvent::WrapObjectInternal(
     JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
   return MerchantValidationEvent_Binding::Wrap(aCx, this, aGivenProto);
 }
 
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/payments/MerchantValidationEvent.h
+++ b/dom/payments/MerchantValidationEvent.h
@@ -4,16 +4,17 @@
  * 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/. */
 
 #ifndef mozilla_dom_MerchantValidationEvent_h
 #define mozilla_dom_MerchantValidationEvent_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/ErrorResult.h"
+#include "mozilla/Result.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/MerchantValidationEventBinding.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 
 namespace mozilla {
 namespace dom {
 
 class Promise;
@@ -44,31 +45,29 @@ class MerchantValidationEvent : public E
       const MerchantValidationEventInit& aEventInitDict, ErrorResult& aRv);
 
   void Complete(Promise& aPromise, ErrorResult& aRv);
 
   void SetRequest(PaymentRequest* aRequest);
 
   void GetValidationURL(nsAString& aValidationURL);
 
-  void SetValidationURL(nsAString& aValidationURL);
-
   void GetMethodName(nsAString& aMethodName);
 
   void SetMethodName(const nsAString& aMethodName);
 
  protected:
-  bool init(const MerchantValidationEventInit& aEventInitDict,
-            ErrorResult& aRv);
+  Result<Ok, nsresult> init(const MerchantValidationEventInit& aEventInitDict,
+                            nsString& errMsg);
   ~MerchantValidationEvent();
 
  private:
   // Indicating whether an Complete()-initiated update is currently in progress.
   bool mWaitForUpdate;
-  nsString mValidationURL;
+  nsCOMPtr<nsIURI> mValidationURL;
   RefPtr<PaymentRequest> mRequest;
   nsString mMethodName;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // mozilla_dom_MerchantValidationEvent_h
old mode 100755
new mode 100644
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -184,30 +184,23 @@ class MOZ_RAII AutoSetTemporaryAncestorL
 };
 
 /********************************************************
  * mozilla::HTMLEditRules
  ********************************************************/
 
 HTMLEditRules::HTMLEditRules() : mHTMLEditor(nullptr), mInitialized(false) {
   mIsHTMLEditRules = true;
-  InitFields();
-}
-
-void HTMLEditRules::InitFields() {
-  mHTMLEditor = nullptr;
 }
 
 nsresult HTMLEditRules::Init(TextEditor* aTextEditor) {
   if (NS_WARN_IF(!aTextEditor) || NS_WARN_IF(!aTextEditor->AsHTMLEditor())) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  InitFields();
-
   mHTMLEditor = aTextEditor->AsHTMLEditor();
   if (NS_WARN_IF(!mHTMLEditor)) {
     return NS_ERROR_FAILURE;
   }
 
   AutoSafeEditorData setData(*this, *mHTMLEditor);
 
   nsresult rv = TextEditRules::Init(aTextEditor);
@@ -1111,17 +1104,18 @@ nsresult HTMLEditRules::GetParagraphStat
 
   // post process list.  We need to replace any block nodes that are not format
   // nodes with their content.  This is so we only have to look "up" the
   // hierarchy to find format nodes, instead of both up and down.
   for (int32_t i = arrayOfNodes.Length() - 1; i >= 0; i--) {
     auto& curNode = arrayOfNodes[i];
     nsAutoString format;
     // if it is a known format node we have it easy
-    if (IsBlockNode(curNode) && !HTMLEditUtils::IsFormatNode(curNode)) {
+    if (HTMLEditor::NodeIsBlockStatic(curNode) &&
+        !HTMLEditUtils::IsFormatNode(curNode)) {
       // arrayOfNodes.RemoveObject(curNode);
       rv = AppendInnerFormatNodes(arrayOfNodes, curNode);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     }
   }
 
@@ -1143,17 +1137,17 @@ nsresult HTMLEditRules::GetParagraphStat
   }
 
   // loop through the nodes in selection and examine their paragraph format
   for (auto& curNode : Reversed(arrayOfNodes)) {
     nsAutoString format;
     // if it is a known format node we have it easy
     if (HTMLEditUtils::IsFormatNode(curNode)) {
       GetFormatString(curNode, format);
-    } else if (IsBlockNode(curNode)) {
+    } else if (HTMLEditor::NodeIsBlockStatic(curNode)) {
       // this is a div or some other non-format block.
       // we should ignore it.  Its children were appended to this list
       // by AppendInnerFormatNodes() call above.  We will get needed
       // info when we examine them instead.
       continue;
     } else {
       nsINode* node = curNode->GetParentNode();
       while (node) {
@@ -1191,17 +1185,17 @@ nsresult HTMLEditRules::AppendInnerForma
 
   // we only need to place any one inline inside this node onto
   // the list.  They are all the same for purposes of determining
   // paragraph style.  We use foundInline to track this as we are
   // going through the children in the loop below.
   bool foundInline = false;
   for (nsIContent* child = aNode->GetFirstChild(); child;
        child = child->GetNextSibling()) {
-    bool isBlock = IsBlockNode(*child);
+    bool isBlock = HTMLEditor::NodeIsBlockStatic(*child);
     bool isFormat = HTMLEditUtils::IsFormatNode(child);
     if (isBlock && !isFormat) {
       // if it's a div, etc., recurse
       AppendInnerFormatNodes(aArray, child);
     } else if (isFormat) {
       aArray.AppendElement(*child);
     } else if (!foundInline) {
       // if this is the first inline we've found, use it
@@ -2039,17 +2033,19 @@ nsresult HTMLEditRules::InsertBRElement(
   // the break.  This is because the break is on the same line we were on,
   // but the next content will be on the following line.
 
   // An exception to this is if the break has a next sibling that is a block
   // node.  Then we stick to the left to avoid an uber caret.
   nsIContent* nextSiblingOfBRElement = brElement->GetNextSibling();
   ErrorResult error;
   SelectionRefPtr()->SetInterlinePosition(
-      !(nextSiblingOfBRElement && IsBlockNode(*nextSiblingOfBRElement)), error);
+      !(nextSiblingOfBRElement &&
+        HTMLEditor::NodeIsBlockStatic(*nextSiblingOfBRElement)),
+      error);
   NS_WARNING_ASSERTION(!error.Failed(),
                        "Failed to set or unset interline position");
   error = NS_OK;
   SelectionRefPtr()->Collapse(afterBRElement, error);
   if (NS_WARN_IF(!CanHandleEditAction())) {
     error.SuppressException();
     return NS_ERROR_EDITOR_DESTROYED;
   }
@@ -2174,17 +2170,17 @@ EditActionResult HTMLEditRules::SplitMai
   if (NS_WARN_IF(error.Failed())) {
     return EditActionIgnored(error.StealNSResult());
   }
 
   // if citeNode wasn't a block, we might also want another break before it.
   // We need to examine the content both before the br we just added and also
   // just after it.  If we don't have another br or block boundary adjacent,
   // then we will need a 2nd br added to achieve blank line that user expects.
-  if (IsInlineNode(*citeNode)) {
+  if (HTMLEditor::NodeIsInlineStatic(*citeNode)) {
     // Use DOM point which we tried to collapse to.
     EditorDOMPoint pointToCreateNewBrNode(atBrNode.GetContainer(),
                                           atBrNode.Offset());
 
     WSRunObject wsObj(&HTMLEditorRef(), pointToCreateNewBrNode);
     WSType wsType;
     wsObj.PriorVisibleNode(pointToCreateNewBrNode, nullptr, nullptr, &wsType);
     if (wsType == WSType::normalWS || wsType == WSType::text ||
@@ -3218,17 +3214,17 @@ nsresult HTMLEditRules::InsertBRIfNeeded
 
   EditorDOMPoint atStartOfSelection(
       EditorBase::GetStartPoint(*SelectionRefPtr()));
   if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
     return NS_ERROR_FAILURE;
   }
 
   // inline elements don't need any br
-  if (!IsBlockNode(*atStartOfSelection.GetContainer())) {
+  if (!HTMLEditor::NodeIsBlockStatic(*atStartOfSelection.GetContainer())) {
     return NS_OK;
   }
 
   // examine selection
   WSRunObject wsObj(&HTMLEditorRef(), atStartOfSelection);
   if (((wsObj.mStartReason & WSType::block) ||
        (wsObj.mStartReason & WSType::br)) &&
       (wsObj.mEndReason & WSType::block)) {
@@ -3677,17 +3673,17 @@ EditActionResult HTMLEditRules::MoveBloc
                                   arrayOfNodes, TouchContent::yes);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return EditActionIgnored(rv);
   }
 
   EditActionResult ret(NS_OK);
   for (uint32_t i = 0; i < arrayOfNodes.Length(); i++) {
     // get the node to act on
-    if (IsBlockNode(arrayOfNodes[i])) {
+    if (HTMLEditor::NodeIsBlockStatic(arrayOfNodes[i])) {
       // For block nodes, move their contents only, then delete block.
       ret |= MoveContents(MOZ_KnownLive(*arrayOfNodes[i]->AsElement()),
                           aLeftBlock, &aLeftOffset);
       if (NS_WARN_IF(ret.Failed())) {
         return ret;
       }
       rv = MOZ_KnownLive(HTMLEditorRef())
                .DeleteNodeWithTransaction(MOZ_KnownLive(*arrayOfNodes[i]));
@@ -4287,17 +4283,17 @@ nsresult HTMLEditRules::MakeList(nsAtom&
       // atCurNode is now referring the right node with mOffset but
       // referring the left node with mRef.  So, invalidate it now.
       atCurNode.Clear();
     }
 
     // if curNode isn't a list item, we must wrap it in one
     nsCOMPtr<Element> listItem;
     if (!HTMLEditUtils::IsListItem(curNode)) {
-      if (IsInlineNode(curNode) && prevListItem) {
+      if (HTMLEditor::NodeIsInlineStatic(curNode) && prevListItem) {
         // this is a continuation of some inline nodes that belong together in
         // the same list item.  use prevListItem
         rv = MOZ_KnownLive(HTMLEditorRef())
                  .MoveNodeToEndWithTransaction(*curNode, *prevListItem);
         if (NS_WARN_IF(!CanHandleEditAction())) {
           return NS_ERROR_EDITOR_DESTROYED;
         }
         if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -4320,17 +4316,17 @@ nsresult HTMLEditRules::MakeList(nsAtom&
                          .InsertContainerWithTransaction(*curNode, aItemType);
           if (NS_WARN_IF(!CanHandleEditAction())) {
             return NS_ERROR_EDITOR_DESTROYED;
           }
           if (NS_WARN_IF(!listItem)) {
             return NS_ERROR_FAILURE;
           }
         }
-        if (IsInlineNode(curNode)) {
+        if (HTMLEditor::NodeIsInlineStatic(curNode)) {
           prevListItem = listItem;
         } else {
           prevListItem = nullptr;
         }
       }
     } else {
       listItem = curNode->AsElement();
     }
@@ -4909,17 +4905,17 @@ nsresult HTMLEditRules::IndentAroundSele
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
       continue;
     }
 
     // Not a list item.
 
-    if (IsBlockNode(*curNode)) {
+    if (HTMLEditor::NodeIsBlockStatic(*curNode)) {
       nsresult rv =
           IncreaseMarginToIndent(MOZ_KnownLive(*curNode->AsElement()));
       if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
         return NS_ERROR_EDITOR_DESTROYED;
       }
       NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to inrease indentation");
       curQuote = nullptr;
       continue;
@@ -5456,17 +5452,17 @@ SplitRangeOffFromNodeResult HTMLEditRule
       }
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return SplitRangeOffFromNodeResult(rv);
       }
       continue;
     }
 
     // Is it a block with a 'margin' property?
-    if (useCSS && IsBlockNode(curNode)) {
+    if (useCSS && HTMLEditor::NodeIsBlockStatic(curNode)) {
       nsAtom& marginProperty = MarginPropertyAtomForIndent(curNode);
       nsAutoString value;
       CSSEditUtils::GetSpecifiedProperty(curNode, marginProperty, value);
       if (NS_WARN_IF(!CanHandleEditAction())) {
         return SplitRangeOffFromNodeResult(NS_ERROR_EDITOR_DESTROYED);
       }
       float f;
       RefPtr<nsAtom> unit;
@@ -5971,17 +5967,17 @@ nsresult HTMLEditRules::CreateStyleForIn
   }
   return NS_OK;
 }
 
 bool HTMLEditRules::IsEmptyBlockElement(Element& aElement,
                                         IgnoreSingleBR aIgnoreSingleBR) {
   MOZ_ASSERT(IsEditorDataAvailable());
 
-  if (NS_WARN_IF(!IsBlockNode(aElement))) {
+  if (NS_WARN_IF(!HTMLEditor::NodeIsBlockStatic(aElement))) {
     return false;
   }
   bool isEmpty = true;
   nsresult rv = HTMLEditorRef().IsEmptyNode(
       &aElement, &isEmpty, aIgnoreSingleBR == IgnoreSingleBR::eYes);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return false;
   }
@@ -6108,17 +6104,17 @@ nsresult HTMLEditRules::AlignContentsAtS
       // Making use of html structure... if next node after where we are
       // putting our div is not a block, then the br we found is in same block
       // we are, so it's safe to consume it.
       nsCOMPtr<nsIContent> sibling;
       if (pointToInsertDiv.GetChild()) {
         sibling =
             HTMLEditorRef().GetNextHTMLSibling(pointToInsertDiv.GetChild());
       }
-      if (sibling && !IsBlockNode(*sibling)) {
+      if (sibling && !HTMLEditor::NodeIsBlockStatic(*sibling)) {
         AutoEditorDOMPointChildInvalidator lockOffset(pointToInsertDiv);
         rv = MOZ_KnownLive(HTMLEditorRef())
                  .DeleteNodeWithTransaction(*brContent);
         if (NS_WARN_IF(!CanHandleEditAction())) {
           return NS_ERROR_EDITOR_DESTROYED;
         }
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return rv;
@@ -6389,17 +6385,17 @@ nsresult HTMLEditRules::AlignBlockConten
 }
 
 nsresult HTMLEditRules::MaybeDeleteTopMostEmptyAncestor(
     nsINode& aStartNode, Element& aEditingHostElement,
     nsIEditor::EDirection aAction, bool* aHandled) {
   MOZ_ASSERT(IsEditorDataAvailable());
 
   // If the editing host is an inline element, bail out early.
-  if (IsInlineNode(aEditingHostElement)) {
+  if (HTMLEditor::NodeIsInlineStatic(aEditingHostElement)) {
     return NS_OK;
   }
 
   // If we are inside an empty block, delete it.  Note: do NOT delete table
   // elements this way.
   RefPtr<Element> block = HTMLEditorRef().GetBlock(aStartNode);
   RefPtr<Element> emptyBlock;
   if (block && block != &aEditingHostElement) {
@@ -6951,17 +6947,17 @@ EditorDOMPoint HTMLEditRules::GetPromote
 
     // look back through any further inline nodes that aren't across a <br>
     // from us, and that are enclosed in the same block.
     nsCOMPtr<nsINode> priorNode =
         HTMLEditorRef().GetPreviousEditableHTMLNodeInBlock(point);
 
     while (priorNode && priorNode->GetParentNode() &&
            !HTMLEditorRef().IsVisibleBRElement(priorNode) &&
-           !IsBlockNode(*priorNode)) {
+           !HTMLEditor::NodeIsBlockStatic(*priorNode)) {
       point.Set(priorNode);
       priorNode = HTMLEditorRef().GetPreviousEditableHTMLNodeInBlock(point);
     }
 
     // finding the real start for this point.  look up the tree for as long as
     // we are the first node in the container, and as long as we haven't hit
     // the body node.
     nsCOMPtr<nsIContent> nearNode =
@@ -7025,17 +7021,18 @@ EditorDOMPoint HTMLEditRules::GetPromote
   //     * <div contenteditable>foo[]<b contenteditable="false">bar</b></div>
   //     * <div contenteditable>foo[]<b>bar</b></div>
   //     * <div contenteditable>foo[]<b contenteditable="false">bar</b>baz</div>
   //     Only in the first case, after the caret position isn't wrapped with
   //     new <div> element.
   nsCOMPtr<nsIContent> nextNode =
       HTMLEditorRef().GetNextEditableHTMLNodeInBlock(point);
 
-  while (nextNode && !IsBlockNode(*nextNode) && nextNode->GetParentNode()) {
+  while (nextNode && !HTMLEditor::NodeIsBlockStatic(*nextNode) &&
+         nextNode->GetParentNode()) {
     point.Set(nextNode);
     if (NS_WARN_IF(!point.AdvanceOffset())) {
       break;
     }
     if (HTMLEditorRef().IsVisibleBRElement(nextNode)) {
       break;
     }
 
@@ -7342,17 +7339,18 @@ nsresult HTMLEditRules::GetNodesForOpera
       aEditSubAction == EditSubAction::eCreateOrChangeList ||
       aEditSubAction == EditSubAction::eSetOrClearAlignment ||
       aEditSubAction == EditSubAction::eSetPositionToAbsolute ||
       aEditSubAction == EditSubAction::eIndent ||
       aEditSubAction == EditSubAction::eOutdent) {
     for (int32_t i = aOutArrayOfNodes.Length() - 1; i >= 0; i--) {
       OwningNonNull<nsINode> node = aOutArrayOfNodes[i];
       // XXX Why do we run this loop even when aTouchContent is "no"?
-      if (aTouchContent == TouchContent::yes && IsInlineNode(node) &&
+      if (aTouchContent == TouchContent::yes &&
+          HTMLEditor::NodeIsInlineStatic(node) &&
           HTMLEditorRef().IsContainer(node) && !EditorBase::IsTextNode(node)) {
         nsTArray<OwningNonNull<nsINode>> arrayOfInlines;
         nsresult rv = BustUpInlinesAtBRs(MOZ_KnownLive(*node->AsContent()),
                                          arrayOfInlines);
         if (NS_WARN_IF(NS_FAILED(rv))) {
           return rv;
         }
 
@@ -7663,17 +7661,17 @@ nsresult HTMLEditRules::BustUpInlinesAtB
   aOutArrayOfNodes.AppendElement(*nextNode);
 
   return NS_OK;
 }
 
 nsIContent* HTMLEditRules::GetHighestInlineParent(nsINode& aNode) const {
   MOZ_ASSERT(IsEditorDataAvailable());
 
-  if (!aNode.IsContent() || IsBlockNode(aNode)) {
+  if (!aNode.IsContent() || HTMLEditor::NodeIsBlockStatic(aNode)) {
     return nullptr;
   }
 
   Element* host = HTMLEditorRef().GetActiveEditingHost();
   if (NS_WARN_IF(!host)) {
     return nullptr;
   }
 
@@ -7688,17 +7686,17 @@ nsIContent* HTMLEditRules::GetHighestInl
   //     calling this expensive method.
   if (NS_WARN_IF(!EditorUtils::IsDescendantOf(aNode, *host))) {
     return nullptr;
   }
 
   // Looks for the highest inline parent in the editing host.
   nsIContent* content = aNode.AsContent();
   for (nsIContent* parent = content->GetParent();
-       parent && parent != host && IsInlineNode(*parent);
+       parent && parent != host && HTMLEditor::NodeIsInlineStatic(*parent);
        parent = parent->GetParent()) {
     content = parent;
   }
   return content;
 }
 
 nsresult HTMLEditRules::GetNodesFromPoint(
     const EditorDOMPoint& aPoint, EditSubAction aEditSubAction,
@@ -8645,17 +8643,17 @@ nsresult HTMLEditRules::RemoveBlockStyle
       GetChildNodesForOperation(*curNode, childArray);
       nsresult rv = RemoveBlockStyle(childArray);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
       continue;
     }
 
-    if (IsInlineNode(curNode)) {
+    if (HTMLEditor::NodeIsInlineStatic(curNode)) {
       if (curBlock) {
         // If so, is this node a descendant?
         if (EditorUtils::IsDescendantOf(*curNode, *curBlock)) {
           // Then we don't need to do anything different for this node
           lastNode = curNode->AsContent();
           continue;
         }
         // Otherwise, we have progressed beyond end of curBlock, so let's
@@ -8726,17 +8724,18 @@ nsresult HTMLEditRules::ApplyBlockStyle(
       newBlock = nullptr;
       continue;
     }
 
     EditorDOMPoint atCurNode(curNode);
 
     // Is it already the right kind of block, or an uneditable block?
     if (curNode->IsHTMLElement(&aBlockTag) ||
-        (!HTMLEditorRef().IsEditable(curNode) && IsBlockNode(curNode))) {
+        (!HTMLEditorRef().IsEditable(curNode) &&
+         HTMLEditor::NodeIsBlockStatic(curNode))) {
       // Forget any previous block used for previous inline nodes
       curBlock = nullptr;
       // Do nothing to this block
       continue;
     }
 
     // If curNode is a address, p, header, address, or pre, replace it with a
     // new block of correct type.
@@ -8872,17 +8871,17 @@ nsresult HTMLEditRules::ApplyBlockStyle(
         return NS_ERROR_EDITOR_DESTROYED;
       }
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
       continue;
     }
 
-    if (IsInlineNode(curNode)) {
+    if (HTMLEditor::NodeIsInlineStatic(curNode)) {
       // If curNode is inline, pull it into curBlock.  Note: it's assumed that
       // consecutive inline nodes in aNodeArray are actually members of the
       // same block parent.  This happens to be true now as a side effect of
       // how aNodeArray is contructed, but some additional logic should be
       // added here if that should change
       //
       // If curNode is a non editable, drop it if we are going to <pre>.
       if (&aBlockTag == nsGkAtoms::pre &&
@@ -9404,31 +9403,31 @@ void HTMLEditRules::CheckInterlinePositi
   }
 
   // Are we after a block?  If so try set caret to following content
   if (atStartOfSelection.GetChild()) {
     node = HTMLEditorRef().GetPriorHTMLSibling(atStartOfSelection.GetChild());
   } else {
     node = nullptr;
   }
-  if (node && IsBlockNode(*node)) {
+  if (node && HTMLEditor::NodeIsBlockStatic(*node)) {
     IgnoredErrorResult ignoredError;
     SelectionRefPtr()->SetInterlinePosition(true, ignoredError);
     NS_WARNING_ASSERTION(!ignoredError.Failed(),
                          "Failed to set interline position");
     return;
   }
 
   // Are we before a block?  If so try set caret to prior content
   if (atStartOfSelection.GetChild()) {
     node = HTMLEditorRef().GetNextHTMLSibling(atStartOfSelection.GetChild());
   } else {
     node = nullptr;
   }
-  if (node && IsBlockNode(*node)) {
+  if (node && HTMLEditor::NodeIsBlockStatic(*node)) {
     IgnoredErrorResult ignoredError;
     SelectionRefPtr()->SetInterlinePosition(false, ignoredError);
     NS_WARNING_ASSERTION(!ignoredError.Failed(),
                          "Failed to unset interline position");
   }
 }
 
 nsresult HTMLEditRules::AdjustSelection(nsIEditor::EDirection aAction) {
@@ -9855,17 +9854,18 @@ nsresult HTMLEditRules::SelectionEndpoin
     }
   }
   return NS_OK;
 }
 
 bool HTMLEditRules::IsEmptyInline(nsINode& aNode) {
   MOZ_ASSERT(IsEditorDataAvailable());
 
-  if (IsInlineNode(aNode) && HTMLEditorRef().IsContainer(&aNode)) {
+  if (HTMLEditor::NodeIsInlineStatic(aNode) &&
+      HTMLEditorRef().IsContainer(&aNode)) {
     bool isEmpty = true;
     HTMLEditorRef().IsEmptyNode(&aNode, &isEmpty);
     return isEmpty;
   }
   return false;
 }
 
 bool HTMLEditRules::ListIsEmptyLine(
@@ -10114,17 +10114,17 @@ nsresult HTMLEditRules::ConfirmSelection
 
   return NS_OK;
 }
 
 nsresult HTMLEditRules::InsertBRIfNeededInternal(nsINode& aNode,
                                                  bool aForPadding) {
   MOZ_ASSERT(IsEditorDataAvailable());
 
-  if (!IsBlockNode(aNode)) {
+  if (!HTMLEditor::NodeIsBlockStatic(aNode)) {
     return NS_OK;
   }
 
   bool isEmpty;
   nsresult rv = HTMLEditorRef().IsEmptyNode(&aNode, &isEmpty);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
@@ -10401,17 +10401,18 @@ nsresult HTMLEditRules::RemoveAlignment(
                .RemoveContainerWithTransaction(
                    MOZ_KnownLive(*child->AsElement()));
       if (NS_WARN_IF(!CanHandleEditAction())) {
         return NS_ERROR_EDITOR_DESTROYED;
       }
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
-    } else if (IsBlockNode(*child) || child->IsHTMLElement(nsGkAtoms::hr)) {
+    } else if (HTMLEditor::NodeIsBlockStatic(*child) ||
+               child->IsHTMLElement(nsGkAtoms::hr)) {
       // the current node is a block element
       if (HTMLEditUtils::SupportsAlignAttr(*child)) {
         // remove the ALIGN attribute if this element can have it
         nsresult rv =
             MOZ_KnownLive(HTMLEditorRef())
                 .RemoveAttributeWithTransaction(
                     MOZ_KnownLive(*child->AsElement()), *nsGkAtoms::align);
         if (NS_WARN_IF(!CanHandleEditAction())) {
@@ -10464,23 +10465,25 @@ nsresult HTMLEditRules::MakeSureElemStar
 
   nsINode* child = aStarts ? HTMLEditorRef().GetFirstEditableChild(aNode)
                            : HTMLEditorRef().GetLastEditableChild(aNode);
   if (NS_WARN_IF(!child)) {
     return NS_OK;
   }
 
   bool foundCR = false;
-  if (IsBlockNode(*child) || child->IsHTMLElement(nsGkAtoms::br)) {
+  if (HTMLEditor::NodeIsBlockStatic(*child) ||
+      child->IsHTMLElement(nsGkAtoms::br)) {
     foundCR = true;
   } else {
     nsINode* sibling = aStarts ? HTMLEditorRef().GetPriorHTMLSibling(&aNode)
                                : HTMLEditorRef().GetNextHTMLSibling(&aNode);
     if (sibling) {
-      if (IsBlockNode(*sibling) || sibling->IsHTMLElement(nsGkAtoms::br)) {
+      if (HTMLEditor::NodeIsBlockStatic(*sibling) ||
+          sibling->IsHTMLElement(nsGkAtoms::br)) {
         foundCR = true;
       }
     } else {
       foundCR = true;
     }
   }
   if (!foundCR) {
     EditorDOMPoint pointToInsert;
@@ -10522,17 +10525,18 @@ nsresult HTMLEditRules::MakeSureElemStar
   return NS_OK;
 }
 
 nsresult HTMLEditRules::AlignBlock(Element& aElement,
                                    const nsAString& aAlignType,
                                    ResetAlignOf aResetAlignOf) {
   MOZ_ASSERT(IsEditorDataAvailable());
 
-  if (!IsBlockNode(aElement) && !aElement.IsHTMLElement(nsGkAtoms::hr)) {
+  if (!HTMLEditor::NodeIsBlockStatic(aElement) &&
+      !aElement.IsHTMLElement(nsGkAtoms::hr)) {
     // We deal only with blocks; early way out
     return NS_OK;
   }
 
   nsresult rv = RemoveAlignment(aElement, aAlignType,
                                 aResetAlignOf == ResetAlignOf::OnlyDescendants);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
--- a/editor/libeditor/HTMLEditRules.h
+++ b/editor/libeditor/HTMLEditRules.h
@@ -113,25 +113,18 @@ class HTMLEditRules : public TextEditRul
  protected:
   virtual ~HTMLEditRules() = default;
 
   HTMLEditor& HTMLEditorRef() const {
     MOZ_ASSERT(mData);
     return mData->HTMLEditorRef();
   }
 
-  static bool IsBlockNode(const nsINode& aNode) {
-    return HTMLEditor::NodeIsBlockStatic(&aNode);
-  }
-  static bool IsInlineNode(const nsINode& aNode) { return !IsBlockNode(aNode); }
-
   enum RulesEndpoint { kStart, kEnd };
 
-  void InitFields();
-
   /**
    * Called before inserting something into the editor.
    * This method may removes mBougsNode if there is.  Therefore, this method
    * might cause destroying the editor.
    *
    * @param aCancel             Returns true if the operation is canceled.
    *                            This can be nullptr.
    */
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -734,40 +734,38 @@ nsresult HTMLEditor::HandleKeyPressEvent
   nsAutoString str(aKeyboardEvent->mCharCode);
   return OnInputText(str);
 }
 
 /**
  * Returns true if the id represents an element of block type.
  * Can be used to determine if a new paragraph should be started.
  */
-bool HTMLEditor::NodeIsBlockStatic(const nsINode* aElement) {
-  MOZ_ASSERT(aElement);
-
+bool HTMLEditor::NodeIsBlockStatic(const nsINode& aElement) {
   // We want to treat these as block nodes even though nsHTMLElement says
   // they're not.
-  if (aElement->IsAnyOfHTMLElements(
+  if (aElement.IsAnyOfHTMLElements(
           nsGkAtoms::body, nsGkAtoms::head, nsGkAtoms::tbody, nsGkAtoms::thead,
           nsGkAtoms::tfoot, nsGkAtoms::tr, nsGkAtoms::th, nsGkAtoms::td,
           nsGkAtoms::dt, nsGkAtoms::dd)) {
     return true;
   }
 
   return nsHTMLElement::IsBlock(
-      nsHTMLTags::AtomTagToId(aElement->NodeInfo()->NameAtom()));
+      nsHTMLTags::AtomTagToId(aElement.NodeInfo()->NameAtom()));
 }
 
 NS_IMETHODIMP
 HTMLEditor::NodeIsBlock(nsINode* aNode, bool* aIsBlock) {
   *aIsBlock = IsBlockNode(aNode);
   return NS_OK;
 }
 
 bool HTMLEditor::IsBlockNode(nsINode* aNode) const {
-  return aNode && NodeIsBlockStatic(aNode);
+  return aNode && HTMLEditor::NodeIsBlockStatic(*aNode);
 }
 
 /**
  * GetBlockNodeParent returns enclosing block level ancestor, if any.
  */
 Element* HTMLEditor::GetBlockNodeParent(nsINode* aNode,
                                         nsINode* aAncestorLimiter) {
   MOZ_ASSERT(aNode);
@@ -778,17 +776,17 @@ Element* HTMLEditor::GetBlockNodeParent(
   // The caller has already reached the limiter.
   if (aNode == aAncestorLimiter) {
     return nullptr;
   }
 
   nsCOMPtr<nsINode> p = aNode->GetParentNode();
 
   while (p) {
-    if (NodeIsBlockStatic(p)) {
+    if (HTMLEditor::NodeIsBlockStatic(*p)) {
       return p->AsElement();
     }
     // Now, we have reached the limiter, there is no block in its ancestors.
     if (p == aAncestorLimiter) {
       return nullptr;
     }
     p = p->GetParentNode();
   }
@@ -799,17 +797,17 @@ Element* HTMLEditor::GetBlockNodeParent(
 /**
  * Returns the node if it's a block, otherwise GetBlockNodeParent
  */
 Element* HTMLEditor::GetBlock(nsINode& aNode, nsINode* aAncestorLimiter) {
   MOZ_ASSERT(!aAncestorLimiter || &aNode == aAncestorLimiter ||
                  EditorUtils::IsDescendantOf(aNode, *aAncestorLimiter),
              "aNode isn't in aAncestorLimiter");
 
-  if (NodeIsBlockStatic(&aNode)) {
+  if (HTMLEditor::NodeIsBlockStatic(aNode)) {
     return aNode.AsElement();
   }
   return GetBlockNodeParent(&aNode, aAncestorLimiter);
 }
 
 /**
  * IsNextCharInNodeWhitespace() checks the adjacent content in the same node to
  * see if following selection is whitespace or nbsp.
@@ -1925,17 +1923,17 @@ nsresult HTMLEditor::GetCSSBackgroundCol
       nodeToExamine = nodeToExamine->GetParentNode();
     }
     // Return default value due to no parent node
     if (!nodeToExamine) {
       return NS_OK;
     }
     do {
       // is the node to examine a block ?
-      if (NodeIsBlockStatic(nodeToExamine)) {
+      if (HTMLEditor::NodeIsBlockStatic(*nodeToExamine)) {
         // yes it is a block; in that case, the text background color is
         // transparent
         aOutColor.AssignLiteral("transparent");
         break;
       } else {
         // no, it's not; let's retrieve the computed style of background-color
         // for the node to examine
         CSSEditUtils::GetComputedProperty(
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -793,19 +793,29 @@ class HTMLEditor final : public TextEdit
                                          nsIContent** outNode = nullptr,
                                          int32_t* outOffset = 0);
   static void IsPrevCharInNodeWhitespace(nsIContent* aContent, int32_t aOffset,
                                          bool* outIsSpace, bool* outIsNBSP,
                                          nsIContent** outNode = nullptr,
                                          int32_t* outOffset = 0);
 
   /**
-   * @param aElement        Must not be null.
+   * NodeIsBlockStatic() returns true if aElement is an element node and
+   * should be treated as a block.
    */
-  static bool NodeIsBlockStatic(const nsINode* aElement);
+  static bool NodeIsBlockStatic(const nsINode& aElement);
+
+  /**
+   * NodeIsInlineStatic() returns true if aElement is an element node but
+   * shouldn't be treated as a block or aElement is not an element.
+   * XXX This looks odd.  For example, how about a comment node?
+   */
+  static bool NodeIsInlineStatic(const nsINode& aElement) {
+    return !NodeIsBlockStatic(aElement);
+  }
 
   /**
    * extracts an element from the normal flow of the document and
    * positions it, and puts it back in the normal flow.
    * @param aElement [IN] the element
    * @param aEnabled [IN] true to absolutely position the element,
    *                      false to put it back in the normal flow
    */
--- a/editor/libeditor/WSRunObject.cpp
+++ b/editor/libeditor/WSRunObject.cpp
@@ -2041,13 +2041,12 @@ nsresult WSRunObject::Scrub() {
       }
     }
     run = run->mRight;
   }
   return NS_OK;
 }
 
 bool WSRunScanner::IsBlockNode(nsINode* aNode) {
-  return aNode && aNode->IsElement() &&
-         HTMLEditor::NodeIsBlockStatic(aNode->AsElement());
+  return aNode && aNode->IsElement() && HTMLEditor::NodeIsBlockStatic(*aNode);
 }
 
 }  // namespace mozilla
old mode 100755
new mode 100644
old mode 100755
new mode 100644
--- a/js/src/tests/non262/regress/regress-1572988-nurseryRegisterCheck.js
+++ b/js/src/tests/non262/regress/regress-1572988-nurseryRegisterCheck.js
@@ -1,24 +1,38 @@
 // |reftest| skip-if(!this.hasOwnProperty("oomTest"))
 
 // Bug 1572988: Make a bunch of nursery ropes and flatten them with oomTest.
 // The goal is to get an OOM while flattening that makes registering the
 // string's malloc buffer with the nursery fail, triggering an assertion when
 // it gets tenured.
 
 var x = 0;
+var N = 1000; // This failed most of the time on my linux64 box.
+
+// But it can time out on the slower machines.
+if (this.getBuildConfiguration) {
+  for (let [k, v] of Object.entries(getBuildConfiguration())) {
+    if (k.includes("simulator") && v)
+      N = 10;
+    if (k.includes("arm") && v)
+      N = 10;
+    if (k.includes("android") && v)
+      N = 10;
+  }
+}
+
 function makeString() {
     x += 1;
     const extensible = ensureFlatString("aaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + x);
     return ensureFlatString(newRope(extensible, "bbbbbbbbbbbbbbb"));
 }
 
 function f(arr) {
-    for (let i = 0; i < 1000; i++)
+    for (let i = 0; i < N; i++)
         arr.push(makeString());
     return arr;
 }
 
 var globalStore = [];
 function ff() {
   globalStore.push(f([]));
 }
old mode 100755
new mode 100644
old mode 100755
new mode 100644
--- a/js/sub.configure
+++ b/js/sub.configure
@@ -4,17 +4,16 @@
 
 @depends(check_build_environment, prepare_configure_options, prepare_mozconfig,
          old_configure, old_configure_assignments, '--cache-file')
 @imports('errno')
 @imports('itertools')
 @imports('logging')
 @imports('os')
 @imports('pickle')
-@imports('subprocess')
 @imports('sys')
 @imports(_from='__main__', _import='config_status')
 @imports(_from='__builtin__', _import='OSError')
 @imports(_from='__builtin__', _import='open')
 @imports(_from='__builtin__', _import='object')
 @imports(_from='mozbuild.configure', _import='ConfigureSandbox')
 @imports(_from='mozbuild.configure.util', _import='ConfigureOutputHandler')
 @imports(_from='mozbuild.util', _import='encode')
old mode 100755
new mode 100644
old mode 100755
new mode 100644
--- a/mobile/android/app/src/main/res/color/pressed_about_page_header_grey.xml
+++ b/mobile/android/app/src/main/res/color/pressed_about_page_header_grey.xml
@@ -1,12 +1,14 @@
 <!-- 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/. -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
 
     <item android:state_pressed="true"
+          android:color="@color/about_page_header_grey"
           android:drawable="@color/about_page_header_grey" />
 
-    <item android:drawable="@android:color/transparent"/>
+    <item android:color="@android:color/transparent"
+          android:drawable="@android:color/transparent"/>
 
 </selector>
--- a/mobile/android/app/src/main/res/color/recyclerview_selector.xml
+++ b/mobile/android/app/src/main/res/color/recyclerview_selector.xml
@@ -1,12 +1,14 @@
 <!-- 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/. -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
 
     <item android:state_pressed="true"
+          android:color="@color/highlight"
           android:drawable="@color/highlight" />
 
-    <item android:drawable="@android:color/transparent"/>
+    <item android:color="@android:color/transparent"
+          android:drawable="@android:color/transparent"/>
 
 </selector>
--- a/mobile/android/app/src/main/res/color/state_pressed_toolbar_grey_pressed.xml
+++ b/mobile/android/app/src/main/res/color/state_pressed_toolbar_grey_pressed.xml
@@ -1,12 +1,14 @@
 <!-- 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/. -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
 
     <item android:state_pressed="true"
+          android:color="@color/toolbar_grey_pressed"
           android:drawable="@color/toolbar_grey_pressed" />
 
-    <item android:drawable="@android:color/transparent"/>
+    <item android:color="@android:color/transparent"
+          android:drawable="@android:color/transparent"/>
 
 </selector>
--- a/mobile/android/build.mk
+++ b/mobile/android/build.mk
@@ -4,18 +4,28 @@
 
 include  $(topsrcdir)/toolkit/mozapps/installer/package-name.mk
 
 installer:
 	@$(MAKE) -C mobile/android/installer installer
 
 package:
 	# Setting MOZ_GECKOVIEW_JAR makes the installer generate a separate GeckoView JAR
+ifdef MOZ_ANDROID_WITH_FENNEC
 	@$(MAKE) MOZ_GECKOVIEW_JAR=1 -C mobile/android/installer stage-package
 	@$(MAKE) -C mobile/android/installer
+else
+	@$(MAKE) MOZ_GECKOVIEW_JAR=1 -C mobile/android/installer
+endif # MOZ_ANDROID_WITH_FENNEC
+
+stage-package:
+	$(MAKE) MOZ_GECKOVIEW_JAR=1 -C mobile/android/installer stage-package
+ifdef MOZ_ANDROID_WITH_FENNEC
+	$(MAKE) -C mobile/android/installer stage-package
+endif # MOZ_ANDROID_WITH_FENNEC
 
 ifeq ($(OS_TARGET),Android)
 ifneq ($(MOZ_ANDROID_INSTALL_TARGET),)
 ANDROID_SERIAL = $(MOZ_ANDROID_INSTALL_TARGET)
 endif
 ifneq ($(ANDROID_SERIAL),)
 export ANDROID_SERIAL
 else
--- a/mobile/android/gradle/with_gecko_binaries.gradle
+++ b/mobile/android/gradle/with_gecko_binaries.gradle
@@ -27,16 +27,21 @@ ext.configureVariantWithGeckoBinaries = 
              "${omnijarDir}/assets/omni.ja") {
             // Throw an exception if we find multiple, potentially conflicting omni.ja files.
             duplicatesStrategy 'fail'
         }
     }
 
     def syncLibsFromDistDir = task("syncLibsFromDistDirFor${variant.name.capitalize()}", type: Sync) {
         onlyIf {
+            if (!mozconfig.substs.COMPILE_ENVIRONMENT && !mozconfig.substs.MOZ_ARTIFACT_BUILDS) {
+                // We won't have JNI libraries if we're not compiling and we're not downloading
+                // artifacts.  Such a configuration is used for running lints, generating docs, etc.
+                return true
+            }
             if (source.empty) {
                 throw new StopExecutionException("Required JNI libraries not found in ${distDir}/lib.  Have you built and packaged?")
             }
             return true
         }
 
         into("${project.buildDir}/moz.build/src/${variant.name}/jniLibs")
         from("${distDir}/lib")
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
old mode 100755
new mode 100644
--- a/mozglue/build/moz.build
+++ b/mozglue/build/moz.build
@@ -89,16 +89,17 @@ if CONFIG['MOZ_WIDGET_TOOLKIT']:
         blocklist_defs = GENERATED_FILES[blocklist_files]
         blocklist_defs.script = 'gen_dll_blocklist_defs.py:gen_blocklists'
         blocklist_defs.inputs = ['WindowsDllBlocklistDefs.in']
         EXPORTS.mozilla += ['!' + hdr for hdr in blocklist_files]
 
     EXPORTS.mozilla += [
         'arm.h',
         'mips.h',
+        'ppc.h',
         'SSE.h',
         'WindowsDllBlocklist.h',
     ]
 
     if CONFIG['CPU_ARCH'].startswith('x86'):
         SOURCES += [
             'SSE.cpp',
         ]
@@ -108,16 +109,21 @@ if CONFIG['MOZ_WIDGET_TOOLKIT']:
             'arm.cpp',
         ]
 
     if CONFIG['CPU_ARCH'].startswith('mips'):
         SOURCES += [
             'mips.cpp',
         ]
 
+    if CONFIG['CPU_ARCH'].startswith('ppc'):
+        SOURCES += [
+            'ppc.cpp',
+        ]
+
     if CONFIG['MOZ_LINKER']:
         USE_LIBS += [
             'zlib',
         ]
 
 USE_LIBS += [
     'mfbt',
 ]
new file mode 100644
--- /dev/null
+++ b/mozglue/build/ppc.cpp
@@ -0,0 +1,64 @@
+/* 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/. */
+
+/* compile-time and runtime tests for whether to use Power ISA-specific
+ * extensions */
+
+#include "ppc.h"
+#include "mozilla/Unused.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if defined(XP_LINUX)
+// Use the getauxval() function if available.
+// ARCH_3_00 wasn't defined until glibc 2.23, so include just in case.
+#  include <sys/auxv.h>
+#  ifndef PPC_FEATURE2_ARCH_3_00
+#    define PPC_FEATURE2_ARCH_3_00 0x00800000
+#  endif
+#endif
+
+const unsigned PPC_FLAG_VMX = 1;
+const unsigned PPC_FLAG_VSX = 2;
+const unsigned PPC_FLAG_VSX3 = 4;
+
+static signed get_ppc_cpu_flags(void) {
+  // This could be expensive, so cache the result.
+  static signed cpu_flags = -1;
+
+  if (cpu_flags > -1) {  // already checked
+    return cpu_flags;
+  }
+  cpu_flags = 0;
+
+#if defined(XP_LINUX)
+  // Try getauxval().
+  unsigned long int cap = getauxval(AT_HWCAP);
+  unsigned long int cap2 = getauxval(AT_HWCAP2);
+
+  if (cap & PPC_FEATURE_HAS_ALTIVEC) {
+    cpu_flags |= PPC_FLAG_VMX;
+  }
+  if (cap & PPC_FEATURE_HAS_VSX) {
+    cpu_flags |= PPC_FLAG_VSX;
+  }
+  if (cap2 & PPC_FEATURE2_ARCH_3_00) {
+    cpu_flags |= PPC_FLAG_VSX3;
+  }
+#else
+  // Non-Linux detection here. Currently, on systems other than Linux,
+  // no CPU SIMD features will be detected.
+#endif
+
+  return cpu_flags;
+}
+
+namespace mozilla {
+namespace ppc_private {
+bool vmx_enabled = !!(get_ppc_cpu_flags() & PPC_FLAG_VMX);
+bool vsx_enabled = !!(get_ppc_cpu_flags() & PPC_FLAG_VSX);
+bool vsx3_enabled = !!(get_ppc_cpu_flags() & PPC_FLAG_VSX3);
+}  // namespace ppc_private
+}  // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/mozglue/build/ppc.h
@@ -0,0 +1,47 @@
+/* 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/. */
+
+/* compile-time and runtime tests for whether to use Power ISA-specific
+   extensions */
+
+#ifndef mozilla_ppc_h_
+#define mozilla_ppc_h_
+
+// for definition of MFBT_DATA
+#include "mozilla/Types.h"
+
+namespace mozilla {
+namespace ppc_private {
+extern bool MFBT_DATA vmx_enabled;
+extern bool MFBT_DATA vsx_enabled;
+extern bool MFBT_DATA vsx3_enabled;
+}  // namespace ppc_private
+
+inline bool supports_vmx() {
+#ifdef __powerpc__
+  return ppc_private::vmx_enabled;
+#else
+  return false;
+#endif
+}
+
+inline bool supports_vsx() {
+#ifdef __powerpc__
+  return ppc_private::vsx_enabled;
+#else
+  return false;
+#endif
+}
+
+inline bool supports_vsx3() {
+#ifdef __powerpc__
+  return ppc_private::vsx3_enabled;
+#else
+  return false;
+#endif
+}
+
+}  // namespace mozilla
+
+#endif /* !defined(mozilla_ppc_h_) */
old mode 100755
new mode 100644
--- a/python/mozbuild/mozbuild/backend/configenvironment.py
+++ b/python/mozbuild/mozbuild/backend/configenvironment.py
@@ -13,16 +13,17 @@ from collections import Iterable, Ordere
 from types import ModuleType
 
 import mozpack.path as mozpath
 
 from mozbuild.util import (
     FileAvoidWrite,
     memoized_property,
     ReadOnlyDict,
+    system_encoding,
 )
 from mozbuild.shellutil import quote as shell_quote
 
 
 class BuildConfig(object):
     """Represents the output of configure."""
 
     _CODE_CACHE = {}
@@ -247,20 +248,19 @@ class PartialConfigDict(object):
         try:
             with open(self._config_track) as fh:
                 existing_files.update(fh.read().splitlines())
         except IOError:
             pass
         return existing_files
 
     def _write_file(self, key, value):
-        encoding = 'mbcs' if sys.platform == 'win32' else 'utf-8'
         filename = mozpath.join(self._datadir, key)
         with FileAvoidWrite(filename) as fh:
-            json.dump(value, fh, indent=4, encoding=encoding)
+            json.dump(value, fh, indent=4, encoding=system_encoding)
         return filename
 
     def _fill_group(self, values):
         # Clear out any cached values. This is mostly for tests that will check
         # the environment, write out a new set of variables, and then check the
         # environment again. Normally only configure ends up calling this
         # function, and other consumers create their own
         # PartialConfigEnvironments in new python processes.
--- a/python/mozbuild/mozbuild/configure/__init__.py
+++ b/python/mozbuild/mozbuild/configure/__init__.py
@@ -1,14 +1,15 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import absolute_import, print_function, unicode_literals
 
+import codecs
 import inspect
 import logging
 import os
 import re
 import six
 from six.moves import builtins as __builtin__
 import sys
 import types
@@ -30,16 +31,17 @@ from mozbuild.configure.util import (
 )
 from mozbuild.util import (
     encode,
     exec_,
     memoize,
     memoized_property,
     ReadOnlyDict,
     ReadOnlyNamespace,
+    system_encoding,
 )
 
 import mozpack.path as mozpath
 
 
 # TRACE logging level, below (thus more verbose than) DEBUG
 TRACE = 5
 
@@ -894,19 +896,31 @@ class ConfigureSandbox(dict):
 
     def _get_one_import(self, what):
         # The special `__sandbox__` module gives access to the sandbox
         # instance.
         if what == '__sandbox__':
             return self
         # Special case for the open() builtin, because otherwise, using it
         # fails with "IOError: file() constructor not accessible in
-        # restricted mode"
+        # restricted mode". We also make open() look more like python 3's,
+        # decoding to unicode strings unless the mode says otherwise.
         if what == '__builtin__.open':
-            return lambda *args, **kwargs: open(*args, **kwargs)
+            def wrapped_open(name, mode=None, buffering=None):
+                args = (name,)
+                kwargs = {}
+                if buffering is not None:
+                    kwargs['buffering'] = buffering
+                if mode is not None:
+                    args += (mode,)
+                    if 'b' in mode:
+                        return open(*args, **kwargs)
+                kwargs['encoding'] = system_encoding
+                return codecs.open(*args, **kwargs)
+            return wrapped_open
         # Special case os and os.environ so that os.environ is our copy of
         # the environment.
         if what == 'os.environ':
             return self._environ
         if what == 'os':
             return self._wrapped_os
         # And subprocess, so that its functions use our os.environ
         if what == 'subprocess':
--- a/python/mozbuild/mozbuild/mozconfig.py
+++ b/python/mozbuild/mozbuild/mozconfig.py
@@ -7,16 +7,17 @@ from __future__ import absolute_import, 
 import filecmp
 import os
 import re
 import sys
 import subprocess
 import traceback
 
 from mozpack import path as mozpath
+from mozbuild.util import system_encoding
 
 
 MOZ_MYCONFIG_ERROR = '''
 The MOZ_MYCONFIG environment variable to define the location of mozconfigs
 is deprecated. If you wish to define the mozconfig path via an environment
 variable, use MOZCONFIG instead.
 '''.strip()
 
@@ -351,18 +352,17 @@ class MozconfigLoader(object):
         current_type = None
         in_variable = None
 
         for line in output.splitlines():
 
             # XXX This is an ugly hack. Data may be lost from things
             # like environment variable values.
             # See https://bugzilla.mozilla.org/show_bug.cgi?id=831381
-            line = line.decode('mbcs' if sys.platform == 'win32' else 'utf-8',
-                               'ignore')
+            line = line.decode(system_encoding, 'ignore')
 
             if not line:
                 continue
 
             if line.startswith('------BEGIN_'):
                 assert current_type is None
                 assert current is None
                 assert not in_variable
--- a/python/mozbuild/mozbuild/test/configure/data/subprocess.configure
+++ b/python/mozbuild/mozbuild/test/configure/data/subprocess.configure
@@ -10,14 +10,14 @@
 @imports('os')
 @imports(_from='__builtin__', _import='open')
 def dies_when_logging(_):
     test_file = 'test.txt'
     quote_char = "'"
     if getpreferredencoding().lower() == 'utf-8':
         quote_char = '\u00B4'.encode('utf-8')
     try:
-        with open(test_file, 'w+') as fh:
+        with open(test_file, 'w+b') as fh:
             fh.write(quote_char)
         out = check_cmd_output('cat', 'test.txt')
         log.info(out)
     finally:
         os.remove(test_file)
--- a/python/mozbuild/mozbuild/test/configure/test_checks_configure.py
+++ b/python/mozbuild/mozbuild/test/configure/test_checks_configure.py
@@ -627,17 +627,17 @@ Java SDK directory or use '--with-java-b
             ),
         )
 
     def test_pkg_check_modules(self):
         mock_pkg_config_version = '0.10.0'
         mock_pkg_config_path = mozpath.abspath('/usr/bin/pkg-config')
 
         def mock_pkg_config(_, args):
-            if args[0:2] == ['--errors-to-stdout', '--print-errors']:
+            if args[0:2] == ('--errors-to-stdout', '--print-errors'):
                 assert len(args) == 3
                 package = args[2]
                 if package == 'unknown':
                     return (1, "Package unknown was not found in the pkg-config search path.\n"
                             "Perhaps you should add the directory containing `unknown.pc'\n"
                             "to the PKG_CONFIG_PATH environment variable\n"
                             "No package 'unknown' found", '')
                 if package == 'valid':
@@ -647,17 +647,17 @@ Java SDK directory or use '--with-java-b
             if args[0] == '--cflags':
                 assert len(args) == 2
                 return 0, '-I/usr/include/%s' % args[1], ''
             if args[0] == '--libs':
                 assert len(args) == 2
                 return 0, '-l%s' % args[1], ''
             if args[0] == '--version':
                 return 0, mock_pkg_config_version, ''
-            self.fail("Unexpected arguments to mock_pkg_config: %s" % args)
+            self.fail("Unexpected arguments to mock_pkg_config: %s" % (args,))
 
         def get_result(cmd, args=[], extra_paths=None):
             return self.get_result(textwrap.dedent('''\
                 option('--disable-compile-environment', help='compile env')
                 compile_environment = depends(when='--enable-compile-environment')(lambda: True)
                 toolchain_prefix = depends(when=True)(lambda: None)
                 include('%(topsrcdir)s/build/moz.configure/util.configure')
                 include('%(topsrcdir)s/build/moz.configure/checks.configure')
--- a/python/mozbuild/mozbuild/test/frontend/test_sandbox.py
+++ b/python/mozbuild/mozbuild/test/frontend/test_sandbox.py
@@ -329,27 +329,16 @@ class TestMozbuildSandbox(unittest.TestC
         sandbox = self.sandbox()
         sandbox._context.add_source(sandbox.normalize_path('moz.build'))
 
         sandbox.exec_source('CONFIGURE_SUBST_FILES += ["bar", "foo"]')
         self.assertEqual(sandbox['CONFIGURE_SUBST_FILES'], ['bar', 'foo'])
         for item in sandbox['CONFIGURE_SUBST_FILES']:
             self.assertIsInstance(item, SourcePath)
 
-    def test_invalid_utf8_substs(self):
-        """Ensure invalid UTF-8 in substs is converted with an error."""
-
-        # This is really mbcs. It's a bunch of invalid UTF-8.
-        config = MockConfig(extra_substs={'BAD_UTF8': b'\x83\x81\x83\x82\x3A'})
-
-        sandbox = MozbuildSandbox(Context(VARIABLES, config))
-
-        self.assertEqual(sandbox['CONFIG']['BAD_UTF8'],
-                         u'\ufffd\ufffd\ufffd\ufffd:')
-
     def test_invalid_exports_set_base(self):
         sandbox = self.sandbox()
 
         with self.assertRaises(SandboxExecutionError) as se:
             sandbox.exec_source('EXPORTS = "foo.h"')
 
         self.assertEqual(se.exception.exc_type, ValueError)
 
--- a/python/mozbuild/mozbuild/util.py
+++ b/python/mozbuild/mozbuild/util.py
@@ -30,16 +30,19 @@ from io import (
     StringIO,
     BytesIO,
 )
 
 
 if sys.platform == 'win32':
     _kernel32 = ctypes.windll.kernel32
     _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000
+    system_encoding = 'mbcs'
+else:
+    system_encoding = 'utf-8'
 
 
 def exec_(object, globals=None, locals=None):
     """Wrapper around the exec statement to avoid bogus errors like:
 
     SyntaxError: unqualified exec is not allowed in function ...
     it is a nested function.
 
--- a/taskcluster/ci/toolchain/rust.yml
+++ b/taskcluster/ci/toolchain/rust.yml
@@ -81,31 +81,31 @@ linux64-rust-1.36:
             '--target', 'aarch64-unknown-linux-gnu',
         ]
 
 linux64-rust-1.37:
     treeherder:
         symbol: TL(rust)
     run:
         arguments: [
-            '--channel', 'beta-2019-07-23',
+            '--channel', '1.37.0',
             '--host', 'x86_64-unknown-linux-gnu',
             '--target', 'x86_64-unknown-linux-gnu',
             '--target', 'i686-unknown-linux-gnu',
             '--target', 'aarch64-unknown-linux-gnu',
         ]
         toolchain-alias: linux64-rust
 
 linux64-rust-nightly:
     description: "rust nightly repack"
     treeherder:
         symbol: TL(rust-nightly)
     run:
         arguments: [
-            '--channel', 'nightly-2019-05-27',
+            '--channel', 'nightly-2019-06-28',
             '--host', 'x86_64-unknown-linux-gnu',
             '--target', 'x86_64-unknown-linux-gnu',
             '--target', 'i686-unknown-linux-gnu',
         ]
 
 linux64-rust-macos-1.31:
     description: "rust repack with macos-cross support"
     treeherder:
@@ -152,45 +152,57 @@ linux64-rust-macos-1.35:
             '--host', 'x86_64-unknown-linux-gnu',
             '--target', 'x86_64-unknown-linux-gnu',
             '--target', 'x86_64-apple-darwin',
         ]
 
 linux64-rust-macos-1.36:
     description: "rust repack with macos-cross support"
     treeherder:
+        symbol: TL(rust-macos-1.36)
+    run:
+        arguments: [
+            '--channel', '1.36.0',
+            '--host', 'x86_64-unknown-linux-gnu',
+            '--target', 'x86_64-unknown-linux-gnu',
+            '--target', 'x86_64-apple-darwin',
+        ]
+
+linux64-rust-macos-1.37:
+    description: "rust repack with macos-cross support"
+    treeherder:
         symbol: TL(rust-macos)
     run:
         arguments: [
-            '--channel', '1.36.0',
+            '--channel', '1.37.0',
             '--host', 'x86_64-unknown-linux-gnu',
             '--target', 'x86_64-unknown-linux-gnu',
             '--target', 'x86_64-apple-darwin',
         ]
         toolchain-alias: linux64-rust-macos
 
 linux64-rust-nightly-macos:
     description: "rust nightly repack with macos-cross support"
     treeherder:
         symbol: TL(rust-nightly-macos)
     run:
         arguments: [
-            '--channel', 'nightly-2019-05-27',
+            '--channel', 'nightly-2019-06-28',
             '--host', 'x86_64-unknown-linux-gnu',
             '--target', 'x86_64-unknown-linux-gnu',
             '--target', 'x86_64-apple-darwin',
         ]
 
-linux64-rust-android-1.36:
+linux64-rust-android-1.37:
     description: "rust repack with android-cross support"
     treeherder:
         symbol: TL(rust-android)
     run:
         arguments: [
-            '--channel', '1.36.0',
+            '--channel', '1.37.0',
             '--host', 'x86_64-unknown-linux-gnu',
             '--target', 'x86_64-unknown-linux-gnu',
             '--target', 'armv7-linux-androideabi',
             '--target', 'thumbv7neon-linux-androideabi',
             '--target', 'aarch64-linux-android',
             '--target', 'i686-linux-android',
             '--target', 'x86_64-linux-android',
         ]
@@ -214,36 +226,36 @@ win64-rust-1.34:
         arguments: [
             '--channel', '1.34.0',
             '--host', 'x86_64-pc-windows-msvc',
             '--target', 'x86_64-pc-windows-msvc',
             '--target', 'i686-pc-windows-msvc',
             '--target', 'aarch64-pc-windows-msvc',
         ]
 
-win64-rust-1.36:
+win64-rust-1.37:
     treeherder:
         symbol: TW64(rust)
     run:
         arguments: [
-            '--channel', '1.36.0',
+            '--channel', '1.37.0',
             '--host', 'x86_64-pc-windows-msvc',
             '--target', 'x86_64-pc-windows-msvc',
             '--target', 'i686-pc-windows-msvc',
             '--target', 'aarch64-pc-windows-msvc',
         ]
         toolchain-alias: win64-rust
 
 win64-rust-nightly:
     description: "rust nightly repack"
     treeherder:
         symbol: TW64(rust-nightly)
     run:
         arguments: [
-            '--channel', 'nightly-2019-05-27',
+            '--channel', 'nightly-2019-06-28',
             '--host', 'x86_64-pc-windows-msvc',
             '--target', 'x86_64-pc-windows-msvc',
             '--target', 'i686-pc-windows-msvc',
         ]
 
 mingw32-rust-1.31:
     treeherder:
         symbol: TMW(rust-1.31)
@@ -252,21 +264,21 @@ mingw32-rust-1.31:
             '--channel', '1.31.0',
             '--host', 'x86_64-unknown-linux-gnu',
             '--target', 'i686-unknown-linux-gnu',
             '--target', 'i686-pc-windows-gnu',
             '--target', 'x86_64-pc-windows-gnu',
             '--target', 'x86_64-unknown-linux-gnu',
         ]
 
-mingw32-rust-1.36:
+mingw32-rust-1.37:
     treeherder:
         symbol: TMW(rust)
     run:
         arguments: [
-            '--channel', '1.36.0',
+            '--channel', '1.37.0',
             '--host', 'x86_64-unknown-linux-gnu',
             '--target', 'i686-unknown-linux-gnu',
             '--target', 'i686-pc-windows-gnu',
             '--target', 'x86_64-pc-windows-gnu',
             '--target', 'x86_64-unknown-linux-gnu',
         ]
         toolchain-alias: mingw32-rust
--- a/testing/marionette/capture.js
+++ b/testing/marionette/capture.js
@@ -36,54 +36,45 @@ capture.Format = {
   Hash: 1,
 };
 
 /**
  * Take a screenshot of a single element.
  *
  * @param {Node} node
  *     The node to take a screenshot of.
- * @param {Array.<Node>=} highlights
- *     Optional array of nodes, around which a border will be marked to
- *     highlight them in the screenshot.
  *
  * @return {HTMLCanvasElement}
  *     The canvas element where the element has been painted on.
  */
-capture.element = function(node, highlights = []) {
+capture.element = function(node) {
   let win = node.ownerGlobal;
   let rect = node.getBoundingClientRect();
 
-  return capture.canvas(win, rect.left, rect.top, rect.width, rect.height, {
-    highlights,
-  });
+  return capture.canvas(win, rect.left, rect.top, rect.width, rect.height);
 };
 
 /**
  * Take a screenshot of the window's viewport by taking into account
  * the current offsets.
  *
  * @param {DOMWindow} win
  *     The DOM window providing the document element to capture,
  *     and the offsets for the viewport.
- * @param {Array.<Node>=} highlights
- *     Optional array of nodes, around which a border will be marked to
- *     highlight them in the screenshot.
  *
  * @return {HTMLCanvasElement}
  *     The canvas element where the viewport has been painted on.
  */
-capture.viewport = function(win, highlights = []) {
+capture.viewport = function(win) {
   return capture.canvas(
     win,
     win.pageXOffset,
     win.pageYOffset,
     win.innerWidth,
-    win.innerHeight,
-    { highlights }
+    win.innerHeight
   );
 };
 
 /**
  * Low-level interface to draw a rectangle off the framebuffer.
  *
  * @param {DOMWindow} win
  *     The DOM window used for the framebuffer, and providing the interfaces
@@ -91,36 +82,33 @@ capture.viewport = function(win, highlig
  * @param {number} left
  *     The left, X axis offset of the rectangle.
  * @param {number} top
  *     The top, Y axis offset of the rectangle.
  * @param {number} width
  *     The width dimension of the rectangle to paint.
  * @param {number} height
  *     The height dimension of the rectangle to paint.
- * @param {Array.<Node>=} highlights
- *     Optional array of nodes, around which a border will be marked to
- *     highlight them in the screenshot.
  * @param {HTMLCanvasElement=} canvas
  *     Optional canvas to reuse for the screenshot.
  * @param {number=} flags
  *     Optional integer representing flags to pass to drawWindow; these
  *     are defined on CanvasRenderingContext2D.
  *
  * @return {HTMLCanvasElement}
  *     The canvas on which the selection from the window's framebuffer
  *     has been painted on.
  */
 capture.canvas = function(
   win,
   left,
   top,
   width,
   height,
-  { highlights = [], canvas = null, flags = null } = {}
+  { canvas = null, flags = null } = {}
 ) {
   const scale = win.devicePixelRatio;
 
   if (canvas === null) {
     let canvasWidth = width * scale;
     let canvasHeight = height * scale;
 
     if (canvasWidth > MAX_SKIA_DIMENSIONS) {
@@ -154,43 +142,20 @@ capture.canvas = function(
     // drawing failures. Wait until drawSnapshot is used and supports
     // these flags (bug 1571341)
     // ctx.DRAWWINDOW_DRAW_VIEW;
     // ctx.DRAWWINDOW_USE_WIDGET_LAYERS;
   }
 
   ctx.scale(scale, scale);
   ctx.drawWindow(win, left, top, width, height, BG_COLOUR, flags);
-  if (highlights.length) {
-    ctx = capture.highlight_(ctx, highlights, top, left);
-  }
 
   return canvas;
 };
 
-capture.highlight_ = function(context, highlights, top = 0, left = 0) {
-  if (typeof highlights == "undefined") {
-    throw new InvalidArgumentError("Missing highlights");
-  }
-
-  context.lineWidth = "2";
-  context.strokeStyle = "red";
-  context.save();
-
-  for (let el of highlights) {
-    let rect = el.getBoundingClientRect();
-    let oy = -top;
-    let ox = -left;
-
-    context.strokeRect(rect.left + ox, rect.top + oy, rect.width, rect.height);
-  }
-
-  return context;
-};
-
 /**
  * Encode the contents of an HTMLCanvasElement to a Base64 encoded string.
  *
  * @param {HTMLCanvasElement} canvas
  *     The canvas to encode.
  *
  * @return {string}
  *     A Base64 encoded string.
--- a/testing/marionette/client/marionette_driver/marionette.py
+++ b/testing/marionette/client/marionette_driver/marionette.py
@@ -1789,68 +1789,58 @@ class Marionette(object):
 
         This is the equivalent of calling `document.cookie` and
         parsing the result.
 
         :returns: A list of cookies for the current domain.
         """
         return self._send_message("WebDriver:GetCookies")
 
-    def save_screenshot(self, fh, element=None, highlights=None,
-                        full=True, scroll=True):
+    def save_screenshot(self, fh, element=None, full=True, scroll=True):
         """Takes a screenhot of a web element or the current frame and
         saves it in the filehandle.
 
         It is a wrapper around screenshot()
         :param fh: The filehandle to save the screenshot at.
 
         The rest of the parameters are defined like in screenshot()
         """
-        data = self.screenshot(element, highlights, "binary", full, scroll)
+        data = self.screenshot(element, "binary", full, scroll)
         fh.write(data)
 
-    def screenshot(self, element=None, highlights=None, format="base64",
-                   full=True, scroll=True):
+    def screenshot(self, element=None, format="base64", full=True, scroll=True):
         """Takes a screenshot of a web element or the current frame.
 
         The screen capture is returned as a lossless PNG image encoded
         as a base 64 string by default. If the `element` argument is defined the
         capture area will be limited to the bounding box of that
         element.  Otherwise, the capture area will be the bounding box
         of the current frame.
 
         :param element: The element to take a screenshot of.  If None, will
             take a screenshot of the current frame.
 
-        :param highlights: A list of
-            :class:`~marionette_driver.marionette.HTMLElement` objects to draw
-            a red box around in the returned screenshot.
-
         :param format: if "base64" (the default), returns the screenshot
             as a base64-string. If "binary", the data is decoded and
             returned as raw binary. If "hash", the data is hashed using
             the SHA-256 algorithm and the result is returned as a hex digest.
 
         :param full: If True (the default), the capture area will be the
             complete frame. Else only the viewport is captured. Only applies
             when `element` is None.
 
         :param scroll: When `element` is provided, scroll to it before
             taking the screenshot (default).  Otherwise, avoid scrolling
             `element` into view.
         """
 
         if element:
             element = element.id
-        lights = None
-        if highlights:
-            lights = [highlight.id for highlight in highlights]
 
         body = {"id": element,
-                "highlights": lights,
                 "full": full,
                 "hash": False,
                 "scroll": scroll}
         if format == "hash":
             body["hash"] = True
 
         data = self._send_message("WebDriver:TakeScreenshot",
                                   body, key="value")
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -3001,83 +3001,75 @@ GeckoDriver.prototype.deleteSession = fu
  * area will be the bounding box of the current frame.
  *
  * If called in the chrome context, the screenshot will always represent
  * the entire viewport.
  *
  * @param {string=} id
  *     Optional web element reference to take a screenshot of.
  *     If undefined, a screenshot will be taken of the document element.
- * @param {Array.<string>=} highlights
- *     List of web elements to highlight. Defaults to an empty list.
  * @param {boolean=} full
  *     True to take a screenshot of the entire document element. Is only
  *     considered if <var>id</var> is not defined. Defaults to true.
  * @param {boolean=} hash
  *     True if the user requests a hash of the image data. Defaults to false.
  * @param {boolean=} scroll
  *     Scroll to element if |id| is provided. Defaults to true.
  *
  * @return {string}
  *     If <var>hash</var> is false, PNG image encoded as Base64 encoded
  *     string.  If <var>hash</var> is true, hex digest of the SHA-256
  *     hash of the Base64 encoded string.
  */
 GeckoDriver.prototype.takeScreenshot = function(cmd) {
   let win = assert.open(this.getCurrentWindow());
 
-  let { id, highlights, full, hash, scroll } = cmd.parameters;
+  let { id, full, hash, scroll } = cmd.parameters;
   let format = hash ? capture.Format.Hash : capture.Format.Base64;
 
-  highlights = highlights || [];
   full = typeof full == "undefined" ? true : full;
   scroll = typeof scroll == "undefined" ? true : scroll;
 
   // Only consider full screenshot if no element has been specified
   full = id ? false : full;
 
   switch (this.context) {
     case Context.Chrome:
-      let highlightEls = highlights
-        .map(ref => WebElement.fromUUID(ref, Context.Chrome))
-        .map(webEl => this.curBrowser.seenEls.get(webEl));
-
       let canvas;
 
       // element or full document element
       if (id || full) {
         let node;
         if (id) {
           let webEl = WebElement.fromUUID(id, Context.Chrome);
           node = this.curBrowser.seenEls.get(webEl);
         } else {
           node = win.document.documentElement;
         }
 
-        canvas = capture.element(node, highlightEls);
+        canvas = capture.element(node);
 
         // viewport
       } else {
-        canvas = capture.viewport(win, highlightEls);
+        canvas = capture.viewport(win);
       }
 
       switch (format) {
         case capture.Format.Hash:
           return capture.toHash(canvas);
 
         case capture.Format.Base64:
           return capture.toBase64(canvas);
       }
       break;
 
     case Context.Content:
       return this.listener.takeScreenshot(format, {
         id,
         full,
-        highlights,
         scroll,
       });
   }
 
   throw new TypeError(`Unknown context: ${this.context}`);
 };
 
 /**
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_screenshot.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_screenshot.py
@@ -9,17 +9,17 @@ import hashlib
 import imghdr
 import struct
 import sys
 import tempfile
 import unittest
 import urllib
 
 from marionette_driver import By
-from marionette_driver.errors import NoSuchElementException, NoSuchWindowException
+from marionette_driver.errors import NoSuchWindowException
 from marionette_harness import (
     MarionetteTestCase,
     skip,
     skip_if_mobile,
     WindowManagerMixin,
 )
 
 
@@ -211,56 +211,16 @@ class TestScreenCaptureChrome(WindowMana
 
         self.marionette.close_chrome_window()
         self.marionette.switch_to_window(self.start_window)
 
     def test_format_unknown(self):
         with self.assertRaises(ValueError):
             self.marionette.screenshot(format="cheese")
 
-    @skip_if_mobile("Fennec doesn't support other chrome windows")
-    def test_highlight_elements(self):
-        dialog = self.open_dialog()
-        self.marionette.switch_to_window(dialog)
-
-        # Highlighting the element itself shouldn't make the image larger
-        element = self.marionette.find_element(By.ID, "test-list")
-        screenshot_element = self.marionette.screenshot(element=element)
-        screenshot_highlight = self.marionette.screenshot(element=element,
-                                                          highlights=[element])
-        self.assertEqual(self.scale(self.get_element_dimensions(element)),
-                         self.get_image_dimensions(screenshot_element))
-        self.assertNotEqual(screenshot_element, screenshot_highlight)
-
-        # Highlighting a sub element
-        button = self.marionette.find_element(By.ID, "choose-button")
-        screenshot_highlight_button = self.marionette.screenshot(element=element,
-                                                                 highlights=[button])
-        self.assertNotEqual(screenshot_element, screenshot_highlight_button)
-        self.assertNotEqual(screenshot_highlight, screenshot_highlight_button)
-
-        self.marionette.close_chrome_window()
-        self.marionette.switch_to_window(self.start_window)
-
-    def test_highlight_element_not_seen(self):
-        """Check that for not found elements an exception is raised."""
-        with self.marionette.using_context('content'):
-            self.marionette.navigate(box)
-            content_element = self.marionette.find_element(By.ID, "green")
-
-        self.assertRaisesRegexp(NoSuchElementException, "Web element reference not seen before",
-                                self.marionette.screenshot, highlights=[content_element])
-
-        chrome_document_element = self.document_element
-        with self.marionette.using_context('content'):
-            self.assertRaisesRegexp(NoSuchElementException,
-                                    "Web element reference not seen before",
-                                    self.marionette.screenshot,
-                                    highlights=[chrome_document_element])
-
 
 class TestScreenCaptureContent(WindowManagerMixin, ScreenCaptureTestCase):
 
     def setUp(self):
         super(TestScreenCaptureContent, self).setUp()
         self.marionette.set_context("content")
 
     def tearDown(self):
@@ -357,35 +317,16 @@ class TestScreenCaptureContent(WindowMan
         # Use a smaller region to speed up the test
         element = self.marionette.find_element(By.TAG_NAME, "div")
         self.assert_formats(element=element)
 
     def test_format_unknown(self):
         with self.assertRaises(ValueError):
             self.marionette.screenshot(format="cheese")
 
-    def test_highlight_elements(self):
-        self.marionette.navigate(box)
-        element = self.marionette.find_element(By.TAG_NAME, "div")
-
-        # Highlighting the element itself shouldn't make the image larger
-        screenshot_element = self.marionette.screenshot(element=element)
-        screenshot_highlight = self.marionette.screenshot(element=element,
-                                                          highlights=[element])
-        self.assertEqual(self.scale(self.get_element_dimensions(element)),
-                         self.get_image_dimensions(screenshot_highlight))
-        self.assertNotEqual(screenshot_element, screenshot_highlight)
-
-        # Highlighting a sub element
-        paragraph = self.marionette.find_element(By.ID, "green")
-        screenshot_highlight_paragraph = self.marionette.screenshot(element=element,
-                                                                    highlights=[paragraph])
-        self.assertNotEqual(screenshot_element, screenshot_highlight_paragraph)
-        self.assertNotEqual(screenshot_highlight, screenshot_highlight_paragraph)
-
     def test_save_screenshot(self):
         expected = self.marionette.screenshot(format="binary")
         with tempfile.TemporaryFile('w+b') as fh:
             self.marionette.save_screenshot(fh)
             fh.flush()
             fh.seek(0)
             content = fh.read()
             self.assertEqual(expected, content)
--- a/testing/marionette/listener.js
+++ b/testing/marionette/listener.js
@@ -1631,60 +1631,50 @@ function switchToFrame(msg) {
  *
  * Accepted values for |opts|:
  *
  * @param {UUID=} id
  *     Optional web element reference of an element to take a screenshot of.
  * @param {boolean=} full
  *     True to take a screenshot of the entire document element. Is only
  *     considered if <var>id</var> is not defined. Defaults to true.
- * @param {Array.<UUID>=} highlights
- *     Draw a border around the elements found by their web element
- *     references.
  * @param {boolean=} scroll
  *     When <var>id</var> is given, scroll it into view before taking the
  *     screenshot.  Defaults to true.
  * @param {capture.Format} format
  *     Format to return the screenshot in.
  * @param {Object.<string, ?>} opts
  *     Options.
  *
  * @return {string}
  *     Base64 encoded string or a SHA-256 hash of the screenshot.
  */
-function takeScreenshot(
-  format,
-  { id, full = true, highlights = [], scroll = true } = {}
-) {
+function takeScreenshot(format, { id, full = true, scroll = true } = {}) {
   let win = curContainer.frame;
 
-  let highlightEls = highlights
-    .map(ref => WebElement.fromUUID(ref, "content"))
-    .map(webEl => seenEls.get(webEl, win));
-
   let canvas;
 
   // element or full document element
   if (id || full) {
     let el;
     if (id) {
       let webEl = WebElement.fromUUID(id, "content");
       el = seenEls.get(webEl, win);
       if (scroll) {
         element.scrollIntoView(el);
       }
     } else {
       el = win.document.documentElement;
     }
 
-    canvas = capture.element(el, highlightEls);
+    canvas = capture.element(el);
 
     // viewport
   } else {
-    canvas = capture.viewport(win, highlightEls);
+    canvas = capture.viewport(win);
   }
 
   switch (format) {
     case capture.Format.Base64:
       return capture.toBase64(canvas);
 
     case capture.Format.Hash:
       return capture.toHash(canvas);
--- a/testing/mozharness/configs/builds/releng_base_android_64_builds.py
+++ b/testing/mozharness/configs/builds/releng_base_android_64_builds.py
@@ -69,18 +69,9 @@ config = {
         'SHIP_LICENSED_FONTS': '1',
     },
     "check_test_env": {
         'MINIDUMP_STACKWALK': '%(abs_tools_dir)s/breakpad/linux/minidump_stackwalk',
         'MINIDUMP_SAVE_PATH': '%(base_work_dir)s/minidumps',
     },
     'src_mozconfig': 'mobile/android/config/mozconfigs/android/nightly',
     #########################################################################
-
-    # It's not obvious, but postflight_build is after packaging, so the Gecko
-    # binaries are in the object directory, ready to be packaged into the
-    # GeckoView AAR.
-    'postflight_build_mach_commands': [
-        ['android',
-         'archive-geckoview',
-        ],
-    ],
 }
--- a/testing/mozharness/configs/builds/releng_sub_android_configs/64_api_16_debug_ccov.py
+++ b/testing/mozharness/configs/builds/releng_sub_android_configs/64_api_16_debug_ccov.py
@@ -1,14 +1,11 @@
 config = {
     'stage_platform': 'android-api-16-debug-ccov',
     'src_mozconfig': 'mobile/android/config/mozconfigs/android-api-16/debug-ccov',
     'multi_locale_config_platform': 'android',
     'debug_build': True,
     'postflight_build_mach_commands': [
         ['android',
-         'archive-geckoview',
-        ],
-        ['android',
          'archive-coverage-artifacts',
         ],
     ],
 }
old mode 100755
new mode 100644
old mode 100755
new mode 100644
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/webvtt/rendering/cues-with-video/processing-model/snap-to-line.html.ini
@@ -0,0 +1,5 @@
+[snap-to-line.html]
+  disabled:
+    if (os == "win"): https://bugzilla.mozilla.org/show_bug.cgi?id=1536762
+    if (os == "android"): https://bugzilla.mozilla.org/show_bug.cgi?id=1536762
+  fuzzy: snap-to-line-ref.html:maxDifference=0-2;totalPixels=0-3500
--- a/testing/web-platform/tests/payment-request/MerchantValidationEvent/constructor.https.html
+++ b/testing/web-platform/tests/payment-request/MerchantValidationEvent/constructor.https.html
@@ -75,16 +75,30 @@ test(() => {
   for (const path of relativePaths) {
     const event = new MerchantValidationEvent("test", { validationURL: path });
     const expected = new URL(path, document.location.href).href;
     assert_equals(event.validationURL, expected);
   }
 }, "Relative validationURLs use the document as the base.");
 
 test(() => {
+  const validationURL = "pass";
+  const base = document.createElement("base");
+  base.href = "https://pass.com";
+  document.head.append(base);
+  const event = new MerchantValidationEvent("test", { validationURL });
+  try {
+    assert_idl_attribute(event, "validationURL");
+    assert_equals(event.validationURL, "https://pass.com/pass");
+  } finally {
+    base.remove();
+  }
+}, "Relative validationURLs use the document.baseURI as the base.");
+
+test(() => {
   const methodName = "https://pass.com";
   const event = new MerchantValidationEvent("test", { methodName });
   assert_idl_attribute(event, "methodName");
   assert_equals(event.methodName, "https://pass.com");
 }, "Must have a methodName IDL attribute, which is initialized with to the methodName dictionary value.");
 
 test(() => {
   const event = new MerchantValidationEvent("test", {});
old mode 100755
new mode 100644
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/webvtt/rendering/cues-with-video/processing-model/snap-to-line-ref.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<title>Reference for WebVTT rendering, set explicit 'line' and 'position', which will force 'snap-to-line' to false</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+html { overflow:hidden }
+body { margin:0 }
+.video {
+    display: inline-block;
+    width: 320px;
+    height: 180px;
+    position: relative;
+}
+.cue {
+    position: absolute;
+    top: 90px;
+    left: 160px;
+    text-align: center;
+    font: 20px/1 Ahem;
+}
+.cueText {
+    background: rgba(0,0,0,0.8);
+    color: green;
+}
+</style>
+<div class=video>
+    <div class="cue">
+        <span class="cueText">foo</span>
+    </div>
+</div>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/webvtt/rendering/cues-with-video/processing-model/snap-to-line.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>WebVTT rendering, set explicit 'line' and 'position', which will force 'snap-to-line' to false</title>
+<link rel="match" href="snap-to-line-ref.html">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+html { overflow:hidden }
+body { margin:0 }
+::cue {
+    font: 20px/1 Ahem;
+    color: green;
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<video width="320" height="180" autoplay onplaying="this.onplaying = null; this.pause(); takeScreenshot();">
+    <source src="/media/white.webm" type="video/webm">
+    <source src="/media/white.mp4" type="video/mp4">
+    <track src="support/snap-to-line.vtt">
+    <script>
+    document.getElementsByTagName('track')[0].track.mode = 'showing';
+    </script>
+</video>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/webvtt/rendering/cues-with-video/processing-model/support/snap-to-line.vtt
@@ -0,0 +1,5 @@
+WEBVTT
+
+NOTE set line as percentage would make 'snap-to-line' to false
+00:00:00.000 --> 00:00:05.000 align:start position:50%,line-left line:50%,start
+foo
--- a/toolkit/components/certviewer/content/certviewer.js
+++ b/toolkit/components/certviewer/content/certviewer.js
@@ -63,17 +63,17 @@ const getElementByPathOrFalse = (obj, pa
     result = result[entry];
     if (result == null) {
       return false;
     }
   }
   return result ? result : false;
 };
 
-const adjustCertInformation = cert => {
+export const adjustCertInformation = cert => {
   let certItems = [];
   let tabName = cert.subject ? cert.subject.cn || "" : "";
 
   if (!cert) {
     return {
       certItems,
       tabName,
     };
@@ -317,19 +317,18 @@ const adjustCertInformation = cert => {
   addToResultUsing(
     () => {
       let items = [];
       if (cert.ext.aia && cert.ext.aia.descriptions) {
         cert.ext.aia.descriptions.forEach(entry => {
           items.push(createEntryItem("Location", entry.location));
           items.push(createEntryItem("Method", entry.method));
         });
-        items.filter(elem => elem != null);
       }
-      return items;
+      return items.filter(elem => elem != null);
     },
     certItems,
     "Authority Info (AIA)",
     getElementByPathOrFalse(cert, "ext.aia.critical")
   );
 
   addToResultUsing(
     () => {
@@ -347,37 +346,35 @@ const adjustCertInformation = cert => {
                   "Qualifier",
                   qualifier.name + " ( " + qualifier.id + " )"
                 )
               );
               items.push(createEntryItem("Value", qualifier.value));
             });
           }
         });
-        items.filter(elem => elem != null);
       }
-      return items;
+      return items.filter(elem => elem != null);
     },
     certItems,
     "Certificate Policies",
     getElementByPathOrFalse(cert, "ext.cp.critical")
   );
 
   addToResultUsing(
     () => {
       let items = [];
       if (cert.ext.scts && cert.ext.scts.timestamps) {
         cert.ext.scts.timestamps.forEach(entry => {
           for (let key of Object.keys(entry)) {
             items.push(createEntryItem(key, entry[key]));
           }
         });
-        items.filter(elem => elem != null);
       }
-      return items;
+      return items.filter(elem => elem != null);
     },
     certItems,
     "Embedded SCTs",
     getElementByPathOrFalse(cert, "ext.scts.critical")
   );
 
   return {
     certItems,
--- a/toolkit/components/certviewer/content/components/certificate-section.js
+++ b/toolkit/components/certviewer/content/components/certificate-section.js
@@ -49,19 +49,21 @@ class CertificateSection extends HTMLEle
     this.setAccessibilityEventListeners();
     this.addClassForPadding();
   }
 
   // Adds class selector for items that need padding,
   // as nth-child/parent-based selectors aren't supported
   // due to the encapsulation of custom-element CSS.
   addClassForPadding() {
-    let items = this.shadowRoot
-      .querySelector(".embedded-scts")
-      .shadowRoot.querySelectorAll(".version");
+    let embeddedScts = this.shadowRoot.querySelector(".embedded-scts");
+    if (!embeddedScts) {
+      return;
+    }
+    let items = embeddedScts.shadowRoot.querySelectorAll(".version");
 
     for (let i = 0; i < items.length; i++) {
       items[i].classList.add("padding");
     }
   }
 
   /* Information on setAccessibilityEventListeners() can be found
    * at https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/Tab_Role */
--- a/toolkit/components/certviewer/content/components/info-item.js
+++ b/toolkit/components/certviewer/content/components/info-item.js
@@ -26,17 +26,19 @@ export class InfoItem extends HTMLElemen
   render() {
     let label = this.shadowRoot.querySelector("label");
     let labelText = normalizeToKebabCase(this.item.label);
     label.setAttribute("data-l10n-id", "certificate-viewer-" + labelText);
 
     this.classList.add(labelText);
 
     let info = this.shadowRoot.querySelector(".info");
-    info.textContent = this.item.info;
+    info.textContent = Array.isArray(this.item.info)
+      ? this.item.info.join(", ")
+      : this.item.info;
 
     // TODO: Use Fluent-friendly condition.
     if (this.item.label === "Modulus") {
       info.classList.add("long-hex");
       this.addEventListener("click", () => {
         info.classList.toggle("long-hex-open");
       });
     }
--- a/toolkit/components/certviewer/tests/browser/browser_renderCertToUI.js
+++ b/toolkit/components/certviewer/tests/browser/browser_renderCertToUI.js
@@ -84,23 +84,29 @@ add_task(async function test() {
           adjustedCertsElemLabel = adjustedCertsElemLabel
             .replace(/\s+/g, "-")
             .replace(/\./g, "")
             .replace(/\//g, "")
             .replace(/--/g, "-")
             .toLowerCase();
 
           let adjustedCertsElemInfo = adjustedCertsElem.sectionItems[i].info;
+
           if (adjustedCertsElemInfo == null) {
             adjustedCertsElemInfo = "";
           }
 
-          if (typeof adjustedCertsElemInfo !== "string") {
+          if (
+            typeof adjustedCertsElemInfo !== "string" ||
+            Array.isArray(adjustedCertsElemInfo)
+          ) {
             // there is a case where we have a boolean
-            adjustedCertsElemInfo = adjustedCertsElemInfo.toString();
+            adjustedCertsElemInfo = adjustedCertsElemInfo
+              .toString()
+              .replace(/,/g, ", ");
           }
 
           Assert.ok(
             infoItemLabel.includes(adjustedCertsElemLabel),
             "data-l10n-id must contain the original label"
           );
 
           if (
--- a/toolkit/components/certviewer/tests/chrome/chrome.ini
+++ b/toolkit/components/certviewer/tests/chrome/chrome.ini
@@ -1,6 +1,9 @@
 [DEFAULT]
 scheme=https
+[test_adjustCertInformation.html]
+support-files =
+   parseOutput.js
+[test_certDecoder.html]
+[test_certDecoderFields.html]
 support-files =
    CSoutput.js
-[test_certDecoder.html]
-[test_certDecoderFields.html]
new file mode 100644
--- /dev/null
+++ b/toolkit/components/certviewer/tests/chrome/parseOutput.js
@@ -0,0 +1,342 @@
+export const parseOutput = [
+  {
+    ext: {
+      aia: {
+        descriptions: [
+          {
+            location: "http://ocsp.digicert.com",
+            method: "Online Certificate Status Protocol (OCSP)",
+          },
+          {
+            location:
+              "http://cacerts.digicert.com/DigiCertSHA2ExtendedValidationServerCA.crt",
+            method: "CA Issuers",
+          },
+        ],
+        critical: false,
+      },
+      aKID: {
+        critical: false,
+        id: "3D:D3:50:A5:D6:A0:AD:EE:F3:4A:60:0A:65:D3:21:D4:F8:F8:D6:0F",
+      },
+      basicConstraints: { cA: false, critical: true },
+      crlPoints: {
+        critical: false,
+        points: [
+          "http://crl3.digicert.com/sha2-ev-server-g2.crl",
+          "http://crl4.digicert.com/sha2-ev-server-g2.crl",
+        ],
+      },
+      cp: {
+        critical: false,
+        policies: [
+          {
+            id: "2.16.840",
+            name: "ANSI Organizational Identifier",
+            qualifiers: [
+              {
+                id: "1.3.6.1.5.5.7.2.1",
+                name: "Practices Statement",
+                value: "https://www.digicert.com/CPS",
+              },
+            ],
+            value: "2.16.840.1.114412.2.1",
+          },
+          {
+            id: "2.23.140.1.1",
+            name: "Certificate Type",
+            value: "Extended Validation",
+          },
+        ],
+      },
+      eKeyUsages: {
+        critical: false,
+        purposes: ["Server Authentication", "Client Authentication"],
+      },
+      keyUsages: {
+        critical: true,
+        purposes: ["Digital Signature", "Key Encipherment"],
+      },
+      msCrypto: { exists: false },
+      ocspStaple: { critical: false, required: false },
+      scts: {
+        critical: false,
+        timestamps: [
+          {
+            logId:
+              "A4:B9:09:90:B4:18:58:14:87:BB:13:A2:CC:67:70:0A:3C:35:98:04:F9:1B:DF:B8:E3:77:CD:0E:C8:0D:DC:10",
+            name: "Google “Pilot”",
+            signatureAlgorithm: "SHA-256 ECDSA",
+            timestamp: "11/7/2018, 7:50:01 PM (Brasilia Standard Time)",
+            timestampUTC: "Wed, 07 Nov 2018 21:50:01 GMT",
+            version: 1,
+          },
+          {
+            logId:
+              "87:75:BF:E7:59:7C:F8:8C:43:99:5F:BD:F3:6E:FF:56:8D:47:56:36:FF:4A:B5:60:C1:B4:EA:FF:5E:A0:83:0F",
+            name: "DigiCert Server 2",
+            signatureAlgorithm: "SHA-256 ECDSA",
+            timestamp: "11/7/2018, 7:50:01 PM (Brasilia Standard Time)",
+            timestampUTC: "Wed, 07 Nov 2018 21:50:01 GMT",
+            version: 1,
+          },
+          {
+            logId:
+              "EE:4B:BD:B7:75:CE:60:BA:E1:42:69:1F:AB:E1:9E:66:A3:0F:7E:5F:B0:72:D8:83:00:C4:7B:89:7A:A8:FD:CB",
+            name: "Google “Rocketeer”",
+            signatureAlgorithm: "SHA-256 ECDSA",
+            timestamp: "11/7/2018, 7:50:01 PM (Brasilia Standard Time)",
+            timestampUTC: "Wed, 07 Nov 2018 21:50:01 GMT",
+            version: 1,
+          },
+        ],
+      },
+      sKID: {
+        critical: false,
+        id: "6C:B0:43:56:FE:3D:E8:12:EC:D9:12:F5:63:D5:C4:CA:07:AF:B0:76",
+      },
+      san: {
+        altNames: [
+          ["DNS Name", "www.digicert.com"],
+          ["DNS Name", "admin.digicert.com"],
+          ["DNS Name", "digicert.com"],
+          ["DNS Name", "content.digicert.com"],
+          ["DNS Name", "login.digicert.com"],
+          ["DNS Name", "api.digicert.com"],
+          ["DNS Name", "ws.digicert.com"],
+          ["DNS Name", "www.origin.digicert.com"],
+        ],
+        critical: false,
+      },
+    },
+    files: {
+      pem:
+        "-----BEGIN%20CERTIFICATE-----%0D%0AMIIIzDCCB7SgAwIBAgIQDrbqtBjIc9jzwDHc3d8YsDANBgkqhkiG9w0BAQsFADB1%0D%0AMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3%0D%0Ad3cuZGlnaWNlcnQuY29tMTQwMgYDVQQDEytEaWdpQ2VydCBTSEEyIEV4dGVuZGVk%0D%0AIFZhbGlkYXRpb24gU2VydmVyIENBMB4XDTE4MTEwNzAwMDAwMFoXDTIwMTExMzEy%0D%0AMDAwMFowgc8xHTAbBgNVBA8MFFByaXZhdGUgT3JnYW5pemF0aW9uMRMwEQYLKwYB%0D%0ABAGCNzwCAQMTAlVTMRUwEwYLKwYBBAGCNzwCAQITBFV0YWgxFTATBgNVBAUTDDUy%0D%0AOTk1MzctMDE0MjELMAkGA1UEBhMCVVMxDTALBgNVBAgTBFV0YWgxDTALBgNVBAcT%0D%0ABExlaGkxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMQwwCgYDVQQLEwNTUkUxGTAX%0D%0ABgNVBAMTEHd3dy5kaWdpY2VydC5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw%0D%0AggIKAoICAQDOn4XKOTAwt/aYabScEF1QOyVj0OVo1NmlyizWNZWyPg0pi53ggUoE%0D%0A98CeNUkz+6scEYqWNY6l3qKB56pJJIqNQmo9NoWO8k2G/jTIjFFGqNWYIq23i4+H%0D%0AqaXi1/H/aWFgazk1qkyyAOQQA/p56bG9m5Ok/IBM/BZnLqVJLGJOx9ihgG1dI9Dr%0D%0A6vap+8QaPRau3t9sEd2cxe4Ix7gLdaYG3vxsYf3BycKTSKtyrbkX1Qy0dsSxy+GC%0D%0AM2ETxE1gMa7vRomQ/ZoZo8Ib55kFp6lIT6UOOkkdyiJdpWPXIZZlsZR5wkegWDsJ%0D%0AP7Xv7nE0WMkY1+05iNYtrzZRhhlnBw2AoMGNI+tsBXLQKeZfWFmU30bhkzX99pmv%0D%0AIYJ3f1fQGLao44nQEjdknIvpm0HMgvagYCnQVnnhJStzyYz324flWLPSp57OQeNM%0D%0Atr6O5W0HdWyhUZU+D4R6wObYQMZ5biYjRhtAQjMg8EVQEfZzEdr0WGO5JRHLHyot%0D%0A8tErXM9DiF5cCbzfcjeuoik2SHW+vbuPagMiHTM9+3lr0oRO+ZWwcM7fJvn1JfR2%0D%0APDLAaI3QUv7OLhSH32UfQsk+1ICq05m2HwSxiAviDRl5De66MEZDdvu03sUAQTHv%0D%0AWnw0Mr7Jgbjtn0DeUKLYwsRWg+spqoFTJHWGbb9RIb+3lxev7nIqOQIDAQABo4ID%0D%0A+zCCA/cwHwYDVR0jBBgwFoAUPdNQpdagre7zSmAKZdMh1Pj41g8wHQYDVR0OBBYE%0D%0AFGywQ1b+PegS7NkS9WPVxMoHr7B2MIGlBgNVHREEgZ0wgZqCEHd3dy5kaWdpY2Vy%0D%0AdC5jb22CEmFkbWluLmRpZ2ljZXJ0LmNvbYIMZGlnaWNlcnQuY29tghRjb250ZW50%0D%0ALmRpZ2ljZXJ0LmNvbYISbG9naW4uZGlnaWNlcnQuY29tghBhcGkuZGlnaWNlcnQu%0D%0AY29tgg93cy5kaWdpY2VydC5jb22CF3d3dy5vcmlnaW4uZGlnaWNlcnQuY29tMA4G%0D%0AA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdQYD%0D%0AVR0fBG4wbDA0oDKgMIYuaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItZXYt%0D%0Ac2VydmVyLWcyLmNybDA0oDKgMIYuaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3No%0D%0AYTItZXYtc2VydmVyLWcyLmNybDBLBgNVHSAERDBCMDcGCWCGSAGG/WwCATAqMCgG%0D%0ACCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAcGBWeBDAEB%0D%0AMIGIBggrBgEFBQcBAQR8MHowJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2lj%0D%0AZXJ0LmNvbTBSBggrBgEFBQcwAoZGaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29t%0D%0AL0RpZ2lDZXJ0U0hBMkV4dGVuZGVkVmFsaWRhdGlvblNlcnZlckNBLmNydDAMBgNV%0D%0AHRMBAf8EAjAAMIIBfwYKKwYBBAHWeQIEAgSCAW8EggFrAWkAdQCkuQmQtBhYFIe7%0D%0AE6LMZ3AKPDWYBPkb37jjd80OyA3cEAAAAWbwJ1QeAAAEAwBGMEQCIAzNFnn0UQyL%0D%0A5ZkwA7BX2JiQkjCk9QZrNHR9S1So7l8LAiAzoHDpWV5Dq5iM5NU86nJwqB1qsjZt%0D%0Aa4fWlvNKs0S+eQB3AId1v+dZfPiMQ5lfvfNu/1aNR1Y2/0q1YMG06v9eoIMPAAAB%0D%0AZvAnVbMAAAQDAEgwRgIhAOr0s3YbgyIs7dytmC1s5ClugVmo+r+W6ZKqRpphsIjT%0D%0AAiEAqgzFns9X9+SKwTSz0h1epijxrnWH+qZ815QgaJVd83UAdwDuS723dc5guuFC%0D%0AaR+r4Z5mow9+X7By2IMAxHuJeqj9ywAAAWbwJ1RAAAAEAwBIMEYCIQCsFv4KXmNK%0D%0A+POADrfs37hcjApxSuiK14+tN5wFGby6QQIhANa+RvbVx1nYk13IyLCBiCMENLEV%0D%0A9urcBZfprZN+ZsrlMA0GCSqGSIb3DQEBCwUAA4IBAQB+tQhW07rk6eb2L2Ir+Wwq%0D%0Al5ZJaoaZq3zwoG8vPMFTZbcWPYsSVI5KuXELdB1QnmPbHebTJuI/gjfD65vf7C3N%0D%0ABjgLoXui39mwN4UNTBCc2Ls8s8/aVfTZGPCNNwynCEsY9h0HRobI8kiVPvU0kyBJ%0D%0AO3p3msqR7W2lAIWciJWmoPQkEFh7u84/oc7Pz2SSE6tqMW9lZmyBqjSuBufRJn1g%0D%0ACTdp/5DZdQWTNL6L5GSsRoXQnarsVtFVriqOjWf5R4O4z6LQznlbBQCMUR3geUNq%0D%0A0vSblnmgav0+L9HK97wqtONu1CrJ9/Q2JwoxFAs/zps/nh9oJU2ToK9lzl/38gpo%0D%0A-----END%20CERTIFICATE-----%0D%0A",
+    },
+    fingerprint: {
+      sha1: "8E:43:B7:D0:84:FD:B2:6C:08:9E:D3:F1:10:0C:D2:1D:D4:AD:C6:DF",
+      sha256:
+        "37:BF:44:A9:28:03:8A:22:AE:0C:E3:2D:96:3C:36:F5:D2:2D:37:99:D6:B2:63:CB:9C:1D:45:D1:CF:FE:B0:69",
+    },
+    issuer: {
+      cn: "DigiCert SHA2 Extended Validation Server CA",
+      dn:
+        "c=US, o=DigiCert Inc, ou=www.digicert.com, cn=DigiCert SHA2 Extended Validation Server CA",
+      entries: [
+        ["Country", "US"],
+        ["Organization", "DigiCert Inc"],
+        ["Organizational Unit", "www.digicert.com"],
+        ["Common Name", "DigiCert SHA2 Extended Validation Server CA"],
+      ],
+    },
+    notBefore: "11/6/2018, 10:00:00 PM (Brasilia Standard Time)",
+    notBeforeUTC: "Wed, 07 Nov 2018 00:00:00 GMT",
+    notAfter: "11/13/2020, 9:00:00 AM (Brasilia Standard Time)",
+    notAfterUTC: "Fri, 13 Nov 2020 12:00:00 GMT",
+    subject: {
+      cn: "www.digicert.com",
+      dn:
+        "OID.2.5.4.15=Private Organization, OID.1.3.6.1.4.1.311.60.2.1.3=US, OID.1.3.6.1.4.1.311.60.2.1.2=Utah, serialNumber=5299537-0142, c=US, s=Utah, l=Lehi, o=DigiCert, Inc., ou=SRE, cn=www.digicert.com",
+      entries: [
+        ["Business Category", "Private Organization"],
+        ["Inc. Country", "US"],
+        ["Inc. State / Province", "Utah"],
+        ["Serial Number", "5299537-0142"],
+        ["Country", "US"],
+        ["State / Province", "Utah"],
+        ["Locality", "Lehi"],
+        ["Organization", "DigiCert, Inc."],
+        ["Organizational Unit", "SRE"],
+        ["Common Name", "www.digicert.com"],
+      ],
+    },
+    serialNumber: "0E:B6:EA:B4:18:C8:73:D8:F3:C0:31:DC:DD:DF:18:B0",
+    signature: {
+      name: "SHA-256 with RSA Encryption",
+      type: "1.2.840.113549.1.1.11",
+    },
+    subjectPublicKeyInfo: {
+      e: 65537,
+      kty: "RSA",
+      n:
+        "CE:9F:85:CA:39:30:30:B7:F6:98:69:B4:9C:10:5D:50:3B:25:63:D0:E5:68:D4:D9:A5:CA:2C:D6:35:95:B2:3E:0D:29:8B:9D:E0:81:4A:04:F7:C0:9E:35:49:33:FB:AB:1C:11:8A:96:35:8E:A5:DE:A2:81:E7:AA:49:24:8A:8D:42:6A:3D:36:85:8E:F2:4D:86:FE:34:C8:8C:51:46:A8:D5:98:22:AD:B7:8B:8F:87:A9:A5:E2:D7:F1:FF:69:61:60:6B:39:35:AA:4C:B2:00:E4:10:03:FA:79:E9:B1:BD:9B:93:A4:FC:80:4C:FC:16:67:2E:A5:49:2C:62:4E:C7:D8:A1:80:6D:5D:23:D0:EB:EA:F6:A9:FB:C4:1A:3D:16:AE:DE:DF:6C:11:DD:9C:C5:EE:08:C7:B8:0B:75:A6:06:DE:FC:6C:61:FD:C1:C9:C2:93:48:AB:72:AD:B9:17:D5:0C:B4:76:C4:B1:CB:E1:82:33:61:13:C4:4D:60:31:AE:EF:46:89:90:FD:9A:19:A3:C2:1B:E7:99:05:A7:A9:48:4F:A5:0E:3A:49:1D:CA:22:5D:A5:63:D7:21:96:65:B1:94:79:C2:47:A0:58:3B:09:3F:B5:EF:EE:71:34:58:C9:18:D7:ED:39:88:D6:2D:AF:36:51:86:19:67:07:0D:80:A0:C1:8D:23:EB:6C:05:72:D0:29:E6:5F:58:59:94:DF:46:E1:93:35:FD:F6:99:AF:21:82:77:7F:57:D0:18:B6:A8:E3:89:D0:12:37:64:9C:8B:E9:9B:41:CC:82:F6:A0:60:29:D0:56:79:E1:25:2B:73:C9:8C:F7:DB:87:E5:58:B3:D2:A7:9E:CE:41:E3:4C:B6:BE:8E:E5:6D:07:75:6C:A1:51:95:3E:0F:84:7A:C0:E6:D8:40:C6:79:6E:26:23:46:1B:40:42:33:20:F0:45:50:11:F6:73:11:DA:F4:58:63:B9:25:11:CB:1F:2A:2D:F2:D1:2B:5C:CF:43:88:5E:5C:09:BC:DF:72:37:AE:A2:29:36:48:75:BE:BD:BB:8F:6A:03:22:1D:33:3D:FB:79:6B:D2:84:4E:F9:95:B0:70:CE:DF:26:F9:F5:25:F4:76:3C:32:C0:68:8D:D0:52:FE:CE:2E:14:87:DF:65:1F:42:C9:3E:D4:80:AA:D3:99:B6:1F:04:B1:88:0B:E2:0D:19:79:0D:EE:BA:30:46:43:76:FB:B4:DE:C5:00:41:31:EF:5A:7C:34:32:BE:C9:81:B8:ED:9F:40:DE:50:A2:D8:C2:C4:56:83:EB:29:AA:81:53:24:75:86:6D:BF:51:21:BF:B7:97:17:AF:EE:72:2A:39",
+      keysize: 4096,
+    },
+    unsupportedExtensions: [],
+    version: "3",
+  },
+  {
+    ext: {
+      aia: {
+        descriptions: [
+          {
+            location: "http://ocsp.digicert.com",
+            method: "Online Certificate Status Protocol (OCSP)",
+          },
+        ],
+        critical: false,
+      },
+      aKID: {
+        critical: false,
+        id: "B1:3E:C3:69:03:F8:BF:47:01:D4:98:26:1A:08:02:EF:63:64:2B:C3",
+      },
+      basicConstraints: { cA: true, critical: true },
+      crlPoints: {
+        critical: false,
+        points: ["http://crl4.digicert.com/DigiCertHighAssuranceEVRootCA.crl"],
+      },
+      cp: {
+        critical: false,
+        policies: [
+          {
+            id: "2.5.29.32.0",
+            qualifiers: [
+              {
+                id: "1.3.6.1.5.5.7.2.1",
+                name: "Practices Statement",
+                value: "https://www.digicert.com/CPS",
+              },
+            ],
+          },
+        ],
+      },
+      eKeyUsages: {
+        critical: false,
+        purposes: ["Server Authentication", "Client Authentication"],
+      },
+      keyUsages: {
+        critical: true,
+        purposes: ["Digital Signature", "Certificate Signing", "CRL Signing"],
+      },
+      msCrypto: { exists: false },
+      ocspStaple: { critical: false, required: false },
+      scts: { critical: false, timestamps: [] },
+      sKID: {
+        critical: false,
+        id: "3D:D3:50:A5:D6:A0:AD:EE:F3:4A:60:0A:65:D3:21:D4:F8:F8:D6:0F",
+      },
+      san: { altNames: [], critical: false },
+    },
+    files: {
+      pem:
+        "-----BEGIN%20CERTIFICATE-----%0D%0AMIIEtjCCA56gAwIBAgIQDHmpRLCMEZUgkmFf4msdgzANBgkqhkiG9w0BAQsFADBs%0D%0AMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3%0D%0Ad3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j%0D%0AZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowdTEL%0D%0AMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3%0D%0ALmRpZ2ljZXJ0LmNvbTE0MDIGA1UEAxMrRGlnaUNlcnQgU0hBMiBFeHRlbmRlZCBW%0D%0AYWxpZGF0aW9uIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC%0D%0AggEBANdTpARR+JmmFkhLZyeqk0nQOe0MsLAAh/FnKIaFjI5j2ryxQDji0/XspQUY%0D%0AuD0+xZkXMuwYjPrxDKZkIYXLBxA0sFKIKx9om9KxjxKws9LniB8f7zh3VFNfgHk/%0D%0ALhqqqB5LKw2rt2O5Nbd9FLxZS99RStKh4gzikIKHaq7q12TWmFXo/a8aUGxUvBHy%0D%0A/Urynbt/DvTVvo4WiRJV2MBxNO723C3sxIclho3YIeSwTQyJ3DkmF93215SF2AQh%0D%0AcJ1vb/9cuhnhRctWVyh+HA1BV6q3uCe7seT6Ku8hI3UarS2bhjWMnHe1c63YlC3k%0D%0A8wyd7sFOYn4XwHGeLN7x+RAoGTMCAwEAAaOCAUkwggFFMBIGA1UdEwEB/wQIMAYB%0D%0AAf8CAQAwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF%0D%0ABQcDAjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp%0D%0AZ2ljZXJ0LmNvbTBLBgNVHR8ERDBCMECgPqA8hjpodHRwOi8vY3JsNC5kaWdpY2Vy%0D%0AdC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3JsMD0GA1UdIAQ2%0D%0AMDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5j%0D%0Ab20vQ1BTMB0GA1UdDgQWBBQ901Cl1qCt7vNKYApl0yHU+PjWDzAfBgNVHSMEGDAW%0D%0AgBSxPsNpA/i/RwHUmCYaCALvY2QrwzANBgkqhkiG9w0BAQsFAAOCAQEAnbbQkIbh%0D%0AhgLtxaDwNBx0wY12zIYKqPBKikLWP8ipTa18CK3mtlC4ohpNiAexKSHc59rGPCHg%0D%0A4xFJcKx6HQGkyhE6V6t9VypAdP3THYUYUN9XR3WhfVUgLkc3UHKMf4Ib0mKPLQNa%0D%0A2sPIoc4sUqIAY+tzunHISScjl2SFnjgOrWNoPLpSgVh5oywM395t6zHyuqB8bPEs%0D%0A1OG9d4Q3A84ytciagRpKkk47RpqF/oOi+Z6Mo8wNXrM9zwR4jxQUezKcxwCmXMS1%0D%0AoVWNWlZopCJwqjyBcdmdqEU79OX2olHdx3ti6G8MdOu42vi/hw15UJGQmxg7kVkn%0D%0A8TUoE6smftX3eg==%0D%0A-----END%20CERTIFICATE-----%0D%0A",
+    },
+    fingerprint: {
+      sha1: "7E:2F:3A:4F:8F:E8:FA:8A:57:30:AE:CA:02:96:96:63:7E:98:6F:3F",
+      sha256:
+        "40:3E:06:2A:26:53:05:91:13:28:5B:AF:80:A0:D4:AE:42:2C:84:8C:9F:78:FA:D0:1F:C9:4B:C5:B8:7F:EF:1A",
+    },
+    issuer: {
+      cn: "DigiCert High Assurance EV Root CA",
+      dn:
+        "c=US, o=DigiCert Inc, ou=www.digicert.com, cn=DigiCert High Assurance EV Root CA",
+      entries: [
+        ["Country", "US"],
+        ["Organization", "DigiCert Inc"],
+        ["Organizational Unit", "www.digicert.com"],
+        ["Common Name", "DigiCert High Assurance EV Root CA"],
+      ],
+    },
+    notBefore: "10/22/2013, 10:00:00 AM (Brasilia Standard Time)",
+    notBeforeUTC: "Tue, 22 Oct 2013 12:00:00 GMT",
+    notAfter: "10/22/2028, 9:00:00 AM (Brasilia Standard Time)",
+    notAfterUTC: "Sun, 22 Oct 2028 12:00:00 GMT",
+    subject: {
+      cn: "DigiCert SHA2 Extended Validation Server CA",
+      dn:
+        "c=US, o=DigiCert Inc, ou=www.digicert.com, cn=DigiCert SHA2 Extended Validation Server CA",
+      entries: [
+        ["Country", "US"],
+        ["Organization", "DigiCert Inc"],
+        ["Organizational Unit", "www.digicert.com"],
+        ["Common Name", "DigiCert SHA2 Extended Validation Server CA"],
+      ],
+    },
+    serialNumber: "0C:79:A9:44:B0:8C:11:95:20:92:61:5F:E2:6B:1D:83",
+    signature: {
+      name: "SHA-256 with RSA Encryption",
+      type: "1.2.840.113549.1.1.11",
+    },
+    subjectPublicKeyInfo: {
+      e: 65537,
+      kty: "RSA",
+      n:
+        "D7:53:A4:04:51:F8:99:A6:16:48:4B:67:27:AA:93:49:D0:39:ED:0C:B0:B0:00:87:F1:67:28:86:85:8C:8E:63:DA:BC:B1:40:38:E2:D3:F5:EC:A5:05:18:B8:3D:3E:C5:99:17:32:EC:18:8C:FA:F1:0C:A6:64:21:85:CB:07:10:34:B0:52:88:2B:1F:68:9B:D2:B1:8F:12:B0:B3:D2:E7:88:1F:1F:EF:38:77:54:53:5F:80:79:3F:2E:1A:AA:A8:1E:4B:2B:0D:AB:B7:63:B9:35:B7:7D:14:BC:59:4B:DF:51:4A:D2:A1:E2:0C:E2:90:82:87:6A:AE:EA:D7:64:D6:98:55:E8:FD:AF:1A:50:6C:54:BC:11:F2:FD:4A:F2:9D:BB:7F:0E:F4:D5:BE:8E:16:89:12:55:D8:C0:71:34:EE:F6:DC:2D:EC:C4:87:25:86:8D:D8:21:E4:B0:4D:0C:89:DC:39:26:17:DD:F6:D7:94:85:D8:04:21:70:9D:6F:6F:FF:5C:BA:19:E1:45:CB:56:57:28:7E:1C:0D:41:57:AA:B7:B8:27:BB:B1:E4:FA:2A:EF:21:23:75:1A:AD:2D:9B:86:35:8C:9C:77:B5:73:AD:D8:94:2D:E4:F3:0C:9D:EE:C1:4E:62:7E:17:C0:71:9E:2C:DE:F1:F9:10:28:19:33",
+      keysize: 2048,
+    },
+    unsupportedExtensions: [],
+    version: "3",
+  },
+  {
+    ext: {
+      aia: { critical: false },
+      aKID: {
+        critical: false,
+        id: "B1:3E:C3:69:03:F8:BF:47:01:D4:98:26:1A:08:02:EF:63:64:2B:C3",
+      },
+      basicConstraints: { cA: true, critical: true },
+      cp: { critical: false },
+      keyUsages: {
+        critical: true,
+        purposes: ["Digital Signature", "Certificate Signing", "CRL Signing"],
+      },
+      msCrypto: { exists: false },
+      ocspStaple: { critical: false, required: false },
+      scts: { critical: false, timestamps: [] },
+      sKID: {
+        critical: false,
+        id: "B1:3E:C3:69:03:F8:BF:47:01:D4:98:26:1A:08:02:EF:63:64:2B:C3",
+      },
+      san: { altNames: [], critical: false },
+    },
+    files: {
+      pem:
+        "-----BEGIN%20CERTIFICATE-----%0D%0AMIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs%0D%0AMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3%0D%0Ad3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j%0D%0AZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL%0D%0AMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3%0D%0ALmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug%0D%0ARVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm%0D%0A+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW%0D%0APNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM%0D%0AxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB%0D%0AIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3%0D%0AhzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg%0D%0AEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF%0D%0AMAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA%0D%0AFLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec%0D%0AnzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z%0D%0AeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF%0D%0AhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2%0D%0AYzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe%0D%0AvEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep%0D%0A+OkuE6N36B9K%0D%0A-----END%20CERTIFICATE-----%0D%0A",
+    },
+    fingerprint: {
+      sha1: "5F:B7:EE:06:33:E2:59:DB:AD:0C:4C:9A:E6:D3:8F:1A:61:C7:DC:25",
+      sha256:
+        "74:31:E5:F4:C3:C1:CE:46:90:77:4F:0B:61:E0:54:40:88:3B:A9:A0:1E:D0:0B:A6:AB:D7:80:6E:D3:B1:18:CF",
+    },
+    issuer: {
+      cn: "DigiCert High Assurance EV Root CA",
+      dn:
+        "c=US, o=DigiCert Inc, ou=www.digicert.com, cn=DigiCert High Assurance EV Root CA",
+      entries: [
+        ["Country", "US"],
+        ["Organization", "DigiCert Inc"],
+        ["Organizational Unit", "www.digicert.com"],
+        ["Common Name", "DigiCert High Assurance EV Root CA"],
+      ],
+    },
+    notBefore: "11/9/2006, 10:00:00 PM (Brasilia Standard Time)",
+    notBeforeUTC: "Fri, 10 Nov 2006 00:00:00 GMT",
+    notAfter: "11/9/2031, 9:00:00 PM (Brasilia Standard Time)",
+    notAfterUTC: "Mon, 10 Nov 2031 00:00:00 GMT",
+    subject: {
+      cn: "DigiCert High Assurance EV Root CA",
+      dn:
+        "c=US, o=DigiCert Inc, ou=www.digicert.com, cn=DigiCert High Assurance EV Root CA",
+      entries: [
+        ["Country", "US"],
+        ["Organization", "DigiCert Inc"],
+        ["Organizational Unit", "www.digicert.com"],
+        ["Common Name", "DigiCert High Assurance EV Root CA"],
+      ],
+    },
+    serialNumber: "02:AC:5C:26:6A:0B:40:9B:8F:0B:79:F2:AE:46:25:77",
+    signature: {
+      name: "SHA-1 with RSA Encryption",
+      type: "1.2.840.113549.1.1.5",
+    },
+    subjectPublicKeyInfo: {
+      e: 65537,
+      kty: "RSA",
+      n:
+        "C6:CC:E5:73:E6:FB:D4:BB:E5:2D:2D:32:A6:DF:E5:81:3F:C9:CD:25:49:B6:71:2A:C3:D5:94:34:67:A2:0A:1C:B0:5F:69:A6:40:B1:C4:B7:B2:8F:D0:98:A4:A9:41:59:3A:D3:DC:94:D6:3C:DB:74:38:A4:4A:CC:4D:25:82:F7:4A:A5:53:12:38:EE:F3:49:6D:71:91:7E:63:B6:AB:A6:5F:C3:A4:84:F8:4F:62:51:BE:F8:C5:EC:DB:38:92:E3:06:E5:08:91:0C:C4:28:41:55:FB:CB:5A:89:15:7E:71:E8:35:BF:4D:72:09:3D:BE:3A:38:50:5B:77:31:1B:8D:B3:C7:24:45:9A:A7:AC:6D:00:14:5A:04:B7:BA:13:EB:51:0A:98:41:41:22:4E:65:61:87:81:41:50:A6:79:5C:89:DE:19:4A:57:D5:2E:E6:5D:1C:53:2C:7E:98:CD:1A:06:16:A4:68:73:D0:34:04:13:5C:A1:71:D3:5A:7C:55:DB:5E:64:E1:37:87:30:56:04:E5:11:B4:29:80:12:F1:79:39:88:A2:02:11:7C:27:66:B7:88:B7:78:F2:CA:0A:A8:38:AB:0A:64:C2:BF:66:5D:95:84:C1:A1:25:1E:87:5D:1A:50:0B:20:12:CC:41:BB:6E:0B:51:38:B8:4B:CB",
+      keysize: 2048,
+    },
+    unsupportedExtensions: [],
+    version: "3",
+  },
+];
new file mode 100644
--- /dev/null
+++ b/toolkit/components/certviewer/tests/chrome/test_adjustCertInformation.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>certviewer adjustCertInformation test</title>
+    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+    <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+    <script src="chrome://global/content/certviewer/pvutils_bundle.js"></script>
+    <script src="chrome://global/content/certviewer/asn1js_bundle.js"></script>
+    <script src="chrome://global/content/certviewer/pkijs_bundle.js"></script>
+
+    <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+  </head>
+<body>
+  <script type="module">
+    import { adjustCertInformation } from "chrome://global/content/certviewer/certviewer.js";
+    import { parseOutput } from "./parseOutput.js";
+
+    function hasNullElements(obj) {
+      for (let key of Object.keys(obj)) {
+        if (obj[key] == null) return false;
+        if (typeof(obj[key]) === 'object') {
+          if (hasNullElements(obj[key]) === false) {
+            return false;
+          }
+        }
+      }
+      return true;
+    }
+
+    async function doTest() {
+      ok(adjustCertInformation, "adjustCertInformation should be available in this context");
+      ok(parseOutput, "parseOutput should be available in this context");
+      is(typeof(parseOutput), 'object', "parseOutput must be an object");
+
+      for (let cert of parseOutput) {
+        let adjustedCerts = adjustCertInformation(cert);
+        let result = hasNullElements(adjustedCerts.certItems);
+        ok(result, "adjustCertInformation function shouldn't return null elements");
+      }
+
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    doTest();
+
+  </script>
+</body>
+</html>
old mode 100755
new mode 100644
old mode 100755
new mode 100644
--- a/toolkit/components/telemetry/core/TelemetryEvent.cpp
+++ b/toolkit/components/telemetry/core/TelemetryEvent.cpp
@@ -1289,17 +1289,17 @@ nsresult TelemetryEvent::CreateSnapshots
         }
       }
     };
 
     // Take a snapshot of the plain and dynamic builtin events.
     snapshotter(gEventRecords);
     if (aClear) {
       gEventRecords.Clear();
-      for (auto pair : leftovers) {
+      for (auto& pair : leftovers) {
         gEventRecords.Put(pair.first(),
                           new EventRecordArray(std::move(pair.second())));
       }
       leftovers.Clear();
     }
   }
 
   // (2) Serialize the events to a JS object.
--- a/toolkit/components/telemetry/core/TelemetryScalar.cpp
+++ b/toolkit/components/telemetry/core/TelemetryScalar.cpp
@@ -1841,17 +1841,17 @@ ScalarResult internal_UpdateKeyedScalar(
 /**
  * Helper function to convert an array of |DynamicScalarInfo|
  * to |DynamicScalarDefinition| used by the IPC calls.
  */
 void internal_DynamicScalarToIPC(
     const StaticMutexAutoLock& lock,
     const nsTArray<DynamicScalarInfo>& aDynamicScalarInfos,
     nsTArray<DynamicScalarDefinition>& aIPCDefs) {
-  for (auto info : aDynamicScalarInfos) {
+  for (auto& info : aDynamicScalarInfos) {
     DynamicScalarDefinition stubDefinition;
     stubDefinition.type = info.kind;
     stubDefinition.dataset = info.dataset;
     stubDefinition.expired = info.mDynamicExpiration;
     stubDefinition.keyed = info.keyed;
     stubDefinition.name = info.mDynamicName;
     stubDefinition.builtin = info.builtin;
     aIPCDefs.AppendElement(stubDefinition);
@@ -1886,17 +1886,17 @@ void internal_RegisterScalars(const Stat
   // Register the new scalars.
   if (!gDynamicScalarInfo) {
     gDynamicScalarInfo = new nsTArray<DynamicScalarInfo>();
   }
   if (!gDynamicStoreNames) {
     gDynamicStoreNames = new nsTArray<RefPtr<nsAtom>>();
   }
 
-  for (auto scalarInfo : scalarInfos) {
+  for (auto& scalarInfo : scalarInfos) {
     // Allow expiring scalars that were already registered.
     CharPtrEntryType* existingKey =
         gScalarNameIDMap.GetEntry(scalarInfo.name());
     if (existingKey) {
       // Change the scalar to expired if needed.
       if (scalarInfo.mDynamicExpiration && !scalarInfo.builtin) {
         DynamicScalarInfo& scalarData =
             (*gDynamicScalarInfo)[existingKey->mData.id];
@@ -3655,17 +3655,17 @@ void TelemetryScalar::GetDynamicScalarDe
  */
 void TelemetryScalar::AddDynamicScalarDefinitions(
     const nsTArray<DynamicScalarDefinition>& aDefs) {
   MOZ_ASSERT(!XRE_IsParentProcess());
 
   nsTArray<DynamicScalarInfo> dynamicStubs;
 
   // Populate the definitions array before acquiring the lock.
-  for (auto def : aDefs) {
+  for (auto& def : aDefs) {
     bool recordOnRelease = def.dataset == nsITelemetry::DATASET_ALL_CHANNELS;
     dynamicStubs.AppendElement(DynamicScalarInfo{def.type,
                                                  recordOnRelease,
                                                  def.expired,
                                                  def.name,
                                                  def.keyed,
                                                  def.builtin,
                                                  {} /* stores */});
--- a/toolkit/components/url-classifier/Classifier.cpp
+++ b/toolkit/components/url-classifier/Classifier.cpp
@@ -34,17 +34,18 @@ extern mozilla::LazyLogModule gUrlClassi
 #define LOG_ENABLED() \
   MOZ_LOG_TEST(gUrlClassifierDbServiceLog, mozilla::LogLevel::Debug)
 
 #define STORE_DIRECTORY NS_LITERAL_CSTRING("safebrowsing")
 #define TO_DELETE_DIR_SUFFIX NS_LITERAL_CSTRING("-to_delete")
 #define BACKUP_DIR_SUFFIX NS_LITERAL_CSTRING("-backup")
 #define UPDATING_DIR_SUFFIX NS_LITERAL_CSTRING("-updating")
 
-#define METADATA_SUFFIX NS_LITERAL_CSTRING(".metadata")
+#define V4_METADATA_SUFFIX NS_LITERAL_CSTRING(".metadata")
+#define V2_METADATA_SUFFIX NS_LITERAL_CSTRING(".sbstore")
 
 namespace mozilla {
 namespace safebrowsing {
 
 void Classifier::SplitTables(const nsACString& str,
                              nsTArray<nsCString>& tables) {
   tables.Clear();
 
@@ -396,74 +397,55 @@ void Classifier::DeleteTables(nsIFile* a
                                    leafName.get())
                        .get());
       }
     }
   }
   NS_ENSURE_SUCCESS_VOID(rv);
 }
 
+// This function is I/O intensive. It should only be called before applying
+// an update.
 void Classifier::TableRequest(nsACString& aResult) {
   MOZ_ASSERT(!NS_IsMainThread(),
              "TableRequest must be called on the classifier worker thread.");
 
   // This function and all disk I/O are guaranteed to occur
   // on the same thread so we don't need to add a lock around.
   if (!mIsTableRequestResultOutdated) {
     aResult = mTableRequestResult;
     return;
   }
 
-  // Generating v2 table info.
-  nsTArray<nsCString> tables;
-  ActiveTables(tables);
-  for (uint32_t i = 0; i < tables.Length(); i++) {
-    HashStore store(tables[i], GetProvider(tables[i]), mRootStoreDirectory);
-
-    nsresult rv = store.Open();
-    if (NS_FAILED(rv)) {
-      continue;
-    }
-
-    ChunkSet& adds = store.AddChunks();
-    ChunkSet& subs = store.SubChunks();
-
-    // Open HashStore will always succeed even that is not a v2 table.
-    // So skip tables without add and sub chunks.
-    if (adds.Length() == 0 && subs.Length() == 0) {
-      continue;
-    }
+  // We reset tables failed to load here; not just tables are corrupted.
+  // It is because this is a safer way to ensure Safe Browsing databases
+  // can be recovered from any bad situations.
+  nsTArray<nsCString> failedTables;
 
-    aResult.Append(store.TableName());
-    aResult.Append(';');
-
-    if (adds.Length() > 0) {
-      aResult.AppendLiteral("a:");
-      nsAutoCString addList;
-      adds.Serialize(addList);
-      aResult.Append(addList);
-    }
-
-    if (subs.Length() > 0) {
-      if (adds.Length() > 0) aResult.Append(':');
-      aResult.AppendLiteral("s:");
-      nsAutoCString subList;
-      subs.Serialize(subList);
-      aResult.Append(subList);
-    }
-
-    aResult.Append('\n');
+  // Load meta data from *.sbstore files in the root directory.
+  // Specifically for v4 tables.
+  nsCString v2Metadata;
+  nsresult rv = LoadHashStore(mRootStoreDirectory, v2Metadata, failedTables);
+  if (NS_SUCCEEDED(rv)) {
+    aResult.Append(v2Metadata);
   }
 
   // Load meta data from *.metadata files in the root directory.
   // Specifically for v4 tables.
-  nsCString metadata;
-  nsresult rv = LoadMetadata(mRootStoreDirectory, metadata);
+  nsCString v4Metadata;
+  rv = LoadMetadata(mRootStoreDirectory, v4Metadata, failedTables);
   if (NS_SUCCEEDED(rv)) {
-    aResult.Append(metadata);
+    aResult.Append(v4Metadata);
+  }
+
+  // Clear data for tables that we failed to open, a full update should
+  // be requested for those tables.
+  if (failedTables.Length() != 0) {
+    LOG(("Reset tables failed to open before applying an update"));
+    ResetTables(Clear_All, failedTables);
   }
 
   // Update the TableRequest result in-memory cache.
   mTableRequestResult = aResult;
   mIsTableRequestResultOutdated = false;
 }
 
 nsresult Classifier::CheckURIFragments(
@@ -742,52 +724,53 @@ nsresult Classifier::AsyncApplyUpdates(c
   RefPtr<Classifier> self = this;
   nsCOMPtr<nsIRunnable> bgRunnable = NS_NewRunnableFunction(
       "safebrowsing::Classifier::AsyncApplyUpdates",
       [self, aUpdates, aCallback, callerThread] {
         MOZ_ASSERT(NS_GetCurrentThread() == self->mUpdateThread,
                    "MUST be on update thread");
 
         nsresult bgRv;
-        nsCString failedTableName;
+        nsTArray<nsCString> failedTableNames;
 
         TableUpdateArray updates;
 
         // Make a copy of the array since we'll be removing entries as
         // we process them on the background thread.
         if (updates.AppendElements(aUpdates, fallible)) {
           LOG(("Step 1. ApplyUpdatesBackground on update thread."));
-          bgRv = self->ApplyUpdatesBackground(updates, failedTableName);
+          bgRv = self->ApplyUpdatesBackground(updates, failedTableNames);
         } else {
           LOG(
               ("Step 1. Not enough memory to run ApplyUpdatesBackground on "
                "update thread."));
           bgRv = NS_ERROR_OUT_OF_MEMORY;
         }
 
         nsCOMPtr<nsIRunnable> fgRunnable = NS_NewRunnableFunction(
             "safebrowsing::Classifier::AsyncApplyUpdates",
-            [self, aCallback, bgRv, failedTableName, callerThread] {
+            [self, aCallback, bgRv, failedTableNames, callerThread] {
               MOZ_ASSERT(NS_GetCurrentThread() == callerThread,
                          "MUST be on caller thread");
 
               LOG(("Step 2. ApplyUpdatesForeground on caller thread"));
-              nsresult rv = self->ApplyUpdatesForeground(bgRv, failedTableName);
+              nsresult rv =
+                  self->ApplyUpdatesForeground(bgRv, failedTableNames);
 
               LOG(("Step 3. Updates applied! Fire callback."));
               aCallback(rv);
             });
         callerThread->Dispatch(fgRunnable, NS_DISPATCH_NORMAL);
       });
 
   return mUpdateThread->Dispatch(bgRunnable, NS_DISPATCH_NORMAL);
 }
 
-nsresult Classifier::ApplyUpdatesBackground(TableUpdateArray& aUpdates,
-                                            nsACString& aFailedTableName) {
+nsresult Classifier::ApplyUpdatesBackground(
+    TableUpdateArray& aUpdates, nsTArray<nsCString>& aFailedTableNames) {
   // |mUpdateInterrupted| is guaranteed to have been unset.
   // If |mUpdateInterrupted| is set at any point, Reset() must have
   // been called then we need to interrupt the update process.
   // We only add checkpoints for non-trivial tasks.
 
   if (aUpdates.IsEmpty()) {
     return NS_OK;
   }
@@ -839,48 +822,62 @@ nsresult Classifier::ApplyUpdatesBackgro
 
     // Will update the mirrored in-memory and on-disk databases.
     if (TableUpdate::Cast<TableUpdateV2>(update)) {
       rv = UpdateHashStore(aUpdates, updateTable);
     } else {
       rv = UpdateTableV4(aUpdates, updateTable);
     }
 
-    if (NS_FAILED(rv)) {
-      aFailedTableName = updateTable;
-      RemoveUpdateIntermediaries();
-      return rv;
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      LOG(("Failed to update table: %s", updateTable.get()));
+      // We don't quit the updating process immediately when we discover
+      // a failure. Instead, we continue to apply updates to the
+      // remaining tables to find other tables which may also fail to
+      // apply an update. This help us reset all the corrupted tables
+      // within a single update.
+      // Note that changes that result from successful updates don't take
+      // effect after the updating process is finished. This is because
+      // when an error occurs during the updating process, we ignore all
+      // changes that have happened during the udpating process.
+      aFailedTableNames.AppendElement(updateTable);
+      continue;
     }
   }
 
+  if (!aFailedTableNames.IsEmpty()) {
+    RemoveUpdateIntermediaries();
+    return NS_ERROR_FAILURE;
+  }
+
   if (LOG_ENABLED()) {
     PRIntervalTime clockEnd = PR_IntervalNow();
     LOG(("update took %dms\n",
          PR_IntervalToMilliseconds(clockEnd - clockStart)));
   }
 
   return rv;
 }
 
 nsresult Classifier::ApplyUpdatesForeground(
-    nsresult aBackgroundRv, const nsACString& aFailedTableName) {
+    nsresult aBackgroundRv, const nsTArray<nsCString>& aFailedTableNames) {
   if (ShouldAbort()) {
     LOG(("Update is interrupted! Just remove update intermediaries."));
     RemoveUpdateIntermediaries();
     return NS_OK;
   }
   if (NS_SUCCEEDED(aBackgroundRv)) {
     // Copy and Invalidate fullhash cache here because this call requires
     // mLookupCaches which is only available on work-thread
     CopyAndInvalidateFullHashCache();
 
     return SwapInNewTablesAndCleanup();
   }
   if (NS_ERROR_OUT_OF_MEMORY != aBackgroundRv) {
-    ResetTables(Clear_All, nsTArray<nsCString>{nsCString(aFailedTableName)});
+    ResetTables(Clear_All, aFailedTableNames);
   }
   return aBackgroundRv;
 }
 
 nsresult Classifier::ApplyFullHashes(ConstTableUpdateArray& aUpdates) {
   MOZ_ASSERT(NS_GetCurrentThread() != mUpdateThread,
              "ApplyFullHashes() MUST NOT be called on update thread");
   MOZ_ASSERT(
@@ -916,19 +913,22 @@ void Classifier::DropStores() {
 
 nsresult Classifier::RegenActiveTables() {
   if (ShouldAbort()) {
     return NS_OK;  // nothing to do, the classifier is done
   }
 
   mActiveTablesCache.Clear();
 
-  // Create
+  // The extension of V2 and V4 prefix files is .vlpset
+  // We still check .pset here for legacy load.
+  nsTArray<nsCString> exts = {NS_LITERAL_CSTRING(".vlpset"),
+                              NS_LITERAL_CSTRING(".pset")};
   nsTArray<nsCString> foundTables;
-  nsresult rv = ScanStoreDir(mRootStoreDirectory, foundTables);
+  nsresult rv = ScanStoreDir(mRootStoreDirectory, exts, foundTables);
   Unused << NS_WARN_IF(NS_FAILED(rv));
 
   // We don't have test tables on disk, add Moz built-in entries here
   rv = AddMozEntries(foundTables);
   Unused << NS_WARN_IF(NS_FAILED(rv));
 
   for (const auto& table : foundTables) {
     RefPtr<const LookupCache> lookupCache = GetLookupCache(table);
@@ -972,46 +972,45 @@ nsresult Classifier::AddMozEntries(nsTAr
 
     aTables.AppendElement(table);
   }
 
   return NS_OK;
 }
 
 nsresult Classifier::ScanStoreDir(nsIFile* aDirectory,
+                                  const nsTArray<nsCString>& aExtensions,
                                   nsTArray<nsCString>& aTables) {
   nsCOMPtr<nsIDirectoryEnumerator> entries;
   nsresult rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIFile> file;
   while (NS_SUCCEEDED(rv = entries->GetNextFile(getter_AddRefs(file))) &&
          file) {
     // If |file| is a directory, recurse to find its entries as well.
     bool isDirectory;
     if (NS_FAILED(file->IsDirectory(&isDirectory))) {
       continue;
     }
     if (isDirectory) {
-      ScanStoreDir(file, aTables);
+      ScanStoreDir(file, aExtensions, aTables);
       continue;
     }
 
     nsAutoCString leafName;
     rv = file->GetNativeLeafName(leafName);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    // The extension of V2 and V4 prefix files is .vlpset
-    // We still check .pset here for legacy load.
-    if (StringEndsWith(leafName, NS_LITERAL_CSTRING(".vlpset"))) {
-      aTables.AppendElement(
-          Substring(leafName, 0, leafName.Length() - strlen(".vlpset")));
-    } else if (StringEndsWith(leafName, NS_LITERAL_CSTRING(".pset"))) {
-      aTables.AppendElement(
-          Substring(leafName, 0, leafName.Length() - strlen(".pset")));
+    for (const auto& ext : aExtensions) {
+      if (StringEndsWith(leafName, ext)) {
+        aTables.AppendElement(
+            Substring(leafName, 0, leafName.Length() - strlen(ext.get())));
+        break;
+      }
     }
   }
 
   return NS_OK;
 }
 
 nsresult Classifier::ActiveTables(nsTArray<nsCString>& aTables) const {
   aTables = mActiveTablesCache;
@@ -1274,33 +1273,17 @@ nsresult Classifier::UpdateHashStore(Tab
 
   HashStore store(aTable, GetProvider(aTable), mUpdatingDirectory);
 
   if (!CheckValidUpdate(aUpdates, store.TableName())) {
     return NS_OK;
   }
 
   nsresult rv = store.Open();
-  if (rv == NS_ERROR_FILE_CORRUPTED) {
-    // This is where we remove the older version(3) of HashStore, we cannot
-    // remove it earlier because we need the 'Completions' in it before
-    // upgrading to new format. Remove this during update because we know that
-    // newer version of HashStore and PrefixSet will be written in the update
-    // process.
-    LOG(("HashStore is corrupted, remove on-disk data and continue to update"));
-
-    // store.Reset removes the on-disk file. We can still apply this update
-    // by merging recived update data to an empty HashStore.
-    rv = store.Reset();
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // Open HashStore again, it should be an empty HashStore at this point.
-    rv = store.Open();
-    NS_ENSURE_SUCCESS(rv, rv);
-  } else if (NS_WARN_IF(NS_FAILED(rv))) {
+  if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   rv = store.BeginUpdate();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Read the part of the store that is (only) in the cache
   RefPtr<LookupCacheV2> lookupCacheV2;
@@ -1575,17 +1558,20 @@ RefPtr<LookupCache> Classifier::GetLooku
   if (aForUpdate) {
     // Remove intermediaries no matter if it's due to file corruption or not.
     RemoveUpdateIntermediaries();
     return nullptr;
   }
 
   // Non-update case.
   if (rv == NS_ERROR_FILE_CORRUPTED) {
-    Reset();  // Not including the update intermediaries.
+    // Remove all the on-disk data when the table's prefix file is corrupted.
+    LOG(("Failed to get prefixes from file for table %s, delete on-disk data!",
+         aTable.BeginReading()));
+    ResetTables(Clear_All, nsTArray<nsCString>{nsCString(aTable)});
   }
   return nullptr;
 }
 
 nsresult Classifier::ReadNoiseEntries(const Prefix& aPrefix,
                                       const nsACString& aTableName,
                                       uint32_t aCount,
                                       PrefixArray& aNoiseEntries) {
@@ -1643,79 +1629,121 @@ nsresult Classifier::ReadNoiseEntries(co
     if (newPrefix != aPrefix) {
       aNoiseEntries.AppendElement(newPrefix);
     }
   }
 
   return NS_OK;
 }
 
-nsresult Classifier::LoadMetadata(nsIFile* aDirectory, nsACString& aResult) {
-  nsCOMPtr<nsIDirectoryEnumerator> entries;
-  nsresult rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
-  NS_ENSURE_SUCCESS(rv, rv);
-  NS_ENSURE_ARG_POINTER(entries);
+nsresult Classifier::LoadHashStore(nsIFile* aDirectory, nsACString& aResult,
+                                   nsTArray<nsCString>& aFailedTableNames) {
+  nsTArray<nsCString> tables;
+  nsTArray<nsCString> exts = {V2_METADATA_SUFFIX};
+
+  nsresult rv = ScanStoreDir(mRootStoreDirectory, exts, tables);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
 
-  nsCOMPtr<nsIFile> file;
-  while (NS_SUCCEEDED(rv = entries->GetNextFile(getter_AddRefs(file))) &&
-         file) {
-    // If |file| is a directory, recurse to find its entries as well.
-    bool isDirectory;
-    if (NS_FAILED(file->IsDirectory(&isDirectory))) {
+  for (const auto& table : tables) {
+    HashStore store(table, GetProvider(table), mRootStoreDirectory);
+
+    nsresult rv = store.Open();
+    if (NS_FAILED(rv) || !GetLookupCache(table)) {
+      // TableRequest is called right before applying an update.
+      // If we cannot retrieve metadata for a given table or we fail to
+      // load the prefixes for a table, reset the table to esnure we
+      // apply a full update to the table.
+      LOG(("Failed to get metadata for v2 table %s", table.get()));
+      aFailedTableNames.AppendElement(table);
       continue;
     }
-    if (isDirectory) {
-      LoadMetadata(file, aResult);
+
+    ChunkSet& adds = store.AddChunks();
+    ChunkSet& subs = store.SubChunks();
+
+    // Open HashStore will always succeed even that is not a v2 table.
+    // So skip tables without add and sub chunks.
+    if (adds.Length() == 0 && subs.Length() == 0) {
       continue;
     }
 
-    // Truncate file extension to get the table name.
-    nsCString tableName;
-    rv = file->GetNativeLeafName(tableName);
-    NS_ENSURE_SUCCESS(rv, rv);
+    aResult.Append(store.TableName());
+    aResult.Append(';');
 
-    int32_t dot = tableName.RFind(METADATA_SUFFIX);
-    if (dot == -1) {
-      continue;
+    if (adds.Length() > 0) {
+      aResult.AppendLiteral("a:");
+      nsAutoCString addList;
+      adds.Serialize(addList);
+      aResult.Append(addList);
+    }
+
+    if (subs.Length() > 0) {
+      if (adds.Length() > 0) {
+        aResult.Append(':');
+      }
+      aResult.AppendLiteral("s:");
+      nsAutoCString subList;
+      subs.Serialize(subList);
+      aResult.Append(subList);
     }
-    tableName.Cut(dot, METADATA_SUFFIX.Length());
+
+    aResult.Append('\n');
+  }
+
+  return rv;
+}
+
+nsresult Classifier::LoadMetadata(nsIFile* aDirectory, nsACString& aResult,
+                                  nsTArray<nsCString>& aFailedTableNames) {
+  nsTArray<nsCString> tables;
+  nsTArray<nsCString> exts = {V4_METADATA_SUFFIX};
 
-    RefPtr<LookupCacheV4> lookupCacheV4;
-    {
-      RefPtr<LookupCache> lookupCache = GetLookupCache(tableName);
-      if (lookupCache) {
-        lookupCacheV4 = LookupCache::Cast<LookupCacheV4>(lookupCache);
-      }
-    }
+  nsresult rv = ScanStoreDir(mRootStoreDirectory, exts, tables);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  for (const auto& table : tables) {
+    RefPtr<LookupCache> c = GetLookupCache(table);
+    RefPtr<LookupCacheV4> lookupCacheV4 = LookupCache::Cast<LookupCacheV4>(c);
+
     if (!lookupCacheV4) {
+      aFailedTableNames.AppendElement(table);
       continue;
     }
 
     nsCString state, sha256;
     rv = lookupCacheV4->LoadMetadata(state, sha256);
     Telemetry::Accumulate(Telemetry::URLCLASSIFIER_VLPS_METADATA_CORRUPT,
                           rv == NS_ERROR_FILE_CORRUPTED);
     if (NS_FAILED(rv)) {
-      LOG(("Failed to get metadata for table %s", tableName.get()));
+      LOG(("Failed to get metadata for v4 table %s", table.get()));
+      aFailedTableNames.AppendElement(table);
       continue;
     }
 
     // The state might include '\n' so that we have to encode.
     nsAutoCString stateBase64;
     rv = Base64Encode(state, stateBase64);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
 
     nsAutoCString checksumBase64;
     rv = Base64Encode(sha256, checksumBase64);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
 
     LOG(("Appending state '%s' and checksum '%s' for table %s",
-         stateBase64.get(), checksumBase64.get(), tableName.get()));
+         stateBase64.get(), checksumBase64.get(), table.get()));
 
-    aResult.AppendPrintf("%s;%s:%s\n", tableName.get(), stateBase64.get(),
+    aResult.AppendPrintf("%s;%s:%s\n", table.get(), stateBase64.get(),
                          checksumBase64.get());
   }
 
   return rv;
 }
 
 bool Classifier::ShouldAbort() const {
   return mIsClosed || nsUrlClassifierDBService::ShutdownHasStarted() ||
--- a/toolkit/components/url-classifier/Classifier.h
+++ b/toolkit/components/url-classifier/Classifier.h
@@ -146,17 +146,19 @@ class Classifier {
   // and on-disk data.
   void RemoveUpdateIntermediaries();
 
 #ifdef MOZ_SAFEBROWSING_DUMP_FAILED_UPDATES
   already_AddRefed<nsIFile> GetFailedUpdateDirectroy();
   nsresult DumpFailedUpdate();
 #endif
 
-  nsresult ScanStoreDir(nsIFile* aDirectory, nsTArray<nsCString>& aTables);
+  nsresult ScanStoreDir(nsIFile* aDirectory,
+                        const nsTArray<nsCString>& aExtensions,
+                        nsTArray<nsCString>& aTables);
 
   nsresult UpdateHashStore(TableUpdateArray& aUpdates,
                            const nsACString& aTable);
 
   nsresult UpdateTableV4(TableUpdateArray& aUpdates, const nsACString& aTable);
 
   nsresult UpdateCache(RefPtr<const TableUpdate> aUpdates);
 
@@ -165,41 +167,45 @@ class Classifier {
   }
 
   RefPtr<LookupCache> GetLookupCacheFrom(const nsACString& aTable,
                                          LookupCacheArray& aLookupCaches,
                                          nsIFile* aRootStoreDirectory);
 
   bool CheckValidUpdate(TableUpdateArray& aUpdates, const nsACString& aTable);
 
-  nsresult LoadMetadata(nsIFile* aDirectory, nsACString& aResult);
+  nsresult LoadHashStore(nsIFile* aDirectory, nsACString& aResult,
+                         nsTArray<nsCString>& aFailedTableNames);
+
+  nsresult LoadMetadata(nsIFile* aDirectory, nsACString& aResult,
+                        nsTArray<nsCString>& aFailedTableNames);
 
   static nsCString GetProvider(const nsACString& aTableName);
 
   /**
    * The "background" part of ApplyUpdates. Once the background update
    * is called, the foreground update has to be called along with the
    * background result no matter whether the background update is
    * successful or not.
    */
   nsresult ApplyUpdatesBackground(TableUpdateArray& aUpdates,
-                                  nsACString& aFailedTableName);
+                                  nsTArray<nsCString>& aFailedTableNames);
 
   /**
    * The "foreground" part of ApplyUpdates. The in-use data (in-memory and
    * on-disk) will be touched so this MUST be mutually exclusive to other
    * member functions.
    *
    * If |aBackgroundRv| is successful, the return value is the result of
    * bringing stuff to the foreground. Otherwise, the foreground table may
    * be reset according to the background update failed reason and
    * |aBackgroundRv| will be returned to forward the background update result.
    */
   nsresult ApplyUpdatesForeground(nsresult aBackgroundRv,
-                                  const nsACString& aFailedTableName);
+                                  const nsTArray<nsCString>& aFailedTableNames);
 
   // Used by worker thread and update thread to abort current operation.
   bool ShouldAbort() const;
 
   // Add built-in entries for testing.
   nsresult AddMozEntries(nsTArray<nsCString>& aTables);
 
   // Remove test files if exist
--- a/toolkit/components/url-classifier/HashStore.cpp
+++ b/toolkit/components/url-classifier/HashStore.cpp
@@ -328,17 +328,20 @@ nsresult HashStore::Open(uint32_t aVersi
   }
 
   mFileSize = static_cast<uint32_t>(fileSize);
   rv = NS_NewBufferedInputStream(getter_AddRefs(mInputStream),
                                  origStream.forget(), mFileSize);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = ReadHeader();
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    LOG(("Failed to read header for %s", mTableName.get()));
+    return NS_ERROR_FILE_CORRUPTED;
+  }
 
   rv = SanityCheck(aVersion);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult HashStore::ReadHeader() {
--- a/toolkit/components/url-classifier/LookupCache.cpp
+++ b/toolkit/components/url-classifier/LookupCache.cpp
@@ -679,17 +679,18 @@ nsresult LookupCache::LoadFromFile(nsCOM
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   // Load header
   Header header;
   rv = ReadValue(in, header);
   if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
+    LOG(("Failed to read header for %s", mTableName.get()));
+    return NS_ERROR_FILE_CORRUPTED;
   }
 
   rv = SanityCheck(header);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   // Load data
--- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
@@ -860,22 +860,18 @@ nsUrlClassifierDBServiceWorker::ResetDat
   rv = CloseDb();
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsUrlClassifierDBServiceWorker::ReloadDatabase() {
-  nsTArray<nsCString> tables;
-  nsresult rv = mClassifier->ActiveTables(tables);
-  NS_ENSURE_SUCCESS(rv, rv);
-
   // This will null out mClassifier
-  rv = CloseDb();
+  nsresult rv = CloseDb();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Create new mClassifier and load prefixset and completions from disk.
   rv = OpenDb();
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
--- a/toolkit/moz.configure
+++ b/toolkit/moz.configure
@@ -1256,16 +1256,45 @@ def launcher(value, target):
     if enabled and target.os != 'WINNT':
         die('Cannot enable launcher process on %s', target.os)
     if enabled:
         return True
 
 set_config('MOZ_LAUNCHER_PROCESS', launcher)
 set_define('MOZ_LAUNCHER_PROCESS', launcher)
 
+# llvm-dlltool (Windows only)
+# ==============================================================
+
+@depends(build_project, target, '--enable-compile-environment')
+def check_for_llvm_dlltool(build_project, target, compile_environment):
+    if build_project != 'browser':
+        return
+
+    if target.os != 'WINNT':
+        return
+
+    return compile_environment
+
+llvm_dlltool = check_prog('LLVM_DLLTOOL', ('llvm-dlltool',),
+                          what='llvm-dlltool', when=check_for_llvm_dlltool,
+                          paths=toolchain_search_path)
+
+@depends(target, when=llvm_dlltool)
+def llvm_dlltool_flags(target):
+    arch = {
+        'x86': 'i386',
+        'x86_64': 'i386:x86-64',
+        'aarch64': 'arm64',
+    }[target.cpu]
+
+    return ['-m', arch]
+
+set_config('LLVM_DLLTOOL_FLAGS', llvm_dlltool_flags)
+
 # Maintenance service (Windows only)
 # ==============================================================
 
 option('--enable-maintenance-service',
        when=target_is_windows, default=target_is_windows,
        help='{Enable|Disable} building of maintenance service')
 
 set_define('MOZ_MAINTENANCE_SERVICE',
old mode 100755
new mode 100644
--- a/toolkit/mozapps/installer/packager.mk
+++ b/toolkit/mozapps/installer/packager.mk
@@ -9,17 +9,19 @@ include $(MOZILLA_DIR)/toolkit/mozapps/i
 
 # browser/locales/Makefile uses this makefile for its variable defs, but
 # doesn't want the libs:: rule.
 ifndef PACKAGER_NO_LIBS
 libs:: make-package
 endif
 
 ifdef MOZ_AUTOMATION
+# This allows `RUN_{FIND_DUPES,MOZHARNESS_ZIP}=1 ./mach package` to test locally.
 RUN_FIND_DUPES ?= $(MOZ_AUTOMATION)
+RUN_MOZHARNESS_ZIP ?= $(MOZ_AUTOMATION)
 endif
 
 export USE_ELF_HACK ELF_HACK_FLAGS
 
 stage-package: multilocale.txt locale-manifest.in $(MOZ_PKG_MANIFEST) $(MOZ_PKG_MANIFEST_DEPS)
 	NO_PKG_FILES="$(NO_PKG_FILES)" \
 	$(PYTHON) $(MOZILLA_DIR)/toolkit/mozapps/installer/packager.py $(DEFINES) $(ACDEFINES) \
 		--format $(MOZ_PACKAGER_FORMAT) \
@@ -33,20 +35,22 @@ stage-package: multilocale.txt locale-ma
 		$(addprefix --jarlog ,$(wildcard $(JARLOG_FILE_AB_CD))) \
 		$(addprefix --compress ,$(JAR_COMPRESSION)) \
 		$(MOZ_PKG_MANIFEST) '$(DIST)' '$(DIST)'/$(MOZ_PKG_DIR)$(if $(MOZ_PKG_MANIFEST),,$(_BINPATH)) \
 		$(if $(filter omni,$(MOZ_PACKAGER_FORMAT)),$(if $(NON_OMNIJAR_FILES),--non-resource $(NON_OMNIJAR_FILES)))
 ifdef RUN_FIND_DUPES
 	$(PYTHON) $(MOZILLA_DIR)/toolkit/mozapps/installer/find-dupes.py $(DEFINES) $(ACDEFINES) $(MOZ_PKG_DUPEFLAGS) $(DIST)/$(MOZ_PKG_DIR)
 endif # RUN_FIND_DUPES
 ifndef MOZ_IS_COMM_TOPDIR
+ifdef RUN_MOZHARNESS_ZIP
 	# Package mozharness
 	$(call py_action,test_archive, \
 		mozharness \
 		$(ABS_DIST)/$(PKG_PATH)$(MOZHARNESS_PACKAGE))
+endif # RUN_MOZHARNESS_ZIP
 endif # MOZ_IS_COMM_TOPDIR
 ifdef MOZ_PACKAGE_JSSHELL
 	# Package JavaScript Shell
 	@echo 'Packaging JavaScript Shell...'
 	$(RM) $(PKG_JSSHELL)
 	$(MAKE_JSSHELL)
 endif # MOZ_PACKAGE_JSSHELL
 ifdef MOZ_AUTOMATION
--- a/widget/cocoa/nsChildView.h
+++ b/widget/cocoa/nsChildView.h
@@ -162,16 +162,19 @@ class WidgetRenderingContext;
 
   // Set to YES when our GL surface has been updated and we need to call
   // updateGLContext on the compositor thread before we composite.
   // Accesses from different threads are synchronized via mGLContext's
   // CGLContextObj lock.
   // Always NO if StaticPrefs::gfx_core_animation_enabled_AtStartup() is true.
   BOOL mNeedsGLUpdate;
 
+  // Whether we're inside updateRootCALayer at the moment.
+  BOOL mIsUpdatingLayer;
+
   // Holds our drag service across multiple drag calls. The reference to the
   // service is obtained when the mouse enters the view and is released when
   // the mouse exits or there is a drop. This prevents us from having to
   // re-establish the connection to the service manager many times per second
   // when handling |draggingUpdated:| messages.
   nsIDragService* mDragService;
 
   // The NSOpenGLContext that is attached to our mPixelHostingView.
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -1515,17 +1515,16 @@ void nsChildView::PaintWindowInContentLa
   }
 
   PaintWindowInIOSurface(
       surf, LayoutDeviceIntRegion::FromUnknownRegion(mContentLayer->CurrentSurfaceInvalidRegion()));
   mContentLayer->NotifySurfaceReady();
 }
 
 void nsChildView::HandleMainThreadCATransaction() {
-  MaybeScheduleUnsuspendAsyncCATransactions();
   WillPaintWindow();
 
   if (GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_BASIC) {
     // We're in BasicLayers mode, i.e. main thread software compositing.
     // Composite the window into our layer's surface.
     PaintWindowInContentLayer();
   } else {
     // Trigger a synchronous OMTC composite. This will call NextSurface and
@@ -1533,19 +1532,23 @@ void nsChildView::HandleMainThreadCATran
     // surface, and the main thread (this thread) will wait inside PaintWindow
     // during that time.
     PaintWindow(LayoutDeviceIntRegion(GetBounds()));
   }
 
   // Apply the changes from mContentLayer to its underlying CALayer. Now is a
   // good time to call this because we know we're currently inside a main thread
   // CATransaction.
-  auto compositingState = mCompositingState.Lock();
-  mNativeLayerRoot->ApplyChanges();
-  compositingState->mNativeLayerChangesPending = false;
+  {
+    auto compositingState = mCompositingState.Lock();
+    mNativeLayerRoot->ApplyChanges();
+    compositingState->mNativeLayerChangesPending = false;
+  }
+
+  MaybeScheduleUnsuspendAsyncCATransactions();
 }
 
 #pragma mark -
 
 void nsChildView::ReportMoveEvent() { NotifyWindowMoved(mBounds.x, mBounds.y); }
 
 void nsChildView::ReportSizeEvent() {
   if (mWidgetListener) mWidgetListener->WindowResized(this, mBounds.width, mBounds.height);
@@ -3158,16 +3161,17 @@ NSEvent* gLastDragMouseDownEvent = nil;
     mClickThroughMouseDownEvent = nil;
     mDragService = nullptr;
 
     mGestureState = eGestureState_None;
     mCumulativeMagnification = 0.0;
     mCumulativeRotation = 0.0;
 
     mNeedsGLUpdate = NO;
+    mIsUpdatingLayer = NO;
 
     [self setFocusRingType:NSFocusRingTypeNone];
 
 #ifdef __LP64__
     mCancelSwipeAnimation = nil;
 #endif
 
     mNonDraggableViewsContainer = [[ViewRegionContainerView alloc] initWithFrame:[self bounds]];
@@ -3752,34 +3756,37 @@ NSEvent* gLastDragMouseDownEvent = nil;
 
     mGeckoChild->WillPaintWindow();
   }
   [super viewWillDraw];
 }
 
 - (void)markLayerForDisplay {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
-  if (StaticPrefs::gfx_core_animation_enabled_AtStartup()) {
+  if (StaticPrefs::gfx_core_animation_enabled_AtStartup() && !mIsUpdatingLayer) {
     // This call will cause updateRootCALayer to be called during the upcoming
     // main thread CoreAnimation transaction. It will also trigger a transaction
     // if no transaction is currently pending.
     [[mPixelHostingView layer] setNeedsDisplay];
   }
 }
 
 - (void)ensureNextCompositeIsAtomicWithMainThreadPaint {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   if (mGeckoChild) {
     mGeckoChild->SuspendAsyncCATransactions();
   }
 }
 
 - (void)updateRootCALayer {
   if (NS_IsMainThread() && mGeckoChild) {
+    MOZ_RELEASE_ASSERT(!mIsUpdatingLayer, "Re-entrant layer display?");
+    mIsUpdatingLayer = YES;
     mGeckoChild->HandleMainThreadCATransaction();
+    mIsUpdatingLayer = NO;
   }
 }
 
 - (CALayer*)rootCALayer {
   return [mPixelHostingView layer];
 }
 
 // If we've just created a non-native context menu, we need to mark it as
--- a/xpcom/base/nsSystemInfo.cpp
+++ b/xpcom/base/nsSystemInfo.cpp
@@ -97,33 +97,28 @@ static void SimpleParseKeyValuePairs(
       aKeyValuePairs[key] = value;
     }
   }
 }
 #endif
 
 #if defined(XP_WIN)
 namespace {
-static nsresult GetFolderDiskInfo(const char* aSpecialDirName,
-                                  FolderDiskInfo& info) {
+static nsresult GetFolderDiskInfo(nsIFile* file, FolderDiskInfo& info) {
   info.model.Truncate();
   info.revision.Truncate();
   info.isSSD = false;
 
-  nsCOMPtr<nsIFile> profDir;
-  nsresult rv =
-      NS_GetSpecialDirectory(aSpecialDirName, getter_AddRefs(profDir));
-  NS_ENSURE_SUCCESS(rv, rv);
-  nsAutoString profDirPath;
-  rv = profDir->GetPath(profDirPath);
+  nsAutoString filePath;
+  nsresult rv = file->GetPath(filePath);
   NS_ENSURE_SUCCESS(rv, rv);
   wchar_t volumeMountPoint[MAX_PATH] = {L'\\', L'\\', L'.', L'\\'};
   const size_t PREFIX_LEN = 4;
   if (!::GetVolumePathNameW(
-          profDirPath.get(), volumeMountPoint + PREFIX_LEN,
+          filePath.get(), volumeMountPoint + PREFIX_LEN,
           mozilla::ArrayLength(volumeMountPoint) - PREFIX_LEN)) {
     return NS_ERROR_UNEXPECTED;
   }
   size_t volumeMountPointLen = wcslen(volumeMountPoint);
   // Since we would like to open a drive and not a directory, we need to
   // remove any trailing backslash. A drive handle is valid for
   // DeviceIoControl calls, a directory handle is not.
   if (volumeMountPoint[volumeMountPointLen - 1] == L'\\') {
@@ -200,26 +195,27 @@ static nsresult GetFolderDiskInfo(const 
                     deviceOutput->ProductRevisionOffset;
     info.revision.CompressWhitespace();
   }
   info.isSSD = isSSD;
   free(deviceOutput);
   return NS_OK;
 }
 
-static nsresult CollectDiskInfo(DiskInfo& info) {
-  nsresult rv = GetFolderDiskInfo(NS_GRE_DIR, info.binary);
+static nsresult CollectDiskInfo(nsIFile* greDir, nsIFile* winDir,
+                                nsIFile* profDir, DiskInfo& info) {
+  nsresult rv = GetFolderDiskInfo(greDir, info.binary);
   if (NS_FAILED(rv)) {
     return rv;
   }
-  rv = GetFolderDiskInfo(NS_WIN_WINDOWS_DIR, info.system);
+  rv = GetFolderDiskInfo(winDir, info.system);
   if (NS_FAILED(rv)) {
     return rv;
   }
-  return GetFolderDiskInfo(NS_APP_USER_PROFILE_50_DIR, info.profile);
+  return GetFolderDiskInfo(profDir, info.profile);
 }
 
 nsresult GetInstallYear(uint32_t& aYear) {
   HKEY hKey;
   LONG status = RegOpenKeyExW(
       HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0,
       KEY_READ | KEY_WOW64_64KEY, &hKey);
 
@@ -1125,25 +1121,42 @@ nsSystemInfo::GetDiskInfo(JSContext* aCx
   ErrorResult erv;
   RefPtr<Promise> promise = Promise::Create(global, erv);
   if (NS_WARN_IF(erv.Failed())) {
     return erv.StealNSResult();
   }
 
   if (!mDiskInfoPromise) {
     RefPtr<mozilla::LazyIdleThread> lazyIOThread = GetHelperThread();
+    nsCOMPtr<nsIFile> greDir;
+    nsCOMPtr<nsIFile> winDir;
+    nsCOMPtr<nsIFile> profDir;
+    nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(greDir));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    rv = NS_GetSpecialDirectory(NS_WIN_WINDOWS_DIR, getter_AddRefs(winDir));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
+                                getter_AddRefs(profDir));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
 
-    mDiskInfoPromise = InvokeAsync(lazyIOThread, __func__, []() {
-      DiskInfo info;
-      nsresult rv = CollectDiskInfo(info);
-      if (NS_SUCCEEDED(rv)) {
-        return DiskInfoPromise::CreateAndResolve(info, __func__);
-      }
-      return DiskInfoPromise::CreateAndReject(rv, __func__);
-    });
+    mDiskInfoPromise =
+        InvokeAsync(lazyIOThread, __func__, [greDir, winDir, profDir]() {
+          DiskInfo info;
+          nsresult rv = CollectDiskInfo(greDir, winDir, profDir, info);
+          if (NS_SUCCEEDED(rv)) {
+            return DiskInfoPromise::CreateAndResolve(info, __func__);
+          }
+          return DiskInfoPromise::CreateAndReject(rv, __func__);
+        });
   }
 
   // Chain the new promise to the extant mozpromise.
   RefPtr<Promise> capturedPromise = promise;
   mDiskInfoPromise->Then(
       GetMainThreadSerialEventTarget(), __func__,
       [capturedPromise](const DiskInfo& info) {
         RefPtr<nsIGlobalObject> global = capturedPromise->GetGlobalObject();