Bug 1404688 - Make headerURL optional and remove text-shadow when there is no headerURL. r=jaws draft
authorTim Nguyen <ntim.bugs@gmail.com>
Thu, 15 Feb 2018 13:37:30 +0000
changeset 755575 2ed208a81ca59367b9140a6e73b85bf630c6e294
parent 755574 93227b85dd4425e59eee6958c0db9669dfb01414
push id99193
push userbmo:ntim.bugs@gmail.com
push dateThu, 15 Feb 2018 13:38:17 +0000
reviewersjaws
bugs1404688
milestone60.0a1
Bug 1404688 - Make headerURL optional and remove text-shadow when there is no headerURL. r=jaws MozReview-Commit-ID: 5x6SPWEJ3jp
browser/base/content/browser.css
browser/base/content/defaultthemes/compact.header.png
browser/base/content/test/general/browser_compacttheme.js
browser/base/jar.mn
browser/components/nsBrowserGlue.js
browser/themes/shared/compacttheme.inc.css
browser/themes/shared/customizableui/customizeMode.inc.css
browser/themes/shared/tabs.inc.css
browser/themes/windows/browser-aero.css
browser/themes/windows/compacttheme.css
toolkit/components/extensions/ext-theme.js
toolkit/components/extensions/test/browser/browser_ext_themes_lwtsupport.js
toolkit/components/extensions/test/browser/browser_ext_themes_toolbars.js
toolkit/modules/LightweightThemeConsumer.jsm
toolkit/mozapps/extensions/LightweightThemeManager.jsm
toolkit/mozapps/extensions/test/xpcshell/test_LightweightThemeManager.js
toolkit/themes/linux/global/global.css
toolkit/themes/linux/global/toolbarbutton.css
toolkit/themes/osx/global/global.css
toolkit/themes/windows/global/global.css
toolkit/themes/windows/global/toolbarbutton.css
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -13,21 +13,25 @@
 }
 
 :root:-moz-lwtheme {
   color: var(--lwt-text-color) !important;
 }
 
 :root:-moz-lwtheme {
   background-color: var(--lwt-accent-color) !important;
-  background-image: var(--lwt-header-image), var(--lwt-additional-images) !important;
+  background-image: var(--lwt-additional-images) !important;
   background-position: var(--lwt-background-alignment) !important;
   background-repeat: var(--lwt-background-tiling) !important;
 }
 
+:root:-moz-lwtheme[lwtheme-image] {
+  background-image: var(--lwt-header-image), var(--lwt-additional-images) !important;
+}
+
 :root:-moz-lwtheme:-moz-window-inactive {
   background-color: var(--lwt-accent-color-inactive, var(--lwt-accent-color)) !important;
 }
 
 #main-window:not([chromehidden~="toolbar"]) {
 %ifdef XP_MACOSX
   min-width: 335px;
 %else
