Web Inspector: add context menu items to switch CSS color property value syntax betwe...
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Models / Color.js
1 /*
2  * Copyright (C) 2009, 2013 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 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 WebInspector.Color = class Color
31 {
32     constructor(format, components)
33     {
34         this.format = format;
35
36         if (format === WebInspector.Color.Format.HSL || format === WebInspector.Color.Format.HSLA)
37             this._hsla = components;
38         else
39             this._rgba = components;
40
41         this.valid = !components.some(isNaN);
42     }
43
44     // Static
45
46     static fromString(colorString)
47     {
48         let value = colorString.toLowerCase().replace(/%|\s+/g, "");
49         let transparentKeywords = ["transparent", "rgba(0,0,0,0)", "hsla(0,0,0,0)"];
50         if (transparentKeywords.includes(value)) {
51             let color = new WebInspector.Color(WebInspector.Color.Format.Keyword, [0, 0, 0, 0]);
52             color.keyword = "transparent";
53             color.original = colorString;
54             return color;
55         }
56
57         // Simple - #hex, rgb(), keyword, hsl()
58         let simple = /^(?:#([0-9a-f]{3,8})|rgb\(([^)]+)\)|(\w+)|hsl\(([^)]+)\))$/i;
59         let match = colorString.match(simple);
60         if (match) {
61             if (match[1]) { // hex
62                 let hex = match[1].toUpperCase();
63                 let len = hex.length;
64                 if (len === 3) {
65                     return new WebInspector.Color(WebInspector.Color.Format.ShortHEX, [
66                         parseInt(hex.charAt(0) + hex.charAt(0), 16),
67                         parseInt(hex.charAt(1) + hex.charAt(1), 16),
68                         parseInt(hex.charAt(2) + hex.charAt(2), 16),
69                         1
70                     ]);
71                 } else if (len === 6) {
72                     return new WebInspector.Color(WebInspector.Color.Format.HEX, [
73                         parseInt(hex.substring(0, 2), 16),
74                         parseInt(hex.substring(2, 4), 16),
75                         parseInt(hex.substring(4, 6), 16),
76                         1
77                     ]);
78                 } else if (len === 4) {
79                     return new WebInspector.Color(WebInspector.Color.Format.ShortHEXAlpha, [
80                         parseInt(hex.charAt(0) + hex.charAt(0), 16),
81                         parseInt(hex.charAt(1) + hex.charAt(1), 16),
82                         parseInt(hex.charAt(2) + hex.charAt(2), 16),
83                         parseInt(hex.charAt(3) + hex.charAt(3), 16) / 255
84                     ]);
85                 } else if (len === 8) {
86                     return new WebInspector.Color(WebInspector.Color.Format.HEXAlpha, [
87                         parseInt(hex.substring(0, 2), 16),
88                         parseInt(hex.substring(2, 4), 16),
89                         parseInt(hex.substring(4, 6), 16),
90                         parseInt(hex.substring(6, 8), 16) / 255
91                     ]);
92                 } else
93                     return null;
94             } else if (match[2]) { // rgb
95                 let rgb = match[2].split(/\s*,\s*/);
96                 if (rgb.length !== 3)
97                     return null;
98                 return new WebInspector.Color(WebInspector.Color.Format.RGB, [
99                     parseInt(rgb[0]),
100                     parseInt(rgb[1]),
101                     parseInt(rgb[2]),
102                     1
103                 ]);
104             } else if (match[3]) { // keyword
105                 let keyword = match[3].toLowerCase();
106                 if (!WebInspector.Color.Keywords[keyword])
107                     return null;
108                 let color = new WebInspector.Color(WebInspector.Color.Format.Keyword, WebInspector.Color.Keywords[keyword].concat(1));
109                 color.keyword = keyword;
110                 color.original = colorString;
111                 return color;
112             } else if (match[4]) { // hsl
113                 let hsl = match[4].replace(/%/g, "").split(/\s*,\s*/);
114                 if (hsl.length !== 3)
115                     return null;
116                 return new WebInspector.Color(WebInspector.Color.Format.HSL, [
117                     parseInt(hsl[0]),
118                     parseInt(hsl[1]),
119                     parseInt(hsl[2]),
120                     1
121                 ]);
122             }
123         }
124
125         // Advanced - rgba(), hsla()
126         let advanced = /^(?:rgba\(([^)]+)\)|hsla\(([^)]+)\))$/i;
127         match = colorString.match(advanced);
128         if (match) {
129             if (match[1]) { // rgba
130                 let rgba = match[1].split(/\s*,\s*/);
131                 if (rgba.length !== 4)
132                     return null;
133                 return new WebInspector.Color(WebInspector.Color.Format.RGBA, [
134                     parseInt(rgba[0]),
135                     parseInt(rgba[1]),
136                     parseInt(rgba[2]),
137                     Number.constrain(parseFloat(rgba[3]), 0, 1)
138                 ]);
139             } else if (match[2]) { // hsla
140                 let hsla = match[2].replace(/%/g, "").split(/\s*,\s*/);
141                 if (hsla.length !== 4)
142                     return null;
143                 return new WebInspector.Color(WebInspector.Color.Format.HSLA, [
144                     parseInt(hsla[0]),
145                     parseInt(hsla[1]),
146                     parseInt(hsla[2]),
147                     Number.constrain(parseFloat(hsla[3]), 0, 1)
148                 ]);
149             }
150         }
151
152         return null;
153     }
154
155     static rgb2hsv(r, g, b)
156     {
157         r /= 255;
158         g /= 255;
159         b /= 255;
160
161         let min = Math.min(Math.min(r, g), b);
162         let max = Math.max(Math.max(r, g), b);
163         let delta = max - min;
164
165         let h;
166         let s;
167         let v = max;
168
169         if (delta === 0)
170             h = 0;
171         else if (max === r)
172             h = (60 * ((g - b) / delta)) % 360;
173         else if (max === g)
174             h = 60 * ((b - r) / delta) + 120;
175         else if (max === b)
176             h = 60 * ((r - g) / delta) + 240;
177
178         if (h < 0)
179             h += 360;
180
181         // Saturation
182         if (max === 0)
183             s = 0;
184         else
185             s = 1 - (min / max);
186
187         return [h, s, v];
188     }
189
190     static hsv2rgb(h, s, v)
191     {
192         if (s === 0)
193             return [v, v, v];
194
195         h /= 60;
196         let i = Math.floor(h);
197         let data = [
198             v * (1 - s),
199             v * (1 - s * (h - i)),
200             v * (1 - s * (1 - (h - i)))
201         ];
202         let rgb;
203
204         switch (i) {
205         case 0:
206             rgb = [v, data[2], data[0]];
207             break;
208         case 1:
209             rgb = [data[1], v, data[0]];
210             break;
211         case 2:
212             rgb = [data[0], v, data[2]];
213             break;
214         case 3:
215             rgb = [data[0], data[1], v];
216             break;
217         case 4:
218             rgb = [data[2], data[0], v];
219             break;
220         default:
221             rgb = [v, data[0], data[1]];
222             break;
223         }
224
225         return rgb;
226     }
227
228
229     // Public
230
231     nextFormat(format)
232     {
233         format = format || this.format;
234
235         switch (format) {
236         case WebInspector.Color.Format.Original:
237             return this.simple ? WebInspector.Color.Format.RGB : WebInspector.Color.Format.RGBA;
238
239         case WebInspector.Color.Format.RGB:
240         case WebInspector.Color.Format.RGBA:
241             return this.simple ? WebInspector.Color.Format.HSL : WebInspector.Color.Format.HSLA;
242
243         case WebInspector.Color.Format.HSL:
244         case WebInspector.Color.Format.HSLA:
245             if (this.keyword)
246                 return WebInspector.Color.Format.Keyword;
247             if (this.simple)
248                 return this.canBeSerializedAsShortHEX() ? WebInspector.Color.Format.ShortHEX : WebInspector.Color.Format.HEX;
249             return this.canBeSerializedAsShortHEX() ? WebInspector.Color.Format.ShortHEXAlpha : WebInspector.Color.Format.HEXAlpha;
250
251         case WebInspector.Color.Format.ShortHEX:
252             return WebInspector.Color.Format.HEX;
253
254         case WebInspector.Color.Format.ShortHEXAlpha:
255             return WebInspector.Color.Format.HEXAlpha;
256
257         case WebInspector.Color.Format.HEX:
258         case WebInspector.Color.Format.HEXAlpha:
259             return WebInspector.Color.Format.Original;
260
261         case WebInspector.Color.Format.Keyword:
262             if (this.simple)
263                 return this.canBeSerializedAsShortHEX() ? WebInspector.Color.Format.ShortHEX : WebInspector.Color.Format.HEX;
264             return this.canBeSerializedAsShortHEX() ? WebInspector.Color.Format.ShortHEXAlpha : WebInspector.Color.Format.HEXAlpha;
265
266         default:
267             console.error("Unknown color format.");
268             return null;
269         }
270     }
271
272     get alpha()
273     {
274         return this._rgba ? this._rgba[3] : this._hsla[3];
275     }
276
277     get simple()
278     {
279         return this.alpha === 1;
280     }
281
282     get rgb()
283     {
284         let rgb = this.rgba.slice();
285         rgb.pop();
286         return rgb;
287     }
288
289     get hsl()
290     {
291         let hsl = this.hsla.slice();
292         hsl.pop();
293         return hsl;
294     }
295
296     get rgba()
297     {
298         if (!this._rgba)
299             this._rgba = this._hslaToRGBA(this._hsla);
300         return this._rgba;
301     }
302
303     get hsla()
304     {
305         if (!this._hsla)
306             this._hsla = this._rgbaToHSLA(this.rgba);
307         return this._hsla;
308     }
309
310     copy()
311     {
312         switch (this.format) {
313         case WebInspector.Color.Format.RGB:
314         case WebInspector.Color.Format.HEX:
315         case WebInspector.Color.Format.ShortHEX:
316         case WebInspector.Color.Format.HEXAlpha:
317         case WebInspector.Color.Format.ShortHEXAlpha:
318         case WebInspector.Color.Format.Keyword:
319         case WebInspector.Color.Format.RGBA:
320             return new WebInspector.Color(this.format, this.rgba);
321         case WebInspector.Color.Format.HSL:
322         case WebInspector.Color.Format.HSLA:
323             return new WebInspector.Color(this.format, this.hsla);
324         }
325     }
326
327     toString(format)
328     {
329         if (!format)
330             format = this.format;
331
332         switch (format) {
333         case WebInspector.Color.Format.Original:
334             return this._toOriginalString();
335         case WebInspector.Color.Format.RGB:
336             return this._toRGBString();
337         case WebInspector.Color.Format.RGBA:
338             return this._toRGBAString();
339         case WebInspector.Color.Format.HSL:
340             return this._toHSLString();
341         case WebInspector.Color.Format.HSLA:
342             return this._toHSLAString();
343         case WebInspector.Color.Format.HEX:
344             return this._toHEXString();
345         case WebInspector.Color.Format.ShortHEX:
346             return this._toShortHEXString();
347         case WebInspector.Color.Format.HEXAlpha:
348             return this._toHEXAlphaString();
349         case WebInspector.Color.Format.ShortHEXAlpha:
350             return this._toShortHEXAlphaString();
351         case WebInspector.Color.Format.Keyword:
352             return this._toKeywordString();
353         }
354
355         throw "invalid color format";
356     }
357
358     isKeyword()
359     {
360         if (this.keyword)
361             return true;
362
363         if (!this.simple)
364             return Object.shallowEqual(this._rgba, [0, 0, 0, 0]) || Object.shallowEqual(this._hsla, [0, 0, 0, 0]);
365
366         let rgb = (this._rgba && this._rgba.slice(0, 3)) || this._hslToRGB(this._hsla);
367         return Object.keys(WebInspector.Color.Keywords).some(key => Object.shallowEqual(WebInspector.Color.Keywords[key], rgb));
368     }
369
370     canBeSerializedAsShortHEX()
371     {
372         let rgba = this.rgba || this._hslaToRGBA(this._hsla);
373
374         let r = this._componentToHexValue(rgba[0]);
375         if (r[0] !== r[1])
376             return false;
377
378         let g = this._componentToHexValue(rgba[1]);
379         if (g[0] !== g[1])
380             return false;
381
382         let b = this._componentToHexValue(rgba[2]);
383         if (b[0] !== b[1])
384             return false;
385
386         if (!this.simple) {
387             let a = this._componentToHexValue(Math.round(rgba[3] * 255));
388             if (a[0] !== a[1])
389                 return false;
390         }
391
392         return true;
393     }
394
395     // Private
396
397     _toOriginalString()
398     {
399         return this.original || this._toKeywordString();
400     }
401
402     _toKeywordString()
403     {
404         if (this.keyword)
405             return this.keyword;
406
407         let rgba = this.rgba;
408         if (!this.simple) {
409             if (rgba[0] === 0 && rgba[1] === 0 && rgba[2] === 0 && rgba[3] === 0)
410                 return "transparent";
411             return this._toRGBAString();
412         }
413
414         let keywords = WebInspector.Color.Keywords;
415         for (let keyword in keywords) {
416             if (!keywords.hasOwnProperty(keyword))
417                 continue;
418
419             let keywordRGB = keywords[keyword];
420             if (keywordRGB[0] === rgba[0] && keywordRGB[1] === rgba[1] && keywordRGB[2] === rgba[2])
421                 return keyword;
422         }
423
424         return this._toRGBString();
425     }
426
427     _toShortHEXString()
428     {
429         if (!this.simple)
430             return this._toRGBAString();
431
432         let rgba = this.rgba;
433         let r = this._componentToHexValue(rgba[0]);
434         let g = this._componentToHexValue(rgba[1]);
435         let b = this._componentToHexValue(rgba[2]);
436
437         if (r[0] === r[1] && g[0] === g[1] && b[0] === b[1])
438             return "#" + r[0] + g[0] + b[0];
439         else
440             return "#" + r + g + b;
441     }
442
443     _toHEXString()
444     {
445         if (!this.simple)
446             return this._toRGBAString();
447
448         let rgba = this.rgba;
449         let r = this._componentToHexValue(rgba[0]);
450         let g = this._componentToHexValue(rgba[1]);
451         let b = this._componentToHexValue(rgba[2]);
452
453         return "#" + r + g + b;
454     }
455
456     _toShortHEXAlphaString()
457     {
458         let rgba = this.rgba;
459         let r = this._componentToHexValue(rgba[0]);
460         let g = this._componentToHexValue(rgba[1]);
461         let b = this._componentToHexValue(rgba[2]);
462         let a = this._componentToHexValue(Math.round(rgba[3] * 255));
463
464         if (r[0] === r[1] && g[0] === g[1] && b[0] === b[1] && a[0] === a[1])
465             return "#" + r[0] + g[0] + b[0] + a[0];
466         else
467             return "#" + r + g + b + a;
468     }
469
470     _toHEXAlphaString()
471     {
472         let rgba = this.rgba;
473         let r = this._componentToHexValue(rgba[0]);
474         let g = this._componentToHexValue(rgba[1]);
475         let b = this._componentToHexValue(rgba[2]);
476         let a = this._componentToHexValue(Math.round(rgba[3] * 255));
477
478         return "#" + r + g + b + a;
479     }
480
481     _toRGBString()
482     {
483         if (!this.simple)
484             return this._toRGBAString();
485
486         let rgba = this.rgba.slice(0, -1);
487         return "rgb(" + rgba.join(", ") + ")";
488     }
489
490     _toRGBAString()
491     {
492         return "rgba(" + this.rgba.join(", ") + ")";
493     }
494
495     _toHSLString()
496     {
497         if (!this.simple)
498             return this._toHSLAString();
499
500         let hsla = this.hsla;
501         return "hsl(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%)";
502     }
503
504     _toHSLAString()
505     {
506         let hsla = this.hsla;
507         return "hsla(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%, " + hsla[3] + ")";
508     }
509
510     _componentToNumber(value)
511     {
512         return Number.constrain(value, 0, 255);
513     }
514
515     _componentToHexValue(value)
516     {
517         let hex = this._componentToNumber(value).toString(16);
518         if (hex.length === 1)
519             hex = "0" + hex;
520         return hex;
521     }
522
523     _rgbToHSL(rgb)
524     {
525         let r = this._componentToNumber(rgb[0]) / 255;
526         let g = this._componentToNumber(rgb[1]) / 255;
527         let b = this._componentToNumber(rgb[2]) / 255;
528         let max = Math.max(r, g, b);
529         let min = Math.min(r, g, b);
530         let diff = max - min;
531         let add = max + min;
532
533         let h;
534         let s;
535         let l = 0.5 * add;
536
537         if (min === max)
538             h = 0;
539         else if (r === max)
540             h = ((60 * (g - b) / diff) + 360) % 360;
541         else if (g === max)
542             h = (60 * (b - r) / diff) + 120;
543         else
544             h = (60 * (r - g) / diff) + 240;
545
546         if (l === 0)
547             s = 0;
548         else if (l === 1)
549             s = 1;
550         else if (l <= 0.5)
551             s = diff / add;
552         else
553             s = diff / (2 - add);
554
555         return [
556             Math.round(h),
557             Math.round(s * 100),
558             Math.round(l * 100)
559         ];
560     }
561
562     _hslToRGB(hsl)
563     {
564         let h = parseFloat(hsl[0]) / 360;
565         let s = parseFloat(hsl[1]) / 100;
566         let l = parseFloat(hsl[2]) / 100;
567
568         h *= 6;
569         let sArray = [
570             l += s *= l < .5 ? l : 1 - l,
571             l - h % 1 * s * 2,
572             l -= s *= 2,
573             l,
574             l + h % 1 * s,
575             l + s
576         ];
577         return [
578             Math.round(sArray[ ~~h      % 6 ] * 255),
579             Math.round(sArray[ (h | 16) % 6 ] * 255),
580             Math.round(sArray[ (h | 8)  % 6 ] * 255)
581         ];
582     }
583
584     _rgbaToHSLA(rgba)
585     {
586         let hsl = this._rgbToHSL(rgba);
587         hsl.push(rgba[3]);
588         return hsl;
589     }
590
591     _hslaToRGBA(hsla)
592     {
593         let rgba = this._hslToRGB(hsla);
594         rgba.push(hsla[3]);
595         return rgba;
596     }
597 };
598
599 WebInspector.Color.Format = {
600     Original: "color-format-original",
601     Keyword: "color-format-keyword",
602     HEX: "color-format-hex",
603     ShortHEX: "color-format-short-hex",
604     HEXAlpha: "color-format-hex-alpha",
605     ShortHEXAlpha: "color-format-short-hex-alpha",
606     RGB: "color-format-rgb",
607     RGBA: "color-format-rgba",
608     HSL: "color-format-hsl",
609     HSLA: "color-format-hsla"
610 };
611
612 WebInspector.Color.Keywords = {
613     "aliceblue": [240, 248, 255],
614     "antiquewhite": [250, 235, 215],
615     "aquamarine": [127, 255, 212],
616     "azure": [240, 255, 255],
617     "beige": [245, 245, 220],
618     "bisque": [255, 228, 196],
619     "black": [0, 0, 0],
620     "blanchedalmond": [255, 235, 205],
621     "blue": [0, 0, 255],
622     "blueviolet": [138, 43, 226],
623     "brown": [165, 42, 42],
624     "burlywood": [222, 184, 135],
625     "cadetblue": [95, 158, 160],
626     "chartreuse": [127, 255, 0],
627     "chocolate": [210, 105, 30],
628     "coral": [255, 127, 80],
629     "cornflowerblue": [100, 149, 237],
630     "cornsilk": [255, 248, 220],
631     "crimson": [237, 164, 61],
632     "cyan": [0, 255, 255],
633     "darkblue": [0, 0, 139],
634     "darkcyan": [0, 139, 139],
635     "darkgoldenrod": [184, 134, 11],
636     "darkgray": [169, 169, 169],
637     "darkgreen": [0, 100, 0],
638     "darkkhaki": [189, 183, 107],
639     "darkmagenta": [139, 0, 139],
640     "darkolivegreen": [85, 107, 47],
641     "darkorange": [255, 140, 0],
642     "darkorchid": [153, 50, 204],
643     "darkred": [139, 0, 0],
644     "darksalmon": [233, 150, 122],
645     "darkseagreen": [143, 188, 143],
646     "darkslateblue": [72, 61, 139],
647     "darkslategray": [47, 79, 79],
648     "darkturquoise": [0, 206, 209],
649     "darkviolet": [148, 0, 211],
650     "deeppink": [255, 20, 147],
651     "deepskyblue": [0, 191, 255],
652     "dimgray": [105, 105, 105],
653     "dodgerblue": [30, 144, 255],
654     "firebrick": [178, 34, 34],
655     "floralwhite": [255, 250, 240],
656     "forestgreen": [34, 139, 34],
657     "gainsboro": [220, 220, 220],
658     "ghostwhite": [248, 248, 255],
659     "gold": [255, 215, 0],
660     "goldenrod": [218, 165, 32],
661     "gray": [128, 128, 128],
662     "green": [0, 128, 0],
663     "greenyellow": [173, 255, 47],
664     "honeydew": [240, 255, 240],
665     "hotpink": [255, 105, 180],
666     "indianred": [205, 92, 92],
667     "indigo": [75, 0, 130],
668     "ivory": [255, 255, 240],
669     "khaki": [240, 230, 140],
670     "lavender": [230, 230, 250],
671     "lavenderblush": [255, 240, 245],
672     "lawngreen": [124, 252, 0],
673     "lemonchiffon": [255, 250, 205],
674     "lightblue": [173, 216, 230],
675     "lightcoral": [240, 128, 128],
676     "lightcyan": [224, 255, 255],
677     "lightgoldenrodyellow": [250, 250, 210],
678     "lightgreen": [144, 238, 144],
679     "lightgrey": [211, 211, 211],
680     "lightpink": [255, 182, 193],
681     "lightsalmon": [255, 160, 122],
682     "lightseagreen": [32, 178, 170],
683     "lightskyblue": [135, 206, 250],
684     "lightslategray": [119, 136, 153],
685     "lightsteelblue": [176, 196, 222],
686     "lightyellow": [255, 255, 224],
687     "lime": [0, 255, 0],
688     "limegreen": [50, 205, 50],
689     "linen": [250, 240, 230],
690     "magenta": [255, 0, 255],
691     "maroon": [128, 0, 0],
692     "mediumaquamarine": [102, 205, 170],
693     "mediumblue": [0, 0, 205],
694     "mediumorchid": [186, 85, 211],
695     "mediumpurple": [147, 112, 219],
696     "mediumseagreen": [60, 179, 113],
697     "mediumslateblue": [123, 104, 238],
698     "mediumspringgreen": [0, 250, 154],
699     "mediumturquoise": [72, 209, 204],
700     "mediumvioletred": [199, 21, 133],
701     "midnightblue": [25, 25, 112],
702     "mintcream": [245, 255, 250],
703     "mistyrose": [255, 228, 225],
704     "moccasin": [255, 228, 181],
705     "navajowhite": [255, 222, 173],
706     "navy": [0, 0, 128],
707     "oldlace": [253, 245, 230],
708     "olive": [128, 128, 0],
709     "olivedrab": [107, 142, 35],
710     "orange": [255, 165, 0],
711     "orangered": [255, 69, 0],
712     "orchid": [218, 112, 214],
713     "palegoldenrod": [238, 232, 170],
714     "palegreen": [152, 251, 152],
715     "paleturquoise": [175, 238, 238],
716     "palevioletred": [219, 112, 147],
717     "papayawhip": [255, 239, 213],
718     "peachpuff": [255, 218, 185],
719     "peru": [205, 133, 63],
720     "pink": [255, 192, 203],
721     "plum": [221, 160, 221],
722     "powderblue": [176, 224, 230],
723     "purple": [128, 0, 128],
724     "rebeccapurple": [102, 51, 153],
725     "red": [255, 0, 0],
726     "rosybrown": [188, 143, 143],
727     "royalblue": [65, 105, 225],
728     "saddlebrown": [139, 69, 19],
729     "salmon": [250, 128, 114],
730     "sandybrown": [244, 164, 96],
731     "seagreen": [46, 139, 87],
732     "seashell": [255, 245, 238],
733     "sienna": [160, 82, 45],
734     "silver": [192, 192, 192],
735     "skyblue": [135, 206, 235],
736     "slateblue": [106, 90, 205],
737     "slategray": [112, 128, 144],
738     "snow": [255, 250, 250],
739     "springgreen": [0, 255, 127],
740     "steelblue": [70, 130, 180],
741     "tan": [210, 180, 140],
742     "teal": [0, 128, 128],
743     "thistle": [216, 191, 216],
744     "tomato": [255, 99, 71],
745     "turquoise": [64, 224, 208],
746     "violet": [238, 130, 238],
747     "wheat": [245, 222, 179],
748     "white": [255, 255, 255],
749     "whitesmoke": [245, 245, 245],
750     "yellow": [255, 255, 0],
751     "yellowgreen": [154, 205, 50]
752 };