2
2
* License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
4
5
- use std:: f32:: consts:: PI ;
6
5
use std:: fmt;
6
+ use std:: { f32:: consts:: PI , str:: FromStr } ;
7
7
8
8
use super :: { BasicParseError , ParseError , Parser , ToCss , Token } ;
9
9
@@ -350,6 +350,81 @@ macro_rules! impl_lch_like {
350
350
impl_lch_like ! ( Lch , "lch" ) ;
351
351
impl_lch_like ! ( Oklch , "oklch" ) ;
352
352
353
+ #[ derive( Clone , Copy , PartialEq , Debug ) ]
354
+ pub enum PredefinedColorSpace {
355
+ Srgb ,
356
+ SrgbLinear ,
357
+ DisplayP3 ,
358
+ A98Rgb ,
359
+ ProphotoRgb ,
360
+ Rec2020 ,
361
+ XyzD50 ,
362
+ XyzD65 ,
363
+ }
364
+
365
+ impl PredefinedColorSpace {
366
+ fn as_str ( & self ) -> & str {
367
+ match self {
368
+ PredefinedColorSpace :: Srgb => "srgb" ,
369
+ PredefinedColorSpace :: SrgbLinear => "srgb-linear" ,
370
+ PredefinedColorSpace :: DisplayP3 => "display-p3" ,
371
+ PredefinedColorSpace :: A98Rgb => "a98-rgb" ,
372
+ PredefinedColorSpace :: ProphotoRgb => "prophoto-rgb" ,
373
+ PredefinedColorSpace :: Rec2020 => "rec2020" ,
374
+ PredefinedColorSpace :: XyzD50 => "xyz-d50" ,
375
+ PredefinedColorSpace :: XyzD65 => "xyz-d65" ,
376
+ }
377
+ }
378
+ }
379
+
380
+ #[ cfg( feature = "serde" ) ]
381
+ impl Serialize for PredefinedColorSpace {
382
+ fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
383
+ where
384
+ S : Serializer ,
385
+ {
386
+ self . as_str ( ) . serialize ( serializer)
387
+ }
388
+ }
389
+
390
+ impl ToCss for PredefinedColorSpace {
391
+ fn to_css < W > ( & self , dest : & mut W ) -> fmt:: Result
392
+ where
393
+ W : fmt:: Write ,
394
+ {
395
+ dest. write_str ( self . as_str ( ) )
396
+ }
397
+ }
398
+
399
+ #[ derive( Clone , Copy , PartialEq , Debug ) ]
400
+ pub struct ColorFunction {
401
+ pub color_space : PredefinedColorSpace ,
402
+ pub red : f32 ,
403
+ pub green : f32 ,
404
+ pub blue : f32 ,
405
+ pub alpha : f32 ,
406
+ }
407
+
408
+ impl ToCss for ColorFunction {
409
+ fn to_css < W > ( & self , dest : & mut W ) -> fmt:: Result
410
+ where
411
+ W : fmt:: Write ,
412
+ {
413
+ dest. write_str ( "color(" ) ?;
414
+ self . color_space . to_css ( dest) ?;
415
+ dest. write_str ( " " ) ?;
416
+ self . red . to_css ( dest) ?;
417
+ dest. write_str ( " " ) ?;
418
+ self . green . to_css ( dest) ?;
419
+ dest. write_str ( " " ) ?;
420
+ self . blue . to_css ( dest) ?;
421
+
422
+ serialize_alpha ( dest, self . alpha , false ) ?;
423
+
424
+ dest. write_char ( ')' )
425
+ }
426
+ }
427
+
353
428
/// An absolutely specified color.
354
429
/// https://w3c.github.io/csswg-drafts/css-color-4/#typedef-absolute-color-base
355
430
#[ derive( Clone , Copy , PartialEq , Debug ) ]
@@ -370,6 +445,8 @@ pub enum AbsoluteColor {
370
445
/// Specifies an Oklab color by Oklab Lightness, Chroma, and hue using
371
446
/// the OKLCH cylindrical coordinate model.
372
447
Oklch ( Oklch ) ,
448
+ /// Specified a sRGB based color with a predefined color space.
449
+ ColorFunction ( ColorFunction ) ,
373
450
}
374
451
375
452
impl AbsoluteColor {
@@ -381,6 +458,7 @@ impl AbsoluteColor {
381
458
Self :: Lch ( c) => c. alpha ,
382
459
Self :: Oklab ( c) => c. alpha ,
383
460
Self :: Oklch ( c) => c. alpha ,
461
+ Self :: ColorFunction ( c) => c. alpha ,
384
462
}
385
463
}
386
464
}
@@ -396,6 +474,7 @@ impl ToCss for AbsoluteColor {
396
474
Self :: Lch ( lch) => lch. to_css ( dest) ,
397
475
Self :: Oklab ( lab) => lab. to_css ( dest) ,
398
476
Self :: Oklch ( lch) => lch. to_css ( dest) ,
477
+ Self :: ColorFunction ( color_function) => color_function. to_css ( dest) ,
399
478
}
400
479
}
401
480
}
@@ -571,7 +650,7 @@ impl Color {
571
650
Token :: Function ( ref name) => {
572
651
let name = name. clone ( ) ;
573
652
return input. parse_nested_block ( |arguments| {
574
- parse_color_function ( component_parser, & * name, arguments)
653
+ parse_color ( component_parser, & * name, arguments)
575
654
} ) ;
576
655
}
577
656
_ => Err ( ( ) ) ,
@@ -785,7 +864,7 @@ fn clamp_floor_256_f32(val: f32) -> u8 {
785
864
}
786
865
787
866
#[ inline]
788
- fn parse_color_function < ' i , ' t , ComponentParser > (
867
+ fn parse_color < ' i , ' t , ComponentParser > (
789
868
component_parser : & ComponentParser ,
790
869
name : & str ,
791
870
arguments : & mut Parser < ' i , ' t > ,
@@ -827,6 +906,8 @@ where
827
906
Color :: Absolute ( AbsoluteColor :: Oklch ( Oklch :: new( l. max( 0. ) , c. max( 0. ) , h, alpha) ) )
828
907
} ) ,
829
908
909
+ "color" => parse_color_function( component_parser, arguments) ,
910
+
830
911
_ => return Err ( arguments. new_unexpected_token_error( Token :: Ident ( name. to_owned( ) . into( ) ) ) ) ,
831
912
} ?;
832
913
@@ -1072,3 +1153,51 @@ where
1072
1153
1073
1154
Ok ( into_color ( lightness, chroma, hue, alpha) )
1074
1155
}
1156
+
1157
+ #[ inline]
1158
+ fn parse_color_function < ' i , ' t , ComponentParser > (
1159
+ component_parser : & ComponentParser ,
1160
+ arguments : & mut Parser < ' i , ' t > ,
1161
+ ) -> Result < Color , ParseError < ' i , ComponentParser :: Error > >
1162
+ where
1163
+ ComponentParser : ColorComponentParser < ' i > ,
1164
+ {
1165
+ let location = arguments. current_source_location ( ) ;
1166
+ let color_space = arguments. try_parse ( |i| {
1167
+ let ident = i. expect_ident ( ) ?;
1168
+ Ok ( match_ignore_ascii_case ! {
1169
+ ident,
1170
+ "srgb" => PredefinedColorSpace :: Srgb ,
1171
+ "srgb-linear" => PredefinedColorSpace :: SrgbLinear ,
1172
+ "display-p3" => PredefinedColorSpace :: DisplayP3 ,
1173
+ "a98-rgb" => PredefinedColorSpace :: A98Rgb ,
1174
+ "prophoto-rgb" => PredefinedColorSpace :: ProphotoRgb ,
1175
+ "rec2020" => PredefinedColorSpace :: Rec2020 ,
1176
+ "xyz-d50" => PredefinedColorSpace :: XyzD50 ,
1177
+ "xyz-d65" => PredefinedColorSpace :: XyzD65 ,
1178
+ _ => return Err ( location. new_unexpected_token_error( Token :: Ident ( ident. clone( ) ) ) )
1179
+ } )
1180
+ } ) ?;
1181
+
1182
+ let red = component_parser
1183
+ . parse_number_or_percentage ( arguments) ?
1184
+ . unit_value ( ) ;
1185
+ let green = component_parser
1186
+ . parse_number_or_percentage ( arguments) ?
1187
+ . unit_value ( ) ;
1188
+ let blue = component_parser
1189
+ . parse_number_or_percentage ( arguments) ?
1190
+ . unit_value ( ) ;
1191
+
1192
+ let alpha = parse_alpha ( component_parser, arguments, false ) ?;
1193
+
1194
+ Ok ( Color :: Absolute ( AbsoluteColor :: ColorFunction (
1195
+ ColorFunction {
1196
+ color_space,
1197
+ red,
1198
+ green,
1199
+ blue,
1200
+ alpha,
1201
+ } ,
1202
+ ) ) )
1203
+ }
0 commit comments