Merge inbound to mozilla-central. a=merge
authorCiure Andrei <aciure@mozilla.com>
Sun, 12 Aug 2018 00:53:49 +0300
changeset 486203 4bf146738292
parent 486191 47091a68bf3a (current diff)
parent 486202 39ad7ffcd976 (diff)
child 486232 f76a479a5872
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone63.0a1
first release with
nightly linux32
4bf146738292 / 63.0a1 / 20180811220142 / files
nightly linux64
4bf146738292 / 63.0a1 / 20180811220142 / files
nightly mac
4bf146738292 / 63.0a1 / 20180811220142 / files
nightly win32
4bf146738292 / 63.0a1 / 20180811220142 / files
nightly win64
4bf146738292 / 63.0a1 / 20180811220142 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -874,19 +874,16 @@ toolbarspring {
   html|*.tabs-container html|*.item-tabs-list html|*.item-icon-container {
     image-rendering: -moz-crisp-edges;
   }
 }
 
 menupopup[emptyplacesresult="true"] > .hide-if-empty-places-result {
   display: none;
 }
-menuitem.spell-suggestion {
-  font-weight: bold;
-}
 
 /* Hide extension toolbars that neglected to set the proper class */
 window[chromehidden~="location"][chromehidden~="toolbar"] toolbar:not(.chromeclass-menubar),
 window[chromehidden~="toolbar"] toolbar:not(#nav-bar):not(#TabsToolbar):not(#print-preview-toolbar):not(.chromeclass-menubar) {
   display: none;
 }
 
 #navigator-toolbox ,
