Backed out 5 changesets (bug 1511138) for causing eslint failure on SelectChild.jsm CLOSED TREE
authorarthur.iakab <aiakab@mozilla.com>
Fri, 07 Dec 2018 20:55:24 +0200
changeset 506125 5fcc6bd202c45914bdbbfcf9a8e3f3dde23c2870
parent 506124 daee82295b3c81d57991a7db1b6851dc7bc8d963
child 506126 a6ae557a428bb1a50478db2fa6a868fb91372856
push id10304
push usercsabou@mozilla.com
push dateMon, 10 Dec 2018 13:40:42 +0000
treeherdermozilla-beta@89eaae012b30 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1511138
milestone65.0a1
backs outdaee82295b3c81d57991a7db1b6851dc7bc8d963
d23c9c3e1566f64b0257d97597daaae3c3ed0897
a99600391704f8752e6f05e312fe8e8cd588715a
4ef293b908879b56b27c1f473127db680c099a60
4df286b234b3daf6c315ae2f3f58f857664f88c7
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
Backed out 5 changesets (bug 1511138) for causing eslint failure on SelectChild.jsm CLOSED TREE Backed out changeset daee82295b3c (bug 1511138) Backed out changeset d23c9c3e1566 (bug 1511138) Backed out changeset a99600391704 (bug 1511138) Backed out changeset 4ef293b90887 (bug 1511138) Backed out changeset 4df286b234b3 (bug 1511138)
browser/base/content/test/forms/browser_selectpopup_colors.js
browser/components/extensions/test/browser/browser_ext_popup_background.js
dom/base/test/test_bug564863.xhtml
dom/tests/mochitest/general/test_offsets.js
layout/reftests/cssom/computed-style-cross-window-ref.html
layout/reftests/cssom/computed-style-cross-window.html
layout/style/nsComputedDOMStyle.cpp
layout/style/test/chrome/bug418986-2.js
layout/style/test/test_bug1203766.html
layout/style/test/test_default_bidi_css.html
testing/web-platform/meta/css/cssom/getComputedStyle-detached-subtree.html.ini
testing/web-platform/tests/css/css-fonts/font-variant-alternates-parsing.html
toolkit/actors/SelectChild.jsm
toolkit/components/extensions/test/browser/browser_ext_themes_autocomplete_popup.js
toolkit/components/extensions/test/browser/browser_ext_themes_sanitization.js
toolkit/content/widgets/browser.xml
toolkit/modules/LightweightThemeConsumer.jsm
toolkit/modules/SelectParentHelper.jsm
--- a/browser/base/content/test/forms/browser_selectpopup_colors.js
+++ b/browser/base/content/test/forms/browser_selectpopup_colors.js
@@ -180,22 +180,18 @@ const SELECT_INHERITED_COLORS_ON_OPTIONS
      <option class="textShadow">{"color": "rgb(0, 0, 255)", "textShadow": "rgb(0, 0, 0) 1px 1px 2px", "backgroundColor": "rgba(0, 0, 0, 0)"}</option>
      <option selected="true">{"end": "true"}</option>
    </select></body></html>
 `;
 
 function getSystemColor(color) {
   // Need to convert system color to RGB color.
   let textarea = document.createElementNS("http://www.w3.org/1999/xhtml", "textarea");
-  textarea.style.display = "none";
   textarea.style.color = color;
-  document.documentElement.appendChild(textarea);
-  let computed = getComputedStyle(textarea).color;
-  textarea.remove();
-  return computed;
+  return getComputedStyle(textarea).color;
 }
 
 function testOptionColors(index, item, menulist) {
   // The label contains a JSON string of the expected colors for
   // `color` and `background-color`.
   let expected = JSON.parse(item.label);
 
   for (let color of Object.keys(expected)) {
@@ -210,17 +206,17 @@ function testOptionColors(index, item, m
   EventUtils.synthesizeKey("KEY_ArrowDown");
 
   if (expected.end) {
     return;
   }
 
   if (expected.unstyled) {
     ok(!item.hasAttribute("customoptionstyling"),
-      `Item ${index} should not have any custom option styling: ${item.outerHTML}`);
+      `Item ${index} should not have any custom option styling`);
   } else {
     is(getComputedStyle(item).color, expected.color,
        "Item " + (index) + " has correct foreground color");
     is(getComputedStyle(item).backgroundColor, expected.backgroundColor,
        "Item " + (index) + " has correct background color");
     if (expected.textShadow) {
       is(getComputedStyle(item).textShadow, expected.textShadow,
          "Item " + (index) + " has correct text-shadow color");
--- a/browser/components/extensions/test/browser/browser_ext_popup_background.js
+++ b/browser/components/extensions/test/browser/browser_ext_popup_background.js
@@ -15,20 +15,17 @@ async function testPanel(browser, standA
            "rgb(255, 255, 255)", "Arrow fill should be set to #fff when no background is supplied and popup is standAlone");
       } else {
         let default_background =
           getComputedStyle(document.documentElement).getPropertyValue("--arrowpanel-background");
         // Need to apply the color to a node and get the computed value
         // to resolve CSS named colors such as -moz-field.
         let span = document.createElementNS("http://www.w3.org/1999/xhtml", "span");
         span.style.color = default_background;
-        span.style.display = "none";
-        document.documentElement.appendChild(span);
         let default_background_computed = getComputedStyle(span).color;
-        span.remove();
 
         is(getComputedStyle(arrow).fill, default_background_computed, "Arrow fill should be the default one");
       }
       return;
     }
 
     is(getComputedStyle(arrowContent).backgroundColor, background, "Arrow content should have correct background");
     is(getComputedStyle(arrow).fill, background, "Arrow should have correct background");
--- a/dom/base/test/test_bug564863.xhtml
+++ b/dom/base/test/test_bug564863.xhtml
@@ -76,22 +76,21 @@ function checkHasId(test) {
   is($("div_id"), div, "div getElementById " + test);
   is($("a_id"),   a,   "a getElementById " + test);
   is($("xul_id"), xul, "xul getElementById " + test);
   is($("svg_id"), svg, "svg getElementById " + test);
   is($("ns_id"),  nsx, "ns getElementById " + test);
 }
 
 function checkHasIdNoGEBI(test) {
-  const connected = test != "removed node";
-  is(div_cs.color, connected ? "rgb(10, 10, 10)" : "", "div color " + test);
-  is(a_cs.color,   connected ? "rgb(20, 20, 20)" : "", "a color " + test);
-  is(xul_cs.color, connected ? "rgb(30, 30, 30)" : "", "xul color " + test);
-  is(svg_cs.color, connected ? "rgb(40, 40, 40)" : "", "svg color " + test);
-  is(nsx_cs.color, connected ? "rgb(50, 50, 50)" : "", "nsx color " + test);
+  is(div_cs.color, "rgb(10, 10, 10)", "div color " + test);
+  is(a_cs.color,   "rgb(20, 20, 20)", "a color " + test);
+  is(xul_cs.color, "rgb(30, 30, 30)", "xul color " + test);
+  is(svg_cs.color, "rgb(40, 40, 40)", "svg color " + test);
+  is(nsx_cs.color, "rgb(50, 50, 50)", "nsx color " + test);
 
   is(div.id, "div_id", "div id " + test);
   is(a.id,   "a_id",   "a id " + test);
   is(xul.id, "xul_id", "xul id " + test);
   is(svg.id, "svg_id", "svg id " + test);
   is (nsx.getAttribute("id"), "ns_id", "ns id " + test);
 }
 
--- a/dom/tests/mochitest/general/test_offsets.js
+++ b/dom/tests/mochitest/general/test_offsets.js
@@ -211,12 +211,12 @@ function checkCoords(element, type, left
     ok(element[type + "Width"] == 0 && element[type + "Height"] == 0,
        element.id + " has zero " + type + " width and height");
 }
 
 function gcs(element, prop)
 {
   var propVal = (element instanceof SVGElement && (prop == "width" || prop == "height")) ?
                    element.getAttribute(prop) : getComputedStyle(element, "")[prop];
-  if (propVal == "auto" || element.id == "nonappended")
+  if (propVal == "auto")
     return 0;
   return parseFloat(propVal);
 }
--- a/layout/reftests/cssom/computed-style-cross-window-ref.html
+++ b/layout/reftests/cssom/computed-style-cross-window-ref.html
@@ -13,30 +13,38 @@ var gRunCount = 2;
 function run() {
   if (--gRunCount != 0)
     return;
 
   var i = document.getElementById("i");
 
   var pout = document.getElementById("out");
   var poutnone = document.getElementById("outnone");
+  var poutdet = document.createElement("p");
   var pin = i.contentDocument.getElementsByTagName("p")[0];
   var pinnone = i.contentDocument.getElementsByTagName("p")[1];
+  var pindet = i.contentDocument.createElement("p");
 
   document.getElementById("res1").style.color =
     window.getComputedStyle(pin).color;
 
   document.getElementById("res2").style.color =
     i.contentWindow.getComputedStyle(pout).color;
 
   document.getElementById("res3").style.color =
     window.getComputedStyle(pinnone).color;
 
   document.getElementById("res4").style.color =
     i.contentWindow.getComputedStyle(poutnone).color;
+
+  document.getElementById("res5").style.color =
+    window.getComputedStyle(pindet).color;
+
+  document.getElementById("res6").style.color =
+    i.contentWindow.getComputedStyle(poutdet).color;
 }
 
 </script>
 <body onload="run()">
 
 <p id="out">This is a paragraph outside the iframe.</p>
 <div style="display:none"><p id="outnone">This is a paragraph outside the iframe.</p></div>
 
@@ -52,8 +60,16 @@ is.</div>
 
 <div style="color:fuchsia">This paragraph is the color that
 outerWindow.getComputedStyle says the display:none paragraph inside the
 iframe is.</div>
 
 <div style="color:blue">This paragraph is the color that
 iframeWindow.getComputedStyle says the display:none paragraph outside
 the iframe is.</div>
+
+<div style="color:blue">This paragraph is the color that
+outerWindow.getComputedStyle says the detached paragraph inside the
+iframe is.</div>
+
+<div style="color:fuchsia">This paragraph is the color that
+iframeWindow.getComputedStyle says the detached paragraph outside
+the iframe is.</div>
--- a/layout/reftests/cssom/computed-style-cross-window.html
+++ b/layout/reftests/cssom/computed-style-cross-window.html
@@ -14,31 +14,39 @@ var gRunCount = 2;
 function run() {
   if (--gRunCount != 0)
     return;
 
   var i = document.getElementById("i");
 
   var pout = document.getElementById("out");
   var poutnone = document.getElementById("outnone");
+  var poutdet = document.createElement("p");
   var pin = i.contentDocument.getElementsByTagName("p")[0];
   var pinnone = i.contentDocument.getElementsByTagName("p")[1];
+  var pindet = i.contentDocument.createElement("p");
 
   document.getElementById("res1").style.color =
     window.getComputedStyle(pin).color;
 
   document.getElementById("res2").style.color =
     i.contentWindow.getComputedStyle(pout).color;
 
   document.getElementById("res3").style.color =
     window.getComputedStyle(pinnone).color;
 
   document.getElementById("res4").style.color =
     i.contentWindow.getComputedStyle(poutnone).color;
 
+  document.getElementById("res5").style.color =
+    window.getComputedStyle(pindet).color;
+
+  document.getElementById("res6").style.color =
+    i.contentWindow.getComputedStyle(poutdet).color;
+
   document.documentElement.removeAttribute("class");
 }
 
 </script>
 <body onload="run()">
 
 <p id="out">This is a paragraph outside the iframe.</p>
 <div style="display:none"><p id="outnone">This is a paragraph outside the iframe.</p></div>
@@ -55,8 +63,16 @@ is.</div>
 
 <div id="res3">This paragraph is the color that
 outerWindow.getComputedStyle says the display:none paragraph inside the
 iframe is.</div>
 
 <div id="res4">This paragraph is the color that
 iframeWindow.getComputedStyle says the display:none paragraph outside
 the iframe is.</div>
+
+<div id="res5">This paragraph is the color that
+outerWindow.getComputedStyle says the detached paragraph inside the
+iframe is.</div>
+
+<div id="res6">This paragraph is the color that
+iframeWindow.getComputedStyle says the detached paragraph outside
+the iframe is.</div>
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -503,22 +503,21 @@ already_AddRefed<ComputedStyle> nsComput
     }
   }
 
   CSSPseudoElementType pseudoType = GetPseudoType(aPseudo);
   if (aPseudo && pseudoType >= CSSPseudoElementType::Count) {
     return nullptr;
   }
 
-  if (!aElement->IsInComposedDoc()) {
-    // Don't return styles for disconnected elements, that makes no sense. This
-    // can only happen with a non-null presShell for cross-document calls.
-    //
-    // FIXME(emilio, bug 1483798): This should also not return styles for
-    // elements outside of the flat tree, not just outside of the document.
+  if (aElement->IsInNativeAnonymousSubtree() && !aElement->IsInComposedDoc()) {
+    // Normal web content can't access NAC, but Accessibility, DevTools and
+    // Editor use this same API and this may get called for anonymous content.
+    // Computing the style of a pseudo-element that doesn't have a parent
+    // doesn't really make sense.
     return nullptr;
   }
 
   // XXX the !aElement->IsHTMLElement(nsGkAtoms::area)
   // check is needed due to bug 135040 (to avoid using
   // mPrimaryFrame). Remove it once that's fixed.
   if (inDocWithShell && aStyleType == eAll &&
       !aElement->IsHTMLElement(nsGkAtoms::area)) {
--- a/layout/style/test/chrome/bug418986-2.js
+++ b/layout/style/test/chrome/bug418986-2.js
@@ -226,17 +226,21 @@ var generateCSSLines = function (resisti
     lines += windows_versions.map(val => "(-moz-os-version: " + val + ")").join(", ") +
              " { #-moz-os-version { background-color: " + (resisting ? "red" : "green") + ";} }\n";
   }
   return lines;
 };
 
 // __green__.
 // Returns the computed color style corresponding to green.
-var green = "rgb(0, 128, 0)";
+var green = (function () {
+  let temp = document.createElement("span");
+  temp.style.backgroundColor = "green";
+  return getComputedStyle(temp).backgroundColor;
+})();
 
 // __testCSS(resisting)__.
 // Creates a series of divs and CSS using media queries to set their
 // background color. If all media queries match as expected, then
 // all divs should have a green background color.
 var testCSS = function (resisting) {
   document.getElementById("display").appendChild(generateHtmlLines(resisting));
   document.getElementById("test-css").textContent = generateCSSLines(resisting);
@@ -248,19 +252,17 @@ var testCSS = function (resisting) {
 };
 
 // __testOSXFontSmoothing(resisting)__.
 // When fingerprinting resistance is enabled, the `getComputedStyle`
 // should always return `undefined` for `MozOSXFontSmoothing`.
 var testOSXFontSmoothing = function (resisting) {
   let div = document.createElement("div");
   div.style.MozOsxFontSmoothing = "unset";
-  document.documentElement.appendChild(div);
   let readBack = window.getComputedStyle(div).MozOsxFontSmoothing;
-  div.remove();
   let smoothingPref = SpecialPowers.getBoolPref("layout.css.osx-font-smoothing.enabled", false);
   is(readBack, resisting ? "" : (smoothingPref ? "auto" : ""),
                "-moz-osx-font-smoothing");
 };
 
 // __sleep(timeoutMs)__.
 // Returns a promise that resolves after the given timeout.
 var sleep = function (timeoutMs) {
--- a/layout/style/test/test_bug1203766.html
+++ b/layout/style/test/test_bug1203766.html
@@ -31,82 +31,82 @@ body > .a { display: none; color: green;
 SimpleTest.waitForExplicitFinish();
 
 addLoadEvent(function() {
 
   // Element that goes from being out of the document to in the document.
   var e = document.createElement("div");
   e.className = "x";
   var cs = getComputedStyle(e);
-  is(cs.color, "");
+  is(cs.color, "rgb(255, 0, 0)");
   document.body.appendChild(e);
   is(cs.color, "rgb(0, 128, 0)");
 
   // Element that goes from in the document (and display:none) to out of
   // the document.
   e = document.querySelector(".y");
   cs = getComputedStyle(e);
   is(cs.color, "rgb(255, 0, 0)");
   e.remove();
-  is(cs.color, "");
+  is(cs.color, "rgb(0, 128, 0)");
 
   // Element that is removed from an out-of-document tree.
   e = document.createElement("div");
   f = document.createElement("span");
   f.className = "z";
   e.appendChild(f);
   cs = getComputedStyle(f);
-  is(cs.color, "");
+  is(cs.color, "rgb(255, 0, 0)");
   f.remove();
-  is(cs.color, "");
+  is(cs.color, "rgb(0, 128, 0)");
 
   // Element going from not in document to in document and display:none.
   e = document.createElement("div");
   e.className = "a";
   cs = getComputedStyle(e);
-  is(cs.color, "");
+  is(cs.color, "rgb(255, 0, 0)");
   document.body.appendChild(e);
   is(cs.color, "rgb(0, 128, 0)");
 
   // Element going from not in document to in document and child of
   // display:none element.
   e = document.createElement("div");
   e.className = "c";
   cs = getComputedStyle(e);
-  is(cs.color, "");
+  is(cs.color, "rgb(255, 0, 0)");
   document.querySelector(".b").appendChild(e);
   is(cs.color, "rgb(0, 128, 0)");
 
   // Element that is added to an out-of-document tree.
   e = document.createElement("div");
   e.className = "d";
   f = document.createElement("span");
   f.className = "e";
   cs = getComputedStyle(f);
-  is(cs.color, "");
+  is(cs.color, "rgb(255, 0, 0)");
   e.appendChild(f);
-  is(cs.color, "");
+  is(cs.color, "rgb(0, 128, 0)");
 
   // Element that is outside the document when an attribute is modified to
   // cause a different rule to match.
   e = document.createElement("div");
   e.className = "f";
   cs = getComputedStyle(e);
-  is(cs.color, "");
+  is(cs.color, "rgb(255, 0, 0)");
   e.className = "g";
-  is(cs.color, "");
+  is(cs.color, "rgb(0, 128, 0)");
 
   // Element that is outside the document when an ancestor is modified to
   // cause a different rule to match.
   e = document.createElement("div");
   e.className = "h";
   f = document.createElement("span");
   f.className = "i";
   e.appendChild(f);
   cs = getComputedStyle(f);
-  is(cs.color, "");
+  is(cs.color, "rgb(255, 0, 0)");
   e.className = "j";
-  is(cs.color, "");
+  is(cs.color, "rgb(0, 128, 0)");
 
   SimpleTest.finish();
 });
 </script>
 </pre>
--- a/layout/style/test/test_default_bidi_css.html
+++ b/layout/style/test/test_default_bidi_css.html
@@ -16,17 +16,16 @@
 
 /** Test for default bidi css  **/
 function styleOf(name, attributes) {
     var element = document.createElement(name);
     for (var name in attributes) {
         var value = attributes[name];
         element.setAttribute(name, value);
     }
-    document.body.appendChild(element);
     return getComputedStyle(element);
 }
 
 var tests = [
     ['div', {}, 'ltr', 'isolate'],
     ['div', {'dir': 'ltr'}, 'ltr', 'isolate'],
     ['div', {'dir': 'rtl'}, 'rtl', 'isolate'],
     ['div', {'dir': 'auto'}, 'ltr', 'isolate'],
--- a/testing/web-platform/meta/css/cssom/getComputedStyle-detached-subtree.html.ini
+++ b/testing/web-platform/meta/css/cssom/getComputedStyle-detached-subtree.html.ini
@@ -1,9 +1,15 @@
 [getComputedStyle-detached-subtree.html]
+  [getComputedStyle returns no style for detached element]
+    expected: FAIL
+
   [getComputedStyle returns no style for element in non-rendered iframe (display: none)]
     expected: FAIL
 
   [getComputedStyle returns no style for element outside the flat tree]
     expected: FAIL
 
   [getComputedStyle returns no style for descendant outside the flat tree]
     expected: FAIL
+
+  [getComputedStyle returns no style for shadow tree outside of flattened tree]
+    expected: FAIL
--- a/testing/web-platform/tests/css/css-fonts/font-variant-alternates-parsing.html
+++ b/testing/web-platform/tests/css/css-fonts/font-variant-alternates-parsing.html
@@ -1,19 +1,18 @@
 <!doctype html>
 <meta charset="utf-8">
 <title>CSS Test:  font-variant-alternates: historical-forms; parses case-insensitively</title>
 <link rel="author" title="Emilio Cobos Álvarez" href="emilio@crisal.io">
 <link rel="help" href="https://www.w3.org/TR/css-fonts-4/#font-variant-alternates-prop">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
-<div></div>
 <script>
 test(function() {
-  let div = document.querySelector('div');
+  let div = document.createElement('div');
   div.style.fontVariantAlternates = "Historical-Forms";
   assert_equals(
     getComputedStyle(div).fontVariantAlternates,
     "historical-forms",
     "historical-forms is parsed case-insensitively"
   );
 });
 </script>
--- a/toolkit/actors/SelectChild.jsm
+++ b/toolkit/actors/SelectChild.jsm
@@ -34,16 +34,20 @@ var gOpen = false;
 var SelectContentHelper = function(aElement, aOptions, aGlobal) {
   this.element = aElement;
   this.initialSelection = aElement[aElement.selectedIndex] || null;
   this.global = aGlobal;
   this.closedWithClickOn = false;
   this.isOpenedViaTouch = aOptions.isOpenedViaTouch;
   this._selectBackgroundColor = null;
   this._selectColor = null;
+  this._uaBackgroundColor = null;
+  this._uaColor = null;
+  this._uaSelectBackgroundColor = null;
+  this._uaSelectColor = null;
   this._closeAfterBlur = true;
   this._pseudoStylesSetup = false;
   this._lockedDescendants = null;
   this.init();
   this.showDropDown();
   this._updateTimer = new DeferredTask(this._update.bind(this), 0);
 };
 
@@ -100,29 +104,29 @@ this.SelectContentHelper.prototype = {
   showDropDown() {
     this.element.openInParentProcess = true;
     this._setupPseudoClassStyles();
     let rect = this._getBoundingContentRect();
     let computedStyles = getComputedStyles(this.element);
     this._selectBackgroundColor = computedStyles.backgroundColor;
     this._selectColor = computedStyles.color;
     this._selectTextShadow = computedStyles.textShadow;
-    let options = this._buildOptionList();
-    let defaultStyles = this.element.ownerGlobal.getDefaultComputedStyle(this.element);
     this.global.sendAsyncMessage("Forms:ShowDropDown", {
       direction: computedStyles.direction,
       isOpenedViaTouch: this.isOpenedViaTouch,
-      options: options,
+      options: this._buildOptionList(),
       rect,
       selectedIndex: this.element.selectedIndex,
       selectBackgroundColor: this._selectBackgroundColor,
       selectColor: this._selectColor,
       selectTextShadow: this._selectTextShadow,
-      uaSelectBackgroundColor: defaultStyles.backgroundColor,
-      uaSelectColor: defaultStyles.color,
+      uaBackgroundColor: this.uaBackgroundColor,
+      uaColor: this.uaColor,
+      uaSelectBackgroundColor: this.uaSelectBackgroundColor,
+      uaSelectColor: this.uaSelectColor,
     });
     this._clearPseudoClassStyles();
     gOpen = true;
   },
 
   _setupPseudoClassStyles() {
     if (this._pseudoStylesSetup) {
       throw new Error("pseudo styles must not be set up yet");
@@ -173,30 +177,76 @@ this.SelectContentHelper.prototype = {
     // Technically we might not need to set this pseudo-class
     // during _update() since the element should organically
     // have :focus, though it is here for belt-and-suspenders.
     this._setupPseudoClassStyles();
     let computedStyles = getComputedStyles(this.element);
     this._selectBackgroundColor = computedStyles.backgroundColor;
     this._selectColor = computedStyles.color;
     this._selectTextShadow = computedStyles.textShadow;
-
-    let defaultStyles = this.element.ownerGlobal.getDefaultComputedStyle(this.element);
     this.global.sendAsyncMessage("Forms:UpdateDropDown", {
       options: this._buildOptionList(),
       selectedIndex: this.element.selectedIndex,
       selectBackgroundColor: this._selectBackgroundColor,
       selectColor: this._selectColor,
       selectTextShadow: this._selectTextShadow,
-      uaSelectBackgroundColor: defaultStyles.backgroundColor,
-      uaSelectColor: defaultStyles.color,
+      uaBackgroundColor: this.uaBackgroundColor,
+      uaColor: this.uaColor,
+      uaSelectBackgroundColor: this.uaSelectBackgroundColor,
+      uaSelectColor: this.uaSelectColor,
     });
     this._clearPseudoClassStyles();
   },
 
+  // Determine user agent background-color and color.
+  // This is used to skip applying the custom color if it matches
+  // the user agent values.
+  _calculateUAColors() {
+    let dummyOption = this.element.ownerDocument.createElementNS("http://www.w3.org/1999/xhtml", "option");
+    dummyOption.style.setProperty("color", "-moz-comboboxtext", "important");
+    dummyOption.style.setProperty("background-color", "-moz-combobox", "important");
+    let optionCS = this.element.ownerGlobal.getComputedStyle(dummyOption);
+    this._uaBackgroundColor = optionCS.backgroundColor;
+    this._uaColor = optionCS.color;
+    let dummySelect = this.element.ownerDocument.createElementNS("http://www.w3.org/1999/xhtml", "select");
+    dummySelect.style.setProperty("color", "-moz-fieldtext", "important");
+    dummySelect.style.setProperty("background-color", "-moz-field", "important");
+    let selectCS = this.element.ownerGlobal.getComputedStyle(dummySelect);
+    this._uaSelectBackgroundColor = selectCS.backgroundColor;
+    this._uaSelectColor = selectCS.color;
+  },
+
+  get uaBackgroundColor() {
+    if (!this._uaBackgroundColor) {
+      this._calculateUAColors();
+    }
+    return this._uaBackgroundColor;
+  },
+
+  get uaColor() {
+    if (!this._uaColor) {
+      this._calculateUAColors();
+    }
+    return this._uaColor;
+  },
+
+  get uaSelectBackgroundColor() {
+    if (!this._selectBackgroundColor) {
+      this._calculateUAColors();
+    }
+    return this._uaSelectBackgroundColor;
+  },
+
+  get uaSelectColor() {
+    if (!this._selectBackgroundColor) {
+      this._calculateUAColors();
+    }
+    return this._uaSelectColor;
+  },
+
   dispatchMouseEvent(win, target, eventName) {
     let mouseEvent = new win.MouseEvent(eventName, {
       view: win,
       bubbles: true,
       cancelable: true,
     });
     target.dispatchEvent(mouseEvent);
   },
--- a/toolkit/components/extensions/test/browser/browser_ext_themes_autocomplete_popup.js
+++ b/toolkit/components/extensions/test/browser/browser_ext_themes_autocomplete_popup.js
@@ -236,17 +236,15 @@ add_task(async function test_popup_url()
                "brighttext should not be set!");
   Assert.equal(root.getAttribute("lwt-popup-darktext"),
                "",
                "darktext should not be set!");
 
   // Calculate what GrayText should be. May differ between platforms.
   let span = document.createXULElement("span");
   span.style.color = "GrayText";
-  document.documentElement.appendChild(span);
   let GRAY_TEXT = window.getComputedStyle(span).color;
-  span.remove();
 
   separator = document.getAnonymousElementByAttribute(results[1], "anonid", "separator");
   Assert.equal(window.getComputedStyle(separator).color,
                GRAY_TEXT,
                `Urlbar popup separator color should be set to ${GRAY_TEXT}`);
 });
--- a/toolkit/components/extensions/test/browser/browser_ext_themes_sanitization.js
+++ b/toolkit/components/extensions/test/browser/browser_ext_themes_sanitization.js
@@ -49,57 +49,16 @@ add_task(async function test_sanitizatio
     window.getComputedStyle(navbar).color,
     "rgb(0, 0, 0)",
     "All CSS variables should always compute to black."
   );
 
   await extension.unload();
 });
 
-add_task(async function test_sanitization_important() {
-  // This test checks that the sanitizer cannot be fooled with !important
-  let stylesheetAttr = `href="data:text/css,*{color:red!important}" type="text/css"`;
-  let stylesheet =
-    document.createProcessingInstruction("xml-stylesheet", stylesheetAttr);
-  let load = BrowserTestUtils.waitForEvent(stylesheet, "load");
-  document.insertBefore(stylesheet, document.documentElement);
-  await load;
-
-  let extension = ExtensionTestUtils.loadExtension({
-    manifest: {
-      "theme": {
-        "colors": {
-          "frame": ACCENT_COLOR,
-          "tab_background_text": TEXT_COLOR,
-          "bookmark_text": "green",
-        },
-      },
-    },
-  });
-
-  await extension.startup();
-
-  let navbar = document.querySelector("#nav-bar");
-  Assert.equal(
-    window.getComputedStyle(navbar).color,
-    "rgb(255, 0, 0)",
-    "Sheet applies"
-  );
-
-  stylesheet.remove();
-
-  Assert.equal(
-    window.getComputedStyle(navbar).color,
-    "rgb(0, 128, 0)",
-    "Shouldn't be able to fool the color sanitizer with !important"
-  );
-
-  await extension.unload();
-});
-
 add_task(async function test_sanitization_transparent() {
   // This test checks whether transparent values are applied properly
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
       "theme": {
         "colors": {
           "frame": ACCENT_COLOR,
           "tab_background_text": TEXT_COLOR,
--- a/toolkit/content/widgets/browser.xml
+++ b/toolkit/content/widgets/browser.xml
@@ -1257,16 +1257,17 @@
               if (!this._selectParentHelper) {
                 this._selectParentHelper =
                   ChromeUtils.import("resource://gre/modules/SelectParentHelper.jsm", {}).SelectParentHelper;
               }
 
               let menulist = document.getElementById(this.getAttribute("selectmenulist"));
               menulist.menupopup.style.direction = data.direction;
               this._selectParentHelper.populate(menulist, data.options, data.selectedIndex, this._fullZoom,
+                                                data.uaBackgroundColor, data.uaColor,
                                                 data.uaSelectBackgroundColor, data.uaSelectColor,
                                                 data.selectBackgroundColor, data.selectColor, data.selectTextShadow);
               this._selectParentHelper.open(this, menulist, data.rect, data.isOpenedViaTouch);
               break;
             }
 
             case "Forms:HideDropDown": {
               if (this._selectParentHelper) {
@@ -1311,17 +1312,17 @@
               }
 
               let menulist = document.getElementById(this.getAttribute("selectmenulist"));
               menulist.menupopup.style.direction = data.direction;
 
               let zoom = Services.prefs.getBoolPref("browser.zoom.full") ||
                          this.isSyntheticDocument ? this._fullZoom : this._textZoom;
               this._selectParentHelper.populate(menulist, data.options, data.selectedIndex,
-                                                zoom,
+                                                zoom, data.uaBackgroundColor, data.uaColor,
                                                 data.uaSelectBackgroundColor, data.uaSelectColor,
                                                 data.selectBackgroundColor, data.selectColor, data.selectTextShadow);
               this._selectParentHelper.open(this, menulist, data.rect, data.isOpenedViaTouch);
               break;
             }
 
             case "FullZoomChange": {
               this._fullZoom = data.value;
--- a/toolkit/modules/LightweightThemeConsumer.jsm
+++ b/toolkit/modules/LightweightThemeConsumer.jsm
@@ -214,61 +214,57 @@ LightweightThemeConsumer.prototype = {
   _setExperiment(active, experiment, properties) {
     const root = this._doc.documentElement;
     if (this._lastExperimentData) {
       const { stylesheet, usedVariables } = this._lastExperimentData;
       if (stylesheet) {
         stylesheet.remove();
       }
       if (usedVariables) {
-        for (const [variable] of usedVariables) {
+        for (const variable of usedVariables) {
           _setProperty(root, false, variable);
         }
       }
     }
-
-    this._lastExperimentData = {};
-
-    if (!active || !experiment) {
-      return;
-    }
-
-    let usedVariables = [];
-    if (properties.colors) {
-      for (const property in properties.colors) {
-        const cssVariable = experiment.colors[property];
-        const value = _sanitizeCSSColor(root.ownerDocument, properties.colors[property]);
-        usedVariables.push([cssVariable, value]);
+    if (active && experiment) {
+      this._lastExperimentData = {};
+      if (experiment.stylesheet) {
+        /* Stylesheet URLs are validated using WebExtension schemas */
+        let stylesheetAttr = `href="${experiment.stylesheet}" type="text/css"`;
+        let stylesheet = this._doc.createProcessingInstruction("xml-stylesheet",
+          stylesheetAttr);
+        this._doc.insertBefore(stylesheet, root);
+        this._lastExperimentData.stylesheet = stylesheet;
       }
-    }
-
-    if (properties.images) {
-      for (const property in properties.images) {
-        const cssVariable = experiment.images[property];
-        usedVariables.push([cssVariable, `url(${properties.images[property]})`]);
-      }
-    }
-    if (properties.properties) {
-      for (const property in properties.properties) {
-        const cssVariable = experiment.properties[property];
-        usedVariables.push([cssVariable, properties.properties[property]]);
+      let usedVariables = [];
+      if (properties.colors) {
+        for (const property in properties.colors) {
+          const cssVariable = experiment.colors[property];
+          const value = _sanitizeCSSColor(root.ownerDocument, properties.colors[property]);
+          _setProperty(root, active, cssVariable, value);
+          usedVariables.push(cssVariable);
+        }
       }
-    }
-    for (const [variable, value] of usedVariables) {
-      _setProperty(root, true, variable, value);
-    }
-    this._lastExperimentData.usedVariables = usedVariables;
-
-    if (experiment.stylesheet) {
-      /* Stylesheet URLs are validated using WebExtension schemas */
-      let stylesheetAttr = `href="${experiment.stylesheet}" type="text/css"`;
-      let stylesheet = this._doc.createProcessingInstruction("xml-stylesheet",
-        stylesheetAttr);
-      this._doc.insertBefore(stylesheet, root);
-      this._lastExperimentData.stylesheet = stylesheet;
+      if (properties.images) {
+        for (const property in properties.images) {
+          const cssVariable = experiment.images[property];
+          _setProperty(root, active, cssVariable, `url(${properties.images[property]})`);
+          usedVariables.push(cssVariable);
+        }
+      }
+      if (properties.properties) {
+        for (const property in properties.properties) {
+          const cssVariable = experiment.properties[property];
+          _setProperty(root, active, cssVariable, properties.properties[property]);
+          usedVariables.push(cssVariable);
+        }
+      }
+      this._lastExperimentData.usedVariables = usedVariables;
+    } else {
+      this._lastExperimentData = null;
     }
   },
 };
 
 function _getContentProperties(doc, active, data) {
   if (!active) {
     return {};
   }
@@ -292,68 +288,52 @@ function _setProperty(elem, active, vari
   if (active && value) {
     elem.style.setProperty(variableName, value);
   } else {
     elem.style.removeProperty(variableName);
   }
 }
 
 function _setProperties(root, active, themeData) {
-  let properties = [];
-
   for (let map of [toolkitVariableMap, ThemeVariableMap]) {
     for (let [cssVarName, definition] of map) {
       const {
         lwtProperty,
         optionalElementID,
         processColor,
         isColor = true,
       } = definition;
       let elem = optionalElementID ? root.ownerDocument.getElementById(optionalElementID)
                                    : root;
+
       let val = themeData[lwtProperty];
       if (isColor) {
         val = _sanitizeCSSColor(root.ownerDocument, val);
         if (processColor) {
           val = processColor(_parseRGBA(val), elem);
         }
       }
-      properties.push([elem, cssVarName, val]);
+      _setProperty(elem, active, cssVarName, val);
     }
   }
-
-  // Set all the properties together, since _sanitizeCSSColor flushes.
-  for (const [elem, cssVarName, val] of properties) {
-    _setProperty(elem, active, cssVarName, val);
-  }
 }
 
 function _sanitizeCSSColor(doc, cssColor) {
   if (!cssColor) {
     return null;
   }
   const HTML_NS = "http://www.w3.org/1999/xhtml";
   // style.color normalizes color values and makes invalid ones black, so a
   // simple round trip gets us a sanitized color value.
-  // Use !important so that the theme's stylesheets cannot override us.
   let div = doc.createElementNS(HTML_NS, "div");
-  div.style.setProperty("color", "black", "important");
-  div.style.setProperty("display", "none", "important");
+  div.style.color = "black";
   let span = doc.createElementNS(HTML_NS, "span");
-  span.style.setProperty("color", cssColor, "important");
-
-  // CSS variables are not allowed and should compute to black.
-  if (span.style.color.includes("var(")) {
-    span.style.color = "";
-  }
-
+  span.style.color = cssColor;
   div.appendChild(span);
-  doc.documentElement.appendChild(div);
   cssColor = doc.defaultView.getComputedStyle(span).color;
-  div.remove();
   return cssColor;
 }
 
 function _parseRGBA(aColorString) {
   if (!aColorString) {
     return null;
   }
   var rgba = aColorString.replace(/(rgba?\()|(\)$)/g, "").split(",");
--- a/toolkit/modules/SelectParentHelper.jsm
+++ b/toolkit/modules/SelectParentHelper.jsm
@@ -43,23 +43,25 @@ var SelectParentHelper = {
    * The `customoptionstyling` attribute controls the application of
    * `-moz-appearance` on the elements and is disabled if the element is
    * defining its own background-color.
    *
    * @param {Element}        menulist
    * @param {Array<Element>} items
    * @param {Number}         selectedIndex
    * @param {Number}         zoom
+   * @param {String}         uaBackgroundColor
+   * @param {String}         uaColor
    * @param {String}         uaSelectBackgroundColor
    * @param {String}         uaSelectColor
    * @param {String}         selectBackgroundColor
    * @param {String}         selectColor
    * @param {String}         selectTextShadow
    */
-  populate(menulist, items, selectedIndex, zoom,
+  populate(menulist, items, selectedIndex, zoom, uaBackgroundColor, uaColor,
            uaSelectBackgroundColor, uaSelectColor, selectBackgroundColor,
            selectColor, selectTextShadow) {
     // Clear the current contents of the popup
     menulist.menupopup.textContent = "";
     let stylesheet = menulist.querySelector("#ContentSelectDropdownStylesheet");
     if (stylesheet) {
       stylesheet.remove();
     }
@@ -92,17 +94,17 @@ var SelectParentHelper = {
     }
 
     if (customStylingEnabled &&
         selectColor != uaSelectColor &&
         selectColor != usedSelectBackgroundColor) {
       ruleBody += `color: ${selectColor};`;
       usedSelectColor = selectColor;
     } else {
-      usedSelectColor = uaSelectColor;
+      usedSelectColor = uaColor;
     }
 
     if (customStylingEnabled &&
         selectTextShadow != "none") {
       ruleBody += `text-shadow: ${selectTextShadow};`;
       sheet.insertRule(`#ContentSelectDropdown > menupopup > [_moz-menuactive="true"] {
         text-shadow: none;
       }`, 0);
@@ -245,23 +247,26 @@ var SelectParentHelper = {
         return;
       }
 
       let scrollBox = currentMenulist.menupopup.scrollBox;
       let scrollTop = scrollBox.scrollTop;
 
       let options = msg.data.options;
       let selectedIndex = msg.data.selectedIndex;
+      let uaBackgroundColor = msg.data.uaBackgroundColor;
+      let uaColor = msg.data.uaColor;
       let uaSelectBackgroundColor = msg.data.uaSelectBackgroundColor;
       let uaSelectColor = msg.data.uaSelectColor;
       let selectBackgroundColor = msg.data.selectBackgroundColor;
       let selectColor = msg.data.selectColor;
       let selectTextShadow = msg.data.selectTextShadow;
       this.populate(currentMenulist, options, selectedIndex,
-                    currentZoom, uaSelectBackgroundColor, uaSelectColor,
+                    currentZoom, uaBackgroundColor, uaColor,
+                    uaSelectBackgroundColor, uaSelectColor,
                     selectBackgroundColor, selectColor, selectTextShadow);
 
       // Restore scroll position to what it was prior to the update.
       scrollBox.scrollTop = scrollTop;
     } else if (msg.name == "Forms:BlurDropDown-Ping") {
       currentBrowser.messageManager.sendAsyncMessage("Forms:BlurDropDown-Pong", {});
     }
   },