deleted file mode 100644
index e4e8dcaa3b3cd01a1287359902561166d7f942ee..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
--- a/browser/base/content/test/general/browser_compacttheme.js
+++ b/browser/base/content/test/general/browser_compacttheme.js
@@ -41,17 +41,16 @@ add_task(async function startTests() {
   LightweightThemeManager.currentTheme = null;
   ok(!CompactTheme.isStyleSheetEnabled, "There is no compact style sheet when no lw theme is applied.");
 });
 
 function dummyLightweightTheme(id) {
   return {
     id,
     name: id,
-    headerURL: "resource:///chrome/browser/content/browser/defaultthemes/compact.header.png",
     iconURL: "resource:///chrome/browser/content/browser/defaultthemes/light.icon.svg",
     textcolor: "red",
     accentcolor: "blue"
   };
 }
 
 add_task(async function testLightweightThemePreview() {
   info("Setting compact to current and previewing others");
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -91,17 +91,16 @@ browser.jar:
         content/browser/defaultthemes/3.icon.png      (content/defaultthemes/3.icon.png)
         content/browser/defaultthemes/3.preview.png   (content/defaultthemes/3.preview.png)
         content/browser/defaultthemes/4.header.png    (content/defaultthemes/4.header.png)
         content/browser/defaultthemes/4.icon.png      (content/defaultthemes/4.icon.png)
         content/browser/defaultthemes/4.preview.png   (content/defaultthemes/4.preview.png)
         content/browser/defaultthemes/5.header.png    (content/defaultthemes/5.header.png)
         content/browser/defaultthemes/5.icon.jpg      (content/defaultthemes/5.icon.jpg)
         content/browser/defaultthemes/5.preview.jpg   (content/defaultthemes/5.preview.jpg)
-        content/browser/defaultthemes/compact.header.png    (content/defaultthemes/compact.header.png)
         content/browser/defaultthemes/dark.icon.svg  (content/defaultthemes/dark.icon.svg)
         content/browser/defaultthemes/light.icon.svg (content/defaultthemes/light.icon.svg)
         content/browser/newtab/newTab.xhtml           (content/newtab/newTab.xhtml)
 *       content/browser/newtab/newTab.js              (content/newtab/newTab.js)
         content/browser/newtab/newTab.css             (content/newtab/newTab.css)
         content/browser/newtab/alternativeDefaultSites.json   (content/newtab/alternativeDefaultSites.json)
 *       content/browser/pageinfo/pageInfo.xul         (content/pageinfo/pageInfo.xul)
         content/browser/pageinfo/pageInfo.js          (content/pageinfo/pageInfo.js)
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -695,27 +695,25 @@ BrowserGlue.prototype = {
     SessionStore.init();
 
     let vendorShortName = gBrandBundle.GetStringFromName("vendorShortName");
 
     LightweightThemeManager.addBuiltInTheme({
       id: "firefox-compact-light@mozilla.org",
       name: gBrowserBundle.GetStringFromName("lightTheme.name"),
       description: gBrowserBundle.GetStringFromName("lightTheme.description"),
-      headerURL: "resource:///chrome/browser/content/browser/defaultthemes/compact.header.png",
       iconURL: "resource:///chrome/browser/content/browser/defaultthemes/light.icon.svg",
       textcolor: "black",
       accentcolor: "white",
       author: vendorShortName,
     });
     LightweightThemeManager.addBuiltInTheme({
       id: "firefox-compact-dark@mozilla.org",
       name: gBrowserBundle.GetStringFromName("darkTheme.name"),
       description: gBrowserBundle.GetStringFromName("darkTheme.description"),
-      headerURL: "resource:///chrome/browser/content/browser/defaultthemes/compact.header.png",
       iconURL: "resource:///chrome/browser/content/browser/defaultthemes/dark.icon.svg",
       textcolor: "white",
       accentcolor: "black",
       author: vendorShortName,
     });
 
 
     // Initialize the default l10n resource sources for L10nRegistry.
--- a/browser/themes/shared/compacttheme.inc.css
+++ b/browser/themes/shared/compacttheme.inc.css
@@ -2,18 +2,16 @@
 % License, v. 2.0. If a copy of the MPL was not distributed with this
 % file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 /* compacttheme.css is loaded in browser.xul after browser.css when it is
    preffed on.  The bulk of the styling is here in the shared file, but
    there are overrides for each platform in their compacttheme.css files. */
 
 :root:-moz-lwtheme {
-  text-shadow: none;
-
   --toolbar-bgcolor: var(--chrome-secondary-background-color);
   --toolbar-gbimage: none;
   --toolbar-non-lwt-bgcolor: var(--toolbar-bgcolor);
   --toolbar-non-lwt-textcolor: var(--chrome-color);
   --toolbar-non-lwt-bgimage: none;
 
   --toolbarbutton-icon-fill-opacity: .7;
 }
@@ -104,14 +102,8 @@ toolbar[brighttext] .toolbarbutton-1 {
 
 #urlbar-zoom-button:-moz-lwtheme-brighttext:hover {
   background-color: rgba(255,255,255,.2);
 }
 
 #urlbar-zoom-button:-moz-lwtheme-brighttext:hover:active {
   background-color: rgba(255,255,255,.3);
 }
-
-.tab-icon-sound[soundplaying],
-.tab-icon-sound[muted] {
-  filter: none !important; /* removes drop-shadow filter */
-}
-
--- a/browser/themes/shared/customizableui/customizeMode.inc.css
+++ b/browser/themes/shared/customizableui/customizeMode.inc.css
@@ -14,32 +14,32 @@
 
 #customization-container {
   background-color: var(--toolbar-non-lwt-bgcolor);
   background-image: var(--toolbar-non-lwt-bgimage);
   color: var(--toolbar-non-lwt-textcolor);
   text-shadow: none;
 }
 
-#customization-container:-moz-lwtheme {
+:root[lwtheme-image] #customization-container {
   background-color: transparent;
   background-image: linear-gradient(var(--toolbar-bgcolor), var(--toolbar-non-lwt-bgcolor) 45px);
 }
 
 #customization-palette {
   padding: 5px 20px 20px;
 }
 
 #customization-header {
   font-weight: 500;
   font-size: 1.2em;
   margin: 20px 20px 15px;
 }
 
