1use super::*;
4
5pub(crate) fn parse_rgb_component(s: &str) -> u32 {
9 let t = s.trim();
10 if let Some(pct) = t.strip_suffix('%') {
11 let p = pct.trim().parse::<f32>().unwrap_or(0.0);
12 let p = if p.is_finite() { p } else { 0.0 };
13 ((p / 100.0) * 255.0).clamp(0.0, 255.0) as u32
14 } else {
15 let val = t.parse::<f32>().unwrap_or(0.0);
16 let val = if val.is_finite() { val } else { 0.0 };
17 val.clamp(0.0, 255.0) as u32
18 }
19}
20
21pub fn parse_color(s: &str) -> Option<u32> {
22 let s_trim = s.trim();
23 if s_trim.is_empty() {
24 return None;
25 }
26
27 if let Some(hex) = s_trim.strip_prefix('#') {
29 let bytes = hex.as_bytes();
30 let from_hex_digit = |b: u8| -> Option<u32> {
31 match b {
32 b'0'..=b'9' => Some((b - b'0') as u32),
33 b'a'..=b'f' => Some((b - b'a' + 10) as u32),
34 b'A'..=b'F' => Some((b - b'A' + 10) as u32),
35 _ => None,
36 }
37 };
38
39 if bytes.len() == 8 {
40 let mut val = 0u32;
41 for &b in bytes {
42 val = (val << 4) | from_hex_digit(b)?;
43 }
44 let r = (val >> 24) & 0xFF;
45 let g = (val >> 16) & 0xFF;
46 let b = (val >> 8) & 0xFF;
47 let a = val & 0xFF;
48 return Some((a << 24) | (r << 16) | (g << 8) | b);
49 } else if bytes.len() == 6 {
50 let mut val = 0u32;
51 for &b in bytes {
52 val = (val << 4) | from_hex_digit(b)?;
53 }
54 return Some(0xFF000000 | val);
55 } else if bytes.len() == 3 {
56 let r = from_hex_digit(bytes[0])?;
57 let g = from_hex_digit(bytes[1])?;
58 let b = from_hex_digit(bytes[2])?;
59 let r_byte = (r << 4) | r;
60 let g_byte = (g << 4) | g;
61 let b_byte = (b << 4) | b;
62 return Some(0xFF000000 | (r_byte << 16) | (g_byte << 8) | b_byte);
63 } else if bytes.len() == 4 {
64 let r = from_hex_digit(bytes[0])?;
65 let g = from_hex_digit(bytes[1])?;
66 let b = from_hex_digit(bytes[2])?;
67 let a = from_hex_digit(bytes[3])?;
68 let r_byte = (r << 4) | r;
69 let g_byte = (g << 4) | g;
70 let b_byte = (b << 4) | b;
71 let a_byte = (a << 4) | a;
72 return Some((a_byte << 24) | (r_byte << 16) | (g_byte << 8) | b_byte);
73 }
74 return None;
75 }
76
77 let s_lower = s_trim.to_lowercase();
78
79 if let Some(inner) = s_lower.strip_prefix("light-dark(").and_then(|s| s.strip_suffix(')')) {
84 let mut depth = 0i32;
85 let mut split_at = None;
86 for (i, ch) in inner.char_indices() {
87 match ch {
88 '(' => depth += 1,
89 ')' => depth -= 1,
90 ',' if depth == 0 => {
91 split_at = Some(i);
92 break;
93 }
94 _ => {}
95 }
96 }
97 if let Some(i) = split_at {
98 let light = inner.get(..i).unwrap_or("").trim();
99 let dark = inner.get(i + 1..).unwrap_or("").trim();
100 let is_dark = PREFERS_DARK.load(AtomicOrd::Relaxed);
101 return parse_color(if is_dark { dark } else { light });
102 }
103 return None;
104 }
105
106 if let Some(inner) = s_lower
111 .strip_prefix("oklab(")
112 .or_else(|| s_lower.strip_prefix("oklch("))
113 .and_then(|s| s.strip_suffix(')'))
114 {
115 let is_lch = s_lower.starts_with("oklch(");
116 let parts: alloc::vec::Vec<&str> = if inner.contains(',') {
117 inner.split(',').collect()
118 } else {
119 inner.split_whitespace().filter(|s| *s != "/").collect()
120 };
121 if parts.len() >= 3 {
122 let parse_l = |s: &str| -> f32 {
123 let s = s.trim();
124 if let Some(pct) = s.strip_suffix('%') {
125 pct.parse::<f32>().unwrap_or(0.0) / 100.0
126 } else {
127 s.parse::<f32>().unwrap_or(0.0)
128 }
129 };
130 let l = parse_l(parts[0]);
131 let (ok_a, ok_b) = if is_lch {
132 let c = parse_l(parts[1]).max(0.0);
133 let h_deg = parts[2]
134 .trim()
135 .trim_end_matches("deg")
136 .parse::<f32>()
137 .unwrap_or(0.0);
138 let h_rad = h_deg * core::f32::consts::PI / 180.0;
139 (c * libm::cosf(h_rad), c * libm::sinf(h_rad))
140 } else {
141 (parse_l(parts[1]), parse_l(parts[2]))
142 };
143 let a_val = if parts.len() >= 4 {
144 let a_str = parts[3].trim();
145 if let Some(pct) = a_str.strip_suffix('%') {
146 pct.parse::<f32>().unwrap_or(100.0) / 100.0
147 } else {
148 a_str.parse::<f32>().unwrap_or(1.0)
149 }
150 } else {
151 1.0
152 };
153 let l_ = l + 0.396_337_78 * ok_a + 0.215_803_76 * ok_b;
154 let m_ = l - 0.105_561_346 * ok_a - 0.063_854_17 * ok_b;
155 let s_ = l - 0.089_484_18 * ok_a - 1.291_485_5 * ok_b;
156 let (l3, m3, s3) = (l_ * l_ * l_, m_ * m_ * m_, s_ * s_ * s_);
157 let lin_r = 4.076_741_7 * l3 - 3.307_711_6 * m3 + 0.230_969_93 * s3;
158 let lin_g = -1.268_438 * l3 + 2.609_757_4 * m3 - 0.341_319_4 * s3;
159 let lin_b = -0.004_196_086_3 * l3 - 0.703_418_6 * m3 + 1.707_614_7 * s3;
160 let to_srgb = |c: f32| -> u32 {
162 let c = c.clamp(0.0, 1.0);
163 let enc = if c <= 0.003_130_8 {
164 c * 12.92
165 } else {
166 1.055 * libm::powf(c, 1.0 / 2.4) - 0.055
167 };
168 libm::roundf((enc * 255.0).clamp(0.0, 255.0)) as u32
172 };
173 let r = to_srgb(lin_r);
174 let g = to_srgb(lin_g);
175 let b_out = to_srgb(lin_b);
176 let a = (a_val * 255.0).clamp(0.0, 255.0) as u32;
177 return Some((a << 24) | (r << 16) | (g << 8) | b_out);
178 }
179 }
180
181 if let Some(inner) = s_lower.strip_prefix("hwb(").and_then(|s| s.strip_suffix(')')) {
184 let parts: alloc::vec::Vec<&str> = if inner.contains(',') {
185 inner.split(',').collect()
186 } else {
187 inner.split_whitespace().filter(|s| *s != "/").collect()
188 };
189 if parts.len() >= 3 {
190 let h_raw = parts[0]
191 .trim()
192 .trim_end_matches("deg")
193 .parse::<f32>()
194 .unwrap_or(0.0);
195 let h = ((h_raw % 360.0) + 360.0) % 360.0;
197 let mut w = parts[1]
198 .trim()
199 .trim_end_matches('%')
200 .parse::<f32>()
201 .unwrap_or(0.0)
202 / 100.0;
203 let mut bl = parts[2]
204 .trim()
205 .trim_end_matches('%')
206 .parse::<f32>()
207 .unwrap_or(0.0)
208 / 100.0;
209 w = w.clamp(0.0, 1.0);
210 bl = bl.clamp(0.0, 1.0);
211 if w + bl > 1.0 {
213 let sum = w + bl;
214 w /= sum;
215 bl /= sum;
216 }
217 let a_val = if parts.len() >= 4 {
218 let a_str = parts[3].trim();
219 if a_str.ends_with('%') {
220 a_str.trim_end_matches('%').parse::<f32>().unwrap_or(100.0) / 100.0
221 } else {
222 a_str.parse::<f32>().unwrap_or(1.0)
223 }
224 } else {
225 1.0
226 };
227 let h_prime = h / 60.0;
228 let x = 1.0 - libm::fabsf(h_prime % 2.0 - 1.0);
229 let (r1, g1, b1) = if h_prime < 1.0 {
230 (1.0, x, 0.0)
231 } else if h_prime < 2.0 {
232 (x, 1.0, 0.0)
233 } else if h_prime < 3.0 {
234 (0.0, 1.0, x)
235 } else if h_prime < 4.0 {
236 (0.0, x, 1.0)
237 } else if h_prime < 5.0 {
238 (x, 0.0, 1.0)
239 } else {
240 (1.0, 0.0, x)
241 };
242 let r = ((r1 * (1.0 - w - bl) + w) * 255.0).clamp(0.0, 255.0) as u32;
243 let g = ((g1 * (1.0 - w - bl) + w) * 255.0).clamp(0.0, 255.0) as u32;
244 let b_out = ((b1 * (1.0 - w - bl) + w) * 255.0).clamp(0.0, 255.0) as u32;
245 let a = (a_val * 255.0).clamp(0.0, 255.0) as u32;
246 return Some((a << 24) | (r << 16) | (g << 8) | b_out);
247 }
248 }
249
250 if let Some(inner) = s_lower.strip_prefix("color(").and_then(|s| s.strip_suffix(')')) {
262 let mut parts = inner.split_whitespace().filter(|s| *s != "/");
263 let space_name = parts.next().unwrap_or("");
264 let Some(space) = crate::os_lib::css::color_space::parse_color_space(space_name) else {
269 return None;
271 };
272 let rest: alloc::vec::Vec<&str> = parts.collect();
273 if rest.len() >= 3 {
274 let parse_c = |s: &str| -> f32 {
275 let s = s.trim();
276 if let Some(pct) = s.strip_suffix('%') {
277 pct.parse::<f32>().unwrap_or(0.0) / 100.0
278 } else {
279 s.parse::<f32>().unwrap_or(0.0)
280 }
281 };
282 let c0 = parse_c(rest[0]);
283 let c1 = parse_c(rest[1]);
284 let c2 = parse_c(rest[2]);
285 let a_val = if rest.len() >= 4 { parse_c(rest[3]) } else { 1.0 };
286 let (lr, lg, lb) = crate::os_lib::css::color_space::components_to_linear_srgb(space, c0, c1, c2);
287 let (r, g, b_out) = crate::os_lib::css::color_space::linear_srgb_to_rgb8(lr, lg, lb);
288 let a = (a_val.clamp(0.0, 1.0) * 255.0) as u32;
289 return Some((a << 24) | (r << 16) | (g << 8) | b_out);
290 }
291 return None;
292 }
293
294 if let Some(inner) = s_lower
303 .strip_prefix("lab(")
304 .or_else(|| s_lower.strip_prefix("lch("))
305 .and_then(|s| s.strip_suffix(')'))
306 {
307 let is_lch = s_lower.starts_with("lch(");
308 let parts: alloc::vec::Vec<&str> = if inner.contains(',') {
309 inner.split(',').collect()
310 } else {
311 inner.split_whitespace().filter(|s| *s != "/").collect()
312 };
313 if parts.len() >= 3 {
314 let l = {
316 let s = parts[0].trim();
317 if let Some(pct) = s.strip_suffix('%') {
318 pct.parse::<f32>().unwrap_or(0.0)
319 } else {
320 s.parse::<f32>().unwrap_or(0.0)
321 }
322 };
323 let p1 = parts[1].trim().trim_end_matches('%').parse::<f32>().unwrap_or(0.0);
324 let p2 = parts[2]
325 .trim()
326 .trim_end_matches("deg")
327 .trim_end_matches('%')
328 .parse::<f32>()
329 .unwrap_or(0.0);
330 let a_val = if parts.len() >= 4 {
331 let s = parts[3].trim();
332 if let Some(pct) = s.strip_suffix('%') {
333 pct.parse::<f32>().unwrap_or(100.0) / 100.0
334 } else {
335 s.parse::<f32>().unwrap_or(1.0)
336 }
337 } else {
338 1.0
339 };
340 let (l, aa, bb) = if is_lch {
341 let h = ((p2 % 360.0) + 360.0) % 360.0;
343 crate::os_lib::css::color_space::lch_to_lab(l, p1, h)
344 } else {
345 (l, p1, p2)
346 };
347 let (lr, lg, lb) = crate::os_lib::css::color_space::lab_to_linear_srgb(l, aa, bb);
348 let (r, g, b_out) = crate::os_lib::css::color_space::linear_srgb_to_rgb8(lr, lg, lb);
349 let a = (a_val.clamp(0.0, 1.0) * 255.0) as u32;
350 return Some((a << 24) | (r << 16) | (g << 8) | b_out);
351 }
352 return None;
353 }
354
355 if s_lower.starts_with("hsl") {
357 let has_alpha = s_lower.starts_with("hsla(");
358 let inner_start = if has_alpha { 5 } else { 4 };
359 if let Some(inner) = s_lower.get(inner_start..) {
360 let inner = inner.trim_end_matches(')');
361 let parts: alloc::vec::Vec<&str> = if inner.contains(',') {
363 inner.split(',').collect()
364 } else {
365 inner.split_whitespace().filter(|s| *s != "/").collect()
366 };
367 if parts.len() >= 3 {
368 let h_raw = parts[0]
373 .trim()
374 .trim_end_matches("deg")
375 .parse::<f32>()
376 .unwrap_or(0.0);
377 let h = ((h_raw % 360.0) + 360.0) % 360.0;
378 let s_pct = parts[1]
379 .trim()
380 .trim_end_matches('%')
381 .parse::<f32>()
382 .unwrap_or(0.0)
383 / 100.0;
384 let l_pct = parts[2]
385 .trim()
386 .trim_end_matches('%')
387 .parse::<f32>()
388 .unwrap_or(0.0)
389 / 100.0;
390 let a_val = if parts.len() >= 4 {
391 let a_str = parts[3].trim();
392 if a_str.ends_with('%') {
393 a_str.trim_end_matches('%').parse::<f32>().unwrap_or(100.0) / 100.0
394 } else {
395 a_str.parse::<f32>().unwrap_or(1.0)
396 }
397 } else {
398 1.0
399 };
400
401 let c = (1.0 - libm::fabsf(2.0 * l_pct - 1.0)) * s_pct;
403 let h_prime = h / 60.0;
404 let x = c * (1.0 - libm::fabsf(h_prime % 2.0 - 1.0));
405 let (r1, g1, b1) = if h_prime < 1.0 {
406 (c, x, 0.0)
407 } else if h_prime < 2.0 {
408 (x, c, 0.0)
409 } else if h_prime < 3.0 {
410 (0.0, c, x)
411 } else if h_prime < 4.0 {
412 (0.0, x, c)
413 } else if h_prime < 5.0 {
414 (x, 0.0, c)
415 } else {
416 (c, 0.0, x)
417 };
418 let m = l_pct - c / 2.0;
419 let r = ((r1 + m) * 255.0).clamp(0.0, 255.0) as u32;
420 let g = ((g1 + m) * 255.0).clamp(0.0, 255.0) as u32;
421 let b = ((b1 + m) * 255.0).clamp(0.0, 255.0) as u32;
422 let a = (a_val * 255.0).clamp(0.0, 255.0) as u32;
423 return Some((a << 24) | (r << 16) | (g << 8) | b);
424 }
425 }
426 }
427
428 if let Some(inner) = s_lower
433 .strip_prefix("color-mix(")
434 .and_then(|s| s.strip_suffix(')'))
435 {
436 if let Some((_space_clause, rest)) = inner.split_once(',') {
437 let segs = split_top_level_commas(rest);
438 if segs.len() == 2 {
439 fn split_color_and_pct(seg: &str) -> (&str, Option<f32>) {
440 let seg = seg.trim();
441 if let Some(ws) = seg.rfind(char::is_whitespace) {
442 let (color_part, pct_part) = seg.split_at(ws);
443 let pct_part = pct_part.trim();
444 if let Some(num) = pct_part.strip_suffix('%') {
445 if let Ok(p) = num.trim().parse::<f32>() {
446 return (color_part.trim(), Some(p));
447 }
448 }
449 }
450 (seg, None)
451 }
452 let (c1_str, p1) = split_color_and_pct(segs[0]);
453 let (c2_str, p2) = split_color_and_pct(segs[1]);
454 let (w1, w2) = match (p1, p2) {
455 (None, None) => (50.0f32, 50.0f32),
456 (Some(a), None) => (a, 100.0 - a),
457 (None, Some(b)) => (100.0 - b, b),
458 (Some(a), Some(b)) => {
459 let sum = a + b;
460 if sum <= 0.0 {
461 (50.0, 50.0)
462 } else {
463 (a / sum * 100.0, b / sum * 100.0)
464 }
465 }
466 };
467 if let (Some(c1), Some(c2)) = (parse_color(c1_str), parse_color(c2_str)) {
468 let mix_channel = |shift: u32| -> u32 {
469 let v1 = ((c1 >> shift) & 0xFF) as f32;
470 let v2 = ((c2 >> shift) & 0xFF) as f32;
471 ((v1 * w1 + v2 * w2) / 100.0).clamp(0.0, 255.0) as u32
472 };
473 let a = mix_channel(24);
474 let r = mix_channel(16);
475 let g = mix_channel(8);
476 let b = mix_channel(0);
477 return Some((a << 24) | (r << 16) | (g << 8) | b);
478 }
479 }
480 }
481 }
482
483 let rgb_inner = s_lower
488 .strip_prefix("rgba(")
489 .or_else(|| s_lower.strip_prefix("rgb("))
490 .and_then(|s| s.strip_suffix(')'));
491 if let Some(inner) = rgb_inner {
492 let parts: Vec<&str> = if inner.contains(',') {
493 inner.split(',').collect()
494 } else {
495 inner.split_whitespace().filter(|s| *s != "/").collect()
496 };
497 if parts.len() >= 3 {
498 let r = parse_rgb_component(parts[0]);
499 let g = parse_rgb_component(parts[1]);
500 let b = parse_rgb_component(parts[2]);
501 let a_val = if parts.len() >= 4 {
502 let a_str = parts[3].trim();
503 if let Some(pct) = a_str.strip_suffix('%') {
504 pct.parse::<f32>().unwrap_or(100.0) / 100.0
505 } else {
506 a_str.parse::<f32>().unwrap_or(1.0)
507 }
508 } else {
509 1.0
510 };
511 let a = (a_val * 255.0).clamp(0.0, 255.0) as u32;
512 return Some((a << 24) | (r << 16) | (g << 8) | b);
513 }
514 }
515
516 match s_lower.as_str() {
518 "black" => Some(0xFF000000),
519 "white" => Some(0xFFFFFFFF),
520 "red" => Some(0xFFFF0000),
521 "lime" => Some(0xFF00FF00),
522 "blue" => Some(0xFF0000FF),
523 "yellow" => Some(0xFFFFFF00),
524 "cyan" | "aqua" => Some(0xFF00FFFF),
525 "magenta" | "fuchsia" => Some(0xFFFF00FF),
526 "silver" => Some(0xFFC0C0C0),
527 "gray" | "grey" => Some(0xFF808080),
528 "maroon" => Some(0xFF800000),
529 "olive" => Some(0xFF808000),
530 "green" => Some(0xFF008000),
531 "purple" => Some(0xFF800080),
532 "teal" => Some(0xFF008080),
533 "navy" => Some(0xFF000080),
534 "orange" => Some(0xFFFFA500),
535 "pink" => Some(0xFFFFC0CB),
536 "brown" => Some(0xFFA52A2A),
537 "coral" => Some(0xFFFF7F50),
538 "tomato" => Some(0xFFFF6347),
539 "gold" => Some(0xFFFFD700),
540 "indigo" => Some(0xFF4B0082),
541 "violet" => Some(0xFFEE82EE),
542 "crimson" => Some(0xFFDC143C),
543 "darkred" => Some(0xFF8B0000),
544 "darkgreen" => Some(0xFF006400),
545 "darkblue" => Some(0xFF00008B),
546 "darkgray" | "darkgrey" => Some(0xFFA9A9A9),
547 "lightgray" | "lightgrey" => Some(0xFFD3D3D3),
548 "lightblue" => Some(0xFFADD8E6),
549 "lightgreen" => Some(0xFF90EE90),
550 "lightyellow" => Some(0xFFFFFFE0),
551 "steelblue" => Some(0xFF4682B4),
552 "slategray" | "slategrey" => Some(0xFF708090),
553 "indianred" => Some(0xFFCD5C5C),
554 "royalblue" => Some(0xFF4169E1),
555 "dodgerblue" => Some(0xFF1E90FF),
556 "skyblue" => Some(0xFF87CEEB),
557 "whitesmoke" => Some(0xFFF5F5F5),
558 "wheat" => Some(0xFFF5DEB3),
559 "tan" => Some(0xFFD2B48C),
560 "salmon" => Some(0xFFFA8072),
561 "plum" => Some(0xFFDDA0DD),
562 "orchid" => Some(0xFFDA70D6),
563 "linen" => Some(0xFFFAF0E6),
564 "khaki" => Some(0xFFF0E68C),
565 "ivory" => Some(0xFFFFFFF0),
566 "honeydew" => Some(0xFFF0FFF0),
567 "hotpink" => Some(0xFFFF69B4),
568 "deeppink" => Some(0xFFFF1493),
569 "beige" => Some(0xFFF5F5DC),
570 "aliceblue" => Some(0xFFF0F8FF),
571 "transparent" => Some(0x00000000),
572 "rebeccapurple" => Some(0xFF663399),
574 "mintcream" => Some(0xFFF5FFFA),
575 "azure" => Some(0xFFF0FFFF),
576 "floralwhite" => Some(0xFFFFFAF0),
577 "ghostwhite" => Some(0xFFF8F8FF),
578 "seashell" => Some(0xFFFFF5EE),
579 "oldlace" => Some(0xFFFDF5E6),
580 "antiquewhite" => Some(0xFFFAEBD7),
581 "bisque" => Some(0xFFFFE4C4),
582 "moccasin" => Some(0xFFFFE4B5),
583 "navajowhite" => Some(0xFFFFDEAD),
584 "papayawhip" => Some(0xFFFFEFD5),
585 "peachpuff" => Some(0xFFFFDAB9),
586 "mistyrose" => Some(0xFFFFE4E1),
587 "lavender" => Some(0xFFE6E6FA),
588 "lavenderblush" => Some(0xFFFFF0F5),
589 "thistle" => Some(0xFFD8BFD8),
590 "powderblue" => Some(0xFFB0E0E6),
591 "lightcyan" => Some(0xFFE0FFFF),
592 "paleturquoise" => Some(0xFFAFEEEE),
593 "turquoise" => Some(0xFF40E0D0),
594 "mediumturquoise" => Some(0xFF48D1CC),
595 "darkturquoise" => Some(0xFF00CED1),
596 "cadetblue" => Some(0xFF5F9EA0),
597 "darkcyan" => Some(0xFF008B8B),
598 "lightseagreen" => Some(0xFF20B2AA),
599 "mediumaquamarine" => Some(0xFF66CDAA),
600 "aquamarine" => Some(0xFF7FFFD4),
601 "springgreen" => Some(0xFF00FF7F),
602 "mediumspringgreen" => Some(0xFF00FA9A),
603 "lawngreen" => Some(0xFF7CFC00),
604 "chartreuse" => Some(0xFF7FFF00),
605 "greenyellow" => Some(0xFFADFF2F),
606 "yellowgreen" => Some(0xFF9ACD32),
607 "darkolivegreen" => Some(0xFF556B2F),
608 "olivedrab" => Some(0xFF6B8E23),
609 "palegreen" => Some(0xFF98FB98),
610 "mediumseagreen" => Some(0xFF3CB371),
611 "seagreen" => Some(0xFF2E8B57),
612 "forestgreen" => Some(0xFF228B22),
613 "limegreen" => Some(0xFF32CD32),
614 "darkkhaki" => Some(0xFFBDB76B),
615 "goldenrod" => Some(0xFFDAA520),
616 "darkgoldenrod" => Some(0xFFB8860B),
617 "saddlebrown" => Some(0xFF8B4513),
618 "sienna" => Some(0xFFA0522D),
619 "peru" => Some(0xFFCD853F),
620 "burlywood" => Some(0xFFDEB887),
621 "sandybrown" => Some(0xFFF4A460),
622 "chocolate" => Some(0xFFD2691E),
623 "rosybrown" => Some(0xFFBC8F8F),
624 "darkmagenta" => Some(0xFF8B008B),
625 "darkviolet" => Some(0xFF9400D3),
626 "blueviolet" => Some(0xFF8A2BE2),
627 "mediumvioletred" => Some(0xFFC71585),
628 "palevioletred" => Some(0xFFDB7093),
629 "mediumorchid" => Some(0xFFBA55D3),
630 "mediumpurple" => Some(0xFF9370DB),
631 "slateblue" => Some(0xFF6A5ACD),
632 "mediumslateblue" => Some(0xFF7B68EE),
633 "darkslateblue" => Some(0xFF483D8B),
634 "midnightblue" => Some(0xFF191970),
635 "cornflowerblue" => Some(0xFF6495ED),
636 "deepskyblue" => Some(0xFF00BFFF),
637 "lightskyblue" => Some(0xFF87CEFA),
638 "lightsteelblue" => Some(0xFFB0C4DE),
639 "darkslategray" | "darkslategrey" => Some(0xFF2F4F4F),
640 "dimgray" | "dimgrey" => Some(0xFF696969),
641 "gainsboro" => Some(0xFFDCDCDC),
642 "snow" => Some(0xFFFFFAFA),
643 "lightcoral" => Some(0xFFF08080),
644 "darksalmon" => Some(0xFFE9967A),
645 "lightsalmon" => Some(0xFFFFA07A),
646 "orangered" => Some(0xFFFF4500),
647 "darkorange" => Some(0xFFFF8C00),
648 "firebrick" => Some(0xFFB22222),
649 "currentcolor" => None, _ => None,
651 }
652}
653