@@ -565,6 +565,7 @@ where
565565 let ( red, green, blue, uses_commas) = match_ignore_ascii_case ! { name,
566566 "rgb" | "rgba" => parse_rgb_components_rgb( component_parser, arguments) ?,
567567 "hsl" | "hsla" => parse_rgb_components_hsl( component_parser, arguments) ?,
568+ "hwb" => parse_rgb_components_hwb( component_parser, arguments) ?,
568569 _ => return Err ( arguments. new_unexpected_token_error( Token :: Ident ( name. to_owned( ) . into( ) ) ) ) ,
569570 } ;
570571
@@ -653,6 +654,65 @@ where
653654 let lightness = component_parser. parse_percentage ( arguments) ?;
654655 let lightness = lightness. max ( 0. ) . min ( 1. ) ;
655656
657+ let ( red, green, blue) = hsl_to_rgb ( hue, saturation, lightness) ;
658+ let red = clamp_unit_f32 ( red) ;
659+ let green = clamp_unit_f32 ( green) ;
660+ let blue = clamp_unit_f32 ( blue) ;
661+ Ok ( ( red, green, blue, uses_commas) )
662+ }
663+
664+ #[ inline]
665+ fn parse_rgb_components_hwb < ' i , ' t , ComponentParser > (
666+ component_parser : & ComponentParser ,
667+ arguments : & mut Parser < ' i , ' t > ,
668+ ) -> Result < ( u8 , u8 , u8 , bool ) , ParseError < ' i , ComponentParser :: Error > >
669+ where
670+ ComponentParser : ColorComponentParser < ' i > ,
671+ {
672+ let hue_degrees = component_parser. parse_angle_or_number ( arguments) ?. degrees ( ) ;
673+
674+ // Subtract an integer before rounding, to avoid some rounding errors:
675+ let hue_normalized_degrees = hue_degrees - 360. * ( hue_degrees / 360. ) . floor ( ) ;
676+ let hue = hue_normalized_degrees / 360. ;
677+
678+ let uses_commas = arguments. try_parse ( |i| i. expect_comma ( ) ) . is_ok ( ) ;
679+
680+ let whiteness = component_parser. parse_percentage ( arguments) ?;
681+ let whiteness = whiteness. max ( 0. ) . min ( 1. ) ;
682+
683+ if uses_commas {
684+ arguments. expect_comma ( ) ?;
685+ }
686+
687+ let blackness = component_parser. parse_percentage ( arguments) ?;
688+ let blackness = blackness. max ( 0. ) . min ( 1. ) ;
689+
690+ let ( red, green, blue) = hwb_to_rgb ( hue, whiteness, blackness) ;
691+
692+ let red = clamp_unit_f32 ( red) ;
693+ let green = clamp_unit_f32 ( green) ;
694+ let blue = clamp_unit_f32 ( blue) ;
695+ Ok ( ( red, green, blue, uses_commas) )
696+ }
697+
698+ /// https://drafts.csswg.org/css-color-4/#hwb-to-rgb
699+ #[ inline]
700+ fn hwb_to_rgb ( h : f32 , w : f32 , b : f32 ) -> ( f32 , f32 , f32 ) {
701+ if w + b >= 1.0 {
702+ let gray = w / ( w + b) ;
703+ return ( gray, gray, gray) ;
704+ }
705+
706+ let ( mut red, mut green, mut blue) = hsl_to_rgb ( h, 1.0 , 0.5 ) ;
707+ let x = 1.0 - w - b;
708+ red = red * x + w;
709+ green = green * x + w;
710+ blue = blue * x + w;
711+ ( red, green, blue)
712+ }
713+
714+ #[ inline]
715+ fn hsl_to_rgb ( hue : f32 , saturation : f32 , lightness : f32 ) -> ( f32 , f32 , f32 ) {
656716 // https://drafts.csswg.org/css-color/#hsl-color
657717 // except with h pre-multiplied by 3, to avoid some rounding errors.
658718 fn hue_to_rgb ( m1 : f32 , m2 : f32 , mut h3 : f32 ) -> f32 {
@@ -680,8 +740,8 @@ where
680740 } ;
681741 let m1 = lightness * 2. - m2;
682742 let hue_times_3 = hue * 3. ;
683- let red = clamp_unit_f32 ( hue_to_rgb ( m1, m2, hue_times_3 + 1. ) ) ;
684- let green = clamp_unit_f32 ( hue_to_rgb ( m1, m2, hue_times_3) ) ;
685- let blue = clamp_unit_f32 ( hue_to_rgb ( m1, m2, hue_times_3 - 1. ) ) ;
686- return Ok ( ( red, green, blue, uses_commas ) ) ;
743+ let red = hue_to_rgb ( m1, m2, hue_times_3 + 1. ) ;
744+ let green = hue_to_rgb ( m1, m2, hue_times_3) ;
745+ let blue = hue_to_rgb ( m1, m2, hue_times_3 - 1. ) ;
746+ ( red, green, blue)
687747}
0 commit comments