-#customization-header:-moz-lwtheme {
+:root[lwtheme-image] #customization-header {
   text-shadow: 0 0 1em var(--toolbar-non-lwt-bgcolor),
                0 0 1em var(--toolbar-non-lwt-bgcolor),
                0 0 .5em var(--toolbar-non-lwt-bgcolor);
 }
 
 #customization-panel-container {
   padding: 0 20px 25px;
 }
--- a/browser/themes/shared/tabs.inc.css
+++ b/browser/themes/shared/tabs.inc.css
@@ -406,25 +406,25 @@ tabbrowser {
 .tab-icon-sound[muted] {
   list-style-image: url(chrome://browser/skin/tabbrowser/tab-audio-muted.svg);
 }
 
 .tab-icon-sound[activemedia-blocked] {
   list-style-image: url(chrome://browser/skin/tabbrowser/tab-audio-blocked.svg);
 }
 
-.tab-icon-sound:-moz-lwtheme-darktext[soundplaying],
-.tab-icon-sound:-moz-lwtheme-darktext[muted],
-.tab-icon-sound:-moz-lwtheme-darktext[activemedia-blocked] {
+:root[lwtheme-image] .tab-icon-sound:-moz-lwtheme-darktext[soundplaying],
+:root[lwtheme-image] .tab-icon-sound:-moz-lwtheme-darktext[muted],
+:root[lwtheme-image] .tab-icon-sound:-moz-lwtheme-darktext[activemedia-blocked] {
   filter: drop-shadow(1px 1px 1px white);
 }
 
-.tab-icon-sound:-moz-lwtheme-brighttext[soundplaying],
-.tab-icon-sound:-moz-lwtheme-brighttext[muted],
-.tab-icon-sound:-moz-lwtheme-brighttext[activemedia-blocked] {
+:root[lwtheme-image] .tab-icon-sound:-moz-lwtheme-brighttext[soundplaying],
+:root[lwtheme-image] .tab-icon-sound:-moz-lwtheme-brighttext[muted],
+:root[lwtheme-image] .tab-icon-sound:-moz-lwtheme-brighttext[activemedia-blocked] {
   filter: drop-shadow(1px 1px 1px black);
 }
 
 .tab-icon-sound[soundplaying]:not(:hover),
 .tab-icon-sound[muted]:not(:hover),
 .tab-icon-sound[activemedia-blocked]:not(:hover) {
   opacity: .8;
 }
@@ -525,17 +525,17 @@ tabbrowser {
 }
 
 /*
  * LightweightThemeConsumer will set the current lightweight theme's header
  * image to the lwt-header-image variable, used in each of the following rulesets.
  */
 
 /* Lightweight theme on tabs */
-#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background[selected=true]:-moz-lwtheme {
+:root[lwtheme-image] #tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background[selected=true] {
   background-attachment: scroll, fixed;
   background-color: transparent;
   background-image: linear-gradient(var(--toolbar-bgcolor), var(--toolbar-bgcolor)),
                     var(--lwt-header-image);
   background-position: 0 0, right top;
   background-repeat: repeat-x, no-repeat;
   background-size: auto 100%, auto auto;
 }
--- a/browser/themes/windows/browser-aero.css
+++ b/browser/themes/windows/browser-aero.css
@@ -101,29 +101,29 @@
       :root[sizemode="maximized"] #titlebar-max {
         list-style-image: url(chrome://browser/skin/window-controls/restore.svg);
       }
 
       #titlebar-close {
         list-style-image: url(chrome://browser/skin/window-controls/close.svg);
       }
 
-      .titlebar-button:-moz-lwtheme {
+      :root[lwtheme-image] .titlebar-button {
         -moz-context-properties: unset;
       }
-      #titlebar-min:-moz-lwtheme {
+      :root[lwtheme-image] #titlebar-min {
         list-style-image: url(chrome://browser/skin/window-controls/minimize-themes.svg);
       }
-      #titlebar-max:-moz-lwtheme {
+      :root[lwtheme-image] #titlebar-max {
         list-style-image: url(chrome://browser/skin/window-controls/maximize-themes.svg);
       }
-      :root[sizemode="maximized"] #titlebar-max:-moz-lwtheme {
+      :root[lwtheme-image][sizemode="maximized"] #titlebar-max {
         list-style-image: url(chrome://browser/skin/window-controls/restore-themes.svg);
       }
-      #titlebar-close:-moz-lwtheme {
+      :root[lwtheme-image] #titlebar-close {
         list-style-image: url(chrome://browser/skin/window-controls/close-themes.svg);
       }
 
       /* the 12px image renders a 10px icon, and the 10px upscaled gets rounded to 12.5, which
        * rounds up to 13px, which makes the icon one pixel too big on 1.25dppx. Fix: */
       @media (min-resolution: 1.20dppx) and (max-resolution: 1.45dppx) {
         .titlebar-button > .toolbarbutton-icon {
           width: 11.5px;
--- a/browser/themes/windows/compacttheme.css
+++ b/browser/themes/windows/compacttheme.css
@@ -26,20 +26,16 @@
       background-color: rgb(185,209,234) !important;
     }
     #main-window:-moz-window-inactive {
       background-color: rgb(215,228,242) !important;
     }
   }
 }
 
-#toolbar-menubar {
-  text-shadow: none !important;
-}
-
 @media (-moz-os-version: windows-win7) {
   @media (-moz-windows-default-theme) {
     /* Always show light toolbar elements on aero surface. */
     #TabsToolbar {
       color: hsl(240,9%,98%);
     }
 
     /* Keep showing the correct color inside the tabs. */
@@ -60,21 +56,16 @@
 }
 
 @media (-moz-windows-glass) {
   /* Set to full fill-opacity to improve visibility of toolbar buttons on aero glass. */
   #TabsToolbar {
     --toolbarbutton-icon-fill-opacity: 1;
   }
 
-  /* Make the menubar text readable on aero glass (copied from browser-aero.css). */
-  #toolbar-menubar {
-    text-shadow: 0 0 .5em white, 0 0 .5em white, 0 1px 0 rgba(255,255,255,.4);
-  }
-
   #main-menubar:not(:-moz-window-inactive) {
     background-color: rgba(255,255,255,.5);
     color: black;
     border-radius: 4px;
   }
 }
 
 @media (-moz-os-version: windows-win7),
