/
color_hex_alpha.rs
127 lines (112 loc) · 4.02 KB
/
color_hex_alpha.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use swc_atoms::js_word;
use swc_common::DUMMY_SP;
use swc_css_ast::{
AbsoluteColorBase, AlphaValue, Color, ComponentValue, Delimiter, DelimiterValue, Function,
Ident, Number,
};
use crate::compiler::{utils::round_alpha, Compiler};
#[inline]
fn from_hex(c: u8) -> u8 {
match c {
b'0'..=b'9' => c - b'0',
b'a'..=b'f' => c - b'a' + 10,
b'A'..=b'F' => c - b'A' + 10,
_ => {
unreachable!();
}
}
}
fn shorten_hex_color(value: &str) -> Option<&str> {
let length = value.len();
let chars = value.as_bytes();
if length == 8 && chars[6] == b'f' && chars[7] == b'f' {
return Some(&value[0..6]);
} else if length == 4 && chars[3] == b'f' {
return Some(&value[0..3]);
}
None
}
fn hex_to_rgba(hex: &str) -> (u8, u8, u8, f64) {
let hex = hex.as_bytes();
match hex.len() {
8 => {
let r = from_hex(hex[0]) * 16 + from_hex(hex[1]);
let g = from_hex(hex[2]) * 16 + from_hex(hex[3]);
let b = from_hex(hex[4]) * 16 + from_hex(hex[5]);
let a = (from_hex(hex[6]) * 16 + from_hex(hex[7])) as f64 / 255.0;
(r, g, b, a)
}
4 => {
let r = from_hex(hex[0]) * 17;
let g = from_hex(hex[1]) * 17;
let b = from_hex(hex[2]) * 17;
let a = (from_hex(hex[3]) * 17) as f64 / 255.0;
(r, g, b, a)
}
_ => {
unreachable!()
}
}
}
impl Compiler {
pub(crate) fn process_color_hex_alpha(&mut self, n: &mut ComponentValue) {
if let ComponentValue::Color(box Color::AbsoluteColorBase(AbsoluteColorBase::HexColor(
hex_color,
))) = n
{
if hex_color.value.len() != 4 && hex_color.value.len() != 8 {
return;
}
if let Some(shortened) = shorten_hex_color(&hex_color.value) {
hex_color.value = shortened.into();
hex_color.raw = None;
return;
}
let rgba = hex_to_rgba(&hex_color.value);
*n = ComponentValue::Color(Box::new(Color::AbsoluteColorBase(
AbsoluteColorBase::Function(Function {
span: hex_color.span,
name: Ident {
span: DUMMY_SP,
value: js_word!("rgba"),
raw: None,
},
value: vec![
ComponentValue::Number(Box::new(Number {
span: DUMMY_SP,
value: rgba.0 as f64,
raw: None,
})),
ComponentValue::Delimiter(Box::new(Delimiter {
span: DUMMY_SP,
value: DelimiterValue::Comma,
})),
ComponentValue::Number(Box::new(Number {
span: DUMMY_SP,
value: rgba.1 as f64,
raw: None,
})),
ComponentValue::Delimiter(Box::new(Delimiter {
span: DUMMY_SP,
value: DelimiterValue::Comma,
})),
ComponentValue::Number(Box::new(Number {
span: DUMMY_SP,
value: rgba.2 as f64,
raw: None,
})),
ComponentValue::Delimiter(Box::new(Delimiter {
span: DUMMY_SP,
value: DelimiterValue::Comma,
})),
ComponentValue::AlphaValue(Box::new(AlphaValue::Number(Number {
span: DUMMY_SP,
value: round_alpha(rgba.3),
raw: None,
}))),
],
}),
)));
}
}
}