Skip to content

Commit e747f21

Browse files
color: Support CSS Color Level 4 rgb & hsl syntax (servo#113)
1 parent be2503e commit e747f21

File tree

5 files changed

+11861
-31
lines changed

5 files changed

+11861
-31
lines changed

src/color.rs

+72-18
Original file line numberDiff line numberDiff line change
@@ -386,33 +386,50 @@ fn clamp_f32(val: f32) -> u8 {
386386

387387
#[inline]
388388
fn parse_color_function(name: &str, arguments: &mut Parser) -> Result<Color, ()> {
389-
let (is_rgb, has_alpha) = match_ignore_ascii_case! { name,
390-
"rgba" => (true, true),
391-
"rgb" => (true, false),
392-
"hsl" => (false, false),
393-
"hsla" => (false, true),
389+
let is_rgb = match_ignore_ascii_case! { name,
390+
"rgba" => true,
391+
"rgb" => true,
392+
"hsl" => false,
393+
"hsla" => false,
394394
_ => return Err(())
395395
};
396396

397397
let red: u8;
398398
let green: u8;
399399
let blue: u8;
400+
let mut uses_commas = false;
400401
if is_rgb {
401402
// Either integers or percentages, but all the same type.
402403
// https://drafts.csswg.org/css-color/#rgb-functions
403404
match try!(arguments.next()) {
404-
Token::Number(NumericValue { int_value: Some(v), .. }) => {
405-
red = clamp_i32(v);
406-
try!(arguments.expect_comma());
407-
green = clamp_i32(try!(arguments.expect_integer()));
408-
try!(arguments.expect_comma());
409-
blue = clamp_i32(try!(arguments.expect_integer()));
405+
Token::Number(NumericValue { value: v, .. }) => {
406+
red = clamp_i32(v as i32);
407+
green = clamp_i32(match try!(arguments.next()) {
408+
Token::Number(NumericValue { value: v, .. }) => v,
409+
Token::Comma => {
410+
uses_commas = true;
411+
try!(arguments.expect_number())
412+
}
413+
_ => return Err(())
414+
} as i32);
415+
if uses_commas {
416+
try!(arguments.expect_comma());
417+
}
418+
blue = clamp_i32(try!(arguments.expect_number()) as i32);
410419
}
411420
Token::Percentage(ref v) => {
412421
red = clamp_f32(v.unit_value);
413-
try!(arguments.expect_comma());
414-
green = clamp_f32(try!(arguments.expect_percentage()));
415-
try!(arguments.expect_comma());
422+
green = clamp_f32(match try!(arguments.next()) {
423+
Token::Percentage(ref v) => v.unit_value,
424+
Token::Comma => {
425+
uses_commas = true;
426+
try!(arguments.expect_percentage())
427+
}
428+
_ => return Err(())
429+
});
430+
if uses_commas {
431+
try!(arguments.expect_comma());
432+
}
416433
blue = clamp_f32(try!(arguments.expect_percentage()));
417434
}
418435
_ => return Err(())
@@ -424,9 +441,17 @@ fn parse_color_function(name: &str, arguments: &mut Parser) -> Result<Color, ()>
424441
let hue = hue_normalized_degrees / 360.;
425442
// Saturation and lightness are clamped to 0% ... 100%
426443
// https://drafts.csswg.org/css-color/#the-hsl-notation
427-
try!(arguments.expect_comma());
428-
let saturation = try!(arguments.expect_percentage()).max(0.).min(1.);
429-
try!(arguments.expect_comma());
444+
let saturation = match try!(arguments.next()) {
445+
Token::Percentage(ref v) => v.unit_value,
446+
Token::Comma => {
447+
uses_commas = true;
448+
try!(arguments.expect_percentage())
449+
}
450+
_ => return Err(())
451+
}.max(0.).min(1.);
452+
if uses_commas {
453+
try!(arguments.expect_comma());
454+
}
430455
let lightness = try!(arguments.expect_percentage()).max(0.).min(1.);
431456

432457
// https://drafts.csswg.org/css-color/#hsl-color
@@ -449,12 +474,41 @@ fn parse_color_function(name: &str, arguments: &mut Parser) -> Result<Color, ()>
449474
blue = clamp_f32(hue_to_rgb(m1, m2, hue_times_3 - 1.));
450475
}
451476

477+
let alpha = if !arguments.is_exhausted() {
478+
let token = if uses_commas {
479+
try!(arguments.expect_comma());
480+
try!(arguments.next())
481+
} else {
482+
let token = try!(arguments.next());
483+
match token {
484+
Token::Delim('/') => {
485+
try!(arguments.next())
486+
}
487+
_ => token
488+
}
489+
};
490+
match token {
491+
Token::Number(NumericValue { value: v, .. }) => {
492+
clamp_f32(v)
493+
}
494+
Token::Percentage(ref v) => {
495+
clamp_f32(v.unit_value)
496+
}
497+
_ => {
498+
return Err(())
499+
}
500+
}
501+
} else {
502+
255
503+
};
504+
505+
/*
452506
let alpha = if has_alpha {
453507
try!(arguments.expect_comma());
454508
clamp_f32(try!(arguments.expect_number()))
455509
} else {
456510
255
457-
};
511+
};*/
458512
try!(arguments.expect_exhausted());
459513
rgba(red, green, blue, alpha)
460514
}
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[
2+
"hsla(120deg, 75%, 50%, 0.4)", [32, 224, 32, 102],
3+
"hsla(133.33333333grad, 75%, 50%, 0.6)", [32, 224, 32, 153],
4+
"hsla(2.0943951024rad, 75%, 50%, 0.8)", [32, 224, 32, 204],
5+
"hsla(0.3333333333turn, 75%, 50%, 1.0)", [32, 224, 32, 255]
6+
"hsl(600deg, 75%, 50%)", [32, 224, 32, 255],
7+
"hsl(1066.66666666grad, 75%, 50%)", [32, 224, 32, 255],
8+
"hsl(10.4719755118rad, 75%, 50%)", [32, 224, 32, 255],
9+
"hsl(2.6666666666turn, 75%, 50%)", [32, 224, 32, 255],
10+
11+
]

src/css-parsing-tests/color3.json

+108-9
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,14 @@
6565
"rgb()", null,
6666
"rgb(0)", null,
6767
"rgb(0, 0)", null,
68-
"rgb(0, 0, 0, 0)", null,
68+
"rgb(0, 0, 0, 0)", [0, 0, 0, 0],
6969
"rgb(0%)", null,
7070
"rgb(0%, 0%)", null,
71-
"rgb(0%, 0%, 0%, 0%)", null,
72-
"rgb(0%, 0%, 0%, 0)", null,
71+
"rgb(0%, 0%, 0%, 0%)", [0, 0, 0, 0],
72+
"rgb(0%, 0%, 0%, 0)", [0, 0, 0, 0],
7373

7474
"rgba(0, 0, 0, 0)", [0, 0, 0, 0],
75+
"rgba(0.3, -1.4, -0.001e2, 0)", [0, 0, 0, 0],
7576
"rgba(204, 0, 102, 0.25)", [204, 0, 102, 64],
7677
"RGBA(255,255,255, 0)", [255, 255, 255, 0],
7778
"rgBA(0, 51,255, 1)", [0, 51, 255, 255],
@@ -92,20 +93,20 @@
9293
"rgba(0%, 20%, 100%, -0.1)", [0, 51, 255, 0],
9394
"rgba(0%, 20%, 100%, -139)", [0, 51, 255, 0],
9495

95-
"rgba(255,255,255, 0%)", null,
96+
"rgba(255,255,255, 0%)", [255, 255, 255, 0],
9697
"rgba(10%, 50%, 0, 1)", null,
9798
"rgba(255, 50%, 0%, 1)", null,
9899
"rgba(0, 0, 0 0)", null,
99100
"rgba(0, 0, 0, 0deg)", null,
100101
"rgba(0, 0, 0, light)", null,
101102
"rgba()", null,
102103
"rgba(0)", null,
103-
"rgba(0, 0, 0)", null,
104+
"rgba(0, 0, 0)", [0, 0, 0, 255],
104105
"rgba(0, 0, 0, 0, 0)", null,
105106
"rgba(0%)", null,
106107
"rgba(0%, 0%)", null,
107-
"rgba(0%, 0%, 0%)", null,
108-
"rgba(0%, 0%, 0%, 0%)", null,
108+
"rgba(0%, 0%, 0%)", [0, 0, 0, 255],
109+
"rgba(0%, 0%, 0%, 0%)", [0, 0, 0, 0],
109110
"rgba(0%, 0%, 0%, 0%, 0%)", null,
110111

111112
"HSL(0, 0%, 0%)", [0, 0, 0, 255],
@@ -123,7 +124,7 @@
123124
"hsl()", null,
124125
"hsl(0)", null,
125126
"hsl(0, 0%)", null,
126-
"hsl(0, 0%, 0%, 0%)", null,
127+
"hsl(0, 0%, 0%, 0%)", [0, 0, 0, 0],
127128

128129
"HSLA(-300, 100%, 37.5%, 1)", [192, 192, 0, 255],
129130
"hsLA(-300, 100%, 37.5%, 12)", [192, 192, 0, 255],
@@ -139,8 +140,106 @@
139140
"hsla()", null,
140141
"hsla(0)", null,
141142
"hsla(0, 0%)", null,
142-
"hsla(0, 0%, 0%, 50%)", null,
143+
"hsla(0, 0%, 0%, 50%)", [0, 0, 0, 128],
143144
"hsla(0, 0%, 0%, 255, 0%)", null,
144145

146+
"rgb(0 0 0 0)", [0, 0, 0, 0],
147+
"rgb(0%)", null,
148+
"rgb(0% 0%)", null,
149+
"rgb(0% 0% 0% 0%)", [0, 0, 0, 0],
150+
"rgb(0% 0% 0% 0)", [0, 0, 0, 0],
151+
152+
"rgba(0%)", null,
153+
"rgba(0% 0%)", null,
154+
"rgba(0% 0% 0%)", [0, 0, 0, 255],
155+
"rgba(0% 0% 0% 0%)", [0, 0, 0, 0],
156+
"rgba(0% 0% 0% 0% 0%)", null,
157+
158+
"rgb(0, 0 0 0)", null,
159+
"rgb(0 0, 0 0)", null,
160+
"rgb(0 0 0, 0)", null,
161+
"rgb(0, 0, 0 0)", null,
162+
163+
"rgba(0%, 0% 0%)", null,
164+
"rgba(0% 0% 0%, 0%)", null,
165+
166+
"HSL(0 0% 0%)", [0, 0, 0, 255],
167+
"hsL(0 100% 50%)", [255, 0, 0, 255],
168+
"hsl(60 100% 37.5%)", [192, 192, 0, 255],
169+
170+
"HSLA(-300 100% 37.5% 1)", [192, 192, 0, 255],
171+
"hsLA(-300 100% 37.5% 12)", [192, 192, 0, 255],
172+
173+
"hsl(0, 0 0 0)", null,
174+
"hsl(0 0, 0 0)", null,
175+
"hsl(0 0 0, 0)", null,
176+
"hsl(0, 0, 0 0)", null,
177+
178+
"hsla(0%, 0% 0%)", null,
179+
"hsla(0% 0% 0%, 0%)", null,
180+
181+
"hsla(120.0, 75%, 50%, 20%)", [32, 224, 32, 51],
182+
"hsla(120, 75%, 50%, 0.4)", [32, 224, 32, 102],
183+
"hsla(120 75% 50% / 60%)", [32, 224, 32, 153],
184+
"hsla(120.0 75% 50% / 1.0)", [32, 224, 32, 255],
185+
"hsla(120/* comment */75%/* comment */50%/1.0)", [32, 224, 32, 255],
186+
"hsla(120,/* comment */75%,/* comment */50%,100%)", [32, 224, 32, 255],
187+
"hsla(120.0, 75%, 50%)", [32, 224, 32, 255],
188+
"hsla(120 75% 50%)", [32, 224, 32, 255],
189+
"hsla(120/* comment */75%/* comment */50%)", [32, 224, 32, 255],
190+
"hsla(120/* comment */,75%,/* comment */50%)", [32, 224, 32, 255],
191+
"hsl(120, 75%, 50%, 0.2)", [32, 224, 32, 51],
192+
"hsl(120, 75%, 50%, 40%)", [32, 224, 32, 102],
193+
"hsl(120 75% 50% / 0.6)", [32, 224, 32, 153],
194+
"hsl(120 75% 50% / 80%)", [32, 224, 32, 204],
195+
"hsl(120/* comment */75%/* comment */50%/1.0)", [32, 224, 32, 255],
196+
"hsl(120/* comment */75%/* comment */50%/100%)", [32, 224, 32, 255],
197+
"hsl(120,/* comment */75%,/* comment */50%,1.0)", [32, 224, 32, 255],
198+
"hsl(120,/* comment */75%,/* comment */50%,100%)", [32, 224, 32, 255],
199+
"hsl(120/* comment */75%/* comment */50%)", [32, 224, 32, 255],
200+
"hsl(120/* comment */,75%,/* comment */50%)", [32, 224, 32, 255],
201+
"hsla(120, 75%, 50%, 0.2)", [32, 224, 32, 51],
202+
"hsl(240, 75%, 50%)", [32, 32, 224, 255],
203+
"hsla(120, 75%, 50%)", [32, 224, 32, 255],
204+
"hsla(120.0, 75%, 50%)", [32, 224, 32, 255],
205+
"hsla(1.2e2, 75%, 50%)", [32, 224, 32, 255],
206+
"hsla(1.2E2, 75%, 50%)", [32, 224, 32, 255],
207+
"hsla(60, 75%, 50%)", [224, 224, 32, 255],
208+
"hsl(120, 75%, 50%, 0.2)", [32, 224, 32, 51],
209+
"hsl(120.0, 75%, 50%, 0.4)", [32, 224, 32, 102],
210+
"hsl(1.2e2, 75%, 50%, 0.6)", [32, 224, 32, 153],
211+
"hsl(1.2E2, 75%, 50%, 0.8)", [32, 224, 32, 204],
212+
"hsl(60.0, 75%, 50%, 1.0)", [224, 224, 32, 255],
213+
"rgb(10%, 60%, 10%, 20%)", [25, 153, 25, 51],
214+
"rgb(10, 175, 10, 0.4)", [10, 175, 10, 102],
215+
"rgb(10 175 10 / 60%)", [10, 175, 10, 153],
216+
"rgb(10.0 175.0 10.0 / 0.8)", [10, 175, 10, 204],
217+
"rgb(10/* comment */175/* comment */10/100%)", [10, 175, 10, 255],
218+
"rgb(10,/* comment */150,/* comment */50)", [10, 150, 50, 255],
219+
"rgb(10%, 60%, 10%)", [25, 153, 25, 255],
220+
"rgb(10.0 100.0 100.0)", [10, 100, 100, 255],
221+
"rgb(10/* comment */75/* comment */125)", [10, 75, 125, 255],
222+
"rgb(10.0, 50.0, 150.0)", [10, 50, 150, 255],
223+
"rgba(10.0, 175.0, 10.0, 0.2)", [10, 175, 10, 51],
224+
"rgba(10, 175, 10, 40%)", [10, 175, 10, 102],
225+
"rgba(10% 75% 10% / 0.6)", [25, 192, 25, 153],
226+
"rgba(10 175 10 / 80%)", [10, 175, 10, 204],
227+
"rgba(10/* comment */175/* comment */10/100%)", [10, 175, 10, 255],
228+
"rgba(10,/* comment */150,/* comment */50)", [10, 150, 50, 255],
229+
"rgba(10.0, 125.0, 75.0)", [10, 125, 75, 255],
230+
"rgba(10%, 45%, 45%)", [25, 115, 115, 255],
231+
"rgba(10/* comment */75/* comment */125)", [10, 75, 125, 255],
232+
"rgba(10.0, 50.0, 150.0)", [10, 50, 150, 255],
233+
"rgb(10, 175, 10, 0.2)", [10, 175, 10, 51],
234+
"rgb(10, 175, 10, 0.4)", [10, 175, 10, 102],
235+
"rgb(10, 175, 10, 0.6)", [10, 175, 10, 153],
236+
"rgb(10%, 70%, 10%, 0.8)", [25, 179, 25, 204],
237+
"rgb(10%, 70%, 10%, 1.0)", [25, 179, 25, 255],
238+
"rgba(10, 150, 50)", [10, 150, 50, 255],
239+
"rgba(10, 125, 75)", [10, 125, 75, 255],
240+
"rgba(10%,40%, 40%)", [25, 102, 102, 255],
241+
"rgba(10%, 45%, 50%)", [25, 115, 128, 255],
242+
"rgba(10%, 50%, 60%)", [25, 128, 153, 255],
243+
145244
"cmyk(0, 0, 0, 0)", null
146245
]

0 commit comments

Comments
 (0)