1 // Functions dealing with parsing/stringifying color go here. 2 3 // Create the following with 4 // node ./htmlcanvas/_namedcolors.js --expose-wasm 5 // JS/closure doesn't have a constexpr like thing which 6 // would really help here. Since we don't, we pre-compute 7 // the map, which saves (a tiny amount of) startup time 8 // and (a small amount of) code size. 9 /* @dict */ 10 var colorMap = {'aliceblue':-984833,'antiquewhite':-332841,'aqua':-16711681,'aquamarine':-8388652,'azure':-983041,'beige':-657956,'bisque':-6972,'black':-16777216,'blanchedalmond':-5171,'blue':-16776961,'blueviolet':-7722014,'brown':-5952982,'burlywood':-2180985,'cadetblue':-10510688,'chartreuse':-8388864,'chocolate':-2987746,'coral':-32944,'cornflowerblue':-10185235,'cornsilk':-1828,'crimson':-2354116,'cyan':-16711681,'darkblue':-16777077,'darkcyan':-16741493,'darkgoldenrod':-4684277,'darkgray':-5658199,'darkgreen':-16751616,'darkgrey':-5658199,'darkkhaki':-4343957,'darkmagenta':-7667573,'darkolivegreen':-11179217,'darkorange':-29696,'darkorchid':-6737204,'darkred':-7667712,'darksalmon':-1468806,'darkseagreen':-7357297,'darkslateblue':-12042869,'darkslategray':-13676721,'darkslategrey':-13676721,'darkturquoise':-16724271,'darkviolet':-7077677,'deeppink':-60269,'deepskyblue':-16728065,'dimgray':-9868951,'dimgrey':-9868951,'dodgerblue':-14774017,'firebrick':-5103070,'floralwhite':-1296,'forestgreen':-14513374,'fuchsia':-65281,'gainsboro':-2302756,'ghostwhite':-460545,'gold':-10496,'goldenrod':-2448096,'gray':-8355712,'green':-16744448,'greenyellow':-5374161,'grey':-8355712,'honeydew':-983056,'hotpink':-38476,'indianred':-3318692,'indigo':-11861886,'ivory':-16,'khaki':-989556,'lavender':-1644806,'lavenderblush':-3851,'lawngreen':-8586240,'lemonchiffon':-1331,'lightblue':-5383962,'lightcoral':-1015680,'lightcyan':-2031617,'lightgoldenrodyellow':-329006,'lightgray':-2894893,'lightgreen':-7278960,'lightgrey':-2894893,'lightpink':-18751,'lightsalmon':-24454,'lightseagreen':-14634326,'lightskyblue':-7876870,'lightslategray':-8943463,'lightslategrey':-8943463,'lightsteelblue':-5192482,'lightyellow':-32,'lime':-16711936,'limegreen':-13447886,'linen':-331546,'magenta':-65281,'maroon':-8388608,'mediumaquamarine':-10039894,'mediumblue':-16777011,'mediumorchid':-4565549,'mediumpurple':-7114533,'mediumseagreen':-12799119,'mediumslateblue':-8689426,'mediumspringgreen':-16713062,'mediumturquoise':-12004916,'mediumvioletred':-3730043,'midnightblue':-15132304,'mintcream':-655366,'mistyrose':-6943,'moccasin':-6987,'navajowhite':-8531,'navy':-16777088,'oldlace':-133658,'olive':-8355840,'olivedrab':-9728477,'orange':-23296,'orangered':-47872,'orchid':-2461482,'palegoldenrod':-1120086,'palegreen':-6751336,'paleturquoise':-5247250,'palevioletred':-2396013,'papayawhip':-4139,'peachpuff':-9543,'peru':-3308225,'pink':-16181,'plum':-2252579,'powderblue':-5185306,'purple':-8388480,'rebeccapurple':-10079335,'red':-65536,'rosybrown':-4419697,'royalblue':-12490271,'saddlebrown':-7650029,'salmon':-360334,'sandybrown':-744352,'seagreen':-13726889,'seashell':-2578,'sienna':-6270419,'silver':-4144960,'skyblue':-7876885,'slateblue':-9807155,'slategray':-9404272,'slategrey':-9404272,'snow':-1286,'springgreen':-16711809,'steelblue':-12156236,'tan':-2968436,'teal':-16744320,'thistle':-2572328,'transparent':0,'tomato':-40121,'turquoise':-12525360,'violet':-1146130,'wheat':-663885,'white':-1,'whitesmoke':-657931,'yellow':-256,'yellowgreen':-6632142}; 11 12 function colorToString(skcolor) { 13 // https://html.spec.whatwg.org/multipage/canvas.html#serialisation-of-a-color 14 var components = CanvasKit.getColorComponents(skcolor); 15 var r = components[0]; 16 var g = components[1]; 17 var b = components[2]; 18 var a = components[3]; 19 if (a === 1.0) { 20 // hex 21 r = r.toString(16).toLowerCase(); 22 g = g.toString(16).toLowerCase(); 23 b = b.toString(16).toLowerCase(); 24 r = (r.length === 1 ? '0'+r: r); 25 g = (g.length === 1 ? '0'+g: g); 26 b = (b.length === 1 ? '0'+b: b); 27 return '#'+r+g+b; 28 } else { 29 a = (a === 0 || a === 1) ? a : a.toFixed(8); 30 return 'rgba('+r+', '+g+', '+b+', '+a+')'; 31 } 32 } 33 34 function valueOrPercent(aStr) { 35 var a = parseFloat(aStr) || 1; 36 if (aStr && aStr.indexOf('%') !== -1) { 37 return a / 100; 38 } 39 return a; 40 } 41 42 function parseColor(colorStr) { 43 colorStr = colorStr.toLowerCase(); 44 // See https://drafts.csswg.org/css-color/#typedef-hex-color 45 if (colorStr.startsWith('#')) { 46 var r, g, b, a = 255; 47 switch (colorStr.length) { 48 case 9: // 8 hex chars #RRGGBBAA 49 a = parseInt(colorStr.slice(7, 9), 16); 50 case 7: // 6 hex chars #RRGGBB 51 r = parseInt(colorStr.slice(1, 3), 16); 52 g = parseInt(colorStr.slice(3, 5), 16); 53 b = parseInt(colorStr.slice(5, 7), 16); 54 break; 55 case 5: // 4 hex chars #RGBA 56 // multiplying by 17 is the same effect as 57 // appending another character of the same value 58 // e.g. e => ee == 14 => 238 59 a = parseInt(colorStr.slice(4, 5), 16) * 17; 60 case 4: // 6 hex chars #RGB 61 r = parseInt(colorStr.slice(1, 2), 16) * 17; 62 g = parseInt(colorStr.slice(2, 3), 16) * 17; 63 b = parseInt(colorStr.slice(3, 4), 16) * 17; 64 break; 65 } 66 return CanvasKit.Color(r, g, b, a/255); 67 68 } else if (colorStr.startsWith('rgba')) { 69 // Trim off rgba( and the closing ) 70 colorStr = colorStr.slice(5, -1); 71 var nums = colorStr.split(','); 72 return CanvasKit.Color(+nums[0], +nums[1], +nums[2], 73 valueOrPercent(nums[3])); 74 } else if (colorStr.startsWith('rgb')) { 75 // Trim off rgba( and the closing ) 76 colorStr = colorStr.slice(4, -1); 77 var nums = colorStr.split(','); 78 // rgb can take 3 or 4 arguments 79 return CanvasKit.Color(+nums[0], +nums[1], +nums[2], 80 valueOrPercent(nums[3])); 81 } else if (colorStr.startsWith('gray(')) { 82 // TODO 83 } else if (colorStr.startsWith('hsl')) { 84 // TODO 85 } else { 86 // Try for named color 87 var nc = colorMap[colorStr]; 88 if (nc !== undefined) { 89 return nc; 90 } 91 } 92 SkDebug('unrecognized color ' + colorStr); 93 return CanvasKit.BLACK; 94 } 95 96 CanvasKit._testing['parseColor'] = parseColor; 97 CanvasKit._testing['colorToString'] = colorToString; 98