blob: 701ee982766c08426db880dddaf0dc9665cc826a [file] [log] [blame]
/*
* Copyright (C) 2009 Apple Inc. All rights reserved.
* Copyright (C) 2009 Joseph Pecoraro
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @param {Array.<number>} rgba
* @param {string=} format
* @param {string=} originalText
* @constructor
*/
WebInspector.Color = function(rgba, format, originalText)
{
this._rgba = rgba;
this._originalText = originalText || null;
this._format = format || null;
if (typeof this._rgba[3] === "undefined")
this._rgba[3] = 1;
for (var i = 0; i < 4; ++i) {
if (this._rgba[i] < 0)
this._rgba[i] = 0;
if (this._rgba[i] > 1)
this._rgba[i] = 1;
}
}
/**
* @param {string} text
* @return {?WebInspector.Color}
*/
WebInspector.Color.parse = function(text)
{
// Simple - #hex, rgb(), nickname, hsl()
var value = text.toLowerCase().replace(/\s+/g, "");
var simple = /^(?:#([0-9a-f]{3,6})|rgb\(([^)]+)\)|(\w+)|hsl\(([^)]+)\))$/i;
var match = value.match(simple);
if (match) {
if (match[1]) { // hex
var hex = match[1].toUpperCase();
var format;
if (hex.length === 3) {
format = WebInspector.Color.Format.ShortHEX;
hex = hex.charAt(0) + hex.charAt(0) + hex.charAt(1) + hex.charAt(1) + hex.charAt(2) + hex.charAt(2);
} else
format = WebInspector.Color.Format.HEX;
var r = parseInt(hex.substring(0,2), 16);
var g = parseInt(hex.substring(2,4), 16);
var b = parseInt(hex.substring(4,6), 16);
return new WebInspector.Color([r / 255, g / 255, b / 255, 1], format, text);
}
if (match[2]) { // rgb
var rgbString = match[2].split(/\s*,\s*/);
var rgba = [ WebInspector.Color._parseRgbNumeric(rgbString[0]),
WebInspector.Color._parseRgbNumeric(rgbString[1]),
WebInspector.Color._parseRgbNumeric(rgbString[2]), 1 ];
return new WebInspector.Color(rgba, WebInspector.Color.Format.RGB, text);
}
if (match[3]) { // nickname
var nickname = match[3].toLowerCase();
if (nickname in WebInspector.Color.Nicknames) {
var rgba = WebInspector.Color.Nicknames[nickname];
var color = WebInspector.Color.fromRGBA(rgba);
color._format = WebInspector.Color.Format.Nickname;
color._originalText = nickname;
return color;
}
return null;
}
if (match[4]) { // hsl
var hslString = match[4].replace(/%/g, "").split(/\s*,\s*/);
var hsla = [ WebInspector.Color._parseHueNumeric(hslString[0]),
WebInspector.Color._parseSatLightNumeric(hslString[1]),
WebInspector.Color._parseSatLightNumeric(hslString[2]), 1 ];
var rgba = WebInspector.Color._hsl2rgb(hsla);
return new WebInspector.Color(rgba, WebInspector.Color.Format.HSL, text);
}
return null;
}
// Advanced - rgba(), hsla()
var advanced = /^(?:rgba\(([^)]+)\)|hsla\(([^)]+)\))$/;
match = value.match(advanced);
if (match) {
if (match[1]) { // rgba
var rgbaString = match[1].split(/\s*,\s*/);
var rgba = [ WebInspector.Color._parseRgbNumeric(rgbaString[0]),
WebInspector.Color._parseRgbNumeric(rgbaString[1]),
WebInspector.Color._parseRgbNumeric(rgbaString[2]),
WebInspector.Color._parseAlphaNumeric(rgbaString[3]) ];
return new WebInspector.Color(rgba, WebInspector.Color.Format.RGBA, text);
}
if (match[2]) { // hsla
var hslaString = match[2].replace(/%/g, "").split(/\s*,\s*/);
var hsla = [ WebInspector.Color._parseHueNumeric(hslaString[0]),
WebInspector.Color._parseSatLightNumeric(hslaString[1]),
WebInspector.Color._parseSatLightNumeric(hslaString[2]),
WebInspector.Color._parseAlphaNumeric(hslaString[3]) ];
var rgba = WebInspector.Color._hsl2rgb(hsla);
return new WebInspector.Color(rgba, WebInspector.Color.Format.HSLA, text);
}
}
return null;
}
/**
* @param {Array.<number>} rgba
* @return {WebInspector.Color}
*/
WebInspector.Color.fromRGBA = function(rgba)
{
return new WebInspector.Color([rgba[0] / 255, rgba[1] / 255, rgba[2] / 255, rgba[3]]);
}
/**
* @param {Array.<number>} hsva
* @return {WebInspector.Color}
*/
WebInspector.Color.fromHSVA = function(hsva)
{
var h = hsva[0];
var s = hsva[1];
var v = hsva[2];
var t = (2 - s) * v;
if (v === 0 || s === 0)
s = 0;
else
s *= v / (t < 1 ? t : 2 - t);
var hsla = [h, s, t / 2, hsva[3]];
return new WebInspector.Color(WebInspector.Color._hsl2rgb(hsla), WebInspector.Color.Format.HSLA);
}
WebInspector.Color.prototype = {
/**
* @return {?string}
*/
format: function()
{
return this._format;
},
/**
* @return {Array.<number>} HSLA with components within [0..1]
*/
hsla: function()
{
if (this._hsla)
return this._hsla;
var r = this._rgba[0];
var g = this._rgba[1];
var b = this._rgba[2];
var max = Math.max(r, g, b);
var min = Math.min(r, g, b);
var diff = max - min;
var add = max + min;
if (min === max)
var h = 0;
else if (r === max)
var h = ((1/6 * (g - b) / diff) + 1) % 1;
else if (g === max)
var h = (1/6 * (b - r) / diff) + 1/3;
else
var h = (1/6 * (r - g) / diff) + 2/3;
var l = 0.5 * add;
if (l === 0)
var s = 0;
else if (l === 1)
var s = 1;
else if (l <= 0.5)
var s = diff / add;
else
var s = diff / (2 - add);
this._hsla = [h, s, l, this._rgba[3]];
return this._hsla;
},
/**
* @return {Array.<number>} HSVA with components within [0..1]
*/
hsva: function()
{
var hsla = this.hsla();
var h = hsla[0];
var s = hsla[1];
var l = hsla[2];
s *= l < 0.5 ? l : 1 - l;
return [h, s !== 0 ? 2 * s / (l + s) : 0, (l + s), hsla[3]];
},
/**
* @return {boolean}
*/
hasAlpha: function()
{
return this._rgba[3] !== 1;
},
/**
* @return {boolean}
*/
canBeShortHex: function()
{
if (this.hasAlpha())
return false;
for (var i = 0; i < 3; ++i) {
var c = Math.round(this._rgba[i] * 255);
if (c % 17)
return false;
}
return true;
},
/**
* @return {?string}
*/
toString: function(format)
{
if (!format)
format = this._format;
/**
* @param {number} value
* @return {number}
*/
function toRgbValue(value)
{
return Math.round(value * 255);
}
/**
* @param {number} value
* @return {string}
*/
function toHexValue(value)
{
var hex = Math.round(value * 255).toString(16);
return hex.length === 1 ? "0" + hex : hex;
}
/**
* @param {number} value
* @return {string}
*/
function toShortHexValue(value)
{
return (Math.round(value * 255) / 17).toString(16);
}
switch (format) {
case WebInspector.Color.Format.Original:
return this._originalText;
case WebInspector.Color.Format.RGB:
if (this.hasAlpha())
return null;
return String.sprintf("rgb(%d, %d, %d)", toRgbValue(this._rgba[0]), toRgbValue(this._rgba[1]), toRgbValue(this._rgba[2]));
case WebInspector.Color.Format.RGBA:
return String.sprintf("rgba(%d, %d, %d, %f)", toRgbValue(this._rgba[0]), toRgbValue(this._rgba[1]), toRgbValue(this._rgba[2]), this._rgba[3]);
case WebInspector.Color.Format.HSL:
if (this.hasAlpha())
return null;
var hsl = this.hsla();
return String.sprintf("hsl(%d, %d%, %d%)", Math.round(hsl[0] * 360), Math.round(hsl[1] * 100), Math.round(hsl[2] * 100));
case WebInspector.Color.Format.HSLA:
var hsla = this.hsla();
return String.sprintf("hsla(%d, %d%, %d%, %f)", Math.round(hsla[0] * 360), Math.round(hsla[1] * 100), Math.round(hsla[2] * 100), hsla[3]);
case WebInspector.Color.Format.HEX:
if (this.hasAlpha())
return null;
return String.sprintf("#%s%s%s", toHexValue(this._rgba[0]), toHexValue(this._rgba[1]), toHexValue(this._rgba[2])).toUpperCase();
case WebInspector.Color.Format.ShortHEX:
if (!this.canBeShortHex())
return null;
return String.sprintf("#%s%s%s", toShortHexValue(this._rgba[0]), toShortHexValue(this._rgba[1]), toShortHexValue(this._rgba[2])).toUpperCase();
case WebInspector.Color.Format.Nickname:
return this.nickname();
}
return this._originalText;
},
/**
* @return {Array.<number>}
*/
_canonicalRGBA: function()
{
var rgba = new Array(3);
for (var i = 0; i < 3; ++i)
rgba[i] = Math.round(this._rgba[i] * 255);
if (this._rgba[3] !== 1)
rgba.push(this._rgba[3]);
return rgba;
},
/**
* @return {?string} nickname
*/
nickname: function()
{
if (!WebInspector.Color._rgbaToNickname) {
WebInspector.Color._rgbaToNickname = {};
for (var nickname in WebInspector.Color.Nicknames) {
var rgba = WebInspector.Color.Nicknames[nickname];
WebInspector.Color._rgbaToNickname[rgba] = nickname;
}
}
return WebInspector.Color._rgbaToNickname[this._canonicalRGBA()] || null;
},
/**
* @return {DOMAgent.RGBA}
*/
toProtocolRGBA: function()
{
var rgba = this._canonicalRGBA();
var result = { r: rgba[0], g: rgba[1], b: rgba[2] };
if (rgba[3] !== 1)
result.a = rgba[3];
return result;
}
}
/**
* @param {string} value
* return {number}
*/
WebInspector.Color._parseRgbNumeric = function(value)
{
var parsed = parseInt(value, 10);
if (value.indexOf("%") !== -1)
parsed /= 100;
else
parsed /= 255;
return parsed;
}
/**
* @param {string} value
* return {number}
*/
WebInspector.Color._parseHueNumeric = function(value)
{
return isNaN(value) ? 0 : (parseFloat(value) / 360) % 1;
}
/**
* @param {string} value
* return {number}
*/
WebInspector.Color._parseSatLightNumeric = function(value)
{
return parseFloat(value) / 100;
}
/**
* @param {string} value
* return {number}
*/
WebInspector.Color._parseAlphaNumeric = function(value)
{
return isNaN(value) ? 0 : parseFloat(value);
}
/**
* @param {Array.<number>} hsl
* @return {Array.<number>}
*/
WebInspector.Color._hsl2rgb = function(hsl)
{
var h = hsl[0];
var s = hsl[1];
var l = hsl[2];
function hue2rgb(p, q, h)
{
if (h < 0)
h += 1;
else if (h > 1)
h -= 1;
if ((h * 6) < 1)
return p + (q - p) * h * 6;
else if ((h * 2) < 1)
return q;
else if ((h * 3) < 2)
return p + (q - p) * ((2 / 3) - h) * 6;
else
return p;
}
if (s < 0)
s = 0;
if (l <= 0.5)
var q = l * (1 + s);
else
var q = l + s - (l * s);
var p = 2 * l - q;
var tr = h + (1 / 3);
var tg = h;
var tb = h - (1 / 3);
var r = hue2rgb(p, q, tr);
var g = hue2rgb(p, q, tg);
var b = hue2rgb(p, q, tb);
return [r, g, b, hsl[3]];
}
WebInspector.Color.Nicknames = {
"aliceBlue": [240,248,255],
"antiqueWhite": [250,235,215],
"aquamarine": [127,255,212],
"azure": [240,255,255],
"beige": [245,245,220],
"bisque": [255,228,196],
"black": [0,0,0],
"blanchedAlmond": [255,235,205],
"blue": [0,0,255],
"blueViolet": [138,43,226],
"brown": [165,42,42],
"burlyWood": [222,184,135],
"cadetBlue": [95,158,160],
"chartreuse": [127,255,0],
"chocolate": [210,105,30],
"coral": [255,127,80],
"cornflowerBlue": [100,149,237],
"cornsilk": [255,248,220],
"crimson": [237,20,61],
"cyan": [0,255,255],
"darkBlue": [0,0,139],
"darkCyan": [0,139,139],
"darkGoldenrod": [184,134,11],
"darkGray": [169,169,169],
"darkGreen": [0,100,0],
"darkKhaki": [189,183,107],
"darkMagenta": [139,0,139],
"darkOliveGreen": [85,107,47],
"darkOrange": [255,140,0],
"darkOrchid": [153,50,204],
"darkRed": [139,0,0],
"darkSalmon": [233,150,122],
"darkSeaGreen": [143,188,143],
"darkSlateBlue": [72,61,139],
"darkSlateGray": [47,79,79],
"darkTurquoise": [0,206,209],
"darkViolet": [148,0,211],
"deepPink": [255,20,147],
"deepSkyBlue": [0,191,255],
"dimGray": [105,105,105],
"dodgerBlue": [30,144,255],
"fireBrick": [178,34,34],
"floralWhite": [255,250,240],
"forestGreen": [34,139,34],
"gainsboro": [220,220,220],
"ghostWhite": [248,248,255],
"gold": [255,215,0],
"goldenrod": [218,165,32],
"gray": [128,128,128],
"green": [0,128,0],
"greenYellow": [173,255,47],
"honeyDew": [240,255,240],
"hotPink": [255,105,180],
"indianRed": [205,92,92],
"indigo": [75,0,130],
"ivory": [255,255,240],
"khaki": [240,230,140],
"lavender": [230,230,250],
"lavenderBlush": [255,240,245],
"lawnGreen": [124,252,0],
"lemonChiffon": [255,250,205],
"lightBlue": [173,216,230],
"lightCoral": [240,128,128],
"lightCyan": [224,255,255],
"lightGoldenrodYellow":[250,250,210],
"lightGreen": [144,238,144],
"lightGrey": [211,211,211],
"lightPink": [255,182,193],
"lightSalmon": [255,160,122],
"lightSeaGreen": [32,178,170],
"lightSkyBlue": [135,206,250],
"lightSlateGray": [119,136,153],
"lightSteelBlue": [176,196,222],
"lightYellow": [255,255,224],
"lime": [0,255,0],
"limeGreen": [50,205,50],
"linen": [250,240,230],
"magenta": [255,0,255],
"maroon": [128,0,0],
"mediumAquaMarine": [102,205,170],
"mediumBlue": [0,0,205],
"mediumOrchid": [186,85,211],
"mediumPurple": [147,112,219],
"mediumSeaGreen": [60,179,113],
"mediumSlateBlue": [123,104,238],
"mediumSpringGreen": [0,250,154],
"mediumTurquoise": [72,209,204],
"mediumVioletRed": [199,21,133],
"midnightBlue": [25,25,112],
"mintCream": [245,255,250],
"mistyRose": [255,228,225],
"moccasin": [255,228,181],
"navajoWhite": [255,222,173],
"navy": [0,0,128],
"oldLace": [253,245,230],
"olive": [128,128,0],
"oliveDrab": [107,142,35],
"orange": [255,165,0],
"orangeRed": [255,69,0],
"orchid": [218,112,214],
"paleGoldenrod": [238,232,170],
"paleGreen": [152,251,152],
"paleTurquoise": [175,238,238],
"paleVioletRed": [219,112,147],
"papayaWhip": [255,239,213],
"peachPuff": [255,218,185],
"peru": [205,133,63],
"pink": [255,192,203],
"plum": [221,160,221],
"powderBlue": [176,224,230],
"purple": [128,0,128],
"red": [255,0,0],
"rosyBrown": [188,143,143],
"royalBlue": [65,105,225],
"saddleBrown": [139,69,19],
"salmon": [250,128,114],
"sandyBrown": [244,164,96],
"seaGreen": [46,139,87],
"seaShell": [255,245,238],
"sienna": [160,82,45],
"silver": [192,192,192],
"skyBlue": [135,206,235],
"slateBlue": [106,90,205],
"slateGray": [112,128,144],
"snow": [255,250,250],
"springGreen": [0,255,127],
"steelBlue": [70,130,180],
"tan": [210,180,140],
"teal": [0,128,128],
"thistle": [216,191,216],
"tomato": [255,99,71],
"turquoise": [64,224,208],
"violet": [238,130,238],
"wheat": [245,222,179],
"white": [255,255,255],
"whiteSmoke": [245,245,245],
"yellow": [255,255,0],
"yellowGreen": [154,205,50],
"transparent": [0, 0, 0, 0],
};
WebInspector.Color.PageHighlight = {
Content: WebInspector.Color.fromRGBA([111, 168, 220, .66]),
ContentLight: WebInspector.Color.fromRGBA([111, 168, 220, .5]),
ContentOutline: WebInspector.Color.fromRGBA([9, 83, 148]),
Padding: WebInspector.Color.fromRGBA([147, 196, 125, .55]),
PaddingLight: WebInspector.Color.fromRGBA([147, 196, 125, .4]),
Border: WebInspector.Color.fromRGBA([255, 229, 153, .66]),
BorderLight: WebInspector.Color.fromRGBA([255, 229, 153, .5]),
Margin: WebInspector.Color.fromRGBA([246, 178, 107, .66]),
MarginLight: WebInspector.Color.fromRGBA([246, 178, 107, .5]),
EventTarget: WebInspector.Color.fromRGBA([255, 196, 196, .66])
}
WebInspector.Color.Format = {
Original: "original",
Nickname: "nickname",
HEX: "hex",
ShortHEX: "shorthex",
RGB: "rgb",
RGBA: "rgba",
HSL: "hsl",
HSLA: "hsla"
}