Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / common / Color.js
1 /*
2  * Copyright (C) 2009 Apple Inc.  All rights reserved.
3  * Copyright (C) 2009 Joseph Pecoraro
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
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.
17  *
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.
28  */
29
30 /**
31  * @param {!Array.<number>} rgba
32  * @param {string=} format
33  * @param {string=} originalText
34  * @constructor
35  */
36 WebInspector.Color = function(rgba, format, originalText)
37 {
38     this._rgba = rgba;
39     this._originalText = originalText || null;
40     this._format = format || null;
41     if (typeof this._rgba[3] === "undefined")
42         this._rgba[3] = 1;
43     for (var i = 0; i < 4; ++i) {
44         if (this._rgba[i] < 0)
45             this._rgba[i] = 0;
46         if (this._rgba[i] > 1)
47             this._rgba[i] = 1;
48     }
49 }
50
51 /**
52  * @param {string} text
53  * @return {?WebInspector.Color}
54  */
55 WebInspector.Color.parse = function(text)
56 {
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);
61     if (match) {
62         if (match[1]) { // hex
63             var hex = match[1].toUpperCase();
64             var format;
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);
68             } else
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);
74         }
75
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);
82         }
83
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;
91                 return color;
92             }
93             return null;
94         }
95
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);
103         }
104
105         return null;
106     }
107
108     // Advanced - rgba(), hsla()
109     var advanced = /^(?:rgba\(([^)]+)\)|hsla\(([^)]+)\))$/;
110     match = value.match(advanced);
111     if (match) {
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);
119         }
120
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);
129         }
130     }
131
132     return null;
133 }
134
135 /**
136  * @param {!Array.<number>} rgba
137  * @return {!WebInspector.Color}
138  */
139 WebInspector.Color.fromRGBA = function(rgba)
140 {
141     return new WebInspector.Color([rgba[0] / 255, rgba[1] / 255, rgba[2] / 255, rgba[3]]);
142 }
143
144 /**
145  * @param {!Array.<number>} hsva
146  * @return {!WebInspector.Color}
147  */
148 WebInspector.Color.fromHSVA = function(hsva)
149 {
150     var h = hsva[0];
151     var s = hsva[1];
152     var v = hsva[2];
153
154     var t = (2 - s) * v;
155     if (v === 0 || s === 0)
156         s = 0;
157     else
158         s *= v / (t < 1 ? t : 2 - t);
159     var hsla = [h, s, t / 2, hsva[3]];
160
161     return new WebInspector.Color(WebInspector.Color._hsl2rgb(hsla), WebInspector.Color.Format.HSLA);
162 }
163
164 WebInspector.Color.prototype = {
165     /**
166      * @return {?string}
167      */
168     format: function()
169     {
170         return this._format;
171     },
172
173     /**
174      * @return {!Array.<number>} HSLA with components within [0..1]
175      */
176     hsla: function()
177     {
178         if (this._hsla)
179             return this._hsla;
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;
186         var add = max + min;
187
188         if (min === max)
189             var h = 0;
190         else if (r === max)
191             var h = ((1/6 * (g - b) / diff) + 1) % 1;
192         else if (g === max)
193             var h = (1/6 * (b - r) / diff) + 1/3;
194         else
195             var h = (1/6 * (r - g) / diff) + 2/3;
196
197         var l = 0.5 * add;
198
199         if (l === 0)
200             var s = 0;
201         else if (l === 1)
202             var s = 1;
203         else if (l <= 0.5)
204             var s = diff / add;
205         else
206             var s = diff / (2 - add);
207
208         this._hsla = [h, s, l, this._rgba[3]];
209         return this._hsla;
210     },
211
212     /**
213      * @return {!Array.<number>} HSVA with components within [0..1]
214      */
215     hsva: function()
216     {
217         var hsla = this.hsla();
218         var h = hsla[0];
219         var s = hsla[1];
220         var l = hsla[2];
221
222         s *= l < 0.5 ? l : 1 - l;
223         return [h, s !== 0 ? 2 * s / (l + s) : 0, (l + s), hsla[3]];
224     },
225
226     /**
227      * @return {boolean}
228      */
229     hasAlpha: function()
230     {
231         return this._rgba[3] !== 1;
232     },
233
234     /**
235      * @return {boolean}
236      */
237     canBeShortHex: function()
238     {
239         if (this.hasAlpha())
240             return false;
241         for (var i = 0; i < 3; ++i) {
242             var c = Math.round(this._rgba[i] * 255);
243             if (c % 17)
244                 return false;
245         }
246         return true;
247     },
248
249     /**
250      * @return {?string}
251      */
252     toString: function(format)
253     {
254         if (!format)
255             format = this._format;
256
257         /**
258          * @param {number} value
259          * @return {number}
260          */
261         function toRgbValue(value)
262         {
263             return Math.round(value * 255);
264         }
265
266         /**
267          * @param {number} value
268          * @return {string}
269          */
270         function toHexValue(value)
271         {
272             var hex = Math.round(value * 255).toString(16);
273             return hex.length === 1 ? "0" + hex : hex;
274         }
275
276         /**
277          * @param {number} value
278          * @return {string}
279          */
280         function toShortHexValue(value)
281         {
282             return (Math.round(value * 255) / 17).toString(16);
283         }
284
285         switch (format) {
286         case WebInspector.Color.Format.Original:
287             return this._originalText;
288         case WebInspector.Color.Format.RGB:
289             if (this.hasAlpha())
290                 return null;
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:
295             if (this.hasAlpha())
296                 return null;
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:
303             if (this.hasAlpha())
304                 return null;
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())
308                 return null;
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();
312         }
313
314         return this._originalText;
315     },
316
317     /**
318      * @return {!Array.<number>}
319      */
320     _canonicalRGBA: function()
321     {
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]);
327         return rgba;
328     },
329
330     /**
331      * @return {?string} nickname
332      */
333     nickname: function()
334     {
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;
340             }
341         }
342
343         return WebInspector.Color._rgbaToNickname[this._canonicalRGBA()] || null;
344     },
345
346     /**
347      * @return {!DOMAgent.RGBA}
348      */
349     toProtocolRGBA: function()
350     {
351         var rgba = this._canonicalRGBA();
352         var result = { r: rgba[0], g: rgba[1], b: rgba[2] };
353         if (rgba[3] !== 1)
354             result.a = rgba[3];
355         return result;
356     },
357
358     /**
359      * @return {!WebInspector.Color}
360      */
361     invert: function()
362     {
363         var rgba = [];
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);
369     },
370
371     /**
372      * @param {number} alpha
373      * @return {!WebInspector.Color}
374      */
375      setAlpha: function(alpha)
376      {
377          var rgba = this._rgba.slice();
378          rgba[3] = alpha;
379          return new WebInspector.Color(rgba);
380      }
381 }
382
383 /**
384  * @param {string} value
385  * return {number}
386  */
387 WebInspector.Color._parseRgbNumeric = function(value)
388 {
389     var parsed = parseInt(value, 10);
390     if (value.indexOf("%") !== -1)
391         parsed /= 100;
392     else
393         parsed /= 255;
394     return parsed;
395 }
396
397 /**
398  * @param {string} value
399  * return {number}
400  */
401 WebInspector.Color._parseHueNumeric = function(value)
402 {
403     return isNaN(value) ? 0 : (parseFloat(value) / 360) % 1;
404 }
405
406 /**
407  * @param {string} value
408  * return {number}
409  */
410 WebInspector.Color._parseSatLightNumeric = function(value)
411 {
412     return parseFloat(value) / 100;
413 }
414
415 /**
416  * @param {string} value
417  * return {number}
418  */
419 WebInspector.Color._parseAlphaNumeric = function(value)
420 {
421     return isNaN(value) ? 0 : parseFloat(value);
422 }
423
424 /**
425  * @param {!Array.<number>} hsl
426  * @return {!Array.<number>}
427  */
428 WebInspector.Color._hsl2rgb = function(hsl)
429 {
430     var h = hsl[0];
431     var s = hsl[1];
432     var l = hsl[2];
433
434     function hue2rgb(p, q, h)
435     {
436         if (h < 0)
437             h += 1;
438         else if (h > 1)
439             h -= 1;
440
441         if ((h * 6) < 1)
442             return p + (q - p) * h * 6;
443         else if ((h * 2) < 1)
444             return q;
445         else if ((h * 3) < 2)
446             return p + (q - p) * ((2 / 3) - h) * 6;
447         else
448             return p;
449     }
450
451     if (s < 0)
452         s = 0;
453
454     if (l <= 0.5)
455         var q = l * (1 + s);
456     else
457         var q = l + s - (l * s);
458
459     var p = 2 * l - q;
460
461     var tr = h + (1 / 3);
462     var tg = h;
463     var tb = h - (1 / 3);
464
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]];
469 }
470
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],
478     "black":              [0,0,0],
479     "blanchedalmond":     [255,235,205],
480     "blue":               [0,0,255],
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],
491     "cyan":               [0,255,255],
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],
518     "gold":               [255,215,0],
519     "goldenrod":          [218,165,32],
520     "gray":               [128,128,128],
521     "green":              [0,128,0],
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],
546     "lime":               [0,255,0],
547     "limegreen":          [50,205,50],
548     "linen":              [250,240,230],
549     "magenta":            [255,0,255],
550     "maroon":             [128,0,0],
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],
565     "navy":               [0,0,128],
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],
583     "red":                [255,0,0],
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],
600     "teal":               [0,128,128],
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],
611 };
612
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])
624 }
625
626 WebInspector.Color.Format = {
627     Original: "original",
628     Nickname: "nickname",
629     HEX: "hex",
630     ShortHEX: "shorthex",
631     RGB: "rgb",
632     RGBA: "rgba",
633     HSL: "hsl",
634     HSLA: "hsla"
635 }