@@ -16,16 +16,16 @@ pub enum Color {
16
16
// Return None on invalid/unsupported value (not a color)
17
17
pub fn parse_color ( component_value : & ComponentValue ) -> Option < Color > {
18
18
match * component_value {
19
- Hash ( ref value) | IDHash ( ref value) => parse_hash_color ( * value) ,
20
- Ident ( ref value) => parse_keyword_color ( * value) ,
21
- Function ( ref name, ref arguments) => parse_function_color ( * name, * arguments) ,
19
+ Hash ( ref value) | IDHash ( ref value) => parse_color_hash ( * value) ,
20
+ Ident ( ref value) => parse_color_keyword ( * value) ,
21
+ Function ( ref name, ref arguments) => parse_color_function ( * name, * arguments) ,
22
22
_ => None
23
23
}
24
24
}
25
25
26
26
27
27
#[ inline]
28
- fn parse_keyword_color ( value : & str ) -> Option < Color > {
28
+ fn parse_color_keyword ( value : & str ) -> Option < Color > {
29
29
let lower_value = to_ascii_lower ( value) ;
30
30
match COLOR_KEYWORDS . bsearch_elem ( & lower_value. as_slice ( ) ) {
31
31
Some ( index) => Some ( COLOR_VALUES [ index] ) ,
@@ -36,7 +36,7 @@ fn parse_keyword_color(value: &str) -> Option<Color> {
36
36
37
37
38
38
#[ inline]
39
- fn parse_hash_color ( value : & str ) -> Option < Color > {
39
+ fn parse_color_hash ( value : & str ) -> Option < Color > {
40
40
macro_rules! from_hex(
41
41
( $c: expr) => { {
42
42
let c = $c;
@@ -72,9 +72,98 @@ fn parse_hash_color(value: &str) -> Option<Color> {
72
72
73
73
74
74
#[ inline]
75
- fn parse_function_color ( name : & str , arguments : & [ ( ComponentValue , SourceLocation ) ] )
75
+ fn parse_color_function ( name : & str , arguments : & [ ( ComponentValue , SourceLocation ) ] )
76
76
-> Option < Color > {
77
- let _lower_name = to_ascii_lower ( name) ;
78
- let _iter = arguments. iter ( ) ;
79
- None // TODO
77
+ let lower_name = to_ascii_lower ( name) ;
78
+
79
+ let ( is_rgb, has_alpha) =
80
+ if "rgba" == lower_name { ( true , true ) }
81
+ else if "rgb" == lower_name { ( true , false ) }
82
+ else if "hsl" == lower_name { ( false , false ) }
83
+ else if "hsla" == lower_name { ( false , true ) }
84
+ else { return None } ;
85
+
86
+ let mut iter = do arguments. iter ( ) . filter_map |& ( ref c, _) | {
87
+ if c != & WhiteSpace { Some ( c) } else { None }
88
+ } ;
89
+ macro_rules! expect_comma(
90
+ ( ) => ( if iter. next( ) != Some ( & Comma ) { return None } ) ;
91
+ )
92
+ macro_rules! expect_percentage(
93
+ ( ) => ( match iter. next( ) {
94
+ Some ( & Percentage ( ref v) ) => v. value,
95
+ _ => return None ,
96
+ } ) ;
97
+ )
98
+ macro_rules! expect_integer(
99
+ ( ) => ( match iter. next( ) {
100
+ Some ( & Number ( ref v) ) if v. int_value. is_some( ) => v. value,
101
+ _ => return None ,
102
+ } ) ;
103
+ )
104
+ macro_rules! expect_number(
105
+ ( ) => ( match iter. next( ) {
106
+ Some ( & Number ( ref v) ) => v. value,
107
+ _ => return None ,
108
+ } ) ;
109
+ )
110
+
111
+ let red: ColorFloat ;
112
+ let green: ColorFloat ;
113
+ let blue: ColorFloat ;
114
+ if is_rgb {
115
+ // Either integers or percentages, but all the same type.
116
+ match iter. next ( ) {
117
+ Some ( & Number ( ref v) ) if v. int_value . is_some ( ) => {
118
+ red = v. value / 255. ;
119
+ expect_comma ! ( ) ;
120
+ green = expect_integer ! ( ) / 255. ;
121
+ expect_comma ! ( ) ;
122
+ blue = expect_integer ! ( ) / 255. ;
123
+ }
124
+ Some ( & Percentage ( ref v) ) => {
125
+ red = v. value / 100. ;
126
+ expect_comma ! ( ) ;
127
+ green = expect_percentage ! ( ) / 100. ;
128
+ expect_comma ! ( ) ;
129
+ blue = expect_percentage ! ( ) / 100. ;
130
+ }
131
+ _ => return None
132
+ } ;
133
+ } else {
134
+ let hue: ColorFloat = expect_number ! ( ) / 360. ;
135
+ let hue = hue - hue. floor ( ) ;
136
+ expect_comma ! ( ) ;
137
+ let saturation: ColorFloat = ( expect_percentage ! ( ) / 100. ) . max ( & 0. ) . min ( & 1. ) ;
138
+ expect_comma ! ( ) ;
139
+ let lightness: ColorFloat = ( expect_percentage ! ( ) / 100. ) . max ( & 0. ) . min ( & 1. ) ;
140
+
141
+ // http://www.w3.org/TR/css3-color/#hsl-color
142
+ fn hue_to_rgb ( m1 : ColorFloat , m2 : ColorFloat , mut h : ColorFloat ) -> ColorFloat {
143
+ if h < 0. { h += 1. }
144
+ if h > 1. { h -= 1. }
145
+
146
+ if h * 6. < 1. { m1 + ( m2 - m1) * h * 6. }
147
+ else if h * 2. < 1. { m2 }
148
+ else if h * 3. < 2. { m1 + ( m2 - m1) * ( 2. / 3. - h) * 6. }
149
+ else { m1 }
150
+ }
151
+ let m2 = if lightness <= 0.5 { lightness * ( saturation + 1. ) }
152
+ else { lightness + saturation - lightness * saturation } ;
153
+ let m1 = lightness * 2. - m2;
154
+ red = hue_to_rgb ( m1, m2, hue + 1. / 3. ) ;
155
+ green = hue_to_rgb ( m1, m2, hue) ;
156
+ blue = hue_to_rgb ( m1, m2, hue - 1. / 3. ) ;
157
+ }
158
+
159
+ let alpha = if has_alpha {
160
+ expect_comma ! ( ) ;
161
+ match iter. next ( ) {
162
+ Some ( & Number ( ref a) ) => a. value . max ( & 0. ) . min ( & 1. ) ,
163
+ _ => return None
164
+ }
165
+ } else {
166
+ 1.
167
+ } ;
168
+ if iter. next ( ) . is_none ( ) { Some ( RGBA ( red, green, blue, alpha) ) } else { None }
80
169
}
0 commit comments