Bug 1310681 - pass css-color-4 color function supporting info to devtool css OutputParser and SwatchColorPickerTooltip. r=tromey
authorJerryShih <hshih@mozilla.com>
Fri, 21 Oct 2016 14:59:07 -0400
changeset 326949 a6e4c1a7cc2b
parent 326948 9964687bc8fb
child 326950 b91e1c0f1960
push id35415
push userhshih@mozilla.com
push dateFri, 23 Dec 2016 01:28:44 +0000
treeherderautoland@b91e1c0f1960 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstromey
bugs1310681
milestone53.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1310681 - pass css-color-4 color function supporting info to devtool css OutputParser and SwatchColorPickerTooltip. r=tromey Pass css-color-4 supporting status from css-property db to OutputParser and SwatchColorPickerTooltip. MozReview-Commit-ID: N1ffWOlf9f
devtools/client/inspector/shared/tooltips-overlay.js
devtools/client/shared/output-parser.js
devtools/client/shared/widgets/tooltip/SwatchColorPickerTooltip.js
devtools/shared/css/color.js
--- a/devtools/client/inspector/shared/tooltips-overlay.js
+++ b/devtools/client/inspector/shared/tooltips-overlay.js
@@ -83,17 +83,19 @@ TooltipsOverlay.prototype = {
     this.previewTooltip.startTogglingOnHover(this.view.element,
       this._onPreviewTooltipTargetHover.bind(this));
 
     // MDN CSS help tooltip
     this.cssDocs = new CssDocsTooltip(toolbox.doc);
 
     if (this.isRuleView) {
       // Color picker tooltip
-      this.colorPicker = new SwatchColorPickerTooltip(toolbox.doc, this.view.inspector);
+      this.colorPicker = new SwatchColorPickerTooltip(toolbox.doc,
+                                                      this.view.inspector,
+                                                      this._cssProperties);
       // Cubic bezier tooltip
       this.cubicBezier = new SwatchCubicBezierTooltip(toolbox.doc);
       // Filter editor tooltip
       this.filterEditor = new SwatchFilterTooltip(toolbox.doc,
         this._cssProperties.getValidityChecker(this.view.inspector.panelDoc));
     }
 
     this._isStarted = true;
--- a/devtools/client/shared/output-parser.js
+++ b/devtools/client/shared/output-parser.js
@@ -35,26 +35,31 @@ const CSS_GRID_ENABLED_PREF = "layout.cs
  *
  * @param {Document} document Used to create DOM nodes.
  * @param {Function} supportsTypes - A function that returns a boolean when asked if a css
  *                   property name supports a given css type.
  *                   The function is executed like supportsType("color", CSS_TYPES.COLOR)
  *                   where CSS_TYPES is defined in devtools/shared/css/properties-db.js
  * @param {Function} isValidOnClient - A function that checks if a css property
  *                   name/value combo is valid.
+ * @param {Function} supportsCssColor4ColorFunction - A function for checking
+ *                   the supporting of css-color-4 color function.
  */
-function OutputParser(document, {supportsType, isValidOnClient}) {
+function OutputParser(document,
+                      {supportsType, isValidOnClient, supportsCssColor4ColorFunction}) {
   this.parsed = [];
   this.doc = document;
   this.supportsType = supportsType;
   this.isValidOnClient = isValidOnClient;
   this.colorSwatches = new WeakMap();
   this.angleSwatches = new WeakMap();
   this._onColorSwatchMouseDown = this._onColorSwatchMouseDown.bind(this);
   this._onAngleSwatchMouseDown = this._onAngleSwatchMouseDown.bind(this);
+
+  this.cssColor4 = supportsCssColor4ColorFunction();
 }
 
 OutputParser.prototype = {
   /**
    * Parse a CSS property value given a property name.
    *
    * @param  {String} name
    *         CSS Property Name
@@ -181,47 +186,49 @@ OutputParser.prototype = {
             }
             ++parenDepth;
           } else {
             let functionText = this._collectFunctionText(token, text,
                                                          tokenStream);
 
             if (options.expectCubicBezier && token.text === "cubic-bezier") {
               this._appendCubicBezier(functionText, options);
-            } else if (colorOK() && colorUtils.isValidCSSColor(functionText)) {
+            } else if (colorOK() &&
+                       colorUtils.isValidCSSColor(functionText, this.cssColor4)) {
               this._appendColor(functionText, options);
             } else {
               this._appendTextNode(functionText);
             }
           }
           break;
         }
 
         case "ident":
           if (options.expectCubicBezier &&
               BEZIER_KEYWORDS.indexOf(token.text) >= 0) {
             this._appendCubicBezier(token.text, options);
           } else if (Services.prefs.getBoolPref(CSS_GRID_ENABLED_PREF) &&
                      options.expectDisplay && token.text === "grid" &&
                      text === token.text) {
             this._appendGrid(token.text, options);
-          } else if (colorOK() && colorUtils.isValidCSSColor(token.text)) {
+          } else if (colorOK() &&
+                     colorUtils.isValidCSSColor(token.text, this.cssColor4)) {
             this._appendColor(token.text, options);
           } else if (angleOK(token.text)) {
             this._appendAngle(token.text, options);
           } else {
             this._appendTextNode(text.substring(token.startOffset,
                                                 token.endOffset));
           }
           break;
 
         case "id":
         case "hash": {
           let original = text.substring(token.startOffset, token.endOffset);
-          if (colorOK() && colorUtils.isValidCSSColor(original)) {
+          if (colorOK() && colorUtils.isValidCSSColor(original, this.cssColor4)) {
             this._appendColor(original, options);
           } else {
             this._appendTextNode(original);
           }
           break;
         }
         case "dimension":
           let value = text.substring(token.startOffset, token.endOffset);
@@ -387,17 +394,17 @@ OutputParser.prototype = {
    *
    * @param  {String} color
    *         Color to append
    * @param  {Object} [options]
    *         Options object. For valid options and default values see
    *         _mergeOptions().
    */
   _appendColor: function (color, options = {}) {
-    let colorObj = new colorUtils.CssColor(color);
+    let colorObj = new colorUtils.CssColor(color, this.cssColor4);
 
     if (this._isValidColor(colorObj)) {
       let container = this._createNode("span", {
         "data-color": color
       });
 
       if (options.colorSwatchClass) {
         let swatch = this._createNode("span", {
--- a/devtools/client/shared/widgets/tooltip/SwatchColorPickerTooltip.js
+++ b/devtools/client/shared/widgets/tooltip/SwatchColorPickerTooltip.js
@@ -23,28 +23,33 @@ const XHTML_NS = "http://www.w3.org/1999
  * color picker.
  *
  * @param {Document} document
  *        The document to attach the SwatchColorPickerTooltip. This is either the toolbox
  *        document if the tooltip is a popup tooltip or the panel's document if it is an
  *        inline editor.
  * @param {InspectorPanel} inspector
  *        The inspector panel, needed for the eyedropper.
+ * @param {Function} supportsCssColor4ColorFunction
+ *        A function for checking the supporting of css-color-4 color function.
  */
-function SwatchColorPickerTooltip(document, inspector) {
+function SwatchColorPickerTooltip(document,
+                                  inspector,
+                                  {supportsCssColor4ColorFunction}) {
   let stylesheet = "chrome://devtools/content/shared/widgets/spectrum.css";
   SwatchBasedEditorTooltip.call(this, document, stylesheet);
 
   this.inspector = inspector;
 
   // Creating a spectrum instance. this.spectrum will always be a promise that
   // resolves to the spectrum instance
   this.spectrum = this.setColorPickerContent([0, 0, 0, 1]);
   this._onSpectrumColorChange = this._onSpectrumColorChange.bind(this);
   this._openEyeDropper = this._openEyeDropper.bind(this);
+  this.cssColor4 = supportsCssColor4ColorFunction();
 }
 
 SwatchColorPickerTooltip.prototype = Heritage.extend(SwatchBasedEditorTooltip.prototype, {
   /**
    * Fill the tooltip with a new instance of the spectrum color picker widget
    * initialized with the given color, and return the instance of spectrum
    */
   setColorPickerContent: function (color) {
@@ -152,24 +157,24 @@ SwatchColorPickerTooltip.prototype = Her
   },
 
   _onEyeDropperDone: function () {
     this.eyedropperOpen = false;
     this.activeSwatch = null;
   },
 
   _colorToRgba: function (color) {
-    color = new colorUtils.CssColor(color);
+    color = new colorUtils.CssColor(color, this.cssColor4);
     let rgba = color._getRGBATuple();
     return [rgba.r, rgba.g, rgba.b, rgba.a];
   },
 
   _toDefaultType: function (color) {
     let colorObj = new colorUtils.CssColor(color);
-    colorObj.setAuthoredUnitFromColor(this._originalColor);
+    colorObj.setAuthoredUnitFromColor(this._originalColor, this.cssColor4);
     return colorObj.toString();
   },
 
   destroy: function () {
     SwatchBasedEditorTooltip.prototype.destroy.call(this);
     this.inspector = null;
     this.currentSwatchColor = null;
     this.spectrum.off("changed", this._onSpectrumColorChange);
--- a/devtools/shared/css/color.js
+++ b/devtools/shared/css/color.js
@@ -23,16 +23,20 @@ const SPECIALVALUES = new Set([
 ]);
 
 /**
  * This module is used to convert between various color types.
  *
  * Usage:
  *   let {colorUtils} = require("devtools/shared/css/color");
  *   let color = new colorUtils.CssColor("red");
+ *   // In order to support css-color-4 color function, pass true to the
+ *   // second argument.
+ *   // e.g.
+ *   //   let color = new colorUtils.CssColor("red", true);
  *
  *   color.authored === "red"
  *   color.hasAlpha === false
  *   color.valid === true
  *   color.transparent === false // transparent has a special status.
  *   color.name === "red"        // returns hex when no name available.
  *   color.hex === "#f00"        // returns shortHex when available else returns
  *                                  longHex. If alpha channel is present then we
@@ -53,18 +57,19 @@ const SPECIALVALUES = new Set([
  *   color.toString() === "#f00"; // Outputs the color type determined in the
  *                                   COLOR_UNIT_PREF constant (above).
  *   // Color objects can be reused
  *   color.newColor("green") === "#0f0"; // true
  *
  *   Valid values for COLOR_UNIT_PREF are contained in CssColor.COLORUNIT.
  */
 
-function CssColor(colorValue) {
+function CssColor(colorValue, supportsCssColor4ColorFunction = false) {
   this.newColor(colorValue);
+  this.cssColor4 = supportsCssColor4ColorFunction;
 }
 
 module.exports.colorUtils = {
   CssColor: CssColor,
   rgbToHsl: rgbToHsl,
   setAlpha: setAlpha,
   classifyColor: classifyColor,
   rgbToColorName: rgbToColorName,
@@ -87,16 +92,19 @@ CssColor.prototype = {
   _colorUnit: null,
   _colorUnitUppercase: false,
 
   // The value as-authored.
   authored: null,
   // A lower-cased copy of |authored|.
   lowerCased: null,
 
+  // Whether the value should be parsed using css-color-4 rules.
+  cssColor4: false,
+
   _setColorUnitUppercase: function (color) {
     // Specifically exclude the case where the color is
     // case-insensitive.  This makes it so that "#000" isn't
     // considered "upper case" for the purposes of color cycling.
     this._colorUnitUppercase = (color === color.toUpperCase()) &&
       (color !== color.toLowerCase());
   },
 
@@ -131,17 +139,17 @@ CssColor.prototype = {
   get hasAlpha() {
     if (!this.valid) {
       return false;
     }
     return this._getRGBATuple().a !== 1;
   },
 
   get valid() {
-    return isValidCSSColor(this.authored);
+    return isValidCSSColor(this.authored, this.cssColor4);
   },
 
   /**
    * Return true for all transparent values e.g. rgba(0, 0, 0, 0).
    */
   get transparent() {
     try {
       let tuple = this._getRGBATuple();
@@ -388,17 +396,17 @@ CssColor.prototype = {
     return color;
   },
 
   /**
    * Returns a RGBA 4-Tuple representation of a color or transparent as
    * appropriate.
    */
   _getRGBATuple: function () {
-    let tuple = colorToRGBA(this.authored);
+    let tuple = colorToRGBA(this.authored, this.cssColor4);
 
     tuple.a = parseFloat(tuple.a.toFixed(1));
 
     return tuple;
   },
 
   _hsl: function (maybeAlpha) {
     if (this.lowerCased.startsWith("hsl(") && maybeAlpha === undefined) {
@@ -476,21 +484,23 @@ function roundTo(number, digits) {
  * Takes a color value of any type (hex, hsl, hsla, rgb, rgba)
  * and an alpha value to generate an rgba string with the correct
  * alpha value.
  *
  * @param  {String} colorValue
  *         Color in the form of hex, hsl, hsla, rgb, rgba.
  * @param  {Number} alpha
  *         Alpha value for the color, between 0 and 1.
+ * @param  {Boolean} useCssColor4ColorFunction
+ *         use css-color-4 color function or not.
  * @return {String}
  *         Converted color with `alpha` value in rgba form.
  */
-function setAlpha(colorValue, alpha) {
-  let color = new CssColor(colorValue);
+function setAlpha(colorValue, alpha, useCssColor4ColorFunction = false) {
+  let color = new CssColor(colorValue, useCssColor4ColorFunction);
 
   // Throw if the color supplied is not valid.
   if (!color.valid) {
     throw new Error("Invalid color.");
   }
 
   // If an invalid alpha valid, just set to 1.
   if (!(alpha >= 0 && alpha <= 1)) {
@@ -1044,22 +1054,21 @@ function parseOldStyleRgb(lexer, hasAlph
   return rgba;
 }
 
 /**
  * Convert a string representing a color to an object holding the
  * color's components.  Any valid CSS color form can be passed in.
  *
  * @param {String} name the color
- * @param {Boolean} oldColorFunctionSyntax use old color function syntax or the
- *        css-color-4 syntax
+ * @param {Boolean} useCssColor4ColorFunction use css-color-4 color function or not.
  * @return {Object} an object of the form {r, g, b, a}; or null if the
  *         name was not a valid color
  */
-function colorToRGBA(name, oldColorFunctionSyntax = true) {
+function colorToRGBA(name, useCssColor4ColorFunction = false) {
   name = name.trim().toLowerCase();
 
   if (name in cssColors) {
     let result = cssColors[name];
     return {r: result[0], g: result[1], b: result[2], a: result[3]};
   } else if (name === "transparent") {
     return {r: 0, g: 0, b: 0, a: 0};
   } else if (name === "currentcolor") {
@@ -1084,17 +1093,17 @@ function colorToRGBA(name, oldColorFunct
   if (!func || func.tokenType !== "function" ||
       !expectedFunctions.includes(func.text)) {
     return null;
   }
 
   let hsl = func.text === "hsl" || func.text === "hsla";
 
   let vals;
-  if (oldColorFunctionSyntax) {
+  if (!useCssColor4ColorFunction) {
     let hasAlpha = (func.text === "rgba" || func.text === "hsla");
     vals = hsl ? parseOldStyleHsl(lexer, hasAlpha) : parseOldStyleRgb(lexer, hasAlpha);
   } else {
     vals = hsl ? parseHsl(lexer) : parseRgb(lexer);
   }
 
   if (!vals) {
     return null;
@@ -1105,13 +1114,14 @@ function colorToRGBA(name, oldColorFunct
 
   return {r: vals[0], g: vals[1], b: vals[2], a: vals[3]};
 }
 
 /**
  * Check whether a string names a valid CSS color.
  *
  * @param {String} name The string to check
+ * @param {Boolean} useCssColor4ColorFunction use css-color-4 color function or not.
  * @return {Boolean} True if the string is a CSS color name.
  */
-function isValidCSSColor(name) {
-  return colorToRGBA(name) !== null;
+function isValidCSSColor(name, useCssColor4ColorFunction = false) {
+  return colorToRGBA(name, useCssColor4ColorFunction) !== null;
 }