From 540e2af62c1dc8d355cb50a975a0c57f8ab56c1e Mon Sep 17 00:00:00 2001 From: tophf Date: Sat, 17 Sep 2022 13:55:44 +0300 Subject: [PATCH] micro-optimize colorConverter.parse #hex, named colors: 15x faster rgb() and other functions: 1.6x faster --- js/color/color-converter.js | 426 ++++++++++++++++++------------------ 1 file changed, 213 insertions(+), 213 deletions(-) diff --git a/js/color/color-converter.js b/js/color/color-converter.js index 61fb8b40..cbe755c7 100644 --- a/js/color/color-converter.js +++ b/js/color/color-converter.js @@ -1,32 +1,23 @@ 'use strict'; -const colorConverter = (() => { +const colorConverter = (NAMED_COLORS => { - const RXS_NUM = /\s*([+-]?(?:\d+\.?\d*|\d*\.\d+))(?:e[+-]?\d+)?/.source; - const RXS_NUM_ANGLE = `${RXS_NUM}(deg|g?rad|turn)?`; + // All groups in RXS_NUM must use ?: in order to enable \1 in RX_COLOR.rgb + const RXS_NUM = /\s*[+-]?(\.\d+|\d+(\.\d*)?)(e[+-]?\d+)?/.source.replace(/\(/g, '(?:'); + const RXS_ANGLE = '(?:deg|g?rad|turn)?'; + const expandRe = re => RegExp(re.source.replace(/N/g, RXS_NUM).replace(/A/g, RXS_ANGLE), 'iy'); const RX_COLOR = { hex: /#([a-f\d]{3}(?:[a-f\d](?:[a-f\d]{2}){0,2})?)\b/iy, - - hsl: new RegExp([ - // num_or_angle, pct, pct [ , num_or_pct]? - `^(${RXS_NUM_ANGLE})\\s*,(${RXS_NUM}%\\s*(,|$)){2}(${RXS_NUM}%?)?\\s*$`, - // num_or_angle pct pct [ / num_or_pct]? - `^(${RXS_NUM_ANGLE})\\s+(${RXS_NUM}%\\s*(\\s|$)){2}(/${RXS_NUM}%?)?\\s*$`, - ].join('|'), 'iy'), - - hwb: new RegExp( - // num|angle|none pct|none pct|none [ / num|pct|none ]? - `^(${RXS_NUM_ANGLE}|none)(\\s+(${RXS_NUM}%|none)){2}(\\s+|$)(/${RXS_NUM}%?|none)?\\s*$`, - 'iy'), - - rgb: new RegExp([ - // num, num, num [ , num_or_pct]? - // pct, pct, pct [ , num_or_pct]? - `^((${RXS_NUM}\\s*(,|$)){3}|(${RXS_NUM}%\\s*(,|$)){3})(${RXS_NUM}%?)?\\s*$`, - // num num num [ / num_or_pct]? - // pct pct pct [ / num_or_pct]? - `^((${RXS_NUM}\\s*(\\s|$)){3}|(${RXS_NUM}%\\s*(\\s|$)){3})(/${RXS_NUM}%?)?\\s*$`, - ].join('|'), 'iy'), + // num_or_angle, pct, pct [ , num_or_pct]? + // num_or_angle pct pct [ / num_or_pct]? + hsl: expandRe(/^NA(\s*(,N%\s*){2}(,N%?\s*)?|(\s+N%){2}\s*(\/N%?\s*)?)$/), + // num_or_angle|none pct|none pct|none [ / num_or_pct|none ]? + hwb: expandRe(/^(NA|none)(\s+(N%|none)){2}\s*(\/(N%?|none)\s*)?$/), + // num, num, num [ , num_or_pct]? + // pct, pct, pct [ , num_or_pct]? + // num num num [ / num_or_pct]? + // pct pct pct [ / num_or_pct]? + rgb: expandRe(/^N(%?)(\s*,N\1\s*,N\1\s*(,N%?\s*)?|\s+N\1\s+N\1\s*(\/N%?\s*)?)$/), }; const ANGLE_TO_DEG = { grad: 360 / 400, @@ -51,6 +42,7 @@ const colorConverter = (() => { 'v' in c ? 'hsv' : 'l' in c ? 'hsl' : undefined; + let HEX; return { parse, @@ -64,8 +56,8 @@ const colorConverter = (() => { snapToInt, testAt, ALPHA_DIGITS: 3, + NAMED_COLORS, RX_COLOR, - // NAMED_COLORS is added below }; function format(color = '', type = color.type, {hexUppercase, usoMode, round} = {}) { @@ -95,45 +87,57 @@ const colorConverter = (() => { } } - function parse(str) { - if (typeof str !== 'string') return; - str = str.trim().toLowerCase(); - if (!str) return; - - if (str[0] !== '#' && !str.includes('(')) { - // eslint-disable-next-line no-use-before-define - str = colorConverter.NAMED_COLORS.get(str); - if (!str) return; + function parse(s) { + if (typeof s !== 'string' || !(s = s.trim())) { + return; + } else if (s[0] === '#') { + return parseHex(s); + } else if (s.endsWith(')') && (s = s.match(/^(hwb|(hsl|rgb)a?)\(\s*([^)]+)/i))) { + return parseFunc((s[2] || s[1]).toLowerCase(), s[3]); + } else { + return colorConverter.NAMED_COLORS.get(s.toLowerCase()); } + } - if (str[0] === '#') { - if (!testAt(RX_COLOR.hex, 0, str)) { - return; - } - str = str.slice(1); - const [r, g, b, a = 255] = str.length <= 4 ? - str.match(/(.)/g).map(c => parseInt(c + c, 16)) : - str.match(/(..)/g).map(c => parseInt(c, 16)); - return { - type: 'hex', - r, - g, - b, - a: a === 255 ? undefined : a / 255, - }; + function initHexMap() { + HEX = Array(256).fill(-0xFFFF); // ensuring a PACKED_SMI array + for (let i = 48; i < 58; i++) HEX[i] = i - 48; // 0123456789 + for (let i = 65; i < 71; i++) HEX[i] = i - 65 + 10; // ABCDEF + for (let i = 97; i < 103; i++) HEX[i] = i - 97 + 10; // abcdef + } + + function parseHex(str) { + if (!HEX) initHexMap(); + let r, g, b, a; + const len = str.length; + if (len === 4 || len === 5 + ? (r = HEX[str.charCodeAt(1)] * 0x11) >= 0 && + (g = HEX[str.charCodeAt(2)] * 0x11) >= 0 && + (b = HEX[str.charCodeAt(3)] * 0x11) >= 0 && + (len < 5 || (a = HEX[str.charCodeAt(4)] * 0x11 / 255) >= 0) + : (len === 7 || len === 9) && + (r = HEX[str.charCodeAt(1)] * 0x10 + HEX[str.charCodeAt(2)]) >= 0 && + (g = HEX[str.charCodeAt(3)] * 0x10 + HEX[str.charCodeAt(4)]) >= 0 && + (b = HEX[str.charCodeAt(5)] * 0x10 + HEX[str.charCodeAt(6)]) >= 0 && + (len < 9 || (a = (HEX[str.charCodeAt(7)] * 0x10 + HEX[str.charCodeAt(8)]) / 255) >= 0) + ) { + return {type: 'hex', r, g, b, a}; } + } - const [, func, type = func, value] = str.match(/^((rgb|hsl)a?|hwb)\(\s*(.*?)\s*\)|$/); - if (!func || !testAt(RX_COLOR[type], 0, value)) { + function parseFunc(type, val) { + if (!testAt(RX_COLOR[type], 0, val)) { return; } - const strings = value.split(/\s*[,/]\s*|\s+/); - const [s1, /*s2*/, /*s3*/, sA] = strings; - const [n1, n2, n3, nA] = strings.map(parseFloat); - const a = isNaN(nA) ? 1 : constrain(0, 1, nA / (sA.endsWith('%') ? 100 : 1)); - + // Not using destructuring because it's slow + const parts = val.trim().split(/\s*[,/]\s*|\s+/); + const n1 = parseFloat(parts[0]); + const n2 = parseFloat(parts[1]); + const n3 = parseFloat(parts[2]); + const nA = parseFloat(parts[3]); + const a = isNaN(nA) ? undefined : constrain(0, 1, parts[3].endsWith('%') ? nA / 100 : nA); if (type === 'rgb') { - const k = s1.endsWith('%') ? 2.55 : 1; + const k = parts[0].endsWith('%') ? 2.55 : 1; return { type, r: constrain(0, 255, Math.round(n1 * k)), @@ -142,8 +146,7 @@ const colorConverter = (() => { a, }; } - - const h = constrainHue(n1 * (ANGLE_TO_DEG[s1.match(/\D*$/)[0]] || 1)); + const h = constrainHue(n1 * (ANGLE_TO_DEG[parts[0].match(/\D*$/)[0].toLowerCase()] || 1)); const n2c = constrain(0, 100, n2 || 0); const n3c = constrain(0, 100, n3 || 0); return type === 'hwb' @@ -268,157 +271,154 @@ const colorConverter = (() => { rx.lastIndex = index; return rx.test(text); } -})(); - -colorConverter.NAMED_COLORS = new Map([ - ['transparent', 'rgba(0, 0, 0, 0)'], - // CSS4 named colors - ['aliceblue', '#f0f8ff'], - ['antiquewhite', '#faebd7'], - ['aqua', '#00ffff'], - ['aquamarine', '#7fffd4'], - ['azure', '#f0ffff'], - ['beige', '#f5f5dc'], - ['bisque', '#ffe4c4'], - ['black', '#000000'], - ['blanchedalmond', '#ffebcd'], - ['blue', '#0000ff'], - ['blueviolet', '#8a2be2'], - ['brown', '#a52a2a'], - ['burlywood', '#deb887'], - ['cadetblue', '#5f9ea0'], - ['chartreuse', '#7fff00'], - ['chocolate', '#d2691e'], - ['coral', '#ff7f50'], - ['cornflowerblue', '#6495ed'], - ['cornsilk', '#fff8dc'], - ['crimson', '#dc143c'], - ['cyan', '#00ffff'], - ['darkblue', '#00008b'], - ['darkcyan', '#008b8b'], - ['darkgoldenrod', '#b8860b'], - ['darkgray', '#a9a9a9'], - ['darkgrey', '#a9a9a9'], - ['darkgreen', '#006400'], - ['darkkhaki', '#bdb76b'], - ['darkmagenta', '#8b008b'], - ['darkolivegreen', '#556b2f'], - ['darkorange', '#ff8c00'], - ['darkorchid', '#9932cc'], - ['darkred', '#8b0000'], - ['darksalmon', '#e9967a'], - ['darkseagreen', '#8fbc8f'], - ['darkslateblue', '#483d8b'], - ['darkslategray', '#2f4f4f'], - ['darkslategrey', '#2f4f4f'], - ['darkturquoise', '#00ced1'], - ['darkviolet', '#9400d3'], - ['deeppink', '#ff1493'], - ['deepskyblue', '#00bfff'], - ['dimgray', '#696969'], - ['dimgrey', '#696969'], - ['dodgerblue', '#1e90ff'], - ['firebrick', '#b22222'], - ['floralwhite', '#fffaf0'], - ['forestgreen', '#228b22'], - ['fuchsia', '#ff00ff'], - ['gainsboro', '#dcdcdc'], - ['ghostwhite', '#f8f8ff'], - ['gold', '#ffd700'], - ['goldenrod', '#daa520'], - ['gray', '#808080'], - ['grey', '#808080'], - ['green', '#008000'], - ['greenyellow', '#adff2f'], - ['honeydew', '#f0fff0'], - ['hotpink', '#ff69b4'], - ['indianred', '#cd5c5c'], - ['indigo', '#4b0082'], - ['ivory', '#fffff0'], - ['khaki', '#f0e68c'], - ['lavender', '#e6e6fa'], - ['lavenderblush', '#fff0f5'], - ['lawngreen', '#7cfc00'], - ['lemonchiffon', '#fffacd'], - ['lightblue', '#add8e6'], - ['lightcoral', '#f08080'], - ['lightcyan', '#e0ffff'], - ['lightgoldenrodyellow', '#fafad2'], - ['lightgray', '#d3d3d3'], - ['lightgrey', '#d3d3d3'], - ['lightgreen', '#90ee90'], - ['lightpink', '#ffb6c1'], - ['lightsalmon', '#ffa07a'], - ['lightseagreen', '#20b2aa'], - ['lightskyblue', '#87cefa'], - ['lightslategray', '#778899'], - ['lightslategrey', '#778899'], - ['lightsteelblue', '#b0c4de'], - ['lightyellow', '#ffffe0'], - ['lime', '#00ff00'], - ['limegreen', '#32cd32'], - ['linen', '#faf0e6'], - ['magenta', '#ff00ff'], - ['maroon', '#800000'], - ['mediumaquamarine', '#66cdaa'], - ['mediumblue', '#0000cd'], - ['mediumorchid', '#ba55d3'], - ['mediumpurple', '#9370db'], - ['mediumseagreen', '#3cb371'], - ['mediumslateblue', '#7b68ee'], - ['mediumspringgreen', '#00fa9a'], - ['mediumturquoise', '#48d1cc'], - ['mediumvioletred', '#c71585'], - ['midnightblue', '#191970'], - ['mintcream', '#f5fffa'], - ['mistyrose', '#ffe4e1'], - ['moccasin', '#ffe4b5'], - ['navajowhite', '#ffdead'], - ['navy', '#000080'], - ['oldlace', '#fdf5e6'], - ['olive', '#808000'], - ['olivedrab', '#6b8e23'], - ['orange', '#ffa500'], - ['orangered', '#ff4500'], - ['orchid', '#da70d6'], - ['palegoldenrod', '#eee8aa'], - ['palegreen', '#98fb98'], - ['paleturquoise', '#afeeee'], - ['palevioletred', '#db7093'], - ['papayawhip', '#ffefd5'], - ['peachpuff', '#ffdab9'], - ['peru', '#cd853f'], - ['pink', '#ffc0cb'], - ['plum', '#dda0dd'], - ['powderblue', '#b0e0e6'], - ['purple', '#800080'], - ['rebeccapurple', '#663399'], - ['red', '#ff0000'], - ['rosybrown', '#bc8f8f'], - ['royalblue', '#4169e1'], - ['saddlebrown', '#8b4513'], - ['salmon', '#fa8072'], - ['sandybrown', '#f4a460'], - ['seagreen', '#2e8b57'], - ['seashell', '#fff5ee'], - ['sienna', '#a0522d'], - ['silver', '#c0c0c0'], - ['skyblue', '#87ceeb'], - ['slateblue', '#6a5acd'], - ['slategray', '#708090'], - ['slategrey', '#708090'], - ['snow', '#fffafa'], - ['springgreen', '#00ff7f'], - ['steelblue', '#4682b4'], - ['tan', '#d2b48c'], - ['teal', '#008080'], - ['thistle', '#d8bfd8'], - ['tomato', '#ff6347'], - ['turquoise', '#40e0d0'], - ['violet', '#ee82ee'], - ['wheat', '#f5deb3'], - ['white', '#ffffff'], - ['whitesmoke', '#f5f5f5'], - ['yellow', '#ffff00'], - ['yellowgreen', '#9acd32'], -]); +})(new Map([ + ['transparent', {r: 0, g: 0, b: 0, a: 0, type: 'rgb'}], + ['aliceblue', {r: 240, g: 248, b: 255, type: 'hex'}], + ['antiquewhite', {r: 250, g: 235, b: 215, type: 'hex'}], + ['aqua', {r: 0, g: 255, b: 255, type: 'hex'}], + ['aquamarine', {r: 127, g: 255, b: 212, type: 'hex'}], + ['azure', {r: 240, g: 255, b: 255, type: 'hex'}], + ['beige', {r: 245, g: 245, b: 220, type: 'hex'}], + ['bisque', {r: 255, g: 228, b: 196, type: 'hex'}], + ['black', {r: 0, g: 0, b: 0, type: 'hex'}], + ['blanchedalmond', {r: 255, g: 235, b: 205, type: 'hex'}], + ['blue', {r: 0, g: 0, b: 255, type: 'hex'}], + ['blueviolet', {r: 138, g: 43, b: 226, type: 'hex'}], + ['brown', {r: 165, g: 42, b: 42, type: 'hex'}], + ['burlywood', {r: 222, g: 184, b: 135, type: 'hex'}], + ['cadetblue', {r: 95, g: 158, b: 160, type: 'hex'}], + ['chartreuse', {r: 127, g: 255, b: 0, type: 'hex'}], + ['chocolate', {r: 210, g: 105, b: 30, type: 'hex'}], + ['coral', {r: 255, g: 127, b: 80, type: 'hex'}], + ['cornflowerblue', {r: 100, g: 149, b: 237, type: 'hex'}], + ['cornsilk', {r: 255, g: 248, b: 220, type: 'hex'}], + ['crimson', {r: 220, g: 20, b: 60, type: 'hex'}], + ['cyan', {r: 0, g: 255, b: 255, type: 'hex'}], + ['darkblue', {r: 0, g: 0, b: 139, type: 'hex'}], + ['darkcyan', {r: 0, g: 139, b: 139, type: 'hex'}], + ['darkgoldenrod', {r: 184, g: 134, b: 11, type: 'hex'}], + ['darkgray', {r: 169, g: 169, b: 169, type: 'hex'}], + ['darkgrey', {r: 169, g: 169, b: 169, type: 'hex'}], + ['darkgreen', {r: 0, g: 100, b: 0, type: 'hex'}], + ['darkkhaki', {r: 189, g: 183, b: 107, type: 'hex'}], + ['darkmagenta', {r: 139, g: 0, b: 139, type: 'hex'}], + ['darkolivegreen', {r: 85, g: 107, b: 47, type: 'hex'}], + ['darkorange', {r: 255, g: 140, b: 0, type: 'hex'}], + ['darkorchid', {r: 153, g: 50, b: 204, type: 'hex'}], + ['darkred', {r: 139, g: 0, b: 0, type: 'hex'}], + ['darksalmon', {r: 233, g: 150, b: 122, type: 'hex'}], + ['darkseagreen', {r: 143, g: 188, b: 143, type: 'hex'}], + ['darkslateblue', {r: 72, g: 61, b: 139, type: 'hex'}], + ['darkslategray', {r: 47, g: 79, b: 79, type: 'hex'}], + ['darkslategrey', {r: 47, g: 79, b: 79, type: 'hex'}], + ['darkturquoise', {r: 0, g: 206, b: 209, type: 'hex'}], + ['darkviolet', {r: 148, g: 0, b: 211, type: 'hex'}], + ['deeppink', {r: 255, g: 20, b: 147, type: 'hex'}], + ['deepskyblue', {r: 0, g: 191, b: 255, type: 'hex'}], + ['dimgray', {r: 105, g: 105, b: 105, type: 'hex'}], + ['dimgrey', {r: 105, g: 105, b: 105, type: 'hex'}], + ['dodgerblue', {r: 30, g: 144, b: 255, type: 'hex'}], + ['firebrick', {r: 178, g: 34, b: 34, type: 'hex'}], + ['floralwhite', {r: 255, g: 250, b: 240, type: 'hex'}], + ['forestgreen', {r: 34, g: 139, b: 34, type: 'hex'}], + ['fuchsia', {r: 255, g: 0, b: 255, type: 'hex'}], + ['gainsboro', {r: 220, g: 220, b: 220, type: 'hex'}], + ['ghostwhite', {r: 248, g: 248, b: 255, type: 'hex'}], + ['gold', {r: 255, g: 215, b: 0, type: 'hex'}], + ['goldenrod', {r: 218, g: 165, b: 32, type: 'hex'}], + ['gray', {r: 128, g: 128, b: 128, type: 'hex'}], + ['grey', {r: 128, g: 128, b: 128, type: 'hex'}], + ['green', {r: 0, g: 128, b: 0, type: 'hex'}], + ['greenyellow', {r: 173, g: 255, b: 47, type: 'hex'}], + ['honeydew', {r: 240, g: 255, b: 240, type: 'hex'}], + ['hotpink', {r: 255, g: 105, b: 180, type: 'hex'}], + ['indianred', {r: 205, g: 92, b: 92, type: 'hex'}], + ['indigo', {r: 75, g: 0, b: 130, type: 'hex'}], + ['ivory', {r: 255, g: 255, b: 240, type: 'hex'}], + ['khaki', {r: 240, g: 230, b: 140, type: 'hex'}], + ['lavender', {r: 230, g: 230, b: 250, type: 'hex'}], + ['lavenderblush', {r: 255, g: 240, b: 245, type: 'hex'}], + ['lawngreen', {r: 124, g: 252, b: 0, type: 'hex'}], + ['lemonchiffon', {r: 255, g: 250, b: 205, type: 'hex'}], + ['lightblue', {r: 173, g: 216, b: 230, type: 'hex'}], + ['lightcoral', {r: 240, g: 128, b: 128, type: 'hex'}], + ['lightcyan', {r: 224, g: 255, b: 255, type: 'hex'}], + ['lightgoldenrodyellow', {r: 250, g: 250, b: 210, type: 'hex'}], + ['lightgray', {r: 211, g: 211, b: 211, type: 'hex'}], + ['lightgrey', {r: 211, g: 211, b: 211, type: 'hex'}], + ['lightgreen', {r: 144, g: 238, b: 144, type: 'hex'}], + ['lightpink', {r: 255, g: 182, b: 193, type: 'hex'}], + ['lightsalmon', {r: 255, g: 160, b: 122, type: 'hex'}], + ['lightseagreen', {r: 32, g: 178, b: 170, type: 'hex'}], + ['lightskyblue', {r: 135, g: 206, b: 250, type: 'hex'}], + ['lightslategray', {r: 119, g: 136, b: 153, type: 'hex'}], + ['lightslategrey', {r: 119, g: 136, b: 153, type: 'hex'}], + ['lightsteelblue', {r: 176, g: 196, b: 222, type: 'hex'}], + ['lightyellow', {r: 255, g: 255, b: 224, type: 'hex'}], + ['lime', {r: 0, g: 255, b: 0, type: 'hex'}], + ['limegreen', {r: 50, g: 205, b: 50, type: 'hex'}], + ['linen', {r: 250, g: 240, b: 230, type: 'hex'}], + ['magenta', {r: 255, g: 0, b: 255, type: 'hex'}], + ['maroon', {r: 128, g: 0, b: 0, type: 'hex'}], + ['mediumaquamarine', {r: 102, g: 205, b: 170, type: 'hex'}], + ['mediumblue', {r: 0, g: 0, b: 205, type: 'hex'}], + ['mediumorchid', {r: 186, g: 85, b: 211, type: 'hex'}], + ['mediumpurple', {r: 147, g: 112, b: 219, type: 'hex'}], + ['mediumseagreen', {r: 60, g: 179, b: 113, type: 'hex'}], + ['mediumslateblue', {r: 123, g: 104, b: 238, type: 'hex'}], + ['mediumspringgreen', {r: 0, g: 250, b: 154, type: 'hex'}], + ['mediumturquoise', {r: 72, g: 209, b: 204, type: 'hex'}], + ['mediumvioletred', {r: 199, g: 21, b: 133, type: 'hex'}], + ['midnightblue', {r: 25, g: 25, b: 112, type: 'hex'}], + ['mintcream', {r: 245, g: 255, b: 250, type: 'hex'}], + ['mistyrose', {r: 255, g: 228, b: 225, type: 'hex'}], + ['moccasin', {r: 255, g: 228, b: 181, type: 'hex'}], + ['navajowhite', {r: 255, g: 222, b: 173, type: 'hex'}], + ['navy', {r: 0, g: 0, b: 128, type: 'hex'}], + ['oldlace', {r: 253, g: 245, b: 230, type: 'hex'}], + ['olive', {r: 128, g: 128, b: 0, type: 'hex'}], + ['olivedrab', {r: 107, g: 142, b: 35, type: 'hex'}], + ['orange', {r: 255, g: 165, b: 0, type: 'hex'}], + ['orangered', {r: 255, g: 69, b: 0, type: 'hex'}], + ['orchid', {r: 218, g: 112, b: 214, type: 'hex'}], + ['palegoldenrod', {r: 238, g: 232, b: 170, type: 'hex'}], + ['palegreen', {r: 152, g: 251, b: 152, type: 'hex'}], + ['paleturquoise', {r: 175, g: 238, b: 238, type: 'hex'}], + ['palevioletred', {r: 219, g: 112, b: 147, type: 'hex'}], + ['papayawhip', {r: 255, g: 239, b: 213, type: 'hex'}], + ['peachpuff', {r: 255, g: 218, b: 185, type: 'hex'}], + ['peru', {r: 205, g: 133, b: 63, type: 'hex'}], + ['pink', {r: 255, g: 192, b: 203, type: 'hex'}], + ['plum', {r: 221, g: 160, b: 221, type: 'hex'}], + ['powderblue', {r: 176, g: 224, b: 230, type: 'hex'}], + ['purple', {r: 128, g: 0, b: 128, type: 'hex'}], + ['rebeccapurple', {r: 102, g: 51, b: 153, type: 'hex'}], + ['red', {r: 255, g: 0, b: 0, type: 'hex'}], + ['rosybrown', {r: 188, g: 143, b: 143, type: 'hex'}], + ['royalblue', {r: 65, g: 105, b: 225, type: 'hex'}], + ['saddlebrown', {r: 139, g: 69, b: 19, type: 'hex'}], + ['salmon', {r: 250, g: 128, b: 114, type: 'hex'}], + ['sandybrown', {r: 244, g: 164, b: 96, type: 'hex'}], + ['seagreen', {r: 46, g: 139, b: 87, type: 'hex'}], + ['seashell', {r: 255, g: 245, b: 238, type: 'hex'}], + ['sienna', {r: 160, g: 82, b: 45, type: 'hex'}], + ['silver', {r: 192, g: 192, b: 192, type: 'hex'}], + ['skyblue', {r: 135, g: 206, b: 235, type: 'hex'}], + ['slateblue', {r: 106, g: 90, b: 205, type: 'hex'}], + ['slategray', {r: 112, g: 128, b: 144, type: 'hex'}], + ['slategrey', {r: 112, g: 128, b: 144, type: 'hex'}], + ['snow', {r: 255, g: 250, b: 250, type: 'hex'}], + ['springgreen', {r: 0, g: 255, b: 127, type: 'hex'}], + ['steelblue', {r: 70, g: 130, b: 180, type: 'hex'}], + ['tan', {r: 210, g: 180, b: 140, type: 'hex'}], + ['teal', {r: 0, g: 128, b: 128, type: 'hex'}], + ['thistle', {r: 216, g: 191, b: 216, type: 'hex'}], + ['tomato', {r: 255, g: 99, b: 71, type: 'hex'}], + ['turquoise', {r: 64, g: 224, b: 208, type: 'hex'}], + ['violet', {r: 238, g: 130, b: 238, type: 'hex'}], + ['wheat', {r: 245, g: 222, b: 179, type: 'hex'}], + ['white', {r: 255, g: 255, b: 255, type: 'hex'}], + ['whitesmoke', {r: 245, g: 245, b: 245, type: 'hex'}], + ['yellow', {r: 255, g: 255, b: 0, type: 'hex'}], + ['yellowgreen', {r: 154, g: 205, b: 50, type: 'hex'}], +]));