@@ -150,28 +141,8 @@
  * over the native border with our custom borders: */
 #navigator-toolbox {
   /* These are !important to avoid specificity-wars with the selectors that add borders here. */
   background-image: none !important;
   border-top: none !important;
   box-shadow: none !important;
   padding-top: 0 !important;
 }
-
-@media (-moz-os-version: windows-win10) {
-  .titlebar-button:-moz-lwtheme {
-    -moz-context-properties: stroke;
-    stroke: currentColor;
-  }
-  #titlebar-min:-moz-lwtheme {
-    list-style-image: url(chrome://browser/skin/window-controls/minimize.svg);
-  }
-  #titlebar-max:-moz-lwtheme {
-    list-style-image: url(chrome://browser/skin/window-controls/maximize.svg);
-  }
-  :root[sizemode="maximized"] #titlebar-max:-moz-lwtheme {
-    list-style-image: url(chrome://browser/skin/window-controls/restore.svg);
-  }
-  #titlebar-close:-moz-lwtheme {
-    list-style-image: url(chrome://browser/skin/window-controls/close.svg);
-  }
-}
-
--- a/toolkit/components/extensions/ext-theme.js
+++ b/toolkit/components/extensions/ext-theme.js
@@ -79,19 +79,18 @@ class Theme {
     if (details.icons) {
       this.loadIcons(details.icons);
     }
 
     if (details.properties) {
       this.loadProperties(details.properties);
     }
 
-    // Lightweight themes require all properties to be defined.
-    if (this.lwtStyles.headerURL &&
-        this.lwtStyles.accentcolor &&
+    // Lightweight themes require accentcolor and textcolor to be defined.
+    if (this.lwtStyles.accentcolor &&
         this.lwtStyles.textcolor) {
       if (this.windowId) {
         windowOverrides.set(this.windowId, this);
       } else {
         windowOverrides.clear();
         defaultTheme = this;
       }
       onUpdatedEmitter.emit("theme-updated", this.details, this.windowId);
--- a/toolkit/components/extensions/test/browser/browser_ext_themes_lwtsupport.js
+++ b/toolkit/components/extensions/test/browser/browser_ext_themes_lwtsupport.js
@@ -25,31 +25,76 @@ add_task(async function test_support_LWT
   });
 
   await extension.startup();
 
   let docEl = window.document.documentElement;
   let style = window.getComputedStyle(docEl);
 
   Assert.ok(docEl.hasAttribute("lwtheme"), "LWT attribute should be set");
+  Assert.ok(docEl.hasAttribute("lwtheme-image"), "LWT image attribute should be set");
   Assert.equal(docEl.getAttribute("lwthemetextcolor"), "bright",
                "LWT text color attribute should be set");
 
   Assert.ok(style.backgroundImage.includes("image1.png"), "Expected background image");
   Assert.equal(style.backgroundColor, "rgb(" + hexToRGB(ACCENT_COLOR).join(", ") + ")",
                "Expected correct background color");
   Assert.equal(style.color, "rgb(" + hexToRGB(TEXT_COLOR).join(", ") + ")",
                "Expected correct text color");
 
   await extension.unload();
 
   Assert.ok(!docEl.hasAttribute("lwtheme"), "LWT attribute should not be set");
+  Assert.ok(!docEl.hasAttribute("lwtheme-image"), "LWT image attribute should not be set");
 });
 
