Bug 1338283 - Use the actual menupopup system colors to determine if the popup should be showing custom styles. draft
authorJared Wein <jwein@mozilla.com>
Wed, 15 Feb 2017 18:04:55 -0500
changeset 484888 263534563759b872eb40d09dc4f8dde8ffa4e454
parent 484733 f10738ad12fe44fa776e304175f3f9c59ec9ce8c
child 545887 b62b81a55099ed04493016b209e7bdd3140fa1df
push id45588
push userbmo:jaws@mozilla.com
push dateWed, 15 Feb 2017 23:05:30 +0000
bugs1338283
milestone54.0a1
Bug 1338283 - Use the actual menupopup system colors to determine if the popup should be showing custom styles. MozReview-Commit-ID: 7AAZNCMVZky
toolkit/content/widgets/browser.xml
toolkit/content/widgets/remote-browser.xml
toolkit/modules/SelectContentHelper.jsm
toolkit/modules/SelectParentHelper.jsm
--- a/toolkit/content/widgets/browser.xml
+++ b/toolkit/content/widgets/browser.xml
@@ -1076,18 +1076,16 @@
               if (!this._selectParentHelper) {
                 this._selectParentHelper =
                   Cu.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);
               this._selectParentHelper.open(this, menulist, data.rect, data.isOpenedViaTouch);
               break;
             }
 
             case "Forms:HideDropDown": {
               if (this._selectParentHelper) {
                 let menulist = document.getElementById(this.getAttribute("selectmenulist"));
--- a/toolkit/content/widgets/remote-browser.xml
+++ b/toolkit/content/widgets/remote-browser.xml
@@ -467,19 +467,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, data.uaBackgroundColor, data.uaColor,
-                                                data.uaSelectBackgroundColor, data.uaSelectColor,
-                                                data.selectBackgroundColor, data.selectColor);
+                                                zoom, data.selectBackgroundColor, data.selectColor);
               this._selectParentHelper.open(this, menulist, data.rect, data.isOpenedViaTouch);
               break;
             }
 
             case "FullZoomChange": {
               this._fullZoom = data.value;
               let event = document.createEvent("Events");
               event.initEvent("FullZoomChange", true, false);
--- a/toolkit/modules/SelectContentHelper.jsm
+++ b/toolkit/modules/SelectContentHelper.jsm
@@ -33,20 +33,16 @@ this.EXPORTED_SYMBOLS = [
 this.SelectContentHelper = function(aElement, aOptions, aGlobal) {
   this.element = aElement;
   this.initialSelection = aElement[aElement.selectedIndex] || null;
   this.global = aGlobal;
   this.closedWithEnter = false;
   this.isOpenedViaTouch = aOptions.isOpenedViaTouch;
   this._selectBackgroundColor = null;
   this._selectColor = null;
-  this._uaBackgroundColor = null;
-  this._uaColor = null;
-  this._uaSelectBackgroundColor = null;
-  this._uaSelectColor = null;
   this.init();
   this.showDropDown();
   this._updateTimer = new DeferredTask(this._update.bind(this), 0);
 }
 
 Object.defineProperty(SelectContentHelper, "open", {
   get() {
     return gOpen;
@@ -100,20 +96,16 @@ this.SelectContentHelper.prototype = {
     this.global.sendAsyncMessage("Forms:ShowDropDown", {
       direction: computedStyles.direction,
       isOpenedViaTouch: this.isOpenedViaTouch,
       options: this._buildOptionList(),
       rect,
       selectedIndex: this.element.selectedIndex,
       selectBackgroundColor: this._selectBackgroundColor,
       selectColor: this._selectColor,
-      uaBackgroundColor: this.uaBackgroundColor,
-      uaColor: this.uaColor,
-      uaSelectBackgroundColor: this.uaSelectBackgroundColor,
-      uaSelectColor: this.uaSelectColor
     });
     gOpen = true;
   },
 
   _getBoundingContentRect() {
     return BrowserUtils.getElementBoundingScreenRect(this.element);
   },
 
@@ -124,69 +116,19 @@ this.SelectContentHelper.prototype = {
   _update() {
     // The <select> was updated while the dropdown was open.
     // Let's send up a new list of options.
     this.global.sendAsyncMessage("Forms:UpdateDropDown", {
       options: this._buildOptionList(),
       selectedIndex: this.element.selectedIndex,
       selectBackgroundColor: this._selectBackgroundColor,
       selectColor: this._selectColor,
-      uaBackgroundColor: this.uaBackgroundColor,
-      uaColor: this.uaColor,
-      uaSelectBackgroundColor: this.uaSelectBackgroundColor,
-      uaSelectColor: this.uaSelectColor
     });
   },
 
-  // 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.createElement("option");
-    dummyOption.style.color = "-moz-comboboxtext";
-    dummyOption.style.backgroundColor = "-moz-combobox";
-    let optionCS = this.element.ownerGlobal.getComputedStyle(dummyOption);
-    this._uaBackgroundColor = optionCS.backgroundColor;
-    this._uaColor = optionCS.color;
-    let dummySelect = this.element.ownerDocument.createElement("select");
-    dummySelect.style.color = "-moz-fieldtext";
-    dummySelect.style.backgroundColor = "-moz-field";
-    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/modules/SelectParentHelper.jsm
+++ b/toolkit/modules/SelectParentHelper.jsm
@@ -18,20 +18,66 @@ const MAX_ROWS = 20;
 // Minimum elements required to show select search
 const SEARCH_MINIMUM_ELEMENTS = 40;
 
 var currentBrowser = null;
 var currentMenulist = null;
 var currentZoom = 1;
 var closedWithEnter = false;
 var selectRect;
+var uaColors = {
+  "menupopup": {
+    get backgroundColor() {
+      let value = AppConstants.platform == "win" ? "-moz-field" : "menu";
+      return calculateUAColors("menupopup", "backgroundColor", value);
+    },
+    get color() {
+      return calculateUAColors("menupopup", "color", "menutext");
+    }
+  },
+  "menucaption": {
+    get backgroundColor() {
+      let value = AppConstants.platform == "win" ? "buttonface" : "-moz-combobox";
+      return calculateUAColors("menucaption", "backgroundColor", value);
+    },
+    get color() {
+      return calculateUAColors("menucaption", "color", "-moz-fieldtext");
+    }
+  },
+  "menuitem": {
+    get backgroundColor() {
+      return calculateUAColors("menuitem", "backgroundColor", "-moz-combobox");
+    },
+    get color() {
+      return calculateUAColors("menuitem", "color", "-moz-comboboxtext");
+    }
+  }
+};
+
+// Determine user agent background-color and color.
+// This is used to skip applying the custom color if it matches
+// the user agent values.
+function calculateUAColors(tagName, property, value) {
+  if (!currentMenulist) {
+    return null;
+  }
+  let document = currentMenulist.ownerDocument;
+  let window = currentMenulist.ownerGlobal;
+  let element = document.createElement(tagName);
+  element.style[property] = value;
+  let cs = window.getComputedStyle(element);
+  delete uaColors[tagName][property];
+  return uaColors[tagName][property] = cs[property];
+}
 
 this.SelectParentHelper = {
-  populate(menulist, items, selectedIndex, zoom, uaBackgroundColor, uaColor,
-           uaSelectBackgroundColor, uaSelectColor, selectBackgroundColor, selectColor) {
+  populate(menulist, items, selectedIndex, zoom, selectBackgroundColor, selectColor) {
+    currentZoom = zoom;
+    currentMenulist = menulist;
+
     // Clear the current contents of the popup
     menulist.menupopup.textContent = "";
     let stylesheet = menulist.querySelector("#ContentSelectDropdownScopedStylesheet");
     if (stylesheet) {
       stylesheet.remove();
     }
 
     let doc = menulist.ownerDocument;
@@ -39,42 +85,39 @@ this.SelectParentHelper = {
     stylesheet.setAttribute("id", "ContentSelectDropdownScopedStylesheet");
     stylesheet.scoped = true;
     stylesheet.hidden = true;
     stylesheet = menulist.appendChild(stylesheet);
 
     let sheet = stylesheet.sheet;
     let ruleBody = "";
 
-    if (selectBackgroundColor != uaSelectBackgroundColor &&
+    if (selectBackgroundColor != uaColors.menupopup.backgroundColor &&
         selectBackgroundColor != "transparent" &&
         selectBackgroundColor != selectColor) {
       ruleBody = `background-color: ${selectBackgroundColor};`;
     }
 
-    if (selectColor != uaSelectColor &&
+    if (selectColor != uaColors.menupopup.color &&
         selectColor != selectBackgroundColor &&
         (selectBackgroundColor != "transparent" ||
-         selectColor != uaSelectBackgroundColor)) {
+         selectColor != uaColors.menupopup.backgroundColor)) {
       ruleBody += `color: ${selectColor};`;
     }
 
     if (ruleBody) {
       sheet.insertRule(`menupopup {
         ${ruleBody}
       }`, 0);
       menulist.menupopup.setAttribute("customoptionstyling", "true");
     } else {
       menulist.menupopup.removeAttribute("customoptionstyling");
     }
 
-    currentZoom = zoom;
-    currentMenulist = menulist;
-    populateChildren(menulist, items, selectedIndex, zoom,
-                     uaBackgroundColor, uaColor, sheet);
+    populateChildren(menulist, items, selectedIndex, zoom, sheet);
   },
 
   open(browser, menulist, rect, isOpenedViaTouch) {
     menulist.hidden = false;
     currentBrowser = browser;
     closedWithEnter = false;
     selectRect = rect;
     this._registerListeners(browser, menulist.menupopup);
@@ -173,23 +216,20 @@ this.SelectParentHelper = {
       // Sanity check - we'd better know what the currently
       // opened menulist is, and what browser it belongs to...
       if (!currentMenulist || !currentBrowser) {
         return;
       }
 
       let options = msg.data.options;
       let selectedIndex = msg.data.selectedIndex;
-      let uaBackgroundColor = msg.data.uaBackgroundColor;
-      let uaColor = msg.data.uaColor;
       let selectBackgroundColor = msg.data.selectBackgroundColor;
       let selectColor = msg.data.selectColor;
       this.populate(currentMenulist, options, selectedIndex,
-                    currentZoom, uaBackgroundColor, uaColor,
-                    selectBackgroundColor, selectColor);
+                    currentZoom, selectBackgroundColor, selectColor);
     }
   },
 
   _registerListeners(browser, popup) {
     popup.addEventListener("command", this);
     popup.addEventListener("popuphidden", this);
     popup.addEventListener("mouseover", this);
     popup.addEventListener("mouseout", this);
@@ -207,18 +247,17 @@ this.SelectParentHelper = {
     browser.ownerGlobal.removeEventListener("mouseup", this, true);
     browser.ownerGlobal.removeEventListener("keydown", this, true);
     browser.ownerGlobal.removeEventListener("fullscreen", this, true);
     browser.messageManager.removeMessageListener("Forms:UpdateDropDown", this);
   },
 
 };
 
-function populateChildren(menulist, options, selectedIndex, zoom,
-                          uaBackgroundColor, uaColor, sheet,
+function populateChildren(menulist, options, selectedIndex, zoom, sheet,
                           parentElement = null, isGroupDisabled = false,
                           adjustedTextSize = -1, addSearch = true, nthChildIndex = 1) {
   let element = menulist.menupopup;
   let win = element.ownerGlobal;
 
   // -1 just means we haven't calculated it yet. When we recurse through this function
   // we will pass in adjustedTextSize to save on recalculations.
   if (adjustedTextSize == -1) {
@@ -240,22 +279,22 @@ function populateChildren(menulist, opti
     // Keep track of which options are hidden by page content, so we can avoid showing
     // them on search input
     item.hiddenByContent = item.hidden;
     item.setAttribute("tooltiptext", option.tooltip);
 
     let ruleBody = "";
     if (option.backgroundColor &&
         option.backgroundColor != "transparent" &&
-        option.backgroundColor != uaBackgroundColor) {
+        option.backgroundColor != uaColors.menuitem.backgroundColor) {
       ruleBody = `background-color: ${option.backgroundColor};`;
     }
 
     if (option.color &&
-        option.color != uaColor) {
+        option.color != uaColors.menuitem.color) {
       ruleBody += `color: ${option.color};`;
     }
 
     if (ruleBody) {
       sheet.insertRule(`${item.localName}:nth-child(${nthChildIndex}):not([_moz-menuactive="true"]) {
         ${ruleBody}
       }`, 0);
 
@@ -271,18 +310,17 @@ function populateChildren(menulist, opti
     let isDisabled = isGroupDisabled || option.disabled;
     if (isDisabled) {
       item.setAttribute("disabled", "true");
     }
 
     if (isOptGroup) {
       nthChildIndex =
         populateChildren(menulist, option.children, selectedIndex, zoom,
-                         uaBackgroundColor, uaColor, sheet,
-                         item, isDisabled, adjustedTextSize, false);
+                         sheet, item, isDisabled, adjustedTextSize, false);
     } else {
       if (option.index == selectedIndex) {
         // We expect the parent element of the popup to be a <xul:menulist> that
         // has the popuponly attribute set to "true". This is necessary in order
         // for a <xul:menupopup> to act like a proper <html:select> dropdown, as
         // the <xul:menulist> does things like remember state and set the
         // _moz-menuactive attribute on the selected <xul:menuitem>.
         menulist.selectedItem = item;