Bug 1310681 - start devtools UI work for css-color-4 draft
authorTom Tromey <tom@tromey.com>
Tue, 18 Oct 2016 14:08:02 -0600
changeset 426571 87f4c7053c2ca2b6f0a202ab5f73dcb34dbfa26b
parent 426570 f464803fca9e747419d4349df81c77f7c475c085
child 534217 0ed27c94669ee47a4bbb9e9da1c9bef7c53a823b
push id32748
push userbmo:ttromey@mozilla.com
push dateTue, 18 Oct 2016 20:09:14 +0000
bugs1310681
milestone52.0a1
Bug 1310681 - start devtools UI work for css-color-4 MozReview-Commit-ID: 7DyMJLrhEUd
devtools/client/shared/output-parser.js
devtools/server/actors/css-properties.js
devtools/shared/css/color.js
devtools/shared/fronts/css-properties.js
--- a/devtools/client/shared/output-parser.js
+++ b/devtools/client/shared/output-parser.js
@@ -33,22 +33,25 @@ const HTML_NS = "http://www.w3.org/1999/
  *
  * @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} supportsCssColor4 - A function that returns true
+ *                   if css-color-4 forms of rgb and hsl should be supported
  */
-function OutputParser(document, {supportsType, isValidOnClient}) {
+function OutputParser(document, {supportsType, isValidOnClient, supportsCssColor4}) {
   this.parsed = [];
   this.doc = document;
   this.supportsType = supportsType;
   this.isValidOnClient = isValidOnClient;
+  this._cssColor4 = supportsCssColor4();
   this.colorSwatches = new WeakMap();
   this.angleSwatches = new WeakMap();
   this._onColorSwatchMouseDown = this._onColorSwatchMouseDown.bind(this);
   this._onAngleSwatchMouseDown = this._onAngleSwatchMouseDown.bind(this);
 }
 
 exports.OutputParser = OutputParser;
 
@@ -180,43 +183,45 @@ 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 (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);
@@ -357,17 +362,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/server/actors/css-properties.js
+++ b/devtools/server/actors/css-properties.js
@@ -26,18 +26,20 @@ exports.CssPropertiesActor = ActorClassW
 
   destroy() {
     Actor.prototype.destroy.call(this);
   },
 
   getCSSDatabase() {
     const properties = generateCssProperties();
     const pseudoElements = DOMUtils.getCSSPseudoElementNames();
+    // Any css-color-4 as added in bug 1295456.
+    const cssColor4 = DOMUtils.isValidCSSColor("rgb(5 5 5)");
 
-    return { properties, pseudoElements };
+    return { properties, pseudoElements, cssColor4 };
   }
 });
 
 /**
  * Generate the CSS properties object. Every key is the property name, while
  * the values are objects that contain information about that property.
  *
  * @return {Object}
--- a/devtools/shared/css/color.js
+++ b/devtools/shared/css/color.js
@@ -22,17 +22,17 @@ const SPECIALVALUES = new Set([
   "unset"
 ]);
 
 /**
  * This module is used to convert between various color types.
  *
  * Usage:
  *   let {colorUtils} = require("devtools/shared/css/color");
- *   let color = new colorUtils.CssColor("red");
+ *   let color = new colorUtils.CssColor("red", false);
  *
  *   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,17 +53,18 @@ 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, cssColor4 = false) {
+  this._cssColor4 = cssColor4;
   this.newColor(colorValue);
 }
 
 module.exports.colorUtils = {
   CssColor: CssColor,
   rgbToHsl: rgbToHsl,
   setAlpha: setAlpha,
   classifyColor: classifyColor,
@@ -86,16 +87,18 @@ CssColor.COLORUNIT = {
 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 +134,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 +391,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) {
@@ -1105,13 +1108,15 @@ 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} oldColorFunctionSyntax use old color function syntax or the
+ *        css-color-4 syntax
  * @return {Boolean} True if the string is a CSS color name.
  */
-function isValidCSSColor(name) {
-  return colorToRGBA(name) !== null;
+function isValidCSSColor(name, oldColorFunctionSyntax = true) {
+  return colorToRGBA(name, oldColorFunctionSyntax) !== null;
 }
--- a/devtools/shared/fronts/css-properties.js
+++ b/devtools/shared/fronts/css-properties.js
@@ -56,21 +56,23 @@ const CssPropertiesFront = FrontClassWit
  *                 A database of CSS properties
  * @param {Object} inheritedList
  *                 The key is the property name, the value is whether or not
  *                 that property is inherited.
  */
 function CssProperties(db) {
   this.properties = db.properties;
   this.pseudoElements = db.pseudoElements;
+  this.cssColor4 = db.cssColor4;
 
   this.isKnown = this.isKnown.bind(this);
   this.isInherited = this.isInherited.bind(this);
   this.supportsType = this.supportsType.bind(this);
   this.isValidOnClient = this.isValidOnClient.bind(this);
+  this.supportsCssColor4 = this.supportsCssColor4.bind(this);
 
   // A weakly held dummy HTMLDivElement to test CSS properties on the client.
   this._dummyElements = new WeakMap();
 }
 
 CssProperties.prototype = {
   /**
    * Checks to see if the property is known by the browser. This function has
@@ -176,16 +178,24 @@ CssProperties.prototype = {
     if (this.isKnown(name)) {
       if (this.properties[name] && this.properties[name].subproperties) {
         return this.properties[name].subproperties;
       }
       return [name];
     }
     return [];
   },
+
+  /**
+   * Returns true if the server supports css-color-4 colors;
+   * specifically just what was added in bug 1295456.
+   */
+  supportsCssColor4() {
+    return this.cssColor4;
+  },
 };
 
 /**
  * Create a CssProperties object with a fully loaded CSS database. The
  * CssProperties interface can be queried synchronously, but the initialization
  * is potentially async and should be handled up-front when the tool is created.
  *
  * The front is returned only with this function so that it can be destroyed
@@ -287,16 +297,19 @@ function normalizeCssData(db) {
         db.properties[name].subproperties =
           CSS_PROPERTIES_DB.properties[name].subproperties;
       }
     }
   }
 
   reattachCssColorValues(db);
 
+  // This will be undefined in older versions of the database.
+  db.cssColor4 = !!db.cssColor4;
+
   return db;
 }
 
 /**
  * Color values are omitted to save on space. Add them back here.
  * @param {Object} The CSS database.
  */
 function reattachCssColorValues(db) {