@@ -565,6 +565,7 @@ where
565
565
let ( red, green, blue, uses_commas) = match_ignore_ascii_case ! { name,
566
566
"rgb" | "rgba" => parse_rgb_components_rgb( component_parser, arguments) ?,
567
567
"hsl" | "hsla" => parse_rgb_components_hsl( component_parser, arguments) ?,
568
+ "hwb" => parse_rgb_components_hwb( component_parser, arguments) ?,
568
569
_ => return Err ( arguments. new_unexpected_token_error( Token :: Ident ( name. to_owned( ) . into( ) ) ) ) ,
569
570
} ;
570
571
@@ -653,6 +654,65 @@ where
653
654
let lightness = component_parser. parse_percentage ( arguments) ?;
654
655
let lightness = lightness. max ( 0. ) . min ( 1. ) ;
655
656
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 ) {
656
716
// https://drafts.csswg.org/css-color/#hsl-color
657
717
// except with h pre-multiplied by 3, to avoid some rounding errors.
658
718
fn hue_to_rgb ( m1 : f32 , m2 : f32 , mut h3 : f32 ) -> f32 {
@@ -680,8 +740,8 @@ where
680
740
} ;
681
741
let m1 = lightness * 2. - m2;
682
742
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)
687
747
}
0 commit comments