-add_task(async function test_LWT_requires_all_properties_defined_image_only() {
+add_task(async function test_LWT_image_attribute() {
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      "theme": {
+        "colors": {
+          "accentcolor": ACCENT_COLOR,
+          "textcolor": TEXT_COLOR,
+        },
+      },
+    },
+  });
+
+  await extension.startup();
+
+  let docEl = window.document.documentElement;
+  Assert.ok(docEl.hasAttribute("lwtheme"), "LWT attribute should be set");
+  Assert.ok(!docEl.hasAttribute("lwtheme-image"), "LWT image attribute should not be set");
+  await extension.unload();
+  Assert.ok(!docEl.hasAttribute("lwtheme"), "LWT attribute should not be set");
+  Assert.ok(!docEl.hasAttribute("lwtheme-image"), "LWT image attribute should not be set");
+});
+
+add_task(async function test_LWT_requires_accentcolor_defined_textcolor_only() {
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      "theme": {
+        "colors": {
+          "textcolor": TEXT_COLOR,
+        },
+      },
+    },
+  });
+
+  await extension.startup();
+
+  let docEl = window.document.documentElement;
+  Assert.ok(!docEl.hasAttribute("lwtheme"), "LWT attribute should not be set");
+  Assert.ok(!docEl.hasAttribute("lwtheme-image"), "LWT image attribute should not be set");
+  await extension.unload();
+  Assert.ok(!docEl.hasAttribute("lwtheme"), "LWT attribute should not be set");
+  Assert.ok(!docEl.hasAttribute("lwtheme-image"), "LWT image attribute should not be set");
+});
+
+add_task(async function test_LWT_requires_accentcolor_defined_image_only() {
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
       "theme": {
         "images": {
           "headerURL": "image1.png",
         },
       },
     },
@@ -57,31 +102,13 @@ add_task(async function test_LWT_require
       "image1.png": BACKGROUND,
     },
   });
 
   await extension.startup();
 
   let docEl = window.document.documentElement;
   Assert.ok(!docEl.hasAttribute("lwtheme"), "LWT attribute should not be set");
+  Assert.ok(!docEl.hasAttribute("lwtheme-image"), "LWT image attribute should not be set");
   await extension.unload();
   Assert.ok(!docEl.hasAttribute("lwtheme"), "LWT attribute should not be set");
+  Assert.ok(!docEl.hasAttribute("lwtheme-image"), "LWT image attribute should not be set");
 });
