Skip to content

Commit 87a95d0

Browse files
color: Integrate PR review suggestions (#113)
1 parent 15d44ab commit 87a95d0

File tree

2 files changed

+116
-101
lines changed

2 files changed

+116
-101
lines changed

src/color.rs

Lines changed: 114 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -400,104 +400,16 @@ fn clamp_f32(val: f32) -> u8 {
400400
#[inline]
401401
fn parse_color_function(name: &str, arguments: &mut Parser) -> Result<Color, ()> {
402402
let is_rgb = match_ignore_ascii_case! { name,
403-
"rgba" => true,
404-
"rgb" => true,
405-
"hsl" => false,
406-
"hsla" => false,
403+
"rgb" | "rgba" => true,
404+
"hsl" | "hsla" => false,
407405
_ => return Err(())
408406
};
409407

410-
let red: u8;
411-
let green: u8;
412-
let blue: u8;
413-
let mut uses_commas = false;
414-
if is_rgb {
415-
// Either integers or percentages, but all the same type.
416-
// https://drafts.csswg.org/css-color/#rgb-functions
417-
match try!(arguments.next()) {
418-
Token::Number(NumericValue { value: v, .. }) => {
419-
red = clamp_i32(v as i32);
420-
green = clamp_i32(match try!(arguments.next()) {
421-
Token::Number(NumericValue { value: v, .. }) => v,
422-
Token::Comma => {
423-
uses_commas = true;
424-
try!(arguments.expect_number())
425-
}
426-
_ => return Err(())
427-
} as i32);
428-
if uses_commas {
429-
try!(arguments.expect_comma());
430-
}
431-
blue = clamp_i32(try!(arguments.expect_number()) as i32);
432-
}
433-
Token::Percentage(ref v) => {
434-
red = clamp_f32(v.unit_value);
435-
green = clamp_f32(match try!(arguments.next()) {
436-
Token::Percentage(ref v) => v.unit_value,
437-
Token::Comma => {
438-
uses_commas = true;
439-
try!(arguments.expect_percentage())
440-
}
441-
_ => return Err(())
442-
});
443-
if uses_commas {
444-
try!(arguments.expect_comma());
445-
}
446-
blue = clamp_f32(try!(arguments.expect_percentage()));
447-
}
448-
_ => return Err(())
449-
};
408+
let (red, green, blue, uses_commas) = if is_rgb {
409+
parse_rgb_components_rgb(arguments)?
450410
} else {
451-
let hue_degrees = match try!(arguments.next()) {
452-
Token::Number(NumericValue { value: v, .. }) => v,
453-
Token::Dimension(NumericValue { value: v, .. }, unit) => {
454-
match &*unit {
455-
"deg" => v,
456-
"grad" => v * 360. / 400.,
457-
"rad" => v * 360. / (2. * PI as f32),
458-
"turn" => v * 360.,
459-
_ => return Err(())
460-
}
461-
}
462-
_ => return Err(())
463-
};
464-
// Subtract an integer before rounding, to avoid some rounding errors:
465-
let hue_normalized_degrees = hue_degrees - 360. * (hue_degrees / 360.).floor();
466-
let hue = hue_normalized_degrees / 360.;
467-
// Saturation and lightness are clamped to 0% ... 100%
468-
// https://drafts.csswg.org/css-color/#the-hsl-notation
469-
let saturation = match try!(arguments.next()) {
470-
Token::Percentage(ref v) => v.unit_value,
471-
Token::Comma => {
472-
uses_commas = true;
473-
try!(arguments.expect_percentage())
474-
}
475-
_ => return Err(())
476-
}.max(0.).min(1.);
477-
if uses_commas {
478-
try!(arguments.expect_comma());
479-
}
480-
let lightness = try!(arguments.expect_percentage()).max(0.).min(1.);
481-
482-
// https://drafts.csswg.org/css-color/#hsl-color
483-
// except with h pre-multiplied by 3, to avoid some rounding errors.
484-
fn hue_to_rgb(m1: f32, m2: f32, mut h3: f32) -> f32 {
485-
if h3 < 0. { h3 += 3. }
486-
if h3 > 3. { h3 -= 3. }
487-
488-
if h3 * 2. < 1. { m1 + (m2 - m1) * h3 * 2. }
489-
else if h3 * 2. < 3. { m2 }
490-
else if h3 < 2. { m1 + (m2 - m1) * (2. - h3) * 2. }
491-
else { m1 }
492-
}
493-
let m2 = if lightness <= 0.5 { lightness * (saturation + 1.) }
494-
else { lightness + saturation - lightness * saturation };
495-
let m1 = lightness * 2. - m2;
496-
let hue_times_3 = hue * 3.;
497-
red = clamp_f32(hue_to_rgb(m1, m2, hue_times_3 + 1.));
498-
green = clamp_f32(hue_to_rgb(m1, m2, hue_times_3));
499-
blue = clamp_f32(hue_to_rgb(m1, m2, hue_times_3 - 1.));
500-
}
411+
parse_rgb_components_hsl(arguments)?
412+
};
501413

502414
let alpha = if !arguments.is_exhausted() {
503415
if uses_commas {
@@ -524,13 +436,114 @@ fn parse_color_function(name: &str, arguments: &mut Parser) -> Result<Color, ()>
524436
255
525437
};
526438

527-
/*
528-
let alpha = if has_alpha {
529-
try!(arguments.expect_comma());
530-
clamp_f32(try!(arguments.expect_number()))
531-
} else {
532-
255
533-
};*/
534439
try!(arguments.expect_exhausted());
535440
rgba(red, green, blue, alpha)
536441
}
442+
443+
444+
#[inline]
445+
fn parse_rgb_components_rgb(arguments: &mut Parser) -> Result<(u8, u8, u8, bool), ()> {
446+
let red: u8;
447+
let green: u8;
448+
let blue: u8;
449+
let mut uses_commas = false;
450+
451+
// Either integers or percentages, but all the same type.
452+
// https://drafts.csswg.org/css-color/#rgb-functions
453+
match try!(arguments.next()) {
454+
Token::Number(NumericValue { value: v, .. }) => {
455+
red = clamp_i32(v as i32);
456+
green = clamp_i32(match try!(arguments.next()) {
457+
Token::Number(NumericValue { value: v, .. }) => v,
458+
Token::Comma => {
459+
uses_commas = true;
460+
try!(arguments.expect_number())
461+
}
462+
_ => return Err(())
463+
} as i32);
464+
if uses_commas {
465+
try!(arguments.expect_comma());
466+
}
467+
blue = clamp_i32(try!(arguments.expect_number()) as i32);
468+
}
469+
Token::Percentage(ref v) => {
470+
red = clamp_f32(v.unit_value);
471+
green = clamp_f32(match try!(arguments.next()) {
472+
Token::Percentage(ref v) => v.unit_value,
473+
Token::Comma => {
474+
uses_commas = true;
475+
try!(arguments.expect_percentage())
476+
}
477+
_ => return Err(())
478+
});
479+
if uses_commas {
480+
try!(arguments.expect_comma());
481+
}
482+
blue = clamp_f32(try!(arguments.expect_percentage()));
483+
}
484+
_ => return Err(())
485+
};
486+
return Ok((red, green, blue, uses_commas));
487+
}
488+
489+
#[inline]
490+
fn parse_rgb_components_hsl(arguments: &mut Parser) -> Result<(u8, u8, u8, bool), ()> {
491+
let mut uses_commas = false;
492+
// Hue given as an angle
493+
// https://drafts.csswg.org/css-values/#angles
494+
let hue_degrees = match try!(arguments.next()) {
495+
Token::Number(NumericValue { value: v, .. }) => v,
496+
Token::Dimension(NumericValue { value: v, .. }, unit) => {
497+
match_ignore_ascii_case! { &*unit,
498+
"deg" => v,
499+
"grad" => v * 360. / 400.,
500+
"rad" => v * 360. / (2. * PI as f32),
501+
"turn" => v * 360.,
502+
_ => return Err(())
503+
}
504+
}
505+
_ => return Err(())
506+
};
507+
// Subtract an integer before rounding, to avoid some rounding errors:
508+
let hue_normalized_degrees = hue_degrees - 360. * (hue_degrees / 360.).floor();
509+
let hue = hue_normalized_degrees / 360.;
510+
511+
// Saturation and lightness are clamped to 0% ... 100%
512+
// https://drafts.csswg.org/css-color/#the-hsl-notation
513+
let saturation = match try!(arguments.next()) {
514+
Token::Percentage(ref v) => v.unit_value,
515+
Token::Comma => {
516+
uses_commas = true;
517+
try!(arguments.expect_percentage())
518+
}
519+
_ => return Err(())
520+
};
521+
let saturation = saturation.max(0.).min(1.);
522+
523+
if uses_commas {
524+
try!(arguments.expect_comma());
525+
}
526+
527+
let lightness = try!(arguments.expect_percentage());
528+
let lightness = lightness.max(0.).min(1.);
529+
530+
// https://drafts.csswg.org/css-color/#hsl-color
531+
// except with h pre-multiplied by 3, to avoid some rounding errors.
532+
fn hue_to_rgb(m1: f32, m2: f32, mut h3: f32) -> f32 {
533+
if h3 < 0. { h3 += 3. }
534+
if h3 > 3. { h3 -= 3. }
535+
536+
if h3 * 2. < 1. { m1 + (m2 - m1) * h3 * 2. }
537+
else if h3 * 2. < 3. { m2 }
538+
else if h3 < 2. { m1 + (m2 - m1) * (2. - h3) * 2. }
539+
else { m1 }
540+
}
541+
let m2 = if lightness <= 0.5 { lightness * (saturation + 1.) }
542+
else { lightness + saturation - lightness * saturation };
543+
let m1 = lightness * 2. - m2;
544+
let hue_times_3 = hue * 3.;
545+
let red = clamp_f32(hue_to_rgb(m1, m2, hue_times_3 + 1.));
546+
let green = clamp_f32(hue_to_rgb(m1, m2, hue_times_3));
547+
let blue = clamp_f32(hue_to_rgb(m1, m2, hue_times_3 - 1.));
548+
return Ok((red, green, blue, uses_commas));
549+
}

src/css-parsing-tests/color3.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,8 @@
243243
"rgba(10%, 50%, 60%)", [25, 128, 153, 255],
244244

245245
"hsla(120deg, 75%, 50%, 0.4)", [32, 224, 32, 102],
246+
"hsla(120DEG, 75%, 50%, 0.4)", [32, 224, 32, 102],
247+
"hsla(120deG, 75%, 50%, 0.4)", [32, 224, 32, 102],
246248
"hsla(133.33333333grad, 75%, 50%, 0.6)", [32, 224, 32, 153],
247249
"hsla(2.0943951024rad, 75%, 50%, 0.8)", [32, 224, 32, 204],
248250
"hsla(0.3333333333turn, 75%, 50%, 1.0)", [32, 224, 32, 255],

0 commit comments

Comments
 (0)