--- a/browser/modules/AsyncTabSwitcher.jsm
+++ b/browser/modules/AsyncTabSwitcher.jsm
@@ -99,16 +99,22 @@ class AsyncTabSwitcher {
     this.unloadTimer = null; // UNLOAD_DELAY nsITimer instance.
 
     // Map from tabs to STATE_* (below).
     this.tabState = new Map();
 
     // True if we're in the midst of switching tabs.
     this.switchInProgress = false;
 
+    // Transaction id for the composite that will show the requested
+    // tab for the first tab after a tab switch.
+    // Set to -1 when we're not waiting for notification of a
+    // completed switch.
+    this.switchPaintId = -1;
+
     // Set of tabs that might be visible right now. We maintain
     // this set because we can't be sure when a tab is actually
     // drawn. A tab is added to this set when we ask to make it
     // visible. All tabs but the most recently shown tab are
     // removed from the set upon MozAfterPaint.
     this.maybeVisibleTabs = new Set([tabbrowser.selectedTab]);
 
     // This holds onto the set of tabs that we've been asked to warm up,
@@ -728,17 +734,28 @@ class AsyncTabSwitcher {
     if (this.loadingTab === tab) {
       this.maybeClearLoadTimer("onLayersReady");
     }
   }
 
   // Fires when we paint the screen. Any tab switches we initiated
   // previously are done, so there's no need to keep the old layers
   // around.
-  onPaint() {
+  onPaint(event) {
+    if (this.switchPaintId != -1 &&
+        event.transactionId >= this.switchPaintId) {
+      let time = TelemetryStopwatch.timeElapsed("FX_TAB_SWITCH_COMPOSITE_E10S_MS", this.window);
+      if (time != -1) {
+        TelemetryStopwatch.finish("FX_TAB_SWITCH_COMPOSITE_E10S_MS", this.window);
+        this.log("DEBUG: tab switch time including compositing = " + time);
+      }
+      this.addMarker("AsyncTabSwitch:Composited");
+      this.switchPaintId = -1;
+    }
+
     this.maybeVisibleTabs.clear();
   }
 
   // Called when we're done clearing the layers for a tab.
   onLayersCleared(browser) {
     let tab = this.tabbrowser.getTabForBrowser(browser);
     if (tab) {
       this.logState(`onLayersCleared(${tab._tPos})`);
@@ -1022,17 +1039,17 @@ class AsyncTabSwitcher {
     this._processing = true;
     this.preActions();
 
     switch (event.type) {
       case "MozLayerTreeReady":
         this.onLayersReady(event.originalTarget);
         break;
       case "MozAfterPaint":
-        this.onPaint();
+        this.onPaint(event);
         break;
       case "MozLayerTreeCleared":
         this.onLayersCleared(event.originalTarget);
         break;
       case "TabRemotenessChange":
         this.onRemotenessChange(event.target);
         break;
       case "sizemodechange":
@@ -1054,16 +1071,19 @@ class AsyncTabSwitcher {
   /*
    * Telemetry and Profiler related helpers for recording tab switch
    * timing.
    */
 
   startTabSwitch() {
     TelemetryStopwatch.cancel("FX_TAB_SWITCH_TOTAL_E10S_MS", this.window);
     TelemetryStopwatch.start("FX_TAB_SWITCH_TOTAL_E10S_MS", this.window);
+
+    TelemetryStopwatch.cancel("FX_TAB_SWITCH_COMPOSITE_E10S_MS", this.window);
+    TelemetryStopwatch.start("FX_TAB_SWITCH_COMPOSITE_E10S_MS", this.window);
     this.addMarker("AsyncTabSwitch:Start");
     this.switchInProgress = true;
   }
 
   /**
    * Something has occurred that might mean that we've completed
    * the tab switch (layers are ready, paints are done, spinners
    * are hidden). This checks to make sure all conditions are
--- a/browser/themes/shared/customizableui/panelUI.inc.css
+++ b/browser/themes/shared/customizableui/panelUI.inc.css
@@ -104,16 +104,21 @@
 
 #nav-bar[brighttext] #PanelUI-menu-button[badge-status="addon-alert"] > .toolbarbutton-badge-stack > .toolbarbutton-badge,
 #nav-bar[brighttext] #PanelUI-menu-button[badge-status="fxa-needs-authentication"] > .toolbarbutton-badge-stack > .toolbarbutton-badge {
   -moz-context-properties: fill, stroke;
   fill: #FFE900;
   stroke: transparent;
 }
 
+.cui-widget-panel,
+#widget-overflow {
+  font: menu;
+}
+
 panelview {
   -moz-box-orient: vertical;
   -moz-box-flex: 1;
   background: var(--arrowpanel-background);
   padding: 0;
 }
 
 /* This section is to anchor all the drop down panels at the same height, shift the
@@ -903,17 +908,16 @@ panelview .toolbarbutton-1,
 .subviewbutton[targetURI] > .toolbarbutton-text,
 .subviewbutton.restoreallitem > .toolbarbutton-text,
 .subviewbutton.bookmark-item > .toolbarbutton-text,
 .subviewbutton[checked="true"] > .toolbarbutton-text {
   padding-inline-start: 8px; /* See '.subviewbutton-iconic > .toolbarbutton-text' rule above. */
 }
 
 .panel-banner-item > .toolbarbutton-multiline-text {
-  font: menu;
   margin: 0;
   padding: 0;
   padding-inline-start: 8px; /* See '.subviewbutton-iconic > .toolbarbutton-text' rule above. */
 }
 
 .subviewbutton-iconic > .toolbarbutton-icon {
   width: 16px;
   height: 16px;
@@ -943,25 +947,16 @@ panelview .toolbarbutton-1,
   padding-inline-start: 6px;
 }
 
 .subviewbutton > .menu-accel-container > .menu-iconic-accel,
 .subviewbutton > .menu-accel-container > .menu-accel {
   margin-inline-end: 0 !important; /* to override menu.css on Windows */
 }
 
-#widget-overflow-fixed-list .toolbarbutton-1 > .toolbarbutton-text,
-#widget-overflow-list .toolbarbutton-1 > .toolbarbutton-text,
-.addon-banner-item,
-.subviewbutton,
-.subviewbutton-nav,
-.subview-subheader {
-  font: menu;
-}
-
 .subviewbutton[shortcut]::after {
   content: attr(shortcut);
   float: right;
   color: var(--panel-disabled-color);
 }
 
 .PanelUI-subView .subviewbutton-nav::after {
   -moz-context-properties: fill, fill-opacity;
@@ -999,22 +994,16 @@ panelview .toolbarbutton-1,
   -moz-context-properties: fill, fill-opacity;
   fill: currentColor;
   fill-opacity: 0.4;
   float: right;
   /* Centers the icon and resizes it to 12px square. */
   transform: translateY(2px) scaleX(.75);
 }
 
-/* This is a <label> but it should fit in with the menu font- and colorwise. */
-#PanelUI-characterEncodingView-autodetect-label {
-  font: menu;
-  color: inherit;
-}
-
 .subviewbutton[checked="true"] {
   list-style-image: url(chrome://browser/skin/check.svg);
   -moz-context-properties: fill;
   fill: currentColor;
   color: inherit;
 }
 
 #appMenu-popup .toolbaritem-combined-buttons {
@@ -1022,17 +1011,16 @@ panelview .toolbarbutton-1,
   -moz-box-orient: horizontal;
   border: 0;
   border-radius: 0;
   margin-inline-end: 8px;
 }
 
 panelmultiview .toolbaritem-combined-buttons > label {
   -moz-box-flex: 1;
-  font: menu;
   margin: 0;
   padding: 4px 0px;
 }
 
 panelmultiview .toolbaritem-combined-buttons > spacer.before-label {
   width: 36px; /* 12px toolbarbutton padding + 16px icon + 8px label padding start */
 }
 
@@ -1081,17 +1069,16 @@ panelmultiview .toolbaritem-combined-but
 }
 
 .PanelUI-subView .toolbaritem-combined-buttons > .subviewbutton-iconic > .toolbarbutton-text,
 .PanelUI-subView .toolbaritem-combined-buttons > .subviewbutton:not(.subviewbutton-iconic) > .toolbarbutton-icon {
   display: none;
 }
 
 .toolbaritem-combined-buttons > .subviewbutton:not(.subviewbutton-iconic) > .toolbarbutton-text {
-  font-size: 1em;
   padding-inline-start: 0;
 }
 
 .subview-subheader {
   color: var(--panel-disabled-color);
 }
 
 panelview .toolbarbutton-1 {
--- a/browser/themes/shared/tabs.inc.css
+++ b/browser/themes/shared/tabs.inc.css
@@ -792,27 +792,24 @@
 }
 
 .all-tabs-item > .all-tabs-button > .tab-throbber-fallback {
   display: block;
   margin-inline-end: 0;
 }
 
 .all-tabs-item[selected] {
+  font-weight: bold;
   box-shadow: inset 4px 0 var(--blue-40);
 }
 
 .all-tabs-item[selected]:-moz-locale-dir(rtl) {
   box-shadow: inset -4px 0 var(--blue-40);
 }
 
-.all-tabs-item[selected] > .all-tabs-button {
-  font-weight: bold;
-}
-
 .all-tabs-button {
   list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.svg");
 }
 
 .all-tabs-secondary-button > label {
   display: none;
   margin: 0 5.5px;
 }
--- a/devtools/client/debugger/new/test/mochitest/browser.ini
+++ b/devtools/client/debugger/new/test/mochitest/browser.ini
@@ -625,16 +625,17 @@ support-files =
   examples/frames.js
   examples/pause-points.js
   examples/script-mutate.js
   examples/script-switching-02.js
   examples/script-switching-01.js
   examples/times2.js
   examples/doc_rr_basic.html
   examples/doc_rr_continuous.html
+  examples/doc_rr_recovery.html
 
 [browser_dbg-asm.js]
 [browser_dbg-async-stepping.js]
 [browser_dbg-sourcemapped-breakpoint-console.js]
 skip-if = (os == "win" && ccov) # Bug 1453549
 [browser_dbg-sourcemapped-scopes.js]
 skip-if = ccov || (verify && debug && (os == 'linux')) # Bug 1441545
 [browser_dbg-sourcemapped-stepping.js]
@@ -734,8 +735,16 @@ skip-if = os != "mac" || debug || !night
 [browser_dbg_rr_stepping-01.js]
 skip-if = os != "mac" || debug || !nightly_build
 [browser_dbg_rr_stepping-02.js]
 skip-if = os != "mac" || debug || !nightly_build
 [browser_dbg_rr_stepping-03.js]
 skip-if = os != "mac" || debug || !nightly_build
 [browser_dbg_rr_stepping-04.js]
 skip-if = os != "mac" || debug || !nightly_build
+[browser_dbg_rr_recovery-01.js]
+skip-if = os != "mac" || debug || !nightly_build
+[browser_dbg_rr_replay-01.js]
+skip-if = os != "mac" || debug || !nightly_build
+[browser_dbg_rr_replay-02.js]
+skip-if = os != "mac" || debug || !nightly_build
+[browser_dbg_rr_replay-03.js]
+skip-if = os != "mac" || debug || !nightly_build
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg_rr_recovery-01.js
@@ -0,0 +1,28 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test basic recovery of crashed child processes in web replay.
+async function test() {
+  waitForExplicitFinish();
+
+  let tab = BrowserTestUtils.addTab(gBrowser, null, { recordExecution: "*" });
+  gBrowser.selectedTab = tab;
+  openTrustedLinkIn(EXAMPLE_URL + "doc_rr_recovery.html", "current");
+  await once(Services.ppmm, "RecordingFinished");
+
+  let toolbox = await attachDebugger(tab), client = toolbox.threadClient;
+  await client.interrupt();
+  await setBreakpoint(client, "doc_rr_recovery.html", 21);
+  await rewindToLine(client, 21);
+  await checkEvaluateInTopFrame(client, "SpecialPowers.Cu.recordReplayDirective(/* CrashSoon */ 1)", undefined);
+  await stepOverToLine(client, 22);
+  await stepOverToLine(client, 23);
+  await checkEvaluateInTopFrame(client, "SpecialPowers.Cu.recordReplayDirective(/* CrashSoon */ 1); " +
+                                        "SpecialPowers.Cu.recordReplayDirective(/* MaybeCrash */ 2)", undefined);
+
+  await toolbox.destroy();
+  await gBrowser.removeTab(tab);
+  finish();
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg_rr_replay-01.js
@@ -0,0 +1,39 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Basic test for saving a recording and then replaying it in a new tab.
+async function test() {
+  waitForExplicitFinish();
+
+  let recordingFile = newRecordingFile();
+  let recordingTab = BrowserTestUtils.addTab(gBrowser, null, { recordExecution: "*" });
+  gBrowser.selectedTab = recordingTab;
+  openTrustedLinkIn(EXAMPLE_URL + "doc_rr_basic.html", "current");
+  await once(Services.ppmm, "RecordingFinished");
+
+  let tabParent = recordingTab.linkedBrowser.frameLoader.tabParent;
+  ok(tabParent, "Found recording tab parent");
+  ok(tabParent.saveRecording(recordingFile), "Saved recording");
+  await once(Services.ppmm, "SaveRecordingFinished");
+
+  let replayingTab = BrowserTestUtils.addTab(gBrowser, null, { replayExecution: recordingFile });
+  gBrowser.selectedTab = replayingTab;
+  await once(Services.ppmm, "HitRecordingEndpoint");
+
+  let toolbox = await attachDebugger(replayingTab), client = toolbox.threadClient;
+  await client.interrupt();
+  await setBreakpoint(client, "doc_rr_basic.html", 21);
+  await rewindToLine(client, 21);
+  await checkEvaluateInTopFrame(client, "number", 10);
+  await rewindToLine(client, 21);
+  await checkEvaluateInTopFrame(client, "number", 9);
+  await resumeToLine(client, 21);
+  await checkEvaluateInTopFrame(client, "number", 10);
+
+  await toolbox.destroy();
+  await gBrowser.removeTab(recordingTab);
+  await gBrowser.removeTab(replayingTab);
+  finish();
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg_rr_replay-02.js
@@ -0,0 +1,49 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test ending a recording at a breakpoint and then separately replaying to the end.
+async function test() {
+  waitForExplicitFinish();
+
+  let recordingFile = newRecordingFile();
+  let recordingTab = BrowserTestUtils.addTab(gBrowser, null, { recordExecution: "*" });
+  gBrowser.selectedTab = recordingTab;
+  openTrustedLinkIn(EXAMPLE_URL + "doc_rr_continuous.html", "current");
+
+  let toolbox = await attachDebugger(recordingTab), client = toolbox.threadClient;
+  await client.interrupt();
+  await setBreakpoint(client, "doc_rr_continuous.html", 14);
+  await resumeToLine(client, 14);
+  await resumeToLine(client, 14);
+  await reverseStepOverToLine(client, 13);
+  let lastNumberValue = await evaluateInTopFrame(client, "number");
+
+  let tabParent = recordingTab.linkedBrowser.frameLoader.tabParent;
+  ok(tabParent, "Found recording tab parent");
+  ok(tabParent.saveRecording(recordingFile), "Saved recording");
+  await once(Services.ppmm, "SaveRecordingFinished");
+
+  await toolbox.destroy();
+  await gBrowser.removeTab(recordingTab);
+
+  let replayingTab = BrowserTestUtils.addTab(gBrowser, null, { replayExecution: recordingFile });
+  gBrowser.selectedTab = replayingTab;
+  await once(Services.ppmm, "HitRecordingEndpoint");
+
+  toolbox = await attachDebugger(replayingTab);
+  client = toolbox.threadClient;
+  await client.interrupt();
+  await checkEvaluateInTopFrame(client, "number", lastNumberValue);
+  await reverseStepOverToLine(client, 13);
+  await setBreakpoint(client, "doc_rr_continuous.html", 14);
+  await rewindToLine(client, 14);
+  await checkEvaluateInTopFrame(client, "number", lastNumberValue - 1);
+  await resumeToLine(client, 14);
+  await checkEvaluateInTopFrame(client, "number", lastNumberValue);
+
+  await toolbox.destroy();
+  await gBrowser.removeTab(replayingTab);
+  finish();
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg_rr_replay-03.js
@@ -0,0 +1,32 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test for saving a recording and then replaying it in a new tab, with rewinding disabled.
+async function test() {
+  waitForExplicitFinish();
+
+  await pushPref("devtools.recordreplay.enableRewinding", false);
+
+  let recordingFile = newRecordingFile();
+  let recordingTab = BrowserTestUtils.addTab(gBrowser, null, { recordExecution: "*" });
+  gBrowser.selectedTab = recordingTab;
+  openTrustedLinkIn(EXAMPLE_URL + "doc_rr_basic.html", "current");
+  await once(Services.ppmm, "RecordingFinished");
+
+  let tabParent = recordingTab.linkedBrowser.frameLoader.tabParent;
+  ok(tabParent, "Found recording tab parent");
+  ok(tabParent.saveRecording(recordingFile), "Saved recording");
+  await once(Services.ppmm, "SaveRecordingFinished");
+
+  let replayingTab = BrowserTestUtils.addTab(gBrowser, null, { replayExecution: recordingFile });
+  gBrowser.selectedTab = replayingTab;
+  await once(Services.ppmm, "HitRecordingEndpoint");
+
+  ok(true, "Replayed to end of recording");
+
+  await gBrowser.removeTab(recordingTab);
+  await gBrowser.removeTab(replayingTab);
+  finish();
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/new/test/mochitest/examples/doc_rr_recovery.html
@@ -0,0 +1,26 @@
+<html lang="en" dir="ltr">
+<body>
+<div id="maindiv">Hello World!</div>
+</body>
+<script>
+// this line intentionally left blank
+// this line intentionally left blank
+// this line intentionally left blank
+const cpmm = SpecialPowers.Services.cpmm;
+var number = 0;
+function f() {
+  updateNumber();
+  if (number >= 10) {
+    cpmm.sendAsyncMessage("RecordingFinished");
+    return;
+  }
+  window.setTimeout(f, 1);
+}
+function updateNumber() {
+  number++;
+  document.getElementById("maindiv").innerHTML = "Number: " + number;
+  SpecialPowers.Cu.recordReplayDirective(/* MaybeCrash */ 2);
+}
+window.setTimeout(f, 1);
+</script>
+</html>
--- a/extensions/spellcheck/locales/en-US/hunspell/en-US.dic
+++ b/extensions/spellcheck/locales/en-US/hunspell/en-US.dic
@@ -1,9 +1,9 @@
-52853
+52862
 0/nm
 0th/pt
 1/n1
 1st/p
 1th/tc
 2/nm
 2nd/p
 2th/tc
@@ -14373,16 +14373,17 @@ altitude/MS
 alto/SM
 altogether
 altruism/M
 altruist/SM
 altruistic
 altruistically
 alum/SM
 alumina/M
+aluminize/D
 aluminum/M
 alumna/M
 alumnae
 alumni
 alumnus/M
 alveolar/S
 always
 am/N
@@ -21314,17 +21315,17 @@ countrywide
 countrywoman/M
 countrywomen
 county/SM
 countywide
 coup's
 coup/AS
 coupe/SM
 couple's
-couple/UCGSD
+couple/UCGSDRZ
 couplet/MS
 coupling/SM
 coupon/SM
 courage/M
 courageous/YP
 courageousness/M
 courgette/S
 courier/MDSG
@@ -26506,16 +26507,17 @@ flambé/MD
 flame/DRSJMZG
 flamenco/MS
 flameproof/DGS
 flamethrower/SM
 flamingo/MS
 flammability/IM
 flammable/SM
 flan/MS
+flaneur/MS
 flange/MS
 flank/SZGMDR
 flanker/M
 flannel/SGMD
 flannelette/M
 flap/MS
 flapjack/MS
 flapped
@@ -31230,16 +31232,17 @@ informed/U
 infotainment/M
 infra
 infrared/M
 infrasonic
 infrastructural
 infrastructure/SM
 infrequence/M
 infrequent/Y
+infringe/RZ
 infringement/MS
 infuriate/GDS
 infuriating/Y
 infuser/SM
 ingenious/PY
 ingeniousness/M
 ingenue/SM
 ingenuity/M
@@ -42776,16 +42779,17 @@ retro/MS
 retroactive/Y
 retrofire/GDS
 retrofit/SM
 retrofitted
 retrofitting
 retrograde/DSG
 retrogress/GVDS
 retrogression/M
+retroreflector/S
 retrorocket/MS
 retrospect/MDSGV
 retrospection/M
 retrospective/MYS
 retrovirus/MS
 retsina/M
 returnable/SM
 returnee/SM
@@ -46742,17 +46746,17 @@ stdio
 stead/SM
 steadfast/YP
 steadfastness/M
 steadily/U
 steadiness/UM
 steady/TGPDRSM
 steak/SM
 steakhouse/SM
-steal/SMHG
+steal/SMHGRZ
 stealth/M
 stealthily
 stealthiness/M
 stealthy/TPR
 steam/SMDRZG
 steamboat/MS
 steamer/M
 steamfitter/SM
@@ -49453,16 +49457,17 @@ tragedy/SM
 tragic
 tragically
 tragicomedy/SM
 tragicomic
 trail/ZGSMDR
 trailblazer/MS
 trailblazing/M
 trailer/M
+trailhead/S
 train/ZGSMDRBJ
 trained/U
 trainee/SM
 trainer/M
 training/M
 trainload/MS
 trainman/M
 trainmen
@@ -52738,16 +52743,20 @@ your/S
 yourself
 yourselves
 youth/M
 youthful/YP
 youthfulness/M
 youths
 yow
 yowl/MDSG
+yowsa
+yowsah
+yowza
+yowzah
 yr/S
 ytterbium/M
 yttrium/M
 yuan/M
 yucca/SM
 yuck/MDSG
 yucky/TR
 yuk/SM
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -8079,21 +8079,23 @@ js::NewRealm(JSContext* cx, JSPrincipals
         compHolder = cx->make_unique<JS::Compartment>(zone);
         if (!compHolder || !compHolder->init(cx))
             return nullptr;
 
         comp = compHolder.get();
     }
 
     UniquePtr<Realm> realm(cx->new_<Realm>(comp, options));
-    if (!realm || !realm->init(cx))
+    if (!realm || !realm->init(cx, principals))
         return nullptr;
 
-    // Set up the principals.
-    JS::SetRealmPrincipals(realm.get(), principals);
+    // Make sure we don't put system and non-system realms in the same
+    // compartment.
+    if (!compHolder)
+        MOZ_RELEASE_ASSERT(realm->isSystem() == IsSystemCompartment(comp));
 
     AutoLockGC lock(rt);
 
     // Reserve space in the Vectors before we start mutating them.
     if (!comp->realms().reserve(comp->realms().length() + 1) ||
         (compHolder && !zone->compartments().reserve(zone->compartments().length() + 1)) ||
         (zoneHolder && !rt->gc.zones().reserve(rt->gc.zones().length() + 1)))
     {
--- a/js/src/jit-test/tests/realms/basic.js
+++ b/js/src/jit-test/tests/realms/basic.js
@@ -19,8 +19,27 @@ function testCrossRealmProto() {
 
         var a = Reflect.construct(Array, [], g.Object);
         assertEq(Array.isArray(a), true);
         assertEq(objectGlobal(a), this);
         assertEq(a.__proto__, g.Object.prototype);
     }
 }
 testCrossRealmProto();
+
+function testSystemNonSystemRealms() {
+    var systemRealm = newGlobal({systemPrincipal: true});
+    var ex;
+    try {
+        var nonSystemRealm = newGlobal({sameCompartmentAs: systemRealm, principal: 10});
+    } catch(e) {
+        ex = e;
+    }
+    assertEq(ex.toString().includes("non-system realms"), true);
+    ex = null;
+    try {
+        systemRealm = newGlobal({systemPrincipal: true, sameCompartmentAs: this});
+    } catch(e) {
+        ex = e;
+    }
+    assertEq(ex.toString().includes("non-system realms"), true);
+}
+testSystemNonSystemRealms();
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -173,40 +173,35 @@ JS::GetRealmPrincipals(JS::Realm* realm)
 
 JS_FRIEND_API(void)
 JS::SetRealmPrincipals(JS::Realm* realm, JSPrincipals* principals)
 {
     // Short circuit if there's no change.
     if (principals == realm->principals())
         return;
 
-    // Any realm with the trusted principals -- and there can be
-    // multiple -- is a system realm.
+    // We'd like to assert that our new principals is always same-origin
+    // with the old one, but JSPrincipals doesn't give us a way to do that.
+    // But we can at least assert that we're not switching between system
+    // and non-system.
     const JSPrincipals* trusted = realm->runtimeFromMainThread()->trustedPrincipals();
     bool isSystem = principals && principals == trusted;
+    MOZ_RELEASE_ASSERT(realm->isSystem() == isSystem);
 
     // Clear out the old principals, if any.
     if (realm->principals()) {
         JS_DropPrincipals(TlsContext.get(), realm->principals());
         realm->setPrincipals(nullptr);
-        // We'd like to assert that our new principals is always same-origin
-        // with the old one, but JSPrincipals doesn't give us a way to do that.
-        // But we can at least assert that we're not switching between system
-        // and non-system.
-        MOZ_ASSERT(realm->isSystem() == isSystem);
     }
 
     // Set up the new principals.
     if (principals) {
         JS_HoldPrincipals(principals);
         realm->setPrincipals(principals);
     }
-
-    // Update the system flag.
-    realm->setIsSystem(isSystem);
 }
 
 JS_FRIEND_API(JSPrincipals*)
 JS_GetScriptPrincipals(JSScript* script)
 {
     return script->principals();
 }
 
@@ -345,22 +340,20 @@ JS_FRIEND_API(JS::Zone*)
 js::GetRealmZone(JS::Realm* realm)
 {
     return realm->zone();
 }
 
 JS_FRIEND_API(bool)
 js::IsSystemCompartment(JS::Compartment* comp)
 {
-    // Note: for now we assume a single realm per compartment. This API will
-    // hopefully go away once Gecko supports same-compartment realms. Another
-    // option is to return comp->zone()->isSystem here, but we'd have to make
-    // sure that's equivalent.
-    MOZ_RELEASE_ASSERT(comp->realms().length() == 1);
-
+    // Realms in the same compartment must either all be system realms or
+    // non-system realms. We assert this in NewRealm and SetRealmPrincipals,
+    // but do an extra sanity check here.
+    MOZ_ASSERT(comp->realms()[0]->isSystem() == comp->realms().back()->isSystem());
     return comp->realms()[0]->isSystem();
 }
 
 JS_FRIEND_API(bool)
 js::IsSystemRealm(JS::Realm* realm)
 {
     return realm->isSystem();
 }
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -5309,29 +5309,47 @@ NewGlobal(JSContext* cx, unsigned argc, 
         if (v.isObject())
             creationOptions.setExistingCompartment(UncheckedUnwrap(&v.toObject()));
 
         if (!JS_GetProperty(cx, opts, "disableLazyParsing", &v))
             return false;
         if (v.isBoolean())
             behaviors.setDisableLazyParsing(v.toBoolean());
 
+        if (!JS_GetProperty(cx, opts, "systemPrincipal", &v))
+            return false;
+        if (v.isBoolean()) {
+            principals = &ShellPrincipals::fullyTrusted;
+            JS_HoldPrincipals(principals);
+        }
+
         if (!JS_GetProperty(cx, opts, "principal", &v))
             return false;
         if (!v.isUndefined()) {
             uint32_t bits;
             if (!ToUint32(cx, v, &bits))
                 return false;
             principals = cx->new_<ShellPrincipals>(bits);
             if (!principals)
                 return false;
             JS_HoldPrincipals(principals);
         }
     }
 
+    if (creationOptions.compartmentSpecifier() == JS::CompartmentSpecifier::ExistingCompartment) {
+        JS::Compartment* comp = creationOptions.compartment();
+        bool isSystem = principals && principals == cx->runtime()->trustedPrincipals();
+        if (isSystem != IsSystemCompartment(comp)) {
+            JS_ReportErrorASCII(cx,
+                                "Cannot create system and non-system realms in the "
+                                "same compartment");
+            return false;
+        }
+    }
+
     RootedObject global(cx, NewGlobalObject(cx, options, principals));
     if (principals)
         JS_DropPrincipals(cx, principals);
     if (!global)
         return false;
 
     if (!JS_WrapObject(cx, &global))
         return false;
@@ -7283,23 +7301,25 @@ JS_FN_HELP("parseBin", BinParse, 1, 0,
 "         scripts, even if it's a top-level script that will only run once\n"
 "         (defaults to using them directly in scripts that will only run\n"
 "         once).\n"
 "      invisibleToDebugger: If true, the global will be invisible to the\n"
 "         debugger (default false)\n"
 "      disableLazyParsing: If true, don't create lazy scripts for functions\n"
 "         (default false).\n"
 "      principal: if present, its value converted to a number must be an\n"
-"         integer that fits in 32 bits; use that as the new compartment's\n"
+"         integer that fits in 32 bits; use that as the new realm's\n"
 "         principal. Shell principals are toys, meant only for testing; one\n"
 "         shell principal subsumes another if its set bits are a superset of\n"
 "         the other's. Thus, a principal of 0 subsumes nothing, while a\n"
 "         principals of ~0 subsumes all other principals. The absence of a\n"
 "         principal is treated as if its bits were 0xffff, for subsumption\n"
-"         purposes. If this property is omitted, supply no principal."),
+"         purposes. If this property is omitted, supply no principal.\n"
+"      systemPrincipal: If true, use the shell's trusted principals for the\n"
+"         new realm. This creates a realm that's marked as a 'system' realm."),
 
     JS_FN_HELP("nukeCCW", NukeCCW, 1, 0,
 "nukeCCW(wrapper)",
 "  Nuke a CrossCompartmentWrapper, which turns it into a DeadProxyObject."),
 
     JS_FN_HELP("nukeAllCCWs", NukeAllCCWs, 0, 0,
 "nukeAllCCWs()",
 "  Like nukeCCW, but for all CrossCompartmentWrappers targeting the current compartment."),
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -763,26 +763,18 @@ CreateGlobalForOffThreadParse(JSContext*
 
     creationOptions.setInvisibleToDebugger(true)
                    .setMergeable(true)
                    .setNewCompartmentAndZone();
 
     // Don't falsely inherit the host's global trace hook.
     creationOptions.setTrace(nullptr);
 
-    JSObject* obj = JS_NewGlobalObject(cx, &parseTaskGlobalClass, nullptr,
-                                       JS::DontFireOnNewGlobalHook, realmOptions);
-    if (!obj)
-        return nullptr;
-
-    Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
-
-    JS::SetRealmPrincipals(global->realm(), currentRealm->principals());
-
-    return global;
+    return JS_NewGlobalObject(cx, &parseTaskGlobalClass, currentRealm->principals(),
+                              JS::DontFireOnNewGlobalHook, realmOptions);
 }
 
 static bool
 QueueOffThreadParseTask(JSContext* cx, ParseTask* task)
 {
     AutoLockHelperThreadState lock;
 
     bool mustWait = OffThreadParsingMustWaitForGC(cx->runtime());
--- a/js/src/vm/Realm.cpp
+++ b/js/src/vm/Realm.cpp
@@ -99,17 +99,17 @@ ObjectRealm::init(JSContext* cx)
         return false;
 
     iteratorSentinel_ = std::move(sentinel);
     enumerators = iteratorSentinel_.get();
     return true;
 }
 
 bool
-Realm::init(JSContext* cx)
+Realm::init(JSContext* cx, JSPrincipals* principals)
 {
     /*
      * As a hack, we clear our timezone cache every time we create a new realm.
      * This ensures that the cache is always relatively fresh, but shouldn't
      * interfere with benchmarks that create tons of date objects (unless they
      * also create tons of iframes, which seems unlikely).
      */
     JS::ResetTimeZone();
@@ -119,16 +119,24 @@ Realm::init(JSContext* cx)
 
     if (!savedStacks_.init() ||
         !varNames_.init())
     {
         ReportOutOfMemory(cx);
         return false;
     }
 
+    if (principals) {
+        // Any realm with the trusted principals -- and there can be
+        // multiple -- is a system realm.
+        isSystem_ = (principals == cx->runtime()->trustedPrincipals());
+        JS_HoldPrincipals(principals);
+        principals_ = principals;
+    }
+
     return true;
 }
 
 jit::JitRuntime*
 JSRuntime::createJitRuntime(JSContext* cx)
 {
     MOZ_ASSERT(!jitRuntime_);
 
--- a/js/src/vm/Realm.h
+++ b/js/src/vm/Realm.h
@@ -446,17 +446,17 @@ class JS::Realm : public JS::shadow::Rea
 
     Realm(const Realm&) = delete;
     void operator=(const Realm&) = delete;
 
   public:
     Realm(JS::Compartment* comp, const JS::RealmOptions& options);
     ~Realm();
 
-    MOZ_MUST_USE bool init(JSContext* cx);
+    MOZ_MUST_USE bool init(JSContext* cx, JSPrincipals* principals);
     void destroy(js::FreeOp* fop);
     void clearTables();
 
     void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
                                 size_t* tiAllocationSiteTables,
                                 size_t* tiArrayTypeTables,
                                 size_t* tiObjectTypeTables,
                                 size_t* realmObject,
@@ -495,16 +495,17 @@ class JS::Realm : public JS::shadow::Rea
     /* Whether to preserve JIT code on non-shrinking GCs. */
     bool preserveJitCode() { return creationOptions_.preserveJitCode(); }
 
     bool isSelfHostingRealm() const {
         return isSelfHostingRealm_;
     }
     void setIsSelfHostingRealm() {
         isSelfHostingRealm_ = true;
+        isSystem_ = true;
     }
 
     /* The global object for this realm.
      *
      * Note: the global_ field is null briefly during GC, after the global
      * object is collected; but when that happens the Realm is destroyed during
      * the same GC.)
      *
@@ -674,29 +675,16 @@ class JS::Realm : public JS::shadow::Rea
         // `principals_`.
         performanceMonitoring.unlink();
         principals_ = principals;
     }
 
     bool isSystem() const {
         return isSystem_;
     }
-    void setIsSystem(bool isSystem) {
-        if (isSystem_ == isSystem)
-            return;
-
-        // If we change `isSystem*(`, we need to unlink immediately this realm
-        // from its PerformanceGroup. For one thing, the performance data we
-        // collect should not be improperly associated to a group to which we
-        // do not belong anymore. For another thing, we use `isSystem()` as part
-        // of the key to map realms to a `PerformanceGroup`, so if we do not
-        // unlink now, this will be too late once we have updated `isSystem_`.
-        performanceMonitoring.unlink();
-        isSystem_ = isSystem;
-    }
 
     // Used to approximate non-content code when reporting telemetry.
     bool isProbablySystemCode() const {
         return isSystem_;
     }
 
     static const size_t IterResultObjectValueSlot = 0;
     static const size_t IterResultObjectDoneSlot = 1;
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -2796,17 +2796,16 @@ JSRuntime::createSelfHostingGlobal(JSCon
 
     AutoRealmUnchecked ar(cx, realm);
     Rooted<GlobalObject*> shg(cx, GlobalObject::createInternal(cx, &shgClass));
     if (!shg)
         return nullptr;
 
     cx->runtime()->selfHostingGlobal_ = shg;
     realm->setIsSelfHostingRealm();
-    realm->setIsSystem(true);
 
     if (!GlobalObject::initSelfHostingBuiltins(cx, shg, intrinsic_functions))
         return nullptr;
 
     JS_FireOnNewGlobalObject(cx, shg);
 
     return shg;
 }
--- a/js/xpconnect/wrappers/AccessCheck.cpp
+++ b/js/xpconnect/wrappers/AccessCheck.cpp
@@ -91,18 +91,17 @@ AccessCheck::wrapperSubsumes(JSObject* w
     JSObject* wrapped = js::UncheckedUnwrap(wrapper);
     return AccessCheck::subsumes(js::GetObjectCompartment(wrapper),
                                  js::GetObjectCompartment(wrapped));
 }
 
 bool
 AccessCheck::isChrome(JS::Compartment* compartment)
 {
-    nsIPrincipal* principal = GetCompartmentPrincipal(compartment);
-    return nsXPConnect::SystemPrincipal() == principal;
+    return js::IsSystemCompartment(compartment);
 }
 
 bool
 AccessCheck::isChrome(JSObject* obj)
 {
     return isChrome(js::GetObjectCompartment(obj));
 }
 
--- a/mobile/android/base/AndroidManifest.xml.in
+++ b/mobile/android/base/AndroidManifest.xml.in
@@ -86,17 +86,16 @@
 
             <intent-filter>
                 <action android:name="android.intent.action.VIEW" />
                 <category android:name="android.intent.category.DEFAULT" />
                 <category android:name="android.intent.category.BROWSABLE" />
                 <data android:scheme="http" />
                 <data android:scheme="https" />
                 <data android:scheme="about" />
-                <data android:scheme="javascript" />
                 <data android:scheme="firefox" />
             </intent-filter>
             <intent-filter>
                 <action android:name="android.intent.action.VIEW" />
                 <category android:name="android.intent.category.BROWSABLE" />
                 <category android:name="android.intent.category.DEFAULT" />
                 <data android:scheme="file" />
                 <data android:scheme="http" />
--- a/mobile/android/base/java/org/mozilla/gecko/webapps/WebAppActivity.java
+++ b/mobile/android/base/java/org/mozilla/gecko/webapps/WebAppActivity.java
@@ -410,21 +410,16 @@ public class WebAppActivity extends AppC
         }
 
         if (mManifest.isInScope(uri) && target != TARGET_WINDOW_NEW) {
             // This is in scope and wants to load in the same frame, so
             // let Gecko handle it.
             return GeckoResult.fromValue(false);
         }
 
-        if ("javascript".equals(uri.getScheme())) {
-            // These URIs will fail the scope check but should still be loaded in the PWA.
-            return GeckoResult.fromValue(false);
-        }
-
         if ("http".equals(uri.getScheme()) || "https".equals(uri.getScheme()) ||
             "data".equals(uri.getScheme()) || "blob".equals(uri.getScheme())) {
             final CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder()
                 .addDefaultShareMenuItem()
                 .setStartAnimations(this, R.anim.slide_in_right, R.anim.slide_out_left)
                 .setExitAnimations(this, R.anim.slide_in_left, R.anim.slide_out_right);
 
             final Integer themeColor = mManifest.getThemeColor();
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/CrashReporterService.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/CrashReporterService.java
@@ -81,17 +81,17 @@ public class CrashReporterService extend
         // When running on pre-O devices the work will be dispatched to onHandleWork() automatically
         // When running on Oreo and later devices we will enqueue the work for the JobIntentService to perform
         if (Build.VERSION.SDK_INT >= 26) {
             // Only when the system restarts the service because of Service.START_STICKY
             // the intent will be null. So the intent is safe to be passed to the JobIntentService.
             enqueueWork(this, intent);
         }
 
-        return Service.START_NOT_STICKY;
+        return super.onStartCommand(intent, flags, startId);
     }
 
     @Override
     public boolean onStopCurrentWork() {
         // If JobScheduler stopped execution before work being completed it should not be restarted.
         return false;
     }
 
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -5803,16 +5803,27 @@
     "expires_in_version": "70",
     "kind": "exponential",
     "high": 1000,
     "n_buckets": 20,
     "bug_numbers": [1156592],
     "releaseChannelCollection": "opt-out",
     "description": "Firefox: Time in ms between tab selection and tab content paint in e10s windows"
   },
+  "FX_TAB_SWITCH_COMPOSITE_E10S_MS": {
+    "record_in_processes": ["main"],
+    "alert_emails": ["mwoodrow@mozilla.com"],
+    "expires_in_version": "70",
+    "kind": "exponential",
+    "high": 1000,
+    "n_buckets": 20,
+    "bug_numbers": [1481704],
+    "releaseChannelCollection": "opt-out",
+    "description": "Firefox: Time in ms between tab selection and first composite of the tab content in e10s windows"
+  },
   "FX_TAB_SWITCH_SPINNER_VISIBLE_MS": {
     "record_in_processes": ["main"],
     "alert_emails": ["mconley@mozilla.com", "dothayer@mozilla.com"],
     "expires_in_version": "70",
     "kind": "exponential",
     "high": 1000,
     "n_buckets": 20,
     "bug_numbers": [1156592],
--- a/toolkit/themes/linux/global/menu.css
+++ b/toolkit/themes/linux/global/menu.css
@@ -5,32 +5,32 @@
 /* ===== menu.css =======================================================
   == Styles used by XUL menu-related elements.
   ======================================================================= */
 
 @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
 
 /* ::::: menu/menuitem ::::: */
 
+menupopup,
+menubar {
+  font: menu;
+}
+
 menu,
 menuitem,
 menucaption {
   -moz-appearance: menuitem;
   -moz-box-align: center;
   max-width: 42em;
   color: MenuText;
-  font: menu;
   list-style-image: none;
   -moz-image-region: auto;
 }
 
-menuitem[default="true"] {
-  font-weight: bold;
-}
-
 menu[_moz-menuactive="true"],
 menuitem[_moz-menuactive="true"] {
   color: -moz-menuhovertext;
   background-color: -moz-menuhover;
 }
 
 menuitem[customoptionstyling="true"] {
   -moz-appearance: none;
@@ -66,59 +66,61 @@ menubar:-moz-lwtheme > menu:not([open="t
 menubar > menu[_moz-menuactive="true"]:not([open]):not([disabled="true"]):not(:-moz-lwtheme) {
   color: -moz-menubartext;
 }
 
 menubar > menu[open] {
   color: -moz-menubarhovertext;
   background-color: -moz-menuhover;
 }
-menuitem.spell-suggestion {
-  font-weight:bold;
+
+menuitem[default="true"],
+menuitem.spell-suggestion,
+menucaption {
+  font-weight: bold;
 }
 
 /* ::::: menu/menuitems in menulist popups ::::: */
 
+menulist > menupopup {
+  font: message-box;
+}
+
 menulist > menupopup > menuitem,
 menulist > menupopup > menucaption,
 menulist > menupopup > menu {
   padding: 1px 5px;
   max-width: none;
-  font: message-box;
 }
 
 /* ..... internal content .... */
 
 .menu-text,
 .menu-iconic-left,
 .menu-iconic-text {
   margin-top: 0px !important;
   margin-bottom: 0px !important;
   margin-inline-start: 0px !important;
   margin-inline-end: 2px !important;
-  color: inherit;
 }
 
 .menu-text {
   /* This is (18 + the size of end-padding on .menu-iconic-left)px */
   margin-inline-start: 21px !important;
-  font-weight: inherit;
 }
 
 menucaption > .menu-iconic-text {
   margin-inline-start: 0 !important;
-  font-weight: bold;
 }
 
 .menu-accel,
 .menu-iconic-accel {
   margin-top: 0px !important;
   margin-bottom: 0px !important;
   margin-inline-start: 7px !important;
-  color: inherit;
 }
 
 .menu-accel-container {
   -moz-box-pack: end;
 }
 
 .menu-iconic-left {
   width: 16px;
@@ -144,22 +146,20 @@ menucaption > .menu-iconic-text {
   -moz-appearance: menuarrow;
 }
 
 .menubar-left {
   margin-top: 0px;
   margin-bottom: 0px;
   margin-inline-start: 0px;
   margin-inline-end: 2px;
-  color: inherit;
 }
 
 .menubar-text {
   margin: 0 1px !important;
-  color: inherit;
 }
 
 
 menulist > menupopup > menuitem > .menu-iconic-left,
 menulist > menupopup > menucaption > .menu-iconic-left,
 menulist > menupopup > menu > .menu-iconic-left {
   display: none;
 }
--- a/toolkit/themes/osx/global/menu.css
+++ b/toolkit/themes/osx/global/menu.css
@@ -6,48 +6,43 @@
 
 menu,
 menuitem,
 menucaption {
   -moz-appearance: menuitem;
   -moz-font-smoothing-background-color: -moz-mac-menuitem;
   -moz-box-align: center;
   color: MenuText;
-  font: -moz-pull-down-menu;
   list-style-image: none;
   -moz-image-region: auto;
   padding: 0 21px 2px;
 }
 
 menu[disabled="true"], menuitem[disabled="true"],
 menu[_moz-menuactive="true"][disabled="true"],
 menuitem[_moz-menuactive="true"][disabled="true"] {
   color: -moz-mac-menutextdisable;
   -moz-font-smoothing-background-color: -moz-mac-menuitem;
 }
 
+menuitem[default="true"],
+menuitem.spell-suggestion,
+menucaption {
+  font-weight: bold;
+}
+
 /* ..... internal content .... */
 
 .menu-text,
 .menu-iconic-text,
 .menu-accel,
 .menu-iconic-accel {
   margin: 0 !important;
 }
 
-.menu-text,
-.menu-iconic-text {
-  font-weight: inherit;
-  color: inherit;
-}
-
-menucaption > .menu-iconic-text {
-  font-weight: bold;
-}
-
 .menu-iconic-icon {
   height: 16px;
   margin-top: -2px;
   margin-bottom: -2px;
   margin-inline-end: 5px;
   /* Empty icons shouldn't take up room, so we need to compensate
    * the 5px margin-end with a negative margin-start.
    */
@@ -104,26 +99,28 @@ menubar > menu[_moz-menuactive="true"][o
   -moz-font-smoothing-background-color: -moz-mac-active-menuitem;
   color: -moz-mac-menutextselect;
 }
 
 /* ..... internal content .... */
 
 .menubar-left {
   margin: 0 2px;
-  color: inherit;
 }
 
 .menubar-text {
   margin: 0 1px !important;
-  color: inherit;
 }
 
 /* ::::: menu/menuitems in popups ::::: */
 
+menupopup {
+  font: -moz-pull-down-menu;
+}
+
 menupopup > menu,
 menupopup > menuitem,
 menupopup > menucaption {
   max-width: 42em;
 }
 
 menu[_moz-menuactive="true"],
 menuitem[_moz-menuactive="true"] {
@@ -139,17 +136,16 @@ menuitem[customoptionstyling="true"] {
 }
 
 /* ::::: menu/menuitems in menulist popups ::::: */
 
 menulist > menupopup > menuitem,
 menulist > menupopup > menucaption,
 menulist > menupopup > menu {
   max-width: none;
-  font: inherit;
   color: -moz-FieldText;
 }
 
 /* ::::: menuitems in editable menulist popups ::::: */
 
 menulist[editable="true"] > menupopup > menuitem,
 menulist[editable="true"] > menupopup > menucaption {
   -moz-appearance: none;
--- a/toolkit/themes/windows/global/menu.css
+++ b/toolkit/themes/windows/global/menu.css
@@ -5,31 +5,31 @@
 /* ===== menu.css =======================================================
   == Styles used by XUL menu-related elements.
   ======================================================================= */
 
 @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
 
 /* ::::: menu/menuitem ::::: */
 
+menupopup,
+menubar {
+  font: menu;
+}
+
 menu,
 menuitem,
 menucaption {
   -moz-appearance: menuitem;
   -moz-box-align: center;
   color: MenuText;
-  font: menu;
   list-style-image: none;
   -moz-image-region: auto;
 }
 
-menuitem[default="true"] {
-  font-weight: bold;
-}
-
 menu[disabled="true"],
 menuitem[disabled="true"],
 menu[_moz-menuactive="true"][disabled="true"],
 menuitem[_moz-menuactive="true"][disabled="true"] {
   color: GrayText;
   text-shadow: none;
 }
 
@@ -37,51 +37,49 @@ menuitem[_moz-menuactive="true"][disable
   menu[disabled="true"],
   menubar > menu[disabled="true"][_moz-menuactive="true"],
   menuitem[disabled="true"] {
     color: ThreeDShadow;
     text-shadow: 1px 1px ThreeDHighlight;
   }
 }
 
-menuitem.spell-suggestion {
+menuitem[default="true"],
+menuitem.spell-suggestion,
+menucaption {
   font-weight: bold;
 }
 
 /* ..... internal content .... */
 
 .menu-accel,
 .menu-iconic-accel,
 .menu-text,
 .menu-iconic-text {
   margin: 0px !important;
   padding: 1px 0px;
-  color: inherit;
 }
 
 .menu-text {
   padding-inline-start: 1.45em !important;
   -moz-appearance: menuitemtext;
 }
 
 .menu-text,
 .menu-iconic-text {
-  font-weight: inherit;
   margin-inline-start: 2px !important;
   padding-inline-end: 2px;
 }
 
 menucaption > .menu-iconic-text {
-  font-weight: bold;
   padding-inline-start: 0 !important;
 }
 
 .menu-accel,
 .menu-iconic-accel {
-  color: inherit;
   margin-inline-start: 0.74em !important;
   margin-inline-end: 1.35em !important;
 }
 
 .menu-iconic-left {
   min-width: 1.45em;
 }
 
@@ -151,23 +149,18 @@ menubar > menu:-moz-lwtheme[_moz-menuact
 %ifdef XP_WIN
 menubar > menu:-moz-window-inactive {
   color: ThreeDShadow;
 }
 %endif
 
 /* ..... internal content .... */
 
-.menubar-left {
-  color: inherit;
-}
-
 .menubar-text {
   margin: 1px 6px 2px 6px !important;
-  color: inherit;
 }
 
 /* ::::: menu/menuitems in popups ::::: */
 
 menupopup > menu,
 menupopup > menuitem,
 menupopup > menucaption {
   max-width: 42em;
@@ -176,25 +169,28 @@ menupopup > menucaption {
 menu[_moz-menuactive="true"],
 menuitem[_moz-menuactive="true"] {
   background-color: -moz-menuhover;
   color: -moz-menuhovertext;
 }
 
 /* ::::: menu/menuitems in menulist popups ::::: */
 
+menulist > menupopup {
+  font: message-box;
+}
+
 menulist > menupopup > menuitem,
 menulist > menupopup > menucaption,
 menulist > menupopup > menu {
   -moz-appearance: none !important;
   border: 1px solid transparent;
   padding-inline-start: 5px;
   padding-inline-end: 5px;
   max-width: none;
-  font: message-box;
   color: -moz-FieldText;
 }
 
 menulist > menupopup > menuitem[_moz-menuactive="true"],
 menulist > menupopup > menu[_moz-menuactive="true"] {
   background-color: highlight;
   color: highlighttext;
 }