-
-add_task(async function test_LWT_requires_all_properties_defined_colors_only() {
-  let extension = ExtensionTestUtils.loadExtension({
-    manifest: {
-      "theme": {
-        "colors": {
-          "accentcolor": ACCENT_COLOR,
-          "textcolor": TEXT_COLOR,
-        },
-      },
-    },
-  });
-
-  await extension.startup();
-
-  let docEl = window.document.documentElement;
-  Assert.ok(!docEl.hasAttribute("lwtheme"), "LWT attribute should not be set");
-  await extension.unload();
-  Assert.ok(!docEl.hasAttribute("lwtheme"), "LWT attribute should not be set");
-});
--- a/toolkit/components/extensions/test/browser/browser_ext_themes_toolbars.js
+++ b/toolkit/components/extensions/test/browser/browser_ext_themes_toolbars.js
@@ -10,30 +10,24 @@ add_task(async function setup() {
 });
 
 add_task(async function test_support_toolbar_property() {
   const TOOLBAR_COLOR = "#ff00ff";
   const TOOLBAR_TEXT_COLOR = "#9400ff";
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
       "theme": {
-        "images": {
-          "headerURL": "image1.png",
-        },
         "colors": {
           "accentcolor": ACCENT_COLOR,
           "textcolor": TEXT_COLOR,
           "toolbar": TOOLBAR_COLOR,
           "toolbar_text": TOOLBAR_TEXT_COLOR,
         },
       },
     },
-    files: {
-      "image1.png": BACKGROUND,
-    },
   });
 
   await extension.startup();
 
   let toolbox = document.querySelector("#navigator-toolbox");
   let toolbars = [...toolbox.querySelectorAll("toolbar:not(#TabsToolbar)")].filter(toolbar => {
     let bounds = toolbar.getBoundingClientRect();
     return bounds.width > 0 && bounds.height > 0;
@@ -60,30 +54,24 @@ add_task(async function test_support_too
 });
 
 add_task(async function test_bookmark_text_property() {
   const TOOLBAR_COLOR = [255, 0, 255];
   const TOOLBAR_TEXT_COLOR = [48, 0, 255];
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
       "theme": {
-        "images": {
-          "headerURL": "image1.png",
-        },
         "colors": {
           "frame": ACCENT_COLOR,
           "background_tab_text": TEXT_COLOR,
           "toolbar": TOOLBAR_COLOR,
           "bookmark_text": TOOLBAR_TEXT_COLOR,
         },
       },
     },
-    files: {
-      "image1.png": BACKGROUND,
-    },
   });
 
   await extension.startup();
 
   let toolbox = document.querySelector("#navigator-toolbox");
   let toolbars = [...toolbox.querySelectorAll("toolbar:not(#TabsToolbar)")].filter(toolbar => {
     let bounds = toolbar.getBoundingClientRect();
     return bounds.width > 0 && bounds.height > 0;
--- a/toolkit/modules/LightweightThemeConsumer.jsm
+++ b/toolkit/modules/LightweightThemeConsumer.jsm
@@ -104,17 +104,17 @@ LightweightThemeConsumer.prototype = {
     } else {
       this._lastData = aData;
       aData = LightweightThemeImageOptimizer.optimize(aData, this._win.screen);
     }
     if (!this._enabled)
       return;
 
     let root = this._doc.documentElement;
-    let active = !!aData.headerURL;
+    let active = !!aData.accentcolor;
 
     // We need to clear these either way: either because the theme is being removed,
     // or because we are applying a new theme and the data might be bogus CSS,
     // so if we don't reset first, it'll keep the old value.
     root.style.removeProperty("--lwt-text-color");
     root.style.removeProperty("--lwt-accent-color");
     let textcolor = aData.textcolor || "black";
     _setProperty(root, active, "--lwt-text-color", textcolor);
@@ -127,16 +127,22 @@ LightweightThemeConsumer.prototype = {
       let luminance = 0.2125 * r + 0.7154 * g + 0.0721 * b;
       root.setAttribute("lwthemetextcolor", luminance <= 110 ? "dark" : "bright");
       root.setAttribute("lwtheme", "true");
     } else {
       root.removeAttribute("lwthemetextcolor");
       root.removeAttribute("lwtheme");
     }
 
+    if (aData.headerURL) {
+      root.setAttribute("lwtheme-image", "true");
+    } else {
+      root.removeAttribute("lwtheme-image");
+    }
+
     this._active = active;
 
     if (aData.icons) {
       let activeIcons = active ? Object.keys(aData.icons).join(" ") : "";
       root.setAttribute("lwthemeicons", activeIcons);
       for (let [name, value] of Object.entries(aData.icons)) {
         _setImage(root, active, name, value);
       }
--- a/toolkit/mozapps/extensions/LightweightThemeManager.jsm
+++ b/toolkit/mozapps/extensions/LightweightThemeManager.jsm
@@ -19,20 +19,20 @@ const ADDON_TYPE             = "theme";
 const ADDON_TYPE_WEBEXT      = "webextension-theme";
 
 const URI_EXTENSION_STRINGS  = "chrome://mozapps/locale/extensions/extensions.properties";
 
 const DEFAULT_MAX_USED_THEMES_COUNT = 30;
 
 const MAX_PREVIEW_SECONDS = 30;
 
-const MANDATORY = ["id", "name", "headerURL"];
-const OPTIONAL = ["footerURL", "textcolor", "accentcolor", "iconURL",
-                  "previewURL", "author", "description", "homepageURL",
-                  "updateURL", "version"];
+const MANDATORY = ["id", "name"];
+const OPTIONAL = ["headerURL", "footerURL", "textcolor", "accentcolor",
+                  "iconURL", "previewURL", "author", "description",
+                  "homepageURL", "updateURL", "version"];
 
 const PERSIST_ENABLED = true;
 const PERSIST_BYPASS_CACHE = false;
 const PERSIST_FILES = {
   headerURL: "lightweighttheme-header",
   footerURL: "lightweighttheme-footer"
 };
 
--- a/toolkit/mozapps/extensions/test/xpcshell/test_LightweightThemeManager.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_LightweightThemeManager.js
@@ -1,12 +1,12 @@
-const MANDATORY = ["id", "name", "headerURL"];
-const OPTIONAL = ["footerURL", "textcolor", "accentcolor", "iconURL",
-                  "previewURL", "author", "description", "homepageURL",
-                  "updateURL", "version"];
+const MANDATORY = ["id", "name"];
+const OPTIONAL = ["headerURL", "footerURL", "textcolor", "accentcolor",
+                  "iconURL", "previewURL", "author", "description",
+                  "homepageURL", "updateURL", "version"];
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 function dummy(id) {
   return {
     id: id || Math.random().toString(),
     name: Math.random().toString(),
     headerURL: "http://lwttest.invalid/a.png",
@@ -307,42 +307,42 @@ function run_test() {
   delete data.name;
   try {
     ltm.currentTheme = data;
     do_throw("Should have rejected a theme with no name");
   } catch (e) {
     // Expected exception
   }
 
+  // Sanitize themes with a bad headerURL
   data = dummy();
   data.headerURL = "foo";
-  try {
-    ltm.currentTheme = data;
-    do_throw("Should have rejected a theme with a bad headerURL");
-  } catch (e) {
-    // Expected exception
-  }
+  ltm.currentTheme = data;
+  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.currentTheme.headerURL, undefined);
+  ltm.forgetUsedTheme(ltm.currentTheme.id);
+  Assert.equal(ltm.usedThemes.length, 0);
 
+  // Sanitize themes with a non-http(s) headerURL
   data = dummy();
   data.headerURL = "ftp://lwtest.invalid/test.png";
-  try {
-    ltm.currentTheme = data;
-    do_throw("Should have rejected a theme with a non-http(s) headerURL");
-  } catch (e) {
-    // Expected exception
-  }
+  ltm.currentTheme = data;
+  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.currentTheme.headerURL, undefined);
+  ltm.forgetUsedTheme(ltm.currentTheme.id);
+  Assert.equal(ltm.usedThemes.length, 0);
 
+  // Sanitize themes with a non-http(s) headerURL
   data = dummy();
   data.headerURL = "file:///test.png";
-  try {
-    ltm.currentTheme = data;
-    do_throw("Should have rejected a theme with a non-http(s) headerURL");
-  } catch (e) {
-    // Expected exception
-  }
+  ltm.currentTheme = data;
+  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.currentTheme.headerURL, undefined);
+  ltm.forgetUsedTheme(ltm.currentTheme.id);
+  Assert.equal(ltm.usedThemes.length, 0);
 
   data = dummy();
   data.updateURL = "file:///test.json";
   ltm.setLocalTheme(data);
   Assert.equal(ltm.usedThemes.length, 1);
   Assert.equal(ltm.currentTheme.updateURL, undefined);
   ltm.forgetUsedTheme(ltm.currentTheme.id);
   Assert.equal(ltm.usedThemes.length, 0);
@@ -352,22 +352,21 @@ function run_test() {
   ltm.setLocalTheme(data);
   Assert.equal(ltm.usedThemes.length, 1);
   Assert.equal(ltm.currentTheme.headerURL, "file:///test.png");
   ltm.forgetUsedTheme(ltm.currentTheme.id);
   Assert.equal(ltm.usedThemes.length, 0);
 
   data = dummy();
   data.headerURL = "ftp://lwtest.invalid/test.png";
-  try {
-    ltm.setLocalTheme(data);
-    do_throw("Should have rejected a theme with a non-http(s), non-file headerURL");
-  } catch (e) {
-    // Expected exception
-  }
+  ltm.setLocalTheme(data);
+  Assert.equal(ltm.usedThemes.length, 1);
+  Assert.equal(ltm.currentTheme.updateURL, undefined);
+  ltm.forgetUsedTheme(ltm.currentTheme.id);
+  Assert.equal(ltm.usedThemes.length, 0);
 
   data = dummy();
   delete data.id;
   try {
     ltm.currentTheme = data;
     do_throw("Should have rejected a theme with no ID");
   } catch (e) {
     // Expected exception
--- a/toolkit/themes/linux/global/global.css
+++ b/toolkit/themes/linux/global/global.css
@@ -117,21 +117,21 @@ toolbar[mode="text"] .toolbarbutton-text
 }
 
 /* ::::: miscellaneous formatting ::::: */
 
 :root:-moz-lwtheme {
   -moz-appearance: none;
 }
 
-:root:-moz-lwtheme-darktext {
+:root[lwtheme-image]:-moz-lwtheme-darktext {
   text-shadow: 0 -0.5px 1.5px white;
 }
 
-:root:-moz-lwtheme-brighttext {
+:root[lwtheme-image]:-moz-lwtheme-brighttext {
   text-shadow: 1px 1px 1.5px black;
 }
 
 .inset {
   border: 1px solid ThreeDShadow;
   border-right-color: ThreeDHighlight;
   border-bottom-color: ThreeDHighlight;
   margin: 0 5px 5px;
--- a/toolkit/themes/linux/global/toolbarbutton.css
+++ b/toolkit/themes/linux/global/toolbarbutton.css
@@ -13,17 +13,17 @@
 toolbarbutton {
   -moz-appearance: toolbarbutton;
   -moz-box-align: center;
   -moz-box-pack: center;
   margin: 0;
   padding: 3px;
 }
 
-toolbarbutton:-moz-lwtheme {
+:root[lwtheme-image] toolbarbutton {
   text-shadow: none;
 }
 
 .toolbarbutton-icon[label]:not([label=""]),
 .toolbarbutton-icon[type="menu"] {
   margin-inline-end: 2px;
 }
 
--- a/toolkit/themes/osx/global/global.css
+++ b/toolkit/themes/osx/global/global.css
@@ -98,21 +98,21 @@ sidebarheader {
   color: -moz-dialogText;
   text-shadow: none;
 }
 
 :root:-moz-lwtheme {
   -moz-appearance: none;
 }
 
-:root:-moz-lwtheme-darktext {
+:root[lwtheme-image]:-moz-lwtheme-darktext {
   text-shadow: 0 -0.5px 1.5px white;
 }
 
-:root:-moz-lwtheme-brighttext {
+:root[lwtheme-image]:-moz-lwtheme-brighttext {
   text-shadow: 1px 1px 1.5px black;
 }
 
 .inset {
   border: 1px solid ThreeDShadow;
   border-right-color: ThreeDHighlight;
   border-bottom-color: ThreeDHighlight;
   margin: 0 5px 5px;
--- a/toolkit/themes/windows/global/global.css
+++ b/toolkit/themes/windows/global/global.css
@@ -124,21 +124,21 @@ sidebarheader > label {
 
 toolbar[mode="text"] .toolbarbutton-text {
   padding: 0 !important;
   margin: 3px 5px !important;
 }
 
 /* ::::: miscellaneous formatting ::::: */
 
-:root:-moz-lwtheme-darktext {
+:root[lwtheme-image]:-moz-lwtheme-darktext {
   text-shadow: 0 -0.5px 1.5px white;
 }
 
-:root:-moz-lwtheme-brighttext {
+:root[lwtheme-image]:-moz-lwtheme-brighttext {
   text-shadow: 1px 1px 1.5px black;
 }
 
 .inset {
   border: 1px solid ThreeDShadow;
   border-right-color: ThreeDHighlight;
   border-bottom-color: ThreeDHighlight;
   margin: 0 5px 5px;
--- a/toolkit/themes/windows/global/toolbarbutton.css
+++ b/toolkit/themes/windows/global/toolbarbutton.css
@@ -65,31 +65,31 @@ toolbarbutton[checked="true"]:not([disab
   padding-top: 4px;
   padding-bottom: 2px;
   padding-inline-start: 4px;
   padding-inline-end: 2px;
   color: ButtonText;
 }
 
 @media (-moz-windows-default-theme) {
-  toolbarbutton:-moz-lwtheme {
+  :root[lwtheme-image] toolbarbutton {
     text-shadow: none;
   }
 
-  toolbarbutton:-moz-lwtheme:not([disabled="true"]) {
+  :root[lwtheme-image] toolbarbutton:not([disabled="true"]) {
     text-shadow: inherit;
   }
 }
 
 @media (-moz-windows-default-theme: 0) {
-  toolbarbutton:-moz-lwtheme {
+  :root[lwtheme-image] toolbarbutton {
     -moz-appearance: none;
   }
 
-  toolbarbutton:-moz-lwtheme:not([disabled="true"]) {
+  :root[lwtheme-image] toolbarbutton:not([disabled="true"]) {
     text-shadow: inherit;
   }
 }
 
 /* ::::: toolbarbutton menu ::::: */
 
 .toolbarbutton-menu-dropmarker {
   -moz-appearance: none !important;