.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / stylelint / lib / rules / color-named / generateColorFuncs.js
1 "use strict";
2
3 // these algorithms are sourced from https://drafts.csswg.org/css-color/#color-conversion-code
4
5 function lin_sRGB(RGB) {
6   // convert an array of sRGB values in the range 0.0 - 1.0
7   // to linear light (un-companded) form.
8   // https://en.wikipedia.org/wiki/SRGB
9   return RGB.map(function(val) {
10     if (val < 0.04045) {
11       return val / 12.92;
12     }
13
14     return Math.pow((val + 0.055) / 1.055, 2.4);
15   });
16 }
17
18 function matrixMultiple3d(matrix, vector) {
19   return [
20     matrix[0][0] * vector[0] +
21       matrix[0][1] * vector[1] +
22       matrix[0][2] * vector[2],
23     matrix[1][0] * vector[0] +
24       matrix[1][1] * vector[1] +
25       matrix[1][2] * vector[2],
26     matrix[2][0] * vector[0] +
27       matrix[2][1] * vector[1] +
28       matrix[2][2] * vector[2]
29   ];
30 }
31
32 function srgb2xyz(srgb) {
33   return matrixMultiple3d(
34     [
35       [0.4124564, 0.3575761, 0.1804375],
36       [0.2126729, 0.7151522, 0.072175],
37       [0.0193339, 0.119192, 0.9503041]
38     ],
39     srgb
40   );
41 }
42
43 function chromaticAdaptationD65_D50(xyz) {
44   return matrixMultiple3d(
45     [
46       [1.0478112, 0.0228866, -0.050127],
47       [0.0295424, 0.9904844, -0.0170491],
48       [-0.0092345, 0.0150436, 0.7521316]
49     ],
50     xyz
51   );
52 }
53
54 function xyz2lab(xyzIn) {
55   // Assuming XYZ is relative to D50, convert to CIE Lab
56   // from CIE standard, which now defines these as a rational fraction
57   const ε = 216 / 24389; // 6^3/29^3
58   const κ = 24389 / 27; // 29^3/3^3
59   const white = [0.9642, 1.0, 0.8249]; // D50 reference white
60
61   // compute xyz, which is XYZ scaled relative to reference white
62   const xyz = xyzIn.map((value, i) => value / white[i]);
63
64   // now compute f
65   const f = xyz.map(
66     value => (value > ε ? Math.cbrt(value) : (κ * value + 16) / 116)
67   );
68
69   return [
70     116 * f[1] - 16, // L
71     500 * (f[0] - f[1]), // a
72     200 * (f[1] - f[2]) // b
73   ];
74 }
75
76 function rgb2hsl(r, g, b) {
77   r /= 255;
78   g /= 255;
79   b /= 255;
80   let h, s, l;
81   const M = Math.max(r, g, b);
82   const m = Math.min(r, g, b);
83   const d = M - m;
84   if (d === 0) {
85     h = 0;
86   } else if (M === r) {
87     h = ((g - b) / d) % 6;
88   } else if (M === g) {
89     h = (b - r) / d + 2;
90   } else {
91     h = (r - g) / d + 4;
92   }
93
94   h *= 60;
95
96   if (h < 0) {
97     h += 360;
98   }
99
100   l = (M + m) / 2;
101
102   if (d === 0) {
103     s = 0;
104   } else {
105     s = d / (1 - Math.abs(2 * l - 1));
106   }
107
108   s *= 100;
109   l *= 100;
110
111   return [Math.round(h), Math.round(s), Math.round(l)];
112 }
113
114 function rgb2hwb(rgb_r, rgb_g, rgb_b) {
115   rgb_r /= 255;
116   rgb_g /= 255;
117   rgb_b /= 255;
118
119   const w = Math.min(rgb_r, rgb_g, rgb_b);
120   const v = Math.max(rgb_r, rgb_g, rgb_b);
121
122   const b = 1 - v;
123
124   if (v === w) {
125     return [0, Math.round(w * 100), Math.round(b * 100)];
126   }
127
128   const f =
129     rgb_r === w ? rgb_g - rgb_b : rgb_g === w ? rgb_b - rgb_r : rgb_r - rgb_g;
130   const i = rgb_r === w ? 3 : rgb_g === w ? 5 : 1;
131
132   return [
133     Math.round((i - f / (v - w)) / 6 * 360) % 360,
134     Math.round(w * 100),
135     Math.round(b * 100)
136   ];
137 }
138
139 function perc255(value) {
140   return Math.round(value * 100 / 255) + "%";
141 }
142
143 function generateColorFuncs(hexString) {
144   if (hexString.length !== 7) {
145     throw new Error(
146       "Invalid hex string color definition (" +
147         hexString +
148         ") - expected 6 character hex string"
149     );
150   }
151   const rgb = [0, 0, 0];
152   for (let i = 0; i < 3; i += 1) {
153     rgb[i] = parseInt(hexString.substr(2 * i + 1, 2), 16);
154   }
155   const hsl = rgb2hsl(rgb[0], rgb[1], rgb[2]);
156   const hwb = rgb2hwb(rgb[0], rgb[1], rgb[2]);
157   const func = [];
158   const rgbStr = rgb[0] + "," + rgb[1] + "," + rgb[2];
159   const rgbPercStr =
160     perc255(rgb[0]) + "," + perc255(rgb[1]) + "," + perc255(rgb[2]);
161   const hslStr = hsl[0] + "," + hsl[1] + "%," + hsl[2] + "%";
162   const hwbStr = hwb[0] + "," + hwb[1] + "%," + hwb[2] + "%";
163
164   // *very* convoluted process, just to be able to establish if the color
165   // is gray -- or not.
166   const linRgb = lin_sRGB([rgb[0] / 255, rgb[1] / 255, rgb[2] / 255]);
167   const xyz_d65 = srgb2xyz(linRgb);
168   const xyz_d50 = chromaticAdaptationD65_D50(xyz_d65);
169   const lab = xyz2lab(xyz_d50);
170
171   func.push("rgb(" + rgbStr + ")");
172   func.push("rgba(" + rgbStr + ",1)");
173   func.push("rgba(" + rgbStr + ",100%)");
174   func.push("rgb(" + rgbPercStr + ")");
175   func.push("rgba(" + rgbPercStr + ",1)");
176   func.push("rgba(" + rgbPercStr + ",100%)");
177   func.push("hsl(" + hslStr + ")");
178   func.push("hsla(" + hslStr + ",1)");
179   func.push("hsla(" + hslStr + ",100%)");
180   func.push("hwb(" + hwbStr + ")");
181   func.push("hwb(" + hwbStr + ",1)");
182   func.push("hwb(" + hwbStr + ",100%)");
183
184   // technically, this should be 0 - but then #808080 wouldn't even be gray
185   if (lab[1] * lab[1] < 0.01 && lab[2] * lab[2] < 0.01) {
186     // yay! gray!
187     const grayStr = Math.round(lab[0]);
188     func.push("gray(" + grayStr + ")");
189     func.push("gray(" + grayStr + ",1)");
190     func.push("gray(" + grayStr + ",100%)");
191     func.push("gray(" + grayStr + "%)");
192     func.push("gray(" + grayStr + "%,1)");
193     func.push("gray(" + grayStr + "%,100%)");
194   }
195   return func;
196 }
197
198 module.exports = generateColorFuncs;