swc_css_compat/compiler/
legacy_rgb_and_hsl.rs

1use std::f64::consts::PI;
2
3use swc_css_ast::{
4    matches_eq_ignore_ascii_case, AbsoluteColorBase, AlphaValue, Angle, ComponentValue, Number,
5    Percentage,
6};
7use swc_css_utils::{clamp_unit_f64, round_alpha};
8
9use crate::compiler::Compiler;
10
11impl Compiler {
12    pub(crate) fn process_rgb_and_hsl(&mut self, n: &mut AbsoluteColorBase) {
13        if let AbsoluteColorBase::Function(function) = n {
14            let is_rgb = matches_eq_ignore_ascii_case!(function.name.as_str(), "rgb", "rgba");
15            let is_hsl = matches_eq_ignore_ascii_case!(function.name.as_str(), "hsl", "hsla");
16
17            if is_rgb {
18                function.value = function
19                    .value
20                    .drain(..)
21                    .map(|n| match n {
22                        ComponentValue::Percentage(percentage) => {
23                            let Percentage {
24                                span,
25                                value: Number { value, .. },
26                                ..
27                            } = &*percentage;
28
29                            ComponentValue::Number(Box::new(Number {
30                                span: *span,
31                                value: clamp_unit_f64(value / 100.0) as f64,
32                                raw: None,
33                            }))
34                        }
35                        _ => n,
36                    })
37                    .collect();
38            } else if is_hsl {
39                function.value = function
40                    .value
41                    .drain(..)
42                    .map(|n| {
43                        if let Some(Angle {
44                            span,
45                            value: Number { value, .. },
46                            unit,
47                            ..
48                        }) = n.as_hue().and_then(|hue| hue.as_angle())
49                        {
50                            let value = match &*unit.value.to_ascii_lowercase() {
51                                "deg" => *value,
52                                "grad" => value * 180.0 / 200.0,
53                                "rad" => value * 180.0 / PI,
54                                "turn" => value * 360.0,
55                                _ => {
56                                    unreachable!();
57                                }
58                            };
59
60                            ComponentValue::Number(Box::new(Number {
61                                span: *span,
62                                value: value.round(),
63                                raw: None,
64                            }))
65                        } else {
66                            n
67                        }
68                    })
69                    .collect();
70            }
71
72            if is_rgb || is_hsl {
73                if let Some(alpha_value) = function
74                    .value
75                    .last_mut()
76                    .and_then(|component_value| component_value.as_mut_alpha_value())
77                    .map(|alpha_value| alpha_value.as_mut())
78                {
79                    if let AlphaValue::Percentage(Percentage {
80                        span,
81                        value: Number { value: a, .. },
82                        ..
83                    }) = alpha_value
84                    {
85                        *alpha_value = AlphaValue::Number(Number {
86                            span: *span,
87                            value: round_alpha(*a / 100.0),
88                            raw: None,
89                        });
90                    }
91                }
92            }
93        }
94    }
95}