2 * Copyright (C) 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2009 Joseph Pecoraro
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 * @param {!Array.<number>} rgba
32 * @param {string=} format
33 * @param {string=} originalText
36 WebInspector.Color = function(rgba, format, originalText)
39 this._originalText = originalText || null;
40 this._format = format || null;
41 if (typeof this._rgba[3] === "undefined")
43 for (var i = 0; i < 4; ++i) {
44 if (this._rgba[i] < 0)
46 if (this._rgba[i] > 1)
52 * @param {string} text
53 * @return {?WebInspector.Color}
55 WebInspector.Color.parse = function(text)
57 // Simple - #hex, rgb(), nickname, hsl()
58 var value = text.toLowerCase().replace(/\s+/g, "");
59 var simple = /^(?:#([0-9a-f]{3,6})|rgb\(([^)]+)\)|(\w+)|hsl\(([^)]+)\))$/i;
60 var match = value.match(simple);
62 if (match[1]) { // hex
63 var hex = match[1].toUpperCase();
65 if (hex.length === 3) {
66 format = WebInspector.Color.Format.ShortHEX;
67 hex = hex.charAt(0) + hex.charAt(0) + hex.charAt(1) + hex.charAt(1) + hex.charAt(2) + hex.charAt(2);
69 format = WebInspector.Color.Format.HEX;
70 var r = parseInt(hex.substring(0,2), 16);
71 var g = parseInt(hex.substring(2,4), 16);
72 var b = parseInt(hex.substring(4,6), 16);
73 return new WebInspector.Color([r / 255, g / 255, b / 255, 1], format, text);
76 if (match[2]) { // rgb
77 var rgbString = match[2].split(/\s*,\s*/);
78 var rgba = [ WebInspector.Color._parseRgbNumeric(rgbString[0]),
79 WebInspector.Color._parseRgbNumeric(rgbString[1]),
80 WebInspector.Color._parseRgbNumeric(rgbString[2]), 1 ];
81 return new WebInspector.Color(rgba, WebInspector.Color.Format.RGB, text);
84 if (match[3]) { // nickname
85 var nickname = match[3].toLowerCase();
86 if (nickname in WebInspector.Color.Nicknames) {
87 var rgba = WebInspector.Color.Nicknames[nickname];
88 var color = WebInspector.Color.fromRGBA(rgba);
89 color._format = WebInspector.Color.Format.Nickname;
90 color._originalText = nickname;
96 if (match[4]) { // hsl
97 var hslString = match[4].replace(/%/g, "").split(/\s*,\s*/);
98 var hsla = [ WebInspector.Color._parseHueNumeric(hslString[0]),
99 WebInspector.Color._parseSatLightNumeric(hslString[1]),
100 WebInspector.Color._parseSatLightNumeric(hslString[2]), 1 ];
101 var rgba = WebInspector.Color._hsl2rgb(hsla);
102 return new WebInspector.Color(rgba, WebInspector.Color.Format.HSL, text);
108 // Advanced - rgba(), hsla()
109 var advanced = /^(?:rgba\(([^)]+)\)|hsla\(([^)]+)\))$/;
110 match = value.match(advanced);
112 if (match[1]) { // rgba
113 var rgbaString = match[1].split(/\s*,\s*/);
114 var rgba = [ WebInspector.Color._parseRgbNumeric(rgbaString[0]),
115 WebInspector.Color._parseRgbNumeric(rgbaString[1]),
116 WebInspector.Color._parseRgbNumeric(rgbaString[2]),
117 WebInspector.Color._parseAlphaNumeric(rgbaString[3]) ];
118 return new WebInspector.Color(rgba, WebInspector.Color.Format.RGBA, text);
121 if (match[2]) { // hsla
122 var hslaString = match[2].replace(/%/g, "").split(/\s*,\s*/);
123 var hsla = [ WebInspector.Color._parseHueNumeric(hslaString[0]),
124 WebInspector.Color._parseSatLightNumeric(hslaString[1]),
125 WebInspector.Color._parseSatLightNumeric(hslaString[2]),
126 WebInspector.Color._parseAlphaNumeric(hslaString[3]) ];
127 var rgba = WebInspector.Color._hsl2rgb(hsla);
128 return new WebInspector.Color(rgba, WebInspector.Color.Format.HSLA, text);
136 * @param {!Array.<number>} rgba
137 * @return {!WebInspector.Color}
139 WebInspector.Color.fromRGBA = function(rgba)
141 return new WebInspector.Color([rgba[0] / 255, rgba[1] / 255, rgba[2] / 255, rgba[3]]);
145 * @param {!Array.<number>} hsva
146 * @return {!WebInspector.Color}
148 WebInspector.Color.fromHSVA = function(hsva)
155 if (v === 0 || s === 0)
158 s *= v / (t < 1 ? t : 2 - t);
159 var hsla = [h, s, t / 2, hsva[3]];
161 return new WebInspector.Color(WebInspector.Color._hsl2rgb(hsla), WebInspector.Color.Format.HSLA);
164 WebInspector.Color.prototype = {
174 * @return {!Array.<number>} HSLA with components within [0..1]
180 var r = this._rgba[0];
181 var g = this._rgba[1];
182 var b = this._rgba[2];
183 var max = Math.max(r, g, b);
184 var min = Math.min(r, g, b);
185 var diff = max - min;
191 var h = ((1/6 * (g - b) / diff) + 1) % 1;
193 var h = (1/6 * (b - r) / diff) + 1/3;
195 var h = (1/6 * (r - g) / diff) + 2/3;
206 var s = diff / (2 - add);
208 this._hsla = [h, s, l, this._rgba[3]];
213 * @return {!Array.<number>} HSVA with components within [0..1]
217 var hsla = this.hsla();
222 s *= l < 0.5 ? l : 1 - l;
223 return [h, s !== 0 ? 2 * s / (l + s) : 0, (l + s), hsla[3]];
231 return this._rgba[3] !== 1;
237 canBeShortHex: function()
241 for (var i = 0; i < 3; ++i) {
242 var c = Math.round(this._rgba[i] * 255);
252 toString: function(format)
255 format = this._format;
258 * @param {number} value
261 function toRgbValue(value)
263 return Math.round(value * 255);
267 * @param {number} value
270 function toHexValue(value)
272 var hex = Math.round(value * 255).toString(16);
273 return hex.length === 1 ? "0" + hex : hex;
277 * @param {number} value
280 function toShortHexValue(value)
282 return (Math.round(value * 255) / 17).toString(16);
286 case WebInspector.Color.Format.Original:
287 return this._originalText;
288 case WebInspector.Color.Format.RGB:
291 return String.sprintf("rgb(%d, %d, %d)", toRgbValue(this._rgba[0]), toRgbValue(this._rgba[1]), toRgbValue(this._rgba[2]));
292 case WebInspector.Color.Format.RGBA:
293 return String.sprintf("rgba(%d, %d, %d, %f)", toRgbValue(this._rgba[0]), toRgbValue(this._rgba[1]), toRgbValue(this._rgba[2]), this._rgba[3]);
294 case WebInspector.Color.Format.HSL:
297 var hsl = this.hsla();
298 return String.sprintf("hsl(%d, %d%, %d%)", Math.round(hsl[0] * 360), Math.round(hsl[1] * 100), Math.round(hsl[2] * 100));
299 case WebInspector.Color.Format.HSLA:
300 var hsla = this.hsla();
301 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]);
302 case WebInspector.Color.Format.HEX:
305 return String.sprintf("#%s%s%s", toHexValue(this._rgba[0]), toHexValue(this._rgba[1]), toHexValue(this._rgba[2])).toUpperCase();
306 case WebInspector.Color.Format.ShortHEX:
307 if (!this.canBeShortHex())
309 return String.sprintf("#%s%s%s", toShortHexValue(this._rgba[0]), toShortHexValue(this._rgba[1]), toShortHexValue(this._rgba[2])).toUpperCase();
310 case WebInspector.Color.Format.Nickname:
311 return this.nickname();
314 return this._originalText;
318 * @return {!Array.<number>}
320 _canonicalRGBA: function()
322 var rgba = new Array(3);
323 for (var i = 0; i < 3; ++i)
324 rgba[i] = Math.round(this._rgba[i] * 255);
325 if (this._rgba[3] !== 1)
326 rgba.push(this._rgba[3]);
331 * @return {?string} nickname
335 if (!WebInspector.Color._rgbaToNickname) {
336 WebInspector.Color._rgbaToNickname = {};
337 for (var nickname in WebInspector.Color.Nicknames) {
338 var rgba = WebInspector.Color.Nicknames[nickname];
339 WebInspector.Color._rgbaToNickname[rgba] = nickname;
343 return WebInspector.Color._rgbaToNickname[this._canonicalRGBA()] || null;
347 * @return {!DOMAgent.RGBA}
349 toProtocolRGBA: function()
351 var rgba = this._canonicalRGBA();
352 var result = { r: rgba[0], g: rgba[1], b: rgba[2] };
359 * @return {!WebInspector.Color}
364 rgba[0] = 1 - this._rgba[0];
365 rgba[1] = 1 - this._rgba[1];
366 rgba[2] = 1 - this._rgba[2];
367 rgba[3] = this._rgba[3];
368 return new WebInspector.Color(rgba);
372 * @param {number} alpha
373 * @return {!WebInspector.Color}
375 setAlpha: function(alpha)
377 var rgba = this._rgba.slice();
379 return new WebInspector.Color(rgba);
384 * @param {string} value
387 WebInspector.Color._parseRgbNumeric = function(value)
389 var parsed = parseInt(value, 10);
390 if (value.indexOf("%") !== -1)
398 * @param {string} value
401 WebInspector.Color._parseHueNumeric = function(value)
403 return isNaN(value) ? 0 : (parseFloat(value) / 360) % 1;
407 * @param {string} value
410 WebInspector.Color._parseSatLightNumeric = function(value)
412 return parseFloat(value) / 100;
416 * @param {string} value
419 WebInspector.Color._parseAlphaNumeric = function(value)
421 return isNaN(value) ? 0 : parseFloat(value);
425 * @param {!Array.<number>} hsl
426 * @return {!Array.<number>}
428 WebInspector.Color._hsl2rgb = function(hsl)
434 function hue2rgb(p, q, h)
442 return p + (q - p) * h * 6;
443 else if ((h * 2) < 1)
445 else if ((h * 3) < 2)
446 return p + (q - p) * ((2 / 3) - h) * 6;
457 var q = l + s - (l * s);
461 var tr = h + (1 / 3);
463 var tb = h - (1 / 3);
465 var r = hue2rgb(p, q, tr);
466 var g = hue2rgb(p, q, tg);
467 var b = hue2rgb(p, q, tb);
468 return [r, g, b, hsl[3]];
471 WebInspector.Color.Nicknames = {
472 "aliceblue": [240,248,255],
473 "antiquewhite": [250,235,215],
474 "aquamarine": [127,255,212],
475 "azure": [240,255,255],
476 "beige": [245,245,220],
477 "bisque": [255,228,196],
479 "blanchedalmond": [255,235,205],
481 "blueviolet": [138,43,226],
482 "brown": [165,42,42],
483 "burlywood": [222,184,135],
484 "cadetblue": [95,158,160],
485 "chartreuse": [127,255,0],
486 "chocolate": [210,105,30],
487 "coral": [255,127,80],
488 "cornflowerblue": [100,149,237],
489 "cornsilk": [255,248,220],
490 "crimson": [237,20,61],
492 "darkblue": [0,0,139],
493 "darkcyan": [0,139,139],
494 "darkgoldenrod": [184,134,11],
495 "darkgray": [169,169,169],
496 "darkgreen": [0,100,0],
497 "darkkhaki": [189,183,107],
498 "darkmagenta": [139,0,139],
499 "darkolivegreen": [85,107,47],
500 "darkorange": [255,140,0],
501 "darkorchid": [153,50,204],
502 "darkred": [139,0,0],
503 "darksalmon": [233,150,122],
504 "darkseagreen": [143,188,143],
505 "darkslateblue": [72,61,139],
506 "darkslategray": [47,79,79],
507 "darkturquoise": [0,206,209],
508 "darkviolet": [148,0,211],
509 "deeppink": [255,20,147],
510 "deepskyblue": [0,191,255],
511 "dimgray": [105,105,105],
512 "dodgerblue": [30,144,255],
513 "firebrick": [178,34,34],
514 "floralwhite": [255,250,240],
515 "forestgreen": [34,139,34],
516 "gainsboro": [220,220,220],
517 "ghostwhite": [248,248,255],
519 "goldenrod": [218,165,32],
520 "gray": [128,128,128],
522 "greenyellow": [173,255,47],
523 "honeydew": [240,255,240],
524 "hotpink": [255,105,180],
525 "indianred": [205,92,92],
526 "indigo": [75,0,130],
527 "ivory": [255,255,240],
528 "khaki": [240,230,140],
529 "lavender": [230,230,250],
530 "lavenderblush": [255,240,245],
531 "lawngreen": [124,252,0],
532 "lemonchiffon": [255,250,205],
533 "lightblue": [173,216,230],
534 "lightcoral": [240,128,128],
535 "lightcyan": [224,255,255],
536 "lightgoldenrodyellow":[250,250,210],
537 "lightgreen": [144,238,144],
538 "lightgrey": [211,211,211],
539 "lightpink": [255,182,193],
540 "lightsalmon": [255,160,122],
541 "lightseagreen": [32,178,170],
542 "lightskyblue": [135,206,250],
543 "lightslategray": [119,136,153],
544 "lightsteelblue": [176,196,222],
545 "lightyellow": [255,255,224],
547 "limegreen": [50,205,50],
548 "linen": [250,240,230],
549 "magenta": [255,0,255],
551 "mediumaquamarine": [102,205,170],
552 "mediumblue": [0,0,205],
553 "mediumorchid": [186,85,211],
554 "mediumpurple": [147,112,219],
555 "mediumseagreen": [60,179,113],
556 "mediumslateblue": [123,104,238],
557 "mediumspringgreen": [0,250,154],
558 "mediumturquoise": [72,209,204],
559 "mediumvioletred": [199,21,133],
560 "midnightblue": [25,25,112],
561 "mintcream": [245,255,250],
562 "mistyrose": [255,228,225],
563 "moccasin": [255,228,181],
564 "navajowhite": [255,222,173],
566 "oldlace": [253,245,230],
567 "olive": [128,128,0],
568 "olivedrab": [107,142,35],
569 "orange": [255,165,0],
570 "orangered": [255,69,0],
571 "orchid": [218,112,214],
572 "palegoldenrod": [238,232,170],
573 "palegreen": [152,251,152],
574 "paleturquoise": [175,238,238],
575 "palevioletred": [219,112,147],
576 "papayawhip": [255,239,213],
577 "peachpuff": [255,218,185],
578 "peru": [205,133,63],
579 "pink": [255,192,203],
580 "plum": [221,160,221],
581 "powderblue": [176,224,230],
582 "purple": [128,0,128],
584 "rosybrown": [188,143,143],
585 "royalblue": [65,105,225],
586 "saddlebrown": [139,69,19],
587 "salmon": [250,128,114],
588 "sandybrown": [244,164,96],
589 "seagreen": [46,139,87],
590 "seashell": [255,245,238],
591 "sienna": [160,82,45],
592 "silver": [192,192,192],
593 "skyblue": [135,206,235],
594 "slateblue": [106,90,205],
595 "slategray": [112,128,144],
596 "snow": [255,250,250],
597 "springgreen": [0,255,127],
598 "steelblue": [70,130,180],
599 "tan": [210,180,140],
601 "thistle": [216,191,216],
602 "tomato": [255,99,71],
603 "turquoise": [64,224,208],
604 "violet": [238,130,238],
605 "wheat": [245,222,179],
606 "white": [255,255,255],
607 "whitesmoke": [245,245,245],
608 "yellow": [255,255,0],
609 "yellowgreen": [154,205,50],
610 "transparent": [0, 0, 0, 0],
613 WebInspector.Color.PageHighlight = {
614 Content: WebInspector.Color.fromRGBA([111, 168, 220, .66]),
615 ContentLight: WebInspector.Color.fromRGBA([111, 168, 220, .5]),
616 ContentOutline: WebInspector.Color.fromRGBA([9, 83, 148]),
617 Padding: WebInspector.Color.fromRGBA([147, 196, 125, .55]),
618 PaddingLight: WebInspector.Color.fromRGBA([147, 196, 125, .4]),
619 Border: WebInspector.Color.fromRGBA([255, 229, 153, .66]),
620 BorderLight: WebInspector.Color.fromRGBA([255, 229, 153, .5]),
621 Margin: WebInspector.Color.fromRGBA([246, 178, 107, .66]),
622 MarginLight: WebInspector.Color.fromRGBA([246, 178, 107, .5]),
623 EventTarget: WebInspector.Color.fromRGBA([255, 196, 196, .66])
626 WebInspector.Color.Format = {
627 Original: "original",
628 Nickname: "nickname",
630 ShortHEX: "shorthex",